天天看點

java實作pdf檔案的電子簽字+蓋章+二維碼+水印+PDF檔案加密的解決方案二、使用itextPDF實作PDF電子公章工具類三、thymeleaf+itext簽字功能+PDF檔案加密實作四、PDF實作生成水印并删除源檔案五、PDF使用工具Adobe Acrobat DC+PDF+Itext模闆實作二維碼功能

二、使用itextPDF實作PDF電子公章工具類

1、電子章的制作

我們需要實作電子章蓋章,我們這次推薦使用的線上做章工具來模拟電子印章

  • 網站:http://seal.biaozhiku.com/
  • 我們選擇圓形章
java實作pdf檔案的電子簽字+蓋章+二維碼+水印+PDF檔案加密的解決方案二、使用itextPDF實作PDF電子公章工具類三、thymeleaf+itext簽字功能+PDF檔案加密實作四、PDF實作生成水印并删除源檔案五、PDF使用工具Adobe Acrobat DC+PDF+Itext模闆實作二維碼功能
  • 然後輸入名,輸入章名輸入編碼然後點選395生成,最後點選儲存圖檔,我們的個人專業章就實作了
java實作pdf檔案的電子簽字+蓋章+二維碼+水印+PDF檔案加密的解決方案二、使用itextPDF實作PDF電子公章工具類三、thymeleaf+itext簽字功能+PDF檔案加密實作四、PDF實作生成水印并删除源檔案五、PDF使用工具Adobe Acrobat DC+PDF+Itext模闆實作二維碼功能
  • 效果如圖:
    java實作pdf檔案的電子簽字+蓋章+二維碼+水印+PDF檔案加密的解決方案二、使用itextPDF實作PDF電子公章工具類三、thymeleaf+itext簽字功能+PDF檔案加密實作四、PDF實作生成水印并删除源檔案五、PDF使用工具Adobe Acrobat DC+PDF+Itext模闆實作二維碼功能
  • PDF模闆圖
java實作pdf檔案的電子簽字+蓋章+二維碼+水印+PDF檔案加密的解決方案二、使用itextPDF實作PDF電子公章工具類三、thymeleaf+itext簽字功能+PDF檔案加密實作四、PDF實作生成水印并删除源檔案五、PDF使用工具Adobe Acrobat DC+PDF+Itext模闆實作二維碼功能
  • 生成PDF效果圖
java實作pdf檔案的電子簽字+蓋章+二維碼+水印+PDF檔案加密的解決方案二、使用itextPDF實作PDF電子公章工具類三、thymeleaf+itext簽字功能+PDF檔案加密實作四、PDF實作生成水印并删除源檔案五、PDF使用工具Adobe Acrobat DC+PDF+Itext模闆實作二維碼功能

2、itextPDF的相關依賴

<!-- itextpdf依賴 -->
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>itextpdf</artifactId>
            <version>5.5.10</version>
        </dependency>
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>itext-asian</artifactId>
            <version>5.2.0</version>
        </dependency>
         <dependency>
             <!-- 摘要算法 -->
    <dependency>
      <groupId>org.bouncycastle</groupId>
      <artifactId>bcprov-jdk15on</artifactId>
      <version>1.49</version>
    </dependency>
    <dependency>
      <groupId>org.bouncycastle</groupId>
      <artifactId>bcpkix-jdk15on</artifactId>
      <version>1.49</version>
    </dependency>

           
  • 使用的是boot項目,是以完整依賴是
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.2.5.RELEASE</version>
</parent>
  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-thymeleaf</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!-- itextpdf依賴 -->
    <dependency>
      <groupId>com.itextpdf</groupId>
      <artifactId>itextpdf</artifactId>
      <version>5.5.10</version>
    </dependency>
    <dependency>
      <groupId>com.itextpdf</groupId>
      <artifactId>itext-asian</artifactId>
      <version>5.2.0</version>
    </dependency>
    <dependency>
      <groupId>org.bouncycastle</groupId>
      <artifactId>bcprov-jdk15on</artifactId>
      <version>1.49</version>
    </dependency>
    <dependency>
      <groupId>org.bouncycastle</groupId>
      <artifactId>bcpkix-jdk15on</artifactId>
      <version>1.49</version>
    </dependency>
  </dependencies>

           

3、相關配置及數字簽名的配置

(1)摘要算法

  • 我們項目啟動之後報錯
java實作pdf檔案的電子簽字+蓋章+二維碼+水印+PDF檔案加密的解決方案二、使用itextPDF實作PDF電子公章工具類三、thymeleaf+itext簽字功能+PDF檔案加密實作四、PDF實作生成水印并删除源檔案五、PDF使用工具Adobe Acrobat DC+PDF+Itext模闆實作二維碼功能
  • 需要加這個配置檔案就不報錯了,這個主要原因是摘要算法沒有,需要引入相關依賴
<dependency>
      <groupId>org.bouncycastle</groupId>
      <artifactId>bcprov-jdk15on</artifactId>
      <version>1.49</version>
    </dependency>
    <dependency>
      <groupId>org.bouncycastle</groupId>
      <artifactId>bcpkix-jdk15on</artifactId>
      <version>1.49</version>
    </dependency>

           
  • 涉及到加密算法就需要數字簽名了(數字簽名格式,CMS,CADE),我們就需要一個檔案(我的命名是:server.p12)這個東西需要我們自己電腦生成數字簽名
java實作pdf檔案的電子簽字+蓋章+二維碼+水印+PDF檔案加密的解決方案二、使用itextPDF實作PDF電子公章工具類三、thymeleaf+itext簽字功能+PDF檔案加密實作四、PDF實作生成水印并删除源檔案五、PDF使用工具Adobe Acrobat DC+PDF+Itext模闆實作二維碼功能

(2)java工具keytool生成p12數字證書檔案

Keytool是用于管理**和證書的工具,位于%JAVA_HOME%/bin目錄。

使用JDK的keytool工具

  • keytool在jdk的bin目錄下
