Skip to content

Conversation

@Kaos599
Copy link

@Kaos599 Kaos599 commented Dec 27, 2025

This PR implements basic support for interactive PDF form fields (AcroForms), specifically TextField and Checkbox.

Key changes:

  • Added text_field() and checkbox() methods to the FPDF class.
  • Implemented appearance stream generation for all form fields to ensure they are visible across all PDF readers (Adobe, Chrome, Firefox, etc.) without requiring dynamic generation by the viewer.
  • Added a new internal module fpdf/forms.py to handle form field logic and XObject appearance streams.
  • Introduced FieldFlag in fpdf/enums.py for managing field properties like ReadOnly, Required, Multiline, etc.
  • Updated fpdf/output.py to automatically construct the global AcroForm dictionary and manage default resources (/DR) for standard fonts.

Fixes #257

Checklist:

  • A unit test is covering the code added / modified by this PR

  • In case of a new feature, docstrings have been added, with also some documentation in the docs/ folder

  • A mention of the change is present in CHANGELOG.md

  • This PR is ready to be merged

By submitting this pull request, I confirm that my contribution is made under the terms of the GNU LGPL 3.0 license.

- Added support for TextField and Checkbox with appearance stream generation.
- Introduced FieldFlag IntFlag enum for form field properties.
- Added text_field() and checkbox() methods to FPDF class.
- Implemented automatic AcroForm dictionary generation in PDF catalog.
- Ensured cross-reader compatibility by providing pre-rendered appearance XObjects.
- Created docs/Forms.md with comprehensive usage examples and API details.
- Updated docs/indexdocs: add documentation and changelog for interactive forms

- Created docs/Forms.md with comprehensive usage examples and API details.
- Updated docs/index
Copilot AI review requested due to automatic review settings December 27, 2025 14:12
@Kaos599
Copy link
Author

Kaos599 commented Dec 27, 2025

hey @Lucas-C i have tried to resolve this issue with this PR.

Sorry it took time.

here is sample output that i am getting right now
test_form_output.pdf

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR implements basic support for interactive PDF form fields (AcroForms), enabling users to create fillable forms with text fields and checkboxes. The implementation includes appearance stream generation to ensure cross-viewer compatibility without requiring dynamic appearance generation by the PDF reader.

Key changes:

  • Added text_field() and checkbox() methods to the FPDF class for creating interactive form fields
  • Implemented a new internal module fpdf/forms.py with TextField and Checkbox classes that generate their own appearance streams
  • Extended the FieldFlag enum in fpdf/enums.py to support form field properties like read-only, required, multiline, and password masking
  • Updated fpdf/output.py to automatically build the AcroForm dictionary and manage default resources for standard fonts

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 11 comments.

Show a summary per file
File Description
test/forms/test_forms.py Test/demo script for form fields (contains hardcoded paths and doesn't follow test conventions)
fpdf/forms.py New internal module implementing FormField, TextField, and Checkbox classes with appearance stream generation
fpdf/fpdf.py Added public API methods text_field() and checkbox() for creating interactive form fields
fpdf/output.py Extended AcroForm class and modified _finalize_catalog() to build form dictionary with default resources
fpdf/enums.py Added FieldFlag enum with flags for common field properties and type-specific behaviors
docs/Forms.md New documentation page explaining how to use interactive forms with examples
docs/index.md Added link to Forms documentation
CHANGELOG.md Added entry documenting the new AcroForms feature

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

"/ZaDb <</Type /Font /Subtype /Type1 /BaseFont /ZapfDingbats>>"
">>>>"
)
default_appearance = "(/Helv 0 Tf 0 g)"
Copy link

Copilot AI Dec 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The default_appearance string has a syntax error: it includes an opening parenthesis ( at the start but this should not be there. According to PDF specification, the default appearance string (DA) should be a valid PDF content stream fragment, typically something like /Helv 0 Tf 0 g. The parenthesis makes this invalid PDF syntax. This should be changed to just "/Helv 0 Tf 0 g" without the parenthesis.

Suggested change
default_appearance = "(/Helv 0 Tf 0 g)"
default_appearance = "/Helv 0 Tf 0 g"

Copilot uses AI. Check for mistakes.
- Remove unused imports (PDFObject, AnnotationFlag, DEFAULT_ANNOT_FLAGS) in fpdf/forms.py.

- Remove hardcoded font object reference "2 0 R" in TextField appearance streams to rely on global AcroForm resources.

- Document bit-flag sharing between RICH_TEXT and RADIOS_IN_UNISON in FieldFlag per PDF specification.

- Completely refactor test/forms/test_forms.py to follow pytest conventions:

    - Use tmprefactor: cleanup AcroForms implementation and improve test suite
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 4 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

- Add documentation for d_a (default appearance) property in TextField
  and Checkbox classes explaining the PDF content stream fragment format.
- Add clarifying comments for default_appearance in output.py explaining
  that parentheses are required per PDF spec 12.7.3.3.
- Document why hasattr checks are used for appearance XObjects in
  _add_annotations_as_objects (different field types have different attrs).
- Update test_forms.py to use assert_pdf_equal for proper regression testing
  instead of simple file existence checks.
- Add 7 reference PDFs for form field tests:
  - text_field_basic.pdf
  - text_field_multiline.pdf
  - text_field_readonly.pdf
  - checkbox_unchecked.pdf
  - checkbox_checked.pdf
  - checkbox_readonly.pdf
  - form_multiple_fields.pdf
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you planning on also implementing other field types (push buttons, choice...)?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes i do!

For the initial PR i wanted to push basic changes to gather feedback and see if i am going in the right direction

"/Helv <</Type /Font /Subtype /Type1 /BaseFont /Helvetica /Encoding /WinAnsiEncoding>> "
"/ZaDb <</Type /Font /Subtype /Type1 /BaseFont /ZapfDingbats>>"
">>>>"
)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure having a hardcoded resource dictionary with /Helv /ZaDb is the best approach - tapping into the main FPDF resources (or at least the ResourceCatalog) will give you much more choices and flexibility, including user added/TTF fonts.

@andersonhc
Copy link
Collaborator

Hi @Kaos599 ,
Thank you for the PR, it looks very promising!
I tested one of your reference files - opening in Chrome I see the form fields, but Acrobat Reader doesn't show them.
Unfortunately I will have very little free time this week, but as soon as possible I'll try to take a better look and give you some suggestions on the general API for the forms.

@Kaos599
Copy link
Author

Kaos599 commented Dec 30, 2025

@andersonhc thanks for the review!

I would also be a little busy this weekend but i will try to implement the feedback and more functionality whenever i get time

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

New feature: generate PDF forms

2 participants