【问题标题】:How to do mail merge on top of a PDF?如何在 PDF 之上进行邮件合并?
【发布时间】:2010-09-26 06:29:28
【问题描述】:

我经常从我们的设计师(内置于 Adob​​e InDesign)那里得到一份 PDF,它应该发送给成千上万的人。

我有所有人员的列表,在 OpenOffice.org 中进行邮件合并很容易。但是,OpenOffice.org 不支持高级 PDF。我只想在每一页上输出一些文本并打印出来。

我现在是这样做的:打印出 6.000 份 PDF,然后将它们全部重新放入打印机,然后在上面打印出姓名、地址和其他信息。但这很贵。

遗憾的是,我无法将 PDF 制作成图像并在 OpenOffice.org 中使用它,因为它会使计算机停止运行。将此作业发送到打印机也需要很长时间。

那么,有没有一种简单的方法可以在不支付第三方封闭解决方案的情况下进行这种邮件合并(最好使用 Python)?

【问题讨论】:

  • 这是一个离线 pdf 邮件合并工具,它是开源的,但不是真正免费的 github.com/plainlab/plainmerge。免责声明:我是作者。

标签: pdf pdf-generation mailmerge adobe-indesign


【解决方案1】:

现在我已经注册了一个帐户。我使用巧妙的 pdftk 修复了它。

在我的任务中,我完全忽略了“背景”和“叠加”功能。我的解决方案是这样的:

pdftk names.pdf background boat_background.pdf output out.pdf

您可以使用 Python reportlab 或类似的 PDF 创建脚本轻松创建 names.pdf。最好使用代码来完成,在 LibreOffice/OpenOffice 中创建 6k 页面需要几个小时,而使用 Python 只需要几秒钟。

【讨论】:

  • 我赞成,因为这是我遇到的另一个问题的解决方案,与表单无关,而是将文本“标记”到 pdf 上
  • 链接失效了。
  • 感谢@stoic,删除链接,因为它基本上只是详细说明了我所有失败的尝试以及失败的原因(有些几乎成功了)。我想我还编写并展示了一个脚本来制作names.pdf 文件,但是您可以使用 Python 轻松地做到这一点。我首先尝试了 LibreOffice,但花了 4 个多小时,Python 花了 4 秒。
  • 你能提供names.pdfboat_background.pdf的例子吗?这似乎是一个很好的解决方案,但我在弄清楚具体细节时遇到了一些麻烦。我认为这两个文件的示例都会有所帮助。
  • 嘿@MikeyE - 我的网站曾经有示例,但我没有再次设置它。我确实添加了我现在在另一个答案中编写的基本脚本:stackoverflow.com/a/57295681/179978
【解决方案2】:

您可能会查看像 iText 这样的 PDF 库。如果您有一些编程知识和一点时间,您可以编写一些代码,将联系信息添加到 PDF 中

