当前位置: 首页 > article >正文

itext - PDF模板套打

目录

环境配置

快速使用

代码实现

添加图片

封装


项目需求:获取列表数据之后直接将数据生成一个pdf。因此需要使用到 itext 对pdf进行直接操作。

环境配置

需要为pdf添加文字域,因此需要安装Adobe Acrobat

准备一个空的PDF文件,如果有现成的模板更好

依赖配置,我们使用itext的7版本

        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>itext7-core</artifactId>
            <version>7.2.3</version>
            <type>pom</type>
        </dependency>

快速使用

使用Adobe Acrobat Pro DC打开空PDF,使用 文字域 工具为PDF添加文字域,要注意为每个文字域命名。

如果你有现成的模板PDF,直接使用识别域可以识别空白区域然后自动生成文字域,但是一般都不太准确

如果你的单个数据很多的话,可以在属性中设置多行 

设置完文字域之后记得保存。

代码实现

@SpringBootTest
class StickerApplicationTests {
    private static final String TEMP_PATH = "C:\\Users\\An1ong\\Desktop\\Stickers.pdf";

    //生成PDF的位置
    private static final String DEST_PATH = "C:\\Users\\An1ong\\Desktop\\StickersOut.pdf";

    //本地上字体的路径
    private static final String FONT_PATH = "";

    @Autowired
    private StickerService stickerService;

    @Test
    void contextLoads() throws IOException {

        //创建一个新的PDF文件,并写入数据
        PdfReader reader = new PdfReader(TEMP_PATH);

        // 创建一个 PdfWriter 对象以写入新的PDF
        PdfWriter writer = new PdfWriter(DEST_PATH);

        // 创建一个 PdfDocument 对象
        PdfDocument pdfDoc = new PdfDocument(reader, writer);

        // 获取 PDF 表单
        PdfAcroForm form = PdfAcroForm.getAcroForm(pdfDoc, false);

        //获得数据,准备填充
        List<Sticker> stickerList = stickerService.list(10);

        //文本填充
        for(int i = 0; i < stickerList.size();i++){
            Sticker sticker = stickerList.get(i);

            // 生成自定义序号,格式为 "001"、"002"、"003"
            String customId = String.format("%03d", i + 1);

            String idFieldName = "id" + (i + 1);
            String nameFieldName = "name" + (i + 1);

            PdfFormField idField = form.getField(idFieldName);
            if (idField != null) {
                idField.setValue(customId);
            }

            PdfFormField nameField = form.getField(nameFieldName);
            if (nameField != null) {
                nameField.setValue(sticker.getStickerName());
            }

        }


        //消除掉表单域
        form.flattenFields();

        //关闭流
        pdfDoc.close();
    }
}

行数也不算少,但里面的逻辑其实很简单。这是一个Springboot的单元测试,我调用service中的方法获取了一个装着对象的列表。

用PdfReader读取你要套写的模板,用PdfWriter将数据写入模板。创建出一个PdfDocument对象并将这两个参数传入就可以开始对PDF操作了。

注意,这个过程不会直接在原PDF上操作,而是生成一个新的PDF进行操作,程序结束后原PDF模版还是空白的。

 PdfAcroFrom获取PDF表单,然后PdfFormField获取其中的文字域,最后使用for循环动态的将数据套打在模板上就完成了。

最终会生成一个新的文件

最终效果:

之所以要在最后调用form.flattenFields消除掉表单域是因为如果不消除表单域的话就会变成这样。


更新......

添加图片

现在又有新的需求,除了自定义序号和文本之外,还要每个的后面添加图片。

添加文本域

代码实现

PdfFormField imgField = form.getField(imgFieldName);
            if (imgField != null){
                List<PdfWidgetAnnotation> widgets = imgField.getWidgets();
                PdfWidgetAnnotation widget = widgets.get(0);

                float x1 = widget.getRectangle().getAsNumber(0).floatValue();
                float y1 = widget.getRectangle().getAsNumber(1).floatValue();

                float x2 = widget.getRectangle().getAsNumber(2).floatValue();
                float y2 = widget.getRectangle().getAsNumber(3).floatValue();

                float fieldWidth = x2 - x1;
                float fieldHeight = y2 - y1;

                Image image = img.scaleToFit(fieldWidth,fieldHeight);


                image.setFixedPosition(x1,y1);

                Document document = new Document(pdfDoc);
                document.add(image);
            }

由于文本域是放置文本的,不能直接放置一个图片上去。所以我们实现的思路是,在放置图片的位置一个文本域,然后根据文本域的坐标将图片移过去,这就是这段代码的思路。

可以得到文本域左下角坐标和右上角坐标 ,通过简单的数学计算得到这块矩形的长和宽,然后使用scaleToFit就可以让图片的长和宽与文字域矩形的长宽一样了。

封装

我们可以把这个在单元测试中的程序封装成工具类重复使用

package com.wal.sticker.util;