java實作pdf檔案的電子簽字+蓋章+二維碼+水印+PDF檔案加密的解決方案二、使用itextPDF實作PDF電子公章工具類三、thymeleaf+itext簽字功能+PDF檔案加密實作四、PDF實作生成水印并删除源檔案五、PDF使用工具Adobe Acrobat DC+PDF+Itext模闆實作二維碼功能

2. 打開keytool所在的bin目錄,然後在上面的路徑顯示框中輸入CMD,然後回車,即可在目前檔案夾下打開指令提示符,并且路徑是目前檔案夾。

java實作pdf檔案的電子簽字+蓋章+二維碼+水印+PDF檔案加密的解決方案二、使用itextPDF實作PDF電子公章工具類三、thymeleaf+itext簽字功能+PDF檔案加密實作四、PDF實作生成水印并删除源檔案五、PDF使用工具Adobe Acrobat DC+PDF+Itext模闆實作二維碼功能
  • 生成數字檔案,在指令行輸入
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

           
java實作pdf檔案的電子簽字+蓋章+二維碼+水印+PDF檔案加密的解決方案二、使用itextPDF實作PDF電子公章工具類三、thymeleaf+itext簽字功能+PDF檔案加密實作四、PDF實作生成水印并删除源檔案五、PDF使用工具Adobe Acrobat DC+PDF+Itext模闆實作二維碼功能

參數解釋:

storepass keystore 檔案存儲密碼
keypass 私鑰加解密密碼
alias 實體别名(包括證書私鑰)
dname 證書個人資訊
keyalt 采用公鑰算法,預設是DSA keysize **長度(DSA算法對應的預設算法是sha1withDSA,不支援2048長度,此時需指定RSA)
validity 有效期
keystore 指定keystore檔案

           
java實作pdf檔案的電子簽字+蓋章+二維碼+水印+PDF檔案加密的解決方案二、使用itextPDF實作PDF電子公章工具類三、thymeleaf+itext簽字功能+PDF檔案加密實作四、PDF實作生成水印并删除源檔案五、PDF使用工具Adobe Acrobat DC+PDF+Itext模闆實作二維碼功能
  • 轉換為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

           
java實作pdf檔案的電子簽字+蓋章+二維碼+水印+PDF檔案加密的解決方案二、使用itextPDF實作PDF電子公章工具類三、thymeleaf+itext簽字功能+PDF檔案加密實作四、PDF實作生成水印并删除源檔案五、PDF使用工具Adobe Acrobat DC+PDF+Itext模闆實作二維碼功能
  • 生成的最終檔案
java實作pdf檔案的電子簽字+蓋章+二維碼+水印+PDF檔案加密的解決方案二、使用itextPDF實作PDF電子公章工具類三、thymeleaf+itext簽字功能+PDF檔案加密實作四、PDF實作生成水印并删除源檔案五、PDF使用工具Adobe Acrobat DC+PDF+Itext模闆實作二維碼功能

4、項目結構及源碼

java實作pdf檔案的電子簽字+蓋章+二維碼+水印+PDF檔案加密的解決方案二、使用itextPDF實作PDF電子公章工具類三、thymeleaf+itext簽字功能+PDF檔案加密實作四、PDF實作生成水印并删除源檔案五、PDF使用工具Adobe Acrobat DC+PDF+Itext模闆實作二維碼功能
  • 工具類(可以直接複制)
package com.whj.pdf;

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.*;
import com.whj.entity.SignatureInfo;

import java.io.*;
import java.security.GeneralSecurityException;

/**
 * @author 王恒傑
 * @date 2022/10/13 22:52
 * @Description:蓋章功能工具類
 */
public class ItextUtil {

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

    /**
     * 單多次簽章通用
     *
     * @param src
     * @param target
     * @param signatureInfo
     * @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
            //四個參數的分别是,圖章左下角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();
            }
        }
    }

}


           
  • 實體類
package com.whj.entity;

import com.itextpdf.text.pdf.PdfSignatureAppearance;

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

/**
 * @author 王恒傑
 * @date 2022/10/13 22:52
 * @Description:
 */
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

    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;
    }

}


           
  • 測試
package com.whj.pdf;

import com.itextpdf.text.pdf.PdfSignatureAppearance;
import com.itextpdf.text.pdf.security.DigestAlgorithms;
import com.whj.entity.SignatureInfo;

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

import static com.whj.pdf.ItextUtil.PASSWORD;

/**
 * @author 王恒傑
 * @date 2022/10/24 10:42
 * @Description:  蓋章功能實作
 */
public class PdfStamp {
    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(new FileInputStream(pkPath), PASSWORD);
            String alias = ks.aliases().nextElement();
            PrivateKey pk = (PrivateKey) ks.getKey(alias, PASSWORD);
            // 得到證書鍊
            Certificate[] chain = ks.getCertificateChain(alias);
            //需要進行簽章的pdf
            String path = "D:\\Idea\\stamp\\Itext\\src\\main\\resources\\pdf\\程式員小王.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("D:\\Idea\\stamp\\Itext\\src\\main\\resources\\pdf\\chapter.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, "D:\\Idea\\stamp\\Itext\\src\\main\\resources\\pdf\\out.pdf", signInfo);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}



           

5、結果展示

java實作pdf檔案的電子簽字+蓋章+二維碼+水印+PDF檔案加密的解決方案二、使用itextPDF實作PDF電子公章工具類三、thymeleaf+itext簽字功能+PDF檔案加密實作四、PDF實作生成水印并删除源檔案五、PDF使用工具Adobe Acrobat DC+PDF+Itext模闆實作二維碼功能

三、thymeleaf+itext簽字功能+PDF檔案加密實作

  • 是以需依賴
  • 需要手工導入一個jar包(jar包我放在了源碼裡面,需要自行下載下傳)
