使用itextPDF实现PDF电子公章工具类

news2024/11/25 0:46:19

一、制作公章

在线网站:印章生成器 - Kalvin在线工具 (kalvinbg.cn)

然后对公章进行下载保存

盖章图片:

二、生成数字签名

2.1: java工具keytool生成p12数字证书文件

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

  • keytool在jdk的bin目录下

2.2:启动黑窗命令

2.3:生成数字文件

D:\keystore\server.keystore : 就是生成的文件地址

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

2.4:转换为p12格式,在命令行输入

注意:这里的路径和上面的路径要保持一直,不能就转不了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.1:添加依赖:

      <!-- itextpdf依赖 -->
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>itextpdf</artifactId>
            <version>5.5.10</version>
        </dependency>
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>itext-asian</artifactId>
            <version>5.2.0</version>
        </dependency>
         <dependency>
             <!-- 摘要算法 -->
    <dependency>
      <groupId>org.bouncycastle</groupId>
      <artifactId>bcprov-jdk15on</artifactId>
      <version>1.49</version>
    </dependency>
    <dependency>
      <groupId>org.bouncycastle</groupId>
      <artifactId>bcpkix-jdk15on</artifactId>
      <version>1.49</version>
    </dependency>

3.2:盖章功能工具类

功能:

对传入的pdf 文件进行盖章处理

public class ItextUtil {

    /**
     *
     * 功能: keystory密码
     */

    public static final char[] PASSWORD = "111111".toCharArray();

