From 722eba8f3b0029da0a3d6e2035df49d9210165a5 Mon Sep 17 00:00:00 2001 From: Jose Venceslau Date: Tue, 23 Apr 2024 14:16:20 +0100 Subject: [PATCH 1/2] write_fill_pdf flatten parameter now preserves multiline edit fields write_fill_pdf flatten option must set first bit of /Ff field but must preserve the other bits. Form fields with multiline option (bitmask 4096) where being transformed into single line by setting /Ff to 1. See https://stackoverflow.com/questions/68119744/python-how-to-properly-fill-a-multiline-text-field-in-pdf-form-using-pdfrw and https://opensource.adobe.com/dc-acrobat-sdk-docs/pdfstandards/pdfreference1.4.pdf, page 552 for a description of /Ff bitmask --- fillpdf/fillpdfs.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/fillpdf/fillpdfs.py b/fillpdf/fillpdfs.py index 0907eb7..6a66ec5 100644 --- a/fillpdf/fillpdfs.py +++ b/fillpdf/fillpdfs.py @@ -198,6 +198,7 @@ def write_fillable_pdf(input_pdf_path, output_pdf_path, data_dict, flatten=False data_dict = convert_dict_values_to_string(data_dict) template_pdf = pdfrw.PdfReader(input_pdf_path) + flatten_mask = 1 for Page in template_pdf.pages: if Page[ANNOT_KEY]: for annotation in Page[ANNOT_KEY]: @@ -290,8 +291,10 @@ def write_fillable_pdf(input_pdf_path, output_pdf_path, data_dict, flatten=False target.update( pdfrw.PdfDict( V=data_dict[key], AP=data_dict[key]) ) if target[ANNOT_FIELD_KIDS_KEY]: target[ANNOT_FIELD_KIDS_KEY][0].update( pdfrw.PdfDict( V=data_dict[key], AP=data_dict[key]) ) + if int(target["/Ff"]) > 0: + flatten_mask |= int(target["/Ff"]) if flatten == True: - annotation.update(pdfrw.PdfDict(Ff=1)) + annotation.update(pdfrw.PdfDict(Ff=flatten_mask)) template_pdf.Root.AcroForm.update(pdfrw.PdfDict(NeedAppearances=pdfrw.PdfObject('true'))) pdfrw.PdfWriter().write(output_pdf_path, template_pdf) @@ -591,4 +594,4 @@ def get_coordinate_map(input_pdf_path, output_map_path, page_number=1, **kwargs) page.insert_text(fitz.Point(x , 12), str(x), fontsize=12, fontname="times-bold", color=(1, 0, 0)) page.draw_line(fitz.Point(x , 12), fitz.Point(x , max_y), color=(1, 0, 0)) - doc.save(output_map_path, **kwargs) \ No newline at end of file + doc.save(output_map_path, **kwargs) From 2e57590c2d422ff1b93a05d0e14e351551b729d3 Mon Sep 17 00:00:00 2001 From: Jose Venceslau Date: Tue, 23 Apr 2024 16:58:10 +0100 Subject: [PATCH 2/2] write_fillable_pdf has aditional parameter, fontinfo Additional field in write_fillable_pdf has addition fontinfo parameter. None by default, uses PDF DA format, as example 'Arial 8.00 Tf 0 g' and changes the edit fields to this font, instead of the font present in the pdf template. --- fillpdf/fillpdfs.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/fillpdf/fillpdfs.py b/fillpdf/fillpdfs.py index 6a66ec5..2c4a673 100644 --- a/fillpdf/fillpdfs.py +++ b/fillpdf/fillpdfs.py @@ -177,7 +177,7 @@ def convert_dict_values_to_string(dictionary): return res -def write_fillable_pdf(input_pdf_path, output_pdf_path, data_dict, flatten=False): +def write_fillable_pdf(input_pdf_path, output_pdf_path, data_dict, flatten=False, fontinfo=None): """ Writes the dictionary values to the pdf. Currently supports text and buttons. Does so by updating each individual annotation with the contents of the dat_dict. @@ -192,6 +192,8 @@ def write_fillable_pdf(input_pdf_path, output_pdf_path, data_dict, flatten=False flatten: bool Default is False meaning it will stay editable. True means the annotations will be uneditable. + fontinfo: str + Default is None to preserve template font. Example of fontinfo to change text fields: Arial 8.00 Tf 0 g Returns --------- """ @@ -199,6 +201,13 @@ def write_fillable_pdf(input_pdf_path, output_pdf_path, data_dict, flatten=False template_pdf = pdfrw.PdfReader(input_pdf_path) flatten_mask = 1 + if fontinfo: + PDF_TEXT_APPEARANCE = ( + pdfrw.objects.pdfstring.PdfString.encode( + '/'+fontinfo + ) + ) + for Page in template_pdf.pages: if Page[ANNOT_KEY]: for annotation in Page[ANNOT_KEY]: @@ -293,6 +302,8 @@ def write_fillable_pdf(input_pdf_path, output_pdf_path, data_dict, flatten=False target[ANNOT_FIELD_KIDS_KEY][0].update( pdfrw.PdfDict( V=data_dict[key], AP=data_dict[key]) ) if int(target["/Ff"]) > 0: flatten_mask |= int(target["/Ff"]) + if fontinfo: + target.update({"/DA": PDF_TEXT_APPEARANCE}) if flatten == True: annotation.update(pdfrw.PdfDict(Ff=flatten_mask)) template_pdf.Root.AcroForm.update(pdfrw.PdfDict(NeedAppearances=pdfrw.PdfObject('true')))