Using Acrobat JavaScript

It's not just for calculating totals.

The "Forms" feature of PDF is one of the most popular additions to the basic specification, and is certainly one of the most used features of our PDF library. As with HTML forms, it's possible to validate and calculate fields with JavaScript: Acrobat contains a JavaScript interpreter that's identical to the parser in a typical web browser, although the Document Object Model (or DOM) is diffferent:

// Browser
window.alert("Hello, World");

// Acrobat
app.alert("Hello, World");

A fairly common use of JavaScript in both Acrobat and HTML is to calculate a field based on the value of other fields - to provide a total, for example. This is done in Acrobat by setting the details in the "Calculate" tab of the form fields properties - a custom JavaScript can be run, or one of the predefined functions as we're doing here:

To get this working in our Java PDF Viewer, you'll need a JavaScript engine to be available to Java. One is supplied with Java 1.6 (OS X users will need to install at least the 1.6.0_13 release). Alternatively, customers still on Java 1.5 or earlier can install Mozilla Rhino. You can tell you have a JavaScript parser installed by checking the "About" dialog in the viewer. If you have a JavaScript engine installed, JavaScript in documents should just work. You can see what's going on under the hood by bringing up the JavaScript console (under the Windows menu in the PDF Viewer) - this is the console object in the Acrobat DOM, and it logs any exceptions and the output of console.println()

Going beyond Acrobat

JavaScript for Java can call methods directly on the Java API, which has the potential for all sorts of security problems. The BFO PDF Viewer locks down the JavaScript environment to the level of an untrusted applet, so privileged operations like file or network access are blocked. You can confirm this by typing java.lang.System.exit(0) into the JavaScript console - it will display a java.security.AccessControlException.

This power can also be used for good - if you know your PDF will always be displayed using the BFO PDF Viewer, you have the whole Java API available to turn your PDF into a much more interesting experience - and not just for the person that now has to debug them! As an example, the javax.swing.JOptionPane class can be used to open a dialog and prompt the user for further information.

For those wishing to access the network or filesystem this can be done in a Privileged Action. This is how we load and save PDFs from the PDFViewer applet, and for your custom actions it's possible to supply a signed Jar alongside the PDF Viewer Jar containing your privileged actions, which can be called by the JavaScript in your PDF.

The essential guide for working with Acrobat JavaScript is the Acrobat JavaScript Reference, which you can download from http://www.adobe.com/devnet/acrobat/javascript.html.

A Simple Worked Example

Here's a fully working example of some of the neat things you can do with JavaScript. We're going to load an save an FDF file to/from the server - new features added in version 2.11.18 of our PDF Library. You can download the full Zip file of the resources that go with this here. The first thing we need is a PDF, which we're going to create with the Report Generator. Here's the XML source:

<?xml version="1.0"?>
<pdf onload="javascript:myinit()">
 <head>
  <style>
body, input { font-family:Helvetica }
input { border:1pt solid gray; background-color:#EEE; }
input[type=text] { width:200pt }
input[type=button] { width:95pt }
th { padding-right:20pt; vertical-align:middle }
  </style>
  <script>
function myinit() {
    console.println("Document initialized");
}

function myload() {
    console.println("Load button pressed");
    this.importAnFDF("testjs.fdf");
    console.println("Import done");
}

function mysave() {
    console.println("Save button pressed");
    this.submitForm({
        cURL: "/path/to/server",
        sSubmitAs: "FDF",
        bAnnotations: true,
    });
}
  </script>
 </head>
 <body>
  <table>
   <tr>
    <th>Text field</th>
    <td colspan="2"><input type="text" name="text"/></td>
   </tr><tr>
    <th></th>
    <td><input type="button" name="load" value="Load" onclick="javascript:myload()"/></td>
    <td><input type="button" name="save" value="Save" onclick="javascript:mysave()"/></td>
   </tr>
  </table>
 </body>
</pdf>

There's not much to this: we're creating a simple PDF with one text field, two buttons which call the myload and mysave JavaScript methods, which we define in the <script> tag in the document head. You can download the Report Generator to convert this (the trial version is fine for these purposes), or the zip file contains the converted file.

Next we need a webserver. We're using Tomcat but this example doesn't have any server-side component so you can use anything you like. Unzip the test.zip example under your webserver's document folder, and point your browser to the index.html in that directory. This will load a page containing an applet which will load the PDF we've just described above.

Go to the Window menu and select Javascript Console - notice the text "Document Initialized", which we printed out from the myinit method on line 12 in the XML. Now click on the Load button in the PDF. This will call the myload method, which will import data from the testjs.fdf file. FDF here stands for "Forms Data Format", and it's one of several file formats that can be used to import/export data from a PDF. The FDF is included in the zip file above.

Finally, click on the Save button. This will run the mysave JavaScript method, which will submit the PDF form back to the webserver. Of course we don't have a server-side component for this example, so you'll get a 404 error here - we'll leave this part as an "exercise for the reader".

To see all this in action, click here to see this running off our server, or you can download the whole zip file to run locally.