java實作pdf檔案的電子簽字+蓋章+二維碼+水印+PDF檔案加密的解決方案二、使用itextPDF實作PDF電子公章工具類三、thymeleaf+itext簽字功能+PDF檔案加密實作四、PDF實作生成水印并删除源檔案五、PDF使用工具Adobe Acrobat DC+PDF+Itext模闆實作二維碼功能
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.2.5.RELEASE</version>
</parent>
  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-thymeleaf</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!-- itextpdf依賴 -->
    <dependency>
      <groupId>com.itextpdf</groupId>
      <artifactId>itextpdf</artifactId>
      <version>5.5.10</version>
    </dependency>
    <dependency>
      <groupId>com.itextpdf</groupId>
      <artifactId>itext-asian</artifactId>
      <version>5.2.0</version>
    </dependency>
    <dependency>
      <groupId>org.bouncycastle</groupId>
      <artifactId>bcprov-jdk15on</artifactId>
      <version>1.49</version>
    </dependency>
    <dependency>
      <groupId>org.bouncycastle</groupId>
      <artifactId>bcpkix-jdk15on</artifactId>
      <version>1.49</version>
    </dependency>
    <!--guava是來自Google的Java核心類庫。包含了新的集合類型(例如:複合map、複合set)、
    不可變集合,以及一些對于并發、I/O、hashing、緩存、原型、字元串等的通用功能。
    guava被廣泛使用在Google的項目中,也被廣泛的使用在其他公司裡。-->
    <dependency>
      <groupId>com.google.guava</groupId>
      <artifactId>guava</artifactId>
      <version>25.0-jre</version>
    </dependency>
  </dependencies>


           

因為這個的相關類太多,隻展示了核心代碼,全部代碼請到部落格底部下載下傳源碼

java實作pdf檔案的電子簽字+蓋章+二維碼+水印+PDF檔案加密的解決方案二、使用itextPDF實作PDF電子公章工具類三、thymeleaf+itext簽字功能+PDF檔案加密實作四、PDF實作生成水印并删除源檔案五、PDF使用工具Adobe Acrobat DC+PDF+Itext模闆實作二維碼功能

1、簽字圖檔上傳和簽字實作的Controller

package com.whj.controller;

import com.whj.service.SignService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

/**
 * @author 王恒傑
 * @date 2022/10/24 13:57
 * @Description: 實作簽字上傳和簽字功能
 */
@RestController
@RequestMapping("/sign")
public class SignController {
    @Autowired
    private SignService signService;

    @PostMapping(value = "/uploadSign")
    @ResponseBody
    public String uploadSign(String img) {
        return signService.uploadSign(img);
    }

    @PostMapping(value = "/sign")
    @ResponseBody
    public String sign() {
        return signService.sign(id);
    }
}



           

2、簽字上傳,簽字,PDF檔案加密業務層實作

/**
 * @author 王恒傑
 * @date 2022/10/24 14:00
 * @Description:
 */
@Service
public class SignServiceImpl implements  SignService{
    @Override
    public String uploadSign(String img) {

        //String idCard="3000";
        // 生成jpeg圖檔 idCard.asString()
        String url = "D:\\Idea\\stamp\\Itext\\src\\main\\resources\\img\\sign.png";

        try {
            if (img == null) // 圖像資料為空
            {
                return "no";
            }
            int i = img.indexOf("base64,") + 7;//擷取字首data:image/gif;base64,的坐标
            String newImage = img.substring(i, img.length());//去除字首

            BASE64Decoder decoder = new BASE64Decoder();
            // Base64解碼
            byte[] bytes = decoder.decodeBuffer(newImage);

            for (int j = 0; j < bytes.length; ++j) {
                if (bytes[j] < 0) {// 調整異常資料
                    bytes[j] += 256;
                }
            }

            OutputStream out = new FileOutputStream(url);

            out.write(bytes);
            out.flush();
            out.close();
            return "yes";
        } catch (Exception e) {
            return "no";
        }
    }

    @Override
    public String sign() {
            try {
                //初始化檔案
                String srcPath = "D:\\Idea\\stamp\\Itext\\src\\main\\resources\\pdf\\out.pdf";
                //輸出檔案
                String outPath = "D:\\Idea\\stamp\\Itext\\src\\main\\resources\\pdf\\signOut.pdf";

                signimg("D:\\Idea\\stamp\\Itext\\src\\main\\resources\\img\\sign.png", srcPath, "準許人", outPath);
                //加密
                EncryptPDFUtil.encryptPDF(outPath, "EncryptPDF");

                return "yes";
            } catch (Exception e) {
                return "no";
            }
    }



           
  • 封裝簽字的方法
public static void signimg(String imgurl, String pdfurl, String keywords, String outPDFPath) throws IOException {
        List list = new ArrayList();
        SignPDFBean bean1 = new SignPDFBean();
        bean1.setKeyStorePass("111111");
        bean1.setKeyStorePath("src/main/resources/server.p12");
        bean1.setKeyWord(keywords);
        bean1.setSealPath(imgurl);
        bean1.setSignLocation(keywords);
        bean1.setSignReason("計量檢定證書簽字");

        list.add(bean1);

        SignPDFRequestBean requestBean = new SignPDFRequestBean();
        requestBean.setSrcPDFPath(pdfurl);
        requestBean.setOutPDFPath(outPDFPath);
        requestBean.setSignPDFBeans(list);

        long startTime = System.currentTimeMillis();
        // 1.解析pdf檔案
        Map<Integer, List<KeyWordBean>> map = KeywordPDFUtils.getPDFText(requestBean.getSrcPDFPath());
        // 2.擷取關鍵字坐标
        List<SignPDFBean> beans = requestBean.getSignPDFBeans();
        byte[] fileData = null;
        InputStream in = null;
        for (int i = 0; i < beans.size(); i++) {
            SignPDFBean pdfBean = beans.get(i);
            KeyWordBean bean = KeywordPDFUtils.getKeyWordXY1(map, pdfBean.getKeyWord());
            if (null == bean) {
                System.out.println("未查詢到關鍵字。。。");
            }
            System.out.println("111" + bean.toString());
            long keyTime = System.currentTimeMillis();
            if (i == 0) {
                in = new FileInputStream(requestBean.getSrcPDFPath());
            } else {
                in = new ByteArrayInputStream(fileData);
            }
            // 3.進行蓋章
            fileData = SignPDFUtils.sign(pdfBean.getKeyStorePass(), pdfBean.getKeyStorePath(), in, pdfBean.getSealPath(), bean.getX(), bean.getY(), bean.getPage(), pdfBean.getSignReason(), pdfBean.getSignLocation());
            long signTime = System.currentTimeMillis();
        }
        // 4.輸出蓋章後pdf檔案
        FileOutputStream f = new FileOutputStream(new File(requestBean.getOutPDFPath()));
        f.write(fileData);
        f.close();
        in.close();

        long endTime = System.currentTimeMillis();
        System.out.println("總時間:" + (endTime - startTime));
    }

}

           

