我将 pdf 文件交给一家按需印刷公司 (lulu.com),这家公司对字体非常挑剔。他们希望嵌入所有字体,不嵌入多种字体,也不进行子集设置。pdftex 的最新版本似乎可以自动完成所有这些操作,只是生成的 pdf 确实有子集设置。目前,我正在做的是通过 ghostscript 进行 pdf->pdf 过滤,如下所示:
gs -q -dCompatibilityLevel=1.4 -dSubsetFonts=false -dPDFSETTINGS=/printer -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -sOutputFile=b.pdf a.pdf -c '.setpdfwrite'
这很慢,而且也很笨拙。有没有更好的方法来实现这一点?
如果通过切换到 luatex 或 xetex 可以更轻松地解决此问题,我愿意接受,但我不确定要选择哪一个,而且这些都是大型图书项目,使用 pdftex 以外的其他工具可能并不简单。
答案1
许多字体许可证不允许完全嵌入字体。假设您只使用允许完全嵌入的字体,您可以修改映射文件(当然,无需真正修改它)。
这需要一些工作,但这项工作是渐进的。
假设文档是
\documentclass{article}
\usepackage{lmodern}
\begin{document}
Hello world!
\end{document}
在日志文件的末尾,您可以找到所用字体的列表,在本例中lmr10.pfb
:
</usr/local/texlive/2011/texmf-dist/fonts/type1/public/lm/lmr10.pfb>
你还有一个编码指令,
{/usr/local/texlive/2011/texmf-dist/fonts/enc/dvips/lm/lm-rm.enc}
您将grep lmr10.pfb $(kpsewhich pdftex.map)
获得以下输出
cs-lmr10 LMRoman10-Regular " enclmcs ReEncodeFont " <lm-cs.enc <lmr10.pfb
dd-lmr10 LMRoman10-Regular <dotdigits.enc <lmr10.pfb " fontinst-autoenc-dotdigits ReEncodeFont "
ec-lmr10 LMRoman10-Regular " enclmec ReEncodeFont " <lm-ec.enc <lmr10.pfb
l7x-lmr10 LMRoman10-Regular " enclml7x ReEncodeFont " <lm-l7x.enc <lmr10.pfb
lmr8ttl10 LMRoman10-Regular <t1-clm.enc <lmr10.pfb " fontinst-autoenc-t1-clm ReEncodeFont "
qx-lmr10 LMRoman10-Regular " enclmqx ReEncodeFont " <lm-qx.enc <lmr10.pfb
rm-lmr10 LMRoman10-Regular " enclmrm ReEncodeFont " <lm-rm.enc <lmr10.pfb
t5-lmr10 LMRoman10-Regular " enclmt5 ReEncodeFont " <lm-t5.enc <lmr10.pfb
texnansi-lmr10 LMRoman10-Regular " enclmtexnansi ReEncodeFont " <lm-texnansi.enc <lmr10.pfb
ts1-lmr10 LMRoman10-Regular " enclmts1 ReEncodeFont " <lm-ts1.enc <lmr10.pfb
因此相关行是以 开头的行rm-lmr10
。准备一个fullembed.map
包含相关行的文件,但稍作修改,如下所示
rm-lmr10 LMRoman10-Regular " enclmrm ReEncodeFont " <lm-rm.enc <<lmr10.pfb
如果您不确定要包含哪一行,请包含全部(但将最后一行更改<
为<<
)。
添加fullembed.map
您需要的所有字体行,然后教 pdftex 在您的文档中使用它
\pdfmapfile{=fullembed.map}
之前\begin{document}
。现在字体将完全嵌入。fullembed.map
可以将其放置在 TeX 搜索的目录中:当前工作目录,或者在 GNU/Linux 系统上~/texmf/fonts/map/pdftex
(创建必要的路径)。
答案2
以下是我编写的一些 perl 代码,用于自动执行 egreg 建议的流程。我认为它可能对其他人有帮助。它从标准输入读取日志文件并将 fullembed.map 写入标准输出。
use strict;
my $default_map = `kpsewhich pdftex.map`;
open(F,"<$default_map");
my @map = ();
while (my $line=<F>) {
chomp $line;
# yvtri8r VenturisADF-Italic <8r.enc <yvtri8a.pfb "TeXBase1Encoding ReEncodeFont"
# "..." may also be before <'s; just eliminate it:
$line =~ s/".*"//;
#print "=$line=\n";
push @map,$line;
}
close(F);
local $/; # slurp whole file
my $log = <>;
#print "encs:\n";
my @enc = (''); # null string is because some lines in pdftex.map have no .enc
while ($log =~ /{([^}]+\.enc)}/g) {
my $enc = $1;
$enc =~ s/\n//g;
if ($enc =~ /([^\/]+)\.enc/) {
my $tail = $1;
#print "enc=$tail\n";
push @enc,$tail;
}
}
#print "pfbs:\n";
my @pfb = ();
while ($log =~ /<([^>]+\.pfb)>/g) {
my $pfb = $1;
$pfb =~ s/\n//g;
if ($pfb =~ /([^\/]+\.pfb)/) {
my $tail = $1;
#print "$tail\n";
push @pfb,$tail;
}
}
foreach my $enc(@enc) {
my $e = quotemeta $enc;
foreach my $pfb(@pfb) {
my $p = quotemeta $pfb;
foreach my $map(@map) {
#if ($pfb =~ /tipasl10/ && $enc eq '') {print "trying enc=$enc, pfb=$pfb, map=$map\n"}
if ( $map =~/$p/ && (($enc ne '' && $map =~ /$e/) || ($enc eq '' && ! ($map =~ /\.enc/)))) {
$map =~ s/(<[^ ]+.pfb)/<$1/;
#print "enc=$enc, pfb=$pfb, map=$map\n";
print "$map\n";
}
}
}
}