PDFBox 1.8.10: Fill out and sign the document, fill out the filling again

In the previous SO question of PDFBox 1.8.10: Fill and Sign PDF creates invalid signatures. I explained how I could not fill out and subsequently sign the PDF using PDFBox 1.8.10. After it turned out with some help, I now continue to work on the same topic. Starting with doc_v2.pdf (links to the file below!), I fill out and sign it, resulting in doc_v2_fillsigned.pdf (do it at a time, saving it step by step). Again I open the edited document (using the PDFBox again) and try to fill in another field.

Then saving the document leads to the following stack trace:

Exception in thread "main" java.lang.NullPointerException at org.apache.pdfbox.pdmodel.interactive.form.PDAppearance.calculateFontSize(PDAppearance.java:930) at org.apache.pdfbox.pdmodel.interactive.form.PDAppearance.setAppearanceValue(PDAppearance.java:359) at org.apache.pdfbox.pdmodel.interactive.form.PDVariableText.setValue(PDVariableText.java:131) at com.c10n.scalibur.ehealthdemo.examples.PdfEditor.fill(PdfEditor.java:100) at com.c10n.scalibur.ehealthdemo.examples.SignPdf_ProfileLayer.start(SignPdf_ProfileLayer.java:66) at com.c10n.scalibur.ehealthdemo.examples.SignPdf_ProfileLayer.main(SignPdf_ProfileLayer.java:28) 

