欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

用C#來(lái)解析PDF文件

 更新時(shí)間:2015年07月12日 15:25:35   投稿:goldensun  
這篇文章主要介紹了用C#來(lái)解析PDF文件,同時(shí)作者也介紹了PdfFileAnalyzer這個(gè)應(yīng)用可以作為很好的成品示例,需要的朋友可以參考下

2015712151420057.png (680×475)

1. 介紹

這個(gè)項(xiàng)目讓你可以去讀取并解析一個(gè)PDF文件,并將其內(nèi)部結(jié)構(gòu)展示出來(lái). PDF文件的格式標(biāo)準(zhǔn)文檔可以從Adobe那兒獲取到. 這個(gè)項(xiàng)目基于“PDF指南,第六版,Adobe便攜文檔格式1.7 2006年11月”. 它是一個(gè)恐怕有1310頁(yè)的大部頭. 本文提供了對(duì)這份文檔的簡(jiǎn)潔概述. 與此相關(guān)的項(xiàng)目定義了用來(lái)讀取和解析PDF文件的C#類. 為了測(cè)試這些類,附帶的測(cè)試程序PdfFileAnalyzer讓你可以去讀取一個(gè)PDF文件,分析它并展示和保存結(jié)果. 程序?qū)DF文件分割成單獨(dú)每頁(yè)的描述,字體,圖片和其它對(duì)象. 有兩種類型的PDF文件不受此程序的支持: 加密文件和多代文件.

這個(gè)程序的1.1版本允許世界各地使用點(diǎn)符號(hào)作為小數(shù)分隔符的程序員來(lái)編譯和運(yùn)行程序.

1.2版本則修復(fù)了一個(gè)有關(guān)使用跨多個(gè)引用流來(lái)讀取PDF文檔的問(wèn)題. 1.2之前的版本對(duì)此場(chǎng)景只會(huì)以一個(gè)對(duì)象數(shù)字重復(fù)的錯(cuò)誤而終止運(yùn)行.

2. 概要

PDF格式的文件,借助Adobe Acrobat軟件,可以在各種屏幕上顯示查看,使用各種打印機(jī)打印。但是,如果使用二進(jìn)制文件編輯器打開(kāi)PDF文件,你會(huì)發(fā)現(xiàn)文件的大部分是不可讀的,有小部分是可讀的,如下:

 

1 0 obj
<</Lang(en-CA)/MarkInfo<</Marked true>>/Pages 2 0 R
/StructTreeRoot 10 0 R/Type/Catalog>>
endobj
2 0 obj
<</Count 1/Kids[4 0 R]/Type/Pages>>
endobj 
4 0 obj
<</Contents 5 0 R/Group <</CS/DeviceRGB /S/Transparency /Type/Group>>
/MediaBox[0 0 612 792] /Parent 2 0 R
/Resources <</Font <</F1 6 0 R /F2 8 0 R>>
/ProcSet[/PDF/Text/ImageB/ImageC/ImageI]>>
/StructParents 0/Tabs/S/Type/Page>>
endobj
5 0 obj
<</Filter/FlateDecode/Length 2319>>
stream
. . .
endstream
endobj

看上去,該文件是由嵌套在“n 0 OBJ ”和“ endobj ”關(guān)鍵詞之間的對(duì)象組成的,術(shù)語(yǔ)PDF也就是間接對(duì)象的意思。 “obj”前面的數(shù)字是對(duì)象編號(hào)和第幾代對(duì)象標(biāo)識(shí), 雙尖括號(hào)中的內(nèi)容表示數(shù)據(jù)字典對(duì)象,中括號(hào)中的內(nèi)容表示數(shù)組對(duì)象, 以斜杠/ 開(kāi)始的內(nèi)容表示參數(shù)名稱 (例如: /Pages)。上例中的第一項(xiàng) “1 0 obj” 表示文檔的目錄或者文檔的根對(duì)象。文檔目錄的字典對(duì)象 “/Pages 2 0 R”,指向定義頁(yè)碼樹(shù)對(duì)象的引用。按照這樣推算,編號(hào)為2的對(duì)象包含指向 “/Kids[4 0 R]”的頁(yè)面的引用,是一個(gè)頁(yè)面文檔。 編號(hào)為4的對(duì)象是唯一的一個(gè)頁(yè)面定義, 頁(yè)面大小為612*792點(diǎn), 換句話說(shuō),也就是8.5” * 11” (1” 代表72 點(diǎn))點(diǎn)。該頁(yè)面使用了兩種字體F1和F2,這兩種字體分別在編號(hào)為6和8的對(duì)象中定義。該頁(yè)面的內(nèi)容在編號(hào)為5的對(duì)象中描述,該對(duì)象中包含頁(yè)面繪圖的流信息,示例中的 “. . .”代表這部分流信息。如果使用二進(jìn)制文件編輯器打開(kāi)PDF文件,會(huì)發(fā)現(xiàn)這部分流信息看起來(lái)是一長(zhǎng)串不可讀的隨機(jī)數(shù),原因是那是壓縮數(shù)據(jù)。流數(shù)據(jù)采用Zlib方法壓縮,壓縮方式由字典對(duì)象“/Filter /FlateDecode”描述,被壓縮流的大小為2319字節(jié)。解壓這部分流信息,前面幾行內(nèi)容如下所示:
 

