跳转到内容
getnextpdf.com

Fast Web View:PDF 如何在下载完成之前就打开

Spec: ISO 32000-2, Annex F

一份线性化的 PDF 经过重新编排,让第一页与一份小巧的导航索引坐落在文件的最前端。因此,查看器可以在文档其余部分仍在抵达时就先绘制第一页,也能直接跳到第 147 页,而不必先读过第 2 到 146 页。

这正是多数读者以其亲切名称熟知的功能:Fast Web View

想象一份 200 页的报告,在一部只剩一格信号的手机上打开。若没有线性化,查看器往往需要拿到文件的最末端才能绘制任何内容,因为那份标明每个对象位置的主索引,传统上是坐落在文件后段。于是你只能盯着转圈圈的图标,看着两百页全部下载完,就为了读第一页。

有了线性化,文件的编排方式让“第一页上有什么”的答案成为最先离开传输线的东西。读者在一秒内就把第一页绘制出来,其余部分只在你滚动或跳页时才取得。在快速连接上,你或许永远不会察觉。但在缓慢或按量计费的连接上,这就是一份可用文档与一个被放弃的标签页之间的差别。

  • 线性化的文件是前置加载的:第一页与一份提示表被放在最前面,先于主体的其余部分。
  • 提示表是一张范围地图。它告诉查看器哪些字节范围属于每一页、哪些属于共享对象,让查看器可以向服务器索取恰好那几段切片——接着由交叉引用表把每个对象编号解析到它确切的偏移量。
  • 这依赖于字节范围请求——查看器按需求获取文件的切片,而非整个文件。
  • 这些字节与一份正常 PDF 的内容完全相同。线性化改变的是顺序与索引,而非页面本身。
  • 在 NextPDF 中,这是一个明确、可切换的步骤——由一套真正的三趟重建产生,而不是一个只能祈求顺利的标志位。

你无法在尚未确切知道每样东西有多大之前就把某一页前置加载,因为提示表记录的是字节偏移量,而偏移量唯有在每个对象的长度都已定案后才会正确。这种循环性——偏移量取决于大小,大小取决于版面——正是线性化器要分趟执行、而非一次扫过的原因。

NextPDF 以一套确定性的三趟重建来化解它。第一趟测量,第二趟决定放置位置,第三趟以此时已知的偏移量把真正的字节写出来。

  1. MEASURESerialise every object once to learn its exact byte length. Offsets are circular — they depend on sizes — so sizes are pinned first.
  2. PLACEDecide the order: first page and its dependencies up front, then the rest. Reserve space for the linearization parameter dictionary and the hint table.
  3. FILLWrite the final bytes. Each reserved field is filled with values computed after MEASURE and PLACE — the first-page length, the hint-table location, the main cross-reference offset — derived from the measured sizes and the chosen placement.
The three-pass linearization rebuild. MEASURE sizes every object so lengths are final; PLACE decides the front-loaded order and reserves the hint-table region; FILL writes the real bytes with the now-known offsets, so the first page and the hint table land at the front and the cross-reference data resolves on first fetch.

输出以一份线性化参数字典作为其第一个对象,并带有一份或多份用来索引各页的提示表,完全依照标准所规定(Spec: ISO 32000-2, Annex F)。这些提示表与一份传统的交叉引用表并肩运作——提示表记录查看器获取所需的字节范围与位置,而交叉引用表则是把每个对象编号对应到其确切字节偏移量的索引。NextPDF 的线性化器输出经典的表格形式,并在过程中清除任何交叉引用流,因此一旦某段切片抵达,读者便能直接从那张表以其偏移量解析出一个对象(Spec: ISO 32000-2, §7.5.4)。

一个有用的心智模型:一份正常的 PDF 是一本目录被粘在封底的书。线性化的 PDF 把那一页目录移到最前面,并加上一份逐页的页码索引,让你可以直接翻到任何一页。各章节并未改变。移动的只有导航部分。

线性化是一个明确、可切换的步骤。你提出请求;引擎执行重建,并输出一份 Fast-Web-View 文件。

