Skip to content

Annotation Flattener

AnnotationFlattener burns annotation appearances into the page content stream and removes the annotation objects, producing a static PDF. This is useful for locking down filled forms, finalizing review markup, or preparing documents for print.

use Phpdftk\Pdf\Toolkit\AnnotationFlattener;
// From file
$flattener = AnnotationFlattener::open('form.pdf');
// From string
$flattener = AnnotationFlattener::openString($pdfBytes);
// Encrypted PDF
$flattener = AnnotationFlattener::open('secured.pdf', password: 'secret');
$flattener->flattenAll()->save('flat.pdf');

Restrict to specific pages:

use Phpdftk\Pdf\Toolkit\PageSelector;
$flattener->flattenAll(PageSelector::pages(1, 2))->save('flat.pdf');

Flatten only specific annotation subtypes (PDF /Subtype values):

$flattener->flattenType('FreeText', 'Stamp')->save('flat.pdf');

A convenience method that flattens only Widget annotations (form fields):

$flattener->flattenForms()->save('flat-form.pdf');
// On specific pages
$flattener->flattenForms(PageSelector::range(1, 3))->save('flat-form.pdf');

For each annotation targeted for flattening:

  1. The annotation’s normal appearance stream (/AP /N) is located
  2. The appearance is positioned using the annotation’s /Rect and the appearance’s /BBox
  3. A transformation matrix maps the appearance BBox to the annotation Rect
  4. The appearance is invoked as an XObject (Do operator) in a new content stream appended to the page
  5. The annotation is removed from the page’s /Annots array

Annotations without an appearance stream are left unchanged.

AnnotationFlattener::open('reviewed.pdf')
->flattenType('Highlight', 'StrikeOut')
->flattenForms()
->save('finalized.pdf');
$bytes = $flattener->toBytes();
$flattener->getPageCount(); // int
$reader = $flattener->getReader(); // PdfReader