RSS Feed Subscribe to RSS Feed

This world is spinning around me. This world is spinning inside me. Every day send future to past. Every breath leaves me one less to my last !!

Silent Printing on Web based Java Application

itextSilent Printing on client’s printer is considered to be security hazard and is not recommended to general applications. It would not sound great when the website you are browsing starts sending prints to your printer without your confirmation. But with advanced web applications, other than regular websites, there are requirements for silent printing. I came across such requirement recently where I need to print a pdf report generated by Jasper to clients computer silently. I am discussing here the example code snippets for this mechanism. The example discussed here uses iText, a free Java PDF library, and JavaScript API for Acrobat. This example elaborates the method of sending pdf directly to a printer from the web server without opening it into clients Acrobat Reader. This example has been tested successfully on Tomcat running on Windows Vista with IE 7 and Acrobat Reader 9.

The first component of this example is PdfPrintServlet, which is a general servlet that calls iText library methods to read an existing pdf file and append JavaScript for silent printing and finally write this new pdf (existing pdf file with JavaScript appended) to clients browser. The code for this servlet is as follows;

?View Code LANGUAGE
package com.examples.general.webapp;
 
import java.io.IOException;
import java.net.URL;
 
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
import com.lowagie.text.DocumentException;
import com.lowagie.text.pdf.PdfAction;
import com.lowagie.text.pdf.PdfReader;
import com.lowagie.text.pdf.PdfStamper;
import com.lowagie.text.pdf.PdfWriter;
 
public class PdfPrintServlet extends HttpServlet {
 
	/**
	 * Explains how to print silently via Servlet/Browser.
	 * @author     Bikram Shrestha, markib@gmail.com
	 */
	private static final long serialVersionUID = 1L;
 
	public void doGet(HttpServletRequest request, HttpServletResponse response)
	throws IOException, ServletException{
 
		response.setContentType("application/pdf");
 
		URL url = new URL(request.getParameter("url"));
		PdfReader reader = new PdfReader(url);
		try {
			PdfStamper stamper = new PdfStamper(reader,response.getOutputStream());
			PdfWriter writer = stamper.getWriter();
 
			StringBuffer javascript = new StringBuffer();
			javascript.append("JSSilentPrint(this)");
 
			PdfAction pdfAction= PdfAction.javaScript(javascript.toString(), writer);
			writer.addJavaScript(pdfAction);
			stamper.close();
 
		} catch (DocumentException de) {
			de.printStackTrace();
			System.err.println("document: " + de.getMessage());
		}
	}
}

In the code above PdfReader opens the pdf document specified in a url which is passed to a servlet as a paramter in a querystring. PdfStamper is used to append JavaScript to this pdf document, as pdf document are not allowed to be edited but we can append attributes and parameters to it using PdfStamper. PdfWriter instance is obtained from PdfStamper which helps write new pdf document to client machine that has all content from pdf specified in url and the appended JavaScript. JavaScript function “JSSilentPrint(this)” is responsilbe for silent printing  and this function is defined in seperate JS file sdkSilentPrint.js.  This file comes along with Adobe Acrobat SDK download and you can edit the printing parameters in this file. The code for this js file is as follows:

?View Code LANGUAGE
/*********************************************************************
 
 ADOBE SYSTEMS INCORPORATED
 Copyright 1994-2008 Adobe Systems Incorporated
 All rights reserved.
 
 NOTICE: Adobe permits you to use, modify, and distribute this file
 in accordance with the terms of the Adobe license agreement
 accompanying it. If you have received this file from a source other
 than Adobe, then your use, modification, or distribution of it
 requires the prior written permission of Adobe.
 
 ---------------------------------------------------------------------
 
 SDKSilentPrint.js
 
 - Folder level Javascript code created by Adobe Acrobat SDK.
 
 *********************************************************************/
 
 /*
  * The sample will add "Silent Print" under Acrobat File menu.
  * Click it to print the front document to the default printer without user interface.
  * It works for Reader, too.
  *
  * See Acrobat JavaScript reference and guide SDK documents for further information.
  */
 
if ( typeof sdkMenuItem == "undefined")
	var sdkMenuItem = false;
 
if (!sdkMenuItem) {
	sdkMenuItem = true;
	app.addSubMenu( {
		cName:"ACROSDK:JSSubMenu",
		cUser: "Acrobat SDK JavaScript",
		cParent: "Tools",
		nPos: 0
	});
}
 
/*
 * Add a menu item
 * you can execute this menu item from other programs such as IAC VB / VC code.
 */
