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


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

          
            <dependency>
                <groupId>com.itextpdfgroupId>
                <artifactId>itextpdfartifactId>
                <version>5.5.10version>
            dependency>
            <dependency>
                <groupId>com.itextpdfgroupId>
                <artifactId>itext-asianartifactId>
                <version>5.2.0version>
            dependency>
             <dependency>
                 
        <dependency>
          <groupId>org.bouncycastlegroupId>
          <artifactId>bcprov-jdk15onartifactId>
          <version>1.49version>
        dependency>
        <dependency>
          <groupId>org.bouncycastlegroupId>
          <artifactId>bcpkix-jdk15onartifactId>
          <version>1.49version>
        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();
            }
        }
    

    效果图:

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

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

  • 相关阅读:
    Fastjson反序列化漏洞
    【svn使用教程】
    java-net-php-python-32jspm手机销售网站程序计算机毕业设计程序
    好用的vue项目插件
    JavaScript 字符串(String) 对象
    【Python】将json字符串配置存储为.py配置文件
    【Vue Router的路由模式】
    如何在Ubuntu 18.04上安装Go并设置本地编程环境
    探索人工智能领域——30个名词详解
    ChatGPT被曝测试新功能:学习所有历史聊天,还能重置记忆、“阅后即焚”
  • 原文地址:https://www.cnblogs.com/blbl-blog/p/18231844