\import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Element;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.*;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.Map;
/**
* PDF模板填充,基于itext-pdf-v5
*/
public class PDFTemplateFiller {
/**
* 模板
*/
private transient PdfReader reader;
/**
* 字体
*/
private BaseFont baseFont;
/**
* 是否添加页码
*/
private boolean addPageNumber;
/**
* 页码字体大小
* {@link #addPageNumber}为true时有效
*/
private float pageNumberFontSize = 14F;
/**
* 页码左边样式字符
* {@link #addPageNumber}为true时有效
*/
private String pageNumberLeft = "";
/**
* 页码邮编样式字符
* {@link #addPageNumber}为true时有效
*/
private String pageNumberRight = "";
/**
* 填充模板,返回填充后文件
*
* @param fillData - 待填充数据
* @return - 填充后文件字节数据
*/
public byte[] fill(Map<String, Object> fillData) throws DocumentException, IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
PdfStamper stamper = new PdfStamper(reader, out);
AcroFields form = stamper.getAcroFields();
// 设置字体
form.addSubstitutionFont(baseFont);
// 执行填充
doFill(stamper, form, fillData);
// 清除表单域可编辑状态
stamper.setFormFlattening(true);
stamper.close();
reader.close();
// 是否需要添加页码,则需要重新将填充后的PDF文档加载进reader中
byte[] filedData = out.toByteArray();
if (addPageNumber) {
this.reader = new PdfReader(filedData);
return pageNumber();
}
return filedData;
}
/**
* 添加页码
*
* @return
* @throws DocumentException
*/
public byte[] pageNumber() throws DocumentException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
Document document = new Document();
PdfWriter writer = PdfWriter.getInstance(document, out);
document.open();
int pages = reader.getNumberOfPages();
for (int i = 1; i <= pages; i++) {
document.newPage();
doAadPageNumber(writer, i);
PdfImportedPage page = writer.getImportedPage(reader, i);
writer.getDirectContent().addTemplate(page, 0, 0);
}
document.close();
reader.close();
return out.toByteArray();
}
/**
* 是否添加页码(默认:否)
*
* @param isAddPageNumber - true-添加/false-不添加
*/
public PDFTemplateFiller pageNumber(boolean isAddPageNumber) {
this.addPageNumber = isAddPageNumber;
return this;
}
/**
* <pre>
* 设置字体(默认:STSong-Light)
* 通过 {@link com.itextpdf.text.pdf.BaseFont#createFont(java.lang.String, java.lang.String, boolean)}创建
* </pre>
*
* @param baseFont - 待设值字体
*/
public PDFTemplateFiller font(BaseFont baseFont) {
this.baseFont = baseFont;
return this;
}
/**
* 页码样式设置
* <p>
* {@link #addPageNumber}为true时有效
*
* @param pageNumberLeft - 页码左边样式字符
* @param pageNumberRight - 页码邮编样式字符
*/
public PDFTemplateFiller pageNumberStyle(String pageNumberLeft, String pageNumberRight) {
this.pageNumberLeft = pageNumberLeft;
this.pageNumberRight = pageNumberRight;
return this;
}
/**
* 根据表单域字段名查找其对应所在页码
*
* @param form - 表单对象
* @param fieldName - 表单域属性名
* @return - 找到返回具体页码(起始页为1);否则返回-1
*/
private int findPageNumber(AcroFields form, String fieldName) {
List<AcroFields.FieldPosition> positions = form.getFieldPositions(fieldName);
if (positions == null || positions.isEmpty()) {
return -1;
}
return positions.get(0).page;
}
/**
* 填充文本
*/
private void doFill(PdfStamper stamper, AcroFields form, Map<String, Object> fillData) throws DocumentException, IOException {
for (Map.Entry<String, Object> entry : fillData.entrySet()) {
if (entry.getValue() instanceof byte[]) {
doFillImage(stamper, entry.getKey(), (byte[]) entry.getValue());
} else {
form.setField(entry.getKey(), String.valueOf(entry.getValue()));
}
}
}
/**
* 填充图片
*/
private void doFillImage(PdfStamper stamper, String fieldName, byte[] image) throws DocumentException, IOException {
AcroFields form = stamper.getAcroFields();
List<AcroFields.FieldPosition> positions = form.getFieldPositions(fieldName);
if (positions != null && !positions.isEmpty()) {
AcroFields.FieldPosition position = positions.get(0);
Rectangle rectangle = position.position;
com.itextpdf.text.Image img = com.itextpdf.text.Image.getInstance(image);
// 根据域的大小缩放图片
img.scaleToFit(rectangle.getWidth(), rectangle.getHeight());
img.setAbsolutePosition(rectangle.getLeft(), rectangle.getBottom());
stamper.getOverContent(position.page).addImage(img);
}
}
/**
* 添加页码
*/
private void doAadPageNumber(PdfWriter writer, int pageNumber) {
PdfContentByte contentByte = writer.getDirectContent();
contentByte.beginText();
contentByte.setFontAndSize(baseFont, pageNumberFontSize);
Rectangle rectangle = writer.getPageSize();
// 页码的 横轴 坐标 居中
float x = (rectangle.getLeft() + rectangle.getRight()) / 2;
contentByte.showTextAligned(Element.ALIGN_CENTER, String.format("%s%d%s", pageNumberLeft, pageNumber, pageNumberRight), x, 20, 0);
contentByte.endText();
}
/**
* 合并多个PDF文件到一个PDF中
*
* @param pdfs - 待合并的PDF 文件
* @return byte - 合并后的PDF流
*/
public static byte[] merge(File... pdfs) throws Exception {
PdfReader[] array = new PdfReader[pdfs.length];
for (int i = 0; i < pdfs.length; i++) {
array[i] = new PdfReader(pdfs[i].getAbsolutePath());
}
return merge(array);
}
/**
* 合并多个PDF文件到一个PDF中
*
* @param pdfs - 待合并的PDF 文件
* @return byte - 合并后的PDF流
*/
public static byte[] merge(byte[]... pdfs) throws Exception {
PdfReader[] array = new PdfReader[pdfs.length];
for (int i = 0; i < pdfs.length; i++) {
array[i] = new PdfReader(pdfs[i]);
}
return merge(array);
}
/**
* 合并多个PDF文件到一个PDF中
*
* @param pdfs - 待合并的PDF 文件
* @return byte - 合并后的PDF流
*/
public static byte[] merge(PdfReader... pdfs) throws Exception {
ByteArrayOutputStream out = new ByteArrayOutputStream();
Document document = new Document();
PdfCopy copy = new PdfCopy(document, out);
document.open();
for (PdfReader reader : pdfs) {
for (int i = 1, pages = reader.getNumberOfPages(); i <= pages; i++) {
copy.addPage(copy.getImportedPage(reader, i));
}
reader.close();
}
copy.close();
document.close();
return out.toByteArray();
}
public static PDFTemplateFiller load(InputStream pdfTemplate) throws IOException, DocumentException {
return new PDFTemplateFiller(new PdfReader(pdfTemplate));
}
public static PDFTemplateFiller load(File pdfTemplate) throws IOException, DocumentException {
return new PDFTemplateFiller(new PdfReader(pdfTemplate.getAbsolutePath()));
}
public static PDFTemplateFiller load(byte[] pdfTemplate) throws IOException, DocumentException {
return new PDFTemplateFiller(new PdfReader(pdfTemplate));
}
public static PDFTemplateFiller load(ByteArrayOutputStream pdfTemplate) throws IOException, DocumentException {
return load(pdfTemplate.toByteArray());
}
private PDFTemplateFiller(PdfReader pdfReader) throws DocumentException, IOException {
this.reader = pdfReader;
this.baseFont = getDefaultFont();
this.addPageNumber = false;
}
/**
* 获取默认的字体(宋体)
*/
private BaseFont getDefaultFont() throws DocumentException, IOException {
return BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
}
}
测试demo
public static void main(String[] args) throws Exception {
String templatePath = "/path/模板.pdf";
byte[] avatar = IOUtils.toByteArray(Files.newInputStream(Paths.get("/path/avatar.jpg")));
Map<String, Object> fillData = new HashMap<>();
fillData.put("name", "Ian");
fillData.put("gender", "男");
fillData.put("addr", "贵州省贵阳市");
fillData.put("avatar", avatar);
fillData.put("avatar1", avatar);
String date = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
byte[] bytes = PDFTemplateFiller.load(Files.newInputStream(Paths.get(templatePath)))
.pageNumber(true)
.pageNumberStyle("-< ", " >-")
.fill(fillData);
write(bytes, "/path/" + date + ".pdf");
File dir = new File("/path/pdfdata/");
File[] files = dir.listFiles((file, name) -> name.endsWith(".pdf"));
assert files != null;
byte[] bytes1 = PDFTemplateFiller.merge(files);
write(bytes1, "/path/merged" + date +".pdf");
}
static void write(byte[] bytes, String dest) throws IOException {
IOUtils.write(bytes, Files.newOutputStream(Paths.get(dest)));
}