import com.itextpdf.forms.PdfAcroForm;
import com.itextpdf.forms.fields.PdfFormField;
import com.itextpdf.io.image.ImageDataFactory;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfReader;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.kernel.pdf.annot.PdfWidgetAnnotation;
import com.itextpdf.layout.Document;
import com.itextpdf.layout.element.Image;
import com.wal.sticker.pojo.Sticker;

import java.io.IOException;
import java.net.URISyntaxException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;

public class PdfPrintUtil {

//    private static final String TEMP_PATH = "C:\\Users\\An1ong\\Desktop\\Stickers.pdf";
//
//    private static final String DEST_PATH = "C:\\Users\\An1ong\\Desktop\\StickersOut.pdf";

    public static void printPDF(String DEST_PATH,List<Sticker> stickerList) throws IOException, URISyntaxException {

        String TEMP_PATH = getResourcePath("templates/background.pdf");
        String IMG_PATH = getResourcePath("static/img/buttonImg.png");


        //创建一个新的PDF文件,并写入数据
        PdfReader reader = new PdfReader(TEMP_PATH);

        // 创建一个 PdfWriter 对象以写入新的PDF
        PdfWriter writer = new PdfWriter(DEST_PATH);

        // 创建一个 PdfDocument 对象
        PdfDocument pdfDoc = new PdfDocument(reader, writer);

        // 获取 PDF 表单
        PdfAcroForm form = PdfAcroForm.getAcroForm(pdfDoc, false);

        // 加载图片
        Image img = new Image(ImageDataFactory.create(IMG_PATH));

        //文本和图片填充
        for(int i = 0; i < stickerList.size();i++){

            Sticker sticker = stickerList.get(i);

            // 生成自定义序号,格式为 "001"、"002"、"003"
            String customId = String.format("%03d", i + 1);

            String idFieldName = "id" + (i + 1);
            String nameFieldName = "text" + (i + 1);
            String imgFieldName = "img" + (i + 1);

            PdfFormField idField = form.getField(idFieldName);
            if (idField != null) {
                idField.setValue(customId);
            }

            PdfFormField nameField = form.getField(nameFieldName);
            if (nameField != null) {
                nameField.setValue(sticker.getStickerName());
            }


            // 添加图像

            PdfFormField imgField = form.getField(imgFieldName);
            if (imgField != null){
                List<PdfWidgetAnnotation> widgets = imgField.getWidgets();
                PdfWidgetAnnotation widget = widgets.get(0);

                float x1 = widget.getRectangle().getAsNumber(0).floatValue();
                float y1 = widget.getRectangle().getAsNumber(1).floatValue();

                float x2 = widget.getRectangle().getAsNumber(2).floatValue();
                float y2 = widget.getRectangle().getAsNumber(3).floatValue();

                float fieldWidth = x2 - x1;
                float fieldHeight = y2 - y1;

                Image image = img.scaleToFit(fieldWidth,fieldHeight);
//
//                float scaledWidth = image.getImageScaledWidth();
//                float scaledHeight = image.getImageScaledHeight();
//
//                float centerX = x1 + (fieldWidth / 2) - (scaledWidth / 2);
//                float centerY = x2 + (fieldHeight / 2) - (scaledHeight / 2);

                image.setFixedPosition(x1,y1);

                Document document = new Document(pdfDoc);
                document.add(image);
            }

        }


        //消除掉表单域
//        form.flattenFields();

        //关闭流
        pdfDoc.close();
    }

    private static String getResourcePath(String fileName) throws URISyntaxException {
        ClassLoader classLoader = PdfPrintUtil.class.getClassLoader();
        Path path = Paths.get(classLoader.getResource(fileName).toURI());
        return path.toString();
    }



}


http://www.kler.cn/a/145926.html

相关文章:

  • JS宏进阶:正则表达式介绍
  • 【华为路由/交换机的ftp文件操作】
  • 神经网络常见面试题
  • 5、docker-compose和docker-harbor
  • 网络安全 | 什么是正向代理和反向代理?
  • 深度学习中的张量 - 使用PyTorch进行广播和元素级操作
  • GPT4测试 — 答题能力及文档处理能力
  • 简单介绍一下js中的构造函数、原型对象prototype、对象原型__proto__、原型链
  • Linux编辑器vim
  • 阿里云MQTT: 子设备上线流程
  • MFC居中显示文字及其应用
  • Java-使用poi-tl根据word模板动态生成word
  • js逆向-某敏感网站登录参数分析
  • QT已有项目导入工程时注意事项
  • STL pair源码分析
  • Windows开启SQL Server服及1433端口
  • [蓝桥杯训练]———高精度乘法、除法
  • 『heqingchun-Ubuntu系统+x86架构+编译安装ffmpeg+带有nvidia硬件加速』
  • Linux7安装mysql数据库以及navicat远程连接mysql
  • Java8实战-总结49
  • jupyter notebook 不知道密码,怎么登录解决办法
  • Spring Boot Actuator 2.2.5 基本使用
  • 代码随想录算法训练营 ---第四十五天
  • 什么是工业物联网(IOT)?这样的IOT平台你需要吗?——青创智通
  • MySQL(免密登录)
  • 【STM32单片机】贪吃蛇游戏设计