    /**
     * 单多次签章通用
     *
     * @param src 盖章文件路径
     * @param target 盖章文件输出目标路径
     * @param signatureInfo 盖章实体
     */
    public void sign(String src, String target, SignatureInfo signatureInfo) {
        InputStream inputStream = null;
        FileOutputStream outputStream = null;
        ByteArrayOutputStream result = new ByteArrayOutputStream();
        try {
            inputStream = Files.newInputStream(Paths.get(src));
            ByteArrayOutputStream tempArrayOutputStream = new ByteArrayOutputStream();
            PdfReader reader = new PdfReader(inputStream);
            // 创建签章工具PdfStamper ,最后一个boolean参数是否允许被追加签名
            // false的话,pdf文件只允许被签名一次,多次签名,最后一次有效
            // true的话,pdf可以被追加签名,验签工具可以识别出每次签名之后文档是否被修改
            PdfStamper stamper = PdfStamper.createSignature(reader,
                    tempArrayOutputStream, '\0', null, true);
            // 获取数字签章属性对象
            PdfSignatureAppearance appearance = stamper
                    .getSignatureAppearance();
            appearance.setReason(signatureInfo.getReason());
            appearance.setLocation(signatureInfo.getLocation());
            // 设置签名的位置,页码,签名域名称,多次追加签名的时候,签名预名称不能一样 图片大小受表单域大小影响(过小导致压缩)
            // 签名的位置,是图章相对于pdf页面的位置坐标,原点为pdf页面左下角
            // 四个参数的分别是,图章左下角x,图章左下角y,图章右上角x,图章右上角y
            //四个参数的分别是,图章左下角x,图章左下角y,图章右上角x,图章右上角y
            appearance.setVisibleSignature(new Rectangle(280, 220, 140, 600), 1, "sig1");
            // 读取图章图片
            Image image = Image.getInstance(signatureInfo.getImagePath());
            appearance.setSignatureGraphic(image);
            appearance.setCertificationLevel(signatureInfo
                    .getCertificationLevel());
            // 设置图章的显示方式,如下选择的是只显示图章(还有其他的模式,可以图章和签名描述一同显示)
            appearance.setRenderingMode(signatureInfo.getRenderingMode());
            // 这里的itext提供了2个用于签名的接口,可以自己实现,后边着重说这个实现
            // 摘要算法
            ExternalDigest digest = new BouncyCastleDigest();
            // 签名算法
            ExternalSignature signature = new PrivateKeySignature(
                    signatureInfo.getPk(), signatureInfo.getDigestAlgorithm(),
                    null);
            // 调用itext签名方法完成pdf签章 //数字签名格式,CMS,CADE
            MakeSignature.signDetached(appearance, digest, signature,
                    signatureInfo.getChain(), null, null, null, 0,
                    MakeSignature.CryptoStandard.CADES);

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

            outputStream = new FileOutputStream(new File(target));
            outputStream.write(result.toByteArray());
            outputStream.flush();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (null != outputStream) {
                    outputStream.close();
                }
                if (null != inputStream) {
                    inputStream.close();
                }
                if (null != result) {
                    result.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

}

测试代码:

public static void main(String[] args) {
        try {
            ItextUtil app = new ItextUtil();
            // 将证书文件放入指定路径,并读取keystore ,获得私钥和证书链
            String pkPath = "src/main/resources/whj.p12";
            KeyStore ks = KeyStore.getInstance("PKCS12");
            ks.load(Files.newInputStream(Paths.get(pkPath)), PASSWORD);
            String alias = ks.aliases().nextElement();
            PrivateKey pk = (PrivateKey) ks.getKey(alias, PASSWORD);
            // 得到证书链
            Certificate[] chain = ks.getCertificateChain(alias);
            //需要进行签章的pdf

            String path = "C:\\Users\\ASUS\\Desktop\\sq.pdf";
            // 封装签章信息
            SignatureInfo signInfo = new SignatureInfo();
            signInfo.setReason("牛逼");
            signInfo.setLocation("666");
            signInfo.setPk(pk);
            signInfo.setChain(chain);
            signInfo.setCertificationLevel(PdfSignatureAppearance.NOT_CERTIFIED);
            signInfo.setDigestAlgorithm(DigestAlgorithms.SHA1);
            signInfo.setFieldName("demo");

            // 签章图片(网上生成的)
            signInfo.setImagePath("C:\\Users\\ASUS\\Desktop\\字节码\\学习测试30.png");
            signInfo.setRenderingMode(PdfSignatureAppearance.RenderingMode.GRAPHIC);
             值越大,代表向x轴坐标平移 缩小 (反之,值越小,印章会放大)
            signInfo.setRectllx(100);
             值越大,代表向y轴坐标向上平移(大小不变)
            signInfo.setRectlly(200);
            // 值越大   代表向x轴坐标向右平移  (大小不变)
            signInfo.setRecturx(150);
            // 值越大,代表向y轴坐标向上平移(大小不变)
            signInfo.setRectury(150);

            //签章后的pdf路径
            app.sign(path, "C:\\Users\\ASUS\\Desktop\\字节码\\out.pdf", signInfo);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

实现对pdf 进行添加水印

一、添加水印工具类

public class WaterMark {
    /**
     * pdf生成水印
     *
     * @param srcPdfPath       插入前的文件路径
     * @param tarPdfPath       插入后的文件路径
     * @param WaterMarkContent 水印文案
     * @param numberOfPage     每页需要插入的条数
     * @throws Exception
     */
    public static void addWaterMark(String srcPdfPath, String tarPdfPath, String WaterMarkContent, int numberOfPage) throws Exception {
        PdfReader reader = new PdfReader(srcPdfPath);
        PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(tarPdfPath));
        PdfGState gs = new PdfGState();
        //设置字体
        BaseFont font = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);

        // 设置透明度
        gs.setFillOpacity(0.4f);

        int total = reader.getNumberOfPages() + 1;
        PdfContentByte content;
        for (int i = 1; i < total; i++) {
            content = stamper.getOverContent(i);
            content.beginText();
            content.setGState(gs);
            //水印颜色
            content.setColorFill(BaseColor.DARK_GRAY);
            //水印字体样式和大小
            content.setFontAndSize(font, 35);
            //插入水印  循环每页插入的条数
            for (int j = 0; j < numberOfPage; j++) {
                content.showTextAligned(Element.ALIGN_CENTER, WaterMarkContent, 300, 200 * (j + 1), 30);
            }
            content.endText();
        }
        stamper.close();
        reader.close();
        // 删除源文件,这个可以根据自己的需要来是否删除源文件
        boolean b = deleteFile(srcPdfPath);
        System.out.println("PDF水印添加完成!");
    }
    /**
     *
     * 功能: 删除文件
     * @param path  需要删除的文件路径
     * @return {@link boolean}
     * @author luoheng
     */

    public static boolean deleteFile(String path) {
        boolean result = false;
        File file = new File(path);
        if (file.isFile() && file.exists()) {
            int tryCount = 0;
            while (!result && tryCount++ < 10) {
                System.gc();
                result = file.delete();
            }
        }
        return result;
    }


}

测试代码

我们传入需要加水印的pdf,设置对应的格式,数量,字体,以及对应输出的文件地址

public static void main(String[] args) {
        /**
         * pdf生成水印
         *
         * @param srcPdfPath       需要加印的文件路径
         * @param tarPdfPath       加印后的文件输出路径
         * @param WaterMarkContent 水印文案
         * @param numberOfPage     每页需要插入的条数
         * @throws Exception
         */
        String srcPdfPath = "C:\\Users\\ASUS\\Desktop\\字节码\\out.pdf";
        String tarPdfPath = "C:\\Users\\ASUS\\Desktop\\字节码\\out2.pdf";
        String WaterMarkContent = "程序员小王";
        Integer numberOfPage = 3;
        try {
            // 添加水印
            WaterMark.addWaterMark(srcPdfPath, tarPdfPath, WaterMarkContent, numberOfPage);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

效果图:

如果代码写的有问题,欢迎大家评论交流,进行指点!!!

也希望大家点个关注哦~~~~~~~~

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

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

相关文章

数学建模----单源最短路径模型建立和求解

目录 1.引言和声明 2.单源最短路径 3.建立模型 4.代码求解 1.引言和声明 &#xff08;1&#xff09;最近又在准备学习matlab,有了一些新的理解和体会&#xff0c;记录一下&#xff1b; &#xff08;2&#xff09;这个首先要声明两个符号&#xff0c;这两个符号也是今天才知…

抖音混剪素材哪里找?可以混剪搬运视频素材网站分享

在抖音上制作精彩的视频离不开高质量的素材资源。今天&#xff0c;我将为大家推荐几个优质的网站&#xff0c;帮助你解决素材短缺的问题。这些网站不仅提供丰富的素材&#xff0c;还符合百度SEO优化的规则&#xff0c;让你的视频更容易被发现。 蛙学府素材网 首先要推荐的是蛙…

AOP切面加自定义注解,实现日志记录

AOP切面加自定义注解&#xff0c;实现日志记录 一、AOP二、准备工作三、添加AOP&#xff0c;把日志保存到数据库 一、AOP 在软件业&#xff0c;AOP为Aspect Oriented Programming的缩写&#xff0c;意为&#xff1a;面向切面编程&#xff0c;通过预编译方式和运行期动态代理实…

IT入门知识博客文章大纲第二部分《编程语言》(2/10)

目录 IT入门知识博客文章大纲第二部分《编程语言》 1.引言 2.编程语言概述 2.1 编程语言的发展历程 2.2 编程范式 3.常见的编程语言 3.1 Python 3.2 Java 3.3 C 3.4 JavaScript 3.5 Ruby 4.编程语言的选择 4.1 技术需求 4.2 团队技能 4.3 社区和生态系统 4.4 可…

3d渲染的类型,渲染100邀请码1a12

3D渲染有不同的类型和方法&#xff0c;它们各有各的优缺点和适用场景&#xff0c;这里我们简单介绍下。 1、离线渲染 离线渲染也被称作预渲染&#xff0c;是指在不考虑时间限制的情况下&#xff0c;生成高质量二维图像或视频的方法。离线渲染通常用于电影、广告、设计等非交互…

【LeetCode】LCR 124. 推理二叉树

题目链接&#xff1a; 题目描述&#xff1a;某二叉树的先序遍历结果记录于整数数组 preorder&#xff0c;它的中序遍历结果记录于整数数组 inorder。请根据 preorder 和 inorder 的提示构造出这棵二叉树并返回其根节点。 注意&#xff1a;preorder 和 inorder 中均不含重复数字…

ESD与EOS区别

最近小白在做项目时&#xff0c;被一个实习生问道了&#xff0c;关于EOS与ESD区别。说实话&#xff0c;以前专注于测试debug的我&#xff0c;在回答对方时&#xff0c;并没法做到太全面的解答。于是乎&#xff0c;借助周内的空闲时间&#xff0c;小白还是简单学习总结了一番。 …

68. UE5 RPG 优化敌人角色的表现效果

我们现在已经有了四个敌人角色&#xff0c;接下来&#xff0c;处理一下在战斗中遇到的问题。 处理角色死亡后还会攻击的问题 因为我们有角色溶解的效果&#xff0c;角色在死亡以后的5秒钟才会被销毁掉。所以在这五秒钟之内&#xff0c;角色其实还是会攻击。主要时因为AI行为树…

Python开发者的7个PyCharm必备插件

大家好&#xff0c;本文将推荐使用7个必备的PyCharm IDE设置和插件&#xff0c;希望能帮助了解如何修改和增强IDE体验&#xff0c;使其更适合个人使用&#xff0c;毕竟作为开发者&#xff0c;大部分时间都是在这里工作。 1.String Manipulation 【链接】&#xff1a;https://…

【机器学习】机器学习重要分支——强化学习:从理论到实践

文章目录 强化学习&#xff1a;从理论到实践引言第一章 强化学习的基本概念1.1 什么是强化学习1.2 强化学习的基本组成部分1.3 马尔可夫决策过程 第二章 强化学习的核心算法2.1 Q学习2.2 深度Q网络&#xff08;DQN&#xff09;2.3 策略梯度方法 第三章 强化学习的应用实例3.1 游…

【Go语言】Gin 框架教程

Gin 框架教程 1.第一个 Gin 程序 1.1 Gin 安装 # 执行执行如下操作即可&#xff0c;安装Gin前需要安装Go环境 go get -u -v github.com/gin-gonic/gin # -v&#xff1a;打印出被构建的代码包的名字 # -u&#xff1a;已存在相关的代码包&#xff0c;强行更新代码包及其依赖包…

顶顶通呼叫中心中间件-限制最大通话时间(mod_cti基于FreeSWITCH)

顶顶通呼叫中心中间件-限制最大通话时间(mod_cti基于FreeSWITCH) 一、最大通话时间 1、配置拨号方案 1、点击拨号方案 ->2、在框中输入通话最大时长->3、点击添加->4、根据图中配置->5、勾选continue。修改拨号方案需要等待一分钟即可生效 action"sched…

趣味C语言——【猜数字】小游戏

&#x1f970;欢迎关注 轻松拿捏C语言系列&#xff0c;来和 小哇 一起进步&#xff01;✊ &#x1f389;创作不易&#xff0c;请多多支持&#x1f389; &#x1f308;感谢大家的阅读、点赞、收藏和关注&#x1f495; &#x1f339;如有问题&#xff0c;欢迎指正 感谢 目录 代码…

高阶数据结构[3]图的遍历

图的两种遍历 前言 1.图的遍历 2.图的广度优先遍历 3.图的深度优先遍历 4.总结 前言 书接上回&#xff0c;这篇文章将在图的存储结构上学习图的遍历方法。 图的遍历分为两种&#xff1a;1.BFS&#xff08;Breadth First Search&#xff09;宽度优先搜索 2.DFS&#xff08…

Linux构建本地时间同步ntp

环境介绍&#xff1a; 主机名 IP地址 系统发行版 环境 Node01 192.168.100.102 Centos 7.4 可联网、已关闭防火墙selinux Node02 192.168.100.103 Centos 7.4 已关闭防火墙selinux 1.主节点同步阿里云标准时间 在保证连接外网的情况下&#xff0c;同步阿里服务器的…

[Linux] TCP协议介绍(1): TCP协议 数据格式、可靠性的控制、标记位... 简单介绍

上一篇文章, 针对UDP协议的格式、数据等内容做了一些简单的介绍. 并且提到, 在网络协议栈TCP/IP模型的传输层中, 有两个最具代表性的协议: UDP和TCP 下面就简单介绍分析一下TCP协议 TCP协议, 完整的称呼其实叫: 传输控制协议(Transmission Control Protocol) 从名字就可以看出…

MobaXterm卡顿问题 解决方案

写在最前面&#xff0c;解决方案是&#xff1a;setting->X11->关闭Automatically start X server at MobaXterm start up 若有空&#xff0c;可以看一下下面的排障流程~ 现象描述 使用MobaXterm作为远程连接工具的时候&#xff0c;会出现很奇怪的卡顿问题。每隔几秒&…

Modbus转Profibus网关接变频器:实现工业自动化无缝连接

一、背景 在工业自动化领域&#xff0c;Modbus和Profibus是两种常见的通讯协议&#xff0c;而变频器作为控制电机转速的重要设备。为了实现不同设备之间的无缝连接和数据传输&#xff0c;现场大多数采用Modbus转Profibus网关&#xff08;XD-MDPB100&#xff09;来解决Modbus设…

linux 部署瑞数6实战(维普,药监局)sign第二部分

声明 本文章中所有内容仅供学习交流使用&#xff0c;不用于其他任何目的&#xff0c;抓包内容、敏感网址、数据接口等均已做脱敏处理&#xff0c;严禁用于商业用途和非法用途&#xff0c;否则由此产生的一切后果均与作者无关&#xff01;wx …

从业余到专业:拼多多跨境选品师的成功之路

拼多多(Pinduoduo)作为中国颇具影响力的电商平台&#xff0c;其跨境电商领域近年来发展迅猛。作为跨境选品师&#xff0c;是否可以将其作为一项副业呢?以下将探讨这个问题&#xff0c;并提供一些实用建议。 1. 跨境电商市场概述 跨境电商市场正在迅速扩展&#xff0c;尤其是在…