![如何删除包含 150,000 种嵌入字体的 PDF 文档中的重复字体?](https://linux22.com/image/1593571/%E5%A6%82%E4%BD%95%E5%88%A0%E9%99%A4%E5%8C%85%E5%90%AB%20150%2C000%20%E7%A7%8D%E5%B5%8C%E5%85%A5%E5%AD%97%E4%BD%93%E7%9A%84%20PDF%20%E6%96%87%E6%A1%A3%E4%B8%AD%E7%9A%84%E9%87%8D%E5%A4%8D%E5%AD%97%E4%BD%93%EF%BC%9F.png)
我正在分析一个 PDF 文件,想看看它为什么这么大(400MB)以及有哪些方法可以减小它的大小。
PDF 文件是由大约 15,000 个较小的 PDF 文件合并而成,这些文件使用模板制作,理论上应该具有相同的字体集。这些小 PDF 文件是由第三方系统生成的,对我们来说是一个黑匣子。
我怀疑合并的 PDF 文件中每种字体都被添加了多次,因此我认为第一步,我可以通过删除重复的字体来减小其文件大小。
我检查了pdffonts
其中一个单独的小型 PDF 文件中使用的字体:
$ pdffonts small-00001.pdf
name type encoding emb sub uni object ID
------------------------------------ ----------------- ---------------- --- --- --- ---------
[none] Type 3 Custom yes no yes 6 0
[none] Type 3 Custom yes no yes 25 0
[none] Type 3 Custom yes no yes 56 0
[none] Type 3 Custom yes no yes 95 0
[none] Type 3 Custom yes no yes 125 0
[none] Type 3 Custom yes no yes 141 0
[none] Type 3 Custom yes no yes 188 0
[none] Type 3 Custom yes no yes 212 0
[none] Type 3 Custom yes no yes 237 0
[none] Type 3 Custom yes no yes 245 0
有点奇怪的是,所有字体都没有名字,但显然这是规范允许的(见表 112(.pdf)) 因为 PDF 文件的版本是 1.4。无论如何,这个小 PDF 文件有 10 种字体。
我看了一下合并的 PDF 文件:
$ pdffonts merged.pdf | wc -l
150000 # rounded number
瞧!合并后的 PDF 文件有超过 150K 种字体!
iText Java PDF 库有一个名为Pdf智能复制用于合并 PDF 文件,其中具有一些智能功能,可以避免合并输出中出现重复的资源(例如字体)。
我编写了一个程序来合并单个文件PdfSmartCopy
,它将合并后的 PDF 文件的大小从 400MB 减少到不到 100MB。我原本pdffonts
以为这个“智能”合并的 PDF 中只有 10 种字体,但令我惊讶的是:
$ pdffonts
20000 # rounded number
因此,嵌入字体的数量从大约 150K 减少到 20K,但我想知道是否有办法进一步减少字体数量,或者就 PDF 而言,这 20K 字体是否真的有区别?
在文本编辑器中打开小型 PDF 文件,我看到以下字体定义:
6 0 obj
<</FontBBox[-40 -200 1000 920]/LastChar 249/FontMatrix[.001 0 0 .001 0 0]/Type/Font/Subtype/Type3/Encoding 7 0 R/CharProcs 8 0 R/ToUnicode 24 0 R/Widths[280 1000 1000 1000 1000 1000 1000 1000 1000 1000 560 280 600 320 600 1000 680 1000 1000 1000 1000 1000 1000 1000 1000 1000 320 560 400 320 280 1000 320 280 1000 1000 1000 1000 1000 1000 1000 1000 1000 280 880 560 600 560 1000 1000 1000 1000 1000 1000 1000 1000 1000 320 280 560 1000 200 600 360 1000 560 560 520 560 560 280 560 560 240 1000 1000 1000 1000 1000 1000 1000 240 520 240 880 560 560 560 560 320 1000 1000 1000 1000 1000 1000 1000 1000 520 280 560 440 720 440 480 480 1000 1000 1000 280 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 280 1000 1000 1000 680 680 720 720 680 600 760 720 240 1000 1000 1000 1000 1000 1000 1000 520 680 560 840 720 760 680 760 720 1000 1000 1000 1000 1000 1000 560 1000 680 560 720 680 1040 680 640 600 1000 1000 1000 1000 1000 1000 560 560 560 560 560 560 560 560 560 560]/FirstChar 64>>
endobj
25 0 obj
<</FontBBox[-57 -228.86 1029 914]/LastChar 249/FontMatrix[.001 0 0 .001 0 0]/Type/Font/Subtype/Type3/Encoding 26 0 R/CharProcs 27 0 R/ToUnicode 55 0 R/Widths[286 1029 1029 1029 1029 1029 1029 1029 1029 1029 543 286 571 343 571 1029 657 1029 1029 1029 1029 1029 1029 1029 1029 1029 314 543 400 343 286 1029 343 286 1029 1029 1029 1029 1029 1029 1029 1029 1029 286 886 543 571 543 1029 1029 1029 1029 1029 1029 1029 1029 1029 343 286 543 1029 200 571 343 1029 514 543 514 543 514 286 543 543 200 1029 1029 1029 1029 1029 1029 1029 257 514 200 829 543 514 543 543 343 1029 1029 1029 1029 1029 1029 1029 1029 514 286 543 486 686 429 486 486 1029 1029 1029 286 1029 1029 1029 1029 1029 1029 1029 1029 1029 1029 1029 1029 1029 1029 1029 286 1029 1029 1029 657 657 714 714 657 600 771 714 257 1029 1029 1029 1029 1029 1029 1029 514 657 543 829 714 771 657 771 714 1029 1029 1029 1029 1029 1029 543 1029 657 600 714 657 1029 657 657 600 1029 1029 1029 1029 1029 1029 543 543 543 543 543 543 543 543 543 543]/FirstChar 64>>
endobj
56 0 obj
<</FontBBox[-30 -214.77 1002.5 939]/LastChar 227/FontMatrix[.001 0 0 .001 0 0]/Type/Font/Subtype/Type3/Encoding 57 0 R/CharProcs 58 0 R/ToUnicode 94 0 R/Widths[273 1030 1030 1030 1030 1030 1030 1030 1030 1030 545 273 576 333 576 1030 636 1030 1030 1030 1030 1030 1030 1030 1030 1030 333 545 394 333 273 1030 333 273 1030 1030 1030 1030 1030 1030 1030 1030 1030 273 879 545 576 545 1030 1030 1030 1030 1030 1030 1030 1030 1030 333 273 545 1030 182 576 364 1030 515 545 515 545 515 303 545 545 212 1030 1030 1030 1030 1030 1030 1030 212 485 212 818 545 515 545 545 333 1030 1030 1030 1030 1030 1030 1030 1030 515 273 545 455 667 455 455 485 1030 1030 1030 273 1030 1030 1030 1030 1030 1030 1030 1030 1030 1030 1030 1030 1030 1030 1030 273 1030 1030 1030 667 667 727 727 667 606 788 727 273 1030 1030 1030 1030 1030 1030 1030 515 667 545 818 727 788 667 788 727 1030 1030 1030 1030 1030 1030 515 1030 667 636]/FirstChar 64>>
endobj
95 0 obj
<</FontBBox[-52 -243.17 1036 914]/LastChar 232/FontMatrix[.001 0 0 .001 0 0]/Type/Font/Subtype/Type3/Encoding 96 0 R/CharProcs 97 0 R/ToUnicode 124 0 R/Widths[276 983 983 983 983 983 983 983 983 983 552 276 586 328 586 983 707 983 983 983 983 983 983 983 983 983 310 552 397 328 345 983 328 276 983 983 983 983 983 983 983 983 983 276 879 552 586 603 983 983 983 983 983 983 983 983 983 328 345 552 983 241 586 483 983 552 603 552 603 552 328 603 603 276 983 983 983 983 983 983 983 276 534 276 897 603 603 603 603 397 983 983 983 983 983 983 983 983 552 328 603 517 776 534 517 500 983 983 983 328 983 983 983 983 983 983 983 983 983 983 983 983 983 983 983 328 983 983 983 707 724 724 724 672 603 776 724 276 983 983 983 983 983 983 983 552 707 603 845 724 776 672 776 724 983 983 983 983 983 983 552 983 672 603 724 672 948 655 638]/FirstChar 64>>
endobj
125 0 obj
<</FontBBox[-48 -236.5 1021.8 929]/LastChar 230/FontMatrix[.001 0 0 .001 0 0]/Type/Font/Subtype/Type3/Encoding 126 0 R/CharProcs 127 0 R/ToUnicode 140 0 R/Widths[286 976 976 976 976 976 976 976 976 976 548 286 595 333 595 976 714 976 976 976 976 976 976 976 976 976 333 548 381 333 333 976 333 286 976 976 976 976 976 976 976 976 976 286 833 548 595 619 976 976 976 976 976 976 976 976 976 333 333 548 976 238 595 476 976 548 619 548 619 548 333 619 619 286 976 976 976 976 976 976 976 286 524 286 881 619 619 619 619 381 976 976 976 976 976 976 976 976 548 333 619 524 786 524 548 500 976 976 976 333 976 976 976 976 976 976 976 976 976 976 976 976 976 976 976 333 976 976 976 690 714 714 714 667 619 786 714 286 976 976 976 976 976 976 976 548 690 619 833 714 786 667 786 714 976 976 976 976 976 976 548 976 667 643 714 667 929]/FirstChar 64>>
endobj
141 0 obj
<</FontBBox[-53 -238.45 1028.2 895]/LastChar 249/FontMatrix[.001 0 0 .001 0 0]/Type/Font/Subtype/Type3/Encoding 142 0 R/CharProcs 143 0 R/ToUnicode 187 0 R/Widths[289 1026 1026 1026 1026 1026 1026 1026 1026 1026 553 289 579 342 579 1026 658 1026 1026 1026 1026 1026 1026 1026 1026 1026 289 553 395 342 289 1026 342 289 1026 1026 1026 1026 1026 1026 1026 1026 1026 289 895 553 579 553 1026 1026 1026 1026 1026 1026 1026 1026 1026 342 289 553 1026 184 579 342 1026 553 553 500 553 526 289 553 553 237 1026 1026 1026 1026 1026 1026 1026 237 500 237 868 553 553 553 553 342 1026 1026 1026 1026 1026 1026 1026 1026 500 289 553 500 684 447 500 474 1026 1026 1026 289 1026 1026 1026 1026 1026 1026 1026 1026 1026 1026 1026 1026 1026 1026 1026 289 1026 1026 1026 658 658 711 711 658 605 789 711 289 1026 1026 1026 1026 1026 1026 1026 500 658 553 816 711 789 658 789 711 1026 1026 1026 1026 1026 1026 553 1026 658 605 711 658 1000 658 658 605 1026 1026 1026 1026 1026 1026 553 553 553 553 553 553 553 553 553 553]/FirstChar 64>>
endobj
188 0 obj
<</FontBBox[-40 -240 1040 940]/LastChar 227/FontMatrix[.001 0 0 .001 0 0]/Type/Font/Subtype/Type3/Encoding 189 0 R/CharProcs 190 0 R/ToUnicode 211 0 R/Widths[280 980 980 980 980 980 980 980 980 980 560 280 580 340 580 980 720 980 980 980 980 980 980 980 980 980 300 560 380 340 340 980 340 280 980 980 980 980 980 980 980 980 980 280 840 560 580 620 980 980 980 980 980 980 980 980 980 340 340 560 980 240 580 480 980 560 620 560 620 560 340 620 600 280 980 980 980 980 980 980 980 280 540 280 880 600 620 620 620 380 980 980 980 980 980 980 980 980 560 340 600 520 780 540 540 500 980 980 980 340 980 980 980 980 980 980 980 980 980 980 980 980 980 980 980 340 980 980 980 700 720 720 720 660 620 780 720 260 980 980 980 980 980 980 980 560 700 620 820 720 780 660 780 720 980 980 980 980 980 980 560 980 660 640]/FirstChar 64>>
endobj
212 0 obj
<</FontBBox[-48 -212.73 998.26 905]/LastChar 249/FontMatrix[.001 0 0 .001 0 0]/Type/Font/Subtype/Type3/Encoding 213 0 R/CharProcs 214 0 R/ToUnicode 236 0 R/Widths[286 1024 1024 1024 1024 1024 1024 1024 1024 1024 548 286 595 333 595 1024 667 1024 1024 1024 1024 1024 1024 1024 1024 1024 333 548 381 333 286 1024 333 286 1024 1024 1024 1024 1024 1024 1024 1024 1024 286 881 548 595 548 1024 1024 1024 1024 1024 1024 1024 1024 1024 333 286 548 1024 190 595 357 1024 548 548 500 548 548 310 548 548 238 1024 1024 1024 1024 1024 1024 1024 238 500 238 857 548 548 548 548 333 1024 1024 1024 1024 1024 1024 1024 1024 476 286 548 548 667 524 500 500 1024 1024 1024 286 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 1024 286 1024 1024 1024 667 667 714 714 667 619 786 714 286 1024 1024 1024 1024 1024 1024 1024 500 667 548 833 714 786 667 786 714 1024 1024 1024 1024 1024 1024 548 1024 667 619 714 667 1000 643 667 619 1024 1024 1024 1024 1024 1024 548 548 548 548 548 548 548 548 548 548]/FirstChar 64>>
endobj
237 0 obj
<</FontBBox[-27 -253.67 733 800]/LastChar 243/FontMatrix[.001 0 0 .001 0 0]/Type/Font/Subtype/Type3/Encoding 238 0 R/CharProcs 239 0 R/ToUnicode 244 0 R/Widths[173 173 173 173]/FirstChar 240>>
endobj
245 0 obj
<</FontBBox[-53 -238.45 1028.6 947]/LastChar 249/FontMatrix[.001 0 0 .001 0 0]/Type/Font/Subtype/Type3/Encoding 246 0 R/CharProcs 247 0 R/ToUnicode 293 0 R/Widths[289 974 974 974 974 974 974 974 974 974 553 289 579 342 579 974 711 974 974 974 974 974 974 974 974 974 289 553 395 342 342 974 342 289 974 974 974 974 974 974 974 974 974 289 868 553 579 605 974 974 974 974 974 974 974 974 974 342 342 553 974 237 579 474 974 553 605 553 605 553 342 605 605 289 974 974 974 974 974 974 974 289 526 289 921 605 605 605 605 395 974 974 974 974 974 974 974 974 553 342 605 526 763 526 526 474 974 974 974 342 974 974 974 974 974 974 974 974 974 974 974 974 974 974 974 342 974 974 974 711 711 711 711 658 605 789 711 289 974 974 974 974 974 974 974 553 684 605 868 711 789 658 789 711 974 974 974 974 974 974 553 974 658 605 711 658 921 632 632 605 974 974 974 974 974 974 553 553 553 553 553 553 553 553 553 553]/FirstChar 64>>
endobj
1 0 obj
<</Contents 2 0 R/Type/Page/Resources<</XObject<</Im3 3 0 R/Im1 4 0 R/Im2 5 0 R>>/Font<</F1 6 0 R/F2 25 0 R/F10 56 0 R/F3 95 0 R/F4 125 0 R/F5 141 0 R/F6 188 0 R/F9 212 0 R/F8 237 0 R/F7 245 0 R>>>>/MediaBox[0 0 595.2 841.92]/Parent 294 0 R>>
endobj
这真的是 10-11 种不同的字体吗?或者这 10 个组件是同一种字体?
另外根据规范:
CharProcs:(必需)一个字典,其中每个键应为字形名称,与该键关联的值应为构造和绘制该字符的字形的内容流。该流应包括其第一个运算符 d0 或 d1,后跟描述一个或多个图形对象的运算符,这些图形对象可能包括路径、文本或图像对象。有关类型 3 字形描述的更多详细信息,请参阅下文。
但CharProcs
这个 PDF 文件中的内容看起来太小,“成为构建和绘制该字符字形的内容流”。 例如:
237 0 obj
<<
/FontBBox[-27 -253.67 733 800]
/LastChar 243
/FontMatrix[.001 0 0 .001 0 0]
/Type/Font
/Subtype/Type3
/Encoding 238 0 R
/CharProcs 239 0 R
/ToUnicode 244 0 R
/Widths[173 173 173 173]
/FirstChar 240>>
endobj
这些
/FontBBox
片段各自代表一种字体吗?为什么它们/CharProcs
太小了?我如何确认最终 PDF 文件中的这 20,000K 字体确实不同——如果不是,我如何进一步删除重复项?
答案1
Type3 字体在 PDF 文件中极为罕见。Type3 字体实际上是 PDF 字体,因为字形是在 PDF 页面图形操作符中描述的。因此,您永远不会在 PDF 之外遇到 Type 3 字体,因为只有 PDF 渲染器才知道该怎么做。
字形在 CharProcs 键引用的对象中定义。所以上一个示例中的对象是 239。/FontBBox 通常仅用于文本选择。您可能只需合并所有 FontBBox 即可。
您可以检查图形操作符,甚至只是散列流,以找到匹配项。然后,也许您可以使用收集的字体合成新字体。但是,您还需要检查编码。如果每种字体的编码不同,不同的字符代码映射到不同的字形,那么您需要返回并使用新的字符代码重写页面内容流。最后,您可能希望保持 ToUnicode 映射正确(如果您想保留文本选择/提取),这意味着还要跟踪字符代码到 unicode 映射并生成新的 ToUnicode CMap。
简而言之,修复作为后处理步骤并非易事。
通常,当您创建 PDF 文件并合并时,返回并处理问题的根源会更好/更容易,这样您就不会遇到该问题。