PDF Forms: Read and Fill AcroForm Fields with Python
Interactive PDF forms (AcroForm) are common in official documentation, contracts, and applications. Python lets you read, fill, and create them automatically.
AcroForm Field Types
| Type | Description |
|---|---|
| TextField | Free text input |
| CheckBox | Check box |
| RadioButton | Radio button (group) |
| ComboBox | Dropdown list |
| ListBox | Multi-selection list |
| Signature | Digital signature field |
Read Form Fields with pypdf
pip install pypdf
from pypdf import PdfReader
reader = PdfReader("form.pdf")
# Text fields
fields = reader.get_form_text_fields()
for name, value in fields.items():
print(f" {name!r}: {value!r}")
# All field types
for name, field in reader.get_fields().items():
field_type = field.get('/FT', '?')
value = field.get('/V', '')
print(f" [{field_type}] {name}: {value}")
Fill an Existing Form
from pypdf import PdfReader, PdfWriter
reader = PdfReader("blank_form.pdf")
writer = PdfWriter()
writer.append(reader)
data = {
"full_name": "Maria Garcia",
"id_number": "12345678A",
"email": "maria@example.com",
"city": "Madrid",
}
for page in writer.pages:
writer.update_page_form_field_values(page, data)
with open("filled_form.pdf", "wb") as f:
writer.write(f)
print("Saved: filled_form.pdf")
Checkboxes and Radio Buttons
data = {
"name": "John Smith",
"accept_terms": "Yes", # Checkbox: "Yes" = checked
"gender": "/Male", # RadioButton: widget value
"country": "US", # ComboBox: option value
}
for page in writer.pages:
writer.update_page_form_field_values(page, data)
Create PDF Form from Scratch with reportlab
pip install reportlab
from reportlab.pdfgen import canvas
from reportlab.lib.pagesizes import A4
def create_form(output="new_form.pdf"):
c = canvas.Canvas(output, pagesize=A4)
width, height = A4
c.setFont("Helvetica-Bold", 18)
c.drawString(50, height - 60, "Registration Form")
c.setFont("Helvetica", 12)
c.drawString(50, height - 110, "Full Name:")
c.acroForm.textfield(name="full_name", x=200, y=height-120, width=300, height=20)
c.drawString(50, height - 150, "Email:")
c.acroForm.textfield(name="email", x=200, y=height-160, width=300, height=20)
c.drawString(50, height - 200, "Accept terms:")
c.acroForm.checkbox(name="accept_terms", x=210, y=height-210, buttonStyle="check")
c.drawString(50, height - 250, "Country:")
c.acroForm.choice(
name="country",
options=[("US","United States"),("GB","UK"),("CA","Canada"),("AU","Australia")],
x=200, y=height-260, width=200, height=20, value="US",
)
c.drawString(50, height - 300, "Gender:")
c.acroForm.radio(name="gender", tooltip="Male", x=200, y=height-310,
buttonStyle="circle", value="Male")
c.drawString(225, height - 305, "Male")
c.acroForm.radio(name="gender", tooltip="Female", x=300, y=height-310,
buttonStyle="circle", value="Female")
c.drawString(325, height - 305, "Female")
c.save()
print(f"Form created: {output}")
create_form()
Fill with pdfrw
pip install pdfrw
import pdfrw
def fill_pdfrw(input_path, output_path, data):
template = pdfrw.PdfReader(input_path)
for page in template.pages:
annotations = page.get('/Annots') or []
for a in annotations:
if a.get('/Subtype') == '/Widget' and a.get('/T'):
name = a['/T'][1:-1]
if name in data:
a.update(pdfrw.PdfDict(V=data[name], AP=''))
template.Root.AcroForm.update(pdfrw.PdfDict(NeedAppearances=pdfrw.PdfObject('true')))
pdfrw.PdfWriter().write(output_path, template)
print(f"Saved: {output_path}")
fill_pdfrw("template.pdf", "filled.pdf", {
"name": "Anna Torres",
"email": "anna@example.com",
})
Flatten the Form (Form to Static)
# Method 1: pypdf
from pypdf import PdfReader, PdfWriter
reader = PdfReader("filled_form.pdf")
writer = PdfWriter()
for page in reader.pages:
writer.add_page(page)
with open("flattened.pdf", "wb") as f:
writer.write(f)
# Method 2: Ghostscript (more faithful)
import subprocess
subprocess.run([
"gs", "-dNOPAUSE", "-dBATCH", "-sDEVICE=pdfwrite",
"-dFlattenForm", "-sOutputFile=flattened_gs.pdf", "filled_form.pdf"
], check=True)
Extract Data from Filled Form
from pypdf import PdfReader
import json
reader = PdfReader("filled_form.pdf")
extracted = {}
for name, field in reader.get_fields().items():
value = field.get('/V', '')
if hasattr(value, 'get_object'):
value = str(value.get_object())
extracted[name] = str(value) if value else ""
print(json.dumps(extracted, indent=2))
Tools for Creating Form Templates
| Tool | Type | AcroForm |
|---|---|---|
| Adobe Acrobat | Paid | Full |
| LibreOffice Draw | Free | Basic |
| PDFescape | Online | Free basic |
| reportlab | Python | Programmatic |
Convert Online
To fill or extract data from PDF forms without Python, KaijuConverter processes PDFs directly in the browser.
Related conversions
Document conversions that follow this topic naturally: