原版: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
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; } /** * * 设置字体(默认:STSong-Light) * 通过 {@link com.itextpdf.text.pdf.BaseFont#createFont(java.lang.String, java.lang.String, boolean)}创建 ** * @param baseFont - 待设值字体 */ public PDFTemplateFiller font(BaseFont baseFont) { this.baseFont = baseFont; return this; } /** * 页码样式设置 *
* {@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
positions = form.getFieldPositions(fieldName); if (positions == null || positions.isEmpty()) { return -1; } return positions.get(0).page; } /** * 填充文本 */ private void doFill(PdfStamper stamper, AcroFields form, Map fillData) throws DocumentException, IOException { for (Map.Entry 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 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 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)));
}