app.addMenuItem( {
	cName: "ACROSDK:SilentPrint",
	cUser: "Silent Print",
	cParent: "ACROSDK:JSSubMenu",
   cEnable: "event.rc = (event.target != null);",
   cExec: "JSSilentPrint(event.target)"
});
/**
* trustedPrint function: Exercise the print function in the privileged context
*
* @param doc The Doc object of the target document
* @param pparam The PrintParams object containing print settings
*/
trustedPrint = app.trustedFunction(
function(doc, pparams) {
app.beginPriv();
doc.print(pparams);
app.endPriv();
}
);
 
/**
* Main function: Print silently
*
* @param theDoc The event target of executing the menu item of this sample.
*/
function JSSilentPrint(theDoc)
{
// get the printParams object of the default printer
var pp = theDoc.getPrintParams();
 
// print all pages.
// You can print certain pages using code:
// pp.firstPage = theDoc.pageNum1;
// pp.lastPage = theDoc.pageNum2;
 
// silent print,
// you can also try .automatic instead of .silent
pp.interactive = pp.constants.interactionLevel.silent;
pp.printerName="MY_PRINTER_NAME";
pp.pageHandling = pp.constants.handling.none;
 
// set flag value which may include many options.
// here we enable automatic paper tray selection
var fv = pp.constants.flagValues;
pp.flags |= fv.setPageSize;
pp.flags |= (fv.suppressCenter | fv.suppressRotate);
 
// Print to the default printer without invoking the print dialog
trustedPrint(theDoc, pp);
}

The above js file needs to be copied to Acrobat’s JavaScript folder, for Acrobat 9 the folder path is C:/Program Files/Adobe/Reader 9.0/Reader/JavaScripts. The only reason to copy this JS file to specified path in clients machine is to execute this javascript in a priviledged context i.e., the above JS file is the folder level  JavaScript with trusted funtion. For more details refer to “Privileged versus non-privileged context” topic in JavaScript for Acrobat API Reference, this reference is available at http://www.adobe.com/devnet/acrobat/pdfs/js_api_reference.pdf. The path to place folder lever JavaScript can be determined by executing app.getPath(“app”,”javascript”), the statement example and its corresponding output on Windows Machine is shown below;

?View Code LANGUAGE
app.getPath("user", "javascript");
/C/Documents and Settings/userName/Application Data/Adobe/Acrobat/8.0/JavaScripts
 
app.getPath("app", "javascript");
/C/Program Files/Adobe/Acrobat 8.0/Acrobat/JavaScripts

You can entirely eliminate using folder level JavaScript and bypass the hassle of copying sdkSilentPrint.js file to all Acrobat JavaScripts folder in each and every clients machine. You can specify all the print parameters in a servlet itself and invoke print method form there only. This would display JavaScript confirmation box with the message “This document is trying to print. Do you want to allow this?” and might not be considered true silent printing. The code example for this is as follows;

?View Code LANGUAGE
/*
 * $Id: PdfServlet.java 3373 2008-05-12 16:21:24Z xlv $
 *
 * This code is derived from the 'iText Tutorial'.
 *
 */
 
package com.examples.general.webapp;
 
import java.io.IOException;
import java.util.Date;
 
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
import com.lowagie.text.Document;
import com.lowagie.text.DocumentException;
import com.lowagie.text.Paragraph;
import com.lowagie.text.pdf.PdfAction;
import com.lowagie.text.pdf.PdfWriter;
 
/**
 * Explains how to print silently via Servlet/Browser.
 * @author     Bikram Shrestha, markib@gmail.com
 */
public class PdfServlet extends HttpServlet {
	public void doGet(HttpServletRequest request, HttpServletResponse response)
	throws IOException, ServletException{
		Document document = new Document();
		response.setContentType("application/pdf");
		try {
			PdfWriter writer = PdfWriter.getInstance(document, response.getOutputStream());
			document.open();
 
			StringBuffer javascript = new StringBuffer();
 
			javascript.append("var params = this.getPrintParams();");
 
			javascript.append("params.interactive =	params.constants.interactionLevel.silent;");
			javascript.append("params.printerName=\"MY_PRINTER_NAME\";");
			javascript.append("params.pageHandling = params.constants.handling.shrink;");
 
			javascript.append("this.print(params);");
 
			PdfAction pdfAction= PdfAction.javaScript(javascript.toString(), writer);
			writer.addJavaScript(pdfAction);
 
			document.add(new Paragraph("Testing Silent Printing with iText"));
 
			document.add(new Paragraph("Hello World"));
			document.add(new Paragraph(new Date().toString()));
		} catch (DocumentException de) {
			de.printStackTrace();
			System.err.println("document: " + de.getMessage());
		}
		document.close();
	}
}