3、封裝的實作PDF加密檔案的方法

package com.whj.util;

import com.spire.pdf.PdfDocument;
import com.spire.pdf.security.PdfEncryptionKeySize;
import com.spire.pdf.security.PdfPermissionsFlags;

import java.util.EnumSet;

/**
 * @author 王恒傑
 * @date 2022/10/18 9:26
 * @Description:   将PDF加密的工具類
 */
public  class EncryptPDFUtil {
    public static void encryptPDF(String startFileName,String EncryptPDF) {
        //建立PdfDocument執行個體
        PdfDocument doc = new PdfDocument();
        //加載PDF檔案
        doc.loadFromFile(startFileName);
        //添加一個空白頁,目的為了删除jar包添加的水印,後面再移除這一頁
        doc.getPages().add();
        //加密PDF檔案
        PdfEncryptionKeySize keySize = PdfEncryptionKeySize.Key_128_Bit;
        String openPassword = "123456";//打開文檔時,僅用于檢視文檔
        String permissionPassword = "test";//打開文檔時,可編輯文檔
        EnumSet flags = EnumSet.of(PdfPermissionsFlags.Print, PdfPermissionsFlags.Fill_Fields);
        doc.getSecurity().encrypt(openPassword, permissionPassword, flags, keySize);
        //移除第一個頁
        doc.getPages().remove(doc.getPages().get(doc.getPages().getCount()-1));
        //儲存檔案
        doc.saveToFile("src/main/resources/pdf/EncryptPDF/"+EncryptPDF+".pdf");

        doc.close();
    }
}


           

4、簽字前端(thymeleaf實作)

  • 配置檔案
server.port=8081
spring.thymeleaf.prefix=classpath:/templates/


           
  • 前端源碼
<!DOCTYPE html>
<html>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  <!--<meta name="viewport" content="initial-scale=1,width=device-width, height=device-height,user-scalable=no,maximum-scale=1, minimum-scale=1" />
         <meta name="apple-mobile-web-app-capable" content="yes">
          <meta name="apple-mobile-web-app-status-bar-style" content="black">
          <meta name="format-detection" content="telephone=no">-->
  <!--<script src="http://www.jq22.com/jquery/2.1.1/jquery.min.js"></script>-->
  <title>手寫簽名</title>
  <script type="text/javascript" src="../jquery-3.1.1.min.js" ></script>
  <script type="text/javascript" src="../ajaxfileupload.js" ></script>
  <style type="text/css">
    #canvas {}
  </style>
