字型子集化¶
字型子集化是將完整字型檔案裁剪為僅包含文件實際使用之字符的技術。NextPDF 的 FontSubsetter 同時支援 TrueType(glyph 資料)與 CFF(OpenType/Type2 Charstring)兩種格式的子集化,在不犧牲渲染品質的前提下大幅縮減輸出 PDF 的體積。
子集化流程¶
文件渲染
└── 收集使用的 Unicode 碼點(UnicodeCollector)
└── 映射至 Glyph ID(GlyphMapper)
└── 裁剪字型資料(FontSubsetter)
└── 生成 ToUnicode CMap
└── 嵌入子集字型至 PDF
TrueType 子集化¶
use NextPDF\Typography\Subsetting\TrueTypeSubsetter;
// TrueTypeSubsetter 由 FontRegistry 內部自動調用
// 開發者通常不需要直接使用此類別
// 進階:手動子集化(用於自訂工作流程)
$subsetter = TrueTypeSubsetter::create();
$subsetBytes = $subsetter->subset(
fontBytes: file_get_contents('/path/to/font.ttf'),
glyphIds: [0, 1, 3, 45, 892, 1024], // 要保留的 Glyph ID
);
CFF 子集化¶
OpenType 字型(副檔名 .otf)使用 CFF(Compact Font Format)儲存 glyph 輪廓,子集化策略與 TrueType 有所不同:
use NextPDF\Typography\Subsetting\CffSubsetter;
$subsetter = CffSubsetter::create();
$subsetBytes = $subsetter->subset(
fontBytes: file_get_contents('/path/to/font.otf'),
codepoints: [0x0041, 0x0042, 0x4E2D, 0x6587], // A, B, 中, 文
);
ToUnicode CMap 生成¶
子集化後必須生成 ToUnicode CMap,確保 PDF 中的文字可以被正確複製與搜尋:
use NextPDF\Typography\Subsetting\CMapGenerator;
// 由 FontSubsetter 內部自動調用
$cmap = CMapGenerator::generate(
mapping: $glyphToUnicodeMapping,
fontName: 'ABCDEF+NotoSansCJK-Regular', // 子集字型名稱前綴
);
子集字型命名¶
PDF 規範要求子集字型使用 6 個大寫字母的隨機前綴:
NextPDF 使用密碼學安全的隨機前綴生成器:
// 內部實作(供參考)
$prefix = SubsetPrefix::generate(); // 例如:'XQRTPZ'
$subsetName = $prefix . '+' . $originalName; // 'XQRTPZ+NotoSansCJK-Regular'
效能¶
| 字型 | 完整大小 | 10 字符子集 | 500 字符子集 |
|---|---|---|---|
| NotoSansCJKtc-Regular | ~16 MB | ~12 KB | ~280 KB |
| Helvetica Neue | ~320 KB | ~8 KB | ~64 KB |