原版:PDF模板填充,基于IText5-CSDN博客
\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)));}