q
37.08 56.424 537.84 679.18 re
W* n
/P <</MCID 0>> BDC 0.753 g
36.6 465.43 537.96 24.84 re
f*
EMC /P <</MCID 1/Lang (x-none)>> BDC BT
/F1 18 Tf
1 0 0 1 39.6 718.8 Tm
0 g
0 G
[(GRA)29(NOTECH LI)-3(MIT)-4(ED)] TJ
ET

這是頁(yè)面描述語(yǔ)言的一個(gè)小例子。 示例中, “re” 代表矩形,“re” 前面的4個(gè)數(shù)字代表矩形的位置和大小,依次為:起點(diǎn)橫坐標(biāo)、起點(diǎn)縱坐標(biāo)、寬度、高度。


這個(gè)簡(jiǎn)單的例子演示了PDF文件內(nèi)部實(shí)現(xiàn)的總體思路。從頁(yè)面層次結(jié)構(gòu)的根對(duì)象開(kāi)始, 每一頁(yè)都定義了諸如字體、圖片、內(nèi)容流的資源,內(nèi)容流由操作符和繪制頁(yè)面所需要的參數(shù)構(gòu)成。PDF文件分析器會(huì)產(chǎn)生一個(gè)對(duì)象匯總文件,該文件包含非流對(duì)象的其他所有對(duì)象。每個(gè)數(shù)據(jù)流會(huì)被解碼并保存為一個(gè)單獨(dú)的文件, 頁(yè)面描述流保存為文本格式的文件, 圖片流保存為.jpg或.bmp格式的文件,字體流保存為.ttf格式的文件,其他二進(jìn)制流保存為.bin 格式的文件,文本流保存為.txt格式的文件。通過(guò)另一個(gè)解析過(guò)程,晦澀難懂的頁(yè)面描述會(huì)被轉(zhuǎn)換為偽C#代碼,如上例中的頁(yè)面描述被轉(zhuǎn)為:
 

SaveGraphicsState(); // q
Rectangle(37.08, 56.424, 537.84, 679.18); // re
ClippingPathEvenOddRule(); // W*
NoPaint(); // n
BeginMarkedContentPropList("/P", "<</MCID 0>>"); // BDC
GrayLevelForNonStroking(0.753); // g
Rectangle(36.6, 465.43, 537.96, 24.84); // re
FillEvenOddRule(); // f*
EndMarkedContent(); // EMC
BeginMarkedContentPropList("/P", "<</Lang(x-none)/MCID 1>>"); // BDC
BeginText(); // BT
SelectFontAndSize("/F1", 18); // Tf
TextMatrix(1, 0, 0, 1, 39.6, 718.8); // Tm
GrayLevelForNonStroking(0); // g
GrayLevelForStroking(0); // G
ShowTextWithGlyphPos("[(GRA)29(NOTECH LI)-3(MIT)-4(ED)]"); // TJ
EndTextObject(); // ET

文章接下來(lái)的部分將對(duì)PDF文件的結(jié)構(gòu)和解析過(guò)程進(jìn)行更為詳細(xì)的描述,接下來(lái)的章節(jié)包括:對(duì)象定義,文件結(jié)構(gòu),文件解析,文件讀取,以及使用PDF文件分析器編程。

3. 免責(zé)聲明

pdf 文件分析器能處理大量的文件,這是我在自己的系統(tǒng)上掃描眾多PDF文件的經(jīng)驗(yàn)。不過(guò),該程序不支持加密文件或者多個(gè)代文件(在對(duì)象不為零之前的第二個(gè)數(shù)字)。在PDF規(guī)格文件之中可用功能的數(shù)量是非常顯著的。這并不可能為一個(gè)單的個(gè)開(kāi)發(fā)者系統(tǒng)地測(cè)試所有的功能。如果在整個(gè)文件分析期間該程序拋出一個(gè)異常,將顯示一條錯(cuò)誤信息,該信息顯示源代碼模塊名和行號(hào)。
4.對(duì)象定義

