pdf加簽章(copy 代碼直接可用)

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.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.bky.test.scpdf.PDFUtil;
import com.bky.test.guanjianzi.PdfKeywordFinder;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.cert.Certificate;
import java.util.List;

/**
 * pdf加簽章
 * @author hxw
 *
 */
public class ItextUtil {

    public static final char[] PASSWORD = "Aa123456".toCharArray();// keystory密碼

    /**
     * 單多次簽章通用
     * 
     * @param src
     * @param target
     * @param signatureInfos
     * @throws GeneralSecurityException
     * @throws IOException
     * @throws DocumentException
     */
    @SuppressWarnings("resource")
    public void sign(String src, String target, SignatureInfo signatureInfo) {
        InputStream inputStream = null;
        FileOutputStream outputStream = null;
        ByteArrayOutputStream result = new ByteArrayOutputStream();
        try {
            inputStream = new FileInputStream(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
            appearance.setVisibleSignature(
                    new Rectangle(signatureInfo.getRectllx(), signatureInfo
                            .getRectlly(), signatureInfo.getRecturx(),
                            signatureInfo.getRectury()),  signatureInfo.getPageNum(), signatureInfo
                            .getFieldName());
            // 讀取圖章圖片
            Image image = Image.getInstance(signatureInfo.getImagePath());
            appearance.setSignatureGraphic(image);
            appearance.setCertificationLevel(signatureInfo
                    .getCertificationLevel());
            // 設置圖章的顯示方式,如下選擇的是隻顯示圖章(還有其他的模式,可以圖章和簽名描述一同顯示)
            appearance.setRenderingMode(signatureInfo.getRenderingMode());
            // 摘要算法
            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) {
        String pathURL = PDFUtil.getPath();
        int pageNum=0;
        int  x=0;
        int y=0;
        try {
            
            File pdfFile = new File("E:/temp/off_cnpc_plasthetics.pdf");
            byte[] pdfData = new byte[(int) pdfFile.length()];
            FileInputStream inputStream = null;
            try {
                inputStream = new FileInputStream(pdfFile);
                inputStream.read(pdfData);
            } catch (IOException e) {
                throw e;
            } finally {
                if (inputStream != null) {
                    try {
                        inputStream.close();
                    } catch (IOException e) {
                    }
                }
            }
            //找到關鍵字的位置,根據關鍵字進行平移和加簽
            String keyword = "11.4";

           //使用另一篇文章中的找到關鍵字

          //https://blog.csdn.net/hxwjilin/article/details/84560899
            PdfKeywordFinder pd=new PdfKeywordFinder();
            List<float[]> positions = pd.findKeywordPostions(pdfData, keyword);

            System.out.println("total:" + positions.size());
            if (positions != null && positions.size() > 0) {
                for (float[] position : positions) {
                    System.out.print("pageNum: " + (int) position[0]);

                    System.out.print("\tx: " + position[1]);
                    System.out.println("\ty: " + position[2]);
                    pageNum=(int) position[0];
                    x=(int) position[1];
                    y=(int) position[2];
                }
            }

            
            ItextUtil app = new ItextUtil();
            // 將證書文件放入指定路徑,並讀取keystore ,獲得私鑰和證書鏈
            String pkPath =pathURL+"templates/tomatocc.p12";
            KeyStore ks = KeyStore.getInstance("PKCS12");
            ks.load(new FileInputStream(pkPath), PASSWORD);
            String alias = ks.aliases().nextElement();
            PrivateKey pk = (PrivateKey) ks.getKey(alias, PASSWORD);
            // 得到證書鏈
            Certificate[] chain = ks.getCertificateChain(alias);
            //需要進行簽章的pdf
            String path = "E:/temp/off_cnpc_plasthetics.pdf";
            // 封裝簽章信息
            SignatureInfo signInfo = new SignatureInfo();
            signInfo.setReason("理由");
            signInfo.setLocation("位置");
            signInfo.setPk(pk);
            signInfo.setChain(chain);
            signInfo.setCertificationLevel(PdfSignatureAppearance.NOT_CERTIFIED);
            signInfo.setDigestAlgorithm(DigestAlgorithms.SHA1);
            signInfo.setFieldName("demo");
            // 簽章圖片
            signInfo.setImagePath(pathURL+"/images/gongzhang.png");
            signInfo.setRenderingMode(PdfSignatureAppearance.RenderingMode.GRAPHIC);
            signInfo.setRectllx(x+100);  // 值越大,代表向x軸座標平移 縮小 (反之,值越小,印章會放大)、獲取的關鍵字x的座標+100
            signInfo.setRectlly(y);  // 值越大,代表向y軸座標向上平移(大小不變)、 獲取的關鍵字y的座標
            signInfo.setRecturx(x);  // 值越大   代表向x軸座標向右平移  (大小不變)   獲取的關鍵字x的座標
            signInfo.setRectury(y-100);  // 值越大,代表向y軸座標向上平移(大小不變)、 獲取的關鍵字y的座標-100
            signInfo.setPageNum(pageNum);
            //簽章後的pdf路徑
            app.sign(path, "E:/temp/demo4.pdf", signInfo);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

import com.itextpdf.text.pdf.PdfSignatureAppearance;
import java.security.PrivateKey;
import java.security.cert.Certificate;

public class SignatureInfo {
    private  String reason; //簽名的原因,顯示在pdf簽名屬性中
    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
    private  int pageNum;//第幾頁


    public int getPageNum() {
        return pageNum;
    }
    public void setPageNum(int pageNum) {
        this.pageNum = pageNum;
    }
    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;
    }


}

 

 

 

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章