近段时间做开发,遇到生成PDF文件的需求,在此做一个总结;
iText的5.0版本较2.0版本变化比较大,比如:颜色,页脚,字体,去掉table对象,文字位置 等等;
公司用的2.0,但我这里想以5.0为例子总结一下。
2.0例子见:https://www.hebaocun.com/blog/23.html
1). Chunk 元素:这是可以添加到文档中的文本最小单位,大多数元素可以分成一个或多个Chunk
① setAnchor(String url);设置超链接
② setUnderline(…);设置下划线
③ setFont(Font font);设置字体
④ setLineHeight(float height);设置行高
⑤setCharacterSpacing(float space);设置字符间距
⑥ setHorizontalScaling(float value);设置水平缩放
⑦ setBackground(BaseColor color);设置背景颜色
2). Phrase 元素:短语是一系列的块。短语有一个主字体,但是短语中的一些块可以有不同于主字体的字体。短语中的所有块有相同的行间距。(中文不显示解决方案:①使用new Phrase(String context,Font font);②使用add(Element element)方法
① add(String str);添加字符串(非中文)
② add(Element element);添加元素
③setFont(Font font);设置字体
④ setLeading(float value);设置行间距
3). Paragraph 元素:段落是一系列的块和/或短语。段落具有短语的性质,但也有一些额外的布局参数:缩进、文本的对齐方式(中文不显示解决方案:①使用new Paragraph (String context,Font font);②使用add(Element element)方法)
① add(Element);添加内容
② setFont(Font font);设置字体
③ setLeading(float value);设置行间距(一个Paragraph只有一个行间距)
④ setIndentationLeft(float value);左缩进
⑤ setIndentationRight(float value);右缩进
⑥ setFirstLineIndent(float value);首行缩进
⑦ setSpacingBefore(float value);设置段落上空白
⑧ setSpacingAfter(float value);设置段落下空白
⑨ setAlignment(int alignment);设置居中对齐方式(可以使用Element)
4).Anchor 元素:可以是引用的目标。
① setName(String name);设置锚的名称
② setReference(String reference) ;设置锚的引用
5). Image 元素
初始化:Image img = Image.getInstance(“watermark.jpg”);
① scalePercent(float percent);设置将图片比例压缩
② scaleToFit(float fitWidth, float fitHeight);缩放图像使其适合指定宽度和高度
③ setAlignment(int value);设置图片对齐方式
④ setRotationDegrees(float degrees);设置图像的旋转角度
⑤ setAbsolutePosition(float x,float y);设置图片的绝对位置
⑥ scaleAbsolute(float width, float height);将图像缩放到绝对宽度和绝对高度
6). PdfGState 元素
① setFillOpacity(float value);设置透明度
7). PdfPTable 元素(特别注意:表格的一行必须填满才能显示出来,包括跨列和空字符)
初始化表格:PdfPTable table = new PdfPTable(int numColumns);
① setTotalWidth(float totalWidth);设置表格总宽度
② setWidths(float widths[]);设置单元格宽度 (数组长度等于列数)
③ setLockedWidth(boolean lockedWidth);锁定表格宽度
④ setHorizontalAlignment(int value);设置对齐方式
⑤ setWidthPercentage(float widthPercent);设置表格宽度百分比
⑥ setBackgroundColor(BaseColor color);设置背景颜色
⑦ setSpacingBefore(float value);设置表格上面空白
⑧ setSpacingAfter(float value);设置表格下面空白
⑨ addCell(PdfPCell cell);添加单元格
8). PdfCell 元素
① setRowspan(int rowspan);设置跨行
② setColspan(int colspan);设置跨列
③ setVerticalAlignment(int align);设置垂直对齐方式
④ setHorizontalAlignment(int align);设置水平对齐方式
⑤ setBorder(int border);设置边框(0表示无边框)
⑥ setBorderWidth(float with);设置边框宽度(0表示无边框)
⑦ setBorderColor(BaseColor color);设置边框颜色
⑧ setBackgroundColor(BaseColor color);设置背景颜色
⑨ setMinimumHeight(float height);设置最小高度
⑩ setFixedHeight(float height);设置固定高度
9). PdfContentByte:包含用户定位的文本和页面的图形内容的对象
① beginText();开始
② setGState(PdfGState gstate);设置图像状态(如:透明度)
③ addImage(Image image);添加图片
④ setFontAndSize(BaseFont font,float size);设置文本字体和大小
⑤ setTextMatrix(float x,float y);设置文本的矩阵
⑥ showTextAligned(int alignment, String text, float x, float y, float rotation);写入文档(对齐方式,文本,x坐标,y坐标,旋转角度)
⑦ endText();结束
iText 5.0中并没有2.0版本HeaderFooter对象设置页眉和页脚,可以利用PdfPageEventHelper来完成页眉页脚的设置工作。PdfPageEventHelper中包含以下事件处理器:
onOpenDocument() — 当打开一个文档时触发,可以用于初始化文档的全局变量。
onStartPage() — 当一个页面初始化时触发,可用于初始化页面的设置参数,但是注意这个函数触发时,该页面并没有创建好,不用利用这个函数添加内容,最好利用onEndPage()处理页面的初始化。
onEndPage() — 在创建一个新页面完成但写入内容之前触发,是添加页眉、页脚、水印等最佳时机。
onCloseDocument() — 在文档关闭之前触发,可以用于释放一些资源。
onCloseDocument() — 在文档关闭之前触发,可以用于释放一些资源。
要想出发事件需要在程序中添加事件,如下:
PdfReportM1HeaderFooter footer=new PdfReportM1HeaderFooter();
writer.setPageEvent(footer);
引入依赖:
<dependency>
<groupId> com.itextpdfgroupId >
<artifactId>itext-asianartifactId>
<version>5.2.0version>
dependency>
<dependency>
<groupId>com.itextpdfgroupId>
<artifactId>itextpdfartifactId>
<version>5.5.10version>
dependency>
页眉和页脚的类:
package com.ws.test;
import java.io.IOException;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Element;
import com.itextpdf.text.Font;
import com.itextpdf.text.PageSize;
import com.itextpdf.text.Phrase;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.ColumnText;
import com.itextpdf.text.pdf.PdfContentByte;
import com.itextpdf.text.pdf.PdfPageEventHelper;
import com.itextpdf.text.pdf.PdfTemplate;
import com.itextpdf.text.pdf.PdfWriter;
public class PdfReportM1HeaderFooter extends PdfPageEventHelper {
/**
* 页眉
*/
public String header = "";
/**
* 文档字体大小,页脚页眉最好和文本大小一致
*/
public int presentFontSize = 12;
/**
* 文档页面大小,最好前面传入,否则默认为A4纸张
*/
public Rectangle pageSize = PageSize.A4;
// 模板
public PdfTemplate total = null;
// 基础字体对象
public BaseFont bf = null;
// 利用基础字体生成的字体对象,一般用于生成中文文字
public Font fontDetail = null;
public PdfReportM1HeaderFooter() {
}
/**
* @param yeMei
* 页眉字符串
* @param presentFontSize
* 数据体字体大小
* @param pageSize
* 页面文档大小,A4,A5,A6横转翻转等Rectangle对象
*/
public PdfReportM1HeaderFooter(String yeMei, int presentFontSize, Rectangle pageSize) {
this.header = yeMei;
this.presentFontSize = presentFontSize;
this.pageSize = pageSize;
}
public void setHeader(String header) {
this.header = header;
}
public void setPresentFontSize(int presentFontSize) {
this.presentFontSize = presentFontSize;
}
/**
* TODO 文档打开时创建模板
*/
@Override
public void onOpenDocument(PdfWriter writer, Document document) {
total = writer.getDirectContent().createTemplate(50, 50);// 共页的矩形的长宽高
}
/**
* TODO 关闭每页的时候,写入页眉,写入'第几页共'这几个字。
*/
@Override
public void onEndPage(PdfWriter writer, Document document) {
try {
if (bf == null) {
bf = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
}
if (fontDetail == null) {
fontDetail = new Font(bf, presentFontSize, Font.NORMAL);// 数据体字体
}
} catch (DocumentException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
// 拿到当前的PdfContentByte
PdfContentByte cb = writer.getDirectContent();
// 1.写入页眉 参数:要写入文本的页面对象,对齐,文字内容,X轴位置,Y轴位置,逆时针旋转的角度
ColumnText.showTextAligned(cb, Element.ALIGN_LEFT, new Phrase(header, fontDetail), document.left(), document.top() + 20, 45);
// 2.写入页脚 前半部分的 第 X页/共
int pageS = writer.getPageNumber();
String foot1 = "第 " + pageS + " 页 /共";
Phrase footer = new Phrase(foot1, fontDetail);
// 计算前半部分的foot1的长度,后面好定位最后一部分的'Y页'这俩字的x轴坐标,字体长度也要计算进去 = len
float len = bf.getWidthPoint(foot1, presentFontSize);
/**
* 写入页脚 前半部分的 第 X页/共
* x轴就是(右margin+左margin + right() -left()- len)/2.0F 再给偏移20F适合人类视觉感受,否则肉眼看上去就太偏左了
* y轴就是底边界-20,否则就贴边重叠到数据体里了就不是页脚了;注意Y轴是从下往上累加的,最上方的Top值是大于Bottom好几百开外的。
*/
ColumnText.showTextAligned(cb, Element.ALIGN_CENTER, footer, (document.rightMargin() + document.right() + document.leftMargin() - document.left() - len) / 2.0F + 20F, document.bottom() - 20, 0);
/**
* 写入页脚 后半部分 ?页
* 注:因为共?页 中的?值是在doc.close() 后才能得到,所以这一先加入模板,最后结束的时候后边用值替换
* x=(右margin+左margin + right() -left())/2.0F
* y 轴和之前的保持一致,底边界-20
*/
cb.addTemplate(total, (document.rightMargin() + document.right() + document.leftMargin() - document.left()) / 2.0F + 20F, document.bottom() - 20); // 调节模版显示的位置
}
/**
* TODO 关闭文档时,替换模板,完成整个页眉页脚组件
*/
@Override
public void onCloseDocument(PdfWriter writer, Document document) {
// 7.最后一步了,就是关闭文档的时候,将模板替换成实际的 Y 值,至此,page x of y 制作完毕,完美兼容各种文档size。
total.beginText();
total.setFontAndSize(bf, presentFontSize);// 生成的模版的字体、颜色
String foot2 = " " + writer.getPageNumber() + " 页";
total.showText(foot2);// 模版显示的内容
total.endText();
total.closePath();
}
}
PDF生成主方法:
package com.ws.test;
import java.io.FileOutputStream;
import com.itextpdf.text.BaseColor;
import com.itextpdf.text.Chunk;
import com.itextpdf.text.Document;
import com.itextpdf.text.Element;
import com.itextpdf.text.Font;
import com.itextpdf.text.Image;
import com.itextpdf.text.PageSize;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.Phrase;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.PdfPCell;
import com.itextpdf.text.pdf.PdfPTable;
import com.itextpdf.text.pdf.PdfWriter;
public class PDFTest {
public static void main(String[] args) throws Exception {
//设置纸张
Rectangle rect = new Rectangle(PageSize.A4);
//设置底色
rect.setBackgroundColor(BaseColor.WHITE);
//rect.setBackgroundColor(new BaseColor(254, 254, 254));//自己调色
//创建文档实例
Document document = new Document(rect);
//创建输出流
PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream("F://demo01.pdf"));
//添加中文字体
BaseFont bf = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
//设置字体样式
Font firsetTitleFont = new Font(bf, 25, Font.BOLD);//标题
Font textFont = new Font(bf,18, Font.NORMAL);//正常
Font redTextFont = new Font(bf,16,Font.NORMAL,BaseColor.RED); //正常,红色
Font underlineFont = new Font(bf,18,Font.UNDERLINE); //下划线
//设置页脚
PdfReportM1HeaderFooter footer = new PdfReportM1HeaderFooter();
writer.setPageEvent(footer);
//----------------------------------以上最好都写在document.open()前-----------------------------------------
//文件开始
document.open();
//创建文件新页面(第1页)
document.newPage();
//添加图片
Image img = Image.getInstance("F:\\cs.jpg");
img.setAbsolutePosition(420, 655); //位置(横,纵)
//img.scaleAbsolute((float)(30*3.33),(float)(45*3.33));// 直接设定显示尺寸 *3.33毫米转化像素(横,纵)
img.scalePercent(50f);//图片大小
document.add(img);
//段落
Paragraph p1 = new Paragraph();
//设置标题
p1 = new Paragraph("XX公司个人工资明细", firsetTitleFont);
p1.setLeading(50);
p1.setAlignment(Element.ALIGN_CENTER);
document.add(p1);
//创建4列表格
PdfPTable pt = new PdfPTable(4);
pt.setTotalWidth(90);//设置总宽度
pt.setWidths(new int[]{1,1,1,1});//设置4列宽度比
pt.setSpacingBefore(30);//设置表格上面空白
pt.setSpacingAfter(30);//设置表格下面空白
//pt.setHeaderRows(1);//每页都输出表头
//创建cell
PdfPCell cell = new PdfPCell();
//cell.setRowspan(1);//设置跨行
cell.setColspan(2);//设置跨列
cell.setBorder(0);//设置无边框
cell.addElement(new Paragraph("查询时间:2019.09.03", textFont));
pt.addCell(cell);
cell = new PdfPCell();
cell.setColspan(2);
cell.setBorder(0);
cell.addElement(new Paragraph("查询人:小帅", textFont));
pt.addCell(cell);
document.add(pt);
//工资明细
pt = new PdfPTable(5);
pt.setTotalWidth(110);
pt.setWidths(new int[]{1,1,1,1,1});
cell = new PdfPCell();
cell.setRowspan(3);
cell.setUseAscender(true); //设置可以居中
cell.setHorizontalAlignment(Element.ALIGN_CENTER); //水平居中
cell.setVerticalAlignment(Element.ALIGN_MIDDLE); //文字垂直居中
Paragraph p = new Paragraph("工资明细", textFont);
p.setAlignment(1);//文字水平居中
cell.addElement(p);
pt.addCell(cell);
//列标题
cell = new PdfPCell();
cell.setUseAscender(true);
cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
p = new Paragraph("月份", textFont);
p.setAlignment(1);
cell.addElement(p);
pt.addCell(cell);
cell = new PdfPCell();
cell.setUseAscender(true);
cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
p = new Paragraph("基本工资", textFont);
p.setAlignment(1);
cell.addElement(p);
pt.addCell(cell);
cell = new PdfPCell();
cell.setUseAscender(true);
cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
p = new Paragraph("效绩提成", textFont);
p.setAlignment(1);
cell.addElement(p);
pt.addCell(cell);
cell = new PdfPCell();
cell.setUseAscender(true);
cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
p = new Paragraph("应发工资", textFont);
p.setAlignment(1);
cell.addElement(p);
pt.addCell(cell);
//工资明细 第一行
cell = new PdfPCell();
cell.setUseAscender(true);
cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
p = new Paragraph("1", textFont);
p.setAlignment(1);
cell.addElement(p);
pt.addCell(cell);
cell = new PdfPCell();
cell.setUseAscender(true);
cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
p = new Paragraph("2000.00", textFont);
p.setAlignment(1);
cell.addElement(p);
pt.addCell(cell);
cell = new PdfPCell();
cell.setUseAscender(true);
cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
p = new Paragraph("3000.00", textFont);
p.setAlignment(1);
cell.addElement(p);
pt.addCell(cell);
cell = new PdfPCell();
cell.setUseAscender(true);
cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
p = new Paragraph("5000.00", textFont);
p.setAlignment(1);
cell.addElement(p);
pt.addCell(cell);
//工资明细 第二行
cell = new PdfPCell();
cell.setUseAscender(true);
cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
p = new Paragraph("2", textFont);
p.setAlignment(1);
cell.addElement(p);
pt.addCell(cell);
cell = new PdfPCell();
cell.setUseAscender(true);
cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
p = new Paragraph("2000.00", textFont);
p.setAlignment(1);
cell.addElement(p);
pt.addCell(cell);
cell = new PdfPCell();
cell.setUseAscender(true);
cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
p = new Paragraph("3500.00", textFont);
p.setAlignment(1);
cell.addElement(p);
pt.addCell(cell);
cell = new PdfPCell();
cell.setUseAscender(true);
cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
p = new Paragraph("5500.00", textFont);
p.setAlignment(1);
cell.addElement(p);
pt.addCell(cell);
document.add(pt);
//加入提示
pt = new PdfPTable(1);
pt.setTotalWidth(110);
pt.setSpacingBefore(15);
cell = new PdfPCell();
cell.setBorder(0);
cell.setUseAscender(true);
cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
p = new Paragraph("提示:该明细仅用于记账和备查,不具备法律效力", redTextFont);
p.setAlignment(1);
cell.addElement(p);
pt.addCell(cell);
document.add(pt);
//创建文件新页面(第2页)
document.newPage();
//段落
Paragraph pa = new Paragraph();
//短语
Phrase ph = new Phrase();
pa = new Paragraph("文本演示", firsetTitleFont);
pa.setSpacingAfter(20);//设置段落下边空白距离(段距)
pa.setAlignment(Element.ALIGN_CENTER);//段落居中
document.add(pa);
//第一段
pa = new Paragraph();
pa.setFirstLineIndent(30);//段落首行缩进
pa.setLeading(25);//设置行距
pa.setSpacingAfter(20);//设置段落下边空白距离(段距)
//块
Chunk c1 = new Chunk("这是一条", textFont);
Chunk c2 = new Chunk("下划线", underlineFont);
Chunk c3 = new Chunk(",文本文本文本文本文本文本文本文本文本文本文本文本文本文本文本文本文本文本文本文本文本文本", textFont);
ph.add(c1);
ph.add(c2);
ph.add(c3);
pa.add(ph);
document.add(pa);
//第二段
pa = new Paragraph();
ph = new Phrase();
pa.setFirstLineIndent(30);
pa.setLeading(25);
pa.setSpacingAfter(20);
c1 = new Chunk("文本文本文本文本文本文本文本文本文本文本文本文本文本文本文本文本文本文本文本文本文本文本", textFont);
ph.add(c1);
pa.add(ph);
document.add(pa);
//文件关闭
document.close();
}
}