【Itext】7步制作Itext5页眉页脚pdf实现第几页共几页

itext5页眉页脚工具类,实现page x of y 完美兼容各种格式大小文档A4/B5/B3,兼容各种文档格式自动计算页脚XY轴坐标

 

鉴于没人做的这么细致,自己就写了一个itext5页眉页脚工具类,实现第几页/共几页,方便各位刚进入itext的童鞋调用。2013年9月16日 14:51:01

 

背景:网上流传的都是一些简单的demo,直接扔个A4文档就说实现了,其实很坑的,换个A4横版打印,那些代码就不行了,所以自己搞了这个出来。

 

如果页面看着排版不好,请移步我的百度空间 :http://hi.baidu.com/ae6623/item/08abce3ce29359119dc65ecf

 

工具类PdfReportM1HeaderFooter.java

[java] view plaincopy
 
  1. <span style="font-family:Microsoft YaHei; font-size:12px">/** 
  2.  * Project Name:report 
  3.  * File Name:PdfReportM1HeaderFooter.java 
  4.  * Package Name:com.riambsoft.report.pdf 
  5.  * Date:2013-9-16上午08:59:00 
  6.  * Copyright (c) 2013, riambsoft All Rights Reserved. 
  7.  * 
  8.  */  
  9.     
  10. package com.riambsoft.report.pdf;  
  11.     
  12. import java.io.IOException;  
  13.     
  14. import com.itextpdf.text.Document;  
  15. import com.itextpdf.text.DocumentException;  
  16. import com.itextpdf.text.Element;  
  17. import com.itextpdf.text.Font;  
  18. import com.itextpdf.text.PageSize;  
  19. import com.itextpdf.text.Phrase;  
  20. import com.itextpdf.text.Rectangle;  
  21. import com.itextpdf.text.pdf.BaseFont;  
  22. import com.itextpdf.text.pdf.ColumnText;  
  23. import com.itextpdf.text.pdf.PdfContentByte;  
  24. import com.itextpdf.text.pdf.PdfPageEventHelper;  
  25. import com.itextpdf.text.pdf.PdfTemplate;  
  26. import com.itextpdf.text.pdf.PdfWriter;  
  27.     
  28. /** 
  29.  * ClassName:PdfReportM1HeaderFooter <br/> Function: TODO ADD FUNCTION. <br/> Reason: TODO ADD REASON. <br/> Date: 2013-9-13 上午08:59:00 <br/> 
  30.  * 
  31.  * @author 落雨 
  32.  * @version 394263788(QQ) 
  33.  * @since JDK 1.5 
  34.  * @see http://hi.baidu.com/ae6623 
  35.  */  
  36. public class PdfReportM1HeaderFooter extends PdfPageEventHelper {  
  37.     
  38.     /** 
  39.      * 页眉 
  40.      */  
  41.     public String header = "";  
  42.     
  43.     /** 
  44.      * 文档字体大小,页脚页眉最好和文本大小一致 
  45.      */  
  46.     public int presentFontSize = 12;  
  47.     
  48.     /** 
  49.      * 文档页面大小,最好前面传入,否则默认为A4纸张 
  50.      */  
  51.     public Rectangle pageSize = PageSize.A4;  
  52.     
  53.     // 模板  
  54.     public PdfTemplate total;  
  55.     
  56.     // 基础字体对象  
  57.     public BaseFont bf = null;  
  58.     
  59.     // 利用基础字体生成的字体对象,一般用于生成中文文字  
  60.     public Font fontDetail = null;  
  61.     
  62.     /** 
  63.      * 
  64.      * Creates a new instance of PdfReportM1HeaderFooter 无参构造方法. 
  65.      * 
  66.      */  
  67.     public PdfReportM1HeaderFooter() {  
  68.     
  69.     }  
  70.     
  71.     /** 
  72.      * 
  73.      * Creates a new instance of PdfReportM1HeaderFooter 构造方法. 
  74.      * 
  75.      * @param yeMei 
  76.      *            页眉字符串 
  77.      * @param presentFontSize 
  78.      *            数据体字体大小 
  79.      * @param pageSize 
  80.      *            页面文档大小,A4,A5,A6横转翻转等Rectangle对象 
  81.      */  
  82.     public PdfReportM1HeaderFooter(String yeMei, int presentFontSize, Rectangle pageSize) {  
  83.         this.header = yeMei;  
  84.         this.presentFontSize = presentFontSize;  
  85.         this.pageSize = pageSize;  
  86.     }  
  87.     
  88.     public void setHeader(String header) {  
  89.         this.header = header;  
  90.     }  
  91.     
  92.     public void setPresentFontSize(int presentFontSize) {  
  93.         this.presentFontSize = presentFontSize;  
  94.     }  
  95.     
  96.     /** 
  97.      * 
  98.      * TODO 文档打开时创建模板 
  99.      * 
  100.      * @see com.itextpdf.text.pdf.PdfPageEventHelper#onOpenDocument(com.itextpdf.text.pdf.PdfWriter, com.itextpdf.text.Document) 
  101.      */  
  102.     public void onOpenDocument(PdfWriter writer, Document document) {  
  103.         total = writer.getDirectContent().createTemplate(50, 50);// 共 页 的矩形的长宽高  
  104.     }  
  105.     
  106.     /** 
  107.      * 
  108.      * TODO 关闭每页的时候,写入页眉,写入'第几页共'这几个字。 
  109.      * 
  110.      * @see com.itextpdf.text.pdf.PdfPageEventHelper#onEndPage(com.itextpdf.text.pdf.PdfWriter, com.itextpdf.text.Document) 
  111.      */  
  112.     public void onEndPage(PdfWriter writer, Document document) {  
  113.     
  114.         try {  
  115.             if (bf == null) {  
  116.                 bf = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", false);  
  117.             }  
  118.             if (fontDetail == null) {  
  119.                 fontDetail = new Font(bf, presentFontSize, Font.NORMAL);// 数据体字体  
  120.             }  
  121.         } catch (DocumentException e) {  
  122.             e.printStackTrace();  
  123.         } catch (IOException e) {  
  124.             e.printStackTrace();  
  125.         }  
  126.     
  127.         // 1.写入页眉  
  128.         ColumnText.showTextAligned(writer.getDirectContent(), Element.ALIGN_LEFT, new Phrase(header, fontDetail), document.left(), document.top() + 20, 0);  
  129.            
  130.         // 2.写入前半部分的 第 X页/共  
  131.         int pageS = writer.getPageNumber();  
  132.         String foot1 = "第 " + pageS + " 页 /共";  
  133.         Phrase footer = new Phrase(foot1, fontDetail);  
  134.     
  135.         // 3.计算前半部分的foot1的长度,后面好定位最后一部分的'Y页'这俩字的x轴坐标,字体长度也要计算进去 = len  
  136.         float len = bf.getWidthPoint(foot1, presentFontSize);  
  137.     
  138.         // 4.拿到当前的PdfContentByte  
  139.         PdfContentByte cb = writer.getDirectContent();  
  140.     
  141.         // 5.写入页脚1,x轴就是(右margin+左margin + right() -left()- len)/2.0F 再给偏移20F适合人类视觉感受,否则肉眼看上去就太偏左了 ,y轴就是底边界-20,否则就贴边重叠到数据体里了就不是页脚了;注意Y轴是从下往上累加的,最上方的Top值是大于Bottom好几百开外的。  
  142.         ColumnText.showTextAligned(cb, Element.ALIGN_CENTER, footer, (document.rightMargin() + document.right() + document.leftMargin() - document.left() - len) / 2.0F + 20F, document.bottom() - 20, 0);  
  143.     
  144.         // 6.写入页脚2的模板(就是页脚的Y页这俩字)添加到文档中,计算模板的和Y轴,X=(右边界-左边界 - 前半部分的len值)/2.0F + len , y 轴和之前的保持一致,底边界-20  
  145.         cb.addTemplate(total, (document.rightMargin() + document.right() + document.leftMargin() - document.left()) / 2.0F + 20F, document.bottom() - 20); // 调节模版显示的位置  
  146.     
  147.     }  
  148.     
  149.     /** 
  150.      * 
  151.      * TODO 关闭文档时,替换模板,完成整个页眉页脚组件 
  152.      * 
  153.      * @see com.itextpdf.text.pdf.PdfPageEventHelper#onCloseDocument(com.itextpdf.text.pdf.PdfWriter, com.itextpdf.text.Document) 
  154.      */  
  155.     public void onCloseDocument(PdfWriter writer, Document document) {  
  156.         // 7.最后一步了,就是关闭文档的时候,将模板替换成实际的 Y 值,至此,page x of y 制作完毕,完美兼容各种文档size。  
  157.         total.beginText();  
  158.         total.setFontAndSize(bf, presentFontSize);// 生成的模版的字体、颜色  
  159.         String foot2 = " " + (writer.getPageNumber() - 1) + " 页";  
  160.         total.showText(foot2);// 模版显示的内容  
  161.         total.endText();  
  162.         total.closePath();  
  163.     }  
  164. }</span>  

