iText in Action 2nd5.4节(Adding page events to PdfWriter)读书笔记
前言
在上一節我們討論了幾種不同頁邊界的類型后這一節我們繼續回到IPdfPageEvent接口中,現在這個接口還剩下以下4個關于文檔和頁面的方法沒有說明:
- OnOpenDocument----當文檔被帶打開的時候調用,一般在這個方法中初始化一些需要在整個文檔中使用的資源。
- OnStartPage----當一個新的頁面開啟時調用,一般使用這個方法初始化一些頁面需要的參數,最后要注意不要在這個方法中往文檔中添加內容。
- OnEndPage----在開啟新的一頁之前或者文檔關閉之前調用,這是為文檔添加頁眉頁腳和水印的最佳地方。
- OnCloseDocument----在文檔關閉之前調用,一般清理一些資源。
現在我們將使用這些方法解決一些經常提到的需求,比如在創建文檔的過程中為每一頁添加頁眉。
Adding a header and a footer
現在我們回到第二節中Chapter和Section對象的列子中,我們會進行兩個小的修改:定義一個art box并為PdfWriter添加頁面事件,具體到代碼中就是HeaderFooter實例,我們可以通過此實例為文檔添加頁眉和頁腳,就如下圖所示:
在上圖中,我們在每個Chapter開始的時候將此Chapter的頁碼順序加入到頁腳中,而且是居中格式顯示。對于頁眉則交替顯示文本"Movie history"(居右顯示)和Chapter的標題(居左顯示),下面就是具體的代碼:
listing 5.19 MovieHistory2.cs
class HeaderFooter : IPdfPageEvent { /** Alternating phrase for the header. */ Phrase[] header = new Phrase[2]; /** Current page number (will be reset for every chapter). */ int pagenumber;/// <summary> /// Initialize one of the headers, based on the chapter title; /// reset the page number. /// </summary> /// <param name="writer"></param> /// <param name="document"></param> /// <param name="paragraphPosition"></param> /// <param name="title"></param> public void OnChapter(PdfWriter writer, Document document, float paragraphPosition, Paragraph title) {header[1] = new Phrase(title.Content);pagenumber = 1; }/// <summary> /// Adds the header and the footer. /// </summary> /// <param name="writer"></param> /// <param name="document"></param> public void OnEndPage(PdfWriter writer, Document document) {Rectangle rect = writer.GetBoxSize("art");switch (writer.PageNumber % 2){case 0:ColumnText.ShowTextAligned(writer.DirectContent, Element.ALIGN_RIGHT, header[0], rect.Right, rect.Top, 0);break;case 1:ColumnText.ShowTextAligned(writer.DirectContent, Element.ALIGN_LEFT, header[1], rect.Left, rect.Top, 0);break;}ColumnText.ShowTextAligned(writer.DirectContent, Element.ALIGN_CENTER, new Phrase(string.Format("page {0}", pagenumber)),(rect.Left + rect.Right) / 2, rect.Bottom - 18, 0); }/// <summary> /// Initialize one of the headers. /// </summary> /// <param name="writer"></param> /// <param name="document"></param> public void OnOpenDocument(PdfWriter writer, Document document) {header[0] = new Phrase("Movie history"); }/// <summary> /// Increase the page number. /// </summary> /// <param name="writer"></param> /// <param name="document"></param> public void OnStartPage(PdfWriter writer, Document document) {pagenumber++; } }以上的代碼比較好懂,我們在類中定義了兩個變量:
- header----一個包含了兩個Pharse對象的數組,一個在OnOpenDocument方法中初始化,這樣就可以在整個文檔操作過程中使用。一個定義在OnChapter方法中
- pagenumber----一個定義的頁碼數,每次創建一個Chapter對象時重置為1。
在一頁完成之前沒有內容通過頁面事件添加到文檔中,我們添加的頁眉和頁腳都是在OnEndPage方法實現的。這里我們要注意的是通過GetBoxSize方法獲取art box,然后使用此crop box來定位頁眉和頁腳,但我們首先要定義crop box,要不然就會返回null值。在接下來的列子中我們會將頁碼加到頁眉中并顯示總的頁碼數。
Solving the “page X of Y” problem
下圖就是"page X of Y"的一個具體實例:
獲取X的值比較容易,我們可以在OnEndPage方法中獲取PdfWriter對象,然后調用其PageNumber即可,但是我們如何獲取Y的值呢?在文檔還沒有構建好的情況下我們是不知道總的頁碼數,只有在寫完最好一頁的情況下才可以計算出來。這個問題有兩個解決方案,其中一個就是通過兩次構建pdf的過程來完成,這個方法在后續章節中會說明,還有一個就是通過PdfTemplate對象和Page Event完成。
在第三節學習XObject的時候我們知道除非顯示的調用ReleaseTemplate方法,否則iText會將此對象一直保存在內存中直到文檔關閉。利用這個特性我們可以在每一個頁中添加PdfTemplate,然后等待文檔的關閉,之后再將頁面的總數添加到PdfTemplate中,這樣即使第一頁的內容已經寫入到輸出流PdfTemplate中的數據還是會顯示在第一頁中。
listing 5.20 MovieCountries1.cs
public class TableHeader : IPdfPageEvent {/** The header text. */string header;public string Header{get { return header; }set { header = value; }}/** The template with the total number of pages. */PdfTemplate total;public TableHeader(){}public TableHeader(string header){this.header = header;}/// <summary>/// Fills out the total number of pages before the document is closed./// </summary>/// <param name="writer"></param>/// <param name="document"></param>public void OnCloseDocument(PdfWriter writer, Document document){ColumnText.ShowTextAligned(total, Element.ALIGN_LEFT, new Phrase((writer.PageNumber - 1).ToString()), 2, 2, 0);}/// <summary>/// Adds a header to every page/// </summary>/// <param name="writer"></param>/// <param name="document"></param>public void OnEndPage(PdfWriter writer, Document document){PdfPTable table = new PdfPTable(3);try{table.SetWidths(new int[] { 24, 24, 2 });table.TotalWidth = 527;table.LockedWidth = true;table.DefaultCell.FixedHeight = 20;table.DefaultCell.Border = Rectangle.BOTTOM_BORDER;table.AddCell(header);table.DefaultCell.HorizontalAlignment = Element.ALIGN_RIGHT;table.AddCell(string.Format("Page {0} of", writer.PageNumber));PdfPCell cell = new PdfPCell(Image.GetInstance(total));cell.Border = Rectangle.BOTTOM_BORDER;table.AddCell(cell);table.WriteSelectedRows(0, -1, 34, 803, writer.DirectContent);}catch (DocumentException){throw;}}/// <summary>/// Creates the PdfTemplate that will hold the total number of pages./// </summary>/// <param name="writer"></param>/// <param name="document"></param>public void OnOpenDocument(PdfWriter writer, Document document){total = writer.DirectContent.CreateTemplate(30, 16);} }在以上代碼中:我們先在OnOpenDocument方法中定義一個PdfTemplate并設置大小為30pt*16pt,然后在OnEndPage方法中我們構建一個表格來畫頁眉,此表格為1行三列。第一個單元格添加的內容為country,第二個單元格添加的內容為"page X of",第三個單元格就比較特殊:我們將PdfTemplate包含在Image中,但這個時候還沒有數據添加到PdfTemplate中。最后在OnCloseDocument中往PdfTemplate寫入中的頁碼數,這樣所有的頁眉都引用了PdfTemplate,總的頁碼數也隨之顯示出來。這樣還要注意的是當文檔被關閉之前,當前頁會調用NewPage方法進行一些資源釋放的操作,但NewPage方法會將頁碼增加,所以我們需要減去1獲取真正的頁碼數。在前面的列子我們一般通過ShowTextAligned方法往頁眉和頁腳寫數據,但在這里我們可以通過表格的WriteSelectedRows方法在頁眉中添加內容,這是比較好的一個方法,因此通過表格的架構我們可以對線,圖和文本進行一些設置。在創建文檔的過程中還有一個通常的需求就是添加水印。
Add a watermark
接下來的列子是對前一個列子的擴展,主要的區別就是新加了一個功能:水印。具體的效果圖見下:
由于是對前面的擴展,代碼基本上差不多,只是添加了一個Watermark類來添加水印。
listing 5.21 MovieCountries2.cs
class Watermark : IPdfPageEvent {Font FONT = new Font(Font.FontFamily.HELVETICA, 52, Font.BOLD, new GrayColor(0.75f));public void OnEndPage(PdfWriter writer, Document document){ColumnText.ShowTextAligned(writer.DirectContentUnder, Element.ALIGN_CENTER, new Phrase("FOOBAR FILM FESTIVAL", FONT),297.5f, 421, writer.PageNumber % 2 == 1 ? 45 : -45);} }以上代碼中水印是以文本的形式添加的,如果我們的水印是圖片則可以有多種選擇:通過PdfContentByte.AddImage方法或者將其包裹在ColumnText對象抑或將其放入到表格的單元格中。當我們將頁面事件中處理圖片時要確認圖片只創建了一次,比如在OnOpenDocument方法中創建,如果我們在OnStartPage或者OnEndPage方法中創建則可能將同樣的圖片添加多次,這不僅會損壞性能而且增加了文檔的大小。
接下來我們會介紹一個功能:文檔的每一頁自動呈現出來,就如同PPT一樣。
Creating a slideshow
在我們讀文檔的時候我們一般按某個按鈕,點擊鼠標或者直接滾動到下一頁,不過我們可以讓PDF閱覽器在幾秒鐘之后自動過度到下一頁。下面這個列子中我們設置了”Full Screen"(全屏)模式,因為我們將PDF文檔當作PPT來使用。
listing 5.22 MovieSlideShow.cs
class TransitionDuration:IPdfPageEvent {public void OnStartPage(PdfWriter writer, Document document){writer.Transition = new PdfTransition(PdfTransition.DISSOLVE, 3);writer.Duration = 5;} } PdfWriter writer = PdfWriter.GetInstance(document, new FileStream(fileName, FileMode.Create)); writer.PdfVersion = PdfWriter.VERSION_1_5; writer.ViewerPreferences = PdfWriter.PageModeFullScreen; writer.PageEvent = new TransitionDuration(); 在OnStartPage方法中我們設置了Duration和Transition屬性,Duration每一個頁面呈現的時間,單位以秒計算。Transition接受一個Transition對象,其構造器有兩個參數:一個為類型,一個transition的持續時間,這個時間是頁面過度效果的時間和頁面呈現的時間不同。iText中有很多Transition類型,具體的大家可以看源代碼,每個類型的具體介紹大家就直接看書吧,我這里就不詳述了。總結
在這一節中我們通過IPdfPageEvent的4個方法學習如何添加頁面頁腳和水印,并介紹解決"Page X of Y"問題的方法,到這里整個的第一章就結束了,還有就是這一節的代碼下載。
這里我們對整個的第一章總結一下:在第一節我們介紹了基本構建塊的使用其中包括:Chunk,Phrase,Paragraphs,List,ListItem,Anchors,Image,Chapter和Section對象,整個第四節中我們介紹了PdfPTable和PdfPCell類。然后在第三節中我們學會了如何使用low-level的方法添加內容(線,圖形,圖和文本),并學習此節中兩個很重要的類:ColumnText和XObject。最后在第五節中我們通過表格事件,單元格事件和頁面事件來處理一些比較常見的需求。通過以上五節的學習大家可以從頭開始用iText構建pdf文檔,后續的章節中我們會學習如何操作已經存在的文檔:如何將一個pdf文檔中的頁面導入到另一個文檔中,如何為已經存在的文檔添加一些內容,如何將不同的文檔組合成一個更大的文檔等等。
轉載于:https://www.cnblogs.com/julyluo/archive/2012/07/20/2601641.html
總結
以上是生活随笔為你收集整理的iText in Action 2nd5.4节(Adding page events to PdfWriter)读书笔记的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ACM博弈总结
- 下一篇: dreamweaver翻译器没有被装载由