Flatten or Delete Fields Make field appearances a static part of a page or delete them

Introduction

Form fields are represented in a PDF document by widget annotations. This type of content is not part of a pages content stream and is defined outside of it. You can think of elements that were laid on top of a rendered page.

The SetaPDF-FormFiller component allows you to convert a form field appearance into a static part of a page. This process is called "flattening". 

It is also possible to flatten a static XFA form (as a whole). But it's not possible to flatten a dynamic XFA form.

Furthermore the component allows you to delete individual form fields from a PDF document. 

Flatten Specific Form Fields

Each field instance offers a flatten() method that allows you to merge the field appearance into its pages content stream. It's also possible to delegate this by the fields instance: 

PHP
<?php
require_once('library/SetaPDF/Autoload.php');

// setup a document instance
$writer = new \SetaPDF_Core_Writer_Http('flattened-field.pdf', true);
$document = \SetaPDF_Core_Document::loadByFilename(
    'files/pdfs/tektown/Order-Form.pdf', $writer
);

// get a form filler instance
$formFiller = new \SetaPDF_FormFiller($document);

// get access to the fields
$fields = $formFiller->getFields();

// get the field instance
$field = $fields->get('Name');

// set a new field value
$field->setValue('Test Person');

// flatten the field
$field->flatten();

// or
// $fields->flatten('Name');

// save the document
$document->save()->finish();

After flatten a form field it will automatically be deleted from the fields collection.

If the form is a static XFA form it is not possible to delete a single field but only all fields through the fields instance. If you try to call the flatten() method on such a field an BadMethodCallException will be thrown. 

You shall not flatten or delete a form field if you iterate over the fields instance!  

If you need to iterate over the fields while need to flatten their appearances you should iterate over their names instead: 

PHP
$names = $fields->getNames();
foreach ($names AS $name) {
    $fields->get($name)->flatten();
}

If the form holds same named form fields each appearance has to be flattened individually. A flatten() call will not be forward to other same named fields. 

Flatten All Form Fields

As already seen the fields instance also offers a flatten() method. This method can be used to flatten a specific form field by passing its instance or name to it. If the method is called without an argument all found form fields will get flattened: 

PHP
<?php
require_once('library/SetaPDF/Autoload.php');

// setup a document instance
$writer = new \SetaPDF_Core_Writer_Http('flattened-fields.pdf', true);
$document = \SetaPDF_Core_Document::loadByFilename(
    'files/pdfs/lenstown/Order-Form.pdf', $writer
);

// get a form filler instance
$formFiller = new \SetaPDF_FormFiller($document);

// get access to the fields
$fields = $formFiller->getFields();

// set some field values
$fields['Name']->setValue('Test Person');
$fields['Company Name']->setValue('Test Company');
// ...

// flatten all fields
$fields->flatten();

// save the document
$document->save()->finish();

If there are no fields left after a flatten process  the function will remove the AcroForm entry from the documents catalog as well. This will also be done if the form is a static XFA form, which results in loosing the complete XFA structure.  

If you want to flatten the whole form, you should instruct the SetaPDF-FormFiller component to remove possible XFA data before you touch any field. This will prohibit the whole XML handling overhead and will speed things up:

PHP
// get a form filler instance
$formFiller = new \SetaPDF_FormFiller($document);
// instruct the form filler to remove any XFA data (if available)
$formFiller->setRemoveXfaInformation(true);

// ...fill fields without the XML handling overhead

// flatten all fields
$fields->flatten();

// save the document
$document->save()->finish();

Rendering Issues

The flattening function will simply move a form field appearance stream into the pages content stream. So a proper rendered version of the form field is needed to get the desirable result.

Flattening in combination with an active render flag could result in unexpected results because the component may not be able to render all glyphs correctly but the Reader does. So the flattened version will look different to the version the Reader displays/renders.

If you need to support several foreign languages and the flattening function you should always provide a separate font for the field appreance.

Delete Form Fields

The process for deleting form fields is nearly identical to the flatten process but you will just need to call the delete() method of a field instance or delegate this by the delete() method of the fields instance: 

PHP
$fields = $formFiller->getFields();

$field = $fields->get('Surname');
$field->delete();
// or
$fields->delete('Surname');

// or all fields
$fields->delete();

Deletion of fields of an XFA form is also only possible by delting all fields through the fields instance.  

You shall not delete a form field if you iterate over the fields instance!

If you need to iterate over the fields while need to delete a field you should iterate over their names instead.