如何调用?

这样调用即可,下面的代码就是 第几页/共几页的实现方式!推荐大家使用,直接扔到自己的工程,在创建pdf的时候,直接把此event set进去即可。

 

 

[java] view plaincopy
 
  1. <span style="font-family:Microsoft YaHei; font-size:12px">/** 
  2. * Project Name:report 
  3. * File Name:PDFBuilder.java 
  4. * Package Name:com.riambsoft.report.itext 
  5. * Date:2013-9-13下午03:35:53 
  6. * Copyright (c) 2013, riambsoft All Rights Reserved. 
  7. * 
  8. */  
  9.     
  10. package com.riambsoft.report.itext;  
  11.     
  12. import java.io.FileOutputStream;  
  13. import java.io.IOException;  
  14.     
  15. import com.itextpdf.text.Document;  
  16. import com.itextpdf.text.DocumentException;  
  17. import com.itextpdf.text.PageSize;  
  18. import com.itextpdf.text.Rectangle;  
  19. import com.itextpdf.text.pdf.ColumnText;  
  20. import com.itextpdf.text.pdf.PdfContentByte;  
  21. import com.itextpdf.text.pdf.PdfWriter;  
  22. import com.riambsoft.report.pdf.PdfReportM1HeaderFooter;  
  23.     
  24. /** 
  25. * ClassName:PDFBuilder <br/> 
  26. * Function: TODO ADD FUNCTION. <br/> 
  27. * Reason:   TODO ADD REASON. <br/> 
  28. * Date: 2013-9-13 下午03:35:53 <br/> 
  29. * @author Administrator 
  30. * @version 
  31. * @since JDK 1.5 
  32. * @see   
  33. */  
  34. public class PDFBuilder {  
  35. private int pageHeight;  
  36. private int pageWidth;  
  37. private PDFBuilder(){  
  38. }  
  39. public static PDFBuilder getInstance(){  
  40. return new PDFBuilder();  
  41. }  
  42. public void generatePDF()throws Exception {  
  43. Document document = new Document(new Rectangle(pageWidth, pageHeight));  
  44. PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(""));  
  45. this.setFooter(writer);  
  46. writer.setFullCompression();  
  47. writer.setPdfVersion(PdfWriter.VERSION_1_4);  
  48. document.open();  
  49. // Set pdf version to 1.4  
  50. PdfContentByte cb = writer.getDirectContent();  
  51. ColumnText ct=new ColumnText(cb);  
  52. for(int i=0;i<10;i++){  
  53. document.newPage();  
  54. //如果不设置 空白页无法单独显示  
  55. writer.setPageEmpty(false);  
  56. }  
  57. document.close();  
  58. }  
  59.     
  60. private void setFooter(PdfWriter writer) throws DocumentException, IOException {  
  61. //HeaderFooter headerFooter = new HeaderFooter(this);  
  62. //更改事件,瞬间变身 第几页/共几页 模式。  
  63. PdfReportM1HeaderFooter headerFooter = new PdfReportM1HeaderFooter();//就是上面那个类  
  64. writer.setBoxSize("art",PageSize.A4);  
  65. writer.setPageEvent(headerFooter);  
  66. }  
  67. public int getPageHeight() {  
  68. return pageHeight;  
  69. }  
  70. public void setPageHeight(int pageHeight) {  
  71. this.pageHeight = pageHeight;  
  72. }  
  73. public int getPageWidth() {  
  74. return pageWidth;  
  75. }  
  76. public void setPageWidth(int pageWidth) {  
  77. this.pageWidth = pageWidth;  
  78. }  
  79. public static void main(String[] args) throws Exception {  
  80. PDFBuilder builder=new PDFBuilder();  
  81. builder.setPageHeight(400);  
  82. builder.setPageWidth(600);  
  83. builder.generatePDF();  
  84. }  
  85. }</span>  

 

