Itext7在PDF指定位置添加电子公章

news2024/11/17 3:56:45

目录

1. 电子公章的制作

2. java工具keytool生成p12数字证书文件

3. pom依赖

4. 实体类

5. 工具类及测试示例

6. 效果


1. 电子公章的制作

 做章网站:http://seal.biaozhiku.com/

  • 我们选择圆形印章

  • 然后输入公司名,输入章名输入编码然后点击395生成,最后点击保存图片,我们的个人专业章就实现了

2. java工具keytool生成p12数字证书文件

Keytool是用于管理**和证书的工具,位于%JAVA_HOME%/bin目录。 使用JDK的keytool工具

  • keytool在jdk的bin目录下

2. 打开keytool所在的bin目录,然后在上面的路径显示框中输入CMD,然后回车,即可在当前文件夹下打开命令提示符,并且路径是当前文件夹。

  • 生成数字文件,在命令行输入
  • keytool -genkeypair -alias whj -keypass 111111 -storepass 111111 -dname “C=CN,ST=SD,L=QD,O=haier,OU=dev,CN=haier.com” -keyalg RSA -keysize 2048 -validity 3650 -keystore D:\keystore\server.keystore

参数解释:

storepass keystore 文件存储密码
keypass 私钥加解密密码
alias 实体别名(包括证书私钥)
dname 证书个人信息
keyalt 采用公钥算法,默认是DSA keysize **长度(DSA算法对应的默认算法是sha1withDSA,不支持2048长度,此时需指定RSA)
validity 有效期
keystore 指定keystore文件

  • 转换为p12格式

在命令行输入

keytool -importkeystore -srckeystore D:\keystore\server.keystore -destkeystore D:\keystore\whj.p12 -srcalias whj -destalias serverkey -srcstoretype jks -deststoretype pkcs12 -srcstorepass 111111 -deststorepass 111111 -noprompt

  • 生成的最终文件

3. pom依赖

<dependency>
	<groupId>cn.hutool</groupId>
	<artifactId>hutool-all</artifactId>
	<version>5.8.11</version>
</dependency>
<!--itext7 pom-->
<dependency>
	<groupId>com.itextpdf</groupId>
	<artifactId>itext7-core</artifactId>
	<version>7.2.0</version>
	<type>pom</type>
</dependency>

4. 实体类

package com.example.demo.itext.model;

import com.itextpdf.signatures.PdfSignatureAppearance;

import java.security.PrivateKey;
import java.security.cert.Certificate;

public class SignatureInfo {
    private String reason; //签名的原因,显示在pdf签名属性中
    /**
     * 将证书文件放入指定路径,并读取keystore ,获得私钥和证书链
     */
    private String pkPath;

    /**
     * KeyStore类型
     */
    private String keyStoreType;

    /**
     * 原PDF文件路径
     */
    private String src;

    /**
     * 数字签章后的文件路径
     */
    private String target;
    private String location;//签名的地点,显示在pdf签名属性中
    private String digestAlgorithm;//摘要算法名称,例如SHA-1
    private String imagePath;//图章路径
    private String fieldName;//表单域名称
    private Certificate[] chain;//证书链
    private PrivateKey pk;//签名私钥
    private int certificationLevel = 0; //批准签章
    private PdfSignatureAppearance.RenderingMode renderingMode;//表现形式:仅描述,仅图片,图片和描述,签章者和描述
    //图章属性
    private float rectllx;//图章左下角x
    private float rectlly;//图章左下角y
    private float recturx;//图章右上角x
    private float rectury;//图章右上角y

    public float getRectllx() {
        return rectllx;
    }

    public void setRectllx(float rectllx) {
        this.rectllx = rectllx;
    }

    public float getRectlly() {
        return rectlly;
    }

    public void setRectlly(float rectlly) {
        this.rectlly = rectlly;
    }

    public float getRecturx() {
        return recturx;
    }

    public void setRecturx(float recturx) {
        this.recturx = recturx;
    }

    public float getRectury() {
        return rectury;
    }

    public void setRectury(float rectury) {
        this.rectury = rectury;
    }

    public String getReason() {
        return reason;
    }

    public void setReason(String reason) {
        this.reason = reason;
    }

    public String getLocation() {
        return location;
    }

    public void setLocation(String location) {
        this.location = location;
    }

    public String getDigestAlgorithm() {
        return digestAlgorithm;
    }

