Ghostscript在合并PDF时跳过了一些字符。

6
我在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个回答

10
我曾经见过这种情况发生,如果嵌入字体子集的名称相同,但这些子集的真正内容是不同的(包含不同的字形集)。
检查您使用的所有输入文件中的字体。使用Poppler的pdffonts实用程序进行此操作:
 for i in input*.pdf; do
     pdffonts ${i} | tee ${i}.pdffonts.txt
 done

寻找每个PDF中使用的字体名称。
我的理论/赌注是你会看到不同输入文件使用相同的字体名称(类似于BAAAAA+ArialMT的名称)。
用于子集字体的BAAAAA+字体名称前缀应该是随机的(尽管官方规范并不是很清楚)。然而,一些应用程序使用可预测的前缀,例如BAAAAA+CAAAAAA+DAAAAA+等(OpenOffice.org和LibreOffice以此著称)。这意味着前缀BAAAAA+在每个至少使用一个子集字体的文件中都会被使用... 你的输入文件可能没有使用完全相同的字符子集。但是,相同的名称可能会让Ghostscript认为字体确实是相同的。它(错误地)“优化”合并的PDF,并仅嵌入其中一个字体实例(两个实例都具有相同的名称,例如BAAAAA+Arial)。然而,该实例可能不包含其他实例中包含的某些字形。
这导致合并输出中缺少某些字符。
我知道Ghostscript的更新版本已经对其字体处理代码进行了重大改进。也许您可以尝试使用Ghostscript v9.06(目前最新版本)来解决问题。
我非常有兴趣进一步调查此问题。如果您可以提供输入文件的样本(以及GS v8.70给出的合并输出),我可以测试它是否与v9.06更好地配合使用。
为了避免这个问题,您可以做以下几点:
尽量始终嵌入完整字体集,而不是子集: 我不知道是否以及如何在使用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不完全嵌入所有字体?”的此答案
只有在确信没有其他人能够查看、打印或使用您的单个输入文件时才执行以下操作:在与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不完全嵌入所有字体?”的此答案
不要使用Ghostscript,而是使用pdftk合并PDF。 pdftk在合并PDF时比Ghostscript(至少旧版本的pdftk)更加“愚蠢”,这种愚蠢可能是一个优势...

更新

为了更明确地回答问题(根据下面@sacohe在评论中的额外问题)。在许多情况下(不是所有情况),以下步骤将起作用:

  • 使用Ghostscript(最好使用9.0x系列中的最新版本)重新“蒸馏”输入PDF文件。

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

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

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


好的,我在我的Mac上无法很好地使用pdffonts工具,但我编写了一个脚本,运行“strings inputfile.pdf | grep FontName”,它告诉我每个输入文件都嵌入了39个GS(39个): /FontName /QRAAAA+NimbusSanL-Regu /FontName /QWAAAA+NimbusSanL-Bold 因此,没有唯一的字体前缀。 GS的输出文件似乎已经将它们全部嵌入了39次,但我不确定:-) 如果您愿意,我很乐意与您分享文件以进行验证。 - Mr R
@MrR:你没有提到你在使用Mac电脑。在Mac上,安装MacPorts,然后运行sudo port -p install ghostscript - Kurt Pfeifle
1
@MrR:如果这39个输入文件的每一个都只使用这两个字体名称(QRAAAA+NimbusSanL-ReguQWAAAA+NimbusSanL-Bold),那么你不仅有一个,而是两个不同的字体使用了非唯一命名前缀! - Kurt Pfeifle
谢谢您的详细解释。我也遇到了同样的问题,但我同时使用wkhtmltopdf来生成我的输入文件 - 有人已经找到了这种情况的解决方案吗? - sacohe
1
@sacohe:我在我的回答中添加了一个更新,更明确地说明了修复方法。真正的解决方法是通过Ghostscript将每个输入文件单独进行处理,直接执行PDF->PDF转换。 - Kurt Pfeifle
显示剩余5条评论

2

很遗憾,重新处理技巧似乎无法与ghostscript 8.70(在redhat/centos版本中)和从word 2010导出的pdf文件一起使用(它似乎对所有内容都使用了ABCDEE+前缀)。我还没有找到任何适用于我的平台的预构建ghostscript 9版本。

您提到旧版本的pdftk可能有效。我们放弃了pdftk(新版本),转而使用gs,因为某些pdf文件会导致pdftk崩溃。@Kurt,您认为尝试找到较旧版本的pdftk可能有所帮助吗?如果是这样,您推荐使用哪个版本?

另一种部分可行的丑陋方法是使用:

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

这会将字体转换为位图,但会导致页面上的字符变得有点淡(不是很严重),尝试选择文本时会偏移大约一行高度(略微烦人),最糟糕的是,即使字符显示正常,复制/粘贴也会在文本中产生随机垃圾。

(我希望这是一条评论,但我想我不能这样做,答案关闭了吗?)


你们的平台是RedHat/CentOS吗?用的是哪个版本?Ghostscript 8.70太旧了(早在2010年之前),而且重新处理的技巧也无法使用。-- 试试这个静态链接版本的GS 9.06(32位),它应该足以测试这个技巧是否适用于你们的文件... - Kurt Pfeifle

0
据我所知,这个问题在Ghostscript 9.21版本中已经被修复。我们曾经遇到过类似的问题,即合并的PDF文件缺少字符,虽然@Kurt Pfeifle建议重新转换这些PDF文件确实有效,但对于我们来说似乎有点不切实际/愚蠢。我们的一些合并PDF文件由600个或更多个单独的PDF文件组成,重新转换每一个PDF文件以进行合并似乎很疯狂。
我们的Ghostscript生产版本是9.10,这导致了这个问题。但当我在9.21上进行了一些测试时,问题似乎消失了。我无法使用GS 9.21生成缺少或损坏字符的文档,因此我认为这才是真正的解决方案。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接