public class ReadMe {
public static void main(String[] args) throws Exception {
//1、创建PDF阅读器
PdfReader pdfReader = new PdfReader("需要签章的PDF文件路径");
//2、创建签章工具PdfStamper
//最后一个参数false的话:PDF文件只允许被签名一次,多次签名时最后一次有效;true的话:可以被追加签名,验签工具可以识别出每次签名之后文档是否被修改
PdfStamper pdfStamper = PdfStamper.createSignature(pdfReader, new FileOutputStream("签章后的PDF文件路径"),
'\0', null, true);
//3、创建数字签名域
int x = 300, y = 400, width = 200, height = 200;
Rectangle areaSignatureRect = new Rectangle(x, y, x + width, y + height); //签名区域
PdfFormField formField = PdfFormField.createSignature(pdfStamper.getWriter());
formField.setFieldName("AREA_SIGNATURE"); //签名域标识
formField.setPage(1); //PDF页码从1开始
formField.setWidget(areaSignatureRect, PdfAnnotation.HIGHLIGHT_OUTLINE); //高亮显示
//可以通过PdfAppearance对象对这块区域外观做下调整
PdfAppearance pdfAppearance = PdfAppearance.createAppearance(pdfStamper.getWriter(), width, height); //设置区域的宽高和边框厚度
pdfAppearance.setColorStroke(BaseColor.LIGHT_GRAY); //边框颜色
pdfAppearance.setColorFill(BaseColor.YELLOW); //填充颜色
//填充矩形区域-开始
pdfAppearance.rectangle(0, 0, width, height);
//填充矩形区域-结束
pdfAppearance.fillStroke();
//添加文字
pdfAppearance.setColorFill(BaseColor.BLACK); //填充颜色重置为黑色,用于显示文字
ColumnText.showTextAligned(pdfAppearance, Element.ALIGN_CENTER, new Phrase("签名区域",
new Font(Font.FontFamily.SYMBOL, 9.0F, Font.NORMAL, new BaseColor(0.0F, 0.0F, 0.0F, 0.5F))),
width / 2, height / 2, 0);
//将外观应用到签名域对象上
formField.setAppearance(PdfAnnotation.APPEARANCE_NORMAL, pdfAppearance);
//最后将签名对象作为标注添加到PdfStamper对象
pdfStamper.addAnnotation(formField, 1);
//3、获取数字签章属性对象,设定数字签章属性(对签名域的属性进行调整)
PdfSignatureAppearance appearance = pdfStamper.getSignatureAppearance();
appearance.setReason("签名原因,显示在PDF签名属性中");
appearance.setLocation("签名地点,显示在PDF签名属性中");
//设置签名的位置,页码、签名域名称,多次追加签名的时候签名域名称不能一样
appearance.setVisibleSignature(new Rectangle(200, 200, 300, 300), 1, "sig1");
//读取印章图片
Image image = Image.getInstance("C:\\gongzhang.png");
appearance.setSignatureGraphic(image);
appearance.setCertificationLevel(PdfSignatureAppearance.NOT_CERTIFIED);
//设置图章的显示方式,如下选择的只是显示图章(还有其他模式,可以图章和签名描述一起显示)
appearance.setRenderingMode(PdfSignatureAppearance.RenderingMode.GRAPHIC);
//这里iText提供了两个用于签名的接口,可以自己实现
ExternalDigest digest = new BouncyCastleDigest(); //摘要算法
//读取keystore,获取私钥和证书链
KeyStore ks = KeyStore.getInstance("PKCS12");
ks.load(new FileInputStream("C:\\pdf\\test.p12"), "111111".toCharArray());
String alias = ks.aliases().nextElement();
PrivateKey pk = (PrivateKey) ks.getKey(alias, "111111".toCharArray()); //签名私钥
ExternalSignature signature = new PrivateKeySignature(pk, DigestAlgorithms.SHA1, null); //签名算法
Certificate[] chain = ks.getCertificateChain(alias); //证书链
MakeSignature.CryptoStandard subFilter = MakeSignature.CryptoStandard.CMS; //数字签名格式,iText有两种
//调用iText签名方法完成PDF签章
MakeSignature.signDetached(appearance, digest, signature, chain, null, null, null,
0, subFilter);
}
}