<?php
declare(strict_types=1);
use NextPDF\Core\Document;
use NextPDF\Contracts\OutputDestination;
$document = Document::createStandalone();
$document->setTitle('Annual Report');
for ($page = 1; $page <= 200; $page++) {
$document->addPage();
$document->setFont('helvetica', '', 12);
$document->cell(0, 12, "Page {$page}", newLine: true);
}
// Linearization is requested explicitly — an operability choice, not a default.
// enableLinearization() takes no arguments; it is the on-switch. The engine
// runs the MEASURE -> PLACE -> FILL rebuild and emits a Fast-Web-View file
// with the first page and hint table at the front.
$document->enableLinearization();
$bytes = $document->output(dest: OutputDestination::String);

页面内容正是你所撰写的内容。差别在于你所收到字节的文件顺序,以及那份此时坐落在接近顶端位置的提示表。

你会以一个陌生人会采用的方式验证结果——借助外部检查工具:

$ qpdf --check-linearization report.pdf
report.pdf: no linearization errors

qpdf --check-linearization 不只是寻找一个标志位。它会重新推导出文件所宣称的偏移量,并确认它们属实:第一页的对象确实位于线性化字典所指出的位置、提示表指向正确的字节,且结构符合 Annex F。一份对自己版面说谎的文件,即使乍看之下像是线性化的,仍会无法通过这项检查。

常见的假设是,线性化会压缩文件,或让下载整体变快。它两者都不会。一份线性化的文件往往更大几个字节,因为它额外带有提示表。整份文档的总传输时间基本上不变。

改变的是第一个有用的像素何时出现。线性化优化的是到第一页的时间,而非总字节数。它是一项延迟功能,而非压缩功能。尽早流式传出第一页,与快速下载完整个文件,是不同的目标,而线性化服务的是前者。

第二个误解是,任何网页服务器都会流式传输一份线性化的文件。查看器需要获取字节范围,这意味着服务器必须兑现 HTTP 范围请求。多数服务器都能,但一个总是返回整个文件的服务器,会把 Fast Web View 变回缓慢的整文件等待——文件已准备好流式传输,但传输层却没有。

NextPDF 对产生线性化文件具备完整的核心支持:一套正式产品级的三趟线性化器,会输出参数字典与提示表,并能通过外部的 Annex F 检查。

Fast Web View (linearization) output — edition availability
EditionAvailability
Core

Full support. NextPDF produces linearized (Fast Web View) output through a production three-pass MEASURE → PLACE → FILL rebuild, conforming to ISO 32000-2 Annex F.

ProNot in this edition
EnterpriseNot in this edition

有两条边界值得点明。第一,线性化是单一修订版本的属性。在你追加一次增量更新的那一刻——一个签名、一次表单填写、一处编辑——追加的字节会放到结尾,于是文件便不再严格属于线性化,直到它被重建为止。这是一种正常的取舍,而非缺陷;关于为何追加才是已签名文档的正确行为,参见增量更新

第二,引擎掌控文件,却不掌控网络。Fast Web View 唯有在提供服务的连接兑现字节范围请求时,才能兑现它的承诺;即使字节完美地经过线性化,只要服务器坚持送出整个文件,它们仍会以一个缓慢的整块形式抵达。

  • PDF 文件剖析 — 线性化所重新编排的标头、主体、交叉引用表与尾段。先读这篇,看看被重新排序的究竟是什么。
  • 内存与流式处理 — 写入端的流式处理,一条不同的轴线:NextPDF 在产生字节时如何让内存维持平稳,相对于读者如何把它们流式读入。
  • 增量更新为何重要 — 为何后续的编辑会追加到结尾,以及这对一份线性化文件的前置加载版面意味着什么。
  • 流与过滤器 — 提示表所指向的主体对象里头住着什么,以及它们如何被压缩。
  • 线性化 — 把第一页与一份导航索引前置加载的那套重建,让查看器能在整个文件抵达之前就进行绘制与导航。这是标准对其结果所取的名称。
  • Fast Web View — 线性化 PDF 面向消费者的名称;这两个词描述的是同一份文件。
  • 提示表 — 线性化文件内部记录每一页与共享对象之字节范围与位置的结构,让查看器知道该请求哪些切片;交叉引用表则是接着把对象编号对应到其确切字节偏移量的东西。
  • 线性化参数字典 — 线性化文件中的第一个对象;它声明那些让按需求获取得以成立的关键偏移量(第一页长度、提示表位置、主交叉引用位置)。
  • 字节范围请求 — 一个只索取文件某段切片、而非整个文件的 HTTP 请求;这是 Fast Web View 所依赖的传输机制。
  • 到第一页的时间 — 读者看到第一页所需的时间。线性化所优化的延迟,有别于总下载时间。