PDF文件生成多個(gè)對(duì)象。在PDF文件分析器項(xiàng)目中每個(gè)PDF對(duì)象都有一個(gè)對(duì)應(yīng)的類。所有這些對(duì)象類都派生于PDFbase類。對(duì)象類定義源代碼是BasicObjects.cs.確卻地PDF對(duì)象定義在Adobe pdf文件 規(guī)格第三章之中是有用的


4.1. 基礎(chǔ)的對(duì)象

    Boolean對(duì)象是靠PdfBoolean類來(lái)實(shí)現(xiàn)的. Boolean在PDF上的定義同C#上的是相同的.

    Integer 對(duì)象是靠PdfInt類來(lái)實(shí)現(xiàn)的. PDF上的定義同C#上Int32的定義是相同的.

    實(shí)數(shù)對(duì)象是靠PdfReal類來(lái)實(shí)現(xiàn)的. PDF上的定義同C#上的Single定義相同.

    String 對(duì)象是靠PdfStr類來(lái)實(shí)現(xiàn)的. PDF上的定義同C#相比有所不同. String 是用字節(jié)構(gòu)造出來(lái)的,而不是字符. 它被包在圓括號(hào)()里面. PdfFileAnalyzer會(huì)把包含在圓括號(hào)中的C#字符串保存成PDF的字符串. PDF的字符串對(duì)于ASCII編碼非常有用.

    十六進(jìn)制字符串獨(dú)享是靠PdfHex類來(lái)實(shí)現(xiàn)的. 它是由每字節(jié)兩個(gè)十六進(jìn)制數(shù)定義,并包在尖括號(hào)里面的字符串. PdfFileAnalyzer 將包含在尖括號(hào)中的C#字符串保存成PDF十六進(jìn)制字符串. 對(duì)于 PDF 讀取器,字符串和十六進(jìn)制字符串對(duì)象可用于同種目的. 字符串 (AB) 等同于<4142>. PDF 十六進(jìn)制字符串對(duì)于任意編碼的場(chǎng)景非常有用.

    Name 對(duì)象是靠PdfName類來(lái)實(shí)現(xiàn)的. Name 對(duì)象是由打頭的正斜杠后面跟著一些字符組成的. 例如 /Width. Named 對(duì)象用作參數(shù)名稱. PdfFileAnalyzer 將正斜杠開(kāi)頭的C#字符串保存成Name對(duì)象.

    Null 對(duì)象是靠PdfNull類來(lái)實(shí)現(xiàn)的. PDF 對(duì)于null的定義基本上同C#中的是一樣的.

