A very common use case for a PDF viewer is allowing a user to upload a document, annotate it, and then download it with those annotations.
This flow is easy to set up in PDF.js Express using the PDF.js Express REST API
This guide assumes that you have PDF.js Express installed, and have it integrated into your app. If you have no done so, please follow the guides here for integrating it into your app.
1. Disable flattened annotations
By default PDF.js Express renders annotations as a flattened bitmap. We want to disable this because we will be using the extract api to load annotations instead.
To disable these annotations, add the disableFlattenedAnnotations
flag to the constructor.
import WebViewer from '@pdftron/pdfjs-express'
WebViewer({
disableFlattenedAnnotations: true,
...otherOptions
}).then(instance => {
// ...
})
2. Listen for document load
Every time a new document is loaded, we want to extract the annotations from it and load them into the viewer. This can be done by using a document listener and the PDF.js Express extract API. In this example we will also use the recommended PDF.js Express API SDK
import WebViewer from '@pdftron/pdfjs-exress'
import ExpressUtils from '@pdftron/pdfjs-express-utils'
WebViewer({
disableFlattenedAnnotations: true,
...otherOptions
}).then(instance => {
// Create a new instance of the utility SDK
const utils = new ExpressUtils();
const { documentViewer, annotationManager } = instance.Core;
// Set a callback function for every time a document is loaded
documentViewer.addEventListener('documentLoaded', async () => {
// Get the loaded document's data
const data = await documentViewer.getDocument().getFileData();
// Set the file in the SDK
utils.setFile(data);
// Use the API to extract the XFDF
const { xfdf } = await utils.extract();
// Loading the resulting XFDF into the viewer
const importedAnnotations = await annotationManager.importAnnotations(xfdf);
})
})
Note: You can load documents using the loadDocument
api. See more info here.
3. Downloading the file
After the user has annotated the file, they might want to download it. In order to bake the annotations they have added into the document, we need to use the merge endpoint. The following sample shows the easiest way to do this.
Note: We will use the file-saver package to help us trigger a download.
import FileSaver from 'file-saver'
import WebViewer from '@pdftron/pdfjs-exress'
import ExpressUtils from '@pdftron/pdfjs-express-utils'
WebViewer({
disableFlattenedAnnotations: true,
...otherOptions
}).then(instance => {
// Create a new instance of the utility SDK
const utils = new ExpressUtils();
const { documentViewer, annotationManager } = instance.Core;
// ... documentLoaded code from above
// A function that gets called when the user clicks your download button.
// This can be implemented any way you want.
// In our example we will assume it is bounded to an '#download-button' button
document.getElementById('download-button').onclick = () => {
// Get the annotations and the documents data
const xfdf = await annotationManager.exportAnnotations({});
const fileData = await documentViewer.getDocument().getFileData({});
// Set the annotations and document into the Utility SDK, then merge them together
const resp = await utils
.setFile(fileData)
.setXFDF(xfdf)
.merge();
// Get the resulting blob from the merge operation
const mergedBlob = await resp.getBlob();
// trigger a download for the user!
FileSaver.saveAs(mergedBlob, 'myfile.pdf')
}
})