Some test text!

menu
Form flattenkeyboard_arrow_down

Flatten PDF forms using Javascript

Annotation or form flattening refers to the operation that changes active 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.

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.

By flattening and merging existing annotation appearances with page content, the original annotations are deleted from the PDF pages.

An alternative approach to annotation or form flattening is to set the annotation to ReadOnly. The ReadOnly property on the Annotation class enables this modification. If it's read only then it can't be edited or deleted.

To flatten annotations, you can perform this when getting the PDF file data or while downloading the PDF file locally. There is also the option to flatten select annotations.

linkGet PDF data with flattened annotations

Only available with the Full API

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.
WebViewer({
  fullAPI: true,
  // other constructor options
}, viewerElement).then(instance => {
  const { docViewer, annotManager } = instance;

  document.getElementById('myBtn').addEventListener('click', async () => {
    const doc = docViewer.getDocument();
    const xfdfString = await annotManager.exportAnnotations();
    const options = { xfdfString, flatten: true };
    const data = await doc.getFileData(options);
    const arr = new Uint8Array(data);
    const blob = new Blob([arr], { type: 'application/pdf' });
    // upload blob to your server
  });
});

linkDownload PDF locally with flattened annotations

Only available with the Full API

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.
WebViewer({
  fullAPI: true,
  // other constructor options
}, viewerElement).then(instance => {

  document.getElementById('myBtn').addEventListener('click', () => {
    // download pdf with all annotations flattened
    instance.downloadPdf({
      includeAnnotations: true,
      flatten: true,
    });
  });
});

linkFlatten annotations in the viewer

Only available with the Full API

Use flattenAnnotations method to flatten all annotations into a document.

WebViewer({
  fullAPI: true,
  // other constructor options
}, viewerElement).then(instance => {
  const { docViewer, PDFNet, annotManager } = instance;

  document.getElementById('myBtn').addEventListener('click', async () => {
    await PDFNet.initialize();
    const doc = await docViewer.getDocument().getPDFDoc();

    // export annotations from the document
    const annots = await annotManager.exportAnnotations();

    // Run PDFNet methods with memory management
    await PDFNet.runWithCleanup(async () => {

      // lock the document before a write operation
      // runWithCleanup will auto unlock when complete
      doc.lock(); 

      // import annotations to PDFNet
      const fdf_doc = await PDFNet.FDFDoc.createFromXFDF(annots);
      await doc.fdfUpdate(fdf_doc);

      // flatten all annotations in the document
      await doc.flattenAnnotations();

      // or optionally only flatten forms
      // await doc.flattenAnnotations(true);

      // clear the original annotations
      annotManager.deleteAnnotations(annotManager.getAnnotationsList());

      // optionally only clear widget annotations if forms were only flattened
      //const widgetAnnots = annots.filter(a => a instanceof Annotations.WidgetAnnotation);
      //annotManager.deleteAnnotations(widgetAnnots);
    });

    // clear the cache (rendered) data with the newly updated document
    docViewer.refreshAll();

    // Update viewer to render with the new document
    docViewer.updateView();

    // Refresh searchable and selectable text data with the new document
    docViewer.getDocument().refreshTextData();
  });
});

linkFlatten select annotations

Only available with the Full API

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

WebViewer({
  fullAPI: true,
  // other constructor options
}, viewerElement).then(instance => {
  const { docViewer, PDFNet, annotManager } = instance;

  document.getElementById('myBtn').addEventListener('click', async () => {
    await PDFNet.initialize();
    const doc = await docViewer.getDocument().getPDFDoc();

    // export annotations from the document
    const annots = await annotManager.exportAnnotations();

    // Run PDFNet methods with memory management
    await PDFNet.runWithCleanup(async () => {

      // lock the document before a write operation
      // runWithCleanup will auto unlock when complete
      doc.lock();

      // import annotations to PDFNet
      const fdf_doc = await PDFNet.FDFDoc.createFromXFDF(annots);
      await doc.fdfUpdate(fdf_doc);

      const page = await doc.getPage(1);
      const annotation = await page.getAnnot(0);
      await annotation.flatten(page); //flatten this annotation

      // clear the original annotations
      annotManager.deleteAnnotations(annotManager.getAnnotationsList());

      // import annotations from PDFNet
      const fdfDoc = await doc.fdfExtract(PDFNet.PDFDoc.ExtractFlag.e_both);
      const xfdf = await fdfDoc.saveAsXFDFAsString();
      annotManager.importAnnotations(xfdf);
    });

    // clear the cache (rendered) data with the newly updated document
    docViewer.refreshAll();

    // Update viewer to render with the new document
    docViewer.updateView();

    // Refresh searchable and selectable text data with the new document
    docViewer.getDocument().refreshTextData();
  });
});

Get the answers you need: Support

close

Free Trial

Get unlimited trial usage of PDFTron SDK to bring accurate, reliable, and fast document processing capabilities to any application or workflow.

Select a platform to get started with your free trial.

Unlimited usage. No email address required.

Join our live demo to learn about use cases & capabilities for WebViewer

Learn more
close