Flatten PDF annotations using JavaScript

Annotation or form flattening refers to the operation that changes annotations (such as markup, widgets, 3D models, etc.) into a static area that is part of the PDF document, just like the other text and images in the document. By flattening and merging existing annotation appearances with page content, the original annotations are deleted from the PDF pages. Try out the flatten annotations sample in WebViewer Showcase.

Forms share a relationship with annotations because the visual display of a form is a widget annotation. The process of flattening annotations therefore can optionally flatten forms as well.

Note that it is not possible to undo the flatten operation. If you are interested in modifying annotations so they cannot be edited or deleted then you should consider setting to ReadOnly instead of flattening them. See the ReadOnly property on the Annotation class for more details.

Flattening annotations can be performed when getting the PDF file data or while downloading the PDF file locally. There is also the option to flatten select annotations.

Flattening annotations when getting PDF data

Use the getFileData method and the flatten option for the annotations to be flattened in the document output when getting the data for uploading to a server.

flatten option

A flag that is only useful when the xfdfString option is used. If true all the annotations in the saved document will be flattened.

1WebViewer({
2 fullAPI: true,
3 // other constructor options
4}, viewerElement).then(instance => {
5 const { documentViewer, annotationManager } = instance.Core;
6
7 document.getElementById('myBtn').addEventListener('click', async () => {
8 const doc = documentViewer.getDocument();
9 const xfdfString = await annotationManager.exportAnnotations();
10 const options = { xfdfString, flatten: true };
11 const data = await doc.getFileData(options);
12 const arr = new Uint8Array(data);
13 const blob = new Blob([arr], { type: 'application/pdf' });
14 // upload blob to your server
15 });
16});

Flattening annotations when downloading PDF

Use the downloadPdf method and the flatten option for the annotations to be flattened in the document output when downloading the PDF locally.

flatten option

Whether or not to flatten all the annotations in the downloaded document. Only useful if fullAPI is enabled and either `xfdfString` or `includeAnnotations` is used.

1WebViewer({
2 fullAPI: true,
3 // other constructor options
4}, viewerElement).then(instance => {
5
6 document.getElementById('myBtn').addEventListener('click', () => {
7 // download pdf with all annotations flattened
8 instance.UI.downloadPdf({
9 includeAnnotations: true,
10 flatten: true,
11 });
12 });
13});

Flattening annotations in the viewer

Use flattenAnnotations method to flatten all annotations into a document.

1WebViewer({
2 fullAPI: true,
3 // other constructor options
4}, viewerElement).then(instance => {
5 const { documentViewer, PDFNet, annotationManager } = instance.Core;
6
7 document.getElementById('myBtn').addEventListener('click', async () => {
8 await PDFNet.initialize();
9 const doc = await documentViewer.getDocument().getPDFDoc();
10
11 // export annotations from the document
12 const annots = await annotationManager.exportAnnotations();
13
14 // Run PDFNet methods with memory management
15 await PDFNet.runWithCleanup(async () => {
16
17 // lock the document before a write operation
18 // runWithCleanup will auto unlock when complete
19 doc.lock();
20
21 // import annotations to PDFNet
22 const fdf_doc = await PDFNet.FDFDoc.createFromXFDF(annots);
23 await doc.fdfUpdate(fdf_doc);
24
25 // flatten all annotations in the document
26 await doc.flattenAnnotations();
27
28 // or optionally only flatten forms
29 // await doc.flattenAnnotations(true);
30
31 // clear the original annotations
32 annotationManager.deleteAnnotations(annotationManager.getAnnotationsList());
33
34 // optionally only clear widget annotations if forms were only flattened
35 // const widgetAnnots = annots.filter(a => a instanceof Annotations.WidgetAnnotation);
36 // annotationManager.deleteAnnotations(widgetAnnots);
37 });
38
39 // clear the cache (rendered) data with the newly updated document
40 documentViewer.refreshAll();
41
42 // Update viewer to render with the new document
43 documentViewer.updateView();
44
45 // Refresh searchable and selectable text data with the new document
46 documentViewer.getDocument().refreshTextData();
47 });
48});

Flattening select annotations

Use the flatten method on annotation objects to flatten select annotations into the document.

1WebViewer({
2 fullAPI: true,
3 // other constructor options
4}, viewerElement).then(instance => {
5 const { documentViewer, PDFNet, annotManager } = instance.Core;
6
7 document.getElementById('myBtn').addEventListener('click', async () => {
8 await PDFNet.initialize();
9 const doc = await documentViewer.getDocument().getPDFDoc();
10
11 // export annotations from the document
12 const annots = await annotManager.exportAnnotations();
13
14 // Run PDFNet methods with memory management
15 await PDFNet.runWithCleanup(async () => {
16
17 // lock the document before a write operation
18 // runWithCleanup will auto unlock when complete
19 doc.lock();
20
21 // import annotations to PDFNet
22 const fdf_doc = await PDFNet.FDFDoc.createFromXFDF(annots);
23 await doc.fdfUpdate(fdf_doc);
24
25 const page = await doc.getPage(1);
26 const annotation = await page.getAnnot(0);
27 await annotation.flatten(page); //flatten this annotation
28
29 // clear the original annotations
30 annotManager.deleteAnnotations(annotManager.getAnnotationsList());
31
32 // import annotations from PDFNet
33 const fdfDoc = await doc.fdfExtract(PDFNet.PDFDoc.ExtractFlag.e_both);
34 const xfdf = await fdfDoc.saveAsXFDFAsString();
35 annotManager.importAnnotations(xfdf);
36 });
37
38 // clear the cache (rendered) data with the newly updated document
39 documentViewer.refreshAll();
40
41 // Update viewer to render with the new document
42 documentViewer.updateView();
43
44 // Refresh searchable and selectable text data with the new document
45 documentViewer.getDocument().refreshTextData();
46 });
47});

Did you find this helpful?

Trial setup questions?

Ask experts on Discord

Need other help?

Contact Support

Pricing or product questions?

Contact Sales