合并PDF时Ghostscript会跳过字符

Mr *_*r R 4 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 
Run Code Online (Sandbox Code Playgroud)

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

Kur*_*fle 9

如果嵌入字体子集的名称相同,但我看到这种情况发生了,但这些子集的实际内容是不同的(包含不同的字形集).

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

 for i in input*.pdf; do
     pdffonts ${i} | tee ${i}.pdffonts.txt
 done
Run Code Online (Sandbox Code Playgroud)

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

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

BAAAAA+用于子集字体的字体名称前缀应该是随机的(尽管官方规范对此并不十分清楚).一些应用程序使用可预见的前缀,但是,开始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).见这个答案质疑"为什么犯规的Acrobat Distiller中完全嵌入所有字体?" 更多细节.

  2. 仅当您确定没有其他人可以查看或打印或使用您的个人输入文件时,请执行以下操作:不要嵌入字体 - 只有在与Ghostscript合并时才会嵌入来自输入的最终结果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).见 这个答案质疑"为什么犯规的Acrobat Distiller中完全嵌入所有字体?" 更多细节.

  3. 不要使用Ghostscript,而是pdftk用于合并PDF. pdftk在合并PDF时,它是一个比Ghostscript(至少是旧版本的pdftk)更"哑"的实用工具,这种愚蠢可能是一个优势......


更新

再次回答,但这一次更明确(在下面的评论中跟随@sacohe的额外问题.在许多(并非所有)案例中,以下程序将起作用:

  • 在Ghostscript的帮助下重新"删除"输入的PDF文件(最好是9.0x系列中的最新版本).

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

然后,生成的输出PDF应使用字体名称的不同(唯一)前缀,即使输入PDF对不同的字体(子集)使用相同的名称前缀.

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