多次数字签名 pdf 并在签名时向其添加文本/图像

问题描述 投票:0回答:0

我想要一个pdf由多个用户顺序签名。他们还可以在对文档进行数字签名时添加文本或姓名首字母的图像。我正在使用 pdfbox 版本 2.0.25.

我在问题的编辑 3 中使用了 here 中的代码来添加文本,同时还签署了文档。 下面是将签名字段添加到 pdf 的代码。

try (FileOutputStream fos = new FileOutputStream(signedFile)) {
            PDSignature signature = new PDSignature();
            PDDocument doc = PDDocument.load(inputFile);
            for (DocumentSigningObject signingObject : documentSigningObjectList) {
                SignatureOptions signatureOptions = new SignatureOptions();
                SignerOptionEntity signerOption = signingObject.getSignerOptionEntity();

                PDRectangle rect = createSignatureRectangle(doc, signingObject.getPlaceholderEntity());
                signatureOptions.setPreferredSignatureSize(SignatureOptions.DEFAULT_SIGNATURE_SIZE * 2);
                signatureOptions.setPage(signingObject.getSignatureComponents().getPage() - 1);
                signatureOptions
                        .setVisualSignature(createVisualSignatureTemplate(doc, rect,
                                signerOption, signingObject.getSignatureComponents().getPage(),
                                signingObject.getSignatureComponents().getText()));

                signature.setFilter(PDSignature.FILTER_ADOBE_PPKLITE);
                signature.setSubFilter(PDSignature.SUBFILTER_ADBE_PKCS7_DETACHED);
                signature.setName(name);

                if (Objects.nonNull(signerOption) && doLocationExists(signerOption)) {
                    signature.setLocation(getFormattedLocationValue(signerOption));
                }

                signature.setSignDate(Calendar.getInstance());
                signature.setReason(Objects.nonNull(signerOption)
                        && StringUtils.isNotBlank(signerOption.getSignatureNote())
                        ? signerOption.getSignatureNote() : "");
                doc.addSignature(signature, signatureOptions);
                ExternalSigningSupport externalSigning = doc.saveIncrementalForExternalSigning(fos);
                MessageDigest digest = MessageDigest.getInstance("SHA-256");
                byte[] hashBytes = digest.digest(IOUtils.toByteArray(externalSigning.getContent()));
                base64Hash = Base64.getEncoder().encodeToString(hashBytes);
                externalSigning.setSignature(new byte[0]);
                offset = signature.getByteRange()[1] + 1;
                IOUtils.closeQuietly(signatureOptions);
            }

方法 createSignatureVisualTemplate()

try (PDDocument doc = new PDDocument()) {
            int pageNum = pageNo - 1;
            PDPage page = new PDPage(srcDoc.getPage(pageNum).getMediaBox());
            doc.addPage(page);
            PDAcroForm acroForm = doc.getDocumentCatalog().getAcroForm();
            if (acroForm == null) {
                acroForm = new PDAcroForm(doc);
            }
            doc.getDocumentCatalog().setAcroForm(acroForm);
            acroForm.setSignaturesExist(true);
            acroForm.setAppendOnly(true);
            acroForm.getCOSObject().setDirect(true);

            PDSignatureField signatureField = new PDSignatureField(acroForm);
            List<PDField> acroFormFields = acroForm.getFields();
            acroFormFields.add(signatureField);
            PDAnnotationWidget widget = signatureField.getWidgets().get(0);
            widget.setRectangle(rect);

            PDStream stream = new PDStream(doc);
            PDFormXObject form = new PDFormXObject(stream);
            PDResources res = new PDResources();
            form.setResources(res);
            form.setFormType(1);
            PDRectangle pdRectangle = new PDRectangle(rect.getWidth(), rect.getHeight());
            Matrix initialScale = null;
            switch (srcDoc.getPage(pageNum).getRotation()) {
                case 90:
                    form.setMatrix(AffineTransform.getQuadrantRotateInstance(1));
                    initialScale = Matrix.getScaleInstance(pdRectangle.getWidth() / pdRectangle.getHeight(),
                            pdRectangle.getHeight() / pdRectangle.getWidth());
                    break;
                case 180:
                    form.setMatrix(AffineTransform.getQuadrantRotateInstance(2));
                    break;
                case 270:
                    form.setMatrix(AffineTransform.getQuadrantRotateInstance(3));
                    initialScale = Matrix.getScaleInstance(pdRectangle.getWidth() / pdRectangle.getHeight(),
                            pdRectangle.getHeight() / pdRectangle.getWidth());
                    break;
                case 0:
                default:
                    break;
            }
            form.setBBox(pdRectangle);

            // from PDVisualSigBuilder.createAppearanceDictionary()
            PDAppearanceDictionary appearance = new PDAppearanceDictionary();
            appearance.getCOSObject().setDirect(true);
            PDAppearanceStream appearanceStream = new PDAppearanceStream(form.getCOSObject());
            appearance.setNormalAppearance(appearanceStream);
            widget.setAppearance(appearance);

            try (PDPageContentStream cs = new PDPageContentStream(doc, appearanceStream)) {
                if (initialScale != null) {
                    cs.transform(initialScale);
                }
                cs.saveGraphicsState();
                //Use the signature image as received, without any modification
                if (Objects.nonNull(signatureOption) && Objects.nonNull(signatureOption.getSignatureImage())) {
                    PDImageXObject img = PDImageXObject.createFromByteArray(doc,
                            getBase64ImageByteData(signatureOption), null);
                    cs.drawImage(img, 0, 0, rect.getWidth(), rect.getHeight());

                }
                cs.restoreGraphicsState();
            }
            
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            doc.save(baos);
            return new ByteArrayInputStream(baos.toByteArray());

第一个用户签署文档后,在 AdobeAcrobatReader 中打开 pdf 时会显示以下消息。

Pdf signed by first user for the fisrt time

现在第二个用户签署了已经签署的 pdf 并添加了他的姓名首字母。现在阅读器上显示的消息是: Pdf signed second time by different user

文本是在签名字段添加到文档之前添加的,但它说文档是在签名后更新的。虽然两个签名仍然有效,但有人可以解释消息和方式,以便仅显示签名的有效性。

java pdf pdfbox
© www.soinside.com 2019 - 2024. All rights reserved.