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

Java实现pdf中动态插入图片

今天接到一个需求,需要在pdf中的签名处,插入签名照片,但签名位置不固定,话不多说上代码:

1、首先引入itextpdf依赖包:

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

2、具体实现逻辑如下:

	/**
     * description PDF插入图片(根据关键字位置动态插入)
     *
     * @author yanzy
     * @version 1.0
     * @date 2025/3/27 17:26
     */
    public static void imgToPdf2(String pdfPath, String imagePath, String outputPath, String keyword) {
        try {

            // 读取原始PDF
            PdfReader reader = new PdfReader(pdfPath);
            FileOutputStream fos = new FileOutputStream(outputPath);
            PdfStamper stamper = new PdfStamper(reader, fos);

            // 遍历PDF每一页,查找关键字并插入签名图片
            Boolean keyBool = true;
            for (int i = 1; i <= reader.getNumberOfPages(); i++) {

                // 获取当前页面的文本和坐标信息
                List<Position> positions = getPositions(reader, i);

                // 合并连续文本块
                StringBuilder combinedText = new StringBuilder();
                List<Position> textChunks = new ArrayList<>();

                for (Position pos : positions) {
                    combinedText.append(pos.getText());
                    textChunks.add(pos);
                }

                // 查找关键字在整个文本中的位置
                String fullText = combinedText.toString();
                int index = fullText.indexOf(keyword);
                if (index != -1) {

                    // 获取关键字起始位置
                    Position endPos = findPositionByIndex(textChunks, index + keyword.length() - 1);

                    // 计算插入坐标(取结束位置右侧)
                    float imgX = endPos.getX() + 20; // 横纵标,右侧偏移20单位
                    float imgY = endPos.getY() - 20; // 纵坐标,向下移动20单位

                    log.info("关键字位置 -> X:{}  Y: {} | 图片位置 -> X: {}  Y:{}", endPos.getX(), endPos.getY(), imgX, imgY);

                    // 添加图片
                    Image img = Image.getInstance(imagePath);
                    // 图片尺寸
                    img.scaleToFit(100, 50);
                    // 设置图片的插入位置(X,Y坐标)
                    img.setAbsolutePosition(imgX, imgY);

                    // PdfStamper:直接修改原始PDF,避免图层顺序问题
                    PdfContentByte canvas = stamper.getOverContent(i);
                    canvas.addImage(img);
                    keyBool = false;
                }
            }

            if (keyBool) {
                throw new Exception("未找到关键字位置!");
            }

            stamper.close();
            reader.close();
            log.info("图片插入成功!");
        } catch (Exception e) {
            e.printStackTrace();
            log.error("pdf插入图片失败! errMsg: {}", e.getMessage());
        }

    }

    /**
     * description 根据文本索引找到对应位置
     *
     * @author yanzy
     * @version 1.0
     * @date 2025/3/27 17:26
     */
    private static Position findPositionByIndex(List<Position> chunks, int targetIndex) {
        int currentIndex = 0;
        for (Position chunk : chunks) {
            int chunkLength = chunk.getText().length();
            if (currentIndex + chunkLength > targetIndex) {
                return chunk;
            }
            currentIndex += chunkLength;
        }
        return chunks.get(chunks.size() - 1);
    }

    /**
     * description 获取PDF页面的所有文本位置
     *
     * @author yanzy
     * @version 1.0
     * @date 2025/3/27 17:26
     */
    private static List<Position> getPositions(PdfReader reader, int pageNumber) throws Exception {

        List<Position> positions = new ArrayList<>();

        // 创建PdfContentByte和RenderListener来提取文本
        PdfReaderContentParser parser = new PdfReaderContentParser(reader);
        parser.processContent(pageNumber, new RenderListener() {
            @Override
            public void beginTextBlock() {
            }

            @Override
            public void endTextBlock() {
            }

            @Override
            public void renderText(TextRenderInfo renderInfo) {
                String text = renderInfo.getText();
                float x = renderInfo.getBaseline().getStartPoint().get(0);
                float y = renderInfo.getBaseline().getStartPoint().get(1);
                positions.add(new Position(x, y, text));
            }

            @Override
            public void renderImage(ImageRenderInfo renderInfo) {
            }
        });

        return positions;
    }

    public static void main(String[] args) {
        // 输入PDF路径
        String srcPdf = "E://test.pdf";
        // 输出PDF路径
        String destPdf = "E://output_image.pdf";
        // 图片路径
        String imagePath = "E://test.jpg";
        // 关键字
        String keyword = "本人签名:";

        //imgToPdf(srcPdf, imagePath, destPdf);
        imgToPdf2(srcPdf, imagePath, destPdf, keyword);
    }
/**
 * description pdf中的文本坐标
 *
 * @author yanzy
 * @date 2025/3/28 15:36
 */
public class Position {

    private final float x;
    private final float y;
    private final String text;

    public Position(float x, float y, String text) {
        this.x = x;
        this.y = y;
        this.text = text;
    }

    public float getX() {
        return x;
    }

    public float getY() {
        return y;
    }

    public String getText() {
        return text;
    }

}

3、下面是pdf的内容:
在这里插入图片描述
4、运行程序后的结果:
在这里插入图片描述
5、可以看到签名照片已经成功加上了

http://www.dtcms.com/a/97161.html

相关文章:

  • 如何在 Postman 中正确设置 Session 以维持用户状态?
  • 亚马逊云科技提供完全托管的DeepSeek-R1模型
  • SEO(搜索引擎优化)详解
  • 处理脚本中函数调用的异常
  • 基于深度强化学习的智能机器人路径规划技术研究
  • 第六届 蓝桥杯 嵌入式 省赛
  • Postman CORS 测试完全指南:轻松模拟跨域请求,排查 CORS 相关问题
  • 软考中级-软件设计师 23种设计模式(内含详细解析)
  • Gateway实战(二)、负载均衡
  • React 中shouldComponentUpdate生命周期方法的作用,如何利用它优化组件性能?
  • Python爬虫如何检测请求频率?
  • Docker-Volume数据卷详讲
  • 循环神经网络 - 给网络增加记忆能力
  • 优化webpack打包体积思路
  • WebSocket:实时双向通信技术详解与实战示例优化指南
  • Linux内核禁止_开启中断和处理器间中断
  • 鸿蒙前后端项目源码-点餐v3.0-原创!原创!原创!
  • js关于for of 与for in
  • webpack和vite之间的区别
  • 从 Word 到 HTML:使用 Aspose.Words 轻松实现 Word 文档的高保真转换
  • Linux:基础IO---缓冲区
  • 1688商品详情接口:深度解析与应用实践
  • 基于社交裂变的S2B2C电商模式创新研究——以“颜值PK+礼品卡+AI智能名片“融合生态为例
  • JDK 17 + Spring Boot 3 全栈升级实战指南--从语法革新到云原生,解锁企业级开发新范式
  • 学习openfoam的两个地方(案例和源码)
  • MATLAB中构建模式表达式
  • Python 在Word中查找并替换文本
  • git在实践使用中的操作流程
  • 力扣:回溯算法
  • 获客、留客、复购...如何利用易境通集运系统越过“三座大山”?