3
votes

Comment éditer un pdf éditable à l'aide de la bibliothèque pdfrw?

J'ai fait des recherches sur la façon de modifier un PDF à l'aide de Python et j'ai trouvé cet article:
Comment remplir les PDF remplissables avec Python

Cependant, il y a un problème une fois que le programme s'exécute et que vous ouvrez le PDF, le document n'est pas rempli uniquement lorsque vous cliquez sur les balises, il affiche les données et lorsque vous cliquez, il disparaît à nouveau. C'est un code que quelqu'un d'autre a écrit en ligne.

#! /usr/bin/python

import os
import pdfrw


INVOICE_TEMPLATE_PATH = 'invoice_template.pdf'
INVOICE_OUTPUT_PATH = 'invoice.pdf'


ANNOT_KEY = '/Annots'
ANNOT_FIELD_KEY = '/T'
ANNOT_VAL_KEY = '/V'
ANNOT_RECT_KEY = '/Rect'
SUBTYPE_KEY = '/Subtype'
WIDGET_SUBTYPE_KEY = '/Widget'


def write_fillable_pdf(input_pdf_path, output_pdf_path, data_dict):
    template_pdf = pdfrw.PdfReader(input_pdf_path)
    annotations = template_pdf.pages[0][ANNOT_KEY]
    for annotation in annotations:
        if annotation[SUBTYPE_KEY] == WIDGET_SUBTYPE_KEY:
            if annotation[ANNOT_FIELD_KEY]:
                key = annotation[ANNOT_FIELD_KEY][1:-1]
                if key in data_dict.keys():
                    annotation.update(
                        pdfrw.PdfDict(V='{}'.format(data_dict[key]))
                    )
    pdfrw.PdfWriter().write(output_pdf_path, template_pdf)


data_dict = {
   'business_name_1': 'Bostata',
   'customer_name': 'company.io',
   'customer_email': 'joe@company.io',
   'invoice_number': '102394',
   'send_date': '2018-02-13',
   'due_date': '2018-03-13',
   'note_contents': 'Thank you for your business, Joe',
   'item_1': 'Data consulting services',
   'item_1_quantity': '10 hours',
   'item_1_price': '$200/hr',
   'item_1_amount': '$2000',
   'subtotal': '$2000',
   'tax': '0',
   'discounts': '0',
   'total': '$2000',
   'business_name_2': 'Bostata LLC',
   'business_email_address': 'hi@bostata.com',
   'business_phone_number': '(617) 930-4294'
}

if __name__ == '__main__':
    write_fillable_pdf(INVOICE_TEMPLATE_PATH, INVOICE_OUTPUT_PATH, data_dict)


1 commentaires

même problème pour moi, as-tu trouvé une solution?


4 Réponses :


10
votes

Je suppose que si vous ajoutez le paramètre NeedAppearances, vous résoudrez votre problème:

template_pdf = pdfrw.PdfReader(TEMPLATE_PATH)
template_pdf.Root.AcroForm.update(pdfrw.PdfDict(NeedAppearances=pdfrw.PdfObject('true'))) 


1 commentaires

Je ne sais pas pourquoi il a été voté à la baisse. Votre solution a résolu le problème ci-dessus pour moi @Sergio Sanchez. Je vous remercie! Ceci a également été publié par TLK3 ici github.com/pmaupin/pdfrw/issues/84



4
votes

La mise à jour de la fonction d'écriture pour avoir les clés AP et V a résolu le problème pour moi dans l'aperçu

pdfrw.PdfDict(AP=data_dict[key], V=data_dict[key])


0 commentaires

2
votes

L'erreur vient du fait qu'aucun flux d'apparence n'est associé au champ, mais que vous l'avez créé d'une manière incorrecte. Vous venez d'attribuer et de diffuser dans le dictionnaire AP. Ce que vous devez faire est d'assigner un Xobject indirect à / N dans le dictionnaire / AP; et vous devez créer Xobject à partir de zéro. Le code doit ressembler à ceci:

from pdfrw import PdfWriter, PdfReader, IndirectPdfDict, PdfName, PdfDict

INVOICE_TEMPLATE_PATH = 'untitled.pdf'
INVOICE_OUTPUT_PATH = 'untitled-output.pdf'

field1value = 'im field_1 value'

template_pdf = PdfReader(INVOICE_TEMPLATE_PATH)
template_pdf.Root.AcroForm.Fields[0].V = field1value

#this depends on page orientation
rct = template_pdf.Root.AcroForm.Fields[0].Rect
hight = round(float(rct[3]) - float(rct[1]),2)
width =(round(float(rct[2]) - float(rct[0]),2)

#create Xobject
xobj = IndirectPdfDict(
            BBox = [0, 0, width, hight],
            FormType = 1,
            Resources = PdfDict(ProcSet = [PdfName.PDF, PdfName.Text]),
            Subtype = PdfName.Form,
            Type = PdfName.XObject
            )

#assign a stream to it
xobj.stream = '''/Tx BMC
BT
 /Helvetica 8.0 Tf
 1.0 5.0 Td
 0 g
 (''' + field1value + ''') Tj
ET EMC'''

#put all together
template_pdf.Root.AcroForm.Fields[0].AP = PdfDict(N = xobj)

#output to new file
PdfWriter().write(INVOICE_OUTPUT_PATH, template_pdf)

Remarque: Pour info: / Type, / FormType, / Resorces sont facultatifs (/ Resources est fortement recommandé).


0 commentaires

0
votes

Pour développer la réponse de Sergio ci-dessus, la ligne suivante:

template_pdf = pdfrw.PdfReader(input_pdf_path)

Doit être placée après cette ligne dans l'exemple de code de OP:

XXX


1 commentaires

Les réponses doivent être autonomes et non complémentaires à d'autres réponses. De plus, les informations que vous essayez d'ajouter ici se trouvent déjà à peu près dans la réponse d'origine. Étant donné que cette réponse originale a déjà reçu une approbation significative, ce qui signifie que son intention était probablement claire au départ, votre ajout est non seulement déplacé, mais quelque peu redondant.