0

I am using itext7 java library as shown below to add PdfButtonFormField to an existing pdf :

String src = "sample.pdf";
String dest = "acro_sample_empty_fields.pdf";


PdfDocument pdf = new PdfDocument(new PdfReader(src), new     PdfWriter(dest));
PdfAcroForm form = PdfAcroForm.getAcroForm(pdf, true);
PdfButtonFormField button = PdfFormField.createPushButton(pdf, new Rectangle(Integer.parseInt(control.xCord), Integer.parseInt(control.yCord),Integer.parseInt(control.width), Integer.parseInt(control.height)), control.name, control.value);

form.addField(button, page);

String resource = "sample.png";
button.setImage(resource);

After this i use the following code to fill the form like below :

String src = "1540982441_313554925_acro_sample_empty_fields_signedFinal.pdf";
String dest = "acro_sample_filled_fields.pdf";

PdfReader reader = new PdfReader(src);
File output = new File(dest);

OutputStream outputStream = new FileOutputStream(output);
PdfDocument document = new PdfDocument(reader,
                    new PdfWriter(outputStream),
                    new StampingProperties().useAppendMode());
PdfAcroForm form = PdfAcroForm.getAcroForm(document, true);
Map<String, PdfFormField> fields = form.getFormFields();

String resource = "sample_test.png";
((PdfButtonFormField)fields.get(control.name)).setImage(resource);

Everything works fine for a normal pdf. But if i digitally sign the created pdf and then try to fill it. then the image is not set properly. For a normal pdf the image on the push button is changed as expected. But on the digitally signed pdf the image is not set.

I have tried looking for this on google but no luck yet. Any help will be appreciated. Thanks in advance.

  • 1
    Thanks for the edit @Daniel – Gautam Anand Oct 31 '18 at 12:32
  • *"But if i digitally sign the created pdf and then try to fill it. then the image is not set properly."* - Please share a sample PDF before and after signing. I would expect the signature to be broken by your code but the button image to be set. – mkl Oct 31 '18 at 18:46
  • Related but using iText 5: [this answer](https://stackoverflow.com/a/52424206/1729265) – mkl Oct 31 '18 at 18:47
  • Thanks for the answer @mkl. I also expected the same as you mentioned that the signature to be broken but the image be set. I will look into the answer you have sited for itext5 and see if it helps me. Otherwise i will share all thee pdfs. 1> just after adding acro fields, 2> after signing it. 3> after changing the signed pdf. – Gautam Anand Nov 01 '18 at 06:27
  • @mkl i tried to port the code you mentioned for itext5 but i was not able to do it successfully. The link for the 3 pdfs are [link]https://jmp.sh/JesPwyE – Gautam Anand Nov 01 '18 at 07:32
  • @mkl thanks for the help, i ported all my code to itext5 and the was able to implement your code. All the help is very much appreciated – Gautam Anand Nov 01 '18 at 11:04
  • I'll have a look, most likely tomorrow, today we have a holiday and I only have my smart phone at hands. – mkl Nov 01 '18 at 13:32
  • This is really interesting. If you look at the file (signed, image changed) in Adobe Acrobat, you indeed get to see the original image. But if you look at the file in Chrome or Foxit, you get to see the new image. This appears to be an Adobe special feature... – mkl Nov 05 '18 at 16:17
  • *"you indeed get to see the original image"*, at least that happened with my test files. Using your signed test file as base I got a blank button... weird... – mkl Nov 05 '18 at 17:20

1 Answers1

1

I tested the code in this answer with the signed but unfilled PDF you shared. As you didn't share a sample image, though, I used one of my own.

A more precise observation

You say

Everything works fine for a normal pdf. But if i digitally sign the created pdf and then try to fill it. then the image is not set properly. For a normal pdf the image on the push button is changed as expected. But on the digitally signed pdf the image is not set.

This is not entirely true, the image is set but not all PDF viewers show it.

In detail: If you set the image in the signed PDF using your code, Adobe Reader indeed shows merely a grey box

Adobe Reader Screen shot

but other PDF viewers, e.g. Foxit or Chrome's built-in viewer, do show the replacement image

Foxit screen shot

Thus, the image is set for the digitally signed PDF, too. The actual problem is that Adobe Reader does not display it!

The cause

After some analysis and having followed some red herrings, the cause of the problem appears to be that if Adobe Reader displays a PDF with a changed AcroForm button appearance and

  • the PDF is not signed, then Adobe Reader simply uses the updated appearance stream; but if
  • the PDF is signed, then Adobe Reader tries to ignore the updated appearance stream and construct a new appearance from appearance characteristics information.

(Other PDF viewers, though, appear to always use the updated appearance stream.)

iText does create an appearance characteristics dictionary for the button (so Adobe Reader assumes it can ignore the updated appearance and can construct an new one based on this dictionary) but unfortunately does not add some button specific information to it, neither when constructing the button nor when changing the button. This in particular concerns the following two entries:

I stream (Optional; push-button fields only; shall be an indirect reference) A form XObject defining the widget annotation’s normal icon, which shall be displayed when it is not interacting with the user.

TP integer (Optional; push-button fields only) A code indicating where to position the text of the widget annotation’s caption relative to its icon:

0 No icon; caption only

1 No caption; icon only

2 Caption below the icon

3 Caption above the icon

4 Caption to the right of the icon

5 Caption to the left of the icon

6 Caption overlaid directly on the icon

Default value: 0.

(ISO 32000-2, Table 192 — Entries in an appearance characteristics dictionary)

As iText does not supply the TP value, the Default value kicks in and Adobe Reader creates a button appearance with "No icon; caption only". As no caption is defined, the result is a grey box.

A work-around

The most simple work-around is to remove the whole appearance characteristics dictionary during image update, i.e. replace

((PdfButtonFormField)fields.get(control.name)).setImage(resource);

by

PdfButtonFormField button = (PdfButtonFormField)fields.get(control.name);
button.setImage(resource);
if (button.getPdfObject().containsKey(PdfName.MK)) {
    button.setModified();
    button.getPdfObject().remove(PdfName.MK);
}

(SetButtonImage helper method setLikeGautamAnandImproved)

Now Adobe Reader does not find any appearance characteristics and, therefore, cannot ignore the updated appearance stream.

A fix

Alternatively we can add the missing appearance characteristics entries, e.g. like this:

PdfButtonFormField button = (PdfButtonFormField)fields.get(control.name);
button.setImage(resource);
PdfWidgetAnnotation widget = button.getWidgets().get(0);
PdfDictionary characteristics = widget.getAppearanceCharacteristics();
if (characteristics != null) {
    characteristics.setModified();
    characteristics.put(PdfName.I, widget.getNormalAppearanceObject());
    characteristics.put(PdfName.TP, new PdfNumber(1));
}

(SetButtonImage helper method setLikeGautamAnandImproved2)

The result looks slightly different, though:

Adobe Reader Screen shot

As you see, there is a small frame around the image. Most likely you can make it vanish by setting other characteristics accordingly.

mkl
  • 90,588
  • 15
  • 125
  • 265