Itext7在PDF指定位置添加电子公章

目录

1. 电子公章的制作

2. java工具keytool生成p12数字证书文件

3. pom依赖

4. 实体类

5. 工具类及测试示例

6. 效果


1. 电子公章的制作

 做章网站:http://seal.biaozhiku.com/

  • 我们选择圆形印章

  • 然后输入公司名,输入章名输入编码然后点击395生成,最后点击保存图片,我们的个人专业章就实现了

2. java工具keytool生成p12数字证书文件

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

  • keytool在jdk的bin目录下

2. 打开keytool所在的bin目录,然后在上面的路径显示框中输入CMD,然后回车,即可在当前文件夹下打开命令提示符,并且路径是当前文件夹。

  • 生成数字文件,在命令行输入
  • 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

参数解释:

storepass keystore 文件存储密码
keypass 私钥加解密密码
alias 实体别名(包括证书私钥)
dname 证书个人信息
keyalt 采用公钥算法,默认是DSA keysize **长度(DSA算法对应的默认算法是sha1withDSA,不支持2048长度,此时需指定RSA)
validity 有效期
keystore 指定keystore文件

  • 转换为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. pom依赖

<dependency>
	<groupId>cn.hutool</groupId>
	<artifactId>hutool-all</artifactId>
	<version>5.8.11</version>
</dependency>
<!--itext7 pom-->
<dependency>
	<groupId>com.itextpdf</groupId>
	<artifactId>itext7-core</artifactId>
	<version>7.2.0</version>
	<type>pom</type>
</dependency>

4. 实体类

package com.example.demo.itext.model;

import com.itextpdf.signatures.PdfSignatureAppearance;

import java.security.PrivateKey;
import java.security.cert.Certificate;

public class SignatureInfo {
    private String reason; //签名的原因,显示在pdf签名属性中
    /**
     * 将证书文件放入指定路径,并读取keystore ,获得私钥和证书链
     */
    private String pkPath;

    /**
     * KeyStore类型
     */
    private String keyStoreType;

    /**
     * 原PDF文件路径
     */
    private String src;

    /**
     * 数字签章后的文件路径
     */
    private String target;
    private String location;//签名的地点,显示在pdf签名属性中
    private String digestAlgorithm;//摘要算法名称,例如SHA-1
    private String imagePath;//图章路径
    private String fieldName;//表单域名称
    private Certificate[] chain;//证书链
    private PrivateKey pk;//签名私钥
    private int certificationLevel = 0; //批准签章
    private PdfSignatureAppearance.RenderingMode renderingMode;//表现形式:仅描述,仅图片,图片和描述,签章者和描述
    //图章属性
    private float rectllx;//图章左下角x
    private float rectlly;//图章左下角y
    private float recturx;//图章右上角x
    private float rectury;//图章右上角y

    public float getRectllx() {
        return rectllx;
    }

    public void setRectllx(float rectllx) {
        this.rectllx = rectllx;
    }

    public float getRectlly() {
        return rectlly;
    }

    public void setRectlly(float rectlly) {
        this.rectlly = rectlly;
    }

    public float getRecturx() {
        return recturx;
    }

    public void setRecturx(float recturx) {
        this.recturx = recturx;
    }

    public float getRectury() {
        return rectury;
    }

    public void setRectury(float rectury) {
        this.rectury = rectury;
    }

    public String getReason() {
        return reason;
    }

    public void setReason(String reason) {
        this.reason = reason;
    }

    public String getLocation() {
        return location;
    }

    public void setLocation(String location) {
        this.location = location;
    }

    public String getDigestAlgorithm() {
        return digestAlgorithm;
    }

    public void setDigestAlgorithm(String digestAlgorithm) {
        this.digestAlgorithm = digestAlgorithm;
    }

    public String getImagePath() {
        return imagePath;
    }

    public void setImagePath(String imagePath) {
        this.imagePath = imagePath;
    }

    public String getFieldName() {
        return fieldName;
    }

    public void setFieldName(String fieldName) {
        this.fieldName = fieldName;
    }

    public Certificate[] getChain() {
        return chain;
    }

    public void setChain(Certificate[] chain) {
        this.chain = chain;
    }

    public PrivateKey getPk() {
        return pk;
    }

    public void setPk(PrivateKey pk) {
        this.pk = pk;
    }

    public int getCertificationLevel() {
        return certificationLevel;
    }

    public void setCertificationLevel(int certificationLevel) {
        this.certificationLevel = certificationLevel;
    }

    public PdfSignatureAppearance.RenderingMode getRenderingMode() {
        return renderingMode;
    }

    public void setRenderingMode(PdfSignatureAppearance.RenderingMode renderingMode) {
        this.renderingMode = renderingMode;
    }


    public String getPkPath() {
        return pkPath;
    }

    public void setPkPath(String pkPath) {
        this.pkPath = pkPath;
    }

