使用 itext 生成简单 pdf 文件

截止2021年7月,itext的最新版本是itext7,本文是基于itext5编写(itext的大版本号是4-5-7,没有6)

itext5已于2020年9月停止维护

相关依赖:

<!-- https://mvnrepository.com/artifact/com.itextpdf/itextpdf -->
<dependency>
    <groupId>com.itextpdf</groupId>
    <artifactId>itextpdf</artifactId>
    <version>5.5.13.2</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>

基本步骤

用itext生成pdf大体分为5个步骤:

os = response.getOutputStream();

// 1.建立Document对象的实例
Document doc = new Document();
// 2.建立一个书写器(Writer)与document对象关联,通过书写器可以将文件写到输出流中
PdfWriter.getInstance(doc, os);
// 3.打开文档
doc.open();
// 4.向文档中添加内容,这部分之后会详细说明
doc.add(new Paragraph("Hello World"));
// 5.关闭文档
doc.close();

重点在第4步打开文档之后往里面加东西的操作。

第2步生成了一个PdfWriter存在了doc里面,在第5步调用doc.close()的时候调用这个PdfWriterclose()方法才关闭流,所以最好写成try-with-resource的形式保证流可以关闭。

文本

itext的文本由文本块(Chunk)、短语(Phrase)、段落(Paragraph)构成。

文本块(Chunk)是处理文本的最小单位,有一串带格式(包括字体、颜色、大小)的字符串组成。

如下代码就是创建一个字体为HELVETICA、大小为10、带下划线的字符串。

Font font = FontFactory.getFont(FontFactory.HELVETICA, 10, Font.UNDERLINE);
Chunk chunk = new Chunk("chunk underline", font);

短语(Phrase)由一个或多个文本块(Chunk)组成,短语(Phrase)也可以设定字体,但对于其中已设定过字体的文本块(Chunk)无效。通过短语(Phrase)函数add()可以将一个文本块(Chunk)加到短语(Phrase)中。

如下代码就是创建一个包括"phrase"chunk的短语,但是"phrase"的字号是20,chunk的字号是10。

Font font = FontFactory.getFont(FontFactory.HELVETICA, 20, Font.UNDERLINE);
Phrase phrase = new Phrase("phrase", font);
phrase.add(chunk);

段落(Paragraph)由一个或多个文本块(Chunk)或短语(Phrase)组成,相当于WORD中的段落,同样可以设定段落的字体大小、颜色等属性。另外也可以设定段落的首行缩进、对齐方式(左对齐、右对齐、居中对齐)。通过函数setAlignment可以设定段落的对齐方式,默认为左对齐。

Paragraph paragraph = new Paragraph("Hello World");
// 左对齐
paragraph.setAlignment(Element.ALIGN_LEFT);
// 居中
paragraph.setAlignment(Element.ALIGN_CENTER);
// 右对齐
paragraph.setAlignment(Element.ALIGN_RIGHT);
// 首行缩进10个单位,不清楚这个单位是什么,但肯定不是字符
paragraph.setFirstLineIndent(10);

中文处理

itext本身并不支持中文字体,如果把上面代码里的文字替换成中文将会输出空白文档(连换行都没有)。

使用中日韩文字需要引入亚洲字体包itext-asian

BaseFont baseFont = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
Font font = new Font(baseFont, 12, Font.NORMAL);

上面这段代码表示生成宋体12号字,UniGB-UCS2-H表示水平编码,UniGB-UCS2-V则是垂直编码。

itext-asian仅支持宋体一种简体字体,可通过扩展的方式添加其他字体。

图片

目前itext支持gif、jpeg、png、wmf等图片格式。获取Image的方法有2种,网络图片可以通过字节数组的方式,本地图片可以直接使用路径获取。都是调用静态函数Image.getInstance(),利用Java多态的特性。

// 根据byte[]获取
byte[] b = bos.toByteArray();
Image image = Image.getInstance(b);
// 根据文件路径获取
String path = "/user/image.jpeg";
Image image = Image.getInstance(path);

表格

表格主要由table和cell两部分组成

table

// 表格有4列
PdfPTable table = new PdfPTable(4);
// 设置表格的宽度
table.setTotalWidth(600);
// 也可以每列分别设置宽度
table.setTotalWidth(new float[] { 160, 70, 130, 100 });
// 锁住宽度
table.setLockedWidth(true);
// 设置表格上面空白宽度
table.setSpacingBefore(30f);
// 设置表格下面空白宽度
table.setSpacingAfter(0f);
// 设置表格默认为无边框
table.getDefaultCell().setBorder(0);
doc.add(table);

图片 cell

byte[] bs = bos.toByteArray();
Image image = Image.getInstance(bs);
PdfPCell cell = new PdfPCell(image, true);
// 设置cell边框(无边框),或setBorder
cell.setBorderWidth(Rectangle.NO_BORDER);
// 设置cell高度
cell.setFixedHeight(100);
// 水平居中
cell.setHorizontalAlignment(Element.ALIGN_CENTER);
// 垂直居中
cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
table.addCell(cell);

在图片比较多的时候,也可使用下面的方法添加图片,这样可以省略一些重新设置格式的消耗,实测会比new一个cell稍微快一些。

PdfPCell cell = new PdfPCell();
cell.setFixedHeight(100);
cell.setImage(image1);
table.addCell(cell);
cell.setImage(image2);
table.addCell(cell);

文本 cell

上例cell中存放的是图片,图片高度会自适应。注意如果是文本,需要cell高度大于文字字体。比如cell高度是30,字体是14,则cell内可以写2行字,第一行放不下的字会自动到第二行。但如果字体是16,则只能放1行字,如果文本过长,长的那部分就不会显示。

PdfPCell cell = new PdfPCell(new Paragraph("Text cell"));
// 设置背景颜色
cell.setBackgroundColor(BaseColor.ORANGE);
// 设置边框颜色
cell.setBorderColor(BaseColor.GREEN);
// 设置左边距
cell.setPaddingLeft(10);
// 设置跨2行
cell.setRowspan(2);
// 设置跨两列
cell.setColspan(2);
table.addCell(cell);

二维码 cell

// 创建一个条形码对象
Barcode128 barcode128 = new Barcode128();
barcode128.setCode("123456789");
barcode128.setCodeType(Barcode128.CODE128);
// 生成条形码图片
Image image = barcode128.createImageWithBarcode(cb, null, null);
// 以图片的方式放到表格
PdfPCell cell = new PdfPCell(image, true);
cell.setHorizontalAlignment(Element.ALIGN_CENTER);
cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
cell.setFixedHeight(30);
table.addCell(cell);

最好给条形码设置一个合适的高度,否则黑条会过密。

todo

这篇文章需要补充的部分

  1. 如何导入自定义字体
  2. Image如何设置大小、透明度、自定义位置等参数
  3. 如何添加PDF文件信息
  4. 如何添加水印
  5. 如何添加页眉页脚

等有空就写......

2021年7月28日

参考

itextpdf生成表格的常见用法

https://blog.csdn.net/u010142437/article/details/84303581

[itext]Java生成PDF文件

https://www.cnblogs.com/qlqwjy/p/8213989.html

itextpdf JAVA 输出PDF文档

https://www.cnblogs.com/icerainsoft/p/4900359.html

使用 itext 生成简单 pdf 文件

上一篇:Skywalking-05:在Skywalking RocketBot上添加监控图表


下一篇:Integer