【讨论】:

    【解决方案3】:

    有两种更简单、更便宜的解决方案。

    首先,您可以使用 DataMerge 在 InDesign 中直接进行邮件合并。这是在 CS 中添加到 InDesign 的实用程序。您以 CSV 格式导出或保存您的姓名。将数据导入 InDesign 模板,然后将您的姓名、地址和布局中的此类字段放入其中。按开始。它将创建一个包含所有已完成字母的新文档,或者您可以直接进入打印机。

    或者,您可以将数据导出到 XML 文件并在 InDesign 中使用 XML 占位符创建动态布局。

    Adobe InDesign 和 XML 设计师指南一书将教您如何做到这一点,或者您可以查看 Lynda.com 视频,了解使用 InDesign 和 XML 进行动态工作流程。

    很容易做到。

    如果您想为邮件合并创建单独的 PDF 文件,您可以用一个文件中的所有名称运行一个长 PDF,然后在 Acrobat Pro 本身中执行提取以分离 PDF 文件。

    【讨论】:

    • 更便宜?至少不像成本那样,因为 pdftk 是免费的。它也非常快。最后,我一直在使用 reportlab pdfgen plus pdftk 来完成这项工作。与之前需要花费数小时相比,现在只需几秒钟即可将 50.000 页的 CSV 文件邮件合并到 PDF 之上。 :-)
    【解决方案4】:

    如果您无法获得 PDF 以外的其他格式的模板,则可以采用简单的临时解决方案

    • 将 PDF 转换为图像
    • 将图像放在 (OpenOffice.org) 文档的背景中
    • 将邮件合并字段置于图像顶部
    • 进行邮件合并和打印

    【讨论】:

    • 打印作业变得巨大而且永远不会完成。
    • 好吧,那么最简单的方法是要求您的设计师提供可行格式的模板(或者获取 Adob​​e Acrobat Professional 的副本,我认为应该有一些可能使用转换 PDF成表格)。似乎交付 6000 封信的投资回报率应该证明这样的投资是合理的。
    【解决方案5】:

    可能最好的方法是生成另一个带有缺失文本的 PDF,然后将一个 PDF 覆盖在另一个上。快速谷歌发现这个链接显示如何在 Acrobat 中执行此操作,我相信还有其他方法。

    http://forums.macrumors.com/showthread.php?t=508226

    【讨论】:

      【解决方案6】:

      对于一个简单、简单的解决方案,使用 iText 将文本简单地添加到 pdf 中。例如,您可以执行以下操作以在加载后向 pdf 文档添加文本:

      PdfContentByte cb= ...;
      cb.BeginText();
      cb.SetFontAndSize(font, fontSize);
      float x = ...;
      float y = ...;
      cb.SetTextMatrix(x, y);
      cb.ShowText(fieldValue);
      cb.EndText();    
      

      从那里开始,将其另存为其他文件,然后打印。

      但是,我发现表单域是从模板生成 pdf 文档的方法。

      如果您有一个带有表单域的模板(使用 Adob​​e Acrobat 添加),您有以下两种选择之一:

      • 创建一个 FDF 文件,它本质上是表单上字段的值列表。 FDF 是一个简单的文本文档,它引用原始文档,因此当您打开 PDF 时,文档会加载 FDF 提供的字段值。
      • 或者,使用 iText / iTextSharp 之类的库加载模板,手动填写表单字段,并将其另存为单独的 pdf。

      一个示例 FDF 文件如下所示(从 Planet PDF 窃取):

      %FDF-1.2
      %âãÏÓ
      1 0 obj
      <<<
       /F(Example PDF Form.pdf)
       /Fields[
        <<
        /T(myTextField)
        /V(myTextField default value)
        >>
        ]
       >>
      >> endobj trailer
      <>
      %%EOF
      

      由于 FDF 的格式简单且体积小,这是首选方法,并且该方法应该适用于任何语言。

      至于以编程方式填充字段,您可以通过以下方式使用 iText:

      PdfAcroForm acroForm = writer.AcroForm;
      acroForm.Put(new PdfName(fieldInfo.Name), new PdfString(fieldInfo.Value));
      

      【讨论】:

      • 但是我可以将 6000 个名称放入一个 FDF 中,还是我必须制作 6000 个 FDF 文件然后输出 6000 个 5MiB PDF 文件(这将是巨大的并且需要永远)?
      【解决方案7】:

      如何使用可变数据程序,例如用于 Adob​​e Indesign 的 XMPie。它是一个插件,应该引用您的人员列表(但认为它可能必须是 Excel 中的列表)。

      【讨论】:

        【解决方案8】:

        一种简单的方法是在 Acrobat 中从原始文档创建一个可填写的 pdf 表单,然后将表单和 csv 进行邮件合并。

        PDF 邮件合并在 python 和pdftk 中相对容易。 Fdfgen (pip install fdfgen) 是一个 python 库,它将从 python 数组创建一个 fdf,因此您可以将 excel 网格保存到 csv,确保 csv 标题与您要填充的 pdf 表单字段的名称匹配该列,并执行类似的操作

        import csv
        import subprocess
        
        from fdfgen import forge_fdf
        
        PDF_FORM = 'path/to/form.pdf'
        CSV_DATA = 'path/to/data.csv'
        
        infile = open(CSV_DATA, 'rb')
        reader = csv.DictReader(infile)
        rows = [row for row in reader]
        infile.close()
        
        for row in rows:
            # Create fdf
            filename = row['filename'] # Construct filename
            fdf_data = [(k,v) for k, v in row.items()]
            fdf = forge_fdf(fdf_data_strings=fdf_data)
            fdf_file = open(filename+'.fdf', 'wb')
            fdf_file.write(fdf)
            fdf_file.close()
        
            # Use PDFTK to create filled, flattened, pdf file
            cmds = ['pdftk', PDF_FORM, 'fill_form', filename+'.fdf',
                    'output', filename+'.pdf', 'flatten', 'dont_ask']
            process = subprocess.Popen(cmds, stdout=subprocess.PIPE)
            stdout, stderr = process.communicate()
            returncode = process.poll()
            os.remove(filename+'.fdf')
        

        我已经遇到了足够多的问题来编写我自己的免费解决方案PdfZero。 PdfZero 具有邮件合并功能,可将电子表格与 PDF 表单合并。您仍然需要创建一个 PDF 表单,但您可以将表单和 csv 上传到 pdfzero,选择要填充哪些列的表单字段,如果需要,使用 csv 数据为每个填充的 pdf 创建命名约定,然后批量生成填充的 PDfs。

        免责声明:我写了 PdfZero

        【讨论】:

          【解决方案9】:

          有人询问具体情况。我不想用它来玷污我的最佳答案,因为您可以按照自己的喜好进行操作(并且知道 pdftk 可以做到这一点应该会给人们这个想法)。

          但这是我多年前使用的一些脚本:

          csv_to_pdf.py

          #!/usr/bin/python
          # This makes one PDF page per name in the CSV file
          # csv_to_pdf.py <CSV_FILE>
          
          import csv
          import sys
          from reportlab.pdfgen.canvas import Canvas
          from reportlab.lib.units import cm, mm
          
          in_db = csv.reader(open(sys.argv[1], "rb"));
          outname = sys.argv[1].replace("csv", "pdf")
          pdf = Canvas(outname)
          in_db.next()
          
          i = 0
          for rad in in_db:
                  pdf.setFontSize(11)
                  adr = rad[1]
          
                  tekst = pdf.beginText(2*cm, 26*cm)
          
                  for a in adr.split('\n'):
                      if not a.strip():
                          continue
                      if a[-1] == ',':
                          a = a[:-1]
                      tekst.textLine(a)
                  pdf.drawText(tekst)
                  pdf.showPage()
          
                  i += 1
                  if i % 1000 == 0:
                          print i
          pdf.save()
          

          运行此程序后,您将拥有一个包含数千页的文件,其中只有一个名称。这是您可以在所有这些下放置精美 PDF 的时候:

          pdftk <YOUR_NEW_PDF_FILE.pdf> background <DESIGNED_FILE.pdf> <MERGED.pdf>
          

          【讨论】:

            【解决方案10】:

            您可以使用 InDesign 的数据合并功能,或者您可以执行您一直在做的事情,打印一部分作业,然后使用 Word 或 Open Office 在其上打印邮件合并。 但也要考虑寻找一家可以进行可变数据胶印或动态出版的公司。前期可能会贵一点,但在时间、测试、甚至包装和邮寄方面可以节省大量费用。

            【讨论】:

              【解决方案11】:

              免责声明:我是这个工具的作者。

              我遇到这个问题的次数足够多,因此我为它构建了一个免费的在线工具:https://pdfbatchfill.com/

              它假定 PDF 表单作为模板,并将其与 CSV 表单数据一起使用以生成单个 PDF 或 zip 文件中的单个 PDF。

              【讨论】:

                猜你喜欢
                • 2010-09-07
                • 2012-10-22
                • 2016-06-25
                • 1970-01-01
                • 1970-01-01
                • 2020-06-21
                • 2017-02-21
                • 2014-02-24
                • 2012-06-16
                相关资源
                最近更新 更多