Pro 版本
Font Tools — 深度参考
本页是 NextPDF Pro Font Tools 的契约级参考。其接口面为一个扫描器 NextPDF\Pro\FontTools\FontDesubsetter,以及两个不可变值对象 SubsetInfo 与 DesubsetPlan。扫描器读取原始 PDF 字节,报告每一个不同的 /BaseFont 条目,并标记出符合 ISO 32000-2:2020 §9.9.2 子集命名约定的条目。规划会汇总被标记的子集,并估算恢复完整字体程序所需的字节开销。本模块仅做分析与估算;它绝不会重写嵌入的字体程序。本页阐明公共 API、可观测的行为契约以及失败模式。
可用性与授权
标题为“可用性与授权”的章节本能力随 NextPDF Pro(nextpdf/pro)发布,并通过 Pro 级授权信封激活。未持有该授权的部署不会加载本能力的类。比较版本并获取授权。
没有逐功能的授权标记门控本模块。只要安装了 nextpdf/pro,Font Tools 的类即可使用。
公共 API 接口面
标题为“公共 API 接口面”的章节| 符号 | 参数 | 默认行为 | 返回 | 抛出或失败于 | 备注 |
|---|---|---|---|---|---|
FontDesubsetter | 无 | 针对原始 PDF 字节的无状态扫描器 | — | — | final;可跨文档安全复用 |
FontDesubsetter::analyzeSubsets() | string $pdfData | 报告每一个不同的 /BaseFont 条目(无论是否为子集),并以 isSubset 标记 | list<SubsetInfo> | 当由宽度推导的子集估算超过由名称推导的完整计数估算时,抛出 InvalidArgumentException | 字节级扫描;不解码压缩的对象流 |
FontDesubsetter::isSubsetFont() | string $baseFontName | 匹配“六个大写字母加 +”的前缀约定 | bool | — | 锚定在名称的起始处 |
FontDesubsetter::extractSubsetPrefix() | string $baseFontName | 返回六字母的子集标签 | string | — | 对非子集名称返回空字符串 |
FontDesubsetter::generateDesubsetPlan() | list<SubsetInfo> $subsets | 收集 isSubset 为 true 的条目并累加大小估算 | DesubsetPlan | 不抛出 | 非子集条目被静默跳过 |
SubsetInfo | 构造函数:$fontName、$baseFont、$subsetGlyphCount、$fullGlyphCount、$isSubset、$encoding | 对单个 /BaseFont 条目的不可变描述 | — | 字形计数为负、或子集计数高于完整计数时,抛出 InvalidArgumentException | final readonly;所有属性公开 |
SubsetInfo::subsetPrefix() | 无 | 从 fontName 提取六字母标签 | string | — | 当非子集、或 + 不在第六位时返回空字符串 |
SubsetInfo::coveragePercent() | 无 | 子集在完整字形集中的占比 | [0.0, 100.0] 范围内的 float | — | 当 fullGlyphCount 为 0 时返回 0.0 |
DesubsetPlan | 构造函数:list<SubsetInfo> $targets、int $estimatedSizeIncrease | 不可变的去子集化规划 | — | — | final readonly;所有属性公开 |
DesubsetPlan::count() | 无 | 目标字体的数量 | int | — | 等于 targets 的长度 |
DesubsetPlan::totalGlyphsNeeded() | 无 | 所有目标缺失字形的总和 | int | — | 各目标 fullGlyphCount - subsetGlyphCount 之和 |
入口点签名
标题为“入口点签名”的章节public function analyzeSubsets(string $pdfData): array
public function isSubsetFont(string $baseFontName): bool
public function extractSubsetPrefix(string $baseFontName): string
public function generateDesubsetPlan(array $subsets): DesubsetPlanpublic function __construct( public string $fontName, public string $baseFont, public int $subsetGlyphCount, public int $fullGlyphCount, public bool $isSubset, public string $encoding,)
public function subsetPrefix(): string
public function coveragePercent(): floatpublic function __construct( public array $targets, public int $estimatedSizeIncrease,) {}
public function count(): int
public function totalGlyphsNeeded(): int行为契约
标题为“行为契约”的章节扫描与子集检测
标题为“扫描与子集检测”的章节analyzeSubsets() 以字节级的模式匹配从原始字节中提取 /BaseFont 名称标记。重复的名称会合并为一个条目;顺序遵循首次出现的次序。每个不同的名称都会产生一个 SubsetInfo,无论它是否为子集。当名称以恰好六个大写 ASCII 字母开头并紧跟 + 时,即为子集,这就是 §9.9.2 的约定。对子集名称,baseFont 是移除七字符前缀后的名称。对普通名称,baseFont 等于 fontName。每个不同的子集名称都作为独立条目报告,与 §9.9.2 将子集视为独立实体的指引一致。
编码检测
标题为“编码检测”的章节对每个字体,扫描器在 /BaseFont 出现处之后搜索一个有界的字节窗口。窗口内的 /Encoding 名称条目优先。若无,则报告窗口内的 Identity-H 或 Identity-V 子串。两者皆无,则该条目报告 Unknown。存放于字典中或通过间接引用抵达的编码值报告为 Unknown。
字形计量
标题为“字形计量”的章节两个字形计数都是估算值。subsetGlyphCount 由字体条目附近可见的宽度数组推导得出:CIDFont 的 /W 数组大致每个宽度三元组产出一个字形,而简单字体的 /Widths 数组每个数值条目产出一个字形。当窗口内两种数组皆不可见时,套用一个较小的固定默认值。当无法为窗口搜索重新定位 /BaseFont 的出现处时,计数为 0。fullGlyphCount 由族名启发式推导得出:一张知名 Latin 族名表、一组 CJK 族名指示符,其余情况则取一个通用下限。嵌入的字体程序绝不会被解析。具体的表、窗口大小与常量属于实现细节,不予公开,且可能在不同发行版之间变化。
规划生成
标题为“规划生成”的章节generateDesubsetPlan() 将输入过滤为 isSubset 为 true 的条目。每个目标以其缺失字形计数乘以一个固定的“每字形平均字节数”常量,计入 estimatedSizeIncrease。该规划是用于容量决策的预估,而非实测的差值。执行规划——即重写字体程序——不在本模块范围之内。
确定性
标题为“确定性”的章节整个接口面是其输入的纯函数。相同的字节产生相同的结果。没有任何随机性、网络调用或文件系统访问。
边界情形与失败模式
标题为“边界情形与失败模式”的章节SubsetInfo的构造会拒绝无效状态:字形计数为负、或子集计数高于完整计数,都会抛出InvalidArgumentException。analyzeSubsets()会在一种边角情形下传播该异常:某字体的名称匹配已知族,但其可见的宽度数组产出的子集估算大于该族的完整计数数值。- 检测作用于字节表示。序列化在压缩对象流内部的
/BaseFont条目不可见;请在扫描前解压这些流。 - 若
/BaseFont的键与值之间以单个空格以外的空白分隔,此类条目仍会被检测到,但逐字体的窗口搜索无法重新定位它们。这些条目报告编码为Unknown,子集字形计数为0。 - 使用
#转义字节的 PDF 名称以原始转义形式报告;转义不会被解码。 - 重复的
/BaseFont名称会合并为单个条目。两个共享同一名称的不同字体对象对本扫描器而言无法区分。 generateDesubsetPlan()对非子集输入绝不失败;isSubset为false的条目仅仅被排除在targets之外。- 所有计数与
estimatedSizeIncrease都是启发式的。不要将它们视为实测值;仅用于分诊与容量规划。 - 本模块不发生任何密码学操作,因此没有 FIPS 模式特有的行为。
一致性
标题为“一致性”的章节| 主张 | 标准 | 条款 |
|---|---|---|
子集检测匹配子集命名约定:在 BaseFont 值前缀以六个大写字母加 + 组成的标签。 | ISO 32000-2:2020 | §9.9.2 |
| 每个不同的子集名称都独立报告,遵循将多个子集视为独立实体的建议。 | ISO 32000-2:2020 | §9.9.2 |
所有条款均为改写;NextPDF 不复制规范性文本。这些是能力声明,而非认证。NextPDF 不持有任何认证,也不授予任何认证。本模块声明其对命名约定的检测与确定性报告;它不声明字形计数或大小估算的准确性。
开发说明
标题为“开发说明”的章节- 使用
composer require nextpdf/pro:^3安装。自nextpdf/pro1.9.0 起可用;当前为nextpdf/pro3.1.0。 FontDesubsetter是无状态的。构造一次即可跨文档与工作线程复用。- 当子集覆盖情况重要时,向
analyzeSubsets()提供解压后的字节;否则被打包进对象流的字体字典会被遗漏。 - 在采取行动前根据
SubsetInfo::isSubset分支处理;结果列表出于清点目的有意包含非子集字体。 - 在获取完整字体程序之前,用
DesubsetPlan::totalGlyphsNeeded()与estimatedSizeIncrease判断去子集化是否值得付出文件大小的代价。 - 扫描的时间复杂度与输入长度成线性,逐字体窗口搜索有界。本模块不存储任何内容,也不发出任何遥测。
发布边界
标题为“发布边界”的章节本页仅记录外部可观测的行为与受支持的公共 API 接口面。内部命名空间路径、辅助类、机制表、运维手册文件名以及工单前缀均不在范围之内。
另请参阅
标题为“另请参阅”的章节- Font Tools(能力) — 安装、快速上手与规划工作流示例。
- Optimizer — 深度参考 — 同类的体积缩减接口面,包含与字体相关的优化。
- Core 字体模块 — NextPDF Core 在文档创建过程中的字体嵌入与子集化。