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