pdfbox 去除签名 保留签名图片

534 阅读2分钟

需求描述

最近来了一个需求,客户要在 10 份 PDF 上使用电子签名,签完了以后还要合并再进行一次总的签名

众所周知,电子签名当文档本身内容发生变化后,它的 hash 值就变了,和电子签名存储的 hash 值不一致,电子签名就失效了,客户觉得这个失效很难看,希望能保留印章图片,去除签名证书

pdfbox 简单介绍

pdfbox 是一个支持 PDF 文档开发转换的 java 开源库

在我看来,这个开源库最棒的功能就是

  • 分割和合并 PDF 文档
  • 将 PDF 保存为图片

思路简单描述

PDF 的数据结构可以这样理解,文档的内容中,所有的文本,图片,签名都是一个个对象,对象直接有互相的引用,签名相当于一个图片对象,对象包含了一个引用对象,引用指向一个签名证书对象,签名证书对象也包含一个指向图片对象的引用对象。

我的思路就是过滤出签名证书,直接把这些签名对象删掉,这样就能只保留图片了。

需要说明的是这只是我的简单理解。

代码实现

public class DocumentConvertNoCert {
	public static void convertNoCert(OutputStream os, byte[] file) {
		PDDocument pdDocument;
		try {
			pdDocument = PDDocument.load(file);
			PDDocumentCatalog documentCatalog = pdDocument.getDocumentCatalog();
			PDAcroForm acroForm = documentCatalog.getAcroForm();
			PDFieldTree fieldTree = acroForm.getFieldTree();
			List<PDField> fields = new ArrayList<>();
			for (PDField pdField : fieldTree) {
				if (pdField instanceof PDSignatureField){
					fields.add(pdField);
				}

			}
			acroForm.flatten(fields,true);
			pdDocument.save(os);
			pdDocument.close();
		} catch (IOException e) {
			throw new BizException("转换无证书文档失败",e);
		}
	}
}

最终效果

我本地的旧版 Adobe pdf 阅读器对于签名图片的点击没有反应,和普通图片一样。

客户的新版 pdf 阅读点击签名图片时会显示签名数据错误。

之后使用 Adobe pdf 阅读器进行文件合并后,文件就看上去正常了,也可以继续正常地签名。