记录使用iText7查找PDF内容关键字坐标,加盖电子签名、印章

news2024/11/24 8:42:57

一、前言

项目以前签字都是由C端那边进行合成操作,最近项目要求把那块功能,由后端进行实现,其中包含坐标、关键字、任意位置进行签字操作,坐标是最容易实现的,曾经也写过类似的功能在(添加图片印章到PDF)直接复用就可以了
为了实现关键字位置签字,在网上查找了挺多资料的,感觉能满足功能的代码参考地址:Itext7获取关键字在文件中的坐标
在他这基础上我进行了优化

二、使用JAR包

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

三、实现代码

import com.itextpdf.kernel.geom.Rectangle;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfPage;
import com.itextpdf.kernel.pdf.PdfReader;
import com.itextpdf.kernel.pdf.canvas.parser.PdfCanvasProcessor;
import com.itextpdf.kernel.pdf.canvas.parser.listener.IPdfTextLocation;
import com.itextpdf.kernel.pdf.canvas.parser.listener.RegexBasedLocationExtractionStrategy;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.*;

public class PDFKeywordFinder {

    public static Map<String, Object> getKeywordLocation(ByteArrayInputStream bytes, String keyword) {
        Map<String, Object> result = new HashMap<>();
        //使用这种方式,无需再关闭了,处理完自动关闭
        try (PdfReader reader = new PdfReader(bytes); PdfDocument pdfDocument = new PdfDocument(reader)) {
            for (int i = 1; i <= pdfDocument.getNumberOfPages(); i++) {
                PdfPage page = pdfDocument.getPage(i);
                RegexBasedLocationExtractionStrategy strategy = new RegexBasedLocationExtractionStrategy(keyword);
                PdfCanvasProcessor canvasProcessor = new PdfCanvasProcessor(strategy);
                canvasProcessor.processPageContent(page);
                Collection<IPdfTextLocation> resultantLocations = strategy.getResultantLocations();
                // 自定义结果处理
                if (!resultantLocations.isEmpty()) {
                    List<Map<String, Object>> locationList = new ArrayList<>();
                    for (IPdfTextLocation item : resultantLocations) {
                        Map<String, Object> map = new HashMap<>();
                        Rectangle rectangle = item.getRectangle();
                        map.put("page", item.getPageNumber());
                        map.put("absoluteX", rectangle.getX());
                        map.put("absoluteY", rectangle.getY());
                        map.put("width", rectangle.getWidth());
                        map.put("height", rectangle.getHeight());
                        map.put("keyword", item.getText());
                        map.put("top", rectangle.getTop());
                        map.put("bottom", rectangle.getBottom());
                        map.put("left", rectangle.getLeft());
                        map.put("right", rectangle.getRight()); // 右坐标
                        map.put("count", locationList.size() + 1); // 出现次数
                        locationList.add(map);
                    }
                    result.put(String.valueOf(i), locationList);
                }
            }
            return result;
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

四、测试用例

本地测试用了文件转内存流方式,如果需要加盖电子印章,可以把签字图片替换成电子印章图片
我这没用到签名密钥,如果需要可以自行添加,或者找其它的处理方式

//引入包信息
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Image;
import com.itextpdf.text.pdf.PdfContentByte;
import com.itextpdf.text.pdf.PdfStamper;

import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.*;

public static void main(String[] args) throws IOException, DocumentException {
    String filePath = "E:\\test.pdf";
    String keyword = "签收人"; // 要查找的关键字
    ByteArrayOutputStream memoryStream = readFileToMemoryStream(filePath);
    Map<String, Object> map = getKeywordLocation(new ByteArrayInputStream(memoryStream.toByteArray()), keyword);
    com.itextpdf.text.pdf.PdfReader pdfReader = new com.itextpdf.text.pdf.PdfReader(memoryStream.toByteArray());
    PdfStamper pdfStamper = new PdfStamper(pdfReader, Files.newOutputStream(Paths.get("E:\\文书.pdf")));
    com.itextpdf.text.Image image = Image.getInstance("E:\\sign.png");
    //设置签字图片宽高
    image.scaleAbsolute(100, 50);
    //我直接在第一页操作,也可以根据返回的数据进行操作
    JSONArray jsonArray = JSONArray.parseArray(JSON.toJSONString(map.get("1")));
    JSONObject jsonObject = jsonArray.getJSONObject(0);
    //这个位置主要是插入签名图片位置坐标,也可以根据情况自行调整取值
    float absoluteX = Float.parseFloat(jsonObject.getString("absoluteX")) - Float.parseFloat(jsonObject.getString("width"));
    float absoluteY = Float.parseFloat(jsonObject.getString("absoluteY")) - (Float.parseFloat(jsonObject.getString("width")) + Float.parseFloat(jsonObject.getString("height")));
    image.setAbsolutePosition(absoluteX, absoluteY);
    PdfContentByte content = pdfStamper.getUnderContent(1);
    content.addImage(image);
    pdfStamper.close();
}

private static ByteArrayOutputStream readFileToMemoryStream(String filePath) throws IOException {
    ByteArrayOutputStream memoryStream = new ByteArrayOutputStream();
    byte[] buffer = new byte[1024]; // 缓冲区大小
    try (FileInputStream fis = new FileInputStream(filePath)) {
        int bytesRead;
        while ((bytesRead = fis.read(buffer)) != -1) {
            memoryStream.write(buffer, 0, bytesRead);
        }
    }
    return memoryStream;
}

五、效果展示

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1045442.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

解锁工业 4.0 元宇宙:AR/VR、AI 和 3D 技术如何为下一次工业革命提供动力

原创 | 文 BFT机器人 沉浸式混合现实和由虚拟现实&#xff08;VR&#xff09;和增强现实&#xff08;AR&#xff09;组成的扩展现实技术仍然是业务创新和扩张的关键驱动因素。通过改变公司的运营、与客户互动和实现目标的方式&#xff0c;这一技术解决方案集已在多个行业产生了…

认证-authentication 和授权-authorization

就好比你可以刷卡进去xxx大厦&#xff08;认证是本公司职员&#xff09;&#xff0c;但无法刷卡进入金融部门&#xff0c;或 实验部门&#xff08;因为没有授权&#xff09;

无线通信——Mesh自组网特点

Mesh&#xff0c;它的中文叫作无线网格状网络。作为当下最为灵活、高效、便捷的扩大信号覆盖的通信解决方案之一&#xff0c;Mesh组网得到了极大推广。其主要应用于&#xff1a;&#xff08;无人机/车/船、特种机器人、巡检、应急安防&#xff08;如城市应急、抢险救援、城区覆…

蜜雪冰城涨价怒赞无数 雪王张红超卷出一条阳道

作者&#xff1a;积溪 简评&#xff1a;最近雪王涨价一元登上了热搜&#xff0c;但评论区却是一片和谐&#xff0c;雪王的魅力究竟是如何养成的&#xff1f;#蜜雪冰城 #雪王 #张红超 #奶茶 别的品牌涨价&#xff0c;只有吐槽声一片&#xff1b;但它涨价&#xff0c;却是网友们…

如何在前端项目中管理依赖关系?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 使用包管理工具⭐ 使用版本控制系统⭐ 使用依赖管理工具⭐ 使用CDN⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 欢迎来到前端入门之旅&#xff01;感兴趣的可以订阅本专栏哦&#xff01;这个专栏是为那些对W…

MyBatis Generator 代码自动生成器

一、什么是逆向工程 Mybatis的逆向工程就是由代码生成器生成我们需要的代码和映射文件。我们在编写Mybatis程序时&#xff0c;基本都是围绕着pojo类&#xff0c;Mapper接口&#xff0c;Mapper.xml文件等文件来进行的。如果实际开发中数据库的表特别多&#xff0c;那么我们需要手…

超全超详细的Redis笔记-数据类型及其使用、主从复制、哨兵模式、缓存穿透、击穿、雪崩

文章目录 狂神聊Redis1、Nosql概述1.1、为什么要用Nosql1.2、什么是NoSQL1.3、NoSQL的四大分类 2、Redis 入门2.1、概述2.2、Windows 安装2.3、Linux安装2.4、测试性能2.5、Redis基础知识 3、五大基本数据类型3.1、Redis-Key3.2、String3.3、List3.4、Set3.5、Hash&#xff08;…

基于SSM的实习管理系统

基于SSM的实习管理系统、前后端分离 开发语言&#xff1a;Java数据库&#xff1a;MySQL技术&#xff1a;SpringSpringMVCMyBatisVue工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 系统展示 管理员界面 教师 学生 研究背景 基于SSM的实习管理系统是一个基于Spring、Spring…

【计算机网络】网络层和数据链路层

文章目录 IP协议网段划分分类划分法CIDR 方案路由NAT网络地址转换技术IP报文的另外三个参数mac帧ARP协议交换机ICMP代理服务器 IP协议 TCP有将数据 可靠、高效 发给对方的 策略&#xff0c;而IP具有发送的能力&#xff0c;即将数据从A主机送到B主机的 能力 。 用户要的是100%…

GeoPandas和Matplotlib地图高亮显示——与中国建交的国家(不全)

GeoPandas和Matplotlib地图高亮显示——与中国建交的国家&#xff08;不全&#xff09; 一、概要二、整体架构流程三、完整代码 一、概要 这段代码是使用GeoPandas和Matplotlib库在Python中绘制世界地图的一个例子&#xff0c;它突出了与中国建交的国家&#xff08;部分&#x…

​数据库查询进阶--多表查询

目录 目录 1. 概述 2. 内连接&#xff08;Inner Join&#xff09; 2.1 语法 2.2 示例 3. 左连接&#xff08;Left Join&#xff09; 3.1 语法 3.2 示例 4. 右连接&#xff08;Right Join&#xff09; 4.1 语法 4.2 示例 5. 全外连接&#xff08;Full Outer Join&am…

vue实现进度条+背景定位

最近在做一个数字孪生项目&#xff0c;用于展示地铁车辆的进场动画及部件&#xff0c;使用的vueunity&#xff0c;但是 unity模型在加载完成之前会有个加载进度条&#xff0c;页面背景色是黑色&#xff0c;中间只有个一进度条框 可以看到很单调很丑&#xff0c;并且客户也不满…

2023软件测试八股文,涵盖所有面试题

Part1 1、你的测试职业发展是什么&#xff1f; 测试经验越多&#xff0c;测试能力越高。所以我的职业发展是需要时间积累的&#xff0c;一步步向着高级测试工程师奔去。而且我也有初步的职业规划&#xff0c;前3年积累测试经验&#xff0c;按如何做好测试工程师的要点去要求自…

如何优化前端性能?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 优化前端性能1. 减少HTTP请求2. 压缩资源3. 使用浏览器缓存4. 使用CDN5. 延迟加载6. 使用响应式设计7. 减少重绘和回流8. 代码优化9. 使用现代Web技术 ⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 欢迎来到前…

vue event bus 事件总线

vue event bus 事件总线 创建 工程&#xff1a; H:\java_work\java_springboot\vue_study ctrl按住不放 右键 悬着 powershell H:\java_work\java_springboot\js_study\Vue2_3入门到实战-配套资料\01-随堂代码素材\day04\准备代码\08-事件总线-扩展 vue --version vue crea…

免杀对抗-内存加载-shellcode转换-UUID+MAC+IPV4

内存加载-UUID地址-ShellCode转换 介绍&#xff1a;通用唯一识别码(UUID),是用于计算机体系中以识别信息数目的一个128位标识符&#xff0c;根据标准方法生成&#xff0c;不依赖中央机构的注册和分配&#xff0c;UUID具有唯一性。 演示语言&#xff1a;c 1.使用以下代码将c语言…

如何使用 API 接口获取商品数据,从申请 API 接口、使用 API 接口到实际应用,一一讲解

在当今的数字化时代&#xff0c;应用程序接口&#xff08;API&#xff09;已经成为数据获取的重要通道。API 接口使得不同的应用程序能够方便地进行数据交换&#xff0c;从而促进了信息的广泛传播和利用。在众多的数据源中&#xff0c;商品数据是一个非常重要的领域&#xff0c…

leetcode面试题0808有重复字符串的排列组合

描述 输入一个长度为 n 字符串&#xff0c;打印出该字符串中字符的所有排列&#xff0c;你可以以任意顺序返回这个字符串数组。 例如输入字符串ABC,则输出由字符A,B,C所能排列出来的所有字符串ABC,ACB,BAC,BCA,CBA和CAB。 数据范围&#xff1a;n<10 要求&#xff1a;空间复…

Mysql高级语句(视图表 、存储过程、条件语句、循环语句)

Mysql高级语句&#xff08;视图表 、存储过程、条件语句、循环语句&#xff09; 一、 CREATE VIEW&#xff08;视图&#xff09;1.1、 视图表概述1.2、 视图表能否修改&#xff1f;&#xff08;面试题&#xff09;1.3、 基本语法1.3.1、 创建1.3.2、 查看1.3.3 、删除 1.4、 通…

基于微信小程序的场地预约系统设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言系统主要功能&#xff1a;具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09;有保障的售后福利 代码参考源码获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计…