2017-11-14 29 views
0

pdfフォームを一括入力する必要がありますので、csvファイルから私のためにpythonコードを作成しようとしました。私はこのquestionの2番目の答えを使用し、フォームを正常に入力します。ただし、入力したフォームを開くと、対応するフィールドが選択されていないと回答が表示されません。また、フォームが印刷されたときの回答は表示されません。私は、生成されたフォームをフラット化できるかどうかをPyPDF2のドキュメントで調べましたが、この機能はまだ1年ほど前から依頼されていますが、実装されていません。私の好みはpdftkを使うのではなく、依存関係を必要とせずにスクリプトをコンパイルできます。上記の質問に元のコードを使用すると、いくつかのフィールドがプリントに表示され、いくつかのフィールドが表示されないため、どのように動作しているのか混乱することがあります。どんな助けもありがとうございます。PyPDF2で埋められたPDFフォームは印刷に表示されません

ここにコードがあります。

# -*- coding: utf-8 -*- 

from collections import OrderedDict 
from PyPDF2 import PdfFileWriter, PdfFileReader 


def _getFields(obj, tree=None, retval=None, fileobj=None): 
    """ 
    Extracts field data if this PDF contains interactive form fields. 
    The *tree* and *retval* parameters are for recursive use. 

    :param fileobj: A file object (usually a text file) to write 
    a report to on all interactive form fields found. 
    :return: A dictionary where each key is a field name, and each 
    value is a :class:`Field<PyPDF2.generic.Field>` object. By 
    default, the mapping name is used for keys. 
    :rtype: dict, or ``None`` if form data could not be located. 
    """ 
    fieldAttributes = {'/FT': 'Field Type', '/Parent': 'Parent', '/T': 'Field Name', '/TU': 'Alternate Field Name', 
        '/TM': 'Mapping Name', '/Ff': 'Field Flags', '/V': 'Value', '/DV': 'Default Value'} 
    if retval is None: 
     retval = {} #OrderedDict() 
     catalog = obj.trailer["/Root"] 
     # get the AcroForm tree 
     if "/AcroForm" in catalog: 
      tree = catalog["/AcroForm"] 
     else: 
      return None 
    if tree is None: 
     return retval 

    obj._checkKids(tree, retval, fileobj) 
    for attr in fieldAttributes: 
     if attr in tree: 
      # Tree is a field 
      obj._buildField(tree, retval, fileobj, fieldAttributes) 
      break 

    if "/Fields" in tree: 
     fields = tree["/Fields"] 
     for f in fields: 
      field = f.getObject() 
      obj._buildField(field, retval, fileobj, fieldAttributes) 

    return retval 


def get_form_fields(infile): 
    infile = PdfFileReader(open(infile, 'rb')) 
    fields = _getFields(infile) 
    return {k: v.get('/V', '') for k, v in fields.items()} 


def update_form_values(infile, outfile, newvals=None): 
    pdf = PdfFileReader(open(infile, 'rb')) 
    writer = PdfFileWriter() 

    for i in range(pdf.getNumPages()): 
     page = pdf.getPage(i) 
     try: 
      if newvals: 
       writer.updatePageFormFieldValues(page, newvals) 
      else: 
       writer.updatePageFormFieldValues(page, 
              {k: f'#{i} {k}={v}' 
               for i, (k, v) in 
enumerate(get_form_fields(infile).items()) 
               }) 
      writer.addPage(page) 
     except Exception as e: 
      print(repr(e)) 
      writer.addPage(page) 

    with open(outfile, 'wb') as out: 
     writer.write(out) 


if __name__ == '__main__': 
    import csv  
    import os 
    from glob import glob 
    cwd=os.getcwd() 
    outdir=os.path.join(cwd,'output') 
    csv_file_name=os.path.join(cwd,'formData.csv') 
    pdf_file_name=glob(os.path.join(cwd,'*.pdf'))[0] 
    if not pdf_file_name: 
     print('No pdf file found') 
    if not os.path.isdir(outdir): 
     os.mkdir(outdir) 
    if not os.path.isfile(csv_file_name): 
     fields=get_form_fields(pdf_file_name) 
     with open(csv_file_name,'w',newline='') as csv_file: 
      csvwriter=csv.writer(csv_file,delimiter=',') 
      csvwriter.writerow(['user label']) 
      csvwriter.writerow(['fields']+list(fields.keys())) 
      csvwriter.writerow(['Mr. X']+list(fields.values())) 
    else: 
     with open(csv_file_name,'r',newline='') as csv_file: 
      csvreader=csv.reader(csv_file,delimiter=',') 
      csvdata=list(csvreader) 
     fields=csvdata[1][1:] 
     for frmi in csvdata[2:]: 
      frmdict=dict(zip(fields,frmi[1:])) 
      outfile=os.path.join(outdir,frmi[0]+'.pdf') 
      update_form_values(pdf_file_name, outfile,frmdict) 

答えて

2

私は同じ問題を持っていたと明らかに(https://github.com/mstamy2/PyPDF2/issues/355を参照)AcroFormのPDFWriterのオブジェクトに「/ NeedsAppearance」属性を追加する問題を修正しました。 ademidun(https://github.com/ademidun)の助けを借りて、私はpdfフォームにデータを入力し、フィールドの値を適切に表示することができました。以下は例です:

enter code here 
from PyPDF2 import PdfFileWriter, PdfFileReader 
from PyPDF2.generic import BooleanObject, NameObject, IndirectObject 

def set_need_appearances_writer(writer: PdfFileWriter): 
    # See 12.7.2 and 7.7.2 for more information: 
    # http://www.adobe.com/content/dam/acom/en/devnet/acrobat/pdfs/PDF32000_2008.pdf 
    try: 
     catalog = writer._root_object 
     # get the AcroForm tree and add "/NeedAppearances attribute 
     if "/AcroForm" not in catalog: 
      writer._root_object.update({ 
       NameObject("/AcroForm"): IndirectObject(len(writer._objects), 0, writer)}) 

     need_appearances = NameObject("/NeedAppearances") 
     writer._root_object["/AcroForm"][need_appearances] = BooleanObject(True) 
     return writer 

    except Exception as e: 
     print('set_need_appearances_writer() catch : ', repr(e)) 
     return writer 

infile = "myInputPdf.pdf" 
outfile = "myOutputPdf.pdf" 

inputStream = open(infile, "rb") 
pdf_reader = PdfFileReader(inputStream), strict=False) 
if "/AcroForm" in pdf_reader.trailer["/Root"]: 
    pdf_reader.trailer["/Root"]["/AcroForm"].update(
     {NameObject("/NeedAppearances"): BooleanObject(True)}) 

pdf_writer = PdfFileWriter() 
set_need_appearances_writer(pdf_writer) 
if "/AcroForm" in pdf_writer._root_object: 
    pdf_writer._root_object["/AcroForm"].update(
     {NameObject("/NeedAppearances"): BooleanObject(True)}) 

field_dictionary = {"Field1": "Value1", "Field2": "Value2"} 

pdf_writer.addPage(pdf_reader.getPage(0)) 
pdf_writer.updatePageFormFieldValues(pdf_writer.getPage(0), field_dictionary) 

outputStream = open(outfile, "wb") 
pdf_writer.write(outputStream) 

inputStream.close() 
outputStream.close() 
+0

これは素晴らしいです。ありがとう。一般的な習慣と同じように、ファイルを開いた後は常にファイルを閉じます:-) – anishtain4

関連する問題