What am I doing in a bad fill:

  File curentDocument new File("doc_v2_fillsigned.pdf); File newDocument = new File("doc_v2_fillsigned_filled.pdf); String fieldName ="New Emergency Contact"; String value="test"; PDDocument doc = null; try(FileOutputStream fos = new FileOutputStream(newDocument)){ try(FileInputStream fis = new FileInputStream(currentDocument);){ int c; while ((c = fis.read(buffer)) != -1) { fos.write(buffer, 0, c); } } doc = PDDocument.load(currentDocument); PDDocumentCatalog catalog = doc.getDocumentCatalog(); catalog.getCOSObject().setNeedToBeUpdate(true); catalog.getPages().getCOSObject().setNeedToBeUpdate(true); PDAcroForm form = catalog.getAcroForm(); form.getCOSObject().setNeedToBeUpdate(true); form.getDefaultResources().getCOSObject().setNeedToBeUpdate(true); PDField field = form.getField(fieldName); field.setValue(value); // here the exception occurs. // What should happen afterwards: field.getCOSObject().setNeedToBeUpdate(true); field.getAcroForm().getCOSObject().setNeedToBeUpdate(true); ((COSDictionary) field.getDictionary().getDictionaryObject("AP")).getDictionaryObject("N").setNeedToBeUpdate(true); try(FileInputStream fis = new FileInputStream(newDocument)){ doc.saveIncremental(fis, fos); } }finally{ if(null != doc){ doc.close(); doc=null; } } 

Files:

empty document: https://www.dropbox.com/s/xf5pb0ng8k9zd4i/doc_v2.pdf?dl=0

completed and signed copy: https://www.dropbox.com/s/s8295tfyjpe1l4l/doc_v2_fillsigned.pdf?dl=0

Again, any help to resolve this is appreciated!

Update:

mkl asked in the code comments to create a fillsigned pdf. So far, I have learned that only signatures are enough to reset the fill code above after that. So, here are some exceptions to my code for signing:

 @Override public byte[] sign(InputStream data) throws SignatureException, IOException { CMSTypedDataInputStream input = new CMSTypedDataInputStream(data); try { CertificateFactory certFactory = CertificateFactory.getInstance("X.509"); InputStream in = new ByteArrayInputStream(certData); X509Certificate signCert = (X509Certificate)certFactory.generateCertificate(in); ContentSigner signer = new MyContentSigner(profile); SignerInfoGenerator i = new JcaSignerInfoGeneratorBuilder( new JcaDigestCalculatorProviderBuilder().setProvider("BC").build()) .build(signer,signCert); Store<?> certStore = new JcaCertStore(Collections.singletonList(signCert)); CMSSignedDataGenerator cmsGen = new CMSSignedDataGenerator(); cmsGen.addCertificates(certStore); cmsGen.addSignerInfoGenerator(i); CMSSignedData signedData = cmsGen.generate(input); byte[] result =signedData.getEncoded(); return result; } catch (Exception e) { e.printStackTrace(); throw new SignatureException(e); } } 

this creates a signature using BouncyCastle 1.52, the code is called from

 public void sign(SignatureInterface signer, String signatureFieldName, int pageNumber, String location, String reason, boolean lock) throws IOException, SignatureException{ PDSignature signature = new PDSignature(); signature.setFilter(PDSignature.FILTER_ADOBE_PPKLITE); // default filter signature.setSubFilter(PDSignature.SUBFILTER_ADBE_PKCS7_DETACHED); // for visible sigs! signature.setLocation(location); signature.setReason(reason); signature.setSignDate(Calendar.getInstance()); SignatureOptions options = makeSignatureVisible(signature,signatureFieldName, pageNumber, lock ); doc.addSignature(signature, signer, options); } 

which uses the following method to create a visible signature in some signature field, adding an image there and placing it correctly:

 SignatureOptions makeSignatureVisible( PDSignature signature, String fieldName, int pageNumber, boolean lock) throws IOException{ PDDocumentCatalog catalog = doc.getDocumentCatalog(); catalog.getCOSObject().setNeedToBeUpdate(true); catalog.getPages().getCOSObject().setNeedToBeUpdate(true); PDAcroForm form = catalog.getAcroForm(); form.getCOSObject().setNeedToBeUpdate(true); form.getDefaultResources().getCOSObject().setNeedToBeUpdate(true); PDSignatureField field = (PDSignatureField) form.getField(fieldName); field.setSignature(signature); field.setReadonly(lock); FileInputStream image = new FileInputStream("MUniverse_Signature.jpg"); PDVisibleSignDesigner visibleSig = new PDVisibleSignDesigner(newDocument.getName(), image, 1); PDRectangle area = getFieldArea(field); float max_width = area.getWidth(); float max_height = area.getHeight(); float scale = 1; if(max_height < visibleSig.getHeight()){ scale = max_height / visibleSig.getHeight(); System.out.println("scale: "+scale); } if(max_width < scale*visibleSig.getWidth()){ scale = max_width / visibleSig.getWidth(); System.out.println("scale: "+scale); } float zoom = ((scale-1)*100); visibleSig.zoom(zoom); PDPage page = (PDPage) doc.getDocumentCatalog().getAllPages().get(pageNumber); visibleSig.coordinates(area.getLowerLeftX(),page.getMediaBox().getHeight()-area.getUpperRightY()); visibleSig.signatureFieldName(fieldName); PDVisibleSigProperties signatureProperties = new PDVisibleSigProperties(); signatureProperties.signerName("name").signerLocation("location").signatureReason("Security") .visualSignEnabled(true).setPdVisibleSignature(visibleSig).buildSignature(); SignatureOptions options = new SignatureOptions(); options.setVisualSignature(signatureProperties); return options; } 

I suspect that this snippet is optional, and applying the signature examples that come with the PDFBox results in the same conflict when you try to fill out a PDF and save it.

Yours faithfully,

Daniel

+1
source share
1 answer

The cause of the problem is that somehow, during the initial filling and signing of fonts in the default resources of the interactive form, the dictionary was lost.

When filling out a form, the PDFBox tries to access the font definition to create an appearance stream. He does not find it and therefore ultimately fails.

More details

In the original document doc_v2.pdf an interactive form dictionary looks like this:

Acroform Dictionary in doc_v2.pdf

You can clearly see ZaDb and Helv entries in the Font dictionary in the default resources of the DR dictionary.

Unlike the dictionary of the interactive form of the completed and signed document, doc_v2_fillsigned.pdf looks like this:

Acroform Dictionary in doc_v2_fillsigned.pdf

As you can see, the Font dictionary in the default DR resources is missing.

Cause

Observed OP:

I played a little more, and it is enough to sign it. After that, filling is not performed. I assume that creating my signature is more or less the same as in the PDFBox example, which describes how to advertise a visible signature.

Based on this, I just applied the PDFBox CreateVisibleSignature example to the original doc_v2.pdf OP file. Indeed, this has already removed the default Font dictionary.

Thus, it finally looks like a PDFBox error.

PS: On Apache Jira ...

Looking back at Jira's PDFBox , you can actually already find problems in this regard:

So this is a known issue. I'm not sure that when developing priorities in the development of PDFBox, votes about problems are taken into account, but if you are interested in solving this problem, voting will not hurt ...;)

+2
source

Source: https://habr.com/ru/post/1232699/


All Articles