</head>
  <body id="bb">
    <div id="canvasDiv"></div>
    <br><br><br>
    <button id="btn_clear">清除</button>
    <button id="btn_submit">送出</button>
    <script language="javascript">

  try
   {
   function onDocumentTouchStart(event) {
        if(event.touches.length == 1) {
          event.preventDefault();
          // Faking double click for touch devices
          var now = new Date().getTime();
          if(now - timeOfLastTouch < 250) {
            reset();
            return;
          }
          timeOfLastTouch = now;
          mouseX = event.touches[0].pageX;
          mouseY = event.touches[0].pageY;
          isMouseDown = true;
        }
      }
      function onDocumentTouchMove(event) {
        if(event.touches.length == 1) {
          event.preventDefault();
          mouseX = event.touches[0].pageX;
          mouseY = event.touches[0].pageY;
        }
      }
      function onDocumentTouchEnd(event) {
        if(event.touches.length == 0) {
          event.preventDefault();
          isMouseDown = false;
        }
      }
      var canvasDiv = document.getElementById('canvasDiv');
      var canvas = document.createElement('canvas');
      var canvasWidth = 1191;
      var canvasHeight = 670;
      document.addEventListener('touchmove', onDocumentTouchMove, false);
      /*document.addEventListener('touchstart', onDocumentTouchStart, true);
      document.addEventListener('touchend', onDocumentTouchEnd, true);*/
      var point = {};
      point.notFirst = false;
      canvas.setAttribute('width', canvasWidth);
      canvas.setAttribute('height', canvasHeight);
      canvas.setAttribute('id', 'canvas');
      canvasDiv.appendChild(canvas);
      if(typeof G_vmlCanvasManager != 'undefined') {
        canvas = G_vmlCanvasManager.initElement(canvas);
      }
      var context = canvas.getContext("2d");
      var img = new Image();
      img.src = "./write.jpg";
      img.onload = function() {
        var ptrn = context.createPattern(img, 'no-repeat');
        context.fillStyle = ptrn;
        context.fillRect(0, 0, canvas.width, canvas.height);
      }
      canvas.addEventListener("touchstart", function(e) {
        console.log("touchstart");
        var mouseX = e.touches[0].pageX - this.offsetLeft;
        var mouseY = e.touches[0].pageY - this.offsetTop;
        paint = true;
        addClick(e.touches[0].pageX - this.offsetLeft, e.touches[0].pageY - this.offsetTop);
        redraw();
      });
      canvas.addEventListener("touchend", function(e) {
        console.log("touchend");
        paint = false;
      });
      canvas.addEventListener("touchmove", function(e) {
        console.log("touchmove");
        console.log(e);
        console.log("觸摸坐标:"+(e.touches[0].clientX - this.offsetLeft)+","+(e.touches[0].clientY - this.offsetTop));
        if(paint) {
          addClick(e.touches[0].pageX - this.offsetLeft, e.touches[0].pageY - this.offsetTop, true);
          redraw();
        }
      });
      canvas.addEventListener("mousedown", function(e) {
        console.log("mousedown");
        var mouseX = e.pageX - this.offsetLeft;
        var mouseY = e.pageY - this.offsetTop;
        paint = true;
        addClick(e.pageX - this.offsetLeft, e.pageY - this.offsetTop);
        redraw();
      });
      canvas.addEventListener("mousemove", function(e) {
        console.log(e);
        /*console.log(this.offsetLeft);
        console.log(this.offsetTop);*/
        console.log("滑鼠坐标:"+(e.pageX - this.offsetLeft)+","+(e.pageY - this.offsetTop));
        console.log("mousemove");
        if(paint) {
          addClick(e.pageX - this.offsetLeft, e.pageY - this.offsetTop, true);
          redraw();
        }
      });
      canvas.addEventListener("mouseup", function(e) {
        console.log("mouseup");
        paint = false;
      });
      canvas.addEventListener("mouseleave", function(e) {
        console.log("mouseleave");
        paint = false;
      });
      var clickX = new Array();
      var clickY = new Array();
      var clickDrag = new Array();
      var paint;
      function addClick(x, y, dragging)
      {
        clickX.push(x);
        clickY.push(y);
        clickDrag.push(dragging);
        console.debug(clickDrag);
      }
      function redraw() {
        
        //canvas.width = canvas.width; // Clears the canvas
        context.strokeStyle = "black";
        context.lineJoin = "round";
        context.lineWidth = 5;
        while(clickX.length > 0) {
          
          point.bx = point.x;
          point.by = point.y;
          point.x = clickX.pop();
          point.y = clickY.pop();
          console.log(point.x);
          console.log(point.y);
          /*alert(point.x);
          alert(point.y);*/
          point.drag = clickDrag.pop();
          context.beginPath();
          if(point.drag && point.notFirst) {
            context.moveTo(point.bx, point.by);
          } else {
            point.notFirst = true;
            context.moveTo(point.x - 1, point.y);
          }
          context.lineTo(point.x, point.y);
          context.closePath();
          context.stroke();
        }
        
        
        
        
        
          for(var i=0; i < clickX.length; i++)
          {    
            context.beginPath();
            if(clickDrag[i] && i){
              context.moveTo(clickX[i-1], clickY[i-1]);
            }else{
               context.moveTo(clickX[i]-1, clickY[i]);
            }
             context.lineTo(clickX[i], clickY[i]);
             context.closePath();
             context.stroke();
          }
       
          
          
      }
      var clear = document.getElementById("btn_clear");
      var submit = document.getElementById("btn_submit");
          var i =0;
      clear.addEventListener("click", function() {
        canvas.width = canvas.width;
      });
      submit.addEventListener("click", function() {
        $("#file").attr("src", canvas.toDataURL("image/png"));
                /*imgData = canvas.toDataURL("image/png").replace("image/png",'image/octet-stream');
                var saveFile = function(data, filename) {
                    var save_link = document.createElementNS('a');
                    save_link.href = data;
                    save_link.download = filename;

                    var event = document.createEvent('MouseEvents');
                    event.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
                    save_link.dispatchEvent(event);
                }
                i=i+1;
                var filename = "測試簽名" +i+ '.' + "png";
                saveFile(imgData,filename);*/
                $.ajax({
                    url: '/sign/uploadSign',
                    type: 'POST',
                    data: {img:canvas.toDataURL("image/png")},
                    success: function (data){
                        if(data=="yes"){
                            alert("上傳圖檔成功")
                        }
                    },
                    error:function(data,status,e){
                        alert(e);
                    }
                });
      });
 
   }
catch(err)
   {
   txt="本頁中存在錯誤。\n\n"
   txt+="錯誤描述:" + err.description + "\n\n"
   txt+="點選“确定”繼續。\n\n"
   alert(txt)
   }

    </script>
      <img id="file" />
  </body>
</html>

           

4、實作簽字功能示範

  • 啟動springboot項目
java實作pdf檔案的電子簽字+蓋章+二維碼+水印+PDF檔案加密的解決方案二、使用itextPDF實作PDF電子公章工具類三、thymeleaf+itext簽字功能+PDF檔案加密實作四、PDF實作生成水印并删除源檔案五、PDF使用工具Adobe Acrobat DC+PDF+Itext模闆實作二維碼功能
  • 輸入http://localhost:8080/ 打開簽字頁面,輸入姓名點選送出
java實作pdf檔案的電子簽字+蓋章+二維碼+水印+PDF檔案加密的解決方案二、使用itextPDF實作PDF電子公章工具類三、thymeleaf+itext簽字功能+PDF檔案加密實作四、PDF實作生成水印并删除源檔案五、PDF使用工具Adobe Acrobat DC+PDF+Itext模闆實作二維碼功能
  • 送出成功會顯示送出成功
java實作pdf檔案的電子簽字+蓋章+二維碼+水印+PDF檔案加密的解決方案二、使用itextPDF實作PDF電子公章工具類三、thymeleaf+itext簽字功能+PDF檔案加密實作四、PDF實作生成水印并删除源檔案五、PDF使用工具Adobe Acrobat DC+PDF+Itext模闆實作二維碼功能
  • 伺服器上可以看到圖檔已經儲存好了
java實作pdf檔案的電子簽字+蓋章+二維碼+水印+PDF檔案加密的解決方案二、使用itextPDF實作PDF電子公章工具類三、thymeleaf+itext簽字功能+PDF檔案加密實作四、PDF實作生成水印并删除源檔案五、PDF使用工具Adobe Acrobat DC+PDF+Itext模闆實作二維碼功能

5、實作PDF的簽字和加密

(1)PDF加密實作思路講解(詳細代碼看工具類)

  • PDF加密的方法
//加密
                EncryptPDFUtil.encryptPDF(outPath, "EncryptPDF");

           
  • 然後我們分裝了兩個權限,如果是需要對這個PDF檔案修改一個密碼,隻能檢視PDF一個密碼