The above code would create a new pdf document along with silent print JavaScript embedded to it. When you invoke the PdfServlet from clients machine it would send a print command to clients printer as soon as pdf opens in the browser.

In both the above cases JavaScript responsible for silent printing is:

?View Code LANGUAGE
var pp = theDoc.getPrintParams();
pp.interactive = pp.constants.interactionLevel.silent;
pp.printerName = "MY_PRINTER_NAME";
pp.pageHandling = pp.constants.handling.none;
 
var fv = pp.constants.flagValues;
pp.flags |= fv.setPageSize;
pp.flags |= (fv.suppressCenter | fv.suppressRotate);
theDoc.print(pp);

Here, getPrintParams() method for the pdf document give access to setting up print parameters for the pdf document and by setting its interaction level “pp.interactive = pp.constants.interactionLevel.silent;” we can acheive silent printing. We can specify whole lots of print parameters like printer name, page scaling, auto rotate and center and much more. These parameters are explained in details in “PrintParams” section of JavaScript for Acrobat API Reference.

Finally if you need to restrict pdf document from being displayed in clients browser while printing silently, you can use iframe ans set its property to be hidden. The html code snippet that I used for hiding pdf document in browser while it is being printed silently is as follows;

?View Code LANGUAGE
<iframe src="http://localhost:8080/pdfPrint/pdfPrintServlet?url=http://localhost:8080/pdfPrint/Label.pdf" width="40%" height="80" align="center" scrolling="yes" style="display:none">
</iframe>

Resources:

 JavaScript for Acrobat API Reference: http://www.adobe.com/devnet/acrobat/pdfs/js_api_reference.pdf
Download iText Library: http://www.lowagie.com/iText/download.html

