Добавьте несколько подписей с помощью PDFBox 3.0.2JAVA

Программисты JAVA общаются здесь
Ответить
Anonymous
 Добавьте несколько подписей с помощью PDFBox 3.0.2

Сообщение Anonymous »

Я пытаюсь подписать документ несколько раз, используя PDFBox 3.0.2. Первый заверил, остальные подписали.

Код: Выделить всё

/*
*  Heavily influenced by:
*  https://github.com/apache/pdfbox/blob/3.0/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateVisibleSignature.java
*/

import lombok.extern.slf4j.Slf4j;
import org.apache.pdfbox.cos.COSDictionary;
import org.apache.pdfbox.cos.COSName;
import org.apache.pdfbox.io.IOUtils;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
import org.apache.pdfbox.pdmodel.interactive.digitalsignature.PDSignature;
import org.apache.pdfbox.pdmodel.interactive.digitalsignature.SignatureOptions;
import org.apache.pdfbox.pdmodel.interactive.digitalsignature.visible.PDVisibleSigProperties;
import org.apache.pdfbox.pdmodel.interactive.digitalsignature.visible.PDVisibleSignDesigner;
import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm;
import org.apache.pdfbox.pdmodel.interactive.form.PDSignatureField;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.*;
import java.security.cert.CertificateException;
import java.util.Calendar;

@Slf4j
@Component

public class CreateVisibleSignature extends CreateSignatureBase {

private static final float SIGNATURE_HEIGHT = 25;

@Value("${signature.name}")
private String name;

@Value("${signature.location}")
private String location;

@Value("${signature.reason}")
private String reason;

@Value("${signature.keystore}")
private String keystorePath;

@Value("${signature.pin}")
private String pin;

private PDVisibleSignDesigner visibleSignDesigner;
private final PDVisibleSigProperties visibleSignatureProperties = new PDVisibleSigProperties();

@PostConstruct
public void init() throws KeyStoreException, CertificateException, IOException, NoSuchAlgorithmException, UnrecoverableKeyException {
KeyStore keystore = loadKeyStore();
super.initialize(keystore, pin.toCharArray());
Security.addProvider(new BouncyCastleProvider());
setVisibleSignatureProperties(name, location, reason, 0, true);
}

public void signPDF(PDDocument document, PDImageXObject pdImage, ByteArrayOutputStream fos, PDSignatureField pdSignatureField, int pageNum, boolean isFirstSignature, boolean isLastSignature) throws IOException {

// 1. Check if the document can be modified.
checkDocumentPermissions(document);

// 2. Find the existing signature
PDSignature signature = findExistingSignature(document, pdSignatureField);

//    // 3. Adjust signature field size
//    adjustSignatureFieldSize(pdSignatureField, pdImage);

// 4. Set Visible Sign Designer and known bug check
setVisibleSignDesigner(document, pdImage, pageNum);

// 5. Set Document Permissions
setDocumentPermissions(document, signature, isFirstSignature, isLastSignature);

// 6. Set Signature Properties
setSignatureProperties(signature);

// 7. Build Signature
buildSignature(pageNum);

// 8. Add Signing Date
signature.setSignDate(Calendar.getInstance());

// 9. Sign the document
SignatureOptions signatureOptions = new SignatureOptions();
// TODO make sure getVisibleSignature is not null!
signatureOptions.setVisualSignature(visibleSignatureProperties.getVisibleSignature());
signatureOptions.setPage(visibleSignatureProperties.getPage() - 1);
document.addSignature(signature, this, signatureOptions);

// 10.  Save incremental (Must be done to add multiple signatures)
document.saveIncremental(fos);
IOUtils.closeQuietly(signatureOptions);
}

/*
* MDP (Modification Detection and Prevention) Permission Levels:
*
* 0: No DocMDP transform parameters dictionary exists (document is not certified)
*
* 1: No changes to the document are permitted
*    - Most restrictive
*    - Forbids even adding more signatures
*
* 2: Allows filling in forms and digitally signing
*    - Default if /P entry is missing or invalid
*    - Forbids other modifications (e.g., adding/deleting pages, editing content)
*
* 3: Allows filling in forms, digitally signing, and adding comments/annotations
*    - Least restrictive
*    - Still forbids modifying the document's core content
*
* Note: Attempting to make changes beyond what's allowed by the permission level will invalidate the certification signature.
*  At least in theory though, in practice, when I set the permissions, then add another signature, the first in invalidated.
*/
private void setDocumentPermissions(PDDocument document, PDSignature signature, boolean isFirstSignature, boolean isLastSignature) throws IOException {
// The first signatures must be the certification signature, the following signatures must be approval signatures
if (document.getVersion() >= 1.5f) {
if (isFirstSignature) {
if (SigUtils.getMDPPermission(document) == 0) {
// See notes above.  Maybe we can get away with this until we figure it out
SigUtils.setMDPPermission(document, signature,2);
} else {
throw new IllegalStateException("Document is already certified");
}
}
} else {

if (!isDocumentCertified(document)) {
log.warn("Adding approval signature to an uncertified document");
}
}
}

private void setSignatureProperties(PDSignature signature){
signature.setFilter(PDSignature.FILTER_ADOBE_PPKLITE);
signature.setSubFilter(PDSignature.SUBFILTER_ADBE_PKCS7_DETACHED);
signature.setName(visibleSignatureProperties.getSignerName());
signature.setLocation(visibleSignatureProperties.getSignerLocation());
signature.setReason(visibleSignatureProperties.getSignatureReason());
}

private void buildSignature(int pageNum) throws IOException {
visibleSignatureProperties.page(pageNum);
visibleSignatureProperties.setPdVisibleSignature(visibleSignDesigner);
visibleSignatureProperties.buildSignature();
}

private void checkDocumentPermissions(PDDocument document) {
// If permissions 1, then no changes are permitted
int accessPermissions = SigUtils.getMDPPermission(document);
if (accessPermissions == 1) {
throw new IllegalStateException("No changes to the document are permitted due to DocMDP transform parameters dictionary");
}
}

private boolean isDocumentCertified(PDDocument document) {
COSDictionary permsDict = document.getDocumentCatalog().getCOSObject()
.getCOSDictionary(COSName.PERMS);
return permsDict != null && permsDict.containsKey(COSName.DOCMDP);
}

public void setVisibleSignDesigner(PDDocument document, PDImageXObject pdImage, int page) throws IOException {

visibleSignDesigner = new PDVisibleSignDesigner(document, pdImage.getImage(), page);

// Calculate aspect ratio
float originalWidth = pdImage.getWidth();
float originalHeight = pdImage.getHeight();
float aspectRatio = originalWidth / originalHeight;

// Set desired height and calculate corresponding width to maintain aspect ratio
float desiredWidth = SIGNATURE_HEIGHT * aspectRatio;

// Set the size and position of the signature image
visibleSignDesigner.xAxis(0).yAxis(0).width(desiredWidth).height(SIGNATURE_HEIGHT).adjustForRotation();
}

public void setVisibleSignatureProperties(String name, String location, String reason, int preferredSize, boolean visualSignEnabled) {
visibleSignatureProperties.signerName(name).signerLocation(location).signatureReason(reason).
preferredSize(preferredSize).visualSignEnabled(visualSignEnabled).
setPdVisibleSignature(visibleSignDesigner);
}

private PDSignature findExistingSignature(PDDocument doc, PDSignatureField signatureField) {
PDAcroForm acroForm = doc.getDocumentCatalog().getAcroForm();
if (acroForm == null) {
throw new IllegalStateException("Document does not contain an AcroForm");
}
PDSignature signature = signatureField.getSignature();
if (signature == null) {
signature = new PDSignature();
signatureField.getCOSObject().setItem(COSName.V, signature);
}
return signature;
}

private KeyStore loadKeyStore() throws KeyStoreException, CertificateException, IOException, NoSuchAlgorithmException {
KeyStore ks = KeyStore.getInstance("PKCS12");
try (InputStream is = CreateVisibleSignature.class.getResourceAsStream(keystorePath)) {
ks.load(is, pin.toCharArray());
}
return ks;
}
}
С одной подписью все работает как положено. Но когда я добавляю вторую подпись, первая становится недействительной. Ниже я называю SignPDF

