@HUST-SuWB
2016-01-21T09:16:28.000000Z
字数 6303
阅读 661
项目实战
由于项目开发中的一个导出的需求,去调研了下对于大量文字、图片和表格的数据,怎样最简单的导出成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-image
writer.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
给图片加上水印后图片的大小变得不可控了,导致排版上非常的难看。这个功能由于时间问题,暂时还没有继续研究如何解决,只能后续在研究了。