4.2. 復(fù)合的對(duì)象

    Array 對(duì)象是靠 PdfArray 類來(lái)實(shí)現(xiàn)的. PDF 數(shù)組是一個(gè)封裝在一堆中括號(hào)中的對(duì)象的集合. 一個(gè)數(shù)組的對(duì)象可以是除了流之外的任何對(duì)象.PdfFileAnalyzer 將一個(gè)C#數(shù)組中的對(duì)象保存成PdfBase類

    . 因?yàn)樗械膶?duì)象都繼承自PdfBase,所有在這個(gè)數(shù)組中保存多種類型的對(duì)象沒(méi)有啥問(wèn)題. 當(dāng)數(shù)組對(duì)象被轉(zhuǎn)換成一個(gè)字符串時(shí)(使用ToString()方法), 程序會(huì)在首位添加中括號(hào). 數(shù)組可以是空的. 下面是一個(gè)有六個(gè)對(duì)象的數(shù)組示例: [120 9.56 true null (string) <414243>].

    Dictionary 對(duì)象是靠PdfDict類實(shí)現(xiàn)的. PDF 字典是一組被包入一對(duì)雙尖括號(hào)中的鍵值對(duì)集合. Dictionary 的鍵是一個(gè)對(duì)象的名稱,而值則可以是除了流之外的任何對(duì)象.  PdfFileAnalyzer 將一個(gè)鍵值對(duì)保存到PdfPair類中. 鍵是一個(gè)C#字符串,而值則是一個(gè)PdfBase.PdfDict 類有一個(gè)PdfPair類的數(shù)組. Dictionary 可以用鍵來(lái)訪問(wèn). 因而鍵值對(duì)的順序沒(méi)有啥意義. PdfFileAnalyzer 用鍵來(lái)對(duì)鍵值對(duì)進(jìn)行排序. 下面是一個(gè)有三個(gè)鍵值對(duì)的字典: <</CropBox [0 0 612 792] /Rotate 0 /Type /Page>>.

    Stream 對(duì)象是靠PdfStream來(lái)實(shí)現(xiàn)的. Streams 被用來(lái)處理面熟語(yǔ)言,圖形和字體. PDF Stream 由一個(gè)字典和一個(gè)字節(jié)流組成. 字典中定義了流的參數(shù). 比如流對(duì)象中字典的一個(gè)鍵值對(duì) /Filter. PDF 文檔定義了10種類型的過(guò)濾器. PdfFileAnalyzer 支持了4種. 這是我發(fā)現(xiàn)在實(shí)際場(chǎng)景中只會(huì)被用到那4種. 壓縮過(guò)濾器 FlateDecode 是現(xiàn)在的PDF寫入器最長(zhǎng)被用到的過(guò)濾器. FlateDecode支持ZLib解壓縮. LZWDecode 壓縮過(guò)濾器在過(guò)去些年用的比較多. 為了能讀取比較老的PDF文件, 我們的程序支持這個(gè)過(guò)濾器. ASCII85Decode 過(guò)濾器將可被打印的ASCII轉(zhuǎn)換成二進(jìn)制位. DCTDecode 用于JPEG圖像的壓縮.PdfFileAnalyzer 為前三種實(shí)現(xiàn)了解壓縮. DCTDecode 流則以文件擴(kuò)展名.jpg保存. 它是一個(gè)可以被展示的圖片文件.

    Object 流在PDF 1.5中被引入. 它是一個(gè)包含多個(gè)間接對(duì)象(在下面會(huì)描述道)的流. 上面描述的Stream 對(duì)象一次只壓縮一個(gè)流. Object 流會(huì)將所有包含進(jìn)來(lái)的流壓縮到一個(gè)壓縮域中.

    多引用流在PDF 1.5中被引入. 它是一個(gè)包含多引用表格的流,下文會(huì)描述到.

    內(nèi)聯(lián)圖片對(duì)象是靠 PdfInlineImage來(lái)實(shí)現(xiàn)的. 它是一個(gè)帶有一個(gè)流的流. 內(nèi)聯(lián)圖片是頁(yè)面描述語(yǔ)言的一部分. 它由BI-開(kāi)頭圖形, ID-圖形數(shù)據(jù)和EI-結(jié)尾圖形這三個(gè)操作符組成. BI 和 ID 之間的區(qū)域是一個(gè)圖形字典,而ID 和 EI 之間的區(qū)域則包含圖形數(shù)據(jù).

4.3. 間接對(duì)象

    間接對(duì)象是靠 PdfIndirectObject實(shí)現(xiàn)的. 它是一個(gè)PDF文檔的主要構(gòu)造塊. 間接對(duì)象是任何被包在 “n 0 obj” 和 “endobj”之間的對(duì)象. 其它對(duì)象可以通過(guò)設(shè)定“n 0 R”來(lái)引用間接對(duì)象. “n”代表對(duì)象編號(hào). “0”代表生成編號(hào). 這個(gè)程序不支持0之外的生成編號(hào). PDF 規(guī)范允許其它的編號(hào). 多代生成的理念允許PDF的修改操作是在保留原有文件的基礎(chǔ)上追加變更.

    對(duì)象引用時(shí)一種引用間接對(duì)象的方法. 例如 /Pages 2 0 R 是目錄對(duì)象中的字典里的一項(xiàng). 它是一個(gè)指向 /Pages 對(duì)象的指針. pages對(duì)象是編號(hào)為2的間接對(duì)象.

4.4. 操作符和關(guān)鍵詞

    操作符和關(guān)鍵詞不被認(rèn)為是PDF對(duì)象. 而PdfFileAnalyzer 程序有一個(gè)PdfOp 和一個(gè)PdfKeyword 類可以從中得到 PdfBase 的類. 在轉(zhuǎn)換過(guò)程中,轉(zhuǎn)換器為每一個(gè)可用的字符序列創(chuàng)建了一個(gè) PdfOp 或者PdfKeyword . Pdf文件規(guī)范的附錄A-操作符總結(jié)中列出了所有的操作符. 列表中有73個(gè)操作符. 下面是一些操作符的示例: BT-打頭的文本對(duì)象, G-用于做記號(hào)的設(shè)置灰度操作, m-移動(dòng)到, re-矩形和Tc-設(shè)置字符間距. 下面是關(guān)鍵詞的示例: stream, obj, endobj, xref.

5. 文件結(jié)構(gòu)

