1

I'm currently using the fillpdf Python library to fill a template PDF with generated data. I'm running this process on Ubuntu 20.04 server, trying to print to a Kyocera ECOSYS p4060dn.

An example of how I'm using the code:

import fillpdf
from fillpdf import fillpdfs

data_dict = {
        'Season1': '2025-2026',
        'Season2': '2025-26',
        'MemberName': 'Test',
        'Address': '123 Sesame St',
        'CityStateZip': 'Birmingham, AK 12345-6789',
        'Number': '9999999',
        'Level': '1'
    }

fillpdfs.write_fillable_pdf('/home/myuser/template.pdf', '/home/myuser/filled.pdf', data_dict, flatten=True)

This appears to work as intended, as when I copy the filled PDf to my Windows machine and open it, the fields are filled with the provided data.

However my issue is that when I try to print the PDF, it prints without the forms filled in. There are no cups errors in /var/log/cups/error_log related to the print, and access_log similarly looks all good.

I'm printing by using the command

lp -d [printer] /path/to/PDf

I have the printer setup with the right driver, and strangely if I fill the PDF on my windows machine and copy it up to the Ubuntu server then print, it prints just fine, fields filled and all.

I've tried using different libraries like PyPDF2, PyPDF, and pdfrw to fill the fields and flatten, all to the same result of the fields being filled but not printing with them filled, or occasionally no print at all.

Any guidance would be greatly appreciated

EDIT: The fields are set to print in Acrobat.

1
  • @KJ The fields are indeed set to print. The need appearances flag sounds like that could be the case, considering cups is printing straight to the printer and there's no 'reader' to process those fields. Will look into that next. Commented Sep 11 at 18:25

1 Answer 1

2

Thanks to KJ for pointing me in the right direction!

A coworker wrote up a different way to fill the fields using pdfrw, example below:

from pdfrw import PdfReader, PdfWriter, PdfDict, PdfObject, PdfName, PageMerge
from pdfrw.objects.pdfstring import PdfString

def fill_pdf_fields(input_path, output_path):
    pdf = PdfReader(input_path)

    # Ensure viewer regenerates appearances
    if not pdf.Root.AcroForm:
        pdf.Root.AcroForm = PdfDict(NeedAppearances=PdfObject('true'))
    else:
        pdf.Root.AcroForm.update(PdfDict(NeedAppearances=PdfObject('true')))

    for page in pdf.pages:
        annotations = page.Annots
        if annotations:
            for annot in annotations:
                if annot.Subtype == PdfName('Widget') and annot.T:
                    field_name = str(annot.T)[1:-1]


                    if field_name == "MemberName": annot.V = PdfObject(f'(Test)')
                    if field_name == "Address": annot.V = PdfObject(f'(123 Sesame St)')
                    if field_name == "CityStateZip": annot.V = PdfObject(f'(Birmingham, AK 12345-6789)')
                    if field_name == "Level": annot.V = PdfObject(f'(1)')
                    if field_name == "OfficialsNumber": annot.V = PdfObject(f'(9999999)')
                    if field_name == "Season2": annot.V = PdfObject(f'(2025-26)')
                    if field_name == "Season1": annot.V = PdfObject(f'(2025-2026)')


    PdfWriter().write(output_path, pdf)
    print(f"Filled PDF saved to: {output_path}")


def flatten_pdf_fields(input_path, output_path):
    template_pdf = PdfReader(input_path)

    for page in template_pdf.pages:
        annotations = page.Annots
        if annotations:
            for annot in annotations:
                if annot.Subtype == PdfName('Widget') and annot.T and annot.V:
                    # Remove interactive field appearance
                    annot.update({
                        PdfName('F'): PdfObject('4'),  # Make field read-only
                        PdfName('AP'): None  # Remove appearance stream
                    })

        # Flatten page by merging its own content (no overlay)
        PageMerge(page).render()

    PdfWriter(output_path, trailer=template_pdf).write()
    print(f"Flattened PDF saved to: {output_path}")


if __name__ == "__main__":
    fill_pdf_fields(template_pdf, filled_pdf)
    flatten_pdf_fields(filled_pdf, flattened_pdf)

I researched interactions with NeedAppearances, and found this Stack post:
NeedAppearances=pdfrw.PdfObject('true') forces manual pdf save in Acrobat Reader

The answer provides a code snippet that from what I can tell, acts as a reader generating those appearance streams so the filled in fields actually show their contents.

Code snippet for reference:

from pikepdf import Pdf

with Pdf.open('source_pdf.pdf') as pdf:
    pdf.generate_appearance_streams()
    pdf.save('output.pdf')
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.