1. 程式人生 > >一個簡單PDF檔案的結構分析

一個簡單PDF檔案的結構分析

一個簡單的PDF檔案結構的分析

AdobePDF參考告訴我們一個PDF檔案可以通過下面4個方面來理解:

1.         物件一個PDF文件是由一組基本資料型別組成的資料結構。

2.         檔案(物理結構)決定物件是如何存放在一個PDF檔案中的,它們是如何被訪問的,如何被更新的。這個結構是獨立於物件的語義的。

3.         文件結構說明一些基本的物件型別是如何來表現PDF文件的成分的:例如頁,圖片,字型,批註等。

4.         內容流,一個PDF檔案內容流包含一系列的指令,描述頁面的外觀或其他圖形實體的外觀和檔案內容。

但是當時對我來說要看懂這幾行字是有很大的困難的,需要了解確切含義,必須看完後面的幾十頁上百頁的內容並且要分析一個實際的PDF

檔案才能完全領會它的意思。

後來經過長時間的文件閱讀,相關開發,並且具體地分析PDF檔案後才把PDF檔案的語法,檔案的解析搞清楚。雖然說學習是痛並快樂著,但是對於當時的我來說真得希望有一個人能夠告訴我一個簡單的例子,通過一個簡單的例子來描述PDF的基本組成,它的解析原理和過程。從我的切身體驗來說,從一個初學者的角度出發,最好的方式應該是一個簡單的例子。因此我主要將以一個簡單的例子並且加以圖例來說明PDF的主要特性並給出一個簡單的PDF檔案的全景。

在繼續閱讀該文章前,先問自己下面的兩個問題:

