Archive for December 28th, 2007

Acrobat Reader Extensions

Friday, December 28th, 2007

The following is an explanation of how to programmatically enable Acrobat Reader Extensions from ColdFusion.

‘Reader Extensions’ is a great enabler for pdf technologies. It allows form filling and annotation on a pdf document for users who only have the free Acrobat Reader. It is useful for general Internet applications, where Acrobat Reader is the norm. We will soon be using it on the Land Rover G4 Challenge, where we need an application form that is the same on the web and when printed.

Another useful scenario is when engaging with large corporates, where Acrobat reader is likely to be part of their standard PC build, and where the time and business cost of getting Acrobat Professional installed for a small number of users in the organisation, can be prohibitive. This is a common scenario with some of our larger clients. Reader Extensions allows us to use Acrobat annotations when approving artwork, catalogs, DM packs etc, without all our users having to install full Acrobat.

Acrobat Professional 8 allows you to enable reader extensions on a PDF for free. There are some limitations which are in the Acrobat EULA and discussed here. If you envisage usage beyond the EULA, have a large number of documents, or need to enable the extensions programmatically then you will need the Reader Extensions service in Adobe LiveCycle.

To anyone unfamiliar with LiveCycle, think of it as a suite of pdf related tools, linked together within a workflow management system, that allows non programmers to define complex workflow interactions. Its a powerful system, designed (and priced) for use by large corporates. Its sold as a modular system, so you can buy just the Reader Extensions part.

There is an article by Allen Levine on the Adobe site on how to enable reader extensions using ColdFusion. Adobe has since released LiveCycle ES, which has improved the integration of the LiveCycle components and provided a web service that can be called without the need for any additional installs or changes to the standard installation. Additionally ColdFusion 8 has made it easier to call and debug web services.

The LiveCycle web service can accept Dime, Mime or Base64 encoded files. The example below uses Base64.

<CFSCRIPT>   

// Define username/password.
// Change to match your installation
creds = structnew();
  creds ['username']='administrator';
  creds ['password']='password';   

// Create web service
wsdl = "http://127.0.0.1/readerExtensions.wsdl";
readerExtensions = createObject("webservice", wsdl, creds);   

// Encode pdf
pdfBase64 = tobinary(ToBase64(ipFile.toByteArray(),
  "iso-8859-1"));   

// Create the structs needed for the web serivce
inPDFDoc = structNew();
  inPDFDoc['contentType'] = "application/pdf";
  inPDFDoc['attachmentID'] = javacast('null','');
  inPDFDoc['remoteURL'] = javacast('null','');
  inPDFDoc['binaryData'] = pdfBase64;   

usageRights = structNew();
  usageRights['enabledComments'] = TRUE|FALSE;
  usageRights['enabledCommentsOnline'] = TRUE|FALSE;
  etc   

applyOptions = structNew();
  applyOptions['message'] = "";
  applyOptions['modeFinal'] = TRUE;
  applyOptions['usageRights'] = usageRights;   

applyUsageRightsRequest = structNew();
  applyUsageRightsRequest['inPDFDoc'] = inPDFDoc;
  applyUsageRightsRequest['credentialAlias'] = credAlias;
  applyUsageRightsRequest['credentialPassword'] = credPassword;
  applyUsageRightsRequest['applyOptions'] = applyOptions;   

// Call web service
applyUsageRightsResponse = readerExtensions.applyUsageRights
  (inPDFDoc,credentialAlias,credentialPassword, applyOptions);   

// decode blessed pdf
pdfBinary = ToBinary(applyUsageRightsResponse.binaryData);   

</CFSCRIPT>

When you install LiveCycle Reader Extensions you will get a certificate from Adobe. You define the credentialAlias and credentialPassword values when installing the certificate.

The only tricky part is providing structures of the correct format to the web service. There are a couple of useful flags to help track down any ambiguities or problems with the wsdl:

creds ['saveJava']=TRUE;
creds ['refreshWSDL']=TRUE;

Add these to the creds struct in the example above, These ensure you have the latest wsdl and also instructs ColdFusion to save the intermediate java files that it creates. These will contain the class definitions which map to the above ColdFusion structures.