> For the complete documentation index, see [llms.txt](https://docs.apryse.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.apryse.com/web/annotation/flatten-annotations.md).

# Flatten PDF annotations using JavaScript

Here is your guide explaining how to flatten annotation in viewer, how to flatten selected annotation and how to get PDF data with flattened annotation

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](https://showcase.apryse.com/flatten-form).

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](https://sdk.apryse.com/api/web/Core.Annotations.Annotation.html) for more details.

Flattening annotations can be performed when [getting the PDF file data](#flattening-annotations-when-getting-pdf-data) or while [downloading the PDF file locally](#flattening-annotations-when-downloading-pdf). There is also the option to [flatten select annotations](#flatten-select-annotations).

## Flattening annotations when getting PDF data

{% hint style="warning" %}
Make sure you have [Full API enabled in WebViewer.](/web/what-is-webviewer/full-api.md)
{% endhint %}

Use the [getFileData](https://sdk.apryse.com/api/web/Core.Document.html#getFileData__anchor) method and the `flatten` option for the annotations to be flattened in the document output when getting the data for uploading to a server.

{% hint style="info" %}
**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.
{% endhint %}

{% tabs %}
{% tab title="JavaScript (SDK v8.0+)" %}
{% code lineNumbers="true" %}

```js
WebViewer({
  fullAPI: true,
  // other constructor options
}, viewerElement).then(instance => {
  const { documentViewer, annotationManager } = instance.Core;

  document.getElementById('myBtn').addEventListener('click', async () => {
    const doc = documentViewer.getDocument();
    const xfdfString = await annotationManager.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
  });
});
```

{% endcode %}

[WebViewerInstance](https://sdk.apryse.com/api/web/WebViewerInstance.html) [Core](https://sdk.apryse.com/api/web/Core.html) [DocumentViewer.getDocument](https://sdk.apryse.com/api/web/Core.DocumentViewer.html#getDocument__anchor) [AnnotationManager.exportAnnotations](https://sdk.apryse.com/api/web/Core.AnnotationManager.html#exportAnnotations__anchor) [Document.getFileData](https://sdk.apryse.com/api/web/Core.Document.html#getFileData__anchor)
{% endtab %}

{% tab title="JavaScript (SDK v6.0+)" %}
{% code lineNumbers="true" %}

```js
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
  });
});
```

{% endcode %}

[WebViewerInstance](https://sdk.apryse.com/api/web/WebViewerInstance.html) [DocumentViewer.getDocument](https://sdk.apryse.com/api/web/Core.DocumentViewer.html#getDocument__anchor) [AnnotationManager.exportAnnotations](https://sdk.apryse.com/api/web/Core.AnnotationManager.html#exportAnnotations__anchor) [Document.getFileData](https://sdk.apryse.com/api/web/Core.Document.html#getFileData__anchor)
{% endtab %}
{% endtabs %}

## Flattening annotations when downloading PDF

{% hint style="warning" %}
Make sure you have [Full API enabled in WebViewer.](/web/what-is-webviewer/full-api.md)
{% endhint %}

Use the [downloadPdf](https://sdk.apryse.com/api/web/UI.html#downloadPdf__anchor) method and the `flatten` option for the annotations to be flattened in the document output when downloading the PDF locally.

{% hint style="info" %}
**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.
{% endhint %}

{% tabs %}
{% tab title="JavaScript (SDK v8.0+)" %}
{% code lineNumbers="true" %}

```js
WebViewer({
  fullAPI: true,
  // other constructor options
}, viewerElement).then(instance => {

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

{% endcode %}

[WebViewerInstance.UI.downloadPdf](https://sdk.apryse.com/api/web/UI.html#downloadPdf__anchor)
{% endtab %}

{% tab title="JavaScript (SDK v6.0+)" %}
{% code lineNumbers="true" %}

```js
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,
    });
  });
});
```

{% endcode %}

[WebViewerInstance.downloadPdf](https://sdk.apryse.com/api/web/UI.html#downloadPdf__anchor)
{% endtab %}
{% endtabs %}

## Flattening annotations in the viewer

{% hint style="warning" %}
Make sure you have [Full API enabled in WebViewer.](/web/what-is-webviewer/full-api.md)
{% endhint %}

Use [flattenAnnotations](https://sdk.apryse.com/api/web/Core.PDFNet.PDFDoc.html#flattenAnnotations) method to flatten all annotations into a document.

{% tabs %}
{% tab title="JavaScript (SDK v8.0+)" %}
{% code lineNumbers="true" %}

```js
WebViewer({
  fullAPI: true,
  // other constructor options
}, viewerElement).then(instance => {
  const { documentViewer, PDFNet, annotationManager } = instance.Core;

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

    // export annotations from the document
    const annots = await annotationManager.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
      annotationManager.deleteAnnotations(annotationManager.getAnnotationsList());

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

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

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

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

{% endcode %}

[Core](https://sdk.apryse.com/api/web/Core.html) [DocumentViewer.getDocument](https://sdk.apryse.com/api/web/Core.DocumentViewer.html#getDocument__anchor) [Document.getPDFDoc](https://sdk.apryse.com/api/web/Core.Document.html#getPDFDoc__anchor) [PDFDoc.flattenAnnotations](https://sdk.apryse.com/api/web/Core.PDFNet.PDFDoc.html#flattenAnnotations)
{% endtab %}

{% tab title="JavaScript (SDK v6.0+)" %}
{% code lineNumbers="true" %}

```js
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();
  });
});
```

{% endcode %}

[WebViewerInstance](https://sdk.apryse.com/api/web/WebViewerInstance.html) [DocumentViewer.getDocument](https://sdk.apryse.com/api/web/Core.DocumentViewer.html#getDocument__anchor) [Document.getPDFDoc](https://sdk.apryse.com/api/web/Core.Document.html#getPDFDoc__anchor) [PDFDoc.flattenAnnotations](https://sdk.apryse.com/api/web/Core.PDFNet.PDFDoc.html#flattenAnnotations)
{% endtab %}
{% endtabs %}

## Flattening select annotations

{% hint style="warning" %}
Make sure you have [Full API enabled in WebViewer.](/web/what-is-webviewer/full-api.md)
{% endhint %}

Use the [flatten](https://sdk.apryse.com/api/web/Core.PDFNet.Annot.html#flatten__anchor) method on annotation objects to flatten select annotations into the document.

{% tabs %}
{% tab title="JavaScript (SDK v8.0+)" %}
{% code lineNumbers="true" %}

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

  document.getElementById('myBtn').addEventListener('click', async () => {
    await PDFNet.initialize();
    const doc = await documentViewer.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
    documentViewer.refreshAll();

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

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

{% endcode %}

[Core](https://sdk.apryse.com/api/web/Core.html) [DocumentViewer.getDocument](https://sdk.apryse.com/api/web/Core.DocumentViewer.html#getDocument__anchor) [Document.getPDFDoc](https://sdk.apryse.com/api/web/Core.Document.html#getPDFDoc__anchor) [PDFDoc.getPage](https://sdk.apryse.com/api/web/Core.PDFNet.PDFDoc.html#getPage__anchor) [Page.getAnnot](https://sdk.apryse.com/api/web/Core.PDFNet.Page.html#getAnnot__anchor) [Annot.flatten](https://sdk.apryse.com/api/web/Core.PDFNet.Annot.html#flatten__anchor)
{% endtab %}

{% tab title="JavaScript (SDK v6.0+)" %}
{% code lineNumbers="true" %}

```js
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();
  });
});
```

{% endcode %}

[WebViewerInstance](https://sdk.apryse.com/api/web/WebViewerInstance.html) [DocumentViewer.getDocument](https://sdk.apryse.com/api/web/Core.DocumentViewer.html#getDocument__anchor) [Document.getPDFDoc](https://sdk.apryse.com/api/web/Core.Document.html#getPDFDoc__anchor) [PDFDoc.getPage](https://sdk.apryse.com/api/web/Core.PDFNet.PDFDoc.html#getPage__anchor) [Page.getAnnot](https://sdk.apryse.com/api/web/Core.PDFNet.Page.html#getAnnot__anchor) [Annot.flatten](https://sdk.apryse.com/api/web/Core.PDFNet.Annot.html#flatten__anchor)
{% endtab %}
{% endtabs %}


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.apryse.com/web/annotation/flatten-annotations.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