    public void setDigestAlgorithm(String digestAlgorithm) {
        this.digestAlgorithm = digestAlgorithm;
    }

    public String getImagePath() {
        return imagePath;
    }

    public void setImagePath(String imagePath) {
        this.imagePath = imagePath;
    }

    public String getFieldName() {
        return fieldName;
    }

    public void setFieldName(String fieldName) {
        this.fieldName = fieldName;
    }

    public Certificate[] getChain() {
        return chain;
    }

    public void setChain(Certificate[] chain) {
        this.chain = chain;
    }

    public PrivateKey getPk() {
        return pk;
    }

    public void setPk(PrivateKey pk) {
        this.pk = pk;
    }

    public int getCertificationLevel() {
        return certificationLevel;
    }

    public void setCertificationLevel(int certificationLevel) {
        this.certificationLevel = certificationLevel;
    }

    public PdfSignatureAppearance.RenderingMode getRenderingMode() {
        return renderingMode;
    }

    public void setRenderingMode(PdfSignatureAppearance.RenderingMode renderingMode) {
        this.renderingMode = renderingMode;
    }


    public String getPkPath() {
        return pkPath;
    }

    public void setPkPath(String pkPath) {
        this.pkPath = pkPath;
    }

    public String getKeyStoreType() {
        return keyStoreType;
    }

    public void setKeyStoreType(String keyStoreType) {
        this.keyStoreType = keyStoreType;
    }

    public String getSrc() {
        return src;
    }

    public void setSrc(String src) {
        this.src = src;
    }

    public String getTarget() {
        return target;
    }

    public void setTarget(String target) {
        this.target = target;
    }
}

5. 工具类及测试示例

ItextUtil工具类参考:https://mp.csdn.net/mp_blog/creation/editor/128789640
package com.example.demo.itext.util;

import com.example.demo.itext.model.KeyWordBean;
import com.example.demo.itext.model.SignatureInfo;
import com.itextpdf.io.image.ImageData;
import com.itextpdf.io.image.ImageDataFactory;
import com.itextpdf.kernel.geom.Rectangle;
import com.itextpdf.kernel.pdf.PdfReader;
import com.itextpdf.kernel.pdf.StampingProperties;
import com.itextpdf.signatures.*;
import lombok.SneakyThrows;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.springframework.util.ResourceUtils;

import java.io.*;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.Security;
import java.security.cert.Certificate;
import java.util.List;
import java.util.Map;

/**
 * 功能描述: pdf数字签章工具类 <br>
 *
 * @Author: lhp
 * @Date: 2023/1/29 15:45
 */
public class PdfStampUtil {

    /**
     * keystory密码,可以放到配置文件中
     */
    public static final char[] PASSWORD = "111111".toCharArray();

