PDF.js Express Plusplay_arrow

Professional PDF.js Viewing & Annotations - Try for free

side menu

Get Started

play_arrow

Learn more

play_arrow

Common use cases

play_arrow

Open a document

play_arrow

Save a document

play_arrow

Viewer

play_arrow

UI Customization

play_arrow

Annotations

play_arrow

Collaboration

play_arrow

Forms

play_arrow

Signature

play_arrow

Searching

play_arrow

Measurement

play_arrow

Compare

play_arrow

Advanced Capabilities

play_arrow

PDF.js Express REST API

play_arrow

Migration Guides

play_arrow

Migrating to PDF.js Express 8.0

The following features are available in:

check

PDF.js Express Viewer

help_outline

PDF.js Express Viewer is a free viewer with limited capabilities compared to PDF.js Express Plus

check

PDF.js Express Plus

help_outline

PDF.js Express Plus is a commercial PDF SDK for viewing, annotating, signing, form filling and more

There are a few breaking changes and other deprecated APIs when migrating to v8 from older versions.

Instance namespace adjustments

This is not actually a breaking change since you can still access the old namespaces, but a number of namespaces have been restructured to more logically group things. All of the WebViewer Core namespaces can now be found on instance.Core and all of the UI related APIs and namespaces can be found on instance.UI. The CoreControls namespace now only exists for backwards compatibility and you can access all functions that were previously found on CoreControls, directly on the Core namespace.

  • annotManager has been renamed to annotationManager and docViewer has been renamed to documentViewer.
  • on has been renamed to addEventListener and off has been renamed to removeEventListener

Before:

WebViewer(...)
  then(instance => {
    const { docViewer, annotManager, Tools, Annotations, PDFNet, CoreControls } = instance;
    CoreControls.setWorkerPath(...);

    instance.disableElements([...]);

    docViewer.on('documentLoaded', () => {

    });
  });

After:

WebViewer(...)
  then(instance => {
    const { Core, UI } = instance;

    const { documentViewer, annotationManager, Tools, Annotations, PDFNet } = Core;
    Core.setWorkerPath(...);

    instance.UI.disableElements([...]);

    documentViewer.addEventListener('documentLoaded', () => {

    });
  });

Inside a config file

When running code inside a config file you can now access instance on the window and it will be identical to the instance that is resolved from the WebViewer function. readerControl no longer exists inside the WebViewer iframe.

Breaking changes

CustomData changes

"Custom data" is stored on annotations and is automatically saved and restored when exporting and importing XFDF, as well as downloading and re-opening a PDF.

To be consistent and fully compatible with other platforms the setCustomData function now only accepts a string as the value. If you pass something other than a string it will automatically be stringified. Similarly getCustomData will only return a string.

To more easily enforce the proper types, setting of the CustomData property directly is now no longer possible. Please use setCustomData to set your properties instead.

If you would like to use object types you can use JSON.stringify and JSON.parse, or parseInt and parseFloat for numbers.

Before:

annotation.setCustomData('number-data', 1);
annotation.setCustomData('object-data', { abc: 123 });

annotation.getCustomData('number-data'); // the number 1
annotation.getCustomData('object-data'); // an object

annotation.CustomData = {
  key1: 1,
  key2: 2
};
annotation.CustomData.key1; // the number 1

After:

annotation.setCustomData('number-data', '1');
annotation.setCustomData('object-data', JSON.stringify({ abc: 123 }));

annotation.getCustomData('number-data'); // the string '1'
JSON.parse(annotation.getCustomData('object-data')); // JSON.parse returns the object

// these will warn and automatically stringify the value
annotation.setCustomData('number-data', 1);
annotation.setCustomData('object-data', { abc: 123 });

// this code no longer works
// annotation.CustomData = {
//  key1: 1,
//  key2: 2
// };
// annotation.CustomData.key1;

Legacy UI no longer officially supported

With PDF.js Express 8.0, the legacy UI is not officially supported. If you would like to continue using the legacy UI you can stay on version 7.3. Note that the legacy 7.3 branch is available in the public UI repo and you can attempt to update it to be compatible with 8.0 if you like.

Updated annotation linking APIs

The associateLink, getAssociatedLinks and unassociateLinks APIs have been removed. Links are now associated with annotations by using the normal annotation grouping APIs, for example annotationManager.groupAnnotations.

If you have associated links already saved in your XFDF then WebViewer will automatically convert them over to groups the next time they are loaded.

Before:

annotation.associateLink(linkAnnotation);

After:

annotationManager.groupAnnotations(annotation, [linkAnnotation]);

annotationSelected event never returns null for annotation list

In previous version when all annotations were deselected the annotationSelected event would provide null as the annotations parameter of the event for a deselect action. Now all deselect actions will return an array of the annotations that were deselected, never null.

Before:

annotManager.on('annotationSelected', (annotations, action) => {
  // when all annotations are deselected, action is 'deselected', annotations is null
});

After:

annotationManager.addEventListener('annotationSelected', (annotations, action) => {
  // when all annotations are deselected, action is 'deselected'
  // annotations is the array of annotations that were previously selected, possibly an empty array
});

CoreControls.js renamed

The file lib/core/CoreControls.js has been renamed to lib/core/webviewer-core.min.js.

getDisplayAuthor parameter change

The AnnotationManager function getDisplayAuthor previously would take an annotation object as a parameter and returned the transformed author name, however sometimes there were times that a transformed author name was needed but no annotation object existed yet.

In WebViewer 8.0 the getDisplayAuthor function now accepts the author id so that it can be used in all cases, with or without an anotation. This also means that the setAnnotationDisplayAuthorMap callback function receives an author id instead of an annotation.