Код: Выделить всё

 private byte[] applyAllSignatures(byte[] pdfBytes, List allSignatures) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();

for (int i = 0; i < allSignatures.size(); i++) {
try (PDDocument pdf = Loader.loadPDF(pdfBytes)) {
SignatureInfo signatureInfo = allSignatures.get(i);
boolean isFirstSignature = (i == 0);
boolean isLastSignature = (i == allSignatures.size() - 1);

PDSignatureField signatureField = findSignatureField(pdf, signatureInfo.fieldName());

if (signatureField != null) {
createVisibleSignature.signPDF(
pdf,
buildSignatureImage(signatureInfo.sigFile(), pdf),
baos,
signatureField,
getPageNumber(pdf, signatureField),
isFirstSignature,
isLastSignature
);
pdfBytes = baos.toByteArray();
baos.reset();
}
}
}
return pdfBytes;
}
А ниже показано, как выглядят мои подписи после добавления второй.
Изображение

Вторая подпись выглядит нормально, но "Поля формы с изменениями свойств" удивляют, как и моя сертификат уже недействителен. Конечно, любой вклад будет принят с благодарностью.
Что интересно, если я вернусь к версии PDFBox 2.0.32 без каких-либо других изменений, обе подписи будут выглядеть именно так, как я ожидал. ; однако они невидимы.
Изображение


Подробнее здесь: https://stackoverflow.com/questions/788 ... fbox-3-0-2
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «JAVA»