跳轉到

PDF 序列化

PdfWriter 是 NextPDF 的最後一個管線階段,負責將記憶體中的 PDF 物件圖(Object Graph)序列化為符合 ISO 32000-2 標準的二進位 PDF 格式。輸出的 PDF 包含完整的交叉參考資訊,確保 PDF 閱讀器能以 O(1) 時間定位任意物件。

序列化概覽

finalize() 呼叫
  ├── 完成渲染管線(字型子集化、頁首頁尾填充)
  ├── 建立 PDF 物件圖
  │   ├── Catalog(文件目錄)
  │   ├── Pages(頁面樹)
  │   ├── Resources(字型、影像、色彩空間)
  │   └── 其他字典(Info、Metadata、AcroForm 等)
  ├── PdfWriter 序列化
  │   ├── PDF 檔頭 (%PDF-2.0)
  │   ├── 物件本體(間接物件序列)
  │   ├── 交叉參考(xref table 或 xref stream)
  │   └── 檔案尾碼(Trailer 字典 + startxref)
  └── 輸出位元組串流

交叉參考格式

NextPDF 使用 PDF 1.5+ 引入的交叉參考串流(xref stream),相較傳統 xref 表有更高的壓縮率:

傳統 xref 表(PDF 1.4 以前):
0000000009 00000 n   ← 每條 20 bytes ASCII
0000000058 00000 n

交叉參考串流(PDF 1.5+):
- 使用 FlateDecode 壓縮
- 支援 Offset Width(變長偏移量)
- 可選 Predictor(PNG 濾波器進一步壓縮)

物件串流(Object Streams)

NextPDF 將小型物件打包進物件串流(ObjStm),減少整體 PDF 體積:

use NextPDF\Writer\WriterOptions;

$options = WriterOptions::create(
    useObjectStreams: true,     // 啟用物件串流(預設:true)
    compressionLevel: 6,       // zlib 壓縮等級(0-9,預設:6)
    maxObjectsPerStream: 200,  // 每個物件串流的最大物件數
);

$pdfBytes = $document->finalize(writerOptions: $options);

字典鍵排序

PDF 字典鍵的順序不影響語義,但 NextPDF 預設按字母順序排序以提高確定性(deterministic output):

$options = WriterOptions::create(
    deterministicOutput: true,  // 相同輸入總是產生相同 SHA-256
    sortDictionaryKeys: true,   // 字典鍵字母排序
);

輸出後處理

// 輸出到標準輸出(HTTP 回應)
header('Content-Type: application/pdf');
header('Content-Disposition: attachment; filename="report.pdf"');
echo $document->finalize();

// 輸出到檔案(原子寫入)
$document->finalizeToFile(path: '/output/report.pdf');

// 輸出到資源串流(PSR-7 StreamInterface 相容)
$stream = $document->finalizeToStream();

PDF 版本宣告

$options = WriterOptions::create(
    pdfVersion: PdfVersion::PDF_2_0,  // PDF_1_7 | PDF_2_0(預設)
);

參見