Skip to content
How to fill and flatten PDF forms

How to fill and flatten PDF forms

Filling writes values into the AcroForm and leaves the document interactive. Flattening draws the field appearances into the page content stream and deletes the fields. Most completed-form workflows do both, in that order.

fdata, err := fjson.LoadFromJSONFile("fill.json")
if err != nil {
    return err
}

fieldAppearance := annotator.FieldAppearance{
    OnlyIfMissing:        true,
    RegenerateTextFields: true,
}

if err := pdfReader.AcroForm.Fill(fdata); err != nil {
    return err
}
if err := pdfReader.FlattenFields(true, fieldAppearance); err != nil {
    return err
}

pdfWriter, err := pdfReader.ToWriter(&model.ReaderToWriterOpts{SkipAcroForm: true})
if err != nil {
    return err
}
return pdfWriter.WriteToFile("output.pdf")

The JSON is an array of {"name": ..., "value": ...} objects. fjson also goes the other way: fjson.LoadFromPDFFile produces the field list from a document, which is how you get the names right.

The appearance generator is the part that trips people up. A field holds its value in V, but a viewer draws the widget annotation’s appearance stream, not V. Fill does not generate appearances, so flattening a programmatically filled form with nil as the generator draws nothing and you get blank space where the values should be. OnlyIfMissing generates one for fields that lack it and leaves the rest alone; RegenerateTextFields overrides that for text fields, which is what you want after a fill, since any appearance already in the file was generated for the old value.

FillWithAppearance takes the same generator and does both steps at once, for when the output has to stay interactive rather than being flattened.

Flattening is destructive and cannot be undone within the same document: no values to read back, no export, no editing. Run it on a copy.

FlattenFields(true, ...) flattens every annotation on every page, not just form widgets. Pass false to leave the others alone, or use FlattenFieldsWithOpts with a FilterFunc to select fields by name. And flattening a signed document invalidates the signature, so flatten first, sign second.

See fill form fields, flatten form and fill and flatten with appearance.

Last updated on