跳转到内容
getnextpdf.com

Pro 版本

Merge — 深度参考

本页是 NextPDF Pro Merge 模块 NextPDF\Pro\Merge 的契约级参考。SmartMerger 将多个输入文档合并为一个,并应用 Pro 增强能力:由各输入标签汇总而成的合并书签树、整文档去重、按输入的页面范围选择,以及内部链接检测。SemanticSplitter 是配套的结构感知拆分入口。本页说明公共 API、可观察的行为契约、资源边界以及失败模式。任务导向的配置与示例见 Merge 能力页

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

没有任何运行时能力标记对本模块进行门控。只要安装并授权 nextpdf/pro,Merge 类即可使用。

符号参数默认行为返回抛出或失败于备注
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()当输入携带至少一个页面范围时为 Truebool
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 头开始时为 Truebool仅做头部检查
SmartMergeResult::hasOptimizations()当移除了任何重复项或统计到任何链接时为 Truebool
SemanticSplitter::__construct()?PdfSplitter $splitter = nullnull 参数构造默认的 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(),
): SmartMergeResult
public function __construct(
public string $pdfData,
public array $pageRanges = [],
public string $label = '',
)
public function hasPageRanges(): bool
public 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(): self
public function isValid(): bool
public function hasOptimizations(): bool
public function __construct(?PdfSplitter $splitter = null)
public function splitByStructure(
string $pdfData,
float $headingFontThreshold = 14.0,
): SplitResult

SmartMerger::merge() 运行一条固定管线,从外部观察如下。

  1. 空的输入列表抛出 InvalidArgumentException。随后输入数量受 maxInputs 约束;超限抛出 OverflowException
  2. 每个输入在使用前都会对照 maxBytesPerInput 做尺寸检查。当输入声明了页面范围时,先通过 Pro splitter 缩减到所选页面,然后仅贡献这些页面。
  3. 当启用 deduplicatePages 时,每个输入文档的完整字节串以非密码学的 xxh128 函数计算指纹。字节与更早某个输入完全匹配的输入会被丢弃。去重以整文档为单位且字节级精确。
  4. 基础组装委派给 Pro PdfSplitter::mergeDocuments() 引擎,它将每个输入重新编号进一个连续的对象空间,并发出真实的交叉引用表。
  5. 当启用 consolidateBookmarks 且至少有一个输入携带非空标签时,应用书签合并。会插入一个最小的 /Outlines 字典,并从文档目录链接,按合并顺序为每个输入生成一个大纲条目。
  6. 当启用 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 模式特定行为。用于去重的 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 包内的可用性:SmartMergerMergeInputSmartMergeConfigSmartMergeResultSemanticSplitter 自 2.2.0 起提供。它们在 nextpdf/pro 3.1.0 中均为现行。
  • 基础合并委派给 Pro PdfSplitter::mergeDocuments()。遗留的 Core PdfMerger::merge() 在本发行版中是一个 fail-closed 存根,从不被调用。
  • 仅当输入可能是字节级相同的整文档时才启用 deduplicatePages;它不会折叠近似重复或重新编码的副本。
  • 纯拼接使用 SmartMergeConfig::basic(),书签加链接扫描使用 ::default()
  • 合并不可信输入时捕获 OverflowException;数量与尺寸边界是刻意的拒绝。
  • 简单的页面范围拆分优先直接使用 Pro PdfSplitter;仅在需要基于标题的分节时才使用 SemanticSplitter

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