I have some questions wrt pdfbox.
Any helpful tips or code references in the public domain would be very helpful. Thanks.
....
contentStream = new PDPageContentStream(doc, page, PDPageContentStream.AppendMode.APPEND, true);
PDImageXObject pdImage = PDImageXObject.createFromFile("C:/logo.png", doc);
....
page.getResources().getCOSObject().getCOSDictionary(COSName.XOBJECT).setNeedToBeUpdated(true);
page.getCOSObject().setNeedToBeUpdated(true);
page.getResources().getCOSObject().setNeedToBeUpdated(true);
doc.getDocumentCatalog().getPages().getCOSObject().setNeedToBeUpdated(true);
doc.getDocumentCatalog().getCOSObject().setNeedToBeUpdated(true);
doc.saveIncremental(fos);
Only a small set of changes is allowed to signed documents, see here for some details. So indeed, you cannot change page contents after signing, and whether or not you can fill form fields or even use arbitrary annotations depends on the signature type of the original signature.
If the signature(s) do allow adding annotations, though, i.e. if there only are approval (non-certification) signatures or at most a certification signature with annotations, form fill-in, and digital signatures allowed, you can add images in annotations.
With PDFBox you can add an annotation showing an image in an incremental update like this:
PDDocument document = ...;
PDImageXObject image = ...;
OutputStream result = ...;
PDAppearanceStream appearanceStream = new PDAppearanceStream(document);
appearanceStream.setBBox(new PDRectangle(1, 1));
appearanceStream.setResources(new PDResources());
try ( PDPageContentStream contentStream = new PDPageContentStream(document, appearanceStream) ) {
contentStream.drawImage(image, new Matrix());
}
PDAppearanceDictionary appearance = new PDAppearanceDictionary();
appearance.setNormalAppearance(appearanceStream);
PDAnnotationRubberStamp stamp = new PDAnnotationRubberStamp();
stamp.setLocked(true);
stamp.setLockedContents(true);
stamp.setPrinted(true);
stamp.setReadOnly(true);
stamp.setAppearance(appearance);
stamp.setIntent("StampImage");
stamp.setRectangle(new PDRectangle(200, 500, 100, 100));
PDPage page = document.getPage(0);
page.getAnnotations().add(stamp);
Set<COSDictionary> objectsToWrite = new HashSet<>();
objectsToWrite.add(page.getCOSObject());
document.saveIncremental(result, objectsToWrite);
(AddToSignedFile test testAddImageAnnotation
)
I here used a feature available in the development head towards 3.0.0, the saveIncremental
overload with a second argument that accepts a collection of dictionaries to save. If you are working with an earlier version, you may instead have to mark a path of objects from the document catalog to the page object for inclusion in the incremental update using setNeedToBeUpdated
.
If the signature(s) don't allow adding annotations, though, but do allow form editing, i.e. if there is a certification signature with form fill-in and digital signatures allowed, you can at least fill in form fields. This in particular may include setting the appearance of a pushbutton to an image of your choice as Adobe regularly mis-uses pushbuttons as pseudo image-fields. This of course means that you need to have a field prepared for each desired later addition.
If the signatures don't even allow that, i.e. if there is a certification signature with no changes allowed, or if there are no open form fields available for your additions, you're out of luck.
As an aside, since PDF 2.0 the certification level can also be made stricter by an entry in the signature locking dictionary of an approval signature. You may have to consider this in the cases above...