    public String getKeyStoreType() {
        return keyStoreType;
    }

    public void setKeyStoreType(String keyStoreType) {
        this.keyStoreType = keyStoreType;
    }

    public String getSrc() {
        return src;
    }

    public void setSrc(String src) {
        this.src = src;
    }

    public String getTarget() {
        return target;
    }

    public void setTarget(String target) {
        this.target = target;
    }
}

5. 工具类及测试示例

ItextUtil工具类参考:https://mp.csdn.net/mp_blog/creation/editor/128789640
package com.example.demo.itext.util;

import com.example.demo.itext.model.KeyWordBean;
import com.example.demo.itext.model.SignatureInfo;
import com.itextpdf.io.image.ImageData;
import com.itextpdf.io.image.ImageDataFactory;
import com.itextpdf.kernel.geom.Rectangle;
import com.itextpdf.kernel.pdf.PdfReader;
import com.itextpdf.kernel.pdf.StampingProperties;
import com.itextpdf.signatures.*;
import lombok.SneakyThrows;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.springframework.util.ResourceUtils;

import java.io.*;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.Security;
import java.security.cert.Certificate;
import java.util.List;
import java.util.Map;

/**
 * 功能描述: pdf数字签章工具类 <br>
 *
 * @Author: lhp
 * @Date: 2023/1/29 15:45
 */
public class PdfStampUtil {

    /**
     * keystory密码,可以放到配置文件中
     */
    public static final char[] PASSWORD = "111111".toCharArray();

