使用itextPDF实现PDF电子公章工具类
一、制作公章
在线网站:印章生成器 - Kalvin在线工具 (kalvinbg.cn)
然后对公章进行下载保存

盖章图片:

二、生成数字签名
2.1: java工具keytool生成p12数字证书文件
Keytool是用于管理和证书的工具,位于%JAVA_HOME%/bin目录。
使用JDK的keytool工具
- keytool在jdk的bin目录下

2.2:启动黑窗命令

2.3:生成数字文件
D:keystoreserver.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:keystoreserver.keystore
2.4:转换为p12格式,在命令行输入
注意:这里的路径和上面的路径要保持一直,不能就转不了P12 格式
keytool -importkeystore -srckeystore D:keystoreserver.keystore -destkeystore D:keystorewhj.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, ' ', 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(); } }
效果图:

如果代码写的有问题,欢迎大家评论交流,进行指点!!!
也希望大家点个关注哦~~~~~~~~