PDF文件由四個(gè)部分構(gòu)成: 頭部Header , 主體body, 多引用cross-reference 和附帶簽名 trailer signature.

  •     Header: 頭部是文件的簽名. 它必須是 %PDF-1.x , x 從 0 到 7.
  •     Body: 主體區(qū)域包含所有的間接對(duì)象.
  •     Cross-reference: 多引用是一個(gè)指向所有間接對(duì)象的文件位置指針列表. 有兩種類型的多引用表格. 原始的類型有ASCII字符組成. 新式的是一個(gè)包含一個(gè)間接對(duì)象的流. 信息以二進(jìn)制數(shù)字編碼. 在多引用表格的結(jié)束部分有一個(gè)附件字典. 一個(gè)文件可以有超過(guò)一個(gè)的多引用區(qū)域.
  •     Trailer signature: 附帶簽名由關(guān)鍵詞“startxref”, 最后一個(gè)多引用表格的偏移位, 和結(jié)束簽名 %%EOF 組成. 請(qǐng)注意: 附帶簽名是多引用區(qū)域的一部分.

6. 文件轉(zhuǎn)換

PDF 文件是一個(gè)字節(jié)的序列. 一些字節(jié)有特殊的意義.

空格被定義成: null, tab, 換行, 換頁(yè), 回車和間隔.

分隔符被定義成: (, ), <, >, [, ], {, }, /, %, 以及空格字符.

文件轉(zhuǎn)換是由PdfParser 類來(lái)完成的. 開(kāi)始進(jìn)行轉(zhuǎn)換過(guò)程是,程序會(huì)設(shè)置文件需要被轉(zhuǎn)換區(qū)域的位置. ParseNextItem() 是提取下一個(gè)對(duì)象的方法.


解析器跳過(guò)空格符和注釋。如果下一個(gè)字節(jié)是“(”,判斷對(duì)象為一個(gè)字符串。如果下一個(gè)字節(jié)是“[”,判斷對(duì)象是一個(gè)數(shù)組。如果接下來(lái)的兩個(gè)字節(jié)是“<<”,判斷對(duì)象是一個(gè)字典。如果下一個(gè)字節(jié)是“<”,判斷對(duì)象是一個(gè)十六進(jìn)制字符串。如果下一個(gè)字節(jié)是“/”,判斷對(duì)象是一個(gè)名稱。如果下一個(gè)字節(jié)不是上述任何一種,解析器會(huì)采集隨后的字節(jié)直到發(fā)現(xiàn)定界符。定界符不是當(dāng)前標(biāo)記符的一部分。標(biāo)記符可以是整數(shù),實(shí)數(shù),操作符或關(guān)鍵詞。在整數(shù)的情況下,程序?qū)⑦M(jìn)一步搜索對(duì)象引用“n 0 R”或間接對(duì)象“n 0 obj”中 n 為該整數(shù)的對(duì)象。從 ParseNextItem() 返回的值是第4節(jié)“對(duì)象的定義”中所述的適當(dāng)對(duì)象。對(duì)象的類作為 PdfBase 類返回。

在數(shù)組或字典的情況下,程序?qū)?zhí)行遞歸調(diào)用 ParseNextItem() 來(lái)解析數(shù)組或字典的內(nèi)部對(duì)象。

7. 文件讀取

PdfDocument 類是 PDF 文件分析的主要類。入口方法是 ReadPdfFile(String FileName)。程序以二進(jìn)制讀取的方式打開(kāi) PDF 文件(一次一個(gè)字節(jié))。

文件分析開(kāi)始于檢查頭部簽名 %PDF-1.x(x為0到7)和結(jié)尾簽名%%EOF。有人會(huì)認(rèn)為,所有的 PDF 生成器會(huì)把頭部簽名放在文件的零位置,結(jié)尾簽名放在文件的最后。不幸的是,實(shí)際并非如此。程序必須在文件的兩端搜索這兩個(gè)簽名。如果頭部簽名不在零位置,所有間接對(duì)象的文件位置的指針也必須調(diào)整。

就在結(jié)尾簽名的前面有一個(gè)指向最后一個(gè)交叉引用表開(kāi)始位置的指針。

解析器為多引用表設(shè)置文件位置. 如果下一個(gè)對(duì)象是“xref” 關(guān)鍵詞,我們就有了原來(lái)類型的多引用. 否則,它就是新的基于流的多引用. 文件可以有多個(gè)多引用表. 文件也可以同時(shí)擁有新的和舊的風(fēng)格的表. 每一個(gè)表都有一個(gè)對(duì)象數(shù)目和指向間接引用開(kāi)頭的指針的列表. 對(duì)于每一個(gè)活動(dòng)對(duì)象程序都會(huì)創(chuàng)建一個(gè)PdfIndirectObject 對(duì)象并將其保存在 ObjectArray中. 除了對(duì)象的數(shù)字和位置,這個(gè)對(duì)象的其它東西都是空的. 對(duì)于原來(lái)的多引用表,其位置是相對(duì)于文件而言的. 對(duì)于流類型的多引用,位置是相對(duì)于一個(gè)父間接對(duì)象流而言的.

