The Wannabe Java Rockstar: How to print PDF documents with Java

How to print PDF documents with Java

I used to like Adobe. Photoshop, Postscript and PDF were great innovations. But the latest Adobe Reader 6 is a catastrophe. I'm not going to mention the application's look or it's dismal start time. No, I'm complaining about Adobe Reader's ActiveX control.

Adobe Reader ships with an ActiveX control. It is normally used for displaying PDF files in Internet Explorer. Since ActiveX controls are embedable, I thought I might use it to print PDF documents from Java. Embedding is easy-- just use JNIWrapper:

public class AcrobatReaderAutomationSample extends JFrame
{
   
private OleContainer _container = new OleContainer();
   
public AcrobatReaderAutomationSample()
    {
       
getContentPane().add(_container, BorderLayout.CENTER);
        _container.createObject
("PDF.PdfCtrl.5");
        addWindowListener
(new WindowAdapter()
        {
           
public void windowOpened(WindowEvent e)
            {
               
_container.doVerb(OleVerbs.INPLACEACTIVATE);
                doPrint
("C:\test.pdf");
           
}
           
public void windowClosing(WindowEvent e)
            {
               
_container.destroyObject();
           
}
        })
;
   
}

   
private void doPrint(String filename)
    {
       
OleMessageLoop.invokeMethod(this, "printFile",
                                   
new Object[] { filename });
   
}

   
public void printFile(String filePath)
    {
       
IDispatchImpl acrobatReader =
         
new IDispatchImpl(_container.getOleObject());
        Automation automation =
new Automation(acrobatReader);
       
// load document
       
automation.invoke("LoadFile", new Object[] { filePath });
       
//print document
       
automation.invoke("printWithDialog", new Object[0] {});
   
}

   
public static void main(String[] args)
    {
       
SwingUtilities.invokeLater(new Runnable()
        {
           
public void run()
            {
               
// initialize OLE
               
OleFunctions.oleInitialize();
                AcrobatReaderAutomationSample sample =
                 
new AcrobatReaderAutomationSample();
                sample.setVisible
(true);
           
}
        })
;
   
}
}

Via the magic of OLE automation, the program opens and prints a  file with Adobe Reader (see method printFile(...)). It actually looks like an easy thing to do. Unfortunately, the devil is in the details:

  1. The line _container.createObject("PDF.PdfCtrl.5"); works only with Adobe Reader 5. Sometimes, but I can't exactly say when, it also works with Adobe Reader 6. But in order to be sure, you have to call  _container.createObject("PDF.PdfCtrl.6") as well. In versions 5 and 6, the control understands the same messages. Why Adobe chose to name the controls differently, I don't know.
  2. When the document contains more than one page, the print dialog automatically selects the Option "Print Pages 1 to 1". There exists the option "Print All", but there's no way to select it via OLE. The user has to do it manually. Urgh.
  3. Theoretically, one could circumvent the above by using the method "printPages(from, to)". With Adobe Reader 5 it works as advertised: it prints the selected pages without showing the print dialog. With Adobe Reader 6, though, the control displays a warning "Attention: some script wants to print a document. It might print the whole document." (I'm paraphrasing, as I only know the German message).

    What the ...? I mean, if you don't want some external process to do something with you, don't expose the method.
  4. Since Reader 6 is such a moloch, Adobe changed the semantics of object release. With OLE objects, you have to do explicit reference management: if you acquire an object reference then you also have to release it. With Adobe Reader 5, the acrord32.exe disappeared from the process list after the object reference was released. Now, it doesn't. Reader 6 uses about 35MB and the only ways to close it are to kill it or open the Adobe Reader program and close that. That takes care of the acrord32.exe instance.

That's it from the top of my head. I fought a week trying to force my will upon Adobe Reader 6. I'm at a point,were I hate that software with passion.

Summary: What looked like the perfect solution to printing with Java under Windows, turned into a week-long debug fest with questionable results. Adobe Reader 5 worked flawlessly. My main gripe is version 6. It is completely screwed up.

Tue, 26 Oct 2004, 15:02 | Java | PermaLink
« Filehand -- An Alternative to Google Desktop Search? | Home | What Makes Link Blogs So Successful »