我正在尝试从 PDF/A-1A 输入文件创建签名的 PDF,输出必须保持一致性级别。
必须添加具有自定义外观的签名。
如果我按照下面的代码行执行此操作,则签名方面的一切正常,并且签名正确显示并验证正常。
但是 PDF/A 一致性被不包含所需 toUnicode CMAP 的嵌入字体破坏。
PdfADocument pdf = ... the doc to be signed
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
PdfReader reader = pdf.getReader();
PrivateKey privateKey = ...
Provider signatureProvider = new BouncyCastleProvider();
Certificate[] signChain = ...
PdfSigner pdfSigner = new PdfSigner(reader, buffer, true);
PdfSignatureAppearance signatureAppearance = pdfSigner.getSignatureAppearance();
signatureAppearance.setReuseAppearance(false);
signatureAppearance.setPageNumber(pdf.getNumberOfPages());
pdfSigner.setFieldName("Custom Signature");
float margin = 35;
Rectangle pageSize = pdf.getLastPage().getMediaBox();
Rectangle signaturePosition = new Rectangle(pageSize.getLeft()+margin,
pageSize.getBottom()+margin,
pageSize.getWidth()-2*margin,
(pageSize.getHeight()-2*margin)/3);
// need to do this before creating any *Canvas object, else the pageRect will be null and the signature invisible
signatureAppearance.setPageRect(signaturePosition);
PdfFont regularFont = PdfFontFactory.createFont("/path/to/truetypefile-regular.ttf", "ISO-8859-1", true);
PdfFont boldFont = PdfFontFactory.createFont("/path/to/truetypefile-bold.ttf", "ISO-8859-1", true);
int fontSize = 10;
PdfFormXObject n0 = signatureAppearance.getLayer0();
PdfCanvas n0Canvas = new PdfCanvas(n0, pdfSigner.getDocument());
PdfFormXObject n2 = signatureAppearance.getLayer2();
Canvas n2Canvas = new Canvas(n2, pdfSigner.getDocument());
if(regularFont != null) {
n2Canvas.setFont(regularFont);
n0Canvas.setFontAndSize(regularFont, fontSize);
}
ImageData imageData = ImageDataFactory.create("/path/to/image.png");
Image image = new Image(imageData);
n2Canvas.add(image);
String layer2Text = ... some lines of text containing newlines and some simple markdown
String[] paragraphs = layer2text.split("\n\n");
for (String text : paragraphs) {
boolean bold = false;
if(text.startsWith("[bold]")) {
bold = true;
text = text.replaceFirst("^\\s*\\[bold\\]\\s*", "");
}
Paragraph p = new Paragraph(text);
p.setFontSize(fontSize);
if(bold) {
p.setFont(boldFont);
}
n2Canvas.add(p);
}
... pdfSigner.setCertificationLevel(PdfSigner.CERTIFIED_FORM_FILLING_AND_ANNOTATIONS);
PrivateKeySignature externalSignature = new PrivateKeySignature(privateKey, DigestAlgorithms.SHA512, signatureProvider.getName());
BouncyCastleDigest externalDigest = new BouncyCastleDigest();
pdfSigner.signDetached(externalDigest, externalSignature, signChain, null, null, null, 0, PdfSigner.CryptoStandard.CMS);
所以我认为那里缺少一些东西。嵌入的字体不符合 PDF/A,因为它们缺少 ToUnicode CMAP 键。pdf-tools 验证器的另一个错误说:“密钥编码的值是差异,但必须是 WinAnsiEncoding 或 MacRomanEncoding。” 这似乎是同样的问题。
签名本身还可以而且很明显,样式和图像应该是适当的。只是字体似乎不太好。