//加密PDF檔案
        PdfEncryptionKeySize keySize = PdfEncryptionKeySize.Key_128_Bit;
        String openPassword = "123456";//打開文檔時,僅用于檢視文檔
        String permissionPassword = "test";//打開文檔時,可編輯文檔

           

(2)實作簽字的方法的講解

signimg("src/main/resources/img/sign.png", srcPath, "準許人", outPath);

           
  • 其中第一個參數代表的是簽字的圖檔,第二個參數源檔案,第三個參數是“準許人”這個關鍵字的地方進行簽字,第四個參數代表的是輸出路徑

(3)使用postman測試(因為是post接口,所有隻能使用postman進行簡單的測試)

java實作pdf檔案的電子簽字+蓋章+二維碼+水印+PDF檔案加密的解決方案二、使用itextPDF實作PDF電子公章工具類三、thymeleaf+itext簽字功能+PDF檔案加密實作四、PDF實作生成水印并删除源檔案五、PDF使用工具Adobe Acrobat DC+PDF+Itext模闆實作二維碼功能

(4)最終生成了兩個檔案

java實作pdf檔案的電子簽字+蓋章+二維碼+水印+PDF檔案加密的解決方案二、使用itextPDF實作PDF電子公章工具類三、thymeleaf+itext簽字功能+PDF檔案加密實作四、PDF實作生成水印并删除源檔案五、PDF使用工具Adobe Acrobat DC+PDF+Itext模闆實作二維碼功能
  • 一個是沒有加密的signOut.pdf,他是簽字後生成的檔案
java實作pdf檔案的電子簽字+蓋章+二維碼+水印+PDF檔案加密的解決方案二、使用itextPDF實作PDF電子公章工具類三、thymeleaf+itext簽字功能+PDF檔案加密實作四、PDF實作生成水印并删除源檔案五、PDF使用工具Adobe Acrobat DC+PDF+Itext模闆實作二維碼功能
  • 加密後的檔案EncryptPDF.pdf 這個需要輸入密碼才能打開檔案
  • 輸入隻讀密碼 123456
java實作pdf檔案的電子簽字+蓋章+二維碼+水印+PDF檔案加密的解決方案二、使用itextPDF實作PDF電子公章工具類三、thymeleaf+itext簽字功能+PDF檔案加密實作四、PDF實作生成水印并删除源檔案五、PDF使用工具Adobe Acrobat DC+PDF+Itext模闆實作二維碼功能
  • 打開檔案後,裡面的所有文字不能複制
java實作pdf檔案的電子簽字+蓋章+二維碼+水印+PDF檔案加密的解決方案二、使用itextPDF實作PDF電子公章工具類三、thymeleaf+itext簽字功能+PDF檔案加密實作四、PDF實作生成水印并删除源檔案五、PDF使用工具Adobe Acrobat DC+PDF+Itext模闆實作二維碼功能
  • 使用可以修改權限打開檔案 密碼:test 檔案是可以複制可以修改的
java實作pdf檔案的電子簽字+蓋章+二維碼+水印+PDF檔案加密的解決方案二、使用itextPDF實作PDF電子公章工具類三、thymeleaf+itext簽字功能+PDF檔案加密實作四、PDF實作生成水印并删除源檔案五、PDF使用工具Adobe Acrobat DC+PDF+Itext模闆實作二維碼功能

四、PDF實作生成水印并删除源檔案

1、生成水印的工具類

package com.whj.util;

import com.itextpdf.text.BaseColor;
import com.itextpdf.text.Element;
import com.itextpdf.text.pdf.*;

import java.io.File;
import java.io.FileOutputStream;

/**
 * @author 王恒傑
 * @date 2022/10/21 14:53
 * @Description:
 */
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();
        System.out.println("adksjskalfklsdk");
        //設定字型
        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水印添加完成!");
    }

    

}



           

删除源檔案

//删除沒有用的檔案
    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;
    }

           

2、測試

(1)加水印之前的源檔案

java實作pdf檔案的電子簽字+蓋章+二維碼+水印+PDF檔案加密的解決方案二、使用itextPDF實作PDF電子公章工具類三、thymeleaf+itext簽字功能+PDF檔案加密實作四、PDF實作生成水印并删除源檔案五、PDF使用工具Adobe Acrobat DC+PDF+Itext模闆實作二維碼功能

(2)測試代碼

