PDF模板填充,基于IText5

前言

对于PDF模板填充,有很多现有的Java库,付费版本略过。

较出名的有Apache的PDFBox,以及ITextPdf。

而后者具有两个很大的版本ITextPdf-5和ITextPdf-7,ITextPdf-7功能更强大,但可能存在商业版权问题。之前也用过一阵,没驾驭住。

今天使用 ITextPdf-5,支持文本填充、图片填充 、添加页码 及 PDF文档合并。

依赖引入


    com.itextpdf
    itextpdf
    5.5.13.3


    com.itextpdf
    itext-asian
    5.2.0

工具代码

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 final 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(getDefaultFont());

        // 执行填充
        doFill(stamper, form, fillData);

        // 添加页码
        if (addPageNumber) {
            int pages = reader.getNumberOfPages();
            for (int i = 1; i < pages; i++) {
                addPageNumber(stamper, i);
            }
        }

        // 清除表单域可编辑状态
        stamper.setFormFlattening(true);
        stamper.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 addPageNumber(PdfStamper stamper, int pageNumber) { PdfContentByte contentByte = stamper.getOverContent(pageNumber); contentByte.beginText(); contentByte.setFontAndSize(baseFont, pageNumberFontSize); Rectangle rectangle = stamper.getReader().getPageSize(pageNumber); // 页码的 横轴 坐标 居中 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(List pdfs) throws Exception { ByteArrayOutputStream out = new ByteArrayOutputStream(); Document document = new Document(); PdfCopy copy = new PdfCopy(document, out); document.open(); for (PdfReader reader : pdfs) { // 获取PDF文件总页数 int n = reader.getNumberOfPages(); for (int i = 1; i <= n; i++) { document.newPage();// 创建新页面 PdfImportedPage page = copy.getImportedPage(reader, i); copy.addPage(page); } } 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); } }

后续

动态表格填充实现较为困难,知道的大佬欢迎骚扰(⊙o⊙)…

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