<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?xml-stylesheet type="text/xsl" href="blog.xsl"?>
 <title>Silently* print a PDF from a web browser</title>
 <subtitle>* almost</subtitle>
 <excerpt>We occasionally are asked how to print a PDF from a web browser without displaying a dialog. There isn't an easy answer to this, but you can get fairly close with our Viewer API.</excerpt>
 <tags>print applet</tags>
We occasionally are asked how to print a PDF from a web browser without displaying a dialog. There isn't an easy answer to this, but you can get fairly close with our Viewer API.
The example below will prompt the user if they want to allow the print.  <b>This is entirely correct behaviour</b> - otherwise you could silently spool a 10,000 page document to every available printer. No matter which approach you take, the client will always have to approve the print in some way.

<p>Solutions to this common (but perhaps still not adequately solved) problem broadly take one of several approaches
<li>Use ActiveX or similar to script or control Acrobat when loading</li>
<li>Embed JavaScript in the PDF to print the PDF on load</li>
<li>Use Java to print from an Applet</li>
Aproach 1 is beyond the scope of our software, is Windows specific and relies on Acrobat being installed and behaving itself. Option 2 requires the PDF to be displayed first, which isn't always what you want. We'll cover Option 3 in more detail here.
<h3>Printing using an Applet</h3>
Applets don't have to be visible on the screen to run - indeed, they're becoming more common "behind the scenes" and controlled by JavaScript. They have the advantage of being platform neutral as well. While you're not going to be able to print completely without user interaction, you can get pretty close.
</p><p>This <a viewtext="true" href="PrintPDFApplet.java?brush=java">applet</a> can be downloaded and compiled - you'll need our <code>bfopdf.jar</code> Jar file and the <code>plugin.jar</code> file supplied with the JRE (look in the "lib" directory). Compile this class and put it in a jar file on it's own, say <code>printapplet.jar</code>. Then to print the PDF you'll need something like the following code:
<pre class="brush:html"><![CDATA[
   applet { position: absolute; visibility:hidden }
   function mycallback() {
       document.getElementById("button").disabled = false;
   function myprint() {
  <applet code="PrintPDFApplet" name="printApplet" archive="printapplet.jar,bfopdf.jar">
   <param name="callback" value="mycallback"/>
   <param name="pdf" value="documents/myfile.pdf"/>
  Click here to print the PDF
  <input type="button" disabled id="button" onClick="myprint()" value="Print" />
<h3>Notes and Caveats</h3>
<li><span style="font-face:bold; color:red">Update</span>. If you're running Java 1.6u10 or later, the above 
approach is going to give warnings due to a mix of signed and unsigned Jars. The best approach is desribed at 
the end of <a href="/blog/2011/11/08/extending_the_pdf_viewer_part_2/">this article</a>, which is to 
repackage the new applet and the bfopdf.jar file into one Jar. We now have a Zip file containing a demo of this 
approach available for download on request.</li>
The applet is made invisible via the "visibility:hidden" and "position:absolute" styling. Using "display:none" will prevent the applet from starting at all, at least in our tests.
This applet will work if it's unsigned, at least with recent versions of the Java Plugin. However it will ask the user if they want to allow the applet to access the printer. You can sign the applet to avoid this, but then they'll be asked if they want to accept the signature instead.
Downloading the applet will take about 750KB with Java 6, provided the <code>bfopdf.jar.pack.gz</code> file is also available. This is one off cost
incurred the first time the page is loaded. A more sophisticated version of our simple example would use a JNLP file to load the applet. There's more on
this on the web and in our <a href="/blog/tags/applet">other articles on applets</a>.
<li>We're prompting for the printer with a standard Java print dialog. You don't have to do this - you can modify the code to just pick the first one. However if the first one is in another office, don't be surprised if your users are very unhappy with you.
The PDF can be loaded via the <code>pdf</code> parameter to the applet, or it can be loaded manually by calling the <code>load</code> method on the applet from JavaScript - the approach is identical to the <code>print</code> method we're calling. We're using a callback from the applet to JavaScript to notify when the PDF is loaded so you can enable the "print" button only when the PDF is available.
If you want to load the PDF from a different server to the one serving the applet, you will need to sign the applet. Currently this is also the case under OS X, which doesn't seem to allow access to the list of printers even if the user approves the action.
<include xmlns="http://www.w3.org/2001/XInclude" href="comments.xml"/>