maven引入依赖
<dependency>
<groupId>repository_personal.com.lowagie</groupId>
<artifactId>itext</artifactId>
<version>1.4</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.itextpdf/itextpdf -->
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itextpdf</artifactId>
<version>5.5.10</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.itextpdf/itext-asian -->
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itext-asian</artifactId>
<version>5.2.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.bouncycastle/bcpkix-jdk15on -->
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk15on</artifactId>
<version>1.60</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.bouncycastle/bcprov-jdk15on -->
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.60</version>
</dependency>
工具类
//PDF盖章
void ImageStamp(){
//创建PdfDocument对象,加载PDF测试文档
PdfDocument doc = new PdfDocument();
doc.loadFromFile("E://浏览器//test1.pdf");
//获取文档第3页
PdfPageBase page = doc.getPages().get(0);
//加载印章图片
PdfImage image = PdfImage.fromFile("E://浏览器//qs.png");
//获取印章图片的宽度和高度
int width = image.getWidth();
int height = image.getHeight();
//创建PdfTemplate对象
PdfTemplate template = new PdfTemplate(width, height);
//将图片绘制到模板
template.getGraphics().drawImage(image, 0, 0, width, height);
//创建PdfRubebrStampAnnotation对象,指定大小和位置
Rectangle2D rect = new Rectangle2D.Float((float) (page.getActualSize().getWidth() - width - 10), (float) (page.getActualSize().getHeight() - height - 60), width, height);
PdfRubberStampAnnotation stamp = new PdfRubberStampAnnotation(rect);
//创建PdfAppearance对象
PdfAppearance pdfAppearance = new PdfAppearance(stamp);
//将模板应用为PdfAppearance的一般状态
pdfAppearance.setNormal(template);
//将PdfAppearance 应用为图章的样式
stamp.setAppearance(pdfAppearance);
//添加图章到PDF
page.getAnnotationsWidget().add(stamp);
//保存文档
doc.saveToFile("E://浏览器//ImageStamp.pdf",FileFormat.PDF);
}
//PDF签字
@Test
void TextStamp() throws IOException, DocumentException {
// 要输出的pdf文件
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(new File("E://浏览器//TextStamp.pdf")));
// 将pdf文件先加水印然后输出
PdfReader reader = new PdfReader("E://浏览器//ImageStamp.pdf");
PdfStamper stamper = new PdfStamper(reader, bos);
// 获取总页数 +1, 下面从1开始遍历
int total = reader.getNumberOfPages() + 1;
// 使用classpath下面的字体库
BaseFont base = null;
try {
base = BaseFont.createFont("E://浏览器//方正楷体.ttf", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
} catch (Exception e) {
// 日志处理
e.printStackTrace();
}
// 设置水印透明度
PdfGState gs = new PdfGState();
gs.setFillOpacity(0.4f);
gs.setStrokeOpacity(0.4f);
PdfContentByte content = null;
for (int i = 1; i < total; i++) {
// 在内容上方加水印
content = stamper.getOverContent(i);
// 在内容下方加水印
// content = stamper.getUnderContent(i);
content.saveState();
content.setGState(gs);
// 设置字体和字体大小
content.beginText();
content.setFontAndSize(base, 10);
// 设置字体样式
float ta = 1F, tb = 0F, tc = 0F, td = 1F, tx = 0F, ty = 0F;
// 设置加粗(加粗)
ta += 0.25F;
td += 0.05F;
ty -= 0.2F;
// 设置倾斜(倾斜程序自己改)
tc += 0.8F;
content.setTextMatrix(ta, tb, tc, td, tx, ty);
// 设置相对于左下角位置(向右为x,向上为y)
content.moveText(300F, 50F);
// 显示text
content.showText("青莳");
content.endText();
content.stroke();
content.restoreState();
}
// 关流
stamper.close();
reader.close();
}
//CA签名认证工具类
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 java.io.FileOutputStream;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.PrivateKey;
import java.security.cert.Certificate;
public class KeystoreUtils {
/**
*
* @param src 需要签章的pdf文件路径
* @param dest 签完章的pdf文件路径
* @param chain 证书链
* @param img 印章图片
* @param pk 签名私钥
* @param digestAlgorithm 摘要算法名称,例如SHA-1
* @param provider 密钥算法提供者,可以为null
* @param subfilter 数字签名格式,itext有2种
* @param reason 签名的原因,显示在pdf签名属性中
* @param location 签名的地点,显示在pdf签名属性中
* @throws GeneralSecurityException
* @throws IOException
* @throws DocumentException
*/
public void sign(String src, String dest,String img, Certificate[] chain, PrivateKey pk, String digestAlgorithm, String provider,
MakeSignature.CryptoStandard subfilter, String reason, String location) throws GeneralSecurityException, IOException, DocumentException {
PdfReader pdfReader = new PdfReader(src);
FileOutputStream fileOutputStream = new FileOutputStream(dest);
/**
* 1 参数依次为:文件名、文件输入流、文件版本号、临时文件、是否可以追加签名
* 1.1 false的话,pdf文件只允许被签名一次,多次签名,最后一次有效
* 1.2 true的话,pdf可以被追加签名,验签工具可以识别出每次签名之后文档是否被修改
*/
PdfStamper stamper = PdfStamper.createSignature(pdfReader, fileOutputStream, '\0', null, false);
// 获取数字签章属性对象,设定数字签章的属性
PdfSignatureAppearance appearance = stamper.getSignatureAppearance();
appearance.setReason(reason);
appearance.setLocation(location);
/**
* 签名的大小以及位置
* 1 三个参数依次为:设置签名的位置、页码、签名域名称,多次追加签名的时候,签名域名称不能一样
* 1.1 签名的位置四个参数:印章左下角的X、Y轴坐标,印章右上角的X、Y轴坐标,
* 这个位置是相对于PDF页面的位置坐标,即该坐标距PDF当前页左下角的坐标
*/
appearance.setVisibleSignature(new Rectangle(100, 100, 200, 200), 1, "sign");
/**
* 用于盖章的印章图片,引包的时候要引入itext包的image
*/
Image image = Image.getInstance(img);
appearance.setSignatureGraphic(image);
/**
* 设置认证等级,共4种,分别为:
* NOT_CERTIFIED、CERTIFIED_NO_CHANGES_ALLOWED、
* CERTIFIED_FORM_FILLING 和 CERTIFIED_FORM_FILLING_AND_ANNOTATIONS
*
* 需要用哪一种根据业务流程自行选择
*/
appearance.setCertificationLevel(PdfSignatureAppearance.NOT_CERTIFIED);
/**
* 印章的渲染方式,同样有4种:
* DESCRIPTION、NAME_AND_DESCRIPTION,
* GRAPHIC_AND_DESCRIPTION,GRAPHIC;
* 这里选择只显示印章
*/
appearance.setRenderingMode(PdfSignatureAppearance.RenderingMode.GRAPHIC);
/**
* 算法主要为:RSA、DSA、ECDSA
* 摘要算法,这里的itext提供了2个用于签名的接口,可以自己实现
*/
ExternalDigest digest = new BouncyCastleDigest();
/**
* 签名算法,参数依次为:证书秘钥、摘要算法名称,例如MD5 | SHA-1 | SHA-2.... 以及 提供者
*/
ExternalSignature signature = new PrivateKeySignature(pk, digestAlgorithm, null);
/**
* 最重要的来了,调用itext签名方法完成pdf签章
*/
MakeSignature.signDetached(appearance, digest, signature, chain, null, null, null, 0, subfilter);
}
}
//测试CA签名认证
@Test
void KeystoreTest(){
String KEYSTORE = "E:\\浏览器\\android.keystore";
// 之前生成的keystory密码
char[] PASSWORD = "123456".toCharArray();
// 需要签名的PDF路径
String SRC = "E://浏览器//test1.pdf";
// 完成签名的PDF路径
String OUTPUT_SRC = "E://浏览器//ImageStamp.pdf";
String IMG = "E://浏览器//qs.png";
try {
//读取keystore ,获得私钥和证书链
KeyStore keyStore = KeyStore.getInstance("JKS");
keyStore.load(new FileInputStream(KEYSTORE), PASSWORD);
String alias = (String)keyStore.aliases().nextElement();
PrivateKey PrivateKey = (PrivateKey) keyStore.getKey(alias, PASSWORD);
Certificate[] chain = keyStore.getCertificateChain(alias);
KeystoreUtils keystoreUtils = new KeystoreUtils();
keystoreUtils.sign(SRC, String.format(OUTPUT_SRC, 3),IMG, chain, PrivateKey, DigestAlgorithms.SHA1, null, MakeSignature.CryptoStandard.CMS, "Test", "Ghent");
} catch (Exception e) {
JOptionPane.showMessageDialog(null, e.getMessage());
e.printStackTrace();
}
}