Reader's Comments

  1. Mahesh | February 6th, 2010 at 11:12 am

    Hi,

    Thanks for the great job. It has solved my problem. I have a question is it possible to print this pdf document without opening it. Means i am using this solution in Applet and wants to print pdf silently but it require PDF to open to get printed. I am using showDocument method of applet to open the PDF and it’s working but i don’t want that. Please suggest me how can i do that.

    Regards,
    Mahesh

  2. Jodik | July 9th, 2010 at 12:55 am

    Thank you, this really a great tutorial. I’ve been search all over the net. Silent printing was really a silent killer. Thank you.

    Jodik

  3. Vijayan | July 9th, 2010 at 6:13 am

    In our project I need to do the silent printing without opening the PDF. But is there any way we can notify the user that the document has been sent to the printer.

    Thanks!
    Vijayan

  4. Jhay | October 27th, 2010 at 2:00 am

    Any working sample source for this?

  5. bikram | November 11th, 2010 at 10:29 am

    Sorry Jhay.. My webhosting do not support Java.. I don’t have any live example.. but try the code above.. it works !!!

  6. why | December 8th, 2010 at 11:12 pm

    Can i know how u declared the “the Doc” variable as i’m getting this error.

  7. bikram | December 9th, 2010 at 11:19 am

    Why,

    If you check the function declaration statement function JSSilentPrint(theDoc)
    theDoc is passed as a prameter to this function. See the code listing for SDKSilentPrint.js.

  8. why | December 9th, 2010 at 10:07 pm

    bikram,

    Thanks for your reply. I noticed it before and maybe I’d confused with all the things I had researched.

    What I actually want to ask is it “theDoc” holding the document’s path or just the filename or other value?

    I’m very sorry for troubling you with this confuse statement, but I’m had try a lot of method to print a web server file with the client’s printer.

    Thanks alot.

  9. Machinator | December 14th, 2010 at 9:33 am

    Great article, but I have a problem, In firefox running on Ubuntu when I open the pdf with the plugin in the browser nothing happens but if I open it directly from abode reader it works perfectly…

    Maybe there are problems with the reader plugin on linux, have anyone tried this?

    I’m going to try it on windows anyway.

    Thanks.

  10. bikram | December 16th, 2010 at 4:39 pm

    Machinator,

    I don’t know which plugin are you using to open the pdf in firefox / ubuntu. The above example uses JavaScript API for Acrobat, so it worked on Adobe Reader when you opened directly in it. Let me repeat again, the code is only for Adobe Reader only. Thanks for trying it out. Share your experience if you have success with other plugins.

  11. Machinator | December 20th, 2010 at 2:20 pm

    Hello, sorry for the late response, I was able to make it work minutes after I post here but I forgot to share the solution, I was using adobe reader in ubuntu but I had to do some extra steps in the configuration to allow the .js run with privileges:

    Open Adobe Reader go to menu Edit-> Preferences and select Javascript from the list then check the two options under “JavaScript Security”, these options are: “Enable menu items javascript execution privileges” and “enable global object security policy”

    It works perfectly now, thanks a lot.

  12. bikram | December 20th, 2010 at 3:44 pm

    Thanks for sharing the info, Machinator.. it would be helpful to all linux users.

  13. Santosh | May 5th, 2011 at 1:59 pm

    ActiveTree has a great solution!

    Silent print PDF from browser without the Acrobat Reader installed on client browser machine. I had the same issue that the PDF should not be opended and moreover client machine may have a Adobe Acrobat reader installed. So, I moved to use ActiveTree solution.

    Try it here (there are some online demo as well)
    http://www.activetree.com/silent_print_pdf_from_browser/

  14. Girish | September 29th, 2011 at 6:47 am

    Hey Guys,

    I am trying to do a similar app.

    I tried your code but i am not satisfied.

    When I am running the PdfServlet the pdf comes up fine but it also gives a js alert that asks for confirmation “This document is trying to print. Do you want to allow this?”. How do i get rid of this alert.

    Please help soon.

  15. Mikael | October 11th, 2011 at 3:03 am

    Hey, first thanks for your solution it was a great help for me !
    I just got a problem with this solution :
    http://www.freeimagehosting.net/acea3
    As you can see in this screenshot, there is some confirmation message from Adobe Reader for the printing to be authorize. How can I avoid the display of this message and make the print completely silent/automatic ?

  16. bikram | October 14th, 2011 at 1:03 pm

    Hi Girish and Mikael, both of you seem to be pointing the same problem. I have discussed the solution above i.e, copy the file SDKSilentPrint.js (it comes with acrobat SDK) to Acrobat’s JavaScript folder, for Acrobat 9 the folder path is C:/Program Files/Adobe/Reader 9.0/Reader/JavaScripts. It is explained better in “Privileged versus non-privileged context” topic in JavaScript for Acrobat API Reference. Hope this helps.

  17. Uddalak | February 18th, 2012 at 2:20 pm

    The code is working fine. But I’ve one problem that is I need to provide the default printer name. In the Code it has been hard coded as pp.printerName = “MY_PRINTER_NAME”; But I need to pass the name from client’s machine. How could I do that? There is only one solution I’ve found in google using javascript. But that is only internet explorer compatible. So please help.

  18. Dino Olivieri | July 19th, 2012 at 8:49 am

    i wrote an article how to open and show and silent print pdfs in Windows and Mac OSX with examples (using native commands):
    http://www.onyrix.com/2012/04/adobe-air-pdf-silent-print-with-acrobat-reader/

    bye
    d

  19. Sameer | August 18th, 2012 at 1:56 pm

    ActiveTree already have completely FREE online silent printing solution for many document formats such as PDF, TIFF, custom reports etc. You can also download the web application to deploy the silent print solution (and optional viewer) to your system for free.

    Check it out here
    http://www.activetree.com

  20. Sweenh | January 31st, 2013 at 6:03 am

    Hi, it works great but it fails after an acrobat reader update from 10 to 11: After this update i have two adobe folder: the old adobe 10 folder with only one file: SDKSilentPrint.js (into javascript subdir) and the new adobe 11 folder without the SDKSilentPrint.js file inside javascript subdir. When I try to silent print it doesn’t work.

    Do you know something about silent print and acrobat update?
    thank you very much
    bye

  21. Jonard | February 1st, 2013 at 3:15 am

    I tried this code with my java web application, is there something I need to set up with glassfish server. There is no error in executing the codes, but nothing happened. There is no printing process occured. Please help with this. Thanks

  22. Jonard | February 1st, 2013 at 3:16 am

    I have installed glassfish server 3.1.2 and Adobe Reader 11. Thanks

  23. Jonard | February 4th, 2013 at 10:47 pm

    I have solved my problem, i just figure out that I need to close first the PDFStamper before other objects. Thanks

  24. Joval junior | June 13th, 2013 at 3:23 pm

    Thanks for your post, this solved my problem.
    I make few modifications on your project, I read directly from a File on my context and use it with JSF 2.
    Now works perfectly.
    Again, thanks for you post.

Leave a Comment