@HUST-SuWB
2016-01-21T09:16:28.000000Z
字数 6303
阅读 719
项目实战
由于项目开发中的一个导出的需求,去调研了下对于大量文字、图片和表格的数据,怎样最简单的导出成PDF文件。经过短暂的调研,很快就确定下了使用iText。原因也很简单,iText的官网做得很好,相关的资料也很多,实在不行,还有本《iText in action》的书。挂一下这本书的PDF版本,大家有钱还是去支持正版图书吧。
其实,把官网上的例子看完了基本上常见的需求都能解决了。我简单的列了一下,我需要的功能大概包括:段落文本的添加、表格的绘制、图片的绘制、简单的排版、中文字符的显示等。实际的开发下来,感觉对于图表的某些操作算是费了点时间,这个就大家自己去感受了。
package tool;import java.io.FileOutputStream;import java.io.IOException;import java.net.MalformedURLException;import java.text.SimpleDateFormat;import java.util.ArrayList;import java.util.Date;import java.util.List;import com.itextpdf.text.BaseColor;import com.itextpdf.text.Document;import com.itextpdf.text.DocumentException;import com.itextpdf.text.Element;import com.itextpdf.text.Font;import com.itextpdf.text.FontFactory;import com.itextpdf.text.Image;import com.itextpdf.text.PageSize;import com.itextpdf.text.Paragraph;import com.itextpdf.text.Phrase;import com.itextpdf.text.pdf.BaseFont;import com.itextpdf.text.pdf.ColumnText;import com.itextpdf.text.pdf.PdfContentByte;import com.itextpdf.text.pdf.PdfPCell;import com.itextpdf.text.pdf.PdfPTable;import com.itextpdf.text.pdf.PdfTemplate;import com.itextpdf.text.pdf.PdfWriter;/*** pdf操作类* @author suwb* @since 2016-01-20**/public class PDFTool {private Font font;private BaseFont bfChinese;private Document doc;private static final String RESULT = "src/source/pdf/";private static final float TABLEPERCENT = 97;public PDFTool() throws Exception {// 设置中文字体bfChinese = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);font = new Font(bfChinese);font.setSize(15);font.setStyle(FontFactory.HELVETICA);// font.setStyle(Font.BOLD);//加粗font.setColor(new BaseColor(0,0,0));}public void helloWorld() throws DocumentException, IOException {doc = new Document(PageSize.A4, 20, 20, 20, 20);PdfWriter writer = PdfWriter.getInstance(doc, new FileOutputStream(RESULT +new SimpleDateFormat("HHmmss").format(new Date()) + "_中文.pdf"));//http://developers.itextpdf.com/question/how-add-text-imagewriter.setStrictImageSequence(true);doc.open();PdfContentByte cb = writer.getDirectContent();addText("中国人");addText("韩国人");List<Object[]> contents = new ArrayList<Object[]>();for(int i=0;i<2;i++){Object[] object = new Object[2];object[0] = "华科" + i;object[1] = "武大" + i;contents.add(object);}addImage((RESULT + "1.png"), cb, null);addText("中国人");addTable(new String[]{"序号一", "序号二"}, contents);addText("韩国人");addImage((RESULT + "2.png"), cb, null);addText("韩国人");doc.close();}/*** 编辑标题* @param text 段落的文本内容* @param fontSize 标题的字体大小* @throws DocumentException*/public void addTitle(String title, int fontSize)throws DocumentException{Font titleFont = new Font(font);titleFont.setSize(fontSize);Paragraph content = new Paragraph(title, titleFont);content.setAlignment(Element.ALIGN_CENTER);doc.add(content);}/*** 编辑文本* @param text 段落的文本内容* @throws DocumentException*/public void addText(String text)throws DocumentException{Paragraph content = new Paragraph(text, font);content.setAlignment(Element.ALIGN_LEFT);doc.add(content);}/*** 自定义文本大小的编辑文本* @param text 段落的文本内容* @param fontSize 字体大小* @throws DocumentException*/public void addText(String text, int fontSize)throws DocumentException{Font textFont = new Font(font);textFont.setSize(fontSize);Paragraph content = new Paragraph(text, textFont);content.setAlignment(Element.ALIGN_LEFT);doc.add(content);}/*** 编辑表格* @param header 表格头* @param contents 表格内容* @throws DocumentException*/public void addTable(Object[] header, List<Object[]> contents)throws DocumentException{PdfPTable table = new PdfPTable(header.length);table.setWidthPercentage(TABLEPERCENT);for(int i = 0; i < header.length; i++){Paragraph paragraph = new Paragraph(header[i].toString(), font);paragraph.setAlignment(Element.ALIGN_CENTER);paragraph.setLeading(0, 1);PdfPCell cell = new PdfPCell();cell.addElement(paragraph);table.addCell(cell);}for(int j = 0; j < header.length*contents.size(); j++){int m = j/(header.length);//行int n = j%(header.length);//列String content = contents.get(m)[n]!=null?contents.get(m)[n].toString():"";Paragraph paragraph = new Paragraph(content, font);paragraph.setAlignment(Element.ALIGN_CENTER);paragraph.setLeading(0, 1);PdfPCell cell = new PdfPCell();cell.addElement(paragraph);table.addCell(cell);}doc.add(table);}/*** 编辑图片+水印* @param imagePath 图片的路径* @param cb PdfContentByte包含用户定位文本和图形内容页面对象* @param watermark 水印[默认可设置为null]* @throws IOException* @throws MalformedURLException* @throws DocumentException*/public void addImage(String imagePath, PdfContentByte cb, String watermark)throws MalformedURLException, IOException, DocumentException{if(watermark!=null){PdfPTable table = new PdfPTable(1);table.addCell(getWatermarkedImage(cb, Image.getInstance(imagePath), watermark));doc.add(table);}else {Image img = Image.getInstance(imagePath);float height = img.getHeight();float width = img.getWidth();int percent = getPercent2(height, width);img.setAlignment(Image.MIDDLE);img.scalePercent(percent + 3);doc.add(img);}}/*** 添加空行* @param number 空行数* @throws DocumentException*/public void addBlankLine(int number) throws DocumentException{Paragraph blankLine = new Paragraph("\n");for(int i=0; i<number; i++){doc.add(blankLine);}}/*** 第一种解决方案 在不改变图片形状的同时,判断,如果h>w,则按h压缩,否则在w>h或w=h的情况下,按宽度压缩。* @param h* @param w* @return*/public int getPercent(float h, float w) {int p = 0;float p2 = 0.0f;if (h > w) {p2 = 297 / h * 100;} else {p2 = 210 / w * 100;}p = Math.round(p2);return p;}/*** 第二种解决方案,统一按照宽度压缩。这样来的效果是,所有图片的宽度是相等的。* @param args*/public int getPercent2(float h, float w) {int p = 0;float p2 = 0.0f;p2 = 530 / w * 100;p = Math.round(p2);return p;}public Image getWatermarkedImage(PdfContentByte cb, Image img, String watermark) throws DocumentException {float width = img.getScaledWidth();float height = img.getScaledHeight();PdfTemplate template = cb.createTemplate(width, height);template.addImage(img, width, 0, 0, height, 0, 0);ColumnText.showTextAligned(template, Element.ALIGN_CENTER,new Phrase(watermark, font), width / 2, height / 2, 30);return Image.getInstance(template);}}
首先给我最直接参考的资料来源是网上的一片博客,这篇博客基本上把基础的问题都解决了,但是有一些他没有说清楚的点,比如实际上官方的iText的jar包是不支持中文的,解决方式常用的就是去下载一个中文扩展包,具体可见这篇博客,但是我后续找到了一个更简便的方式,网上直接有人提供扩展了中文之后的iText包,最终我采用的就是这个jar包解决中文问题。
然后,针对实际操作中遇到的关于表格和图片的问题,直接参考了官网的图片资料和表格资料。如果对表格有更加深入的需求,比如各种不规则的排版,则可以好好看看这一篇:http://developers.itextpdf.com/content/zugferd-future-invoicing/5-creating-pdf-invoices-basic-profile。
另外,如果最终的排版中碰到了乱序的问题,可以参考官网上的这篇Q&A,重点在于
writer.setStrictImageSequence(true);
最后,如果是用于常见的B/S系统中,那么你会需要看看如何在web开发中使用这种pdf的导出功能,这里,很可能你会碰到一些坑,这里只能帮你们填两个坑,参考如下:
http://bbs.csdn.net/topics/380054889
http://www.360doc.com/content/12/0612/13/1967709_217660151.shtml
给图片加上水印后图片的大小变得不可控了,导致排版上非常的难看。这个功能由于时间问题,暂时还没有继续研究如何解决,只能后续在研究了。