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 

有没有其他人经历过这个,或者甚至更好地知道它的解决方案?

4

3 回答 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 并仅嵌入 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(最好是 9.0x 系列的最新版本)重新“提取”输入的 PDF 文件。

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

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

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

于 2012-10-09T20:24:01.873 回答
1

我想提供一些反馈,不幸的是,重新处理技巧似乎不适用于 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

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

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

于 2013-01-24T23:41:36.853 回答
0

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

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

于 2017-08-02T22:36:45.520 回答