这两天碰到了一个根据模板导出pdf的需求,研究了几天以后,发现网上的资料不太齐全,主要是没找到既根据模板导出,又可以动态增加页数的例子。只能通过各种资料结合来实现这个需求了(其实是懒得看iText英文文档,这个以后得改过来)。
下面先来说下pdf导出主要的两种方式:
1.直接使用iText的api,写出原生的pdf文档,但是样式和排版很难控制,比较方便的是,可以动态的添加文档数据,还可以增加页数等操作。关于样式和排版可以通过结合XmlWorker,从HTML模板生成PDF。
2.根据pdf模板导出,这里会涉及到使用adobe acrobat这个软件。通过adobe acrobat来制作表单域,然后在应用程序里动态向表单域添加数据。
(1)在adobe acrobat中打开一个pdf文档,然后点击右侧的“准备表单”,选择文件后点击“开始”
图片步骤为:
(2).在页面上新建表单域,可以通过右键-属性,修改表单域的设置,这里新建了两个name为“title”和“img”的文本域
(3).将设置了表单域的pdf文档保存即可
3.现在就是开始写java代码了,首先需要在pom文件里引入两个itext的jar包,如下所示:
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itextpdf</artifactId>
<version>5.5.6</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itext-asian</artifactId>
</dependency>
(1)多页导出,包含图片。如果导出的中文无法显示,需要重新设置字体。
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Image;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.*;
import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class PdfTest {
// 利用模板生成pdf
public static void fillTemplate() {
// 原pdf模板路径
String templatePath = "D:/old.pdf";
// 生成的新文件路径
String newPDFPath = "D:/new.pdf";
//图片路径
String imgPath = "D:/test.jpg";
FileOutputStream out;
int num = 2;//页数
ByteArrayOutputStream bos[] = new ByteArrayOutputStream[num];
try {
out = new FileOutputStream(newPDFPath);// 输出流
Document doc = new Document(); //新建一个文档
PdfCopy copy = new PdfCopy(doc, out); //用于保存原页面内容,然后输出
doc.open();
for (int i = 0; i < num; i++) {
bos[i] = new ByteArrayOutputStream();
PdfReader reader = new PdfReader(templatePath);// 读取pdf模板
PdfStamper stamper = new PdfStamper(reader, bos[i]); //生成输出流
AcroFields form = stamper.getAcroFields(); //获取文本域
form.setField("title", "这是标题");
int pageNo = form.getFieldPositions("img").get(0).page;
Rectangle rectangle = form.getFieldPositions("img").get(0).position;
float x = rectangle.getLeft();
float y = rectangle.getBottom();
//根据路径读取图片
Image image = Image.getInstance("D:/test.jpg");
//获取图片页面
PdfContentByte under = stamper.getOverContent(pageNo);
//图片大小自适应
image.scaleToFit(rectangle.getWidth(), rectangle.getHeight());
//添加图片
image.setAbsolutePosition(x, y);
under.addImage(image);
stamper.setFormFlattening(true);// 如果为false那么生成的PDF文件还能编辑,一定要设为true
stamper.close();
}
PdfImportedPage page = null;
for (int i = 0; i < num; i++) {
page = copy.getImportedPage(new PdfReader(bos[i].toByteArray()), i + 1);
copy.addPage(page);
}
doc.close();
out.close();
} catch (IOException e) {
System.out.println("导出异常");
} catch (DocumentException e) {
System.out.println("文档异常");
}
}
public static void main(String[] args) {
fillTemplate();
}
}
(2)此时的需求是需要根据应用程序,动态复制第二页的模板,那么代码改为下面这种
// 利用模板生成pdf
public static void fillTemplate() {
// 原pdf模板路径
String templatePath = "D:/old.pdf";
// 生成的新文件路径
String newPDFPath = "D:/new.pdf";
//图片路径
String imgPath = "D:/test.jpg";
FileOutputStream out;
int num = 4;//页数
ByteArrayOutputStream bos[] = new ByteArrayOutputStream[num];
try {
out = new FileOutputStream(newPDFPath);// 输出流
Document doc = new Document(); //新建一个文档
PdfCopy copy = new PdfCopy(doc, out); //用于保存原页面内容,然后输出
doc.open();
for (int i = 0; i < 2; i++) {
bos[i] = new ByteArrayOutputStream();
PdfReader reader = new PdfReader(templatePath);// 读取pdf模板
PdfStamper stamper = new PdfStamper(reader, bos[i]); //生成输出流
AcroFields form = stamper.getAcroFields(); //获取文本域
form.setField("title", "这是标题");
int pageNo = form.getFieldPositions("img").get(0).page;
Rectangle rectangle = form.getFieldPositions("img").get(0).position;
float x = rectangle.getLeft();
float y = rectangle.getBottom();
//根据路径读取图片
Image image = Image.getInstance("D:/test.jpg");
//获取图片页面
PdfContentByte under = stamper.getOverContent(pageNo);
//图片大小自适应
image.scaleToFit(rectangle.getWidth(), rectangle.getHeight());
//添加图片
image.setAbsolutePosition(x, y);
under.addImage(image);
stamper.setFormFlattening(false);// 如果为false那么生成的PDF文件还能编辑,一定要设为true
stamper.close();
}
//将之前的两次输出
PdfImportedPage page = null;
for (int i = 0; i < 2; i++) {
page = copy.getImportedPage(new PdfReader(bos[i].toByteArray()), i + 1);
copy.addPage(page);
}
//复制两次
for (int j=0;j<2;j++){
PdfReader reader = new PdfReader(templatePath);// 重新读取pdf模板
bos[j]=new ByteArrayOutputStream();
reader.selectPages("2-2");//截取模板的第二页
PdfStamper stamper = new PdfStamper(reader, bos[j]);
AcroFields fields = stamper.getAcroFields();
fields.setField("img", "这是第"+j+"张图片");
page = copy.getImportedPage(reader, 1);//输出当前页
copy.addPage(page);
}
doc.close();
out.close();
} catch (IOException e) {
System.out.println("导出异常");
} catch (DocumentException e) {
System.out.println("文档异常");
}
这就是我的实现方式了,如果你有更好的方式,欢迎提出来。
下面粘贴几个参考链接:
1.java根据模板生成pdf文件并导出 https://blog.csdn.net/top__one/article/details/65442390
2.java根据模板动态生成PDF https://segmentfault.com/a/1190000009160184