Ghostscript 在合并 PDF 时跳过字符
Posted
技术标签:
【中文标题】Ghostscript 在合并 PDF 时跳过字符【英文标题】:Ghostscript skips characters when merging PDFs 【发布时间】:2012-10-09 19:18:58 【问题描述】:在 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
是否有其他人经历过这种情况,或者更了解它的解决方案?
【问题讨论】:
【参考方案1】:如果嵌入字体子集的名称相同,但这些子集的真正内容不同(包含不同的字形集),我已经看到会发生这种情况。
检查所有输入文件中使用的字体。为此使用 Poppler 的 pdffonts
实用程序:
for i in input*.pdf; do
pdffonts $i | tee $i.pdffonts.txt
done
查找每个 PDF 中使用的字体名称。
我的理论/赌注是你看到不同的输入文件使用相同的字体名称(类似于BAAAAA+ArialMT
的名称)。
用于子集字体的BAAAAA+
字体名称前缀应该是随机(尽管官方规范对此不是很清楚)。但是,某些应用程序使用 predictable 前缀,以 BAAAAA+
、CAAAAAA+
DAAAAA+
等开头(OpenOffice.org 和 LibreOffice 因这方面而臭名昭著)。 这意味着前缀BAAAAA+
会在每个使用了至少一种子集字体的文件中使用...
您的输入文件不使用完全相同的字符子集很容易发生。然而,使用相同的名称可能会使 Ghostscript 认为字体确实是相同的。它(错误地)“优化”合并的 PDF 并仅嵌入 2 个字体实例之一(两者具有相同的名称,例如 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)。请参阅this answer 来提问“为什么 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)。请参阅this answer 来提问“为什么 Acrobat Distiller 不完全嵌入所有字体?”了解更多详情。
不要使用 Ghostscript,而是使用 pdftk
来合并 PDF。 pdftk
是一个比 Ghostscript(至少旧版本的 pdftk)更“愚蠢”的实用程序。合并 PDF,这种愚蠢可能是一个优势......
更新
再次回答,但这次更明确(遵循下面 cmets 中@sacohe 的额外问题。在许多(不是所有)情况下,以下过程将工作:
借助 Ghostscript(最好是 9.0x 系列的最新版本)重新“提取”输入的 PDF 文件。
要使用的命令是这样的(或类似的):gs -o redistilled-out.pdf -sDEVICE=pdfwrite input.pdf
然后,即使输入 PDF 对不同字体(子集)使用相同的名称前缀,生成的输出 PDF 也应该对字体名称使用不同的(唯一的)前缀。
当我处理原始问题的作者“R 先生”提供给我的原始输入文件样本时,此过程对我有用。修复后,“跳过字符问题”在最终结果中消失了(从固定的输入文件创建的合并 PDF)。
【讨论】:
哇,Kurt 这真的很有帮助。我将对此进行进一步调查,并尝试获取一些样本发送给您进行深入研究。我回来更新了。 库尔特。如果您仍然感兴趣,我已经为您整理了文件。由于我不想与公众分享,我可以私下发送给您吗? Okey 我无法让 pdffonts 实用程序在我的 mac 上正常工作,但我编写了一个运行 'strings inputfile.pdf |grep FontName' 的脚本,它给了我每个输入文件到 GS (其中 39 个)嵌入:/FontName /QRAAAA+NimbusSanL-Regu /FontName /QWAAAA+NimbusSanL-Bold 所以那里没有唯一的字体前缀。 GS 的输出文件似乎已将它们全部嵌入了 39 次,但我不确定 :-) 我很高兴与您分享这些文件以验证您是否愿意。 @MrR:如果 39 的每个输入文件都只使用这两个字体名称(QRAAAA+NimbusSanL-Regu
和 QWAAAA+NimbusSanL-Bold
),那么您不仅使用了一种,而且使用了两种不同的字体名字前缀! --
@sacohe:我在答案中添加了更新,更明确地说明了修复。真正的解决方法是通过 Ghostscript 在直接 PDF->PDF 转换中单独重新处理每个输入文件。【参考方案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 年),重新处理技巧无法使用。 -- 试试这个statically linked version of GS 9.06 (32bit) 应该足以测试这个技巧是否适用于您的文件...【参考方案3】:据我所知,此问题已在 Ghostscript 9.21 版中修复。我们遇到了类似的问题,合并的 PDF 缺少字符,虽然 @Kurt Pfeifle 建议重新提取这些 PDF 确实有效,但对我们来说似乎有点不可行/愚蠢。我们合并的一些 PDF 包含多达 600 个或更多单独的 PDF,并且重新提取其中的每一个以合并它们似乎很疯狂
我们的 Ghostscript 生产版本是 9.10,这导致了这个问题。但是当我在 9.21 上进行一些测试时,问题似乎消失了。我无法使用 GS 9.21 生成缺少或损坏字符的文档,所以我认为这是真正的解决方案。
【讨论】:
以上是关于Ghostscript 在合并 PDF 时跳过字符的主要内容,如果未能解决你的问题,请参考以下文章
Ghostscript:如何在 Windows 上将 PDF 与通配符合并