    /**
     * 功能描述: PDF添加数字签章 <br>
     *
     * @Param: [src:原PDF文件路径, target:数字签章后的文件路径, signatureInfo:参数]
     * @Return: void
     * @Author: lhp
     * @Date: 2023/1/29 15:33
     */
    public static void sign(SignatureInfo signatureInfo) {
        // 原PDF文件路径
        String src = signatureInfo.getSrc();
        // 数字签章后的文件输出路径
        String target = signatureInfo.getTarget();
        InputStream inputStream = null;
        FileOutputStream outputStream = null;
        ByteArrayOutputStream result = new ByteArrayOutputStream();
        try {
            inputStream = new FileInputStream(src);
            ByteArrayOutputStream tempArrayOutputStream = new ByteArrayOutputStream();
            PdfReader reader = new PdfReader(inputStream);
            PdfSigner stamper = new PdfSigner(reader, tempArrayOutputStream, new StampingProperties());
            stamper.setCertificationLevel(signatureInfo.getCertificationLevel());

            // 获取数字签章属性对象
            PdfSignatureAppearance appearance = stamper.getSignatureAppearance();
            appearance.setReason(signatureInfo.getReason());
            appearance.setLocation(signatureInfo.getLocation());


            // 读取图章图片
            ImageData image = ImageDataFactory.create(signatureInfo.getImagePath());
            appearance.setSignatureGraphic(image);

            Float rectllx = signatureInfo.getRectllx();
            System.out.println("x:" + rectllx);
            Float rectlly = signatureInfo.getRectlly();
            System.out.println("y:" + rectlly);
            Float recturx = signatureInfo.getRecturx();
            System.out.println("recturx:" + recturx);
            Float rectury = signatureInfo.getRectury();
            System.out.println("rectury:" + rectury);
            appearance.setPageNumber(1);

            appearance.setPageRect(new Rectangle(rectllx, rectlly, recturx, rectury));
//            appearance.setPageRect(new Rectangle(rectllx, rectlly, image.getWidth(), image.getHeight()));

            // 设置图章的显示方式,如下选择的是只显示图章(还有其他的模式,可以图章和签名描述一同显示)
            appearance.setRenderingMode(signatureInfo.getRenderingMode());

            // 这里的itext提供了2个用于签名的接口,可以自己实现,后边着重说这个实现
            // 摘要算法
            IExternalDigest digest = new BouncyCastleDigest();
            // 签名算法
            Security.addProvider(new BouncyCastleProvider());
            // 签名算法
            IExternalSignature signature = new PrivateKeySignature(signatureInfo.getPk(), signatureInfo.getDigestAlgorithm(), BouncyCastleProvider.PROVIDER_NAME);
            // 调用itext签名方法完成pdf签章 //数字签名格式,CMS,CADE
            stamper.signDetached(digest, signature, signatureInfo.getChain(), null, null, null, 0, PdfSigner.CryptoStandard.CADES);

            inputStream = new ByteArrayInputStream(
                    tempArrayOutputStream.toByteArray());
            // 定义输入流为生成的输出流内容,以完成多次签章的过程
            result = tempArrayOutputStream;

            outputStream = new FileOutputStream(target);
            outputStream.write(result.toByteArray());
            outputStream.flush();

            reader.close();
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            try {
                if (null != outputStream) {
                    outputStream.close();
                }
                if (null != inputStream) {
                    inputStream.close();
                }
                if (null != result) {
                    result.close();
                }
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }

    @SneakyThrows
    public static void pdfStamp(SignatureInfo signatureInfo) {
        String keyStoreType = signatureInfo.getKeyStoreType();
        KeyStore ks = KeyStore.getInstance(keyStoreType);
        // 将证书文件放入指定路径,并读取keystore ,获得私钥和证书链
        ks.load(new FileInputStream(ResourceUtils.getFile("classpath:whj.p12")), PASSWORD);
        String alias = ks.aliases().nextElement();
        PrivateKey pk = (PrivateKey) ks.getKey(alias, PASSWORD);
        // 得到证书链
        Certificate[] chain = ks.getCertificateChain(alias);

        signatureInfo.setPk(pk);
        signatureInfo.setChain(chain);
        signatureInfo.setCertificationLevel(1);
        signatureInfo.setDigestAlgorithm(DigestAlgorithms.SHA1);
        signatureInfo.setRenderingMode(PdfSignatureAppearance.RenderingMode.GRAPHIC);

        sign(signatureInfo);
    }

    public static void main(String[] args) {
        SignatureInfo signInfo = new SignatureInfo();
        signInfo.setReason("理由");
        signInfo.setLocation("位置");

        signInfo.setFieldName("demo");

        // 签章图片
        String imagePath = "F:\\software\\myfile\\南无阿弥陀佛电子印章制作平台.png";
        signInfo.setImagePath(imagePath);
        // 需要进行签章的pdf
        String path = "F:\\software\\myfile\\txt12_加水印_加水印.pdf";
        signInfo.setSrc(path);

        String target = "F:\\software\\myfile\\txt12-PdfStamp15.pdf";
        signInfo.setTarget(target);
        String keyStoreType = "PKCS12";
        signInfo.setKeyStoreType(keyStoreType);

        // 值越大,代表向x轴坐标平移 缩小 (反之,值越小,印章会橫向放大)
//        signInfo.setRectllx(100);
        // 值越大,代表向y轴坐标向上平移(反之,值越小,印章会纵向放大)
//        signInfo.setRectlly(100);
        // 值越大   代表向x轴坐标向右平移  (大小不变)
        signInfo.setRecturx(100);
        // 值越大,代表向y轴坐标向上平移(大小不变)
        signInfo.setRectury(100);

        Map<Integer, List<KeyWordBean>> listMap = ItextUtil.keyWordLocationMap("负责人签名:", path);
        KeyWordBean keyWordBean = listMap.get(1).get(0);
//        KeyWordBean keyWordBean = listMap.get(1).get(1);
        signInfo.setRectllx(keyWordBean.getX() + 70);
        signInfo.setRectlly(keyWordBean.getY() - 50);

        pdfStamp(signInfo);
    }
}

6. 效果

参考:

历经一个月总结使用java实现pdf文件的电子签字+盖章+防伪二维码+水印+PDF文件加密的全套解决方案: 历经一个月总结使用java实现pdf文件的电子签字+盖章+防伪二维码+水印+PDF文件加密的全套解决方案

itext根据关键字定位在pdf中的坐标_牛一样的程序员的博客-CSDN博客_itext 坐标

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

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

相关文章

快速幂及矩阵快速幂分析及代码实现

文章目录前言一、认识快速幂二、快速幂思路及代码三、矩阵快速幂3.1、矩阵乘法代码实现3.2、矩阵快速幂代码实现参考资料前言 在学习Acwing c蓝桥杯辅导课第九讲复杂DP-AcWing 1303. 斐波那契前 n 项和时有使用到矩阵快速幂算法&#xff0c;这里来记录下知识点正好也将快速幂部…

车载以太网 - SomeIP测试专栏 - 详细解析 - 01

对于介绍SomeIP协议&#xff0c;我还是想从最基础的协议解析来&#xff0c;所以今天还是先将SomeIP协议详解给大家列举一下&#xff0c;也方便大家在工作中如果不记得哪些信息随时可以查看学习&#xff0c;也算是留给我自己的笔记吧&#xff0c;毕竟确实容易忘记。 SomeIP数据&…

分布式数据库中间件——Mycat2

一、Mycat2 概述 Mycat是基于java语言编写的数据库中间件&#xff0c;核心功能是分库分表和读写分离&#xff0c;可以将大表水平分割为N个小表。 可以看做为Mysql的数据库服务器&#xff0c;可以用连接Mysql的方式去连接Mycat&#xff0c;端口为8066 二、Mycat的三大作用 2.…

Node 项目中常见的问题及解决方法

1. window和mac下设置NODE_ENV变量的问题 我们都知道在前端项目中会根据不同的环境变量来处理不同的逻辑&#xff0c;在node后端中也一样&#xff0c;我们需要设置本地开发环境、测试环境、 线上环境等&#xff0c;此时有一直设置环境变量的方案是在package.json中的script属性…

Python学习笔记——错误和异常

错误的分类编写程序过程中遇到的错误都分为两类&#xff1a;语法错误与运行时错误。语法错误&#xff1a;当代码不符合Python语法规则时, 在解析过程中会报SyntaxError。运行时错误&#xff1a;即语句或表达式在语法上都是正确的, 但在运行时发生了错误。当程序发生异常时&…

从零搭建完整python自动化测试框架(UI自动化和接口自动化

从零搭建完整python自动化测试框架&#xff08;UI自动化和接口自动化&#xff09; 文章目录 总体框架 PO模式、DDT数据驱动、关键字驱动 框架技术选择 框架运行结果 各用例对应的定义方式&#xff08;PO/DDT&#xff09; 测试执行结果 从零开始搭建项目 一、开发环境搭…

Vue-Vuex

前言 Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式 库 官网介绍&#xff1a;https://vuex.vuejs.org/zh/ 以下主要讲解的是如何定义与使用&#xff0c;如果还没有对vuex进行了解的话&#xff0c;请先查看官网&#xff0c;了解其功能、用法及用途。 关于vuex&#xff0c…

代码随想录算法训练营第五十二天_第九章_动态规划 | 121. 买卖股票的最佳时机、122.买卖股票的最佳时机II

LeetCdoe 121. 买卖股票的最佳时机给定一个数组 prices &#xff0c;它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。 你只能选择 某一天 买入这只股票&#xff0c;并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。 返回你可…

verilog 数字系统设计读书笔记-------持久更新

Verilog模型可以是实际电路的不同级别的抽象。这些抽象的级别和它们所对应的模型类型共有以下5种&#xff1a;系统级、算法级、RTL级、门级、开关级‘bz :表示高阻态&#xff0c; ’bx表示不定值&#xff08;0或1均可&#xff09;include "muxtwo.v" 将文件引进{$ ra…

【Linux】怎么理解进程

✍作者&#xff1a;阿润菜菜 &#x1f4d6;专栏&#xff1a;Liunx系统编程 本文通过冯诺依曼体系结构&#xff08;硬件部分&#xff09;和操作系统&#xff08;软件部分&#xff09;为基础来介绍我们应该如何理解进程&#xff0c;为后续的学习做铺垫。 本文目录一、预备知识1.建…

误差逆传播算法公式理解及推导

前言&#xff1a;公式理解及推导参考自《机器学习》周志华 P101 BP网络 BP网络一般是指由 误差逆传播&#xff08;error BackPropagation, BP&#xff09;算法训练的多层前馈神经网络。 给定训练集 D{(x1,y1)D\left\{\left(\boldsymbol{x}_1, \boldsymbol{y}_1\right)\right…

2023年我的Flag已准备完毕

前言&#xff1a; &#x1f604;作者简介&#xff1a;小曾同学.com,小伙伴们也可以叫我小曾&#xff0c;一个致力于测试开发的博主⛽️ 如果文章知识点有错误的地方&#xff0c;还请大家指正&#xff0c;让我们一起学习&#xff0c;一起进步。 &#x1f60a; 座右铭&#xff1a…

用力过猛,把服务压挂了?

背景 在刚开始进行压测的时候&#xff0c;我也不知道需要提前分析下压测的QPS目标&#xff0c;也不知道说第一步压测的预估值是多少&#xff0c;结果一下子干上去&#xff0c;就把测试环境的服务给整挂了&#xff0c;然后就迎来了一大波的投诉&#xff08;好惨呐&#xff09…

【6-循环神经网络】北京大学TensorFlow2.0

课程地址&#xff1a;【北京大学】Tensorflow2.0_哔哩哔哩_bilibiliPython3.7和TensorFlow2.1六讲&#xff1a;神经网络计算&#xff1a;神经网络的计算过程&#xff0c;搭建第一个神经网络模型神经网络优化&#xff1a;神经网络的优化方法&#xff0c;掌握学习率、激活函数、损…

基于微信小程序的校园自助打印系统小程序

文末联系获取源码 开发语言&#xff1a;Java 框架&#xff1a;springboot JDK版本&#xff1a;JDK1.8 服务器&#xff1a;tomcat7 数据库&#xff1a;mysql 5.7/8.0 数据库工具&#xff1a;Navicat11 开发软件&#xff1a;eclipse/myeclipse/idea Maven包&#xff1a;Maven3.3.…

GJB 5000B二级-RDM需求开发与管理

一、主要变化情况 新增3项(金色)、合并12->5项(绿色)、修订3项(蓝色) 合并的主要内容 1、合并过程域:原标准中RD与ReqM合并为RDM   需求开发与需求管理的过程活动紧密相关,在全生命周期中不可分割。 2、合并实践条目:精炼实践,聚焦重点   a)ReqM SP1.1“获…

UE运行时动态设置屏幕分辨率

文章目录 1.实现目标2.实现过程2.1 控制台直接输入命令2.2 通过蓝图设置3.参考资料1.实现目标 在UE中以独立进程(Standalone Game)方式启动游戏,并在运行时动态修改游戏窗口的屏幕分辨率大小,如下图所示屏幕大小从1000x800修改为600x400。 2.实现过程 参考文档和资料,通…

微服务服务治理

服务治理什么是服务治理&#xff1f;第一部分 服务注册第二部分 服务发现Nacos(常见注册中心)入门搭建Nacos环境Nacos远程调用实现商品服务的负载均衡什么是负载均衡&#xff1f;手动实现负载均衡利用组件实现负载均衡修改负载均衡策略什么是服务治理&#xff1f; 服务治理是微…

PySpark sql 中一些函数的总结(持续更新)

看到什么函数就记录了&#xff0c;没有什么逻辑关系 spark 中DataFrame 和 pandas的DataFrame的区别 1. F.split() 和 df.withColumn() from pyspark.sql import SparkSession from pyspark.sql import functions as F from pyspark.sql.types import *df spark.sql(sql) sp…

打开Jupyter notebook没有虚拟环境内核

放了个假&#xff0c;今天准备打开anaconda中的jupyter notebook重温一下之前的文档&#xff0c;结果双击Anaconda-Navigator出现了【应用程序“Anaconda-Navigator”无法打开】&#xff0c;想着利用终端也可以操作&#xff0c;于是使用下面命令激活了环境并打开jupter noteboo…