l         你瞭解至少一種檔案格式嗎?(例如HTML

l         為什麼要學習PDF

的相關知識?

如果你對第一個問題的答案為“是”並且第二個問題你能給出一個非常明確的答案,那麼這篇短文就是為你準備的。否則,如果對任何一種格式都不瞭解,建議你先了解一下HTML,或XML,你可以從這兩種語言裡得到很多啟發,對學習PDF的構成或研究學習其他格式檔案有很大的好處;如果你不清楚你要學習是為了什麼,那麼我就認為你學習沒有目的性和動力,說不定你今天學了以後明天就忘得一乾二淨,因此也不建議你繼續看下去,等到你想清楚了歡迎你來看這則短文。

1PDF格式和HTML,XML格式:

一個PDF文件從根本上來說是一個8位元組序列。其實PDF格式和我們已經熟知的HTMLXML等結構化的檔案格式一樣,包含有關鍵字,分隔符,資料等等。

不同的是PDF檔案是按照二進位制流的方式儲存的,而html檔案則是可讀的文字方式儲存的,你可以用文字編輯器分別開啟一個html檔案和PDF檔案比較一下就知道了。XML檔案一般只包含資料本身,並沒有把如何顯示的資訊放在其中,因此要顯示一個XML檔案還需要一個Schema檔案才能顯示,否則看到的將是所有的位元組流,包括所有的標誌;HTML包含了資料的同時也包含了一些關於如何顯示的資訊,但是HTML是按照是不經過壓縮的文字存放的,是可讀的,你開啟一個HTML檔案就能知道所有將顯示在瀏覽器裡的文字。另外就是HTML不能包含二進位制流,它對影象檔案的引用都是通過引用外部檔案的方式來實現的。

2PDF規範的發展

PDF規範從1993年到現在,已經有過7個版本,六次版本升級,從最初的pdf1.0版本到現在的PDF1.6, 每次的版本升級都會加入一些新的特性,PDF參考說明書也是從最初的100多頁到現在的1000多頁,但是PDF檔案格式的主要特性還是沒有改變,可以這麼理解,PDF1.6是PDF1.0的擴充套件集,學習了PDF1.0以後也能基本上理解PDF1.6的內容, 而PDF1.0規範是相對簡單的,因此說我選擇一個符合PDF1.0規範的最簡單的一個PDF檔案來進行分析。

PDF規範的6次升級:

1.1 1995 加入了文件加密(40位元組),線索樹,名字樹,連結,裝置獨立色彩資源。

1.2 1996 表單, 半色調螢幕,和其他的一些高階色彩特性, 對中文,日文和韓文的支援

1.3 2000 數字簽名, 邏輯結構, JavaScript, 嵌入式檔案,Masked Images,平滑陰影, 支援 CID字型的附加色彩。

1.4 2001 檔案加密 (128 位元組), 標籤式 PDF, 訪問控制,透明,元資料流

1.5 2003 文件加密 (公鑰), JPEG 2000 壓縮, 可選的內容組,附加的註解型別

1.6 2005 文件加密 (AES),增加最大檔案支援,加入3D支援,額外的註解型別

3PDF檔案的基本組成:

一個PDF檔案從大的方面來說可以分4個部分:

l         檔案頭,指明瞭該檔案所遵從的PDF規範的版本號,它出現在PDF檔案的第一行。

l         檔案體,PDF檔案的主要部分,由一系列物件組成。

l         交叉引用表,為了能對間接物件進行隨機存取而設立的一個間接物件的地址索引表。

l         檔案尾,聲明瞭交叉引用表的地址,即指明瞭檔案體的根物件(Catalog),從而能夠找到PDF檔案中各個物件體的位置,達到隨機訪問。另外還儲存了PDF檔案的加密等安全資訊(以後詳細討論)。

如下圖:

 1

4PDF文件的邏輯結構

作為一種結構化的檔案格式,一個PDF文件是由一些稱為“物件”的模組組成的。並且每個物件都有數字標號,這樣的話可以這些物件就可以被其他的物件所引用。這些物件不需要按照順序出現在PDF文件裡面,出現的順序可以是任意的,比如一個PDF檔案有3頁,第3頁可以出現在第1頁以前,物件按照順序出現唯一的好處就是能夠增加檔案的可讀性,如果你不會用文字編輯器來閱讀PDF結構,那麼大可不必關心該順序。正是因為頁與頁之間的不相關性,就能夠對PDF檔案的頁面進行隨機的訪問。

檔案尾(Trail),說明根物件的物件號,並且說明交叉引用表的位置,通過對交叉引用表的查詢可以找到目錄物件(Catalog)這個目錄物件是該PDF文件的根物件,包含PDF文件的大綱(outline)和頁面組物件(pages)引用。大綱物件是指PDF檔案的書籤樹;頁面組物件(pages)包含該檔案的頁面數,各個頁面物件(page)的物件號。

下圖是PDF文件的層次關係:

 2

頁面(page)物件作為PDF中最重要的物件,包含如何顯示該頁面的資訊,例如使用的字型,包含的內容(文字,圖片等),頁面的大小。裡面的資訊可以直接給出,當然裡面的子項更多的是對其他物件的引用,真正的資訊存放在其他物件裡面。頁面中包含的資訊是包含在一個稱為流(stream)的物件裡,這個流的長度(位元組數)必須直接給出或指向另外一個物件(包含一個整數值,表明這個流的長度)。如下圖:

 3

5 PDF的基本語法:

檔案的第一行是檔案頭,指明瞭該檔案所遵從的PDF規範的版本號,它出現在PDF檔案的第一行。

一個物件的第一行一般有兩個數字和關鍵字“obj”。例如:

3 0 obj

<<

/Type /Pages

/Count 1

/Kids [4 0 R]

>>

endobj

第一個數字稱為物件號,來唯一標識一個物件的,第二個是產生號,是用來表明它在被建立後的第幾次修改,所有新建立的PDF檔案的物件號應該都是0,即第一次被建立以後沒有被修改過。上面的例子就說明該物件的物件號是3,而且建立後沒有被修改過。

物件的內容應該是包含在<< >>之間的,最後以關鍵字endobj結束.

6.     檔案Hello World的檔案分析:

6.1.檔案的具體分析

%PDF-1.0        

檔案頭,說明符合PDF1.0規範

1 0 obj

<<

/Type /Catalog

/Pages 3 0 R

/Outlines 2 0 R

>>

endobj

Catalog物件(根物件)

/Type /Catalog說明該物件的型別為/Catalog/Pages 3 0 R,這裡/Pages指的是這個根物件包含的/Pages的目標是物件號為3的物件,3 0 R的意思是對物件3的引用。

2 0 obj

<<

/Type /Outlines

/Count 0

>>

endobj

outline物件(此處它的計數為0,說明沒有書籤)

3 0 obj

<<

/Type /Pages

/Count 1

/Kids [4 0 R]

>>

endobj

pages物件(頁面組物件),/Type /Pages 說明自身的屬性,物件的型別為頁碼,/Count 1說明頁碼數量為1/Kids [4 0 R]說明它的孩子、頁的物件號為4,如果有多個頁面,就有多個頁面物件的引用,例如/Kids [4 0 R 10 0 R], 就說明該PDF的第一頁的物件號是4,第二頁的物件號是10

4 0 obj

<<

/Type /Page

/Parent 3 0 R

/Resources << /Font << /F1 7 0 R >> /ProcSet 6 0 R >>

/MediaBox [0 0 612 792]

/Contents 5 0 R

>>

endobj

頁物件,/Parent 3 0 R說明其父物件的物件號為3,及Pages物件,/Resources << /Font << /F1 7 0 R >> /ProcSet 6 0 R >>說明該頁所要包含的資源,包括字型和內容的型別,/MediaBox [0 0 612 792]說明頁面的顯示大小(以象素為單位),/Contents 5 0 R說明頁面內容物件的物件號為5

5 0 obj

<< /Length 44 >>

stream

BT

/F1 24 Tf

100 100 Td (Hello World) Tj

ET

endstream

endobj

<< /Length 44 >>說明stream物件為位元組數,從BT開始,ET結束,包括中間的行結束符。

Stream說明一個流物件的開始。

BT說明一個文字物件的開始。

/F1 24 TfTf說明True font物件,字型明為F1, 大小為24個象素。

100 150 Td (Hello World) Tj100 100 說明這一行文字放置的位置,對於Td, 我們可以這樣理解,我們的當前X,Y座標分別加上100150就是文字的位置,因為在該例子中只有一個物件,那麼它的位置就是(100,150), 如果下個物件位置資訊為100, 50 Td, 那麼它的位置應該就是(100+100, 150+50)也就是(200200)。(Hello World Tj說明文字的內容,當然,如果這裡是文字的內容寫成16進位制,則用<>包含。

ET說明文字物件的結束標誌。

Endstream為流物件的結束標誌

6 0 obj

[/PDF /Text]

Endobj

[/PDF /Text]說明PDF的內容型別僅僅為文字,如果有圖片則為[/PDF /Image]

7 0 obj

<<

/Type /Font

/Subtype /Type1

/Name /F1

/BaseFont /Helvetica

>>

endobj

字型物件,不再多作解釋。

所有的物件之後是下面的交叉引用表:

xref

0 8

0000000000 65535 f

0000000009 00000 n

0000000074 00000 n

0000000120 00000 n

0000000179 00000 n

0000000322 00000 n

0000000415 00000 n

0000000445 00000 n

xref說明一個交叉引用表的開始,交叉引用表的第一行0 8 說明下面各行所描述的物件號是從0開始,並且有8個物件。

0000000000 65535 f,一般每個PDF檔案都是以這一行開始交叉應用表的,說明物件0的起始地址為0000000000,產生號(generation number)為65535,也是最大產生號,不可以再進行更改,而且最後物件的表示是f, 表明該物件為free, 這裡,大家可以看到,其實這個物件可以看作是檔案頭。

0000000009 00000 n就是表示物件1,也就是catalog物件了,0000000009是其偏移地址,000005位產生號(最大為65535),0表明該物件未被修改過,  n表示該物件在使用,區別與自由物件,可以更改。

下面的幾行相信大家就可以告訴我含義了。

Trailer

<<

/Size 8

/Root 1 0 R

>>

startxref

553

%%EOF

trailer

說明檔案尾trailer物件的開始。

/Size 8說明該PDF檔案的物件數目。

/Root 1 0 R說明根物件的物件號為1

Startxref

553說明交叉引用表的偏移地址,從而可以找到PDF文件中所有的物件的相對地址,進而訪問物件。

%%EOF為檔案結束標誌。

6.2.PDF解析過程

回顧上面的詳細解釋,我們可以將這個簡單的PDF解析過程簡化為如下圖例:

 4

7.結束語:

到這裡,對一個最簡單的PDF檔案的介紹就結束了,大家對PDF檔案的格式和特定也應該已經有所瞭解了。

當然,我這裡介紹的是不完整的,完整的資訊,請訪問adobe的網站下載最新的PDF REFERENCE1.6

下次介紹PDF的加密過程及原理。