使用itext实现pdf图片签章

1:配置环境
首先配置开发环境,本人使用itext5生成pdf,除了,itext5的一些基础包外,org.bouncycastle的两个包是itext生成证书所依赖的包,必须添加,否则会提示ClassNotFound,我百度查到的解决方案,详细见
解决方案

当然网上还有文章说将bcprov-jdk15on-149.jar放到jdk安装目录jre/lib/ext 见 [其他解决思路](http://blog.csdn.net/moxuelang/article/details/17415147)
只能解决当前问题,还会出现其他类找不到的情况,按照以下只在pom文件中添加依赖的org.bouncycastle包即可。
<dependency>
      <groupId>com.itextpdfgroupId>
      <artifactId>itextpdfartifactId>
      <version>5.5.9version>
    dependency>

    <dependency>
      <groupId>com.itextpdfgroupId>
      <artifactId>itext-pdfaartifactId>
      <version>5.5.9version>
    dependency>

    <dependency>
      <groupId>com.itextpdfgroupId>
      <artifactId>itext-xtraartifactId>
      <version>5.5.9version>
    dependency>

    <dependency>
      <groupId>com.itextpdf.toolgroupId>
      <artifactId>xmlworkerartifactId>
      <version>5.5.9version>
    dependency>

    <dependency>
        <groupId>org.bouncycastlegroupId>
        <artifactId>bcprov-jdk15onartifactId>
        <version>1.49version>
        <type>jartype>
        <scope>compilescope>
        <optional>trueoptional>
    dependency>
    <dependency>
        <groupId>org.bouncycastlegroupId>
        <artifactId>bcpkix-jdk15onartifactId>
        <version>1.49version>
        <type>jartype>
        <scope>compilescope>
        <optional>trueoptional>
    dependency>

2:生成p12自签名数字证书
签章需要用到数字证书,有两种方式,1.去CA申请,2.自己生成,CA端申请的证书的好处是能验证加签证书的有效性,自己生成pdf工具无法验证有效性,但不影响加签效果。
我们使用 jdk tool 工具实现,只要电脑安装了jdk就可以操作:
1.keytool支持交互的方式提供证书信息。要生成一个p12证书,必须了解这样几个参数:
● -genkeypair 生成证书
● -keystore 生成证书的路径和文件名
● -storetype 生成的证书类型,使用pkcs12指定p12格式证书
● -validity 有效期的天数,用一个足够大的值跳转到2034年
下面是cmd窗口操作视图样例:
keytool -genkeypair -keystore test.p12 -storetype pkcs12 -validity 8050
输入密钥库口令:
再次输入新口令:

密钥库口令,就是证书的密码,用于获取密钥,此步设置为 111111
参考文章如下 http://blog.csdn.net/cui130/article/details/52487604

3:编码
接下来,准备好一个pdf,一个签章用的图片,就可以开始编码了。

a.创建一个类MainWindow

public class MainWindow {
}

b.往类中添加常量参数

public static final String KEYSTORE = "c:\\pdf\\test.p12";
public static final char[] PASSWORD = "111111".toCharArray();//keystory密码
public static final String SRC = "c:\\pdf\\zqzr.pdf";
public static final String DEST = "c:\\pdf\\signed_zqzr.pdf";

c.往类中添加加签章方法

public void sign(String src  //需要签章的pdf文件路径
            , String dest  // 签完章的pdf文件路径
            , Certificate[] chain //证书链
            , PrivateKey pk //签名私钥
            , String digestAlgorithm  //摘要算法名称,例如SHA-1
            , String provider  // 密钥算法提供者,可以为null
            , CryptoStandard subfilter //数字签名格式,itext有2种
            , String reason  //签名的原因,显示在pdf签名属性中,随便填
            , String location) //签名的地点,显示在pdf签名属性中,随便填
                    throws GeneralSecurityException, IOException, DocumentException {
        //下边的步骤都是固定的,照着写就行了,没啥要解释的
        // Creating the reader and the stamper,开始pdfreader
        PdfReader reader = new PdfReader(src);
        //目标文件输出流
        FileOutputStream os = new FileOutputStream(dest);
        //创建签章工具PdfStamper ,最后一个boolean参数 
        //false的话,pdf文件只允许被签名一次,多次签名,最后一次有效
        //true的话,pdf可以被追加签名,验签工具可以识别出每次签名之后文档是否被修改
        PdfStamper stamper = PdfStamper.createSignature(reader, os, '\0', null, true);
        // 获取数字签章属性对象,设定数字签章的属性
        PdfSignatureAppearance appearance = stamper.getSignatureAppearance();
        appearance.setReason(reason);
        appearance.setLocation(location);
        //设置签名的位置,页码,签名域名称,多次追加签名的时候,签名预名称不能一样
        //签名的位置,是图章相对于pdf页面的位置坐标,原点为pdf页面左下角
        //四个参数的分别是,图章左下角x,图章左下角y,图章右上角x,图章右上角y
        appearance.setVisibleSignature(new Rectangle(200, 200, 300, 300), 1, "sig1");
        //读取图章图片,这个image是itext包的image
        Image image = Image.getInstance("c:\\pdf\\gongzhang.png"); 
        appearance.setSignatureGraphic(image); 
        appearance.setCertificationLevel(PdfSignatureAppearance.NOT_CERTIFIED);
        //设置图章的显示方式,如下选择的是只显示图章(还有其他的模式,可以图章和签名描述一同显示)
        appearance.setRenderingMode(RenderingMode.GRAPHIC);

        // 这里的itext提供了2个用于签名的接口,可以自己实现,后边着重说这个实现
        // 摘要算法
        ExternalDigest digest = new BouncyCastleDigest();
        // 签名算法
        ExternalSignature signature = new PrivateKeySignature(pk, digestAlgorithm, null);
        // 调用itext签名方法完成pdf签章
        MakeSignature.signDetached(appearance, digest, signature, chain, null, null, null, 0, subfilter);
    }

d.最后编写main方法执行加签章生成加签pdf代码

public static void main(String[] args)  {
        try {
        //读取keystore ,获得私钥和证书链
            KeyStore ks = KeyStore.getInstance("PKCS12");
            ks.load(new FileInputStream(KEYSTORE), PASSWORD);
            String alias = (String)ks.aliases().nextElement();
            PrivateKey pk = (PrivateKey) ks.getKey(alias, PASSWORD);
            Certificate[] chain = ks.getCertificateChain(alias);
            //new一个上边自定义的方法对象,调用签名方法
            MainWindow app = new MainWindow();
            app.sign(SRC, String.format(DEST, 3), chain, pk, DigestAlgorithms.SHA1, null, CryptoStandard.CMS, "pdf", "CN");
        } catch (Exception e) {
            // TODO Auto-generated catch block
            JOptionPane.showMessageDialog(null, e.getMessage());
            e.printStackTrace();
        } 
    }

以上的路径,根据个人电脑文件路径进行修改,直接执行main方法即可,查看加签成功后的效果为
使用itext实现pdf图片签章_第1张图片

执行过程有任何问题先可比较下引入的类是否正确,参照如下:

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.cert.Certificate;

import javax.swing.JOptionPane;

import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Image;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfSignatureAppearance;
import com.itextpdf.text.pdf.PdfSignatureAppearance.RenderingMode;
import com.itextpdf.text.pdf.PdfStamper;
import com.itextpdf.text.pdf.security.BouncyCastleDigest;
import com.itextpdf.text.pdf.security.DigestAlgorithms;
import com.itextpdf.text.pdf.security.ExternalDigest;
import com.itextpdf.text.pdf.security.ExternalSignature;
import com.itextpdf.text.pdf.security.MakeSignature;
import com.itextpdf.text.pdf.security.MakeSignature.CryptoStandard;
import com.itextpdf.text.pdf.security.PrivateKeySignature;

最后,感谢全文中参考文章和最后图片的作者,大家在使用过程中有任何问题,请及时留言。

你可能感兴趣的:(工具的使用)