Pro 版本
Merge — 深度参考
本页是 NextPDF Pro Merge 模块 NextPDF\Pro\Merge 的契约级参考。SmartMerger 将多个输入文档合并为一个,并应用 Pro 增强能力:由各输入标签汇总而成的合并书签树、整文档去重、按输入的页面范围选择,以及内部链接检测。SemanticSplitter 是配套的结构感知拆分入口。本页说明公共 API、可观察的行为契约、资源边界以及失败模式。任务导向的配置与示例见 Merge 能力页。
可用性与授权
标题为“可用性与授权”的章节本能力随 NextPDF Pro(nextpdf/pro)发布,并通过 Pro 级授权信封激活。缺少该授权的部署不会加载本能力的类。对比版本并获取授权。
没有任何运行时能力标记对本模块进行门控。只要安装并授权 nextpdf/pro,Merge 类即可使用。
公共 API 接口面
标题为“公共 API 接口面”的章节| 符号 | 参数 | 默认行为 | 返回 | 抛出或失败于 | 备注 |
|---|---|---|---|---|---|
SmartMerger::__construct() | ?PdfMerger $coreMerger = null, ?PdfSplitter $splitter = null | 接受并忽略遗留的 core merger;null 的 splitter 构造默认的 Pro splitter | — | — | $coreMerger 仅为向后兼容构造而保留 |
SmartMerger::merge() | list<MergeInput> $inputs, SmartMergeConfig $config = new SmartMergeConfig() | 缩减页面范围、对整个输入去重、委派基础组装,然后按配置注入书签并统计链接 | SmartMergeResult | 输入列表为空时抛出 InvalidArgumentException;输入数量超过 maxInputs 或某输入超过 maxBytesPerInput 时抛出 OverflowException | 唯一的合并入口 |
MergeInput::__construct() | string $pdfData, list<PageRange> $pageRanges = [], string $label = '' | 值对象;空的 $pageRanges 选择所有页面 | — | — | Readonly |
MergeInput::hasPageRanges() | — | 当输入携带至少一个页面范围时为 True | bool | — | — |
SmartMergeConfig::__construct() | bool $consolidateBookmarks = true, bool $deduplicatePages = false, bool $rewriteLinks = true, int $maxInputs = 100, int $maxBytesPerInput = 100_000_000 | 持有增强开关与资源边界的值对象 | — | — | Readonly;去重需显式开启 |
SmartMergeConfig::default() | — | 书签与链接扫描开启,去重关闭 | self | — | 静态工厂 |
SmartMergeConfig::basic() | — | 关闭全部增强;仅做基础拼接 | self | — | 静态工厂 |
SmartMergeResult::__construct() | string $pdfData, int $totalPages, int $sourceCount, int $mergedSize, int $bookmarksAdded = 0, int $duplicatesRemoved = 0, int $linksRewritten = 0, list<string> $inputLabels = [] | 承载合并后字节与汇总统计的 readonly 载体 | — | — | Readonly |
SmartMergeResult::isValid() | — | 当输出以 %PDF 头开始时为 True | bool | — | 仅做头部检查 |
SmartMergeResult::hasOptimizations() | — | 当移除了任何重复项或统计到任何链接时为 True | bool | — | — |
SemanticSplitter::__construct() | ?PdfSplitter $splitter = null | null 参数构造默认的 Pro splitter | — | — | 用于测试的构造函数注入 |
SemanticSplitter::splitByStructure() | string $pdfData, float $headingFontThreshold = 14.0 | 将标题大小的 Tf 操作符检测为分节起点并在这些边界处拆分;未检测到结构时返回单个整文档分节 | SplitResult | 缓冲区为空或缺少 %PDF 头时抛出 InvalidArgumentException;输入超过 100 MB 时抛出 OverflowException | 回退到 Core 页面范围拆分 |
入口签名
标题为“入口签名”的章节public function __construct( ?PdfMerger $coreMerger = null, ?PdfSplitter $splitter = null,)
public function merge( array $inputs, SmartMergeConfig $config = new SmartMergeConfig(),): SmartMergeResultpublic function __construct( public string $pdfData, public array $pageRanges = [], public string $label = '',)
public function hasPageRanges(): boolpublic function __construct( public bool $consolidateBookmarks = true, public bool $deduplicatePages = false, public bool $rewriteLinks = true, public int $maxInputs = 100, public int $maxBytesPerInput = 100_000_000,)
public static function default(): self
public static function basic(): selfpublic function isValid(): bool
public function hasOptimizations(): boolpublic function __construct(?PdfSplitter $splitter = null)
public function splitByStructure( string $pdfData, float $headingFontThreshold = 14.0,): SplitResult行为契约
标题为“行为契约”的章节合并管线
标题为“合并管线”的章节SmartMerger::merge() 运行一条固定管线,从外部观察如下。
- 空的输入列表抛出
InvalidArgumentException。随后输入数量受maxInputs约束;超限抛出OverflowException。 - 每个输入在使用前都会对照
maxBytesPerInput做尺寸检查。当输入声明了页面范围时,先通过 Pro splitter 缩减到所选页面,然后仅贡献这些页面。 - 当启用
deduplicatePages时,每个输入文档的完整字节串以非密码学的xxh128函数计算指纹。字节与更早某个输入完全匹配的输入会被丢弃。去重以整文档为单位且字节级精确。 - 基础组装委派给 Pro
PdfSplitter::mergeDocuments()引擎,它将每个输入重新编号进一个连续的对象空间,并发出真实的交叉引用表。 - 当启用
consolidateBookmarks且至少有一个输入携带非空标签时,应用书签合并。会插入一个最小的/Outlines字典,并从文档目录链接,按合并顺序为每个输入生成一个大纲条目。 - 当启用
rewriteLinks时,扫描合并输出中的/S /GoTo动作并报告其计数。
结果统计
标题为“结果统计”的章节SmartMergeResult 报告合并后的字节以及统计数据。totalPages 来自基础合并。sourceCount 是原始输入数量,在去重之前取得。mergedSize 是输出字节长度。bookmarksAdded 仅统计提供了非空标签的输入。duplicatesRemoved 统计被丢弃的整个输入。linksRewritten 是检测到的 GoTo 计数。inputLabels 按合并顺序列出解析后的标签。isValid() 检查 %PDF 头;hasOptimizations() 在移除了重复项或统计到链接时为 true。
书签标题
标题为“书签标题”的章节每个大纲条目将输入标签作为 /Title 携带,并依照 ISO 32000-2:2020 §7.3.4.2 转义为 PDF 字面字符串。先将反斜杠加倍,转义圆括号,命名控制字节使用其既定序列,任何剩余的不可打印字节转为三位八进制转义。因此恶意标签无法破坏字面字符串定界符的同步,也无法注入对象结构。标签为空的输入会获得一个 Document N 占位标题,从一开始计数。
基础组装
标题为“基础组装”的章节遗留的 Core PdfMerger::merge() 在本发行版中是一个刻意的 fail-closed 存根;SmartMerger 从不调用它。基础合并改为通过 Pro PdfSplitter::mergeDocuments() 运行,因此合并文件依照 ISO 32000-2:2020 §7.5.4 携带一个字节精确的交叉引用表,每个间接对象一条记录。确定性遵循 Pro splitter 记录在案的行为画像:相同的输入与配置产出稳定的字节流。
结构感知拆分
标题为“结构感知拆分”的章节SemanticSplitter::splitByStructure() 扫描页面内容流中达到或超过 headingFontThreshold(默认 14.0)的 Tf 设置字体操作符,并将每个这样的页面视为一个分节起点。边界被转换为页面范围并委派给 Pro PdfSplitter::split()。当未检测到边界时,整个文档作为单个分节返回。输入必须以 %PDF 开始并保持在 100 MB 界限内。
边界情形与失败模式
标题为“边界情形与失败模式”的章节- 空的输入列表在任何组装之前就以
InvalidArgumentException失败。 - 输入数量超过
maxInputs(默认 100),或任一输入超过maxBytesPerInput(默认 100 MB),以OverflowException失败。两条边界都是刻意的 fail-closed 拒绝,而非瞬时错误。 - 去重以整文档为单位且字节级精确。两个渲染结果相同但任一字节不同的输入都会被保留,尽管
deduplicatePages的名称是面向页面的,duplicatesRemoved统计的仍是被丢弃的整个输入。 sourceCount反映原始输入数量,而非去重后的文档数量。- 书签合并仅在至少一个输入具有非空标签时触发。当
consolidateBookmarks为 true 但每个标签都为空时,不写入任何/Outlines对象。 - 注入的大纲条目携带标题以及
/Parent、/Prev、/Next树链接;本发行版中它们不嵌入显式的/Dest目标点。 - 链接重写仅统计
/S /GoTo动作;它不会跨重新编号的对象重新指向目标点。请将linksRewritten视为一个检测计数。 SemanticSplitter的检测是词法性的。它以Tf字体大小操作符为依据,因此纯图像或编码异常的页面不会产生边界,并返回单个整文档分节。
FIPS 模式行为
标题为“FIPS 模式行为”的章节本模块不发生任何密码学操作,因此不存在 FIPS 模式特定行为。用于去重的 xxh128 内容指纹是一个非密码学的变更检测哈希,不承载任何完整性或证据性分量。
一致性
标题为“一致性”的章节| 主张 | 标准 | 条款 |
|---|---|---|
合并书签以从文档目录链接的 /Outlines 字典写入 | ISO 32000-2:2020 | §7.7.2 |
| 基础合并为每个间接对象发出字节精确的交叉引用表 | ISO 32000-2:2020 | §7.5.4 |
| 大纲条目标题转义为 PDF 字面字符串,含反斜杠与圆括号处理 | ISO 32000-2:2020 | §7.3.4.2 |
| 完整的跨文档链接重解析 | — | 不支持(仅 GoTo 检测) |
| 显式的按分节大纲目标点 | — | 本发行版不发出 |
所有条款均为转述;NextPDF 不复制规范正文。这些是能力陈述,不是认证;NextPDF 不持有任何认证,也不授予任何认证。
开发说明
标题为“开发说明”的章节- Pro 包内的可用性:
SmartMerger、MergeInput、SmartMergeConfig、SmartMergeResult与SemanticSplitter自 2.2.0 起提供。它们在nextpdf/pro3.1.0 中均为现行。 - 基础合并委派给 Pro
PdfSplitter::mergeDocuments()。遗留的 CorePdfMerger::merge()在本发行版中是一个 fail-closed 存根,从不被调用。 - 仅当输入可能是字节级相同的整文档时才启用
deduplicatePages;它不会折叠近似重复或重新编码的副本。 - 纯拼接使用
SmartMergeConfig::basic(),书签加链接扫描使用::default()。 - 合并不可信输入时捕获
OverflowException;数量与尺寸边界是刻意的拒绝。 - 简单的页面范围拆分优先直接使用 Pro
PdfSplitter;仅在需要基于标题的分节时才使用SemanticSplitter。
发布边界
标题为“发布边界”的章节本页仅记录外部可观察的行为与受支持的公共 API 接口面。内部命名空间路径、辅助类、机制表、运维手册文件名以及工单前缀均不在范围内。
另请参阅
标题为“另请参阅”的章节- Merge(能力) — 安装、快速上手与生产示例。
- Toc — 深度参考
- Diff — 深度参考
- Document — 深度参考 — Pro splitter 与基础合并引擎。