用同一系列的其他字体替换 PDF 中未嵌入的字体的最佳方法是什么?

What is the best way to replace not embedded fonts in a PDF with others of the same family?

我没有意识到 R 制作的统计图表和图表使用的字体没有安装在我的 Windows 机器上,这些是:
Helvetica
Helvetica-Bold
Helvetica-Oblique
ZapfDingbats

我是通过 运行 pdffonts <file.name.pdf> 从命令行发现的。所以这些字体没有嵌入到 PDF 文件中。

我已将我的论文送去印刷,但印刷厂说这些字体需要嵌入到 PDF 文件中。我使用 LaTeX 编写了它,并将图表作为 PDF 包含在内。

如何在不扭曲单个 PDF 中的图形的情况下,用非常相似的字体替换或替换这些字体(有些已获得许可)?我不打算使用商业工具。

备注
- Windows 7 32 位
- 这个 post 是相似的:

https://superuser.com/a/223687/212779

不过是用商业程序做的,现在比较老了。可能有更好的新想法来克服这个问题。但愿如此。

我目前的试用期
我已经成功地使用以下 post 中的一些 Ghostscript 专家的程序进行了替换: https://superuser.com/q/39167/212779

这需要 Ghostscript to be installed (I have version 9.15) plus Adobe PostScript for Windows,一个通用的和这个来自命令行的脚本:

gswin32c ^
 -dNOPAUSE ^
 -dBATCH ^
 -sDEVICE=pdfwrite ^
 -dPDFSETTINGS=/prepress ^
 -dCompatibilityLevel=1.4 ^
 -dHaveTrueTypes=true ^
 -dSubsetFonts=true ^
 -sOutputFile="c:\path\to\somename.pdf" ^
 -c ".setpdfwrite <</NeverEmbed [ ]>> setdistillerparams" ^
 -f "c:\path\to\somename.ps"

问题
如何获取生成的 .ps post 脚本文件和随后的 .pdf 文件(现在优雅地嵌入了类似的字体)具有与原始 PDF 相同的大小,即精确裁剪与原始 PDF 文件的尺寸相同?

如果我在 Adob​​e Reader(版本 XI)中保留所有默认设置——不要与商业 Adob​​e Professional 混淆,我在 .ps 文件中得到相同的大小,所以我真正需要的是 Ghostscript 中的一些代码,以在生成最终 PDF 时保留 .ps 文件的尺寸,有什么帮助吗?顺便说一句,我用 SumatraPDF 查看器打开 .ps 文件。

Windows 中所需要的只是以下步骤:

步骤 1
安装 Ghostscript 并添加到 PATH 变量(Win + break 是有用的快捷方式)

步骤 2
运行 这个脚本来自命令行,然后转到你有错误 PDF 的目标文件夹(我这样做是为了避免写整个路径)。

步骤 3

通过命令行中的 运行 pdffont 检查您的错误 PDF:

pdffonts input-pdf-where-some-fonts-are-not-embedded.pdf

步骤 4
运行 此代码用于获取带有嵌入字体的所需 PDF:

gswin32c ^  
-sFONTPATH=C\Windows\Fonts ^
-o output-pdf-with-embedded-fonts.pdf  ^
-sDEVICE=pdfwrite ^
-dPDFSETTINGS=/prepress ^
"input-pdf-where-some-fonts-are-not-embedded.pdf"

你很接近:之前的 SO 问题 (12857849) 提到将 -dEmbedAllFonts=true 添加到 gswin32c 的命令行。

关于批处理多个 PDF 的第二个问题(在评论中)可以通过多种方式完成,"best" 是您最容易理解、维护和使用的工具准备好访问。

在 R 中:

fnames <- list.files(pattern = 'doctorate-.*.pdf')
for (fn in fnames) {
    ofn <- paste0(gsub('\.pdf$', '', fn, ignore.case = TRUE), '-withfonts.pdf')
    message('Processing: ', fn, ' --> ', ofn)
    system2('gswin32c',
            paste0('-dNOPAUSE -dBATCH -sDEVICE=pdfwrite -dPDFSETTINGS=/prepress ',
                   '-dCompatibilityLevel=1.4 -dHaveTrueTypes=true -dSubsetFonts=true ',
                   '-dEmbedAllFonts=true -sOutputFile="', ofn, '" ',
                   '-c ".setpdfwrite <</NeverEmbed [ ]>> setdistillerparams" ',
                   '-f "', fn, '"'))
}

这有点冗长。如果您在 system2 中添加 stdout=FALSE,您应该看到如下内容:

Processing: doctorate-1.pdf --> doctorate-1-withfonts.pdf
Processing: doctorate-2.pdf --> doctorate-2-withfonts.pdf
Processing: doctorate-3.pdf --> doctorate-3-withfonts.pdf

bash中:

for fn in doctorate-*.pdf ; do
    ofn="$(basename ${fn} .pdf)-withfonts.pdf"
    echo "Processing: ${fn} --> ${ofn}"
    gswin32c -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -dPDFSETTINGS=/prepress ^
             -dCompatibilityLevel=1.4 -dHaveTrueTypes=true -dSubsetFonts=true ^
             -dEmbedAllFonts=true -sOutputFile="${ofn}" ^
             -c ".setpdfwrite <</NeverEmbed [ ]>> setdistillerparams" ^
             -f "${fn}"
done

(请注意,如果您在 windows 中的 msys2 下的 bash 终端中执行此操作,这可能会失败,因为 msys2 看到“/prepress”并假定它是一个路径,将其转换到 c:/msys64/prepress,这显然对 gs 没有任何意义 ...)