below the code using one text field, two list boxes and one signature field. selecting an entry of listbox domicilation updates the entries of listbox legalForm. The newDateField currently servers as debug field, it contains the last listbox value that was updated. I would like to know why the result cannot be signed. It must be related to the javascript of the list boxes... Kindly help
import org.apache.pdfbox.cos.COSName;
import org.apache.pdfbox.pdmodel.*;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.apache.pdfbox.pdmodel.font.PDFont;
import org.apache.pdfbox.pdmodel.font.PDType1Font;
import org.apache.pdfbox.pdmodel.interactive.action.PDActionJavaScript;
import org.apache.pdfbox.pdmodel.interactive.action.PDAnnotationAdditionalActions;
import org.apache.pdfbox.pdmodel.interactive.action.PDFormFieldAdditionalActions;
import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotationWidget;
import org.apache.pdfbox.pdmodel.interactive.annotation.PDAppearanceDictionary;
import org.apache.pdfbox.pdmodel.interactive.annotation.PDAppearanceStream;
import org.apache.pdfbox.pdmodel.interactive.form.*;
import java.awt.*;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
public class AnaCreditForm {
public static void main(String[] args) {
System.out.println("Creating pdf docoument including signature field");
try {
// Create a new document with an empty page.
PDDocument document = new PDDocument();
PDPage page = new PDPage(PDRectangle.A4);
document.addPage(page);
String javaScript = "var now = util.printd('yyyy-mm-dd', new Date());"
+ "var ndf = this.getField('newDateField');"
+ "ndf.value = now;"
// + "this.getField('signatureField').display=display.hidden;"
// + "var formReady = false;"
+ "var anacredit = { '-': [['-', '-']], "
+ " 'Luxembourg': [[ '-', '-'], ['LU01 Entreprise individuelle', 'LU01'],[ 'LU06 Société anonyme', 'LU06'] ,['LU14 Société civile','LU14']] , "
+ " 'Germany': [[ '-', '-'], ['DE201 Aktiengesellschaft', 'DE201'], ['DE602 Eingetragener Verein', 'DE602'], ['DE205 Investmentaktiengesellschaft', 'DE205']], "
+ " 'Greece': [[ '-', '-'], ['GR906 Εταιρία Περιορισμένης Ευθύνης/Etería Periorisménis Euthínis', 'GR906'], ['GR912 Κοινοπραξία/Kinopraxia', 'GR912'], ['GR999 Λοιπά/Lipa', 'GR999']] };";
// Create an action as JavaScript action
PDActionJavaScript jsAction = new PDActionJavaScript();
jsAction.setAction(javaScript);
// Set the action to be executed when the document is opened
document.getDocumentCatalog().setOpenAction(jsAction);
// Adobe Acrobat uses Helvetica as a default font and
// stores that under the name '/Helv' in the resources dictionary
PDFont font = PDType1Font.HELVETICA;
PDResources resources = new PDResources();
resources.put(COSName.getPDFName("Helv"), font);
PDDocumentCatalog pdCatalog = document.getDocumentCatalog();
PDAcroForm pdAcroForm = new PDAcroForm(document);
pdCatalog.setAcroForm(pdAcroForm);
pdAcroForm.setDefaultResources(resources);
String defaultAppearanceString = "/Helv 0 Tf 0 g";
pdAcroForm.setDefaultAppearance(defaultAppearanceString);
PDTextField newDateField = new PDTextField(pdAcroForm);
newDateField.setPartialName("newDateField");
defaultAppearanceString = "/Helv 12 Tf 0 g";
newDateField.setDefaultAppearance(defaultAppearanceString);
pdAcroForm.getFields().add(newDateField);
PDAnnotationWidget widget = newDateField.getWidgets().get(0);
PDRectangle rect = new PDRectangle(50, 450, 500, 15);
widget.setRectangle(rect);
widget.setPage(page);
// make sure the annotation is visible on screen and paper
widget.setPrinted(true);
// Add the annotation to the page
page.getAnnotations().add(widget);
//newDateField.setValue("value in newly created text field");
//textBox.setActions(fieldActions);
PDListBox domicilation = new PDListBox(pdAcroForm);
domicilation.setPartialName("domicilation");
List<String> displayList = Arrays.asList("-", "Germany", "Luxembourg", "Greece");
List<String> exportList = Arrays.asList("-", "Germany", "Luxembourg", "Greece");
domicilation.setOptions(exportList, displayList);
defaultAppearanceString = "/Helv 12 Tf 0 g";
domicilation.setDefaultAppearance(defaultAppearanceString);
pdAcroForm.getFields().add(domicilation);
String jsListBox0 =
"var f = this.getField('domicilation');"
+ "var r = this.getField('legalForm');"
+ " console.println('domicilation ' + f.value + 'legalForm' + r.value);"
+ "f.setAction('Keystroke', 'fft();');"
+ "function fft() { if (event.willCommit)"
+ "{ console.println('domiciliation' + event.change + ' ' + event.value); "
+ "r.setItems( anacredit[event.value] );"
+ "f.value=event.value) ; ndf.value= event.value;"
+ " }}";
// + "r.value='-'; formReady=false; }}";
PDFormFieldAdditionalActions fieldActions = new PDFormFieldAdditionalActions();
PDActionJavaScript jsKeystrokeAction = new PDActionJavaScript();
//jsKeystrokeAction.setAction("app.alert(\"On 'keystroke' action\")");
jsKeystrokeAction.setAction(jsListBox0);
fieldActions.setK(jsKeystrokeAction);
domicilation.setActions(fieldActions);
PDAnnotationWidget widget2 = domicilation.getWidgets().get(0);
PDRectangle rect2 = new PDRectangle(50, 380, 500, 50);
widget2.setRectangle(rect2);
widget2.setPage(page);
// make sure the annotation is visible on screen and paper
widget2.setPrinted(true);
//PDAnnotationAdditionalActions annotationActions = new PDAnnotationAdditionalActions();
// Add the annotation to the page
page.getAnnotations().add(widget2);
domicilation.setValue("-");
PDListBox legalForm = new PDListBox(pdAcroForm);
legalForm.setPartialName("legalForm");
List<String> displayList2 = Arrays.asList("-");
List<String> exportList2 = Arrays.asList(" ");
legalForm.setOptions(exportList2, displayList2);
defaultAppearanceString = "/Helv 12 Tf 0 g";
legalForm.setDefaultAppearance(defaultAppearanceString);
pdAcroForm.getFields().add(legalForm);
PDAnnotationWidget widget3 = legalForm.getWidgets().get(0);
PDRectangle rect3 = new PDRectangle(50, 310, 500, 50);
widget3.setRectangle(rect3);
widget3.setPage(page);
// make sure the annotation is visible on screen and paper
widget3.setPrinted(true);
String jsListBox2 = "var lb = this.getField('legalForm'); "
+ "console.println('in legalForm action ' + lb.value);"
+ "lb.setAction('Keystroke', 'fft2();');"
+ "function fft2() { if (event.willCommit)"
+ "{ console.println('in legalForm action ' + event.change + ' ' + event.value);"
+ "lb.value=event.value; ndf.value= event.value;}}";
// + "console.println(formReady);"
// + "lb.setAction('Keystroke', 'flb();');"
// + "function flb() { if (event.willCommit)"
// + "{ console.println('in listbox action'); console.println(event.value); "
// + "if (lb.value == '-') formReady= false; else formReady=true; "
// + "if (formReady) this.getField('signatureField').display=display.visible; "
// + "else this.getField('signatureField').display=display.hidden; }}" +
// + " lb.value=event.value; ndf.value=event.value; }}" ;
// "f2.setAction('Keystroke', 'fft2();');function fft2() { if (!event.willCommit) { console.println(event.change); r2.value = event.change; }}";
PDFormFieldAdditionalActions fieldActions2 = new PDFormFieldAdditionalActions(); // usable only for .setK, not for .setU
//PDAnnotationAdditionalActions annotationActions = new PDAnnotationAdditionalActions();
PDActionJavaScript jsKeyStrokeAction = new PDActionJavaScript();
//jsKeystrokeAction.setAction("app.alert(\"On 'keystroke' action\")");
jsKeyStrokeAction.setAction(jsListBox2);
fieldActions2.setK(jsKeyStrokeAction);
legalForm.setActions(fieldActions2);
//widget3.setActions(annotationActions);*/
//PDAnnotationAdditionalActions annotationActions = new PDAnnotationAdditionalActions();
PDFormFieldAdditionalActions listboxAction2 = new PDFormFieldAdditionalActions();
// Add the annotation to the page
page.getAnnotations().add(widget3);
legalForm.setValue("-");
PDRectangle rect4 = new PDRectangle(50, 150, 200, 50);
PDAppearanceDictionary appearanceDictionary = new PDAppearanceDictionary();
PDAppearanceStream appearanceStream = new PDAppearanceStream(document);
appearanceStream.setBBox(rect4.createRetranslatedRectangle());
appearanceStream.setResources(resources);
appearanceDictionary.setNormalAppearance(appearanceStream);
PDPageContentStream contentStream = new PDPageContentStream(document, appearanceStream);
contentStream.setStrokingColor(Color.BLACK);
contentStream.setNonStrokingColor(Color.LIGHT_GRAY);
contentStream.setLineWidth(2);
contentStream.addRect(0, 0, rect4.getWidth(), rect4.getHeight());
contentStream.fill();
contentStream.moveTo(1 * rect4.getHeight() / 4, 1 * rect4.getHeight() / 4);
contentStream.lineTo(2 * rect4.getHeight() / 4, 3 * rect4.getHeight() / 4);
contentStream.moveTo(1 * rect4.getHeight() / 4, 3 * rect4.getHeight() / 4);
contentStream.lineTo(2 * rect4.getHeight() / 4, 1 * rect4.getHeight() / 4);
contentStream.moveTo(3 * rect4.getHeight() / 4, 1 * rect4.getHeight() / 4);
contentStream.lineTo(rect4.getWidth() - rect4.getHeight() / 4, 1 * rect4.getHeight() / 4);
contentStream.stroke();
contentStream.setNonStrokingColor(Color.DARK_GRAY);
contentStream.beginText();
contentStream.setFont(font, rect4.getHeight() / 5);
contentStream.newLineAtOffset(3 * rect4.getHeight() / 4, -font.getBoundingBox().getLowerLeftY() * rect4.getHeight() / 5000);
contentStream.showText("Customer");
contentStream.endText();
contentStream.close();
PDSignatureField signatureField = new PDSignatureField(pdAcroForm);
signatureField.setPartialName("signatureField");
PDAnnotationWidget widget4 = signatureField.getWidgets().get(0);
widget4.setAppearance(appearanceDictionary);
widget4.setRectangle(rect4);
widget4.setPage(page);
page.getAnnotations().add(widget4);
pdAcroForm.getFields().add(signatureField);
document.save("anacreditForm.pdf");
for (PDField pdField : pdAcroForm.getFields()) {
System.out.println(pdField.getFullyQualifiedName() + " " + pdField.getFieldType() + " " + pdField.getValueAsString());
}
document.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Adobe Reader apparently does reject signing attempts for documents in which by means of JavaScript an event handler has been changed.
Your code actually is an example why that is good: As soon as the original domicilation
event handler is executed, it is set to 'fft();'
but the code of fft()
is only in the Adobe Reader's memory, not in the PDF anymore. Thus, a thereafter signed version of the PDF would behave differently as it would be missing that code.
As an aside, there is one unwanted closing round bracket in
+ "f.value=event.value) ; ndf.value= event.value;"
in jsListBox0
.