使用iTextSharp修改PDF檔案(二)
(最近研究了PDF的一些東西,在網上找了不少資料,但大部分講的都是利用iTextSharp建立新的pdf,涉及到修改pdf的很少,這篇博文給了我一些不錯的想法,非常感謝)
相關連結:使用iTextSharp修改PDF檔案(一)
這個iTextSharp確實是個好東西,可以建立、讀取PDF格式的文件,雖然我的需求比較簡單,但我首先還是基本上、完整地看完了它的相關文件,不喜歡英文的同志,可以搜尋一篇《用C#製作PDF檔案全攻略》(苟安廷),這篇文章是苟先生在使用iTextSharp時的一些心得,裡面雖然重點是說明如何建立PDF檔案,對讀取、修改PDF檔案的方法略過不提,因此,對於我的任務來說,並沒有太大的作用,但在這裡,仍然感謝苟先生的無私奉獻。
具體使用iTextSharp的方法,我這裡就不細說了,因為非常簡單,仔細看看它的文件,應該都可以很輕鬆地建立、讀取PDF檔案。我這裡就只說說我在使用過程中碰到的一些問題,讓後來的人少走一些彎路:
1、 PDF檔案從理論上來說,只要建立成功之後,就不能再修改。
因為我需要修改原來的PDF檔案,將它的頁首頁尾去掉,然後換上新的頁首頁尾。所以,我最開始對怎麼只取得原始檔案中的內容區域(是去掉了頁首、頁尾、左邊固定區域、右邊固定區域的一個矩形區域),研究了很久。呼叫了其中的GetImportedPage方法,得到字串,然後通過分析該字串(是極其粗略的分析,因為PDF檔案格式的標誌太多,後面會有相關說明),去掉其中不需要的部分,再將剩下的其它部分進行儲存,生成新的PDF檔案。
理論上這種方法是正確的,也比較符合我們的一般邏輯思維(因為我們對已生成的文件、程式進行修改,大多數情況下都是用類似方法,比如:對某個程式進行解密等等)。我也確實按這種方法得到了符合要求的、新的PDF檔案,但隨即就發現了該方法其實不具備通用性,即對某篇檔案是有效的,但對另一篇檔案卻有可能會造成格式錯位。
因為分析PDF檔案的格式是一件非常麻煩的事情,很多明明應該是在內容區域的位元組,卻顯示在頁首處,如果我再分析到裡面最細小的、每一個標誌位,還不如直接看它的SDK,而且這樣的話,在規定的時間裡,這個程式也將完不成了。
解決辦法:
我先研究了Acrobat裡的crop,它為什麼可以這麼精確的剪裁呢?
結果讓我啞然失笑,原來它的crop也不是真正的剪裁,而只是把需要的剪裁掉的區域遮蔽掉了而已,如果再回到crop裡,進行上、下、左、右的設定,原來看起來好像被剪裁掉的區域仍然會顯示出來,呵呵,有意思。
好的,現在心裡有底了,大概知道怎麼做了,這時再仔細看看iTextSharp的文件,發現有一段話以前沒有注意到:
If you have an existing PDF file that represents a form, you could copy the pages of this form and paint text at precise locations on this form. You can't edit an existing PDF document, by saying: for instance replace the word Louagie by Lowagie. To achieve this, you would have to know the exact location of the word Louagie, paint a white rectangle over it and paint the word Lowagie on this white rectangle. Please avoid this kind of 'patch' work. Do your PDF editing with an Adobe product.
呵呵,跟我想的一樣,就是用新的區域,把需要剪裁的區域給覆蓋掉。
這就容易多了,先用iTextSharp的Template功能,把自己需要的文字、圖片、表格放到Template裡,然後把整個的Template加到合適的位置,即可。
哦,別忘了,得先在Template里加個白色的矩形框,放在最底層。
注:上面提到了PDF檔案的格式,其實PDF檔案的格式非常有趣,是的,非常有趣。相關的資訊,可參考網上的《一個簡單的PDF檔案結構的分析》等文章。否則當你看到<BT>、<ET>、/F1、TF時,你會感覺莫明其妙的。
2、 PDF檔案中的屬性,不是我們一般意義上的檔案的屬性。
這一點開始讓我走了一段彎路,我用iTextSharp中的相關函式,在Document.Opent()之前,設定了相關的屬性,如:subject/author/title等等,但奇怪的是,生成新的PDF檔案中,我用一般的看某一個檔案屬性的方法,卻沒有看到預料中的屬性,都是空的。
後來,經過有經驗的同事提醒,才知道:原來所謂的PDF檔案的屬性,是要在Acrobat Reader的某個選單中才能看到的。
呵呵,以前對Acrobat的應用就基本上只有對檔案進行互相轉換,沒用過其它太多的功能,沒有經驗呀。雖然中間經歷了無數的嘗試、無數的推倒重來。這個小程式後來還是在3天之內完成了,起到了它應有的作用。貼個介面上來: