一個PDF文檔從根本上來說是一個8字節序。其實PDF格式和我們已經熟知的HTML,XML等結構化的文件格式一樣,包含有關鍵字,分隔符,數據等等。
不
同的是PDF文件是按照二進制流的方式保存的,而html文件則是文本方式保存的。XML文件一般只包含數據本身,並沒有把如何顯示的信息放在其中,因此
要顯示一個XML文件還需要一個Schema文件才能顯示,否則看到的將是所有的字節流;HTML包含了數據的同時也包含了一些關於如何顯示的信息,但是
HTML是基於文本存放的,是可讀的,你打開一個HTML文件就能知道所有顯示在瀏覽器裏得文字。 另外就是HTML不能包含二進制流,它對圖像文件的引
用都是通過鏈接的,全部是外部文件的方式來實現的。
PDF文件的基本組成:
一個PDF文件從大的方面來說分4個部分:
l 文件頭,指明瞭該文件所遵從的PDF規範的版本號,它出現在PDF文件的第一行。
l 文件體,PDF文件的主要部分,由一系列對象組成。
l 交叉引用表,爲了能對間接對象進行隨機存取而設立的一個間接對象的地址索引表。
l 文件尾,聲明瞭交叉引用表的地址,即指明瞭文件體的根對象(Catalog),從而能夠找到PDF文件中各個對象體的位置,達到隨機訪問。另外還保存了PDF文件的加密等安全信息(以後詳細討論)。
PDF文檔的邏輯結構
作爲一種結構化的文件格式,一個PDF文檔是由一些稱爲“對象”的模塊組成的。並且每個對象都有數字標號,這樣的
話可以這些對象就可以北其他的對象所引用。這些對象不需要按照順序出現在PDF文檔裏面,出現的順序可以是任意的,比如一個PDF文件有3頁,第3頁可以
出現在第一頁以前,對象按照順序出現唯一的好處就是能夠增加文件的可讀性,如果你不會用文本編輯器來閱讀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對象(根對象)
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,
/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 Tf,Tf說明True font對象,字體明爲F1, 大小爲24個象素。
100 150 Td (Hello World) Tj,100 100 說
明這一行文字放置的位置,對於Td, 我們可以這樣理解,我們的當前X,Y座標分別加上100和150就是文本的位置,因爲在該例子中只有一個對象,那麼
它的位置就是(100,150), 如果下個對象位置信息爲100, 50 Td, 那麼它的位置應該就是(100+100, 150+50)也就是
(200,200)。(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
Object six defines the
字體對象,不再多作解釋。
所有的對象之後是下面的交叉引用表:
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是其偏移地址,00000爲5位產生號(最大爲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解析過程
圖4