public class TestWaterMark {
    public static void main(String[] args) {
        /**
         * pdf生成水印
         *
         * @param srcPdfPath       插入前的檔案路徑
         * @param tarPdfPath       插入後的檔案路徑
         * @param WaterMarkContent 水印文案
         * @param numberOfPage     每頁需要插入的條數
         * @throws Exception
         */
        String srcPdfPath = "D:\\Idea\\stamp\\Itext\\src\\main\\resources\\pdf\\signOut.pdf";
        String tarPdfPath = "D:\\Idea\\stamp\\Itext\\src\\main\\resources\\pdf\\TestWaterMark.pdf";
        String WaterMarkContent = "程式員小王";
        Integer numberOfPage = 3;
        try {
            WaterMark.addWaterMark(srcPdfPath, tarPdfPath, WaterMarkContent, numberOfPage);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

           

[外鍊圖檔轉存失敗,源站可能有防盜鍊機制,建議将圖檔儲存下來直接上傳(img-u39T5Cpx-1666600264552)(image/image_XDeFaw_Svq.png)]

  • 删除源檔案的代碼
boolean b = deleteFile(srcPdfPath);

           

(3)加水印之後的檔案

java實作pdf檔案的電子簽字+蓋章+二維碼+水印+PDF檔案加密的解決方案二、使用itextPDF實作PDF電子公章工具類三、thymeleaf+itext簽字功能+PDF檔案加密實作四、PDF實作生成水印并删除源檔案五、PDF使用工具Adobe Acrobat DC+PDF+Itext模闆實作二維碼功能
java實作pdf檔案的電子簽字+蓋章+二維碼+水印+PDF檔案加密的解決方案二、使用itextPDF實作PDF電子公章工具類三、thymeleaf+itext簽字功能+PDF檔案加密實作四、PDF實作生成水印并删除源檔案五、PDF使用工具Adobe Acrobat DC+PDF+Itext模闆實作二維碼功能

五、PDF使用工具Adobe Acrobat DC+PDF+Itext模闆實作二維碼功能

1、打開電腦中的Adobe Acrobat pro DC(這個應該win10 都有,搜尋一下就出來了),點選 檔案→建立→建立表單

  • 如果沒有自己安裝下載下傳一個下載下傳位址:adobe acrobat pro dc2018破解版
  • acrobat pro dc 2018序列号

    1118-1629-0753-5166-7814-8217

java實作pdf檔案的電子簽字+蓋章+二維碼+水印+PDF檔案加密的解決方案二、使用itextPDF實作PDF電子公章工具類三、thymeleaf+itext簽字功能+PDF檔案加密實作四、PDF實作生成水印并删除源檔案五、PDF使用工具Adobe Acrobat DC+PDF+Itext模闆實作二維碼功能

2、然後導入剛剛生成的pdf(注意簽名後的檔案不能再進行添加二維碼或者文字了)

java實作pdf檔案的電子簽字+蓋章+二維碼+水印+PDF檔案加密的解決方案二、使用itextPDF實作PDF電子公章工具類三、thymeleaf+itext簽字功能+PDF檔案加密實作四、PDF實作生成水印并删除源檔案五、PDF使用工具Adobe Acrobat DC+PDF+Itext模闆實作二維碼功能

3、點選圖檔

java實作pdf檔案的電子簽字+蓋章+二維碼+水印+PDF檔案加密的解決方案二、使用itextPDF實作PDF電子公章工具類三、thymeleaf+itext簽字功能+PDF檔案加密實作四、PDF實作生成水印并删除源檔案五、PDF使用工具Adobe Acrobat DC+PDF+Itext模闆實作二維碼功能

4、固定好二維碼固定位置然後編輯他為img()

  • 擊這個陰影部分,将名稱改成你要設定的名稱,後面要根據這個名稱來給他指派
java實作pdf檔案的電子簽字+蓋章+二維碼+水印+PDF檔案加密的解決方案二、使用itextPDF實作PDF電子公章工具類三、thymeleaf+itext簽字功能+PDF檔案加密實作四、PDF實作生成水印并删除源檔案五、PDF使用工具Adobe Acrobat DC+PDF+Itext模闆實作二維碼功能

5、全部設定好以後就可以另存為了,打開後是這個樣子

java實作pdf檔案的電子簽字+蓋章+二維碼+水印+PDF檔案加密的解決方案二、使用itextPDF實作PDF電子公章工具類三、thymeleaf+itext簽字功能+PDF檔案加密實作四、PDF實作生成水印并删除源檔案五、PDF使用工具Adobe Acrobat DC+PDF+Itext模闆實作二維碼功能

6、實作二維碼生成的工具類(僅供測試,詳細代碼看7)

java實作pdf檔案的電子簽字+蓋章+二維碼+水印+PDF檔案加密的解決方案二、使用itextPDF實作PDF電子公章工具類三、thymeleaf+itext簽字功能+PDF檔案加密實作四、PDF實作生成水印并删除源檔案五、PDF使用工具Adobe Acrobat DC+PDF+Itext模闆實作二維碼功能
  • jar包
<!-- 條形碼、二維碼生成 -->
        <dependency>
            <groupId>com.google.zxing</groupId>
            <artifactId>core</artifactId>
            <version>3.3.0</version>
        </dependency>
        <dependency>
            <groupId>com.google.zxing</groupId>
            <artifactId>javase</artifactId>
            <version>3.3.0</version>
        </dependency>

           
  • 代碼
package com.whj.util.QR;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.WriterException;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;

import java.awt.image.BufferedImage;
import java.io.IOException;
import java.nio.file.FileSystems;
import java.nio.file.Path;
import java.util.Hashtable;

/**
 * @author 王恒傑
 * @date 2022/10/21 16:25
 * 二維碼生成工具類
 *
 * 通過Google開源的zxing庫來事項生成二維碼圖檔
 */
public class QrCodeUtils {

    public static final String QR_CODE_IMAGE_PATH = "D:\\Idea\\stamp\\Itext\\src\\main\\resources\\QR\\MyQRCode.png";

    public static void generateQRCodeImage(String text, int width, int height, String filePath) throws WriterException, IOException {
        QRCodeWriter qrCodeWriter = new QRCodeWriter();

        BitMatrix bitMatrix = qrCodeWriter.encode(text, BarcodeFormat.QR_CODE, width, height);

        Path path = FileSystems.getDefault().getPath(filePath);

        MatrixToImageWriter.writeToPath(bitMatrix, "PNG", path);

    }

    /**
     * 生成二維碼
     * @param contents 二維碼的内容
     * @param width 二維碼圖檔寬度
     * @param height 二維碼圖檔高度
     */
    public static BufferedImage createQrCodeBufferdImage(String contents, int width, int height){
        Hashtable hints= new Hashtable();
        hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
        BufferedImage image = null;
        try {
            BitMatrix bitMatrix = new MultiFormatWriter().encode(
                    contents,BarcodeFormat.QR_CODE, width, height, hints);
            image = toBufferedImage(bitMatrix);
        } catch (WriterException e) {
            e.printStackTrace();
        }
        return image;
    }

    public static BufferedImage toBufferedImage(BitMatrix matrix) {
        int width = matrix.getWidth();
        int height = matrix.getHeight();
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        for (int x = 0; x < width; x++) {
            for (int y = 0; y < height; y++) {
                image.setRGB(x, y, matrix.get(x, y) ? 0xFF000000 : 0xFFFFFFFF);
            }
        }
        return image;
    }

    public static void main(String[] args) {
        try {
            generateQRCodeImage ("https://www.baidu.com/", 350, 350,QR_CODE_IMAGE_PATH);
        } catch (WriterException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }

}



           
  • 測試二維碼生成
package com.whj.util.QR;

import com.google.zxing.WriterException;

import java.io.IOException;

import static com.whj.util.QR.QrCodeUtils.QR_CODE_IMAGE_PATH;

/**
 * @author 王恒傑
 * @date 2022/10/24 15:42
 * @Description:
 */
public class TestQR {
    public static void main(String[] args) {
        try {
            /**
             * 第一個參數:内容可以是二維碼 也可以是内容
             * 第二第三參數:二維碼的寬高
             * 第四個參數:二維碼生成後的位址
             */
            QrCodeUtils.generateQRCodeImage ("https://www.wolai.com/6MjBCdAq3mmGXBcb62V4DE", 350, 350,QR_CODE_IMAGE_PATH);
        } catch (WriterException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

           
  • 生成後的二維碼
java實作pdf檔案的電子簽字+蓋章+二維碼+水印+PDF檔案加密的解決方案二、使用itextPDF實作PDF電子公章工具類三、thymeleaf+itext簽字功能+PDF檔案加密實作四、PDF實作生成水印并删除源檔案五、PDF使用工具Adobe Acrobat DC+PDF+Itext模闆實作二維碼功能

7、生成二維碼之後将二維碼嵌入進PDF綜合版本

  • 生成二維碼并且嵌入PDF工具
package com.whj;

import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Font;
import com.itextpdf.text.Image;
import com.itextpdf.text.pdf.*;

import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * @author 王恒傑
 * @date 2022/10/24 16:06
 * @Description:
 */
public class QR {

    // 利用模闆生成pdf

    public static void pdfout(Map<String,Object> map) {

        // 模闆路徑

        String templatePath = "D:\\Idea\\stamp\\Itext\\src\\main\\resources\\QR\\QR.pdf";

        // 生成的新檔案路徑

        String newPDFPath = "D:\\Idea\\stamp\\Itext\\src\\main\\resources\\QR\\testout.pdf";

        PdfReader reader;

        FileOutputStream out;

        ByteArrayOutputStream bos;

        PdfStamper stamper;

        try {

            //給表單添加中文字型 這裡采用系統字型。不設定的話,中文可能無法顯示

            BaseFont bf = BaseFont.createFont("D:\\Idea\\stamp\\Itext\\src\\main\\resources\\Font\\SIMYOU.TTF" , BaseFont.IDENTITY_H, BaseFont.EMBEDDED);

            Font FontChinese = new Font(bf, 5, Font.NORMAL);

            // 輸出流

            out = new FileOutputStream(newPDFPath);

            // 讀取pdf模闆

            reader = new PdfReader(templatePath);

            bos = new ByteArrayOutputStream();

            stamper = new PdfStamper(reader, bos);

            AcroFields form = stamper.getAcroFields();

            Map<String,Object> qrcodeFields=(Map<String, Object>) map.get("qrcodeFields");

            //周遊二維碼字段

            for (Map.Entry<String, Object> entry : qrcodeFields.entrySet()) {

                String key = entry.getKey();

                Object value = entry.getValue();

                // 擷取屬性的類型

                if(value != null && form.getField(key) != null){

                    //擷取位置(左上右下)

                    AcroFields.FieldPosition fieldPosition = form.getFieldPositions(key).get(0);

                    //繪制二維碼

                    float width = fieldPosition.position.getRight() - fieldPosition.position.getLeft();

                    BarcodeQRCode pdf417 = new BarcodeQRCode(value.toString(), (int)width, (int)width, null);

                    //生成二維碼圖像

                    Image image128 = pdf417.getImage();

                    //繪制在第一頁

                    PdfContentByte cb = stamper.getOverContent(1);

                    //左邊距(居中處理)

                    float marginLeft = (fieldPosition.position.getRight() - fieldPosition.position.getLeft() - image128.getWidth()) / 2;

                    //條碼位置

                    image128.setAbsolutePosition(fieldPosition.position.getLeft() + marginLeft, fieldPosition.position.getBottom());

                    //加入條碼

                    cb.addImage(image128);

                }

            }

            // 如果為false,生成的PDF檔案可以編輯,如果為true,生成的PDF檔案不可以編輯

            stamper.setFormFlattening(true);

            stamper.close();

            Document doc = new Document();

            Font font = new Font(bf, 20);

            PdfCopy copy = new PdfCopy(doc, out);

            doc.open();
            PdfImportedPage importPage = copy.getImportedPage(new PdfReader(bos.toByteArray()), 1);

            copy.addPage(importPage);

            doc.close();

        } catch (IOException e) {

            e.printStackTrace();

        } catch (DocumentException e) {

            e.printStackTrace();

        }

    }

}


           
  • 測試
public static void main(String[] args) {

        //文本内容map

        Map<String,Object> map = new HashMap<String, Object>();

        //二維碼map

        Map<String,Object> qrcodeFields = new HashMap<String, Object>();

        qrcodeFields.put("img","https://www.wolai.com/6MjBCdAq3mmGXBcb62V4DE");

        //組裝map傳過去

        Map<String,Object> o=new HashMap<String, Object>();

        o.put("qrcodeFields",qrcodeFields);
        //執行

        pdfout(o);

    }

           
java實作pdf檔案的電子簽字+蓋章+二維碼+水印+PDF檔案加密的解決方案二、使用itextPDF實作PDF電子公章工具類三、thymeleaf+itext簽字功能+PDF檔案加密實作四、PDF實作生成水印并删除源檔案五、PDF使用工具Adobe Acrobat DC+PDF+Itext模闆實作二維碼功能

項目開源位址:https://gitee.com/wanghengjie563135/pdf.git

csdn下載下傳位址:https://download.csdn.net/download/weixin_44385486/86813947

java實作pdf檔案的電子簽字+蓋章+二維碼+水印+PDF檔案加密的解決方案二、使用itextPDF實作PDF電子公章工具類三、thymeleaf+itext簽字功能+PDF檔案加密實作四、PDF實作生成水印并删除源檔案五、PDF使用工具Adobe Acrobat DC+PDF+Itext模闆實作二維碼功能

本文轉自 https://blog.csdn.net/weixin_44385486/article/details/127495462,如有侵權,請聯系删除。