java动态生成pdf文件(使用itext编辑pdf)

本文介绍了如何在Java中使用iText库,通过PDFelement创建模板并动态插入数据和图片,即使在困难时期也能保持技能更新。面对公司变动,作者分享了关键步骤和合并PDF的方法,适合开发者在不确定的工作环境中提升技能。

😔下午刚上班就得到个悲痛得消息,上家工作就干了两个月公司干不下去了,现在老板被抓了。工资还不知道什么时候有着落。/(ㄒoㄒ)/~~忍痛更新一篇博客记录下最近做得其中一个功能。
更加详细的使用方法可以访问我另一篇文章:java使用itext编辑pdf,动态生成pdf文件(从利用Adobe创建pdf模板开始一步步详细介绍)

一、创建pdf模板

使用PDFelement制作pdf模板(数据域的名称对应后面插入的key)
 在这里插入图片描述

二、导入maven依赖

<dependency>
    <groupId>com.itextpdf</groupId>
    <artifactId>itextpdf</artifactId>
    <version>5.5.13</version>
</dependency>

<dependency>
    <groupId>com.itextpdf</groupId>
    <artifactId>itext-asian</artifactId>
    <version>5.2.0</version>
</dependency>  

三、插入数据和图片到pdf模板

Map<String, Object> data;//要插入的数据
        //初始化itext
        //设置编码
        BaseFont baseFont = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H",BaseFont.NOT_EMBEDDED);
        PdfReader pdfReader=new PdfReader(“pdf模板文件路径”);
        PdfStamper pdfStamper=new PdfStamper(pdfReader, new FileOutputStream(“输出pdf文件路径”));
        AcroFields form = pdfStamper.getAcroFields();
        form.addSubstitutionFont(baseFont);

        //写入数据
        for(String key:data.keySet()){
            String value=data.get(key).toString();
            //key对应模板数据域的名称
            form.setField(key,value);
        }

        //添加图片
        int pageNo = form.getFieldPositions("img").get(0).page;
        Rectangle signRect = form.getFieldPositions("img").get(0).position;
        float x = signRect.getLeft();
        float y = signRect.getBottom();
        Image image = Image.getInstance("图片路径");
        PdfContentByte under = pdfStamper.getOverContent(pageNo);
        //设置图片大小
        image.scaleAbsolute(signRect.getWidth(), signRect.getHeight());
        //设置图片位置
        image.setAbsolutePosition(x, y);
        under.addImage(image);

        //设置不可编辑
        pdfStamper.setFormFlattening(true);
        pdfStamper.close();

PS:合并多个pdf成一个

