网上各种收费还说不到重点的自己研究了一下,提供给大家 盖章是抄的 二维码超链接自己写的
import cn.hutool.json.JSONObject;
import com.itextpdf.text.*;
import com.itextpdf.text.Image;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.*;
import com.itextpdf.text.pdf.PdfSignatureAppearance.RenderingMode;
import com.itextpdf.text.pdf.security.BouncyCastleDigest;
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;
import sun.misc.BASE64Decoder;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.security.MessageDigest;
import java.security.PrivateKey;
import java.security.cert.Certificate;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.List;
public static void main(String[] args) throws IOException, DocumentException, GeneralSecurityException {
String size = "{\"pagesizes\":[[1262,892],[1262,892],[1262,892],[1262,892],[1262,892],[1262,892],[1262,892],[1262,892]]}";
String img = "base64图片";
System.out.println(sign("D:\\Download\\981502a8a472c9adcfb35f59bf15d0f5.pdf",img,7,300.00F,1165.00F,400.00F,1265.00F,
"F:\\78910.pdf","F:\\文件管理\\公司\\4693642__sygnew.com.pfx",
"8KrSWRNu","SHA-1",null,
"CMS","Test","dd",1,size,"https://www.baidu.com/","https://www.baidu.com/"));
}
public static String sign(String src //需要签章的pdf文件路径
, String img,int pageNum
, float x1,float y1,float x2,float y2
, String dest // 签完章的pdf文件路径
, String ketstore //
, String password //
, String digestAlgorithm //摘要算法名称,例如SHA-1
, String provider // 密钥算法提供者,可以为null
, String subfilter //数字签名格式,itext有2种
, String reason //签名的原因,显示在pdf签名属性中,随便填
, String location //签名的地点,显示在pdf签名属性中,随便填
, int signtype//签章类型,1.普通章,2.骑缝章,3.连续章
, String size //前端传入pdf尺寸
, String filedl //短链接地址
, String linkurl //跳转地址
)
//throws GeneralSecurityException, IOException, DocumentException {
{
try{
int isCreateBarcodeQRCode=0;
//生成二维码
BarcodeQRCode barcodeQRCode = new BarcodeQRCode(filedl, 66, 66, null);
Image img2 = barcodeQRCode.getImage();
//设置二维码
Rectangle linkLocation=null;
PdfAnnotation link=null;
PdfAction action = new PdfAction(linkurl);
if(signtype==1){
//获取前端传入pdf尺寸
JSONObject jsonObject = new JSONObject(size);
List listsize=(List)jsonObject.getObj("pagesizes");
List size1= (List)listsize.get(pageNum-1);
//获取前台带入pdf尺寸
Float yy=Float.parseFloat(size1.get(0).toString());
Float xx=Float.parseFloat(size1.get(1).toString());
String uuid = UUID.randomUUID().toString();
String IMG=img;
if(!img.startsWith("/")){
IMG="F:\\"+uuid+".png";
if(IMG.startsWith("/var/www/work"))
IMG="/var/www/pdf/"+uuid+".png";
byte []b= Base64.getDecoder().decode(img);
java.io.FileOutputStream out = null;
try{
out=new java.io.FileOutputStream(IMG);
out.write(b,0,b.length);
out.close();
}catch(Exception e){
e.printStackTrace();
return e.getMessage();
}
}
//下边的步骤都是固定的,照着写就行了,没啥要解释的
// Creating the reader and the stamper,开始pdfreader
PdfReader reader = new PdfReader(src);
//获取后台pdf尺寸
Float x=Float.parseFloat(reader.getPageSize(pageNum).toString().substring(11).split("x")[0]);
Float y=Float.parseFloat(reader.getPageSize(pageNum).toString().split("x")[1].split(" ")[0]);
//得到比例
Float XB=x/xx;
Float YB=y/yy;
Float x1XB=x1*XB-2.0F;
Float y1YB=y1*YB-2.0F;
Float x2XB=x2*XB+2.0F;
Float y2YB=y2*YB+2.0F;
//目标文件输出流
FileOutputStream os = new FileOutputStream(dest);
//创建签章工具PdfStamper ,最后一个boolean参数
//false的话,pdf文件只允许被签名一次,多次签名,最后一次有效
//true的话,pdf可以被追加签名,验签工具可以识别出每次签名之后文档是否被修改
PdfStamper stamper = PdfStamper.createSignature(reader, os, '\0', null, true);
//设置二维码尺寸及位置
Float w3 = img2.getScaledWidth();
Float h3 = img2.getScaledHeight();
for (int p = 0; p <reader.getNumberOfPages() ; p++) {
x=Float.parseFloat(reader.getPageSize(p+1).toString().substring(11).split("x")[0]);
y=Float.parseFloat(reader.getPageSize(p+1).toString().split("x")[1].split(" ")[0]);
Float x3 = x-99F;
Float y3 = y-63F;
//每页都加上
img2.setAbsolutePosition(x3, y3);
stamper.getOverContent(p+1).addImage(img2);
linkLocation = new Rectangle(x3, y3, x3 + w3, y3 + h3);
link = PdfAnnotation.createLink(stamper.getWriter(),
linkLocation, PdfAnnotation.HIGHLIGHT_INVERT,
action);
link.setBorder(new PdfBorderArray(0, 0, 0));
stamper.addAnnotation(link, p+1);
}
// 获取数字签章属性对象,设定数字签章的属性
PdfSignatureAppearance appearance = stamper.getSignatureAppearance();
appearance.setReason(reason);
appearance.setLocation(location);
//设置签名的位置,页码,签名域名称,多次追加签名的时候,签名预名称不能一样
//签名的位置,是图章相对于pdf页面的位置坐标,原点为pdf页面左下角
//四个参数的分别是,图章左下角x,图章左下角y,图章右上角x,图章右上角y
appearance.setVisibleSignature(new Rectangle(x1XB,y1YB,x2XB,y2YB), pageNum, uuid);// "sig1");
//读取图章图片,这个image是itext包的image
Image image = Image.getInstance(IMG);
appearance.setSignatureGraphic(image);
appearance.setCertificationLevel(PdfSignatureAppearance.NOT_CERTIFIED);
//设置图章的显示方式,如下选择的是只显示图章(还有其他的模式,可以图章和签名描述一同显示)
appearance.setRenderingMode(RenderingMode.GRAPHIC);
char[]password2=password.toCharArray();
//读取keystore ,获得私钥和证书链
KeyStore ks = KeyStore.getInstance("PKCS12");
ks.load(new FileInputStream(ketstore), password2);
String alias = (String)ks.aliases().nextElement();
PrivateKey pk = (PrivateKey) ks.getKey(alias, password2);//签名私钥
Certificate[] chain = ks.getCertificateChain(alias);//证书链
CryptoStandard subfilter2=CryptoStandard.CMS;
if("CADES".equals(subfilter))subfilter2=CryptoStandard.CADES;
System.out.println( src+":"
+":"+ x1+":"+ y1 +":"+ x2+":"+ y2
+":"+ dest // 签完章的pdf文件路径
+":"+ ketstore //
+":"+ password //
+":"+ digestAlgorithm //摘要算法名称,例如SHA-1
+":"+ provider // 密钥算法提供者,可以为null
+":"+ subfilter //数字签名格式,itext有2种
+":"+ reason //签名的原因,显示在pdf签名属性中,随便填
+":"+ location);
// 这里的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, subfilter2);
}
}catch(Exception e) {
e.printStackTrace();
return e.getMessage();
}catch(Throwable e) {
e.printStackTrace();
return e.getMessage();
}
return "ok";
}