要解析一個PDF檔案,首先要掌握PDF的物理結構,這是第一步。但是這個僅僅只是基礎,更重要的是對PDF邏輯結構的解析。PDF的邏輯大體上是一個樹狀結構,根節點是catalog字典,通過這裡去解析頁、目錄、連結資訊等等,在這裡按照PDF的樹形結構,詳細討論一下整個檔案的邏輯架構。
一、catalog根節點
catalog是整個PDF邏輯結構的根節點,這個可以通過trailer的Root欄位定位,雖然簡單,但是相當重要,因為這裡是PDF檔案物理結構和邏輯結構的連接點。Catalog字典包含的資訊非常多,這裡僅就最主要的幾個欄位做個說明。
(1)Pages欄位
這是個必須欄位,是PDF裡面所有頁面的描述集合。Pages欄位本身是個字典,它裡面又包含了一下幾個主要欄位:
欄位
類型
值
Type
name
(必須)只能為Pages 。
Parent
dictionary
(如果不是catalog裡面指定的跟節點,則必須有,並且必須是間接對象) 當前節點的直接父節點。
Kids
array
(必須)一個間接對象組成的數組,節點可能是page或page tree。
Count
integer
(必須) page tree裡面所包含葉子節點(page 對象)的個數。
從以上欄位可以看出,Pages最主要的功能就是組織所有的page對象。Page對象描述了一個PDF頁面的屬性、資源等資訊。Page對象是一個字典,它主要包含一下幾個重要的屬性:
欄位
類型
值
Type
name
(必須)必須是Page。
Parent
dictionary
(必須;並且只能是間接對象)當前page節點的直接父節點page tree 。
LastModified
date
(如果存在PieceInfo欄位,就必須有,否則可選)記錄當前頁面被最後一次修改的日期和時間。
Resources
dictionary
(必須; 可繼承)記錄了當前page用到的所有資源。如果當前頁不用任何資源,則這是個空字典。忽略所有欄位則表示繼承父節點的資源。
MediaBox
rectangle
(必須; 可繼承)定義了要顯示或列印頁面的物理媒介的地區(default user space units)
CropBox
rectangle
(可選; 可繼承)定義了一個可視地區,當前頁被顯示或列印的時候,它的內容會被這個地區裁剪。預設值就是 MediaBox。
BleedBox
rectangle
(可選) 定義了一個地區,當輸出裝置是個生產環境( production environment)的時候,頁面顯示的內容會被裁剪。預設值是 CropBox.
Contents
stream or array
(可選) 描述頁面內容的流。如果這個欄位預設,則頁面上什麼也不會顯示。
這個值可以是一個流,也可以是由幾個流組成的一個數組。如果是數組,實際效果相當於所有的流是按順序連在一起的一個流,這就允許PDF產生的時候可以隨時插入圖片或其他資源。流之間的分割只是詞彙上的一個分割,並不是邏輯上或者組織形式的切割。
Rotate
integer
(可選; 可繼承) 順時鐘旋轉的角度數,這個必須是90的整數倍,預設是0。
Thumb
stream
(可選)定義當前頁的縮圖。
Annots
array
(可選) 和當前頁面關聯的注釋。
Metadata
stream
(可選) 當前頁包含的中繼資料。
一個簡單例子:
3 0 obj
<< /Type /Page
/Parent 4 0 R
/MediaBox [ 0 0 612 792 ]
/Resources <</Font<<
/F3 7 0 R /F5 9 0 R /F7 11 0 R
>>
/ProcSet [ /PDF ]
>>
/Contents 12 0 R
/Thumb 14 0 R
/Annots [ 23 0 R 24 0 R]
>>
endobj
(2)Outlines欄位
Outline是PDF裡面為了方便使用者從PDF的一部分跳轉到另外一部分而設計的,有時候也叫書籤(Bookmark),它是一個樹狀結構,可以直觀的把PDF檔案結構展現給使用者。使用者可以通過滑鼠點擊來開啟或者關閉某個outline項來實現互動,當開啟一個outline時,使用者可以看到它的所有子節點,關閉一個outline的時候,這個outline的所有子節點會自動隱藏。並且,在點擊的時候,閱讀器會自動跳轉到outline對應的頁面位置。Outlines包含一下幾個欄位:
KEY
TYPE
VALUE
Type
name
(可選)如果這個欄位有值,則必須是Outlines。
First
dictionary
(必須;必須是間接對象) 第一個頂層Outline item。
Last
dictionary
(必須;必須是間接對象)最後一個頂層outline item。
Count
integer
(必須)outline的所有層次的item的總數。
Outline是一個管理outline item的頂層對象,我們看到的,其實是outline item,這個裡面才包含了文字、行為、目的地區域等等。一個outline item主要有一下幾個欄位:
Title
text string
(必須)當前item要顯示的標題。
Parent
dictionary
(必須;必須是間接對象) outline層級中,當前item的父物件。如果item本身是頂級item,則父物件就是它本身。
Prev
dictionary
(除了每層的第一個item外,其他item必須有這個欄位;必須是間接對象)當前層級中,此item的前一個item。
Next
dictionary
(除了每層的最後一個item外,其他item必須有這個欄位;必須是間接對象)當前層級中,此item的後一個item。
First
dictionary
(如果當前item有任何子節點,則這個欄位是必須的;必須是間接對象) 當前item的第一個直接子節點。
Last
dictionary
(如果當前item有任何子節點,則這個欄位是必須的;必須是間接對象) 當前item的最後一個直接子節點。
Dest
name,
byte string, or array
(可選; 如果A欄位存在,則這個不能被會略)當前的outline item被啟用的時候,要顯示的地區。
A
dictionary
(可選; 如果Dest 欄位存在,則這個不能被忽略)當前的outline item被啟用的時候,要執行的動作。
(3)URI欄位
URI(uniform resource identifier),定義了文檔層級的統一資源識別項和相關連結資訊。目錄和文檔中的連結就是通過這個欄位來處理的。
(4)Metadata欄位
文檔的一些附帶資訊,用xml表示,符合adobe的xmp規範。這個可以方便程式不用解析整個檔案就能獲得檔案的大致資訊。
(5)其他
Catalog字典中,常用的欄位一般有以下一些:
欄位
類型
值
Type
name
(必須)必須為Catalog。
Version
name
(可選)PDF檔案所遵循的版本號碼(如果比檔案頭指定的版本號碼高的話)。如果這個欄位預設或者檔案頭指定的版本比這裡的高,那就以檔案頭為準。一個PDF產生程式可以通過更新這個欄位的值來修改PDF檔案版本號碼。
Pages
dictionary
(必須並且必須為間接對象)當前文檔的頁面集合入口。
PageLabels
number tree
(可選) number tree,定義了頁面和頁面label對應關係。
Names
dictionary
(可選)文檔的name字典。
Dests
dictionary
(可選;必須是間接對象)name和相應目標對應關係字典。
ViewerPreferences
dictionary
(可選)閱讀參數配置字典,定義了文檔被開啟時候的行為。如果預設,則使用閱讀器自己的配置。
PageLayout
name
(可選) 指定文檔被開啟的時候頁面的布局方式。SinglePageDisplay 單頁
OneColumnDisplay 單列
TwoColumnLeftDisplay 雙列,奇數頁在左
TwoColumnRightDisplay 雙列,奇數頁在右
TwoPageLeft 雙頁,奇數頁在左
TwoPageRight 雙頁,奇數頁在右
預設值: SinglePage.
PageMode
name
(可選) 當文檔被開啟時,指定文檔怎麼顯示
UseNone 目錄和縮圖都不顯示
UseOutlines 顯示目錄
UseThumbs 顯示縮圖
FullScreen 全螢幕模式,沒有菜單,任何其他視窗
UseOC 顯示Optional content group 面板
UseAttachments顯示附件面板
預設值: UseNone.
Outlines
dictionary
(可選;必須為間接對象)文檔的目錄字典
Threads
array
(可選;必須為間接對象)文章線索字典組成的數組。
OpenAction
array or dictionary
(可選) 指定一個地區或一個action,在文檔開啟的時候顯示(地區)或者執行(action)。如果預設,則會用預設縮放率顯示第一頁的頂部。
AA
dictionary
(可選)一個附加的動作字典,在全域範圍內定義了響應各種事件的action。
URI
dictionary
(可選)一個URI字典包含了文檔層級的URI action資訊。
AcroForm
dictionary
(可選)文檔的互動式form (AcroForm)字典。
Metadata
stream
(可選;必須是間接對象)文檔包含的中繼資料流。