itext 使用
需求背景
在工作中经常会有生成pdf文件的需求,大多数情况下,我们只需要使用pdf模版添加表单域,就足以胜任了。但是有一些特殊的需求,需要生成较为复杂的文件,如动态数据表格、插入图像等。
这时候,我们就可以使用拼接的方式,将pdf文件内容一段段拼上去,组合成一个pdf文件,来灵活的操纵文件的排版与内存形式。
itext 的使用
依赖
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itextpdf</artifactId>
<version>5.5.13</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.itextpdf/itext-asian -->
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itext-asian</artifactId>
<version>5.2.0</version>
</dependency>
简单示例
生成一个内容为“Hello World”的pdf文件
import com.itextpdf.text.*;
import com.itextpdf.text.pdf.PdfWriter;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* 生成一个内容为“Hello World”的pdf文件
* @author ym
*/
public class HelloWorld {
public static void main(String[] args) {
String FILE_DIR = "./"; // 项目根目录:盘符:/.../.../项目名称,注意:点号并不表示当前类文件所在的目录,而是项目目录下
//Step 1—Create a Document.
Document document = new Document();
try {
//Step 2—Get a PdfWriter instance.
PdfWriter.getInstance(document, new FileOutputStream(FILE_DIR + "createSamplePDF.pdf"));
//Step 3—Open the Document.
document.open();
//Step 4—Add content.
document.add(new Paragraph("Hello World"));
//Step 5—Close the Document.
document.close();
} catch (DocumentException ex) {
Logger.getLogger(HelloWorld.class.getName()).log(Level.SEVERE, null, ex);
} catch (FileNotFoundException ex) {
Logger.getLogger(HelloWorld.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
基础设置(页面大小、边距、字体等)
//页面大小
Rectangle rect = new Rectangle(PageSize.A4.rotate());
//页面背景色
rect.setBackgroundColor(BaseColor.ORANGE);
// page , 外边距 marginLeft marginRight marginTop marginBottom
Document doc = new Document(rect,90, 90, 30, 40);
// 新开一页
doc.newPage();
/**
* 段落设置
*/
Paragraph titleParagraph = new Paragraph("hello world!", getChineseTitleFont());
titleParagraph.setAlignment(Element.ALIGN_CENTER);// 居中
titleParagraph.setFirstLineIndent(24);// 首行缩进
titleParagraph.setLeading(35f);// 行间距
titleParagraph.setSpacingBefore(5f);// 设置上空白
titleParagraph.setSpacingAfter(10f);// 设置段落下空白
//支持中文 设置字体,字体颜色、大小等
public Font getChineseTitleFont() throws RuntimeException {
Font ChineseFont = null;
try {
/**
* name – the name of the font or its location on file
* encoding – the encoding to be applied to this font
* embedded – true if the font is to be embedded in the PDF
*/
BaseFont simpChinese = BaseFont.createFont("STSongStd-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
ChineseFont = new Font(simpChinese, 15, Font.BOLD, BaseColor.BLACK);
} catch (DocumentException e) {
log.error("getChineseFont" ,"字体异常",e);
throw new RuntimeException("getChineseFont字体异常",e);
} catch (IOException e) {
log.error("getChineseFont" ,"字体异常",e);
throw new RuntimeException("getChineseFont字体异常",e);
}
return ChineseFont;
}
段落内部,特殊设置关键字 字体或颜色
// 文本内容
String content = "This is a sample text with different colors.";
String[] words = content.split(" "); // 将文本拆分为单词
for (String word : words) {
Chunk chunk = new Chunk(word); // 创建一个新的 Chunk
// 如果单词是 "different",则设置为红色
if (word.equals("different")) {
chunk.setForegroundColor(BaseColor.RED);
}
// 如果单词是 "colors.",则设置为蓝色
if (word.equals("colors.")) {
chunk.setForegroundColor(BaseColor.BLUE);
}
contentParagraph.add(chunk); // 将 Chunk 添加到段落中
contentParagraph.add(" "); // 添加单词之间的空格
}
document.add(contentParagraph); // 将段落添加到文档中
生成动态表格
// 创建一个包含5列的表格
PdfPTable table = new PdfPTable(5);
// 添加表头
table.addCell("Header 1");
table.addCell("Header 2");
table.addCell("Header 3");
table.addCell("Header 4");
table.addCell("Header 5");
// 添加动态数据到表格
for (int i = 0; i < 10; i++) {
table.addCell("Data " + i + ", 1");
table.addCell("Data " + i + ", 2");
table.addCell("Data " + i + ", 3");
table.addCell("Data " + i + ", 4");
table.addCell("Data " + i + ", 5");
}
document.add(table);
/**
* 如果需要更精细的控制属性
*/
cell = new PdfPCell(new Phrase("title1",fontChinese));
cell.setColspan(1);//设置所占列数
cell.setRowspan(1);//合并行
cell.setHorizontalAlignment(Element.ALIGN_CENTER);//设置水平居中
cell.setVerticalAlignment(Element.ALIGN_MIDDLE);//设置垂直居中
cell.setFixedHeight(30);//设置高度
table.addCell(cell);
页脚展示页数
PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(FILE_DIR + "createSamplePDF.pdf"));
writer.setPageEvent(new FooterEvent());
public class FooterEvent extends PdfPageEventHelper {
//总页数
PdfTemplate totalPage;
//字体
Font font;
{
try {
BaseFont chinese = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
font = new Font(chinese,10);
} catch (DocumentException | IOException e) {
e.printStackTrace();
}
}
//打开文档时,创建一个总页数的模版
@Override
public void onOpenDocument(PdfWriter writer, Document document) {
PdfContentByte cb = writer.getDirectContent();
totalPage = cb.createTemplate(50, 9);
}
@Override
public void onEndPage(PdfWriter writer, Document document) {
//创建一个两列的表格
PdfPTable table = new PdfPTable(2);
try {
table.setTotalWidth(PageSize.A4.getWidth());//总宽度为A4纸张宽度
table.setLockedWidth(true);//锁定列宽
table.setWidths(new int[]{50, 50});//设置每列宽度
PdfPCell cell = new PdfPCell(new Phrase("第"+document.getPageNumber() + " 页,共", font));
cell.setHorizontalAlignment(Element.ALIGN_RIGHT);//设置水平右对齐
cell.setVerticalAlignment(Element.ALIGN_MIDDLE);//设置垂直居中
cell.disableBorderSide(15);//隐藏全部边框
table.addCell(cell);
PdfPCell cell1 = new PdfPCell(Image.getInstance(totalPage));//共 页
cell1.setHorizontalAlignment(Element.ALIGN_LEFT);//设置水平左对齐
cell1.setVerticalAlignment(Element.ALIGN_MIDDLE);//设置垂直居中
cell1.disableBorderSide(15);//隐藏全部边框
table.addCell(cell1);
table.writeSelectedRows(0, -1, 0, 30, writer.getDirectContent());
} catch (Exception e) {
throw new ExceptionConverter(e);
}
}
@Override
public void onCloseDocument(PdfWriter writer, Document document) {
String text = "" +String.valueOf(writer.getPageNumber()) +"页";
ColumnText.showTextAligned(totalPage, Element.ALIGN_MIDDLE, new Paragraph(text, font), 0, 0, 0);
}
}
其他
设置密码
PdfWriter writer = PdfWriter.getInstance(doc, out);
// 设置密码为:"World"
writer.setEncryption("Hello".getBytes(), "World".getBytes(),
PdfWriter.ALLOW_SCREENREADERS,
PdfWriter.STANDARD_ENCRYPTION_128);
doc.open();
doc.add(new Paragraph("Hello World"));
添加水印(背景图)
//图片水印
PdfReader reader = new PdfReader(FILE_DIR + "setWatermark.pdf");
PdfStamper stamp = new PdfStamper(reader, new FileOutputStream(FILE_DIR
+ "setWatermark2.pdf"));
Image img = Image.getInstance("resource/watermark.jpg");
img.setAbsolutePosition(200, 400);
PdfContentByte under = stamp.getUnderContent(1);
under.addImage(img);
//文字水印
PdfContentByte over = stamp.getOverContent(2);
over.beginText();
BaseFont bf = BaseFont.createFont(BaseFont.HELVETICA, BaseFont.WINANSI,
BaseFont.EMBEDDED);
over.setFontAndSize(bf, 18);
over.setTextMatrix(30, 30);
over.showTextAligned(Element.ALIGN_LEFT, "DUPLICATE", 230, 430, 45);
over.endText();
//背景图
Image img2 = Image.getInstance("resource/test.jpg");
img2.setAbsolutePosition(0, 0);
PdfContentByte under2 = stamp.getUnderContent(3);
under2.addImage(img2);
stamp.close();
reader.close();
目录
// Code 1
document.add(new Chunk("Chapter 1").setLocalDestination("1"));
document.newPage();
document.add(new Chunk("Chapter 2").setLocalDestination("2"));
document.add(new Paragraph(new Chunk("Sub 2.1").setLocalDestination("2.1")));
document.add(new Paragraph(new Chunk("Sub 2.2").setLocalDestination("2.2")));
document.newPage();
document.add(new Chunk("Chapter 3").setLocalDestination("3"));
// Code 2
PdfContentByte cb = writer.getDirectContent();
PdfOutline root = cb.getRootOutline();
// Code 3
@SuppressWarnings("unused")
PdfOutline oline1 = new PdfOutline(root, PdfAction.gotoLocalPage("1", false), "Chapter 1");
PdfOutline oline2 = new PdfOutline(root, PdfAction.gotoLocalPage("2", false), "Chapter 2");
oline2.setOpen(false);
@SuppressWarnings("unused")
PdfOutline oline2_1 = new PdfOutline(oline2, PdfAction.gotoLocalPage("2.1", false), "Sub 2.1");
@SuppressWarnings("unused")
PdfOutline oline2_2 = new PdfOutline(oline2, PdfAction.gotoLocalPage("2.2", false), "Sub 2.2");
@SuppressWarnings("unused")
PdfOutline oline3 = new PdfOutline(root, PdfAction.gotoLocalPage("3", false), "Chapter 3");
Header, Footer
PdfWriter writer = PdfWriter.getInstance(doc, new FileOutputStream(FILE_DIR + "setHeaderFooter.pdf"));
writer.setPageEvent(new PdfPageEventHelper() {
public void onEndPage(PdfWriter writer, Document document) {
PdfContentByte cb = writer.getDirectContent();
cb.saveState();
cb.beginText();
BaseFont bf = null;
try {
bf = BaseFont.createFont(BaseFont.HELVETICA, BaseFont.WINANSI, BaseFont.EMBEDDED);
} catch (Exception e) {
e.printStackTrace();
}
cb.setFontAndSize(bf, 10);
//Header
float x = document.top(-20);
//左
cb.showTextAligned(PdfContentByte.ALIGN_LEFT,
"H-Left",
document.left(), x, 0);
//中
cb.showTextAligned(PdfContentByte.ALIGN_CENTER,
writer.getPageNumber()+ " page",
(document.right() + document.left())/2,
x, 0);
//右
cb.showTextAligned(PdfContentByte.ALIGN_RIGHT,
"H-Right",
document.right(), x, 0);
//Footer
float y = document.bottom(-20);
//左
cb.showTextAligned(PdfContentByte.ALIGN_LEFT,
"F-Left",
document.left(), y, 0);
//中
cb.showTextAligned(PdfContentByte.ALIGN_CENTER,
writer.getPageNumber()+" page",
(document.right() + document.left())/2,
y, 0);
//右
cb.showTextAligned(PdfContentByte.ALIGN_RIGHT,
"F-Right",
document.right(), y, 0);
cb.endText();
cb.restoreState();
}
});
doc.open();
doc.add(new Paragraph("1 page"));
doc.newPage();
doc.add(new Paragraph("2 page"));
doc.newPage();
doc.add(new Paragraph("3 page"));
doc.newPage();
doc.add(new Paragraph("4 page"));
分割 PDF
FileOutputStream out = new FileOutputStream(FILE_DIR + "splitPDF.pdf");
Document document = new Document();
PdfWriter.getInstance(document, out);
document.open();
document.add(new Paragraph("1 page"));
document.newPage();
document.add(new Paragraph("2 page"));
document.newPage();
document.add(new Paragraph("3 page"));
document.newPage();
document.add(new Paragraph("4 page"));
document.close();
PdfReader reader = new PdfReader(FILE_DIR + "splitPDF.pdf");
Document dd = new Document();
PdfWriter writer = PdfWriter.getInstance(dd, new FileOutputStream(FILE_DIR + "splitPDF1.pdf"));
dd.open();
PdfContentByte cb = writer.getDirectContent();
dd.newPage();
cb.addTemplate(writer.getImportedPage(reader, 1), 0, 0);
dd.newPage();
cb.addTemplate(writer.getImportedPage(reader, 2), 0, 0);
dd.close();
writer.close();
Document dd2 = new Document();
PdfWriter writer2 = PdfWriter.getInstance(dd2, new FileOutputStream(FILE_DIR + "splitPDF2.pdf"));
dd2.open();
PdfContentByte cb2 = writer2.getDirectContent();
dd2.newPage();
cb2.addTemplate(writer2.getImportedPage(reader, 3), 0, 0);
dd2.newPage();
cb2.addTemplate(writer2.getImportedPage(reader, 4), 0, 0);
dd2.close();
writer2.close();
合并 PDF
PdfReader reader1 = new PdfReader(FILE_DIR + "splitPDF1.pdf");
PdfReader reader2 = new PdfReader(FILE_DIR + "splitPDF2.pdf");
FileOutputStream out = new FileOutputStream(FILE_DIR + "mergePDF.pdf");
Document document = new Document();
PdfWriter writer = PdfWriter.getInstance(document, out);
document.open();
PdfContentByte cb = writer.getDirectContent();
int totalPages = 0;
totalPages += reader1.getNumberOfPages();
totalPages += reader2.getNumberOfPages();
java.util.List<PdfReader> readers = new ArrayList<PdfReader>();
readers.add(reader1);
readers.add(reader2);
int pageOfCurrentReaderPDF = 0;
Iterator<PdfReader> iteratorPDFReader = readers.iterator();
// Loop through the PDF files and add to the output.
while (iteratorPDFReader.hasNext()) {
PdfReader pdfReader = iteratorPDFReader.next();
// Create a new page in the target for each source page.
while (pageOfCurrentReaderPDF < pdfReader.getNumberOfPages()) {
document.newPage();
pageOfCurrentReaderPDF++;
PdfImportedPage page = writer.getImportedPage(pdfReader, pageOfCurrentReaderPDF);
cb.addTemplate(page, 0, 0);
}
pageOfCurrentReaderPDF = 0;
}
out.flush();
document.close();
out.close();