Frameworks
Integrations
Mendix
SharePoint
Modular UI
Legacy UI
AnnotationManager
Annotation Types
Customize
Version 11
Version 10
v10.12
v10.11
v10.10
v10.9
v10.8
v10.7
v10.6
v10.5
v10.4
v10.3
v10.2
v10.1
v10.0
Version 8
v8.12
v8.11
v8.10
v8.9
v8.8
v8.7
v8.6
v8.5
v8.4
v8.3
v8.2
v8.1
v8.0
Version 7
Version 6
v6.3
v6.2
v6.1
v6.0
Version 5
Version 4
Version 3
Version 2
WebViewer Server
WebViewer BIM
There are a few ways to import or export annotations such as from a file, a database, or a document. There are also more advanced loading options to help with finer control of the data.
WebViewer is able to import and export PDF annotations with the XFDF format. XFDF is an XML-based standard that is able to represent information about annotations. Saving and loading annotations in WebViewer is the process of saving and loading this XFDF data.
We will go through relevant APIs and examples for different scenarios in the following guides:
Importing and exporting annotations using a file
To import and export XFDF annotations using a file.
Importing and exporting annotations using a database
To import and export XFDF annotations using a databse.
Importing and exporting annotations using a document
To import and export XFDF annotations using a document.
Importing and exporting annotation in Salesforce
To import and export XFDF annotations using Salesforce.
Advanced annotation loading
To perform advanced control of the annotation loading process
A short introduction to XFDF file format
An introduction to XFDF file format
One of the options is to use XFDF files to save and load annotations. You can use AJAX requests to save and load the XFDF string from the server, and setup the server to write and read XFDF files. For example,
Importing annotations require at least the document to be loaded. When using the setDocumentXFDFRetriever
API, the XFDF is imported at the earliest point possible.
Alternatively, importing annotations can be done with the importAnnotations
API as well. The earliest point in which XFDF can be imported is documentLoaded
.
In the POST and GET requests you can pass an ID to the server to uniquely identify the XFDF file that should be saved/loaded. You have full flexibility to choose this ID but here are some simple examples:
For samples about saving annotations into XFDF files in different backends, see Github repos below:
Using the documentViewer.setXFDFRetriever
or documentXFDFRetriever
WebViewer constructor option is the preferred way of importing annotations from your server if you are adding them all at once initially.
documentXFDFRetriever
merges your annotations at the proper time automatically and prevents conflicts and potential flashing of annotations on the page.importAnnotations
and your server has modifications to an annotation inside the document, for example on page 10 and WebViewer hasn't loaded the annotations for page 10 yet then there may be a conflict when merging these changes together.annotationsLoaded
event is one way to work around this so that there aren't any conflicts, however this event doesn't fire until annotations on every page have been loaded, so for documents with many pages this may take some time. It may also cause annotations to jump if the internal annotation has loaded on a page, then much later your server annotations are imported the annotation may change positions or even be deleted from the document.importAnnotations
is fine for importing annotations later, after the document's internal annotations have loaded, however for the initial import of your server annotations documentXFDFRetriever
is recommended instead.
Another option is to use a database to store XFDF. You can choose to store the XFDF string for the document and user as described in using files, but with a database you can store and organize the XFDF data so that the XFDF string for each annotation is separate, allowing you to update it individually instead of updating the entire XFDF file for every change. For example, you can store and organize XFDF strings based on a combination of factors like document ID, annotation ID, author, etc.
For example, with a relational database, you can have a table called Annotations which contains annotation ID, document ID and xfdfString columns. In this setup, you can fetch all annotations for a particular document, or just fetch one annotation you are interested in.
To save individual annotations separately, the exportAnnotationCommand
and annotationChanged
event are very useful. exportAnnotationCommand
returns XFDF data for all of the annotations that have changed since the last time you called exportAnnotationCommand
.
Annotations that have been added are inside the add
element, modified annotations are in the modify
element and deleted annotations have their ID inside the delete
element of the XFDF. If you call this function on the annotationChanged
event, you can POST each command to your server to save each annotation change as it happens as opposed to having your user press a save button.
When importing annotations, you can use importAnnotationCommand
. The earliest point you can call this is during documentLoaded
.
At this point you'll be saving annotations in realtime, so if you want to have a fully realtime solution you'll need to update annotations on each client in realtime. You can extend realtime saving further by hooking it up to a WebSocket, which can broadcast the new xfdfString in the database to be imported to all the clients. By utilizing exportAnnotationCommand
instead of exportAnnotations
you can greatly reduce the size of the data being transferred to/from the annotation server.
For samples about saving annotations into different databases, see links below:
Another option is to merge the annotations back into the document, avoiding the need to handle XFDF separately. It is achieved by using getFileData which returns an ArrayBuffer of the PDF with annotations. It can be sent to the server with a POST request, so that the file can be updated on the server.
This setup can also be useful for applications that do not have a server or that will handle documents in the user's device locally. However, it would not be suitable for applications where multiple users are annotating and sharing the same document.
For samples about saving annotations into the document itself, see Github repo below:
Importing and exporting annotations using Salesforce
Another option for importing and exporting annotation is using Salesforce custom objects to store XFDF data if you are hosting WebViewer in the Salesforce platform. You can create custom object in Salesforce setting page or using sfdx
command line utility tool. In this example we will create Apex class called AnnotationController.cls
which will utilize Salesforce SOQL to store and retrieve XFDF data to and from custom objects.
Create custom object in Salesforce setting page, under Manage Objects section. Here is a sample custom object used in this sample
Apex class for storing and retrieving annotation XFDF data.
Sample app in Lightning Web Component to showcase importing and exporting XFDF stirng to Salesforce custom object.
For more advanced control over the annotation loading process you can use the setPagesUpdatedInternalAnnotationsTransform
function on DocumentViewer. When WebViewer loads a document it will import the annotation data as XFDF and this function allows you to transform that data before it gets loaded into the viewer.
The function that you pass to setPagesUpdatedInternalAnnotationsTransform
may be called multiple times, specifying the list of pages that the annotation data is a part of.
You can use the function like this:
One way to use setPagesUpdatedInternalAnnotationsTransform
is to replace the original annotation data inside the document with the data from your server. Note that this would also replace any existing links or form fields unless they are also saved on your server.
Alternatively you can modify the existing data that is passed in. When modifying the data it is easiest to first parse it into DOM elements, perform your modifications and then serialize back to a string.
An example of something you might want to do is remove all clickable links:
Here's another example of changing the color attribute of every annotation to blue:
With setPagesUpdatedInternalAnnotationsTransform
you have very fine control over all of the annotation data and can modify it exactly as you like.
Did you find this helpful?
Trial setup questions?
Ask experts on DiscordNeed other help?
Contact SupportPricing or product questions?
Contact Sales