重命名 PDF 嵌入字体

Rename PDF embedded font

我正在使用 ghostscript 合并 PDF 文件。但是偶尔嵌入的字体名称在不同的文件中发生冲突,ghostscript会选择一个子集,合并后其他同名子集中的一些字符无法呈现。

为了解决这个问题,我想添加一个预处理阶段,为每个文件重命名嵌入的字体,新名称由我的逻辑生成。

首选Linux以下的解决方案。

P.S。我评估了其他合并 pdf 的工具(pdfbox、pdfjam、pdftk、pdfunite、qpdf),但看起来 none 它们识别相同的图像,合并后的 PDF 很大。 GhostScript 只为多个输入文件中完全相同的图像保留 1 个对象,它适合我的场景。


阅读@KenS 的回复后更新

GhostScript 版本:9.18

PDF 创建者:

2个带有冲突字体名称的PDF的输出:

$ gs -q -dSAFER -dBATCH -dNOPAUSE -dPDFSETTINGS=/prepress -sDEVICE=pdfwrite -sOutputFile=merged.pdf 1.pdf 2.pdf
GPL Ghostscript 9.18: Missing glyph CID=120, glyph=0078 in the font BLTQUA+LMRoman9-Regular . The output PDF may fail with some viewers.
GPL Ghostscript 9.18: Missing glyph CID=117, glyph=0075 in the font BLTQUA+LMRoman9-Regular . The output PDF may fail with some viewers.
GPL Ghostscript 9.18: Missing glyph CID=118, glyph=0076 in the font BLTQUA+LMRoman9-Regular . The output PDF may fail with some viewers.
GPL Ghostscript 9.18: Missing glyph CID=116, glyph=0074 in the font BLTQUA+LMRoman9-Regular . The output PDF may fail with some viewers.

嵌入字体:

$ pdffonts 1.pdf
name                                 type              encoding         emb sub uni object ID
------------------------------------ ----------------- ---------------- --- --- --- ---------
ITLHBL+LMRoman10-Regular-Identity-H  CID Type 0C       Identity-H       yes yes yes      7  0
BLTQUA+LMRoman9-Regular-Identity-H   CID Type 0C       Identity-H       yes yes yes      9  0
MHRCBY+LMRoman8-Regular-Identity-H   CID Type 0C       Identity-H       yes yes yes     12  0

$ pdffonts 2.pdf
name                                 type              encoding         emb sub uni object ID
------------------------------------ ----------------- ---------------- --- --- --- ---------
ITLHBL+LMRoman10-Regular-Identity-H  CID Type 0C       Identity-H       yes yes yes      7  0
BLTQUA+LMRoman9-Regular-Identity-H   CID Type 0C       Identity-H       yes yes yes      9  0
MHRCBY+LMRoman8-Regular-Identity-H   CID Type 0C       Identity-H       yes yes yes     12  0

字体名称完全相同。因为我使用 xelatex 以编程方式生成模式中的 PDF,所以字体的对象 ID 完全相同。 GhostScript 认为来自 2 个文件的 BLTQUA+LMRoman9-Regular 字体是相同的子集,并在处理时抱怨。

按照@KenS 的建议,我让 GhostScript 为每个 PDF 生成一个新文件。

Ghostscript will calculate a prefix using the MD5 sum of the font contents.

然后检查字体:

$ pdffonts preproc_1.pdf 
name                                 type              encoding         emb sub uni object ID
------------------------------------ ----------------- ---------------- --- --- --- ---------
JUVZAM+LMRoman8-Regular              CID Type 0C       Identity-H       yes yes yes     22  0
DCQLFZ+LMRoman9-Regular              CID Type 0C       Identity-H       yes yes yes     17  0
YAKIEH+LMRoman10-Regular             CID Type 0C       Identity-H       yes yes yes     13  0

$ pdffonts preproc_2.pdf 
name                                 type              encoding         emb sub uni object ID
------------------------------------ ----------------- ---------------- --- --- --- ---------
JUVZAM+LMRoman8-Regular              CID Type 0C       Identity-H       yes yes yes     22  0
EQFACS+LMRoman9-Regular              CID Type 0C       Identity-H       yes yes yes     17  0
YAKIEH+LMRoman10-Regular             CID Type 0C       Identity-H       yes yes yes     13  0

现在,很明显 LMRoman9-Regular 不是相同的子集(尽管仍然具有相同的对象 ID),这不会再混淆 GhostScript。

[插入关于 Ghostscript 不合并 PDF 文件这一事实的通常免责声明]

请注意,这实际上只是在创建应用程序在为嵌入字体名称选择前缀方面做得不好时才会出现的问题。实际上,错误在于 PDF 创建者。

您没有说明您使用的是哪个版本的 Ghostscript。 Ghostscript 的最新版本同时使用字体名称和 PDF 对象编号来尝试提供更大程度的唯一性。因此,只有当两个 PDF 文件中的名称 对象编号相同时,字体才会发生冲突,这种可能性较小。

如果这仍然是一个问题,一个实用的解决方案是通过 Ghostscript 和 pdfwrite 设备传递每个原始 PDF 文件,以生成许多新的 PDF 文件。在新 PDF 文件中创建字体时,Ghostscript 将使用字体内容的 MD5 和计算前缀。虽然并非绝对牢不可破,但两个不同子集的内容产生相同 MD5 哈希值的可能性非常低。

然后您可以安全地处理新创建的 PDF 文件,而不会有不同字体具有相同名称和对象编号的真正风险。

如果您坚持自己重命名,您也许可以通过查看 PDF 文件来查找 for XXXXX+FontName 的名称。您可以修改5个字母的前缀并重写文件。

我不记得字体对象是否可以存储在压缩对象流中,如果它们可以,那将显着增加问题,因为您必须解压缩流、修改数据、重新压缩它,并且,最有可能修改外部参照 table,因为重新压缩的流不太可能与原始流的长度相同。