在處理過(guò)程中,如果間接對(duì)象生成了0之外的數(shù)字, 程序的執(zhí)行就會(huì)被終止. PdfFileAnalyzer 不支持多代的形式.


附件字典在交叉引用表的末尾處。分析PDF文件的時(shí)候,我們創(chuàng)建了一個(gè)帶負(fù)對(duì)象號(hào)的虛擬間接對(duì)象用于保存附件字典。

程序在附件字典中尋找四個(gè)特定的入口。如果找到/Encrypt入口,表示PDF文件是被加密的,程序的將結(jié)束分析,因?yàn)槌绦虿恢С址治黾用芨袷降腜DF文件。接著程序?qū)ふ?Root目錄對(duì)象的對(duì)象號(hào)。如果找到/XRefStm入口,我們就有了兩種交叉引用的類型。最后如果存在/Prev入口,我們有了另一個(gè)用于處理的交叉引用表。

交叉引用的處理完成后,我們擁有所有的間接對(duì)象的數(shù)組。  在處理階段,可用信息是對(duì)象號(hào)和對(duì)象位置。下一步,程序遍歷數(shù)組,讀取并解析每一個(gè)間接對(duì)象,并設(shè)置對(duì)象的值。如果對(duì)象是流,僅字典部分被解析,因?yàn)樵谶@個(gè)時(shí)候還不知道流的長(zhǎng)度。除了上述對(duì)象,如果字典和流對(duì)象的對(duì)象類型和子類型成員是可用的,系統(tǒng)將為字典和流對(duì)象設(shè)置這兩個(gè)值。


接下來(lái)程序遍歷所有的對(duì)象,并處理流對(duì)象。流對(duì)象的對(duì)象類型是"/ObjStm"。程序讀取和對(duì)象相關(guān)聯(lián)的流,并分解流到多個(gè)間接對(duì)象上。

接下來(lái)程序搜索所有的字典對(duì)象和流對(duì)象引用的對(duì)象字典對(duì)象。程序查找鍵值對(duì),例如“/name n 0 R”。加入鍵值對(duì)被找到,程序檢查對(duì)象類型。如果再對(duì)象解析階段沒(méi)有設(shè)置對(duì)象類型,對(duì)象類型將設(shè)置為/name值。

下一步,讀取所有前面沒(méi)有讀取的流。系統(tǒng)讀取從文件讀取流。流被解碼并保存到對(duì)應(yīng)的文件中。PdfFileAnalyzer支持如下的過(guò)濾:/FlateDecode,/LZWDecode, /ASCII85Decode和/DCTDecode。文本文件的擴(kuò)展名是.txt,二進(jìn)制文件的擴(kuò)展名是.bin,圖片文件的擴(kuò)展名是.jpg和.bmp,字體文件的擴(kuò)展名是.ttf,交叉引用文件的擴(kuò)展名是.xref。/FlateDecode是ZLib Deflate壓縮算法。
下一步是構(gòu)建頁(yè)的內(nèi)容。程序跟隨從根開(kāi)始的頁(yè)面樹(shù)。頁(yè)對(duì)象不是流對(duì)象。換句話說(shuō),頁(yè)描述命令是不能直接在也對(duì)象中的。頁(yè)對(duì)象字典有/Contents的鍵值對(duì)。如果不存在這個(gè)鍵值對(duì),那么頁(yè)面就是空的。內(nèi)容入口值可以是一個(gè)單獨(dú)的引用或者是一個(gè)應(yīng)用數(shù)組。程序?qū)閬?lái)自于一個(gè)或多個(gè)內(nèi)容流的頁(yè)面創(chuàng)建虛擬的內(nèi)容流。頁(yè)內(nèi)容虛擬流保存在PageObj_xx.txt和PageSource_xx.txt中。PageObj_xx.txt是頁(yè)面的實(shí)際描述內(nèi)容。PageSource_xx.txt是將頁(yè)面的描述內(nèi)容轉(zhuǎn)換為偽C#源代碼。在第二節(jié)概要中,有這兩個(gè)文件的例子。

頁(yè)內(nèi)容流是由參數(shù)和操作符組成的。例如矩形由四個(gè)實(shí)數(shù)描述的,內(nèi)嵌的圖片不遵循這個(gè)規(guī)則。它的描述是在第三節(jié)對(duì)象定義中。

最后,程序產(chǎn)生對(duì)象匯總文件ObjectSummary.txt。文件顯示所有簡(jiǎn)介對(duì)象的信息不包含流。

8. PdfFileAnalyzer 程序

