Skip to content

Fill PDF forms⚓︎

PyPDFForm fills PDF forms from a mapping of field names to values. The library accepts this mapping as a Python dictionary. The CLI fill command accepts a YAML or JSON file or a set of field options.

Most fields use flat, non-nested values. Image and signature fields can also use nested CLI objects when you need per-field options such as preserve_aspect_ratio.

Filled forms stay editable by default. Pass readonly=True to the library's fill method, or add --readonly to the CLI fill command, to prevent further edits to the filled fields.

CLI input methods⚓︎

The fill command can read field values from a YAML or JSON file supplied with --file / -f:

test: test_1
check: true
test_2: test_2
check_2: false
test_3: test_3
check_3: true
pypdfform fill sample_template.pdf -f data.yaml -o output.pdf

Alternatively, pass the mapping directly by using each field name as an option:

pypdfform fill sample_template.pdf \
    --test test_1 \
    --check true \
    --test_2 test_2 \
    --check_2 false \
    --test_3 test_3 \
    --check_3 true \
    -o output.pdf

When --file and field options are supplied together, --file takes precedence.

Fill text field and checkbox⚓︎

Use string values for text fields and boolean values for checkboxes. The following example fills this PDF:

from PyPDFForm import PdfWrapper

filled = PdfWrapper("sample_template.pdf").fill(
    {
        "test": "test_1",
        "check": True,
        "test_2": "test_2",
        "check_2": False,
        "test_3": "test_3",
        "check_3": True,
    },
    readonly=False,  # optional, set to True to make the filled PDF form read-only
)

filled.write("output.pdf")
test: test_1
check: true
test_2: test_2
check_2: false
test_3: test_3
check_3: true
pypdfform fill sample_template.pdf -f data.yaml -o output.pdf

Fill radio button group⚓︎

A radio button group is a collection of radio buttons sharing the same name on a PDF form.

Fill each radio button group with the zero-based index of the option to select. The index must satisfy the choice-index bounds. For example, to fill this PDF:

from PyPDFForm import PdfWrapper

filled = PdfWrapper("sample_template_with_radio_button.pdf").fill(
    {
        "radio_1": 0,
        "radio_2": 1,
        "radio_3": 2,
    },
    readonly=False,  # optional, set to True to make the filled PDF form read-only
)

filled.write("output.pdf")
radio_1: 0
radio_2: 1
radio_3: 2
pypdfform fill sample_template_with_radio_button.pdf -f data.yaml -o output.pdf

Fill dropdown field⚓︎

A dropdown can be filled with either the zero-based option index or the option text. For example, to fill this PDF:

from PyPDFForm import PdfWrapper

filled = PdfWrapper("sample_template_with_dropdown.pdf").fill(
    {"dropdown_1": 1},
    readonly=False,  # optional, set to True to make the filled PDF form read-only
)

filled.write("output.pdf")

You can also specify a dropdown option by its string value:

from PyPDFForm import PdfWrapper

filled = PdfWrapper("sample_template_with_dropdown.pdf").fill(
    {"dropdown_1": "bar"},
    readonly=False,  # optional, set to True to make the filled PDF form read-only
)

filled.write("output.pdf")
dropdown_1: 1
dropdown_1: bar
pypdfform fill sample_template_with_dropdown.pdf -f data.yaml -o output.pdf
Note

If you fill a dropdown field with a string value that is not one of its existing options, the new value is added as the last option in the dropdown and automatically selected.

Choice-index validation⚓︎

Dropdown and radio indices must satisfy 0 <= index < option_count: zero selects the first option, and option_count - 1 selects the last. Negative indices and indices equal to or greater than the option count are rejected. A field with no options rejects every integer index. An empty dropdown can still accept a string, which adds and selects a new option.

The generated JSON schema enforces these integer bounds, and the CLI validates fill data against that schema. In the Python API, an out-of-range integer passed to fill() or assigned to pdf.widgets[name].value raises ValueError.

fill() checks both supplied and retained selections before applying values or pending field updates. If an index is invalid, existing widget values, queued updates, and PDF data remain unchanged. If you shorten a dropdown's choices, supply a valid replacement for any selection that is now out of range. This guarantee covers index validation; failures during later hook execution, image processing, or serialization are not rolled back.

Fill signature field⚓︎

A signature field can be filled with a handwritten signature image.

The examples below use this PDF and this signature image:

from PyPDFForm import PdfWrapper

signed = PdfWrapper("sample_template_with_signature.pdf").fill(
    {"signature": "sample_signature.png"},
    readonly=False,  # optional, set to True to make the filled PDF form read-only
)

signed.write("output.pdf")
from PyPDFForm import PdfWrapper

with open("sample_signature.png", "rb+") as sig:
    signed = PdfWrapper("sample_template_with_signature.pdf").fill(
        {"signature": sig},
        readonly=False,  # optional, set to True to make the filled PDF form read-only
    )

signed.write("output.pdf")
from PyPDFForm import PdfWrapper

with open("sample_signature.png", "rb+") as sig:
    signed = PdfWrapper("sample_template_with_signature.pdf").fill(
        {"signature": sig.read()},
        readonly=False,  # optional, set to True to make the filled PDF form read-only
    )

signed.write("output.pdf")

By default, PyPDFForm preserves a signature image's aspect ratio. To stretch the image to the field bounds, set the preserve_aspect_ratio property to False on the signature field:

from PyPDFForm import PdfWrapper

pdf = PdfWrapper("sample_template_with_signature.pdf")
pdf.widgets["signature"].preserve_aspect_ratio = False
pdf.fill(
    {"signature": "sample_signature.png"},
)

pdf.write("output.pdf")
signature: sample_signature.png
signature:
  path: sample_signature.png
  preserve_aspect_ratio: false
pypdfform fill sample_template_with_signature.pdf -f data.yaml -o output.pdf

Fill image field⚓︎

An image field accepts the same input types as a signature field: a file path, an open file object, or a bytes stream.

The examples below use this PDF and this image:

from PyPDFForm import PdfWrapper

filled = PdfWrapper("sample_template_with_image_field.pdf").fill(
    {"image_1": "sample_image.jpg"},
    readonly=False,  # optional, set to True to make the filled PDF form read-only
)

filled.write("output.pdf")
from PyPDFForm import PdfWrapper

with open("sample_image.jpg", "rb+") as img:
    filled = PdfWrapper("sample_template_with_image_field.pdf").fill(
        {"image_1": img},
        readonly=False,  # optional, set to True to make the filled PDF form read-only
    )

filled.write("output.pdf")
from PyPDFForm import PdfWrapper

with open("sample_image.jpg", "rb+") as img:
    filled = PdfWrapper("sample_template_with_image_field.pdf").fill(
        {"image_1": img.read()},
        readonly=False,  # optional, set to True to make the filled PDF form read-only
    )

filled.write("output.pdf")

Unlike signature fields, image fields are stretched to the field bounds by default. To preserve the original image aspect ratio, set the preserve_aspect_ratio property to True on the image field:

from PyPDFForm import PdfWrapper

pdf = PdfWrapper("sample_template_with_image_field.pdf")
pdf.widgets["image_1"].preserve_aspect_ratio = True
pdf.fill(
    {"image_1": "sample_image.jpg"},
)

pdf.write("output.pdf")
image_1: sample_image.jpg
image_1:
  path: sample_image.jpg
  preserve_aspect_ratio: true
pypdfform fill sample_template_with_image_field.pdf -f data.yaml -o output.pdf