合并PDF时Ghostscript会跳过字符

时间:2012-10-09 19:18:58

标签: pdf merge ghostscript

在Ubuntu上使用Ghostscript(版本8.71)合并用wkhtmltopdf创建的PDF文件时遇到问题。

我在随机场合遇到的问题是,某些字符在合并过程中会丢失,并被合并后的PDF中的任何内容(或空格)所取代。如果我查看原始PDF,它看起来很好,但合并后一些字符丢失。

请注意,一个丢失的字符(例如数字9或字母a)可能会丢失在文档的一个位置,但在文档的其他位置显示正常,因此显示它或字体问题不是问题

我使用的命令是:

gs \
   -q \
   -dNOPAUSE \
   -sDEVICE=pdfwrite \
   -sOutputFile=/tmp/outputfilename \
   -dBATCH \
    /var/www/documents/docs/input1.pdf \
    /var/www/documents/docs/input2.pdf \
    /var/www/documents/docs/input3.pdf 

其他任何经历过这种情况的人,或者甚至更好地了解它的解决方案?

3 个答案:

答案 0 :(得分:9)

如果嵌入字体子集的名称相同,但这些子集的真实内容不同(包含不同的字形集),我就已经看到了这种情况。 / p>

检查所有输入文件以查找所使用的字体。使用Poppler的pdffonts实用程序:

 for i in input*.pdf; do
     pdffonts ${i} | tee ${i}.pdffonts.txt
 done

查找每个PDF中使用的字体名称。

我的理论/赌注是你看到不同的输入文件使用相同的字体名称(类似于BAAAAA+ArialMT的名称)。

用于子集字体的BAAAAA+字体名称前缀应该是 random (尽管官方规范对此并不十分清楚)。有些应用程序使用可预测的前缀,但是从BAAAAA+CAAAAAA+ DAAAAA+等开始(OpenOffice.org和LibreOffice因此而臭名昭着)。 这意味着前缀BAAAAA+会在每个使用至少一个子集字体的文件中使用...

很容易发生输入文件不使用完全相同的字符子集。但是,使用相同的名称可能会使Ghostscript认为字体真的是相同的。它(错误地)“优化”合并的PDF并仅嵌入2个字体实例中的一个(两者都具有相同的名称,例如BAAAAA+Arial)。但是,此实例可能不包含某些字形,其中包含其他实例的一部分。

这会导致合并输出中缺少某些字符。

我知道更新版本的Ghostscript已经对其字体处理代码进行了大量改革。也许你会更幸运地尝试Ghostscript v9.06(迄今为止的最新版本)。

我非常有兴趣以更详细的方式对此进行调查。如果您可以提供输入文件的样本(以及GS v8.70给出的合并输出),我可以测试它是否适用于v9.06。

您可以采取哪些措施来避免此问题

  1. 尝试始终将字体嵌入为完整集,而不是子集

    • 我不知道在使用wkhtmltopdf时是否以及如何控制完整的字体嵌入。
    • 如果您从Libre / OpenOffice生成输入PDF,那么您运气不好,而且您将无法控制它。
    • 如果您使用Acrobat生成输入PDF,则可以在Distiller设置中调整字体嵌入详细信息。
    • 如果Ghostscript生成输入PDF,则强制执行完整字体嵌入的命令行参数为:
      gs -o output.pdf -sDEVICE=pdfwrite -dSubsetFonts=false input.file

    某些类型的字体无法完全嵌入,但只能进行子集化(TrueType,Type3,CIDFontType0,CIDFontType1,CIDFontType2)。请参阅this answer以询问“为什么Acrobat Distiller没有完全嵌入所有字体?”了解更多详情。

  2. 只有当您确定没有其他人可以查看或打印或使用您的个人输入文件时,请执行以下操作:根本不要嵌入字体 - 仅在与Ghostscript合并时嵌入< / strong>来自您输入的最终结果PDF。

    • 我不知道在使用wkhtmltopdf时是否以及如何控制没有字体嵌入。
    • 如果您从Libre / OpenOffice生成输入PDF,那么您运气不好,而且您将无法控制它。
    • 如果您使用Acrobat生成输入PDF,则可以在Distiller设置中调整字体嵌入详细信息。
    • 如果Ghostscript生成输入PDF,则防止字体嵌入的命令行参数为:
      gs -o output.pdf -sDEVICE=pdfwrite -dEmbedAllFonts=false -c "<</AlwaysEmbed [ ]>>setpagedevice" input.file

    某些类型的字体无法完全嵌入,但只能进行子集化(Type3,CIDFontType1)。请参阅this answer以询问“为什么Acrobat Distiller没有完全嵌入所有字体?”了解更多详情。

  3. 不要使用Ghostscript,而是使用pdftk来合并PDF。 pdftk是一个比Ghostscript更为“愚蠢”的实用程序(至少旧版本的pdftk是)在合并PDF时,这种愚蠢可能是一个优势......


  4. 更新

    再次回答,但这一次更明确(在下面的评论中跟随@sacohe的额外问题。在许多(不是所有)案例中,以下程序会工作:

    • 借助Ghostscript重新“删除”输入的PDF文件(最好是9.0x系列中的最新版本)。

    • 使用的命令是这个(或类似的):
      gs -o redistilled-out.pdf -sDEVICE=pdfwrite input.pdf

    结果输出PDF应该使用字体名称的不同(唯一)前缀,即使输入PDF对不同的字体(子集)使用相同的名称前缀。

    当我处理原始问题的作者'Mr R'提供给我的原始输入文件样本时,此程序对我有用。修复之后,“跳过的字符问题”在最终结果中消失了(从固定输入文件创建的合并PDF)。

答案 1 :(得分:1)

我想提供一些反馈,不幸的是,重新处理技巧似乎不适用于ghostscript 8.70(在redhat / centos版本中)和从2010年以字面形式导出为pdf的文件(似乎使用ABCDEE+一切的前缀)。我无法为我的平台找到任何预制版本的ghostscript 9。

你提到旧版本的pdftk可能有效。我们从pdftk(较新版本)转移到gs,因为一些pdf文件会导致pdftk变为coredump。 @Kurt,你认为试图找到旧版本的pdftk可能会有所帮助吗?如果是这样,你推荐什么版本?

中途工作的另一个丑陋方法是使用:

-sDEVICE=pdfwrite -dCompatibilityLevel=1.2 -dHaveTrueType=false

将字体转换为位图,但它会导致页面上的字符有点轻(不是很大),尝试选择文本大约一行高(稍微烦人),最糟糕的是即使字符显示正常,复制/粘贴也会在文本中显示随机垃圾。

(我希望这会是一个评论,但我想我不能这样做,答案是否已关闭?)

答案 2 :(得分:0)

据我所知,这个问题在Ghostscript版本9.21中已经修复。我们遇到了类似的问题,其中合并的PDF文件缺少字符,而@Kurt Pfeifle建议重新提炼这些PDF文件确实有效,但对我们来说似乎有点不可行/愚蠢。我们的一些合并的PDF包含多达600个或更多的单独PDF,并重新提炼每一个合并它们只是看起来很疯狂

我们的Ghostscript的生产版本是9.10,这导致了这个问题。但是当我在9.21上做了一些测试时,问题似乎消失了。我无法使用GS 9.21生成缺少或损坏字符的文档,因此我认为这是真正的解决方案。