    /**
     * 功能描述: PDF添加数字签章 <br>
     *
     * @Param: [src:原PDF文件路径, target:数字签章后的文件路径, signatureInfo:参数]
     * @Return: void
     * @Author: lhp
     * @Date: 2023/1/29 15:33
     */
    public static void sign(SignatureInfo signatureInfo) {
        // 原PDF文件路径
        String src = signatureInfo.getSrc();
        // 数字签章后的文件输出路径
        String target = signatureInfo.getTarget();
        InputStream inputStream = null;
        FileOutputStream outputStream = null;
        ByteArrayOutputStream result = new ByteArrayOutputStream();
        try {
            inputStream = new FileInputStream(src);
            ByteArrayOutputStream tempArrayOutputStream = new ByteArrayOutputStream();
            PdfReader reader = new PdfReader(inputStream);
            PdfSigner stamper = new PdfSigner(reader, tempArrayOutputStream, new StampingProperties());
            stamper.setCertificationLevel(signatureInfo.getCertificationLevel());

            // 获取数字签章属性对象
            PdfSignatureAppearance appearance = stamper.getSignatureAppearance();
            appearance.setReason(signatureInfo.getReason());
            appearance.setLocation(signatureInfo.getLocation());


            // 读取图章图片
            ImageData image = ImageDataFactory.create(signatureInfo.getImagePath());
            appearance.setSignatureGraphic(image);

            Float rectllx = signatureInfo.getRectllx();
            System.out.println("x:" + rectllx);
            Float rectlly = signatureInfo.getRectlly();
            System.out.println("y:" + rectlly);
            Float recturx = signatureInfo.getRecturx();
            System.out.println("recturx:" + recturx);
            Float rectury = signatureInfo.getRectury();
            System.out.println("rectury:" + rectury);
            appearance.setPageNumber(1);

            appearance.setPageRect(new Rectangle(rectllx, rectlly, recturx, rectury));
//            appearance.setPageRect(new Rectangle(rectllx, rectlly, image.getWidth(), image.getHeight()));

            // 设置图章的显示方式,如下选择的是只显示图章(还有其他的模式,可以图章和签名描述一同显示)
            appearance.setRenderingMode(signatureInfo.getRenderingMode());

            // 这里的itext提供了2个用于签名的接口,可以自己实现,后边着重说这个实现
            // 摘要算法
            IExternalDigest digest = new BouncyCastleDigest();
            // 签名算法
            Security.addProvider(new BouncyCastleProvider());
            // 签名算法
            IExternalSignature signature = new PrivateKeySignature(signatureInfo.getPk(), signatureInfo.getDigestAlgorithm(), BouncyCastleProvider.PROVIDER_NAME);
            // 调用itext签名方法完成pdf签章 //数字签名格式,CMS,CADE
            stamper.signDetached(digest, signature, signatureInfo.getChain(), null, null, null, 0, PdfSigner.CryptoStandard.CADES);

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

            outputStream = new FileOutputStream(target);
            outputStream.write(result.toByteArray());
            outputStream.flush();

            reader.close();
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            try {
                if (null != outputStream) {
                    outputStream.close();
                }
                if (null != inputStream) {
                    inputStream.close();
                }
                if (null != result) {
                    result.close();
                }
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }

    @SneakyThrows
    public static void pdfStamp(SignatureInfo signatureInfo) {
        String keyStoreType = signatureInfo.getKeyStoreType();
        KeyStore ks = KeyStore.getInstance(keyStoreType);
        // 将证书文件放入指定路径,并读取keystore ,获得私钥和证书链
        ks.load(new FileInputStream(ResourceUtils.getFile("classpath:whj.p12")), PASSWORD);
        String alias = ks.aliases().nextElement();
        PrivateKey pk = (PrivateKey) ks.getKey(alias, PASSWORD);
        // 得到证书链
        Certificate[] chain = ks.getCertificateChain(alias);

        signatureInfo.setPk(pk);
        signatureInfo.setChain(chain);
        signatureInfo.setCertificationLevel(1);
        signatureInfo.setDigestAlgorithm(DigestAlgorithms.SHA1);
        signatureInfo.setRenderingMode(PdfSignatureAppearance.RenderingMode.GRAPHIC);

        sign(signatureInfo);
    }

    public static void main(String[] args) {
        SignatureInfo signInfo = new SignatureInfo();
        signInfo.setReason("理由");
        signInfo.setLocation("位置");

        signInfo.setFieldName("demo");

        // 签章图片
        String imagePath = "F:\\software\\myfile\\南无阿弥陀佛电子印章制作平台.png";
        signInfo.setImagePath(imagePath);
        // 需要进行签章的pdf
        String path = "F:\\software\\myfile\\txt12_加水印_加水印.pdf";
        signInfo.setSrc(path);

        String target = "F:\\software\\myfile\\txt12-PdfStamp15.pdf";
        signInfo.setTarget(target);
        String keyStoreType = "PKCS12";
        signInfo.setKeyStoreType(keyStoreType);

        // 值越大,代表向x轴坐标平移 缩小 (反之,值越小,印章会橫向放大)
//        signInfo.setRectllx(100);
        // 值越大,代表向y轴坐标向上平移(反之,值越小,印章会纵向放大)
//        signInfo.setRectlly(100);
        // 值越大   代表向x轴坐标向右平移  (大小不变)
        signInfo.setRecturx(100);
        // 值越大,代表向y轴坐标向上平移(大小不变)
        signInfo.setRectury(100);

        Map<Integer, List<KeyWordBean>> listMap = ItextUtil.keyWordLocationMap("负责人签名:", path);
        KeyWordBean keyWordBean = listMap.get(1).get(0);
//        KeyWordBean keyWordBean = listMap.get(1).get(1);
        signInfo.setRectllx(keyWordBean.getX() + 70);
        signInfo.setRectlly(keyWordBean.getY() - 50);

        pdfStamp(signInfo);
    }
}

6. 效果

参考:

历经一个月总结使用java实现pdf文件的电子签字+盖章+防伪二维码+水印+PDF文件加密的全套解决方案: 历经一个月总结使用java实现pdf文件的电子签字+盖章+防伪二维码+水印+PDF文件加密的全套解决方案

itext根据关键字定位在pdf中的坐标_牛一样的程序员的博客-CSDN博客_itext 坐标

以下是使用itextpdf类在pdf指定位置写入字符串的示例代码: ```java import com.itextpdf.text.Document; import com.itextpdf.text.DocumentException; import com.itextpdf.text.Font; import com.itextpdf.text.Paragraph; import com.itextpdf.text.pdf.BaseFont; import com.itextpdf.text.pdf.PdfContentByte; import com.itextpdf.text.pdf.PdfReader; import com.itextpdf.text.pdf.PdfStamper; import java.io.FileOutputStream; import java.io.IOException; public class PdfWriterExample { public static void main(String[] args) { try { // 读取原始PDF文件 PdfReader reader = new PdfReader("input.pdf"); // 创建输出PDF文件 PdfStamper stamper = new PdfStamper(reader, new FileOutputStream("output.pdf")); // 获取指定页面的内容流 PdfContentByte content = stamper.getOverContent(1); // 设置字体 BaseFont baseFont = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED); Font font = new Font(baseFont, 12, Font.NORMAL); // 在指定位置添加文本 content.beginText(); content.setFontAndSize(baseFont, 12); content.showTextAligned(PdfContentByte.ALIGN_LEFT, "Hello, World!", 100, 100, 0); content.endText(); // 关闭PDF文件 stamper.close(); reader.close(); } catch (IOException | DocumentException e) { e.printStackTrace(); } } } ``` 这段代码使用itextpdf库来读取原始的PDF文件,并在指定位置添加文本。首先,我们创建一个PdfReader对象来读取原始PDF文件。然后,我们创建一个PdfStamper对象来写入输出PDF文件。通过调用`getOverContent()`方法,我们可以获取指定页面的内容流。接下来,我们设置字体并使用`showTextAligned()`方法在指定位置添加文本。最后,我们关闭PDF文件。 请注意,这只是一个示例代码,你需要根据你的实际需求进行适当的修改。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值