PDF模板填充,基于IText5(改进版)

原版: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)));
    }

你可能感兴趣的:(Java专栏,工具,pdf,java)