zoukankan      html  css  js  c++  java
  • Itext5生成PDF

    Itext

    官网

    Java操作pdf方法

    1. 通过Adobe Acrobat生成pdf form,通过Java设置form表单中的元素值进行数据填充。
    2. 读取pdf通过坐标进行填充数据,绘制成结果pdf。
    3. 通过itext代码绘制pdf。

    Acrobat制作模板

    先用Excel制作一个Excel模板,另存为PDF文件。

    制作Excel模板

    Excel另存为PDF

    用Adobe Acrobat Pro DC打开PDF模板文件,打开表单功能,在指定地方添加文字域,模板即可制作完成。

    Java代码填充AcroField

    Java代码对Acrobat制作的PDF中的Form进行填充。

    Maven坐标

    <properties>
        <itextpdf.version>5.5.6</itextpdf.version>
    </properties>
    
    <dependencies>
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>itextpdf</artifactId>
            <version>${itextpdf.version}</version>
        </dependency>
        <dependency>
            <groupId>com.itextpdf.tool</groupId>
            <artifactId>xmlworker</artifactId>
            <version>${itextpdf.version}</version>
        </dependency>
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>itext-asian</artifactId>
            <version>5.2.0</version>
        </dependency>
    </dependencies>
    

    Java代码

    //设置字体
    //BaseFont bfChinese = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
    /*模板*/
    PdfReader reader = new PdfReader("发票模板.pdf");
    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    PdfStamper ps = new PdfStamper(reader, bos);
    /*使用中文字体 使用 AcroFields填充值的不需要在程序中设置字体,在模板文件中设置字体为中文字体 Adobe 宋体 std L*/
    AcroFields s = ps.getAcroFields();
    //设置表单的key-value值
    //通过s.setFieldProperty("字段名", "textfont", BaseFont , null); 设置字段的字体格式或者在模板中修改样式
    //s.setFieldProperty("checkNo","textfont",bfChinese,null); //只有第一个字段是变量,其他的都固定死,这样可以解决Acro默认字段时中文只显示最后一位的问题。
    s.setField("checkNo", "20210204");
    s.setField("$info$", "测试单位");
    s.setField("$projectName_1$", "测试项目");
    s.setField("$num_1$", "2");
    s.setField("$bw_1$", "1");
    s.setField("$amount_1$", "100000000");
    s.setField("$total$", "壹佰万整");
    s.setField("$bz_1$", "个");
    s.setField("$SKR$", "测试人");
    s.setField("$SKDW$", "测试单位");
    s.setField("$year$", "2021");
    s.setField("$month$", "11");
    s.setField("$day$", "08");
    // 设为true,设置为false后生成的pdf依然可编辑
    ps.setFormFlattening(true);
    ps.close();
    
    /*输出到指定位置*/
    FileOutputStream fos = new FileOutputStream("d:\发票.pdf");
    fos.write(bos.toByteArray());
    

    输出展示

    可能遇到的问题

    批量设置字体

    使用默认表单域中文字段一定要s.setFieldProperty("字段名", "textfont", BaseFont , null)设置中文字体,否则显示可能出问题。
    居中显示等样式需要在adobe acrobat中显示。

    给每个表单域都添加代码

    s.getFields().forEach((k, v) -> {
    	s.setFieldProperty(k, "textfont", BaseFont, null);
            s.setFieldProperty(k, "textsize", Float.valueOf("14"), null);
    });
    

    文字超出表单域

    换行法

    换行法就是增加单元格高度,先在adobe acrobat中设置表单文字域属性->选项->勾选多行,然后判断文字宽度是否大于表单域,如果大于,则展示的表单域高度增加。

    /**
     * 判断字体是否超出文本域长度
     * @param filedVal 表单域的值
     * @param filedName 表单域的key
     * @param form 表单域实例
     * @return 文本超过表单域的返回true
     * @throws IOException
     * @throws DocumentException
     */
    public static boolean checkLength(String filedVal, String filedName, AcroFields form) throws IOException, DocumentException {
        float fontSize = 12f;
        boolean flag = false;
        BaseFont baseFont = BaseFont.createFont("STSongStd-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
        float textWidth = baseFont.getWidthPoint(filedVal, fontSize);
        Rectangle position = form.getFieldPositions(filedName).get(0).position;
        float textBoxWidth = position.getWidth();
        if (textWidth > textBoxWidth) {
            flag = true;
        }
        return flag;
    }
    
    
    /*使用,首先在adobe acrobat中设置表单文字域属性->选项->勾选多行*/
    boolean b = checkLength("超出表单域宽度的金额.........","$amount_1$",s);
    if (b){  //如果超过了,则修改表单域的大小,使其显示的高度+16
        /*获取当前文本框的尺寸,返回的数据依次为左上右下(0,1,2,3)*/
        PdfArray rect1 = s.getFieldItem("$amount_1$").getValue(0).getAsArray(PdfName.RECT);
        rect1.set(1, new PdfNumber(rect1.getAsNumber(1).intValue() - 16));
    }
    s.setField("$amount_1$", "超出表单域宽度的金额.........");
    

    缩小字体

    单行,用缩小字体方法单行显示字体。

    /**
     * 判断字体是否超出文本域长度
     * @param fieldVal 表单域的值
     * @param filedName 表单域的key
     * @param form 表单域实例
     * @return 字体大小
     * @throws IOException
     * @throws DocumentException
     */
    public static float checkLengthFront(String fieldVal, String filedName, AcroFields form) throws IOException, DocumentException {
        BaseFont baseFont = BaseFont.createFont("STSongStd-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
        float fontSize = 12f;
        Rectangle position = form.getFieldPositions(filedName).get(0).position;
        float textBoxWidth = position.getWidth();
        /*文本框高度*/
        float textBoxHeight = position.getHeight();
        /*文本单行行高*/
        float ascent = baseFont.getFontDescriptor(baseFont.ASCENT, fontSize);
        /*baseFont渲染后的文字宽度*/
        float textWidth = baseFont.getWidthPoint(fieldVal, fontSize);
    
        /*文本框高度只够写一行,并且文字宽度大于文本框宽度,则缩小字体*/
        if (textBoxHeight < ascent * 1.6) {
            while (textWidth > textBoxWidth) {
                fontSize--;
                textWidth = baseFont.getWidthPoint(fieldVal, fontSize);
            }
        }
        return fontSize;
    }
    
    /*使用*/
    float fsize= checkLengthFront("超出表单域宽度的金额.........", "$amount_1$",s);  //计算字体大小并返回
    s.setFieldProperty("$amount_1$", "textsize", fsize , null);  //设置字体大小
    s.setField("$amount_1$", "超出表单域宽度的金额.........");
    

    选框样式差号BUG

    在制作模板时,放入一组Radio或者CheckBox,无论样式选择成什么,结果都是显示一个x号。

    解决办法:把com.itextpdf.itextpdf核心包从5.5.6降到5.2.1/5.3.0/5.5.0/5.5.1/5.5.2/5.5.3/5.5.4,经过多次测试,发现就是不能超过5.5.5,一旦超过5.5.5就会出现差,到5.5.7时Radio会变成圆点样式但是CheckBox依然是差,所以我选择最接近5.5.6的5.5.4。

    <dependency>
        <groupId>com.itextpdf</groupId>
        <artifactId>itextpdf</artifactId>
        <version>5.5.4</version>
    </dependency>
    <dependency>
        <groupId>com.itextpdf.tool</groupId>
        <artifactId>xmlworker</artifactId>
        <version>5.5.6</version>
    </dependency>
    <dependency>
        <groupId>com.itextpdf</groupId>
        <artifactId>itext-asian</artifactId>
        <version>5.2.0</version>
    </dependency>
    

    通过选择框的名称和值来打勾

    s.setField("RadioGroup", "1");
    s.setField("CheckBox", "1");
    

    最终样式

    参考:

    https://blog.csdn.net/u011391773/article/details/53084231

    https://blog.csdn.net/sand_clock/article/details/85328849

    如果这篇文章对你有用,麻烦关注一下本人微信公众号,关注送福利哦~
    微信公众号二维码
    不定期安利各种插件,编程技巧,编程思想,欢迎交流~
  • 相关阅读:
    解决Python开发中,Pycharm中无法使用中文输入法问题
    PointNet++作者的视频讲解文字版
    StringBuilder
    DropDownList 添加“请选择”
    SQLServer 2008中SQL增强之三 Merge(在一条语句中使用
    ASP.NET Web Forms 的 DI 應用範例
    怎么设置环境变量
    ParameterizedThreadStart,ThreadStart的使用,线程Thread传参数
    异步删除
    SqlCommandBuilder的作用
  • 原文地址:https://www.cnblogs.com/aeolian/p/14373581.html
Copyright © 2011-2022 走看看