# PDF forms

Use `NativeElixirPdfUtilities.Forms` to inspect, fill and flatten AcroForm
fields. HTML rendering creates these fields by default. An ordinary PDF with
printed lines or scanned boxes has no field names to fill; use `Stamp.text/3`
for explicit text placement in those documents.

## Generate and complete a form

```elixir
alias NativeElixirPdfUtilities.{Forms, HtmlToPdf}

html = """
<div>Your name: <input name="full_name"></div>
<div><input type="checkbox" name="consent"> I agree</div>
"""

{:ok, pdf} = HtmlToPdf.render(html)
{:ok, fields} = Forms.fields(pdf)
{:ok, completed} = Forms.fill(pdf, %{
  "full_name" => "Cees Kettenis",
  "consent" => true
})
{:ok, flattened} = Forms.flatten(completed)
File.write!("completed.pdf", flattened)
```

`fields/1` returns a list of maps with `:name`, `:type`, `:value`, `:choices`,
`:read_only`, `:export_values` and `:widgets`. Each widget has a one-based
`:page` and a `:rect` of `[left, bottom, right, top]` in PDF page coordinates.
Choice entries contain `:value` and `:label`. Checkbox values are booleans;
radio export values are strings.

## HTML field names and compatibility

Text inputs, textareas, checkboxes, radio buttons and single-selection selects
become interactive fields. Buttons remain static artwork. Use
`HtmlToPdf.render(html, forms: :static)` for the pre-0.18 behavior.

A nonempty HTML `name` becomes the field key. Otherwise the renderer generates
`TYPE_PAGENR_ELEMENT`, such as `TEXT_1_1`, `CHECKBOX_1_2`, `RADIO_2_1` or
`CHOICE_2_2`. Textareas use `TEXT`. Pages and element numbers start at 1.
The element number counts controls on that page in HTML document order after
pagination. CSS visual ordering does not change this order. The HTML `id`
attribute does not supply a field name.

All explicit names are reserved before assigning generated names. A generated
name that collides gains `_1`, `_2`, and so on until unique. Explicit duplicate
names fail, except for radio controls sharing a group name. Radio group values
must be distinct, nonempty, and different from the reserved `Off` state. At
most one radio control in a group may be checked. Select options require unique
values. HTML names cannot contain a period or NUL; periods separate nested
field names in existing PDFs.

Generated names can change when pagination changes. Supply `name` for keys
used by application code. Controls cannot span pages or repeat with the same
control identity in page furniture. HTML `disabled` makes a field read-only.
The HTML parser still supports its documented subset; HTML listboxes and
multiple-selection selects are not implemented.

Initial appearances use the rendered HTML styling. Text extraction reads page
content, so flatten fields first when you need their values included in
`Text.extract/2` output.

## Fill an existing PDF

```elixir
{:ok, original} = File.read("application.pdf")
{:ok, fields} = Forms.fields(original)
IO.inspect(fields)
{:ok, completed} = Forms.fill(original, %{"applicant.full_name" => "Cees Kettenis"})
```

Use the fully qualified names returned by inspection, including parent names
separated by periods. Repeated widgets of a field are updated together.
Unselected fields and unrelated annotations, metadata and page content remain
in place.

| Field type | Fill value |
| --- | --- |
| Single-line text | UTF-8 string without line breaks, or `nil` to clear |
| Multiline text | UTF-8 string with explicit line breaks, or `nil` to clear |
| Checkbox | `true` or `false` |
| Radio group | One declared export-value string |
| Single choice | One declared value, or `nil` to clear |
| Multiple choice | A list of distinct declared values, or `nil` to clear |

Multiple choice is supported for existing PDFs with the appropriate field flag.
Inspection includes declared choices and export values. Unknown names,
read-only fields, invalid selections and field `MaxLen` violations return
[diagnostics](diagnostics.md).

Filling generates text and choice appearances using bundled DejaVu Sans and
black text. Text shrinks to fit, up to 12 points, with a two-point inset.
Explicit line breaks are retained; automatic word wrapping is not performed.
PDF left, center and right alignment are respected. Missing glyphs and widgets
too small for the inset return diagnostics. Existing external font/style
instructions are replaced by this supported appearance style.

Checkbox and radio fills preserve their existing Off/on artwork. Fields
generated by this library retain their background and border artwork when
filled. Existing external text-field decorations inside an old appearance are
not reconstructed. All filled fields have self-contained appearances and do
not depend on a viewer regenerating them.

## Flatten selected fields

```elixir
{:ok, flat_name} = Forms.flatten(completed, fields: ["applicant.full_name"])
{:ok, filled_and_flat} = Forms.fill(original,
  %{"applicant.full_name" => "Cees Kettenis"}, flatten: true)
```

`flatten: true` flattens only the fields supplied to that fill call.
`Forms.flatten(pdf)` flattens all supported fields. `fields: []` selects none.
Flattening paints current appearances into page content, removes selected
widgets and prunes their field tree. Remaining fields stay interactive.
Appearance transforms, page rotation and existing resource names are preserved.
Flattening preserves screen visibility. Widgets marked Hidden or NoView are
removed without painting their appearances, including fields whose widgets
are all hidden. The Print flag does not change this screen policy;
print-only widgets are omitted and screen-only widgets become ordinary page
content. Invisible does not hide the supported Widget annotation type.
Missing or degenerate appearances on visible widgets return errors.

Updates are incremental. Earlier field values and attachments can remain in
historical revisions. Flattening removes active interactivity and is not secure
redaction.

## Unsupported structures

XFA, pushbuttons, signature operations, password/comb/rich-text fields,
editable combo boxes, field/widget actions and widget-specific rotation are
unsupported. Changing signed PDFs or PDFs with signature permissions is
rejected. Encrypted input follows the reader's existing rejection policy.
Malformed field trees, ambiguous names and widgets not uniquely associated
with a page fail with diagnostics. Automatic detection or conversion of drawn
or scanned forms is outside this API.

Selected fields and widgets with either primary `/A` or additional `/AA`
actions are rejected, including indirect actions and action chains. Inspection
and editing unrelated fields do not certify a PDF as safe to open. Filling,
flattening, merging and other edits are not document sanitization; applications
must apply their own policy to uploaded PDFs before distributing them.

See [resource limits](resource-limits.md#forms-and-attachments) for field,
appearance-object and byte budgets, and [attachments](pdf-attachments.md) for
embedding supporting files.
