Silent print a PDF file in Acrobat Reader (for PDF files served on the Internet)

Update: Please do not forget to check the other PDF and print related links in the sidebar

Some of you might have been awaiting this.
You maybe disappointed with the results of this article though, so dont expect too much – I’ll explain what is possible with existing software and code ( but not voodoo programming : that’s not the kind of code that’s bug free ).

Prerequisites

  • Acrobat Javascript Guide (pdf file) and Reference (pdf file),
  • Some basic knowledge of Java servlets,
  • Some knowledge of the iText PDF library or atleast some enthusiasm to learn it.

Précis

I will demonstrate how to generate a PDF document with the iText PDF library. The document will have embedded Acrobat Javascript in it. Using the Acrobat Javascript commands I will ensure that the PDF document will be printed (to the default printer) when it is opened, followed by an attempt to close the document (which may not succeed when the document is opened inside a browser using the Acrobat Reader plugin or BHO). The PDF with the embedded Acrobat Javascript is served by a Java servlet which allows for the solution to be demonstrated over the internet.

Source Code

The WAR (Web ARchive) file containing the servlet and the iText library can be downloaded here(Mail me if the download fails). You could straightaway deploy it on Apache Tomcat or any other servlet container or even a J2EE application server.

What’s going on?

The important stuff is being done here:

/*
The output stream of the servlet to which the PDF document is sent.
*/
ServletOutputStream out = response.getOutputStream();

/*
Create an iText document – that’s a PDF document that we’re creating.
*/
Document document = new Document();

/*
Create a ByteArrayOutputStream to which the document will be written (the document will NOT be created on as a disk file at the server – use FileOutputStream for that.
*/
ByteArrayOutputStream baos = new ByteArrayOutputStream();

try {

/*
We get an instance of Pdfwriter. The instance is “listening” to the document object, and is “tied” to the byte array output stream. This means – whenever we add elements to the document the writer object picks it up and transfers it to the output stream.
*/
PdfWriter writer = PdfWriter.getInstance(document, baos);

/*
I’m setting the viewer preferences so that the user is not able to see the menubar or scrollbar inside the browser when this file is opened using the Acrobat Reader PDF plugin. This could be treated as a “security measure” for preventing users from saving the file or printing the file once again. Be careful – it’s a viewer preference and not a security provision. It can be reverted by the user because it’s only an indication to the Reader plugin on how the document is to be presented when it is initially loaded.
*/
writer.setViewerPreferences( PdfWriter.HideMenubar | PdfWriter.HideToolbar | PdfWriter.HideWindowUI );

/*
We have to open the document for writing information after the header and meta-information is added. Which means that we have to “prepare” the document before we are have to write the user-visible information.
*/
document.open();

/*
We now add a document level Javascript action so that the entire action is executed when the document is opened. To see what other options are available, you will have to go through the Acrobat Javascript Reference and Guide (links are same as above).
The necessary information can be found in the Doc object provided by the Acrobat Javascript model. The Doc object can be referenced usually by using the “this” object.
*/
writer.addJavaScript(
“this.print({bUI: false,bSilent: false,bShrinkToFit: true});” +
“\r\n” +
“this.closeDoc();”
);

/*
We add some dummy statement to be printed.
I hate to print a blank document, but I dont waste paper.
So, if you are environment conscious, please enter whitespaces instead.
Do not (God forbid), remove the line of code below to save on paper. LOL.
*/
document.add(new Chunk(“Silent Auto Print”));

/*
You have to close the document when you’re done with it.
*/
document.close();
}
catch (DocumentException e)
{
e.printStackTrace();
}

/*
I’m setting the content type of the response so that the browser will recognize that it is going to receive a PDF file. However, do not be too confident about this.
Some browsers – especially IE and Opera are known to do “content-sniffing” to determine what is to be done with a server’s response. And that could change the equation drastically.
*/
response.setContentType(“application/pdf”);

/*
Some browsers are known to flip and throw up when they dont know how much data is going to be received by them. So it is wise to set the content length header before sending data to the browser.
*/
response.setContentLength(baos.size());

/*
We wrote the document to a ByteArrayOutputStream. Now flush that stream to the servlet’s response object.
*/
baos.writeTo(out);

/*
Flush the servlet’s response object so that the servlet responds to the browser’s request.
*/
out.flush();

A Trial Run

You could go to this demonstration page and see how it works. Be sure to try this out in different environments – with and without Acrobat Reader browser plugin installed, with and without SP2 installed on Windows XP, different browsers (especially Firefox and Opera), and even when the user is able to save the file and then open it. You’ll learn quite a lot on why I chose to write the servlet this way and not any other way. Consistency matters a lot when it comes to the internet.

Advertisements

8 Comments

Filed under Uncategorized

8 responses to “Silent print a PDF file in Acrobat Reader (for PDF files served on the Internet)

  1. hey thanks for the article.
    i might try it out. too bad we still need to open Acrobat for printing. we have these pro users and they might print several 100 docs a day. in the end we might stick with the applet solution (we are more or less in control of the browser… so applet would work)

    have a nice day

  2. Thanks for the feedback.
    In my next article I’m going to explore MeadCo’s plugin so that you could use that instead (if the budget permits).
    It seems to be a robust plugin and doesnt have the startup load time associated with a Java applet.

  3. yeah, startup time of applets is crap. but we could fly around this with some hidden frame solution. to many boundaries in this project 🙂

  4. Hi. Very nice example.

    It could be useful to catch any possible exception in the JavaScript code. Something like that:

    String js = “try { this.print({bUI: false, bSilent: true}); this.closeDoc(true); } catch(e) {/*handle exception*/}”;
    writer.addJavaScript(js);

    When a document (PDF) is shown inside the browser, trying to “close” that document will raise an exception.

  5. Yes, that’s right Jose.
    I chose to omit that just in case the programmers using iText wouldn’t understand that.

    The ability to close the PDF document from the browser triggers an exception as you rightly pointed out. However that is the pitfall of using the Adobe Acrobat plugin to view pdf files in the browser. A plugin written differently might show different behavior. It’s very difficult to get consistent results across various browsers which is what I chose to show here.

    Thanks for your time and inputs.

  6. the war can be downloaded now

  7. gsr600

    Hi, thanks for your example.
    Sorry for my english…

    How do I add a auto-submit instruction on this example?

    I need tu change page before document as printed.

    Thanks for your time.

  8. Jagadeesh

    Hi,
    I tried ur example.
    It worked fine. The only problem is, the print dialog is coming up repeatingly.
    when i click OK on the print dialog once, it goes to the printer and the printout comes fine, but again the print dialog comes up. The user has to close it manually. Is there any solution for this?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s