跳至內容
100% 本地 · 上傳 0 KB壓縮 PDF

PDF 如何儲存文字和影像(幕後原理)

PDF 是一個內含二進位 blob 的文字檔案。其結構 出奇地可讀:一個標頭、一列編號的物件、一張 交叉引用表和一個 trailer。這個頁面走訪這個 結構,並展示文字、字型和影像實際存在哪裡。為開發者和任何 想了解 PDF 工具在讀寫檔案時做了什麼的人而寫。

概覽

PDF 的四個部分

每個 PDF 檔案都有相同的四部分 佈局:

  1. 標頭——一行,例如 %PDF-1.7,宣告版本。
  2. 主體——一串編號的間接物件。一切都在這裡:頁面、字型、影像、元資料。
  3. 交叉引用表(xref)——每個物件的位元組偏移量,讓閱讀器能找到它們而無需掃描整個檔案。
  4. Trailer——指向根物件(文件目錄)、xref 位置和可選的加密資訊。閱讀器首先讀取 trailer,然後跳到根。

trailer 優先的設計是為什麼 PDF 可以 在常數時間內讀取而無需載入整個檔案—— 這對大型文件和串流 閱讀器很重要。

主體

間接物件

主體中的每個物件都有編號,看起來像 這樣:

3 0 obj
<< /Type /Page /MediaBox [0 0 612 792] /Contents 4 0 R /Resources << /Font << /F1 5 0 R >> >> >>
endobj

3 0 obj 表示「這是物件 3, 世代 0」。<< ... >> 中的主體 是一個字典——一列鍵值對。 值可以是數字、字串、 名稱(以 / 為前綴)、陣列、其他 字典或像 4 0 R這樣的引用(「去看物件 4」)。這就是頁面 如何指向其內容串流和字型而不 內嵌它們。

世代號通常為 0。當 增量更新刪除並重寫物件時它會 遞增——這是一個允許 在檔案末尾新增修改來編輯 PDF 而無需重寫一切的功能。大多數現代寫入器 重寫整個檔案,因此世代 保持為 0。

內容

文字如何儲存

頁面的內容存在於一個內容 串流中——一個值為位元組串流的物件(通常以 Flate 壓縮),包含 PDF 繪圖運算子。文字用BT(開始文字)、Tf(設定字型和大小)、Td(移動 位置)、Tj(顯示文字)和 ET(結束文字)等運算子繪製。一個簡單的「Hello」大致看起來像:

BT
/F1 24 Tf
100 700 Td
(Hello) Tj
ET

字串 (Hello) 使用字型的 編碼。對於簡單的拉丁文字,通常是 WinAnsiEncoding 或字型的內建編碼。對於 Unicode 文字,字串是 16 位元編碼的位元組串流,且字型有/ToUnicode 映射,讓閱讀器能 取回實際的 code point 以進行複製貼上和 搜尋。如果一個 PDF 複製貼上亂碼但 文字可見,/ToUnicode 映射 遺失或錯誤——這是一個常見的匯出錯誤。

文字不是以 HTML 或 段落儲存。沒有語意的「段落」物件。 行、換行和定位都是 明確的繪圖命令。這就是為什麼 將 PDF 重排到不同頁面寬度很 困難:閱讀器必須從繪圖命令 反向工程出版面。

字型

字型內嵌

PDF 中的字型物件有兩部分:一個字型字典命名字型並 指向其資料,和字型程式本身(Type 1、TrueType 或 OpenType)以串流內嵌。PDF 規範要求字型被內嵌以便文件 在任何地方都相同呈現——但 不強制執行,這就是為什麼有些 PDF 在沒有它們的機器上替換字型。

子集化只內嵌 文件中實際使用的字符。一個 250 KB 的字型用於單一標題變成 8 KB 的子集。大多數現代匯出器 預設進行子集化。老舊匯出器或 某些「列印成 PDF」路徑有時內嵌 完整字型,這是檔案 膨脹的常見原因。請參閱我們的 檔案大小指南了解完整細節。

影像

影像如何儲存

影像以 XObject(外部物件)儲存——原始或 壓縮像素資料串流,搭配描述寬度、 高度、色彩空間、每元件位元數和篩選器的字典。 頁面的內容串流然後用Do 運算子繪製影像。

PDF 支援多種影像篩選器(壓縮):

  • DCTDecode——JPEG。有損,適合相片。影像豐富 PDF 中大小最常見的來源。
  • FlateDecode——zlib/deflate。無損,適合線稿和色彩少的影像。
  • JPXDecode——JPEG2000。高品質下壓縮率優於 JPEG,但較慢且不普遍支援。
  • JBIG2Decode——用於二值(1 位元)掃描文字。可大幅縮減掃描頁面。
  • CCITTFaxDecode——傳統傳真壓縮,用於二值影像。

影像豐富的 PDF 主要是一串 壓縮影像串流。以更激進的 JPEG 品質重新編碼這些串流是 掃描文件最大的單一大小槓桿。

索引

xref 表和 trailer

xref 表列出每個 間接物件的位元組偏移量。閱讀器開啟檔案, 讀取 trailer(位於從檔案末尾 已知偏移處),找到 xref 並用它 直接跳到任何物件而無需解析整個 檔案。這就是 PDF 支援直接存取的原因。

PDF 1.5 新增了交叉引用 串流,壓縮 xref 表 本身。結合物件串流(多個 小物件打包進壓縮串流),這就是 使現代 PDF 比其 1.4 等價物更小的結構壓縮。請參閱我們的壓縮解說了解這在實務上的效果。

trailer 也指向/Root(文件目錄,列出 頁面樹)、/Info 字典 (Title、Author、CreationDate——元資料)和 可選的 /Encrypt 字典(如果 檔案已加密)。

壓縮

串流和篩選器

任何值為二進位資料的物件(內容 串流、影像、內嵌字型)都是一個串流:一個字典後接stream、原始位元組和endstream。字典的 /Filter 項 告訴閱讀器如何解碼位元組 ——FlateDecode 用於 zlib、DCTDecode用於 JPEG 等等。多個篩選器可以串聯, 例如一個影像先解碼再 降取樣。

這就是為什麼「壓縮 PDF」不是 單一操作。每個串流獨立用 自己的篩選器壓縮。以物件串流 重新儲存的壓縮工具減少結構 冗餘;以更激進的 JPEG 品質 重新編碼影像減少影像串流。這些是 獨立的槓桿。

實務

為什麼這對 PDF 工具很重要

當像 IXPDF 這樣的工具合併、分割或 旋轉 PDF 時,它解析 xref、走訪頁面 樹、複製或重排頁面物件並重寫 xref 和 trailer。內容串流(文字和 影像)逐位元組複製——不 重新編碼,不損失品質。這就是為什麼 結構操作快速且無損: 它們重排物件引用,不 重新繪製頁面。

壓縮是例外:它以物件串流 重新序列化結構。即使如此,影像和 字型串流原樣複製,除非 使用者明確要求重新編碼。

這一切都透過 Web Worker 在您的瀏覽器中進行——檔案在本機 解析、修改和重新序列化。 您的 PDF 永遠不會離開您的裝置。

接下來閱讀

相關資源