Flatten PDF form fields in Angular

24 Jul 20266 minutes to read

Overview

Flattening PDF forms converts interactive fields such as textboxes, dropdowns, checkboxes, signatures, etc., into non‑editable page content. Use this when you want to protect filled data, finalize a document, or prepare it for secure sharing.

Prerequisites

  • EJ2 Angular PDF Viewer installed and configured
  • Basic viewer setup completed with toolbar and page organizer services injected. For more information, see getting started guide

Flatten forms before downloading PDF

  1. Add a ViewChild to the PdfViewerComponent so you can access viewer APIs from event handlers.
  2. Intercept the download flow using downloadStart and cancel the default flow.
  3. Retrieve the viewer’s blob via saveAsBlob() and convert the blob to base64.
  4. Use PdfDocument from Syncfusion PDF Library to open the document, set field.flatten = true for each form field, then save.
  5. To flatten the form fields when downloading through the Save As option in Page Organizer, repeat steps 2–4 by using pageOrganizerSaveAs event.

Complete example

import { Component, ViewChild } from '@angular/core';
import {
    PdfViewerComponent, Toolbar, Magnification, Navigation, Annotation, LinkAnnotation,
    ThumbnailView, BookmarkView, TextSelection, TextSearch, FormFields, FormDesigner,
    PageOrganizer, Print, PageOrganizerSaveAsEventArgs, DownloadStartEventArgs
} from '@syncfusion/ej2-angular-pdfviewer';
import { PdfDocument, PdfField } from '@syncfusion/ej2-pdf';

@Component({
    selector: 'app-root',
    standalone: true,
    imports: [PdfViewerComponent, Toolbar, Magnification, Navigation, Annotation, LinkAnnotation,
        ThumbnailView, BookmarkView, TextSelection, TextSearch, FormFields, FormDesigner, PageOrganizer, Print],
    template: `
        <div style="height: 640px">
            <ejs-pdfviewer
                #pdfViewer
                [documentPath]="'https://cdn.syncfusion.com/content/pdf/form-filling-document.pdf'"
                [resourceUrl]="'https://cdn.syncfusion.com/ej2/32.2.5/dist/ej2-pdfviewer-lib'"
                (downloadStart)="onDownloadStart($event)"
                (pageOrganizerSaveAs)="onPageOrganizerSaveAs($event)"
            >
            </ejs-pdfviewer>
        </div>
    `
})
export class AppComponent {
    @ViewChild('pdfViewer')
    public pdfViewer!: PdfViewerComponent;

    blobToBase64(blob: Blob): Promise<string> {
        return new Promise((resolve, reject) => {
            const reader = new FileReader();
            reader.onerror = () => reject(reader.error);
            reader.onload = () => {
                const dataUrl: string = reader.result as string;
                const data: string = dataUrl.split(',')[1];
                resolve(data);
            };
            reader.readAsDataURL(blob);
        });
    }

    flattenFormFields(data: string) {
        const document: PdfDocument = new PdfDocument(data);
        for (let index = 0; index < document.form.count; index++) {
            const field: PdfField = document.form.fieldAt(index);
            field.flatten = true;
        }
        // If both annotations and form fields needs to be flattened, use
        // document.flatten = true
        document.save(`${this.pdfViewer.fileName}.pdf`);
        document.destroy();
    }

    async handleFlattening(): Promise<void> {
        const blob: Blob = await this.pdfViewer.saveAsBlob();
        const data: string = await this.blobToBase64(blob);
        this.flattenFormFields(data);
    }

    onDownloadStart(args: DownloadStartEventArgs): void {
        args.cancel = true;
        this.handleFlattening();
    }

    onPageOrganizerSaveAs(args: PageOrganizerSaveAsEventArgs): void {
        args.cancel = true;
        this.handleFlattening();
    }
}

Expected result

  • The downloaded or “Save As” PDF will contain the visible appearance of filled form fields as static, non-editable content.
  • Form fields will no longer be interactive or editable in common PDF readers.

Troubleshooting

  • If pdfViewer is null, ensure #pdfViewer is present and the component has mounted before invoking saveAsBlob().
  • Missing resourceUrl: If viewer resources are not reachable, set resourceUrl to the correct CDN or local path for the ej2-pdfviewer-lib.