//先删除之前的all.pdf
        String filePath="all.pdf";
        File file=new File(filePath);
        file.delete();
        //要合并的所有pdf的路径
        List<String> fileList;
        //all.pdf保存路径
        String savepath="all.pdf";
        Document document = null;
        try {
            document = new Document(new PdfReader(fileList.get(0)).getPageSize(1));
            PdfCopy copy = new PdfCopy(document, new FileOutputStream(savepath));
            document.open();
            for (int i = 0; i < fileList.size(); i++) {
                PdfReader reader = new PdfReader(fileList.get(i));
                int n = reader.getNumberOfPages();// 获得总页码
                for (int j = 1; j <= n; j++) {
                    document.newPage();
                    PdfImportedPage page = copy.getImportedPage(reader, j);// 从当前Pdf,获取第j页
                    copy.addPage(page);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        } catch (DocumentException e) {
            e.printStackTrace();
        } finally {
            if (document != null) {
                document.close();
            }
        }

下面代码是用在项目中使用得截取部分作为参考:
// 保存路径 生成

    String savePath =
            GlConfig.getDownloadResourcePath() + "student/" + student.getName() + "ClassHoursProve.pdf";
            // 生成 pdf
    PdfUtil.exportTemplateByPdf(savePath, dto.toJson(), path);

pdfUtil

package com.gl.common.file.util;

import cn.hutool.core.io.resource.ResourceUtil;
import cn.hutool.json.JSONObject;
import com.itextpdf.text.Document;
import com.itextpdf.text.Image;
import com.itextpdf.text.PageSize;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.net.URL;
import java.util.Map;


@Slf4j
public class PdfUtil {

    /**
     * 学时证明模板路径
     */
    public static final URL TEMPLATE_URL = ResourceUtil.getResource("template/ClassHoursProve.pdf");

    /**
     * 导出PDF方法
     *
     * @param savePath 保存服务器路径
     * @param obj      导出的参数
     */
    public static void exportTemplateByPdf(String savePath, JSONObject obj,String filePath) {
        PdfReader reader = null;
        ByteArrayOutputStream bos = null;
        PdfStamper stamper = null;
        OutputStream os = null;
        FileOutputStream out = null;
        File file;
        Document document = null;
        PdfCopy copy = null;
        Document doc = null;

        try {
            /** 实例化文档对象 */
            document = new Document(PageSize.A4, 50, 40, 40, 50);
            /** 创建 PdfWriter 对象 */
            // 打开文档
            document.open();
            /** pdf文档中中文字体的设置,注意一定要添加iTextAsian.jar包 */
            String localFontPath = "c:\\windows\\fonts\\";
            BaseFont bfChinese =
                    BaseFont.createFont(localFontPath + "simhei.ttf", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
            FileUtils.deleteFile(savePath);
            file = new File(savePath);
            if (!file.getParentFile().exists()) {
                file.getParentFile().mkdirs();
            }
            out = new FileOutputStream(file);
            reader = new PdfReader(TEMPLATE_URL);
            bos = new ByteArrayOutputStream();
            stamper = new PdfStamper(reader, bos);
            AcroFields form = stamper.getAcroFields();
            // 文字类的内容处理
            form.addSubstitutionFont(bfChinese);
            String vlaues;
            for (Map.Entry<String, Object> entry : obj.entrySet()) {
                vlaues = String.valueOf(entry.getValue());
                if ("photo".equals(entry.getKey()) || "qrcode".equals(entry.getKey())) {
                    try {
                        // 通过域名获取所在页和坐标,左下角为起点
                        int pageNo = form.getFieldPositions(entry.getKey()).get(0).page;
                        Rectangle signRect = form.getFieldPositions(entry.getKey()).get(0).position;
                        // 印章位置
                        Rectangle seal_signRect = form.getFieldPositions("month").get(0).position;
                        float x = signRect.getLeft();
                        float y = signRect.getBottom();
                        // 印章坐标位置
                        float seal_x = seal_signRect.getLeft();
                        float seal_y = seal_signRect.getBottom();
                        // 读图片
                        Image image = Image.getInstance(vlaues);
                        Image seal_image = Image.getInstance(filePath);
                        // 获取操作的页面
                        PdfContentByte under = stamper.getOverContent(pageNo);
                        // 根据域的大小缩放图片
                        image.scaleToFit(signRect.getWidth(), signRect.getHeight());
                        seal_image.scaleToFit(signRect.getWidth(), signRect.getHeight());
                        // 添加图片
                        image.setAbsolutePosition(x, y);
                        seal_image.setAbsolutePosition(seal_x, seal_y);
                        under.addImage(image);
                        under.addImage(seal_image);
                    } catch (Exception e) {
                        log.info(e.getMessage());
                    }

                } else {
                    if ("fileno".equals(entry.getKey())) {
                        form.setFieldProperty(entry.getKey(), "textsize", 50f, null);
                    } else {
                        form.setFieldProperty(entry.getKey(), "textsize", 10f, null);
                    }
                    form.setField(entry.getKey(), vlaues);
                }
            }
            // 如果为false,生成的PDF文件可以编辑,如果为true,生成的PDF文件不可以编辑
            stamper.setFormFlattening(true);
            stamper.close();
            doc = new Document();
            copy = new PdfCopy(doc, out);
            doc.open();
            PdfImportedPage importPage = copy.getImportedPage(new PdfReader(bos.toByteArray()), 1);
            copy.addPage(importPage);
            doc.close();
            document.close();
            copy.flush();
            copy.close();

        } catch (Exception e) {
            log.info(e.getMessage());
        } finally {
            try {

                if (stamper != null) {
                    stamper.close();
                    stamper = null;
                }
                if (reader != null) {
                    reader.close();
                    reader = null;
                }
                IOUtils.closeQuietly(os);
                IOUtils.closeQuietly(bos);
                IOUtils.closeQuietly(out);
                if (document != null) {
                    document.close();
                    document = null;
                }
                if (doc != null) {
                    doc.close();
                    doc = null;
                }
                if (copy != null) {
                    copy.flush();
                    copy.close();
                    copy = null;
                }
            } catch (Exception ignored) {
            }
        }
    }
}

在目前工程化应用中,基于轻量化YOLO检测 + 卡尔曼滤波预测 + 匈牙利算法关联的改进型Tracking - by - Detection(TbD)范式应用相对更多。 基于轻量化YOLO检测 + 卡尔曼滤波预测 + 匈牙利算法关联的改进型TbD范式在多目标跟踪场景中具有显著优势。轻量化YOLO检测能够快速且准确地检测出目标卡尔曼滤波可以对目标的运动状态进行有效预测,匈牙利算法则能高效地完成目标关联,使得整个跟踪系统在准确性和实时性上达到较好的平衡。这种范式在智能交通、安防监控等领域有广泛应用,例如在基于YOLODeepSORT的多目标车辆追踪和速度检测任务中,DeepSORT就利用了卡尔曼滤波器和匈牙利算法进行目标跟踪,并且结合了YOLO的检测结果,展现出了良好的性能和实用性 [^1][^3]。 而改进型Siamese网络(孪生网络)+ 相关滤波器(CF)虽然在目标跟踪方面也有一定的优势,如在处理目标外观变化等方面有较好的表现,但由于其计算复杂度相对较高,在一些对实时性要求极高的大规模工程应用场景中,可能不如改进型TbD范式那样具有广泛的适用性。 ```python # 以下为简单示意代码,模拟改进型TbD范式中目标检测和跟踪部分 import numpy as np from filterpy.kalman import KalmanFilter from scipy.optimize import linear_sum_assignment # 模拟轻量化YOLO检测结果 def yolo_detection(frame): # 这里只是简单示意,实际需要实现YOLO检测算法 detections = np.array([[100, 100, 200, 200], [300, 300, 400, 400]]) return detections # 初始化卡尔曼滤波器 def init_kalman_filter(): kf = KalmanFilter(dim_x=4, dim_z=2) kf.F = np.array([[1, 0, 1, 0], [0, 1, 0, 1], [0, 0, 1, 0], [0, 0, 0, 1]]) kf.H = np.array([[1, 0, 0, 0], [0, 1, 0, 0]]) return kf # 匈牙利算法关联 def hungarian_assignment(cost_matrix): row_ind, col_ind = linear_sum_assignment(cost_matrix) return row_ind, col_ind # 模拟目标跟踪过程 def track(frame): detections = yolo_detection(frame) kf = init_kalman_filter() # 这里只是简单示意,实际需要维护多个目标的滤波器 predictions = [] for detection in detections: kf.predict() kf.update([detection[0], detection[1]]) predictions.append(kf.x[:2]) # 计算代价矩阵 cost_matrix = np.random.rand(len(detections), len(predictions)) row_ind, col_ind = hungarian_assignment(cost_matrix) return row_ind, col_ind ```
评论 6
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值