核心算法:就是计算文档的长宽,算出中点,记得中文字体是需要占用宽度的,所以也要计算进去,其次没什么重点,研究一下中点的计算吧,初中知识。

paga x 这种好做,page x of y 按照官方 itext in action 2这本书上面说的那种办法,无法准确计算各种文档的x轴和y轴坐标。

 

我按照书上所写的实现方式如下,不推荐使用,因为只适合于A4纸张。

PdfReportM1HeaderFooter2.java

 

[java] view plaincopy
 
  1. <span style="font-family:Microsoft YaHei; font-size:12px">/** 
  2. * Project Name:report 
  3. * File Name:PdfReportM1HeaderFooter.java 
  4. * Package Name:com.riambsoft.report.pdf 
  5. * Date:2013-9-13上午08:59:00 
  6. * Copyright (c) 2013, riambsoft All Rights Reserved. 
  7. * 
  8. */  
  9.   
  10. package com.riambsoft.report.pdf;  
  11.   
  12. import java.io.IOException;  
  13.   
  14. import com.itextpdf.text.Document;  
  15. import com.itextpdf.text.DocumentException;  
  16. import com.itextpdf.text.Element;  
  17. import com.itextpdf.text.ExceptionConverter;  
  18. import com.itextpdf.text.Font;  
  19. import com.itextpdf.text.Image;  
  20. import com.itextpdf.text.Phrase;  
  21. import com.itextpdf.text.Rectangle;  
  22. import com.itextpdf.text.pdf.BaseFont;  
  23. import com.itextpdf.text.pdf.ColumnText;  
  24. import com.itextpdf.text.pdf.PdfPCell;  
  25. import com.itextpdf.text.pdf.PdfPTable;  
  26. import com.itextpdf.text.pdf.PdfPageEventHelper;  
  27. import com.itextpdf.text.pdf.PdfTemplate;  
  28. import com.itextpdf.text.pdf.PdfWriter;  
  29.   
  30. /** 
  31. * ClassName:PdfReportM1HeaderFooter2 <br/> Function: TODO ADD FUNCTION. <br/> Reason: TODO ADD REASON. <br/> Date: 2013-9-13 上午08:59:00 <br/> 
  32. *  
  33. * @author Administrator 
  34. * @version  
  35. * @since JDK 1.5 
  36. * @see  
  37. */  
  38. public class PdfReportM1HeaderFooter2 extends PdfPageEventHelper {  
  39.   
  40. String header;  
  41. int presentFontSize = 12;  
  42. PdfTemplate total;  
  43. BaseFont bf = null;  
  44. Font fontDetail = null;  
  45.   
  46. public void setHeader(String header) {  
  47. this.header = header;  
  48. }  
  49.   
  50. public void onOpenDocument(PdfWriter writer, Document document) {  
  51. total = writer.getDirectContent().createTemplate(30, 16);  
  52. }  
  53.   
  54. public void onEndPage(PdfWriter writer, Document document) {  
  55.   
  56. Rectangle pageSize = writer.getBoxSize("art");  
  57.   
  58. try {  
  59. if (bf == null) {  
  60. bf = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", false);  
  61. }  
  62. if (fontDetail == null) {  
  63. fontDetail = new Font(bf, presentFontSize, Font.NORMAL);// 数据体字体  
  64. }  
  65. } catch (DocumentException e) {  
  66. e.printStackTrace();  
  67. } catch (IOException e) {  
  68. e.printStackTrace();  
  69. }  
  70. int pageN = writer.getPageNumber();  
  71. String text = "第 " + pageN + "页/共 ";  
  72.   
  73. // 页眉  
  74. ColumnText.showTextAligned(writer.getDirectContent(), Element.ALIGN_LEFT, new Phrase("我是页眉,土豪我们做朋友吧",fontDetail), document.left(), document.top() + 20, 0);  
  75.   
  76. PdfPTable table = new PdfPTable(2);  
  77.   
  78. try {  
  79. table.setWidths(new int[] { 1, 1 });  
  80. table.setWidthPercentage(100F);// 占据百分百宽度  
  81. table.setTotalWidth(pageSize.getRight() - pageSize.getLeft() - 100);  
  82.   
  83. PdfPCell cell1 = new PdfPCell(new Phrase(text, fontDetail));  
  84. PdfPCell cell2 = new PdfPCell(Image.getInstance(total));  
  85.   
  86. cell1.setHorizontalAlignment(Element.ALIGN_RIGHT);  
  87. cell1.setBorder(Rectangle.NO_BORDER);  
  88. cell2.setHorizontalAlignment(Element.ALIGN_LEFT);  
  89. cell2.setBorder(Rectangle.NO_BORDER);  
  90.   
  91. table.addCell(cell1);  
  92. table.addCell(cell2);  
  93. table.writeSelectedRows(0, -1, document.left(), document.bottom(), writer.getDirectContent());  
  94. } catch (DocumentException de) {  
  95. throw new ExceptionConverter(de);  
  96. }  
  97.   
  98. }  
  99.   
  100. public void onCloseDocument(PdfWriter writer, Document document) {  
  101.   
  102. try {  
  103. if (bf == null) {  
  104. bf = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", false);  
  105. }  
  106. if (fontDetail == null) {  
  107. fontDetail = new Font(bf, presentFontSize, Font.NORMAL);// 数据体字体  
  108. }  
  109. } catch (DocumentException e) {  
  110. e.printStackTrace();  
  111. } catch (IOException e) {  
  112. e.printStackTrace();  
  113. }  
  114.   
  115. ColumnText.showTextAligned(total, Element.ALIGN_LEFT, new Phrase(String.format("%d页", writer.getPageNumber() - 1), fontDetail), 2, 2, 0);  
  116. }  
  117. }</span>  

 

 

这种只能自己去计算Y轴坐标,很容易不在一行。所以不如我的第一种方便。具体就看你使用了。

posted @ 2015-10-29 17:31  疯子110  阅读(930)  评论(0)    收藏  举报