Printing a PDF document from AIR without displaying it or the control bar (using PDF cross-scripting)

October 6th, 2009 by Adrian

Recently I had a project where I needed to allow the user to print out a PDF document from my AIR application, but I really didn’t need the user to actually view the document first and I didn’t want to display the default PDF control bar. I needed some way to send the PDF file to the printer directly from ActionScript. Enter PDF cross-scripting and Acrobat JavaScript. The following information should help you achieve the same result (note you need to have access to a copy of Adobe Acrobat Pro to add the JavaScript code to your PDF file).

There are several steps required for this to work …

  1. Open the PDF document you want to print in Adobe Acrobat Pro.
  2. Add the JavaScript code to your document and save it.
  3. Create an HTML page that contains a JavaScript function and embed the PDF document.
  4. In your Flash (or Flex) file add a button that prompts the user to print the document.
  5. Add the ActionScript 3.0 code that communicates with the HTML page you created in step 3.
  6. Publish your AIR file (making sure you include the HTML and PDF files).
  7. Test your AIR app.

Here is a copy of the PDF file I am printing in the following example.

Right, let’s explain each of the above steps in more detail.

Step 1

I presume you already have a PDF file prepared which you wish to print. Open this file up in Adobe Acrobat Pro. I’m pretty sure this works in version 7.0 and onwards.

Step 2

Open the ‘JavaScript Functions’ dialog box in Adobe Acrobat Pro by going to ‘Advanced’ > ‘Document Processing’ > ‘Document JavaScripts’.

Acrobat Document JavaScript Menu

Enter ‘myOnMessage’ in to the textfield and click on the ‘Add…’ button.

Acrobat JavaScript Functions

Then enter the following JavaScript code in to the window and click on the ‘OK’ button.

JavaScript Editor

function myOnMessage(aMessage)
{
      if (aMessage.length==1) {
            switch(aMessage[0])
            {
                  case "Print":
                        //app.alert("Trying to print PDF");
                        print({
                              bUI: true,
                              bSilent: false,
                              bShrinkToFit: true
                        });
                        break;
                  default:
                        app.alert("Unknown message: " + aMessage[0]);
             }
      }
      else
      {
            app.alert("Message from hostContainer: \n" + aMessage);
      }
}

var msgHandlerObject = new Object();
msgHandlerObject.onMessage = myOnMessage;
msgHandlerObject.onError = myOnError;
msgHandlerObject.onDisclose = myOnDisclose;

function myOnDisclose(cURL,cDocumentURL)
{
      return true;
}

function myOnError(error, aMessage)
{
      app.alert(error);
}

this.hostContainer.messageHandler = msgHandlerObject;

Then remember to re-save your PDF file.

Step 3

Create a blank HTML file and save it next to the PDF file. Then add the following code …

<html>
    <head>
    <title>Load PDF</title>
    <script>
        function callPdfFunctionFromJavascript(arg)
        {
            pdfObject = document.getElementById("PDFObj");
            try {
                 pdfObject.postMessage([arg]);
            }
            catch (e)
            {
                alert( "Error: \n name = " + e.name + "\n message = " + e.message );
            }
        }
    </script>
    </head>
    <body>
        <object id="PDFObj" data="document.pdf" type="application/pdf" width="800" height="600"/>
    </body>
</html>

Step 4

For this example I’m using Flash CS3. Create a movieclip on stage that acts as a button prompting the user to print the PDF document. Give the button instance the name of ‘button’.

Step 5

In this example I have put all the ActionScript code into the document class. The code looks like this …

package
{
    import flash.display.MovieClip;
    import flash.events.MouseEvent;
    import flash.events.Event;
    import flash.html.HTMLLoader;
    import flash.html.HTMLPDFCapability;
    import flash.net.URLRequest;

    public class PrintPdfFromAir extends MovieClip
    {
       
        private var _htmlLoader:HTMLLoader;

        public function PrintPdfFromAir():void
        {
            button.mouseEnabled = false;
            button.alpha = 0.3;
            button.buttonMode = true;
            button.addEventListener(MouseEvent.CLICK, onButtonClick);
           
            trace("HTMLLoader.pdfCapability: "+HTMLLoader.pdfCapability);
           
            if (HTMLLoader.pdfCapability == HTMLPDFCapability.STATUS_OK) {
                _htmlLoader = new HTMLLoader();
                _htmlLoader.addEventListener(Event.COMPLETE, onHtmlLoader_COMPLETE);
                var urlRequest:URLRequest = new URLRequest("load_pdf.html");
                _htmlLoader.load(urlRequest);
                addChild(_htmlLoader);
            }
        }
       
        private function onHtmlLoader_COMPLETE(event:Event):void
        {
            button.alpha = 1;
            button.mouseEnabled = true;
        }
       
        private function onButtonClick(event:MouseEvent):void
        {
            _htmlLoader.window.callPdfFunctionFromJavascript('Print');
        }

    }

}

Basically, we disable to button straight away and add a CLICK event listener. We then check the ‘HTMLLoader.pdfCapability’ property to see if the user has Adobe Reader 8.1 or greater installed on their system. If it equals ‘HTMLPDFCapability.STATUS_OK’ then we can continue. We then create a new instance of the HTMLLoader class, add a listener for the COMPLETE event. We then create an instance of the URLRequest class passing it the name of the HTML file we created in step 3. Next we call the ‘load’ method on our _htmlLoader instance, passing it the urlRequest instance. Then we add the _htmlLoader instance to the stage using addChild.

Normally, when you want to actually display the PDF file on screen, you also need to specify the width and height of the HTMLLoader instance. But in our case we don’t want to actually display it to the user. You may be wondering why we add it to the display list using addChild if we don’t want it to be visible. But I have found that it doesn’t work if you don’t add it to the display list. Not specifying the width and height also means it is not visible (which is what we want on this occasion).

Now we just have the two event handlers to write. The event handler for the HTMLLoader COMPLETE event just makes the button on screen active. We didn’t want the user to be able to click it before the COMPLETE event was fired.

The event handler for the button CLICK event calls the JavaScript function inside the HTML page, which we wrote in step 3.

Step 6

Now you are ready to publish the SWF file and then package it up as an AIR app in the usual way. The important thing to remember is to include the two external files (HTML and PDF) in the AIR Settings dialog box.

Include files

You can create a self-signed certificate for the purposes of testing. I have included my self-signed certificate with the source files (the password is ’1234′) which you can use if you wish, or you could just create a new one.

Step 7

Once you have exported your AIR file it is a good idea to test it on a few different computers to make sure it works properly. Try it on a machine that doesn’t have Adobe Reader installed, or one that has an older version (< 8.1).

Download example AIR app

Download the example AIR file

Click here to download the example AIR file

Download source files

Download ZIP file containing source files

You can download a ZIP file containing my example source files from here.

Useful links

Here are some other blog posts and articles I found useful …

Posted in ActionScript 3.0, AIR, Sample Code | 10 Comments »

PDF Widget on Acrobat.com

August 22nd, 2008 by Adrian

With the release of Acrobat 9 comes the new Acrobat.com website where you can upload and share documents online. One cool new feature is the ability to embed a PDF file on your website using the PDF Widget. It is basically a SWF movie that works like FlashPaper used to. Thanks to Lori DeFurio for making me aware of this and providing an explanation of how to create one yourself.

Below is an example of the PDF Widget, displaying the ‘Programming ActionScript 3.0‘ document from Adobe.

Posted in ActionScript 3.0, Adobe | No Comments »