開(kāi)發(fā)應(yīng)用程序 PdfFileAnalyzer 的目的是用來(lái)測(cè)試這個(gè) PDF 文件解析類。如果你想在開(kāi)發(fā)環(huán)境之外測(cè)試它的可執(zhí)行程序,需創(chuàng)建一個(gè)名為 PdfFileAnalyzer 的目錄并復(fù)制 PdfFileAnalyzer.exe 到這個(gè)目錄中,然后運(yùn)行這個(gè)程序。如果你想從 Visual C# 開(kāi)發(fā)環(huán)境中運(yùn)行這個(gè)項(xiàng)目,請(qǐng)確保你在“項(xiàng)目屬性”的“Debug”標(biāo)簽欄中定義了一個(gè)工作目錄。此程序是使用 Microsoft Visual C# 2012 開(kāi)發(fā)的。

運(yùn)行程序,可用的操作項(xiàng)有: Open, Setup 和 Exit.

程序首次執(zhí)行時(shí)你必須使用 Setup 定義工程目錄。這個(gè)目錄盛放所有被分析的 PDF 文件所產(chǎn)生的對(duì)應(yīng)子目錄。

Open 按鈕會(huì)顯示一個(gè)標(biāo)準(zhǔn)的文件選擇對(duì)話框,你可以在其中找到你要進(jìn)行分析的 PDF 文件。


PDF文件分析器界面將切換到類的匯總界面:

2015712151511150.png (600×581)

每行代表一個(gè)間接的PDF對(duì)象。每列是:

  •     Object No. 間接對(duì)象號(hào)。對(duì)于附件字典來(lái)說(shuō)dummy號(hào),對(duì)象號(hào)是一個(gè),對(duì)象號(hào)是負(fù)數(shù)時(shí),在界面上顯示為TRn
  •     Ojbect 在第4節(jié)中定義的對(duì)象類型
  •     Type 如果對(duì)象是字典或者流,類型是/Type字典的值。如果類型不是字典或者字典不包含/Type,顯示值來(lái)自于對(duì)這個(gè)對(duì)象的間接引用
  •     Subtype 如果對(duì)象是字典或者流,或者字典包含/Subtype,將顯示在這一列
  •     Parent Object No. 如果間接對(duì)象是對(duì)象流的一部分(見(jiàn)4.2節(jié)復(fù)合對(duì)象),這一列顯示流對(duì)象的對(duì)象號(hào)
  •     Parent Index 如果間接對(duì)象是對(duì)象流的一部分,索引號(hào)是父對(duì)象流的號(hào)
  •     File Name 流對(duì)象和頁(yè)面對(duì)象存在文件名。File Name是文件存儲(chǔ)在流對(duì)象內(nèi)的名字。文件有如下的擴(kuò)展名:.txt是文本文件,.bin是二進(jìn)制文件,.bmp是圖片,.jpg是圖片,.ttf是字體,.xref是多引用流。如果分析MyFile.PDF的流文件,工程目錄的子目錄MyFile將被指定在啟動(dòng)界面上。頁(yè)面對(duì)象不是流。文件表示這一頁(yè)所有對(duì)象的關(guān)聯(lián)關(guān)系
  •     Ojbect Position 如果間接對(duì)象文件不是對(duì)象流類型,這是對(duì)象在PDF文件內(nèi)的位置。如果間接對(duì)象是對(duì)象流的一部分,這對(duì)象在父對(duì)象內(nèi)的位置。位置按照十進(jìn)制和十六進(jìn)制數(shù)字顯示,便于程序員再二進(jìn)制編輯器中查看PDF文件
  •     Stream Position 和 Stream Length 流的位置和長(zhǎng)度。流的位置是相對(duì)于文件或者父對(duì)象的,同對(duì)象的位置使用相同的計(jì)算方法


點(diǎn)擊Summary按鈕,查看ObjectSummary.txt 文件。

選擇一行并點(diǎn)擊View按鈕或者雙擊一行后將顯示對(duì)象分析界面,用于查看間接對(duì)象的詳情。

2015712151532679.png (600×657)

對(duì)于所有的非流對(duì)象,前面的三個(gè)按鈕是不能點(diǎn)擊的。僅僅顯示對(duì)象自身的信息。你能用文本方式或者十六進(jìn)制格式查看這些信息。

對(duì)于流對(duì)象,第一個(gè)按鈕的名字是object type。前兩個(gè)按鈕object type和Stream允許你在查看對(duì)象和流之間切換。Hex和Text按鈕允許你采用二進(jìn)制格式或者文本格式查看。如果是圖片流,文本格式顯示為四列:(1) 對(duì)象號(hào),(2) 類型 (0-未使用,1-普通對(duì)象,2-流對(duì)象),(3)普通對(duì)象的位置和流對(duì)象的父對(duì)象,(4) 父對(duì)象的索引號(hào)。如果是二進(jìn)制流(例如:字體),則僅能用十六進(jìn)制格式查看。

