iText in Action 2nd5.4节(Adding page events to PdfWriter)读书笔记
前言
在上一節(jié)我們討論了幾種不同頁邊界的類型后這一節(jié)我們繼續(xù)回到IPdfPageEvent接口中,現(xiàn)在這個接口還剩下以下4個關(guān)于文檔和頁面的方法沒有說明:
- OnOpenDocument----當(dāng)文檔被帶打開的時候調(diào)用,一般在這個方法中初始化一些需要在整個文檔中使用的資源。
- OnStartPage----當(dāng)一個新的頁面開啟時調(diào)用,一般使用這個方法初始化一些頁面需要的參數(shù),最后要注意不要在這個方法中往文檔中添加內(nèi)容。
- OnEndPage----在開啟新的一頁之前或者文檔關(guān)閉之前調(diào)用,這是為文檔添加頁眉頁腳和水印的最佳地方。
- OnCloseDocument----在文檔關(guān)閉之前調(diào)用,一般清理一些資源。
現(xiàn)在我們將使用這些方法解決一些經(jīng)常提到的需求,比如在創(chuàng)建文檔的過程中為每一頁添加頁眉。
Adding a header and a footer
現(xiàn)在我們回到第二節(jié)中Chapter和Section對象的列子中,我們會進行兩個小的修改:定義一個art box并為PdfWriter添加頁面事件,具體到代碼中就是HeaderFooter實例,我們可以通過此實例為文檔添加頁眉和頁腳,就如下圖所示:
在上圖中,我們在每個Chapter開始的時候?qū)⒋薈hapter的頁碼順序加入到頁腳中,而且是居中格式顯示。對于頁眉則交替顯示文本"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對象的數(shù)組,一個在OnOpenDocument方法中初始化,這樣就可以在整個文檔操作過程中使用。一個定義在OnChapter方法中
- pagenumber----一個定義的頁碼數(shù),每次創(chuàng)建一個Chapter對象時重置為1。
在一頁完成之前沒有內(nèi)容通過頁面事件添加到文檔中,我們添加的頁眉和頁腳都是在OnEndPage方法實現(xiàn)的。這里我們要注意的是通過GetBoxSize方法獲取art box,然后使用此crop box來定位頁眉和頁腳,但我們首先要定義crop box,要不然就會返回null值。在接下來的列子中我們會將頁碼加到頁眉中并顯示總的頁碼數(shù)。
Solving the “page X of Y” problem
下圖就是"page X of Y"的一個具體實例:
獲取X的值比較容易,我們可以在OnEndPage方法中獲取PdfWriter對象,然后調(diào)用其PageNumber即可,但是我們?nèi)绾潍@取Y的值呢?在文檔還沒有構(gòu)建好的情況下我們是不知道總的頁碼數(shù),只有在寫完最好一頁的情況下才可以計算出來。這個問題有兩個解決方案,其中一個就是通過兩次構(gòu)建pdf的過程來完成,這個方法在后續(xù)章節(jié)中會說明,還有一個就是通過PdfTemplate對象和Page Event完成。
在第三節(jié)學(xué)習(xí)XObject的時候我們知道除非顯示的調(diào)用ReleaseTemplate方法,否則iText會將此對象一直保存在內(nèi)存中直到文檔關(guān)閉。利用這個特性我們可以在每一個頁中添加PdfTemplate,然后等待文檔的關(guān)閉,之后再將頁面的總數(shù)添加到PdfTemplate中,這樣即使第一頁的內(nèi)容已經(jīng)寫入到輸出流PdfTemplate中的數(shù)據(jù)還是會顯示在第一頁中。
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并設(shè)置大小為30pt*16pt,然后在OnEndPage方法中我們構(gòu)建一個表格來畫頁眉,此表格為1行三列。第一個單元格添加的內(nèi)容為country,第二個單元格添加的內(nèi)容為"page X of",第三個單元格就比較特殊:我們將PdfTemplate包含在Image中,但這個時候還沒有數(shù)據(jù)添加到PdfTemplate中。最后在OnCloseDocument中往PdfTemplate寫入中的頁碼數(shù),這樣所有的頁眉都引用了PdfTemplate,總的頁碼數(shù)也隨之顯示出來。這樣還要注意的是當(dāng)文檔被關(guān)閉之前,當(dāng)前頁會調(diào)用NewPage方法進行一些資源釋放的操作,但NewPage方法會將頁碼增加,所以我們需要減去1獲取真正的頁碼數(shù)。在前面的列子我們一般通過ShowTextAligned方法往頁眉和頁腳寫數(shù)據(jù),但在這里我們可以通過表格的WriteSelectedRows方法在頁眉中添加內(nèi)容,這是比較好的一個方法,因此通過表格的架構(gòu)我們可以對線,圖和文本進行一些設(shè)置。在創(chuàng)建文檔的過程中還有一個通常的需求就是添加水印。
Add a watermark
接下來的列子是對前一個列子的擴展,主要的區(qū)別就是新加了一個功能:水印。具體的效果圖見下:
由于是對前面的擴展,代碼基本上差不多,只是添加了一個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對象抑或?qū)⑵浞湃氲奖砀竦膯卧裰小.?dāng)我們將頁面事件中處理圖片時要確認圖片只創(chuàng)建了一次,比如在OnOpenDocument方法中創(chuàng)建,如果我們在OnStartPage或者OnEndPage方法中創(chuàng)建則可能將同樣的圖片添加多次,這不僅會損壞性能而且增加了文檔的大小。
接下來我們會介紹一個功能:文檔的每一頁自動呈現(xiàn)出來,就如同PPT一樣。
Creating a slideshow
在我們讀文檔的時候我們一般按某個按鈕,點擊鼠標或者直接滾動到下一頁,不過我們可以讓PDF閱覽器在幾秒鐘之后自動過度到下一頁。下面這個列子中我們設(shè)置了”Full Screen"(全屏)模式,因為我們將PDF文檔當(dāng)作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方法中我們設(shè)置了Duration和Transition屬性,Duration每一個頁面呈現(xiàn)的時間,單位以秒計算。Transition接受一個Transition對象,其構(gòu)造器有兩個參數(shù):一個為類型,一個transition的持續(xù)時間,這個時間是頁面過度效果的時間和頁面呈現(xiàn)的時間不同。iText中有很多Transition類型,具體的大家可以看源代碼,每個類型的具體介紹大家就直接看書吧,我這里就不詳述了。總結(jié)
在這一節(jié)中我們通過IPdfPageEvent的4個方法學(xué)習(xí)如何添加頁面頁腳和水印,并介紹解決"Page X of Y"問題的方法,到這里整個的第一章就結(jié)束了,還有就是這一節(jié)的代碼下載。
這里我們對整個的第一章總結(jié)一下:在第一節(jié)我們介紹了基本構(gòu)建塊的使用其中包括:Chunk,Phrase,Paragraphs,List,ListItem,Anchors,Image,Chapter和Section對象,整個第四節(jié)中我們介紹了PdfPTable和PdfPCell類。然后在第三節(jié)中我們學(xué)會了如何使用low-level的方法添加內(nèi)容(線,圖形,圖和文本),并學(xué)習(xí)此節(jié)中兩個很重要的類:ColumnText和XObject。最后在第五節(jié)中我們通過表格事件,單元格事件和頁面事件來處理一些比較常見的需求。通過以上五節(jié)的學(xué)習(xí)大家可以從頭開始用iText構(gòu)建pdf文檔,后續(xù)的章節(jié)中我們會學(xué)習(xí)如何操作已經(jīng)存在的文檔:如何將一個pdf文檔中的頁面導(dǎo)入到另一個文檔中,如何為已經(jīng)存在的文檔添加一些內(nèi)容,如何將不同的文檔組合成一個更大的文檔等等。
轉(zhuǎn)載于:https://www.cnblogs.com/julyluo/archive/2012/07/20/2601641.html
總結(jié)
以上是生活随笔為你收集整理的iText in Action 2nd5.4节(Adding page events to PdfWriter)读书笔记的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ACM博弈总结
- 下一篇: dreamweaver翻译器没有被装载由