java对现有的pdf添加签名、签章

java对现有的pdf添加签名、签章

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

import com.itextpdf.text.BaseColor;
import com.itextpdf.text.Chunk;
import com.itextpdf.text.Font;
import com.itextpdf.text.Image;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.ColumnText;
import com.itextpdf.text.pdf.PdfContentByte;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfSignatureAppearance;
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.PrivateKeySignature;
import com.wanbo.vo.BalanceBaseInfo;

/**
 * 对现有的对账单pdf签名并按规则命名存放
 *
 * EditPdfStatementSeal.java Create on 2020-06-02 下午2:09:22
 * 
 */
public class EditPdfStatementSeal implements Runnable{
    //对账单源地址
    private String statementFilePath;
    //对账单目的地址
    private String destStatementFilePath;
    //印章图片地址
    private String assetSeal;
    //签名证书地址
    private String signPath;
    //填充信息
    private BalanceBaseInfo balanceBaseInfo;

    @Override
    public void run(){
        sealPdf();
    }

    public void sealPdf(){
        try {
            //原pdf输入流
            FileInputStream sourceInputStream = new FileInputStream(statementFilePath);
            //目标pdf输出流
            FileOutputStream destOutputStream = new FileOutputStream(destStatementFilePath);
            //签名证书
            FileInputStream signInputStream = new FileInputStream(signPath);
            //签名密钥
            char[] password = "elink@D18".toCharArray();
            //读取keystore ,获得私钥和证书链
            KeyStore keyStore = KeyStore.getInstance("jks");
            //载入密码和证书流
            keyStore.load(signInputStream, password);
            //获取私钥
            String alias = (String)keyStore.aliases().nextElement();
            PrivateKey pk = (PrivateKey) keyStore.getKey(alias, password);
            //获取证书链
            Certificate[] chain = keyStore.getCertificateChain(alias);
            //读取原pdf文件
            PdfReader reader = new PdfReader(sourceInputStream);
            //目标文件输出流
            //创建签章工具PdfStamper ,最后一个boolean参数
            //false的话,pdf文件只允许被签名一次,多次签名,最后一次有效
            //true的话,pdf可以被追加签名,验签工具可以识别出每次签名之后文档是否被修改
            PdfStamper stamper = PdfStamper.createSignature(reader, destOutputStream, '\0', null, false);
            //给pdf追加内容:企业名称,对账人姓名,对账日期
            BaseFont baseFont = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", false);
            Font font = new Font(baseFont);
            font.setColor(BaseColor.RED);
            PdfContentByte over = stamper.getOverContent(1);
            ColumnText columnText = new ColumnText(over);
            columnText.setSimpleColumn(150, 44, 1200, 20);
            Paragraph elements = new Paragraph(0, new Chunk(balanceBaseInfo.getParam1()+"|"+balanceBaseInfo.getParam2()+"|"+balanceBaseInfo.getParam3()));
            elements.setFont(font);
            columnText.addElement(elements);
            columnText.go();
            // 获取数字签章属性对象,设定数字签章的属性
            PdfSignatureAppearance pdfAppearance = stamper.getSignatureAppearance();
            pdfAppearance.setReason("对账行为签章");
            pdfAppearance.setLocation(balanceBaseInfo.getParam1()+"|"+balanceBaseInfo.getParam2()+"|"+balanceBaseInfo.getParam3());
            //设置签名的位置,页码,签名域名称,多次追加签名的时候,签名预名称不能一样
            int pageCount = reader.getNumberOfPages();
            //签名的位置,是图章相对于pdf页面的位置坐标,原点为pdf页面左下角
            //四个参数的分别是,图章左下角x,图章左下角y,图章右上角x,图章右上角y
            pdfAppearance.setVisibleSignature(new Rectangle(40, 0, 143, 93), pageCount, "param13");
            //读取图章图片,这个image是itext包的image
            Image image = Image.getInstance(assetSeal);
            pdfAppearance.setSignatureGraphic(image);
            pdfAppearance.setCertificationLevel(PdfSignatureAppearance.CERTIFIED_NO_CHANGES_ALLOWED);
            //设置图章的显示方式,如下选择的是只显示图章(还有其他的模式,可以图章和签名描述一同显示)
            pdfAppearance.setRenderingMode(PdfSignatureAppearance.RenderingMode.GRAPHIC);
            // 这里的itext提供了2个用于签名的接口,可以自己实现,后边着重说这个实现
            // 摘要算法
            ExternalDigest digest = new BouncyCastleDigest();
            // 签名算法
            ExternalSignature signature = new PrivateKeySignature(pk, DigestAlgorithms.SHA1, null);
            // 调用itext签名方法完成pdf签章CryptoStandard.CMS 签名方式,建议采用这种
            MakeSignature.signDetached(pdfAppearance, digest, signature, chain, null, null, null, 0, MakeSignature.CryptoStandard.CMS);
            stamper.close();
            reader.close();
            sourceInputStream.close();
            destOutputStream.close();
            signInputStream.close();
        } catch (Exception e) {
            LogUtils.errorOutPutInfo("----pdf sign is error");
        }
    }

    public String getStatementFilePath() {
        return statementFilePath;
    }

    public void setStatementFilePath(String statementFilePath) {
        this.statementFilePath = statementFilePath;
    }

    public String getAssetSeal() {
        return assetSeal;
    }
    public void setAssetSeal(String assetSeal) {
        this.assetSeal = assetSeal;
    }
    public BalanceBaseInfo getBalanceBaseInfo() {
        return balanceBaseInfo;
    }
    public void setBalanceBaseInfo(BalanceBaseInfo balanceBaseInfo) {
        this.balanceBaseInfo = balanceBaseInfo;
    }

    public String getDestStatementFilePath() {
        return destStatementFilePath;
    }

    public void setDestStatementFilePath(String destStatementFilePath) {
        this.destStatementFilePath = destStatementFilePath;
    }

    public String getSignPath() {
        return signPath;
    }

    public void setSignPath(String signPath) {
        this.signPath = signPath;
    }
}



版权声明:本文为weixin_44865161原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。