1. 程式人生 > >使用C#開發pdf閱讀器初探(基於WPF,沒有使用開源庫)

使用C#開發pdf閱讀器初探(基於WPF,沒有使用開源庫)

前言 pdf是最流行的版式格式檔案標準,已成為國際標準。pdf相關的開源軟體非常多,也基本能滿足日常需要了。相關商業軟體更是林林總總,幾乎應有盡有!似乎沒必要自己再獨立自主開發!但,本人基於以下考慮,決定自主研發一款pdf閱讀器。

  1)通過編寫pdf閱讀器,可以迅速的熟悉pdf檔案的處理。pdf格式包含的內容非常多,僅僅通過查資料,很難掌握其內容。

  2)任何技術,只有自主可控,才能到達氣定神閒!使用開源軟體是簡單,萬一遇到問題,就是個坑!

  3)解決pdf與ofd互轉問題。ofd是國家標準,相關的處理軟體非常少。為了解決兩種格式檔案互轉,必須瞭解pdf。

  4)本人此前開發了一款ofd閱讀器,積累了一些經驗。為開發pdf閱讀器增添了信心。

特別說明 本人花了幾周寫了這款閱讀器,驗證了pdf不同型別的資料處理,還遠遠到不了商用的要求。不積跬步無以至千里!本人會慢慢完善這款軟體,敬請期待。本人的參考資料有兩本英文書籍和pdf英文標準文件。

程式介面: 點選下載程式

pdf相關參考資料:

pdf檔案結構簡介 

pdf總的內容結構如下:

 1)header: 有關pdf版本資訊。最新版為 %PDF−1. 7

 2)Body:儲存具體資料,pdf就是由很多object組成的。每個object由dictionary和stream組成。dictionary儲存就是key、value字元對。dictionary是可以巢狀的,就是value有可能也是一個dictionary。

 3)Cross-Reference Table:交叉索引表。可以快速定位到具體object。便於隨機讀取object。

 4)Trailer:給出交叉索引表的位置。讀取pdf檔案都是從最後開始讀的,所以Trailer一定是在檔案最後。

 pdf處理總體結構

 object內容讀取

  交叉索引表能快速定位到某個object的位置,讀取object內容不難,關鍵是分析dictionary。dictionary是可以巢狀,就是dictionary的內容還有dictionary。快速解析出所有的dictionary是處理的關鍵。典型的dictionary結構如下:

<<
/Annots 68 0 R
/BleedBox [0 0 504 661.5]
/Contents [51 0 R]
/CropBox [0 0 504 661.5]
/MediaBox [0 0 504 661.5]
/Parent 4334 0 R

/Resources
<< //巢狀dictionary
/ColorSpace <</CS1 62 0 R>>  //2次巢狀dictionary
/Font <</F1 7 0 R/F2 11 0 R/F3 13 0 R/F4 53 0 R>> //2次巢狀dictionary
/ProcSet [/PDF/Text/ImageB/ImageC] //陣列
/XObject <</I1 54 0 R/I2 56 0 R/I3 60 0 R>>//2次巢狀dictionary
>>

/Type /Page
>>

頁面內容分析

  頁面內容由系列運算元和操作符組成。所有的運算元和操作符在同一個文字中,所以要快速的將運算元和操作符組成可以執行的操作對。

0 0 515.95 728.6 re
W* n
0 w
2 M
2 J
2 j
0 0 0 RG
BT
0 0 0 rg
/FT8 180 Tf
/GS13 gs
0.05 0 0 -0.05 187.68 676.49 Tm
<35BE>Tj 180 0 TD<1D5F>Tj 180 0 TD<4205>Tj 180 0 TD<4EC8>Tj
ET

  字元都是存在()或<>中,除去字元和數字,就是操作符。如上文W*、n都是操作符;<35BE>為16進位制字元對應的key,具體代表哪個字,需要到查字元表。這裡的35BE並不是unicode字元對應的值,還需要再查表。如下圖:

beginbfchar
<0019> <0036>
<35BE> <0037>
<001B> <0038>
<001C> <0039>
endbfchar

  <35BE>對應的是<0037>。該表存在字型資原始檔object中。

 頁面顯示

  座標系變換

  理清不同座標系之間的關係是處理的關鍵。座標系分為:Device Space(裝置座標空間)、User Space(裝置座標空間)、text space(文字座標空間)等。

  繪畫上下文設定 

  當前繪畫的狀態(畫筆、畫刷等)是儲存在棧中,會有入棧出棧操作。

  特出畫刷處理

  pdf有一種畫刷,比如漸變色,這個很難找到現成的畫刷使用。我使用的是ImageBrush,就是使用圖片作為畫刷。在記憶體中建立可擦寫的圖片,可以精確控制每個畫素的值。根據pdf標準提供的演算法,計算每個畫素的值。

  pdf的顯示大體分為三種:曲線、文字、圖片。其中曲線的顯示是比較麻煩的,關鍵是將pdf標準的描述與wpf曲線操作對應起來。

pdf閱讀器開發說明

  如果完全引數標準檔案開發,是比較枯燥,感覺慢慢長路看不到盡頭。我採用是單個功能各個擊破的方法,能很快見到開發成果。我使用的參考書是《PDF Explained》,100多頁,只是對pdf做大體介紹,但是各個功能點都有所提及。我就參照該書提供的示例檔案,逐步驗證每個檔案。

  每種顯示都有多種處理方法,每個軟體生成pdf的風格是不同的。對特定的軟體生成的pdf做幾次驗證後,基本可以保證該軟體生成的pdf都可以正常顯示。

  wps是可以直接將doc檔案轉換為pdf的。我特地對wps生成的pdf做了測試,經過幾次除錯,現在基本可以正常處理wps生成的pdf檔案。

  後記 對於開發pdf閱讀器這類軟體,以前都是不敢想象的。像這種複雜的軟體,必須遵循一定的設計模式、正確建立域模型。所以開發這類軟體,並不是在於你對pdf標準的理解是否深刻,關鍵還是程式設計的功底。繼承、封裝、多型、SOLID設計準則這些並不難理解,但是要達到應用自如還需要反覆錘鍊。把握好每個細節,正確運用設計準則,一步一個腳印,最終會將不可能變成可