Bootstrap

itext5 PdfStamper渲染 设置BaseFont字体,但是生成pdf文件过大

遇到的问题

1.addSubstitutionFont  设置字体填充不生效,以及生成的pdf文件过大

解决:删除itext-asian 包引用

2.BaseFont无法设置粗体

解决:用getFieldPositions 加载文本框 通过Font类来设置粗体.

3.文本框设置粗体大号文字产生位移

解决:自己调整new Paragraph 的几个参数控制.

pom必须引入
 


        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.83</version>
        </dependency>
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>itextpdf</artifactId>
            <version>5.4.3</version>
        </dependency>
        <dependency>
            <groupId>com.itextpdf.tool</groupId>
            <artifactId>xmlworker</artifactId>
            <version>5.4.1</version>
        </dependency>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.0</version>
        </dependency>

通用生成示例

package com.example.pdftmpelet;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.itextpdf.text.*;
import com.itextpdf.text.pdf.*;

import java.io.*;
import java.util.List;

/**
 * 使用pdf模板生成pdf文件
 */
public class WriteToPDF {

    public static String create(String mobanPath,String fileName,String textFields,String imgFields) {
        JSONArray text=JSONArray.parseArray(textFields);
        JSONArray img=JSONArray.parseArray(imgFields);
            
        File f=new File("D:\\"+fileName+System.currentTimeMillis()+".pdf");

        OutputStream os = null;
        PdfStamper ps = null;
        PdfReader reader = null;
        try {
            // 1 获取文件的输出流
            os = new FileOutputStream(f);
            // 2 读取pdf模板
            reader = new PdfReader(mobanPath);
            // 3 根据表单生成一个新的pdf
            ps = new PdfStamper(reader, os);
            // 4 获取pdf表单
            AcroFields form = ps.getAcroFields();
            ps.setFormFlattening(true);


            // 拼接字体文件的完整路径

            // 5 给表单添加中文字体
            BaseFont font = BaseFont.createFont("C:/Windows/Fonts/simsun.ttc,0", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
            font.setSubset(true);
            form.addSubstitutionFont(font);

            // 6遍历data赋值到form
            if(text!=null && text.size()>0){
                for (int i = 0; i < text.size(); i++) {
                    JSONObject o = text.getJSONObject(i);
                    String key=o.getString("KEY");
                    String value=o.getString("VALUE");
                    String fontsize=o.getString("SIZE");
                    String ifBlod=o.getString("BLOD");
                    Float sze=12f;
                    try {
                        sze=fontsize==null?sze:Float.parseFloat(fontsize);
                    }catch (Exception e){
                        System.out.println("font size error!"+fontsize);
                    }
                    //如果是加粗就使用 Rectangle 写入, 这里有个坑, 字号过大会跑出去. 可以自己调整new Rectangle 的几个值来兼容.
                    if("Y".equals(ifBlod)){
                        int tpdd=sze.intValue()-12-2;
                        Font blod = new Font(font, sze, Font.BOLD);
                        List<AcroFields.FieldPosition> multiLinePosition = form.getFieldPositions(key);
                        int page = multiLinePosition.get(0).page;
                        Rectangle rectangle = multiLinePosition.get(0).position;
                        float left = rectangle.getLeft();
                        float right = rectangle.getRight();
                        float top = rectangle.getTop();
                        float bottom = rectangle.getBottom();
                        PdfContentByte pdfContentByte = ps.getOverContent(page);
                        ColumnText columnText = new ColumnText(pdfContentByte);
                        Rectangle r = new Rectangle(left, bottom, right, top-(tpdd>0?tpdd:0));
                        columnText.setSimpleColumn(r);
                        Chunk chunk = new Chunk(value);

                        Paragraph paragraph = new Paragraph(12, chunk);
                        columnText.addText(paragraph);
                        paragraph.setFont(blod);
                        columnText.addElement(paragraph);
                        columnText.go();
                    }else{
                        form.setFieldProperty(key, "textsize", sze, null);
                        form.setFieldProperty(key, "spacing", 1f, null);
                        form.setField(key, value);
                    }

                }

            }

            
            // 7 填充图片到form
            PdfStamper stamper = ps;

            if(img!=null && img.size()>0){
                for (int i = 0; i < img.size(); i++) {
                    JSONObject o = img.getJSONObject(i);
                    String key=o.getString("KEY");
                    String value=o.getString("VALUE");

                    try {
                        List<AcroFields.FieldPosition> fieldPositions = form.getFieldPositions(key);
                        for (AcroFields.FieldPosition fieldPosition : fieldPositions) {
                            // 通过域名获取所在页和坐标,左下角为起点
                            int pageno = fieldPosition.page;
                            Rectangle signrect = fieldPosition.position;
                            float x = signrect.getLeft();
                            float width = signrect.getWidth();
                            float y = signrect.getBottom();
                            // 读图片
                            Image image = Image.getInstance(value);
                            float img_width = image.getWidth();
                            // 获取操作的页面
                            PdfContentByte under = stamper.getOverContent(pageno);
                            // 图片的大小
                            image.scaleToFit(signrect.getWidth(), signrect.getHeight());
                            // 添加图片
                            image.setAbsolutePosition(x, y);
                            under.addImage(image);
                        }
                    } catch (BadElementException e) {
                        e.printStackTrace();
                    } catch (IOException e) {
                        e.printStackTrace();
                    } catch (DocumentException e) {
                        e.printStackTrace();
                    }

                }

            }

        } catch (Exception e) {
            e.printStackTrace();
            return null;
        } finally {
            try {
                ps.close();
                reader.close();
                os.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
 


        return f.getAbsolutePath();
    }




    public static void main(String[] args) {
        String text="[{\"KEY\":\"文本域名称\",\"VALUE\":\"填充值\",\"SIZE\":\"20\",\"BLOD\":\"Y\"},{\"KEY\":\"文本域名称\",\"VALUE\":\"123123\"},{\"KEY\":\"文本域名称\",\"VALUE\":\"123123\",\"BLOD\":\"Y\"},{\"KEY\":\"文本域名称\",\"VALUE\":\"123456\"}]";
        String img="[{\"KEY\":\"图片渲染\",\"VALUE\":\"本地图片绝对路径或者网络图片url\"}]";
        //生成pdf文件 通过json指定一堆待填充 的文本域名称, 值, 字号, 是否加粗 
        String rsp=create("D:\\moban.pdf","测试1",text,img);
        System.out.println(rsp);
    }



}

;