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

news/2025/1/22 14:54:33/文章来源:https://www.cnblogs.com/blbl-blog/p/18231844

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

一、制作公章

在线网站:印章生成器 - 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,图章右上角yappearance.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,CADEMakeSignature.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);//需要进行签章的pdfString 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.hqwc.cn/news/721609.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

前后端分离的四种开发模式

前后端分离已经成为了开发的主流模式,很多老铁认为前后端分离就是各干各的,其实不然。 前后端分离有多种模式,我们一一详解。1. 前后端完全分离 在这种模式下,前端和后端是完全独立的两个系统。前端使用一种框架(如React、Angular、Vue.js等)来实现用户界面,通过API调用…

2024/6/7

今天进行了数据库相关实验。 (1)查询所有供应商情况,先按城市升序排列,城市相同按供应商名称降序排列。(2)查询所有零件情况,先按零件名称升序排列,零件名称相同按重量降序排列。(3)查询项目名中含有“厂”的项目情况。(4)查询供应商名称中第二个字为“方”的供应商…

美团面试:百亿级分片,如何设计基因算法?

文章很长,且持续更新,建议收藏起来,慢慢读!疯狂创客圈总目录 博客园版 为您奉上珍贵的学习资源 : 免费赠送 :《尼恩Java面试宝典》 持续更新+ 史上最全 + 面试必备 2000页+ 面试必备 + 大厂必备 +涨薪必备 免费赠送 :《尼恩技术圣经+高并发系列PDF》 ,帮你 实现技术自由,…

Bug记录:Content-Type application/json;charset=UTF-8 is not supported异常解决

Content-Type application/json;charset=UTF-8 is not supported异常解决 前提:确定不是因为Content-Type导致的异常,controller层有注解@RequestBody。 报错详情:确定不是因为缺少Jackson依赖或者版本过低:注意到报错信息上边有一条警告日志: .c.j.MappingJackson2HttpMe…

6.7哈希表

哈希表 哈希表(英文名字为Hash table,国内也有一些算法书籍翻译为散列表,大家看到这两个名称知道都是指hash table就可以了)。哈希表是根据关键码的值而直接进行访问的数据结构。数组就是一张哈希表。哈希表中关键码就是数组的索引下标,然后通过下标直接访问数组中的元素。…

Day16 | 104.二叉树的最大深度 、111.二叉树的最小深度 、222.完全二叉树的节点个数

104.二叉树的最大深度 (优先掌握递归) 什么是深度,什么是高度,如何求深度,如何求高度,这里有关系到二叉树的遍历方式。 大家 要先看视频讲解,就知道以上我说的内容了,很多录友刷过这道题,但理解的还不够。 题目链接/文章讲解/视频讲解: https://programmercarl.com/0…

计算机简史 第1章 手动计算时代

我们在数字出现之前,人们怎么计数呢?‍ 手指计数 我们在数字出现之前,人们怎么计数呢?如何统计人口,统计今天打到了多少猎物? 最开始,人们曾尝试过用手指和脚趾,一指/趾就是 1,双手就是 10,一人就是 20,为此史上有诸多民族曾使用二十进制。藏文中,「人」字有 20 的…

uni-app项目uview的表单验证在小程序上不生效

前情 uni-app是我比较喜欢的跨平台框架,它能开发小程序/H5/APP(安卓/iOS),重要的是对前端开发友好,自带的IDE让开发体验非常棒,公司项目就是主推uni-app,在uniapp生态中uView是其中非常好的全平台的第三方开源ui库,我在公司项目中果断的使用了它。 坑位 在用uView做小程序…

四层反向代理和七层反向代理

1、概述代理也称网络代理,是一种特殊的网络服务,允许一个网络终端(一般为客户端)通过这个服务与另一个网络终端(一般为服务器)进行非直接的连接。一些网关、路由器等网络设备具备网络代理功能。一般认为代理服务有利于保障网络终端的隐私或安全,防止攻击。 2、四层网络…

Python的基本

python之基本介绍(1)什么是pythonpython 是一门编程语言python是一门面向对象,解释型的动态类型的编程语言 guido van rossunm (吉多*范罗苏姆) 在1989年发明,第一个公开发行版本与1991年; python在市面上的版本:python 2.7 (以前用的非常多)目前用的版本是3.0 版本最…

IP-域名关联关系系统设计

0x01 数据库表实现 IP域名关系系统包括域名库检索和whois库检索,详情如下。 域名库检索 域名库检索支持以下5项功能: 1.通过过滤器检索 筛选条件包含IP地址、口令、工具名称、可利用的漏洞编号、创建时间; 2.通过关键字检索 在查询框中输入域名库名称的部分关键词,支持模糊…