頁(yè)面對(duì)象按照流對(duì)象來(lái)處理。所有內(nèi)容對(duì)象的文本顯示是關(guān)聯(lián)的。另外,Source按鈕允許你查看頁(yè)面在C#代碼中的描述語(yǔ)言。

JPG圖片和BMP圖片可以旋轉(zhuǎn)方向和調(diào)整大小。

 

相關(guān)文章

  • 詳解c# 數(shù)組(Array)

    詳解c# 數(shù)組(Array)

    這篇文章主要介紹了c# 數(shù)組的的相關(guān)資料,文中講解非常細(xì)致,代碼幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下
    2020-07-07
  • 關(guān)于C#中使用Oracle存儲(chǔ)過(guò)程返回結(jié)果集的問(wèn)題

    關(guān)于C#中使用Oracle存儲(chǔ)過(guò)程返回結(jié)果集的問(wèn)題

    Oracle中可以使用游標(biāo)(Cursor)對(duì)數(shù)據(jù)集進(jìn)行操作,但在存儲(chǔ)過(guò)程輸出參數(shù)中直接使用Cursor錯(cuò)誤,下面小編給大家?guī)?lái)了C#中使用Oracle存儲(chǔ)過(guò)程返回結(jié)果集的問(wèn)題,感興趣的朋友一起看看吧
    2021-10-10
  • 淺談C# 字段和屬性

    淺談C# 字段和屬性

    這篇文章主要介紹了C# 字段和屬性的的相關(guān)資料,文中示例代碼非常詳細(xì),供大家參考和學(xué)習(xí),感興趣的朋友可以了解下
    2020-06-06
  • C#多線程之取消架構(gòu)介紹

    C#多線程之取消架構(gòu)介紹

    這篇文章介紹了C#多線程之取消架構(gòu),文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-04-04
  • Unity實(shí)現(xiàn)見(jiàn)縫插針小游戲

    Unity實(shí)現(xiàn)見(jiàn)縫插針小游戲

    這篇文章主要為大家詳細(xì)介紹了Unity實(shí)現(xiàn)見(jiàn)縫插針小游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-04-04
  • C#實(shí)現(xiàn)簡(jiǎn)單的3DES加密解密功能示例

    C#實(shí)現(xiàn)簡(jiǎn)單的3DES加密解密功能示例

    這篇文章主要介紹了C#實(shí)現(xiàn)簡(jiǎn)單的3DES加密解密功能,結(jié)合實(shí)例形式分析了C#實(shí)現(xiàn)3DES加密解密的定義、使用等具體步驟與相關(guān)操作技巧,需要的朋友可以參考下
    2017-08-08
  • C# WINFORM 強(qiáng)制讓窗體獲得焦點(diǎn)的方法代碼

    C# WINFORM 強(qiáng)制讓窗體獲得焦點(diǎn)的方法代碼

    C# WINFORM 強(qiáng)制讓窗體獲得焦點(diǎn)的方法代碼,需要的朋友可以參考一下
    2013-04-04
  • C# .NET中Socket簡(jiǎn)單實(shí)用框架的使用教程

    C# .NET中Socket簡(jiǎn)單實(shí)用框架的使用教程

    最近一個(gè)項(xiàng)目因?yàn)橐玫絊ocket傳輸問(wèn)題,所以決定學(xué)習(xí)一下,將自己學(xué)習(xí)的內(nèi)容總結(jié)分享出來(lái),下面這篇文章主要給大家介紹了關(guān)于C# .NET中Socket簡(jiǎn)單實(shí)用框架使用的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友可以參考下。
    2017-09-09
  • WPF TextBox實(shí)現(xiàn)按字節(jié)長(zhǎng)度限制輸入功能

    WPF TextBox實(shí)現(xiàn)按字節(jié)長(zhǎng)度限制輸入功能

    這篇文章主要為大家詳細(xì)介紹了WPF TextBox實(shí)現(xiàn)按字節(jié)長(zhǎng)度限制輸入功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-11-11
  • ZooKeeper的安裝及部署教程

    ZooKeeper的安裝及部署教程

    Zookeeper是一個(gè)針對(duì)大型分布式系統(tǒng)的可靠協(xié)調(diào)系統(tǒng),提供的功能包括:配置維護(hù)、名字服務(wù)、分布式同步、組服務(wù)等,這篇文章主要介紹了ZooKeeper的安裝及部署,需要的朋友可以參考下
    2019-06-06

最新評(píng)論