跳转到内容
getnextpdf.com

Pro 版本

Font Tools — 深度参考

本页是 NextPDF Pro Font Tools 的契约级参考。其接口面为一个扫描器 NextPDF\Pro\FontTools\FontDesubsetter,以及两个不可变值对象 SubsetInfoDesubsetPlan。扫描器读取原始 PDF 字节,报告每一个不同的 /BaseFont 条目,并标记出符合 ISO 32000-2:2020 §9.9.2 子集命名约定的条目。规划会汇总被标记的子集,并估算恢复完整字体程序所需的字节开销。本模块仅做分析与估算;它绝不会重写嵌入的字体程序。本页阐明公共 API、可观测的行为契约以及失败模式。

本能力随 NextPDF Pronextpdf/pro)发布,并通过 Pro 级授权信封激活。未持有该授权的部署不会加载本能力的类。比较版本并获取授权

没有逐功能的授权标记门控本模块。只要安装了 nextpdf/pro,Font Tools 的类即可使用。

符号参数默认行为返回抛出或失败于备注
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收集 isSubsettrue 的条目并累加大小估算DesubsetPlan不抛出非子集条目被静默跳过
SubsetInfo构造函数:$fontName$baseFont$subsetGlyphCount$fullGlyphCount$isSubset$encoding对单个 /BaseFont 条目的不可变描述字形计数为负、或子集计数高于完整计数时,抛出 InvalidArgumentExceptionfinal readonly;所有属性公开
SubsetInfo::subsetPrefix()fontName 提取六字母标签string当非子集、或 + 不在第六位时返回空字符串
SubsetInfo::coveragePercent()子集在完整字形集中的占比[0.0, 100.0] 范围内的 floatfullGlyphCount0 时返回 0.0
DesubsetPlan构造函数:list<SubsetInfo> $targetsint $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): DesubsetPlan
public 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(): float
public 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-HIdentity-V 子串。两者皆无,则该条目报告 Unknown。存放于字典中或通过间接引用抵达的编码值报告为 Unknown

两个字形计数都是估算值。subsetGlyphCount 由字体条目附近可见的宽度数组推导得出:CIDFont 的 /W 数组大致每个宽度三元组产出一个字形,而简单字体的 /Widths 数组每个数值条目产出一个字形。当窗口内两种数组皆不可见时,套用一个较小的固定默认值。当无法为窗口搜索重新定位 /BaseFont 的出现处时,计数为 0fullGlyphCount 由族名启发式推导得出:一张知名 Latin 族名表、一组 CJK 族名指示符,其余情况则取一个通用下限。嵌入的字体程序绝不会被解析。具体的表、窗口大小与常量属于实现细节,不予公开,且可能在不同发行版之间变化。

generateDesubsetPlan() 将输入过滤为 isSubsettrue 的条目。每个目标以其缺失字形计数乘以一个固定的“每字形平均字节数”常量,计入 estimatedSizeIncrease。该规划是用于容量决策的预估,而非实测的差值。执行规划——即重写字体程序——不在本模块范围之内。

整个接口面是其输入的纯函数。相同的字节产生相同的结果。没有任何随机性、网络调用或文件系统访问。

  • SubsetInfo 的构造会拒绝无效状态:字形计数为负、或子集计数高于完整计数,都会抛出 InvalidArgumentException
  • analyzeSubsets() 会在一种边角情形下传播该异常:某字体的名称匹配已知族,但其可见的宽度数组产出的子集估算大于该族的完整计数数值。
  • 检测作用于字节表示。序列化在压缩对象流内部的 /BaseFont 条目不可见;请在扫描前解压这些流。
  • /BaseFont 的键与值之间以单个空格以外的空白分隔,此类条目仍会被检测到,但逐字体的窗口搜索无法重新定位它们。这些条目报告编码为 Unknown,子集字形计数为 0
  • 使用 # 转义字节的 PDF 名称以原始转义形式报告;转义不会被解码。
  • 重复的 /BaseFont 名称会合并为单个条目。两个共享同一名称的不同字体对象对本扫描器而言无法区分。
  • generateDesubsetPlan() 对非子集输入绝不失败;isSubsetfalse 的条目仅仅被排除在 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/pro 1.9.0 起可用;当前为 nextpdf/pro 3.1.0。
  • FontDesubsetter 是无状态的。构造一次即可跨文档与工作线程复用。
  • 当子集覆盖情况重要时,向 analyzeSubsets() 提供解压后的字节;否则被打包进对象流的字体字典会被遗漏。
  • 在采取行动前根据 SubsetInfo::isSubset 分支处理;结果列表出于清点目的有意包含非子集字体。
  • 在获取完整字体程序之前,用 DesubsetPlan::totalGlyphsNeeded()estimatedSizeIncrease 判断去子集化是否值得付出文件大小的代价。
  • 扫描的时间复杂度与输入长度成线性,逐字体窗口搜索有界。本模块不存储任何内容,也不发出任何遥测。

本页仅记录外部可观测的行为与受支持的公共 API 接口面。内部命名空间路径、辅助类、机制表、运维手册文件名以及工单前缀均不在范围之内。