结论先行:PDF字体子集化能减小90%体积,根本原因是中文字体动辄15-20MB,而文档实际只用到一两千个字符。子集化的核心原理是三步——扫描文档中实际使用的字符集合、重建CMap映射表、重排字形索引丢弃未用字形。思源宋体完整文件18MB,子集化后仅0.4MB,降幅97.7%。下面从字体文件结构讲起,详解子集化的技术原理,并附三款字体的实测对比数据。
如果你对PDF压缩的整体方法还不太熟悉,建议先阅读PDF압축 원리与方法详解。
一、字体文件结构:为什么中文嵌入字体那么大
要理解子集化为什么有效,先得搞清楚字体文件里装了什么。TrueType(.ttf)和OpenType(.otf)字体文件由多张数据表组成,每张表负责不同功能。嵌入PDF时,这些表被完整打包进文件,不管文档用了几个字。
| 数据表 | 功能 | 典型占比 | 子集化能否裁剪 |
|---|---|---|---|
| cmap | 字符编码到字形索引的映射 | 1%–3% | 需重建 |
| glyf | TrueType字形轮廓数据 | 70%–85% | 可大幅裁剪 |
| CFF | OpenType CFF字形轮廓(PostScript) | 60%–80% | 可大幅裁剪 |
| loca | 字形数据位置索引 | 1%–2% | 需重建 |
| hmtx | 水平度量(字宽/前进量) | 2%–5% | 需重建 |
| name | 字体名称、版权等元信息 | 0.5%–1% | 保留 |
| post | PostScript名称映射 | 1%–3% | 部分裁剪 |
从上表可以看出,字形轮廓数据(glyf表或CFF表)占了字体文件60%–85%的体积。一个中文字体包含2万到7万个字形,每个汉字的矢量轮廓数据平均300–600字节,合计就是10–20MB。而一份50页的PDF文档通常只用到800–2000个不同字符,意味着95%以上的字形数据是浪费的——这正是子集化的压缩空间所在。
二、子集化原理:三步裁剪未用字形
字体子集化的核心思路是:只保留文档实际用到的字形,丢弃其余。实现过程分三个关键步骤,每步都涉及字体表结构的精确操作。
| 步骤 | 操作 | 原理 | 处理的数据表 |
|---|---|---|---|
| 1. 字符使用扫描 | 遍历PDF所有页面内容流,提取显示的字符编码 | 通过解析文本操作符(Tj/TJ)收集Unicode码点 | 无(生成字符集合) |
| 2. CMap表重建 | 根据使用字符重建编码到字形索引的映射 | 仅保留使用字符的映射条目,删除其余 | cmap |
| 3. 字形索引重映射 | 将使用字形连续重排,更新所有引用索引 | 原索引可能不连续,重排后索引0到N连续 | glyf/CFF, loca, hmtx |
1. 字符使用扫描
第一步是扫描PDF文档,找出所有实际显示的字符。PDF中的文字通过文本操作符(Tj显示字符串、TJ显示数组)写入内容流,每个字符对应一个编码。子集化工具遍历所有页面的内容流,提取这些编码,再通过字体当前的CMap表转换为Unicode码点,最终得到一个"已使用字符集合"。
扫描时还需要处理特殊情况:ToUnicode CMap(反向映射)、多字节编码(CJK字体常用)、嵌入字体的子集化前缀(六字符+号格式)。一份50页中文PDF通常扫描出800–2000个不同Unicode字符,加上标点和数字,总计约1000–2500个字形需要保留。
2. CMap表重建
CMap表是字体的"目录",记录每个字符编码对应的字形索引(glyph ID)。原始中文字体的CMap表包含2万到7万条映射,子集化后只保留使用字符对应的条目。重建时还需要处理多种编码子表格式。
| CMap子表格式 | 编码范围 | 用途 | 子集化处理 |
|---|---|---|---|
| Format 0 | 0–255 | 单字节ASCII/Latin | 裁剪未用条目 |
| Format 4 | BMP基本平面 | 中日韩常用字符 | 重建区段表 |
| Format 12 | 全Unicode | 覆盖所有字符 | 裁剪未用区段 |
3. 字形索引重映射
这是最关键也最复杂的一步。原始字体中字形索引(GID)从0到N连续排列,但需要保留的字形可能分散在各处。重映射就是把保留的字形按新顺序连续排列:原GID 0(.notdef)保持不变,原GID 1523可能变成新GID 1,原GID 8944变成新GID 2,以此类推。
重映射后需要同步更新所有引用GID的表:glyf表(或CFF表)只保留对应字形数据并按新索引排列、loca表重建位置索引、hmtx表重建水平度量数据、post表更新PostScript名称映射。这一步处理不当会导致字体损坏,因此需要严格遵循OpenType规范。
三、实测数据:三款字体子集化前后对比
我们选取三款常用字体进行子集化实测,分别代表中文字体(思源宋体、微软雅黑)和英文字体(Arial)。测试文档为50页中文投标书,使用字符数1342个。
| 字体 | 原始文件 | 字形数(原始) | 字形数(子集) | 子集化后 | 降幅 |
|---|---|---|---|---|---|
| 思源宋体 Regular | 18.2MB | 65535 | 1342 | 0.42MB | 97.7% |
| 微软雅黑 Regular | 15.6MB | 28622 | 1342 | 0.35MB | 97.8% |
| Arial Regular | 0.82MB | 3257 | 96 | 0.06MB | 92.7% |
实测数据显示,中文字体子集化效果最为显著——思源宋体从18.2MB降到0.42MB,降幅97.7%。这是因为中文字体字形多(6万+)但文档用到的少(1000+),裁剪空间巨大。英文字体Arial原始仅0.82MB,子集化后0.06MB,降幅92.7%,绝对体积虽小但比例同样可观。
再看不同字符使用量下的子集化效果,以思源宋体为例:
| 文档类型 | 使用字符数 | 子集化后体积 | 降幅 | 说明 |
|---|---|---|---|---|
| 短通知(1页) | 约200 | 0.08MB | 99.6% | 字符极少,子集极小 |
| 会议纪要(10页) | 约600 | 0.19MB | 99.0% | 日常办公文档 |
| 投标书(50页) | 约1342 | 0.42MB | 97.7% | 专业文档字符覆盖广 |
| 技术手册(200页) | 约2800 | 0.85MB | 95.3% | 字符使用量大 |
| 百科全书(1000页) | 约6500 | 1.92MB | 89.5% | 接近极限覆盖率 |
四、子集化工具对比与场景推荐
字体子集化有多种工具可选,从开源命令行工具到商业压缩引擎,各有优劣。下表对比主流方案。
| 工具 | 子集化能力 | CFF支持 | 批量处理 | 集成难度 |
|---|---|---|---|---|
| 智压通 SmartSlim | ★★★★★ | 是 | 支持 | SDK/API/桌面 |
| fonttools (Python) | ★★★★☆ | 是 | 需脚本 | 中等 |
| Adobe Acrobat | ★★★★☆ | 是 | 有限 | GUI操作 |
| Ghostscript | ★★★☆☆ | 部分 | 支持 | 命令行 |
| 在线工具 | ★★☆☆☆ | 部分 | 不支持 | 低(有隐私风险) |
智压通 SmartSlim 基于自研 Rust 压缩引擎,在子集化时自动处理TrueType和OpenType CFF两种字形格式,支持批量拖拽处理数百个PDF。更重要的是,整个子集化过程在本地完成,字体数据和文档内容不经过任何外部服务器,对涉密文档和企业敏感文件尤为关键。
不同场景的子集化策略建议:
| 场景 | 是否建议子集化 | 注意事项 | 推荐工具 |
|---|---|---|---|
| 终稿归档分发 | 强烈推荐 | 子集化后不可编辑新字符 | 智压通 SmartSlim |
| 企业批量归档 | 强烈推荐 | 用API自动化批量处理 | 智压通服务器版 |
| 在线发布/预览 | 推荐 | 减小下载体积提升加载速度 | fonttools脚本 |
| 仍需编辑的草稿 | 不推荐 | 保留完整字体以便编辑 | 暂不子集化 |
| 涉密/机密文档 | 推荐 | 必须本地处理,禁用在线工具 | 智压通 SmartSlim |
更多PDF优化技巧,可以参考PDF线性化优化指南和Word文档压缩方法。
五、常见问题FAQ
Q1:PDF字体子集化会影响显示效果吗?
不会。字体子集化只丢弃文档中未使用的字符和字形数据,保留的字符与原字体完全一致,显示效果零影响。子集化后字体仍是矢量轮廓,放大缩小不失真,颜色粗细等属性也保持不变。唯一限制是子集化后的字体只能用于该文档,无法在其他文档中复用。
Q2:字体子集化能减小多少体积?
取决于字符使用量与原字体大小的比值。中文字体(如思源宋体18MB)通常只用1000-2000个字符,子集化后体积降至0.3-0.8MB,降幅95%以上。英文字体(如Arial 0.8MB)使用字符更少,子集化后0.05-0.1MB,降幅约90%。字体越大、使用字符越少,子集化效果越显著。
Q3:子集化后的PDF还能编辑文字吗?
有限制。子集化只保留了文档已使用的字符,如果编辑时输入了新字符(原文档中未出现的字),该字符将无法显示,会显示为方框或空白。因此子集化适合终稿归档和分发,不适合仍需大量编辑的文档。若需编辑,建议保留完整字体或重新嵌入子集。
Q4:如何检查PDF是否已经做了字体子集化?
用Adobe Acrobat打开PDF,点击文件-属性-字体,查看嵌入字体列表。如果字体名称带有六字符前缀(如ABCDEO+思源宋体),说明已子集化。也可以用智压通 SmartSlim 打开PDF,引擎会自动分析字体嵌入状态并提示是否需要子集化,同时给出预估压缩体积。
总结
PDF字体子集化是减小PDF体积最有效的手段之一,尤其对嵌入中文字体的文档效果显著。核心原理是三步操作:扫描使用字符、重建CMap映射表、重排字形索引丢弃未用字形。实测数据显示,思源宋体18MB子集化后仅0.4MB,降幅97.7%,且对显示效果零影响。
实操建议:终稿分发前务必做字体子集化,涉密文档用本地工具处理。如果你需要批量处理PDF文件,智压通 SmartSlim 支持 PDF/图片/视频/Office/OFD 等 10 大类 40+ 格式,基于自研 Rust 压缩引擎自动完成字体子集化,数据不出域。