首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >PyPDF2 PdfFileMerger在合并文件中松散PDF模块

PyPDF2 PdfFileMerger在合并文件中松散PDF模块
EN

Stack Overflow用户
提问于 2019-07-12 14:14:15
回答 1查看 1.4K关注 0票数 2

我正在将PDF文件与PyPDF2合并,但是当其中一个文件包含一个填充了数据的PDF模块(一个典型的应用程序填充的PDF)时,在合并的文件中,模块是空的,没有显示数据。

下面是我用来合并PDF的两种方法:

代码语言:javascript
复制
def merge_pdf_files(pdf_files, i):
    pdf_merger = PdfFileMerger(strict=False)
    for pdf in pdf_files:
        pdf_merger.append(pdf)
    output_filename = '{out_root}{prog}.{cf}.pdf'.format(out_root=out_root_path, prog=i+1, cf=cf)
    pdf_merger.write(output_filename)

def merge_pdf_files2(pdf_files, i):
    output = PdfFileWriter()
    for pdf in pdf_files:
        input = PdfFileReader(pdf)
        for page in input.pages:
            output.addPage(page)
    output_filename = '{out_root}{prog}.{cf}.pdf'.format(out_root=out_root_path, prog=i+1, cf=cf)
    with open(output_filename,'wb') as output_stream:
        output.write(output_stream)

我期望最终的,合并的PDF显示所有的数据填充在PDF模块。或者,或者,有人可以告诉我另一个python库没有这个(表面上)的错误。谢谢

UPDATE I也尝试了PyMuPDF,结果也一样。

代码语言:javascript
复制
def merge_pdf_files4(pdf_files, i):
    output = fitz.open()
    for pdf in pdf_files:
        input = fitz.open(pdf)
        output.insertPDF(input)
    output_filename = '{out_root}{prog}.{cf}.pdf'.format(out_root=out_root_path, prog=i+1, cf=cf)
    output.save(output_filename)

也试过PyPDF4。与PyPDF2相同的结果

还尝试使用命令行从脚本启动的外部工具:

代码语言:javascript
复制
subprocess.call(cmd, shell=True)

一开始我试了pdftk,但也失败了。唯一起作用的是PDFill,商业版,花19美元在这个任务上.(可惜我找不到开源的、平台无关的解决方案。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-08-28 07:34:53

最后,我自己解决了这个问题,我在这里分享,希望能对其他人有所帮助。

这是一项艰巨的任务。

最后,我粘贴到pdfrw库(https://pypi.org/project/pdfrw/https://github.com/pmaupin/pdfrw)上,它提供了良好的PDF-DOM表示,非常接近Adobe官方引用(reference.html)中公开记录的PDF-结构。

使用这个库、PyCharm的对象检查器和Adobe的文档,我可以对输出文件的结构进行实验,并发现简单的1行合并:

代码语言:javascript
复制
    from pdfrw import PdfReader, PdfWriter

    output = PdfWriter()
    input = PdfReader(pdf_filename)
    output.addpages(input.pages)

不会将AcroForm节点添加到输出 PDF文件中,从而丢失所有表单字段。

因此,我不得不编写自己的代码来合并,尽可能地,各种输入文件的AcroForm节点。

我强调“尽我所能的最佳广告”这个句子,因为我最终得到的合并函数远不是完美的,但至少它对我有用,如果需要的话,可以帮助其他人在这一点上建立起来。

要做的一件重要事情是重命名表单字段以避免冲突,因此我将它们重命名为{file_num}_{field_num}_{original_name}。

然后,由于不知道如何合并CO、DA、DR和NeedAppearances节点,我只需添加包含它们的第一个源文件的节点。如果后续文件中存在相同的节点,则跳过它。

我跳过了,除了字体,我合并了DR节点的字体子节点的内容。

最后,在我的第一次尝试中,所有上述操作都是对output的预告片属性进行的。然后,我发现每次从新输入文件中添加页面时,pdfrw似乎都会删除预告片中已经存在的任何AcroForm。我不知道原因,但我必须构建一个ouptut_acroform变量,并将其赋值给输出文件行,然后才能写出最终的pdf。

最后,这是我的代码。原谅我,如果它不是节奏曲,我只是希望它澄清以上各点。

代码语言:javascript
复制
from pdfrw import PdfReader, PdfWriter, PdfName


def merge_pdf_files_pdfrw(pdf_files, output_filename):
  output = PdfWriter()
  num = 0
  output_acroform = None
  for pdf in pdf_files:
      input = PdfReader(pdf,verbose=False)
      output.addpages(input.pages)
      if PdfName('AcroForm') in input[PdfName('Root')].keys():  # Not all PDFs have an AcroForm node
          source_acroform = input[PdfName('Root')][PdfName('AcroForm')]
          if PdfName('Fields') in source_acroform:
              output_formfields = source_acroform[PdfName('Fields')]
          else:
              output_formfields = []
          num2 = 0
          for form_field in output_formfields:
              key = PdfName('T')
              old_name = form_field[key].replace('(','').replace(')','')  # Field names are in the "(name)" format
              form_field[key] = 'FILE_{n}_FIELD_{m}_{on}'.format(n=num, m=num2, on=old_name)
              num2 += 1
          if output_acroform == None:
              # copy the first AcroForm node
              output_acroform = source_acroform
          else:
              for key in source_acroform.keys():
                  # Add new AcroForms keys if output_acroform already existing
                  if key not in output_acroform:
                      output_acroform[key] = source_acroform[key]
              # Add missing font entries in /DR node of source file
              if (PdfName('DR') in source_acroform.keys()) and (PdfName('Font') in source_acroform[PdfName('DR')].keys()):
                  if PdfName('Font') not in output_acroform[PdfName('DR')].keys():
                      # if output_acroform is missing entirely the /Font node under an existing /DR, simply add it
                      output_acroform[PdfName('DR')][PdfName('Font')] = source_acroform[PdfName('DR')][PdfName('Font')]
                  else:
                      # else add new fonts only
                      for font_key in source_acroform[PdfName('DR')][PdfName('Font')].keys():
                          if font_key not in output_acroform[PdfName('DR')][PdfName('Font')]:
                              output_acroform[PdfName('DR')][PdfName('Font')][font_key] = source_acroform[PdfName('DR')][PdfName('Font')][font_key]
          if PdfName('Fields') not in output_acroform:
              output_acroform[PdfName('Fields')] = output_formfields
          else:
              # Add new fields
              output_acroform[PdfName('Fields')] += output_formfields
      num +=1
  output.trailer[PdfName('Root')][PdfName('AcroForm')] = output_acroform
  output.write(output_filename)

希望这能有所帮助。

票数 9
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/57008782

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档