• 使用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:添加依赖:

    1. com.itextpdf
    2. itextpdf
    3. 5.5.10
    4. com.itextpdf
    5. itext-asian
    6. 5.2.0
    7. org.bouncycastle
    8. bcprov-jdk15on
    9. 1.49
    10. org.bouncycastle
    11. bcpkix-jdk15on
    12. 1.49

    3.2:盖章功能工具类

    功能:

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

    1. public class ItextUtil {
    2. /**
    3. *
    4. * 功能: keystory密码
    5. */
    6. public static final char[] PASSWORD = "111111".toCharArray();
    7. /**
    8. * 单多次签章通用
    9. *
    10. * @param src 盖章文件路径
    11. * @param target 盖章文件输出目标路径
    12. * @param signatureInfo 盖章实体
    13. */
    14. public void sign(String src, String target, SignatureInfo signatureInfo) {
    15. InputStream inputStream = null;
    16. FileOutputStream outputStream = null;
    17. ByteArrayOutputStream result = new ByteArrayOutputStream();
    18. try {
    19. inputStream = Files.newInputStream(Paths.get(src));
    20. ByteArrayOutputStream tempArrayOutputStream = new ByteArrayOutputStream();
    21. PdfReader reader = new PdfReader(inputStream);
    22. // 创建签章工具PdfStamper ,最后一个boolean参数是否允许被追加签名
    23. // false的话,pdf文件只允许被签名一次,多次签名,最后一次有效
    24. // true的话,pdf可以被追加签名,验签工具可以识别出每次签名之后文档是否被修改
    25. PdfStamper stamper = PdfStamper.createSignature(reader,
    26. tempArrayOutputStream, '\0', null, true);
    27. // 获取数字签章属性对象
    28. PdfSignatureAppearance appearance = stamper
    29. .getSignatureAppearance();
    30. appearance.setReason(signatureInfo.getReason());
    31. appearance.setLocation(signatureInfo.getLocation());
    32. // 设置签名的位置,页码,签名域名称,多次追加签名的时候,签名预名称不能一样 图片大小受表单域大小影响(过小导致压缩)
    33. // 签名的位置,是图章相对于pdf页面的位置坐标,原点为pdf页面左下角
    34. // 四个参数的分别是,图章左下角x,图章左下角y,图章右上角x,图章右上角y
    35. //四个参数的分别是,图章左下角x,图章左下角y,图章右上角x,图章右上角y
    36. appearance.setVisibleSignature(new Rectangle(280, 220, 140, 600), 1, "sig1");
    37. // 读取图章图片
    38. Image image = Image.getInstance(signatureInfo.getImagePath());
    39. appearance.setSignatureGraphic(image);
    40. appearance.setCertificationLevel(signatureInfo
    41. .getCertificationLevel());
    42. // 设置图章的显示方式,如下选择的是只显示图章(还有其他的模式,可以图章和签名描述一同显示)
    43. appearance.setRenderingMode(signatureInfo.getRenderingMode());
    44. // 这里的itext提供了2个用于签名的接口,可以自己实现,后边着重说这个实现
    45. // 摘要算法
    46. ExternalDigest digest = new BouncyCastleDigest();
    47. // 签名算法
    48. ExternalSignature signature = new PrivateKeySignature(
    49. signatureInfo.getPk(), signatureInfo.getDigestAlgorithm(),
    50. null);
    51. // 调用itext签名方法完成pdf签章 //数字签名格式,CMS,CADE
    52. MakeSignature.signDetached(appearance, digest, signature,
    53. signatureInfo.getChain(), null, null, null, 0,
    54. MakeSignature.CryptoStandard.CADES);
    55. inputStream = new ByteArrayInputStream(
    56. tempArrayOutputStream.toByteArray());
    57. // 定义输入流为生成的输出流内容,以完成多次签章的过程
    58. result = tempArrayOutputStream;
    59. outputStream = new FileOutputStream(new File(target));
    60. outputStream.write(result.toByteArray());
    61. outputStream.flush();
    62. } catch (Exception e) {
    63. e.printStackTrace();
    64. } finally {
    65. try {
    66. if (null != outputStream) {
    67. outputStream.close();
    68. }
    69. if (null != inputStream) {
    70. inputStream.close();
    71. }
    72. if (null != result) {
    73. result.close();
    74. }
    75. } catch (IOException e) {
    76. e.printStackTrace();
    77. }
    78. }
    79. }
    80. }

    测试代码:

    1. public static void main(String[] args) {
    2. try {
    3. ItextUtil app = new ItextUtil();
    4. // 将证书文件放入指定路径,并读取keystore ,获得私钥和证书链
    5. String pkPath = "src/main/resources/whj.p12";
    6. KeyStore ks = KeyStore.getInstance("PKCS12");
    7. ks.load(Files.newInputStream(Paths.get(pkPath)), PASSWORD);
    8. String alias = ks.aliases().nextElement();
    9. PrivateKey pk = (PrivateKey) ks.getKey(alias, PASSWORD);
    10. // 得到证书链
    11. Certificate[] chain = ks.getCertificateChain(alias);
    12. //需要进行签章的pdf
    13. String path = "C:\\Users\\ASUS\\Desktop\\sq.pdf";
    14. // 封装签章信息
    15. SignatureInfo signInfo = new SignatureInfo();
    16. signInfo.setReason("牛逼");
    17. signInfo.setLocation("666");
    18. signInfo.setPk(pk);
    19. signInfo.setChain(chain);
    20. signInfo.setCertificationLevel(PdfSignatureAppearance.NOT_CERTIFIED);
    21. signInfo.setDigestAlgorithm(DigestAlgorithms.SHA1);
    22. signInfo.setFieldName("demo");
    23. // 签章图片(网上生成的)
    24. signInfo.setImagePath("C:\\Users\\ASUS\\Desktop\\字节码\\学习测试30.png");
    25. signInfo.setRenderingMode(PdfSignatureAppearance.RenderingMode.GRAPHIC);
    26. 值越大,代表向x轴坐标平移 缩小 (反之,值越小,印章会放大)
    27. signInfo.setRectllx(100);
    28. 值越大,代表向y轴坐标向上平移(大小不变)
    29. signInfo.setRectlly(200);
    30. // 值越大 代表向x轴坐标向右平移 (大小不变)
    31. signInfo.setRecturx(150);
    32. // 值越大,代表向y轴坐标向上平移(大小不变)
    33. signInfo.setRectury(150);
    34. //签章后的pdf路径
    35. app.sign(path, "C:\\Users\\ASUS\\Desktop\\字节码\\out.pdf", signInfo);
    36. } catch (Exception e) {
    37. e.printStackTrace();
    38. }
    39. }

    实现对pdf 进行添加水印

    一、添加水印工具类

    1. public class WaterMark {
    2. /**
    3. * pdf生成水印
    4. *
    5. * @param srcPdfPath 插入前的文件路径
    6. * @param tarPdfPath 插入后的文件路径
    7. * @param WaterMarkContent 水印文案
    8. * @param numberOfPage 每页需要插入的条数
    9. * @throws Exception
    10. */
    11. public static void addWaterMark(String srcPdfPath, String tarPdfPath, String WaterMarkContent, int numberOfPage) throws Exception {
    12. PdfReader reader = new PdfReader(srcPdfPath);
    13. PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(tarPdfPath));
    14. PdfGState gs = new PdfGState();
    15. //设置字体
    16. BaseFont font = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
    17. // 设置透明度
    18. gs.setFillOpacity(0.4f);
    19. int total = reader.getNumberOfPages() + 1;
    20. PdfContentByte content;
    21. for (int i = 1; i < total; i++) {
    22. content = stamper.getOverContent(i);
    23. content.beginText();
    24. content.setGState(gs);
    25. //水印颜色
    26. content.setColorFill(BaseColor.DARK_GRAY);
    27. //水印字体样式和大小
    28. content.setFontAndSize(font, 35);
    29. //插入水印 循环每页插入的条数
    30. for (int j = 0; j < numberOfPage; j++) {
    31. content.showTextAligned(Element.ALIGN_CENTER, WaterMarkContent, 300, 200 * (j + 1), 30);
    32. }
    33. content.endText();
    34. }
    35. stamper.close();
    36. reader.close();
    37. // 删除源文件,这个可以根据自己的需要来是否删除源文件
    38. boolean b = deleteFile(srcPdfPath);
    39. System.out.println("PDF水印添加完成!");
    40. }
    41. /**
    42. *
    43. * 功能: 删除文件
    44. * @param path 需要删除的文件路径
    45. * @return {@link boolean}
    46. * @author luoheng
    47. */
    48. public static boolean deleteFile(String path) {
    49. boolean result = false;
    50. File file = new File(path);
    51. if (file.isFile() && file.exists()) {
    52. int tryCount = 0;
    53. while (!result && tryCount++ < 10) {
    54. System.gc();
    55. result = file.delete();
    56. }
    57. }
    58. return result;
    59. }
    60. }

    测试代码

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

    1. public static void main(String[] args) {
    2. /**
    3. * pdf生成水印
    4. *
    5. * @param srcPdfPath 需要加印的文件路径
    6. * @param tarPdfPath 加印后的文件输出路径
    7. * @param WaterMarkContent 水印文案
    8. * @param numberOfPage 每页需要插入的条数
    9. * @throws Exception
    10. */
    11. String srcPdfPath = "C:\\Users\\ASUS\\Desktop\\字节码\\out.pdf";
    12. String tarPdfPath = "C:\\Users\\ASUS\\Desktop\\字节码\\out2.pdf";
    13. String WaterMarkContent = "程序员小王";
    14. Integer numberOfPage = 3;
    15. try {
    16. // 添加水印
    17. WaterMark.addWaterMark(srcPdfPath, tarPdfPath, WaterMarkContent, numberOfPage);
    18. } catch (Exception e) {
    19. e.printStackTrace();
    20. }
    21. }

    效果图:

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

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

  • 相关阅读:
    分布式锁中-基于Zookeeper的实现是怎样
    阿里终面:10亿数据如何快速插入MySQL?
    安卓绘制原理之 MeasureCache优化了什么?
    [SWPUCTF 2022 新生赛]善哉善哉(隐写,新佛曰,MD5)
    Docker安装Prometheus + Grafana
    SkeyeVSS密集场所人流密度监控预警解决方案
    【学一点儿前端】ajax、axios和fetch的概念、区别和易混淆点
    【Hadoop】- MapReduce & YARN 初体验[9]
    初学Vue(全家桶)-第19天(vue3):计算属性、监视属性、vue3生命周期
    俄罗斯方块游戏开发教程8:下落处理
  • 原文地址:https://blog.csdn.net/qq_38140936/article/details/139634781