pypdf icon indicating copy to clipboard operation
pypdf copied to clipboard

Can't Fill PDFs without /DR dictionary

Open BrooksWatson717 opened this issue 1 month ago • 0 comments

I am trying to fill out a PDF form, but running into an issue where the /Font dictionary is not populated, so nothing can be written to the PDF.

Environment

Which environment were you using when you encountered the problem?

$ python -m platform
macOS-14.4.1-arm64-arm-64bit


$ python -c "import pypdf;print(pypdf._debug_versions)"
pypdf==4.2.0, crypt_provider=('pycryptodome', '3.20.0'), PIL=none

Code + PDF

This is a minimal, complete example that shows the issue:

from pypdf import PdfReader, PdfWriter
from pypdf.constants import AnnotationDictionaryAttributes

reader = PdfReader("modified_example.pdf")
writer = PdfWriter()
writer.append(reader)
fields = []
for page in reader.pages:
    writer.reattach_fields(page)
    for annot in page.annotations:
        annot = annot.get_object()
        if annot[AnnotationDictionaryAttributes.Subtype] == "/Widget":
            fields.append(annot)
            if annot['/FT'] == "/Tx":
                fieldName = annot["/T"]
                writer.update_page_form_field_values(
                    writer.pages[page.page_number],
                    {fieldName: "Brooks"},
                    auto_regenerate=False,
                )

with open("test2.pdf", "wb") as output_stream:
    writer.write(output_stream)

Share here the PDF file(s) that cause the issue. The smaller they are, the better. Let us know if we may add them to our tests!

f1040.pdf

Traceback

This is the complete traceback I see:

Traceback (most recent call last):
  File "/Users/brooks.watson/PdfGenerator/PyPdfTest.py", line 16, in <module>
    writer.update_page_form_field_values(
  File "/Users/brooks.watson/PdfGenerator/venv/lib/python3.9/site-packages/pypdf/_writer.py", line 977, in update_page_form_field_values
    self._update_field_annotation(writer_parent_annot, writer_annot)
  File "/Users/brooks.watson/PdfGenerator/venv/lib/python3.9/site-packages/pypdf/_writer.py", line 800, in _update_field_annotation
    dr = dr.get_object().get("/Font", DictionaryObject()).get_object()
AttributeError: 'dict' object has no attribute 'get_object'

Process finished with exit code 1

For reference, adding the following code to the _writer.py file fixes the issue:

        # Retrieve font information from local DR ...
        # Original code
        dr: Any = cast(
            DictionaryObject,
            cast(
                DictionaryObject,
                anno.get_inherited(
                    "/DR",
                    cast(
                        DictionaryObject, self.root_object[CatalogDictionary.ACRO_FORM]
                    ).get("/DR", DictionaryObject()),
                ),
            ).get_object(),
        )

        # New Code
        if "/Font" not in dr or not isinstance(dr["/Font"], DictionaryObject):
            dr[NameObject("/Font")] = DictionaryObject()

        font_dict = dr["/Font"]

        # Check if the specific font (e.g., Helvetica) is in /Font
        font_name = NameObject("/Helvetica")
        if font_name not in font_dict:
            font_entry = DictionaryObject({
                NameObject("/Type"): NameObject("/Font"),
                NameObject("/Subtype"): NameObject("/Type1"),
                NameObject("/BaseFont"): NameObject("/Helvetica"),
                NameObject("/Encoding"): NameObject("/WinAnsiEncoding")
            })
            font_dict[font_name] = font_entry

        #Original code
        dr = dr.get("/Font", DictionaryObject()).get_object()

BrooksWatson717 avatar May 22 '24 15:05 BrooksWatson717