利用iText写PDF开始使用iText写PDF文件,从网上搜索到一些信息,但都是零碎的一些,现在稍微整理一下,仅限于写pdf文件部分。
首先创建一个pdfWriter的模板
1
. /*
2. * Created on 2005-7-1
3. *
4. * TODO To change the template for this generated file go to
5. * Window - Preferences - java - Code Style - Code Templates
6. */
7. package javax.print.PDF;
8.
9. import java.io.FileNotFoundException;
10. import java.io.FileOutputStream;
11. import java.io.IOException;
12.
13. import com.lowagie.text.Cell;
14. import com.lowagie.text.Document;
15. import com.lowagie.text.DocumentException;
16. import com.lowagie.text.Paragraph;
17. import com.lowagie.text.Rectangle;
18. import com.lowagie.text.Table;
19. import com.lowagie.text.pdf.PdfWriter;
20.
21. /**
22. * @author jcoder
23. *
24. * TODO To change the template for this generated type comment go to Window -
25. * Preferences - java - Code Style - Code Templates
26. */
27. abstract public class PDFWriter {
28. protected Document document = null;
29. protected FileOutputStream out = null;
30. protected Rectangle pageSize = null;
31. protected String filePath = null;
32. protected Cell cell = null;
33. protected Paragraph header = null;
34. protected Paragraph prg = null;
35. protected Table table = null;
36.
37. public PDFWriter(String filePath) {
38. try {
39. this.filePath = filePath;
40. document = new Document();
41. out = new FileOutputStream(filePath);
42. PdfWriter.getInstance(document, out);
43. document.open();
44. } catch (FileNotFoundException e) {
45. // TODO Auto-generated catch block
46. e.printStackTrace();
47. } catch (DocumentException e) {
48. // TODO Auto-generated catch block
49. e.printStackTrace();
50. }
51.
52. }
53.
54. public void close() {
55. try {
56. document.close();
57. out.close();
58. } catch (IOException e) {
59. // TODO Auto-generated catch block
60. e.printStackTrace();
61. }
62. }
63.
64. }
由于我需要在pdf中创建表格,要使用到com.lowagie.text.Cell,com.lowagie.text.Paragraph, com.lowagie.text.Table,com.lowagie.text.Cell,
com.lowagie.text.Chunk,com.lowagie.text.Font等类,cell为表格中的每个单元格的内容, paragraph为段落内容,cell的构造函数有很多,这里不一一列举了,因为我要用到中文字符,所以特别使用了cell(Element e)这个构造函数,Element为一个接口,实现此接口的类有很多,包含chunk,meta等,表明cell里可以添加很多不同的内容,可以实现自己的定制, chunk的构造函数为Chunk(String content,Font f),在这里我定制了自己的cell,代码如下:
1.
/*
2. * Created on 2005-7-1
3. *
4. * TODO To change the template for this generated file go to
5. * Window - Preferences - java - Code Style - Code Templates
6. */
7. package javax.print.PDF;
8.
9. import com.lowagie.text.BadElementException;
10. import com.lowagie.text.Cell;
11. import com.lowagie.text.Chunk;
12. import com.lowagie.text.Font;
13.
14. /**
15. * @author jcoder
16. *
17. * TODO To change the template for this generated type comment go to Window -
18. * Preferences - java - Code Style - Code Templates
19. */
20. public class PDFCell extends Cell {
21.
22. public PDFCell(String content, int rowspan, int colspan)
23. throws BadElementException {
24. super(new Chunk(content, PDFChineseFont
25. .createChineseFont(10, Font.NORMAL)));
26. setRowspan(rowspan);
27. setColspan(colspan);
28. setHeader(false);
29. }
30. }
稍许解释一下,rowspan和colspan为Cell的两个属性,写过网页的朋友都知道,表格中的行和列有的时候有必要进行合并,这里就实现了这个功能。
Paragraph类我也进行了封装:
1. /*
2. * Created on 2005-7-5
3. *
4. * TODO To change the template for this generated file go to
5. * Window - Preferences - java - Code Style - Code Templates
6. */
7. package javax.print.PDF;
8.
9. import com.lowagie.text.Element;
10. import com.lowagie.text.Font;
11. import com.lowagie.text.Paragraph;
12.
13. /**
14. * @author Administrator
15. *
16. * TODO To change the template for this generated type comment go to Window -
17. * Preferences - java - Code Style - Code Templates
18. */
19. public class PDFParagragh extends Paragraph {
20.
21. public PDFParagragh(String content, int alignment, int fontSize) {
22. super(content, PDFChineseFont.createChineseFont(fontSize, Font.NORMAL));
23. setAlignment(alignment);
24. }
25.
26. public static final int CENTER = Element.ALIGN_CENTER;
27. public static final int LEFT = Element.ALIGN_LEFT;
28. public static final int RIGHT = Element.ALIGN_RIGHT;
29. public static final int TOP = Element.ALIGN_TOP;
30. public static final int MIDDLE = Element.ALIGN_MIDDLE;
31. public static final int BOTTOM = Element.ALIGN_BOTTOM;
32.
33. }
从以上两个代码段中可以看到PDFChineseFont.createChineseFont(int fontSize,int fontStyle)函数 这个也进行了封装,为自定义函数:
1. /*
2. * Created on 2005-7-1
3. *
4. * TODO To change the template for this generated file go to
5. * Window - Preferences - java - Code Style - Code Templates
6. */
7. package javax.print.PDF;
8.
9. import java.io.IOException;
10.
11. import com.lowagie.text.DocumentException;
12. import com.lowagie.text.Font;
13. import com.lowagie.text.pdf.BaseFont;
14.
15. /**
16. * @author jcoder
17. *
18. * TODO To change the template for this generated type comment go to Window -
19. * Preferences - java - Code Style - Code Templates
20. */
21. public class PDFChineseFont {
22. private static Font chineseFont;
23.
24. public final static Font createChineseFont(int size, int style) {
25. try {
26. chineseFont = new Font(BaseFont.createFont("STSong-Light",
27. "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED), size, style);
28. } catch (DocumentException e) {
29. // TODO Auto-generated catch block
30. e.printStackTrace();
31. } catch (IOException e) {
32. // TODO Auto-generated catch block
33. e.printStackTrace();
34. }
35. return chineseFont;
36. }
37. }
如果无此函数定义,生成的pdf文件中的中文字符将不显示。
最后实现自己定制好的pdf文档格式
1. /*
2. * Created on 2005-7-1
3. *
4. * TODO To change the template for this generated file go to
5. * Window - Preferences - java - Code Style - Code Templates
6. */
7. package javax.print.PDF;
8.
9. import com.lowagie.text.BadElementException;
10. import com.lowagie.text.DocumentException;
11. import com.lowagie.text.Table;
12.
13. /**
14. * @author jcoder
15. *
16. * TODO To change the template for this generated type comment go to Window -
17. * Preferences - java - Code Style - Code Templates
18. */
19. public class MyWriter extends PDFWriter {
20. public MyWriter(String path) {
21. super(path);
22. try {
23. header = new PDFParagraph("仪器设备调拨单");
24. document.add(header);
25. table = new Table(14);
26. table.setBorderWidth(0);
27. table.addCell(new PDFCell("(单价:500元以上含500元)", 1, 5));
28. table.addCell(new PDFCell("2005年7月1号", 1, 9));
29. document.add(table);
30. table = new Table(14);
31. table.setBorderWidth(1);
32. table.addCell(new PDFCell("设备编号", 1, 2));
33. table.addCell(new PDFCell("设备名称", 1, 3));
34. table.addCell(new PDFCell("型号规格", 1, 2));
35. table.addCell(new PDFCell("数量", 1, 1));
36. table.addCell(new PDFCell("单价", 1, 1));
37. table.addCell(new PDFCell("总价", 1, 1));
38. table.addCell(new PDFCell("附件", 1, 2));
39. table.addCell(new PDFCell("备注", 1, 2));
40. table.endHeaders();//换行
41. table.addCell(new PDFCell("0126242245", 1, 2));
42. table.addCell(new PDFCell("IBM大型机", 1, 3));
43. table.addCell(new PDFCell("5465-445GH", 1, 2));
44. table.addCell(new PDFCell("3", 1, 1));
45. table.addCell(new PDFCell("299,000", 1, 1));
46. table.addCell(new PDFCell("2,230,200", 1, 1));
47. table.addCell(new PDFCell("无", 1, 2));
48. table.addCell(new PDFCell("软件学院买入", 1, 2));
49. table.endHeaders();
50. table.addCell(new PDFCell("调出单位意见:", 1, 11));
51. table.addCell(new PDFCell("院(系)签章", 1, 3));
52. table.endHeaders();
53. table.addCell(new PDFCell("申请调入单位意见:", 1, 11));
54. table.addCell(new PDFCell("院(系)签章", 1, 3));
55. table.endHeaders();
56. table.addCell(new PDFCell("设备管理科审批:", 1, 5));
57. table.addCell(new PDFCell("实验室与设备管理处审批", 1, 4));
58. table.addCell(new PDFCell("校部审批:", 1, 5));
59. table.endHeaders();
60. document.add(table);
61. close();//别忘记关闭
62. } catch (BadElementException e) {
63. // TODO Auto-generated catch block
64. e.printStackTrace();
65. } catch (DocumentException e) {
66. // TODO Auto-generated catch block
67. e.printStackTrace();
68. }
69. }
70. }
1. /*
2. * Created on 2005-7-1
3. *
4. * TODO To change the template for this generated file go to
5. * Window - Preferences - java - Code Style - Code Templates
6. */
7. package javax.print.PDF;
8.
9. /**
10. * @author jcoder
11. *
12. * TODO To change the template for this generated type comment go to Window -
13. * Preferences - java - Code Style - Code Templates
14. */
15. public class Test {
16.
17. public static void main(String[] args) {
18. PDFWriter pdf = new MyWriter("mine.pdf");
19. }
20. }
一个表格是包含单元格排列成矩阵的矩形区域。表格的距阵并不要求是m×n的,它可以有空洞或者单元格比单个的要大。
创建一个表格最通用的办法是预先知道有几行几列:
public Table(intcolumns, int rows);
在示例代码0501中,我们构建了一个简单的表:
Table aTable =new Table(2,2);
aTable.addCell("0.0");
aTable.addCell("0.1");
aTable.addCell("1.0");
aTable.addCell("1.1");
该表格有两行两列,单元格被自动添加,从第一行第一列开始,然后是第二列,当一行满后,下一单元格自动添加到下一行的第一列中。
也可以将单元格添加到表中指定的位置,如示例代码0502,别了要添加System.Drawing.dll引用,以获得Point对象,我们创建了一个4行4列的表格然后添加一些单元格到随机的位置上:
Table aTable =new Table(4,4);
aTable.AutoFillEmptyCells = true;
aTable.addCell("2.2", new Point(2,2));
aTable.addCell("3.3", new Point(3,3));
aTable.addCell("2.1", new Point(2,1));
aTable.addCell("1.3", new Point(1,3));
你可以看到我们将AutoFillEmptyCells属性设置为true,这将自动、默认的单元格布局填充空的单元格,如果我们忘记了这样做(就象本例中第二个表格),将没有额外的单元格添加,不包含任何单格的行也将被忽略,在本例中,第一行将不显示,因为该行是空行。
经常用数据库查询结果来填充表格,大多数情况下,你预先并不知道到底需要多少行,这就是为什么还有第二个构造函数的原因:
public Table(intcolumns);
iText根据需要自动添加行,在示例代码0503中,初始化了4行4列,当我们添加第6行和第7行的单元格时,iText自动增加行数到7。
增加列数也是可能的,但是有点麻烦,它不能自动生成,你必须使用addColumns方法并设置列宽,详见示例代码0504。
一些表格参数
前面例子中的表格并不美观,我们可以设置大量的参数来改变表格外观。类Table和类Cell派生于类Rectangle,我们可以用大量典型的Rectangle方法,让我们来看看示例代码0505。
Table table = newTable(3);
table.BorderWidth= 1;
table.BorderColor= new Color(0, 0, 255);
table.Cellpadding= 5;
5.table.Cellspacing = 5;
Cell cell = newCell("header");
cell.Header =true;
cell.Colspan =3;
table.addCell(cell);
10. cell = new Cell("example cell with colspan 1 and rowspan2");
cell.Rowspan =2;
cell.BorderColor= new Color(255, 0, 0);
table.addCell(cell);
table.addCell("1.1");
15. table.addCell("2.1");
table.addCell("1.2");
table.addCell("2.2");
table.addCell("cell test1");
cell = newCell("big cell");
20. cell.Rowspan = 2;
cell.Colspan =2;
cell.BackgroundColor = new Color(0xC0, 0xC0,0xC0);
table.addCell(cell);
table.addCell("cell test2");
25. document.Add(table);
单元格间距和填距
在第4行中,我们设置了表格的填距,就是单元格边界和内容间一定数量的空间,在前面的示例中,我们看到文本紧贴边界,通过使用用特定的填距,就可以避免。
在第5行中,我们设置了表格的间距,就是单元格和表格边界间的一定数量的空间,不同的单元格间使用了半数空间,具体代码见示例代码0506。
对齐方式
在示例代码0506中,我们也改变了单元格“bigcell”的对齐方式:
cell.HorizontalAlignment =Element.ALIGN_CENTER;
cell.VerticalAlignment =Element.ALIGN_MIDDLE;
注:不能总是相信垂直对齐方式。
边框
如果我们象在第14行中那样添加了一个单元格,将使用默认的单元格布局(默认的布局可以SetDefalut方法改变),如果我们使用了Cell对象,我们可以控制每一个单元格的布局。
在第2和第三中,我们设置整个表格的边框宽度和边框颜色,我们在单元格上可以使用的方法,在12行中,每个单元格用“box”作为边界绘制(就象在HTML中),但是示例代码0507显示,我们在PDF中有大量更多可能。
颜色
在第22行中,你也能定义单元格的背景色,在示例代码0507中,我们不使用颜色只是用一定灰度填充。
行跨和列跨
最后,你也能设置单元格的行跨(11/20行)和列跨(8/21列)。通过这种方法可以将几个单元格合并成一个大的单元格。
备注
第7行在PDF中没有意义,用于生成HTML,在HTML中并不是总能产生同样的布局,PDF表格有点象:
header | ||
example cellwith colspan 1 and rowspan 2 | 1.1 | 2.1 |
1.2 | 2.2 | |
celltest1 | bigcell | |
celltest2 |
u 表格分割
如果一个表格不能放在一页中,将自动被分割,示例代码0508显示了当一个表格到达页边时发生的情况,这将在下一节中解释。
大表格
跨越几页的表格将自动被分割成不同的部分。示例代码0509显示了一个跨越多页的报表。该报表有一个表头,如果你希望这个表头在每页都出现,你可以用endHeaders()方法标记表头区域的结束点,见示例代码0510。
为做这样的报表,建议设置单元格间距为0和仅使用指定的填距。
你可能已经注意到了,当一个表格被分割时,一些边界好象丢失了。这是因为单元格在前一页被完整地绘制了而不会传递给下一页。
强行将一个表格或单元格布置到一页上
有有些情况下,你可能希望避免单元格或者整个表被拆分成两个部分,示例代码0511差不多和示例代码0508完全一样,但我们设置了参数TableHasToFit为true,看看示例代码0508和示例代码0511结果区别。在示例代码0512中我们修改了示例代码0510的CellsHaveToFit属性为true,比较两个示例产生结果的区别。
内存管理
当我们添加一个对象到文档时,该对象一有可能就写入了输出流,但当创建一个表格时,该Table对象一直保存着,对于真正的大表格,这将成为一个问题。
同样,当你正写一个HttpServletResponse对象到输出流时,浏览器也可能超时。这就是为什么你自己用fitsPage()方法控制表分割是有用的,示例代码0513告诉你如何做。
嵌套表格
有两种方法嵌套表格,第一种是利用insertTable方法明确地将一个表格插入到另外一个表格,示例代码0514显示了通过插入到其他表格的办法创建的5个表格。正如你看到的在前面两个表中,所有空的单元格自动得到分割,因为改变了原来的表格。如果一个单元格不空,列跨度和(或)行跨度将自动调整到新的位置,页面上第三个表格显示所有原表中列的相关宽度都得到了保护,第四个表格显示我们可以在插入了表格后添加其他单元格:该单元格自由地添加到下一个单元格中。最后是一个深度嵌套的表格。
当你使用insertTable方法时,插入表的宽度百分比不会被考虑,如果你希望插入表仅占单元格的80%(这是默认的宽度百分比),你不得不在单元格中绕排,见示例代码0515,这也是让一个表结合其他数据存放在同一个单元格中的唯一办法,见示例代码0516。
备注:你只能将一个表格插入到列跨度和行跨度均为1的单元格中。
表格偏移
当一个表格被添加到文档之前,以当前间距为准的新行将被添加(如前一个插入对象的间距)。有时因为前一个插入对象和当前表格间的间距过大或过小你并不希望这样做,如果你想改变这个空间,你不得不设置表格偏移,如示例代码0517。
表格的绝对位置
iTextSharp.text.Table是一个通过标准方法创建表格的相当简单的类,但有时你希望表格有一些特殊的行为,这种情况下你将使用更复杂的类com.lowagie.text.pdf.PdfPTable,示例代码0518是一个非常简单的例子,在第十章和十二章中将有一些更复杂的例子。
七、中文处理
默认的iText字体设置不支持中文字体,需要下载远东字体包iTextAsian.jar,否则不能往PDF文档中输出中文字体。通过下面的代码就可以在文档中使用中文了:
BaseFont bfChinese = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
com.lowagie.text.Font FontChinese = new com.lowagie.text.Font(bfChinese, 12, com.lowagie.text.Font.NORMAL);
Paragraph pragraph=new Paragraph("你好", FontChinese);