Before:

annotManager.setAnnotationDisplayAuthorMap((annotation) => {
  if (annotation.Id === '1') {
    return 'John';
  } else {
    return 'Guest';
  }
});

const displayAuthor = annotManager.getDisplayAuthor(annotation);

After:

annotationManager.setAnnotationDisplayAuthorMap((authorId) => {
  if (authorId === '1') {
    return 'John';
  } else {
    return 'Guest';
  }
});

const displayAuthor = annotationManager.getDisplayAuthor(annotation.Author);

A few functions are now asynchronous

RubberStampCreateTool

SignatureCreateTool

Consistent NoZoom handling across all annotations

The NoZoom property on annotations now works consistently for all types of annotations. If you were overriding the draw function for sticky note annotations then it has changed somewhat. Previously the canvas context was already translated to where the sticky note was drawn, but now you must first translate by annotation.X and annotation.Y.

Before:

Annotations.setCustomDrawHandler(Annotations.StickyAnnotation, function(ctx, pageMatrix, options) {
  // ctx functions here without translating
});

After:

Annotations.setCustomDrawHandler(Annotations.StickyAnnotation, function(ctx, pageMatrix, options) {
  ctx.translate(options.annotation.X, options.annotation.Y);
  // continue with previous drawing code
});

Small parameter updates for consistency

The callback for documentViewer.setPagesUpdatedInternalAnnotationsTransform now provides 1-indexed page numbers instead of 0-indexed page numbers.

Before:

docViewer.setPagesUpdatedInternalAnnotationsTransform((xfdfData, pageList, callback) => {
  console.log(pageList); // 0, 1, 2, etc
});

After:

documentViewer.setPagesUpdatedInternalAnnotationsTransform((xfdfData, pageList, callback) => {
  console.log(pageList); // 1, 2, 3 etc
});

The documentViewer.select function expects the point objects to have the pageNumber property instead of pageIndex.

Before:

const location1 = {
  x: 0,
  y: 100,
  pageIndex: 0
};

const location2 = {
  x: 100,
  y: 200,
  pageIndex: 0
};

docViewer.select(location1, location2);

After:

const location1 = {
  x: 0,
  y: 100,
  pageNumber: 1
};

const location2 = {
  x: 100,
  y: 200,
  pageNumber: 1
};

documentViewer.select(location1, location2);

Deprecated usages

To make the API more consistent many boolean APIs have mostly moved to the form enableXYZ/disableXYZ/isXYZEnabled. The previous functions are still accessible but have been deprecated.

AnnotationManager

  • setReadOnly becomes enableReadOnlyMode, disableReadOnlyMode, isReadOnlyModeEnabled
  • setFreeformRotationEnabled becomes enableFreeformRotation, disableFreeformRotation
  • enableRedaction(boolean) becomes enableRedaction, disableRedaction
  • setIsAdminUser, getIsAdminUser becomes promoteUserToAdmin, demoteUserFromAdmin, isUserAdmin

DocumentViewer

  • getRightToLeftPages, setRightToLeftPages becomes enableRightToLeftPageRendering, disableRightToLeftPageRendering, isRightToLeftPageRenderingEnabled
  • setLoadAnnotationsFromVisiblePages becomes enableLoadingAnnotationsFromVisiblePages, disableLoadingAnnotationsFromVisiblePages
  • setEnableAutomaticLinking becomes enableAutomaticLinking, disableAutomaticLinking
  • setEnableStylusMode becomes enableStylusMode, disableStylusMode

Document

  • enableColorSeparations(boolean) becomes enableColorSeparations, disableColorSeparations
  • setOfflineModeEnabled becomes enableOfflineMode, disableOfflineMode

Tools

  • AnnotationSelectTool.setEnableImmediateActionOnAnnotationSelection becomes AnnotationSelectTool.enableImmediateActionOnAnnotationSelection, AnnotationSelectTool.disableImmediateActionOnAnnotationSelection
  • DistanceMeasurementCreateTool.setEnableLeaderLines becomes DistanceMeasurementCreateTool.enableLeaderLines, DistanceMeasurementCreateTool.disableLeaderLines
  • RedactionCreateTool.setEnableTextAutoSize becomes RedactionCreateTool.enableAutoSizedText, RedactionCreateTool.disableAutoSizedText
  • setAllowCreationOverAnnotation becomes enableCreationOverAnnotation, disableCreationOverAnnotation

Other

  • CoreControls.enableFullPDF(boolean) becomes Core.enableFullPDF, Core.disableFullPDF
  • annotation.setRotationControlEnabled becomes annotation.enableRotationControl, annotation.disableRotationControl
  • popupAnnotation.setOpen becomes popupAnnotation.open, popupAnnotation.close
  • WebViewer constructor option pdftronServer becomes webviewerServerURL

APIs removed

Previously deprecated APIs that have been removed:

  • The deprecated new PDFTron.WebViewer constructor for WebViewer has been removed.

Before:

const viewerInstance = new PDFTron.WebViewer(options, viewerElement);
viewerElement.addEventListener('ready', () => {
  // viewer ready
});

After:

WebViewer(options, viewerElement)
  .then(viewerInstance => {
    // viewer ready
  });
  • annotation.getLeft() use annotation.getX() or annotation.X instead
  • annotation.getRight() use annotation.X + annotation.Width instead
  • annotation.getTop() use annotation.getY() or annotation.Y instead
  • annotation.getBottom() use annotation.Y + annotation.Height instead
  • signatureWidget.isSignedInitially() use signatureWidget.isSignedDigitally() instead
  • annotationManager.getAnnotCommand() use annotationManager.exportAnnotCommand() instead