Printing Directly to a Network Printer

Recently I had to print from a mobile Java application that was being developed for both BlackBerry and Android. Printing from Java SE on the desktop is quite easy by using either the Java Print Service API or the older java.awt.print API for printing Swing/AWT components. Unfortunately neither of these APIs is available in the mobile Java environments for BlackBerry or Android.

Instead I figured it should be possible to create the print data on my own and send it directly to a network printer. It turns out this was a bit trickier than I expected, so I decided to write this blog post about it. At the end of this post I also include some useful links to other reference material.

Getting Started

The first question I had was which port on the network printer to use. Port 9100 is the standard port for the "RAW" print protocol. This port appears to be used by all network printers. Many printers also support the Internet Printing Protocol on port 631. Some printers even support the LPD printer protocol on port 515. The LPD protocol is quite old and is documented in RFC 1179

I was a bit confused initially since in my research port 9100 was often referred to as the port for the "RAW" print protocol. It turns out there is no "protocol" here, it is indeed simply the raw print data that can be sent directly to this port and the printer will interpret it for printing. Therefore port 9100 is most likely what you want to use, unless you need some of the features provided by the other protocols. I decided to print directly to port 9100.

The next question is, what "raw" print data should be sent to the printer? Printers expect print data in a Page Description Language (PDL). There are two common PDL languages in use today. One is PostScript from Adobe and the other is the Printer Command Language (PCL) from HP. There are also some other manufacturer specific languages such as UFRII from Canon, but they only work with printers from that manufacturer.

PostScript has a lot of history and there are several Java libraries available for generating PostScript code. I was under the assumption that all network laser printers today support PostScript, so I started with that. The problem was that sending PostScript to our office printer resulted in it simply printing the PostScript source as plain text. Not good!

This led me to discover a third printer language that is in common use today: Printer Job Language (PJL) which was also developed by HP. PJL sits above languages like PostScript and PCL. It can be used to set printer parameters and then switch the printer into the desired page description language (usually either PostScript or PCL).

After discovering PJL I modified my prototype to first send some PJL commands to switch the printer into PostScript mode. Unfortunately this still did not work on any of the printers I tried. They either printed nothing at all or the PostScript code as plain text. After more research I discovered that in fact PostScript is not commonly supported. You usually have to purchase a printer add-on for PostScript support. So it turns out that in the end there is no way around using PCL. This is where the fun really started since PCL is quite cryptic and there are no existing PCL generation libraries for Java that I could find.

Next I am going to explain how to send a simple PJL/PCL print job directly to a network printer on port 9100.

PJL Commands

The first thing you need to send to the printer are some PJL commands. 

All PJL commands start with an escape sequence: <ESC>%–12345X

Here <ESC> is the code for the ESC key (decimal 27, hex 1B) and the others are regular ASCII characters.

This escape sequence has to be included at the start of all PJL command sequences. After the escape sequence each PJL command appears as plain text and is terminated by CR-LF characters. Here are some basic PJL commands to switch the printer into PCL mode:

<ESC>%–12345X@PJL JOB NAME = "My Print Job Name" <CR><LF>
@PJL ENTER LANGUAGE = PCL <CR><LF>

Notice that there is no newline between the escape sequence and the first PJL command. This is intentional. Newlines only appear after the first PJL command. The PCL print data is sent directly after the ENTER LANGUAGE command.

After sending the PCL print data the printer has to be switched back to PJL mode so that we can end the print job. This is done by again sending the PJL escape sequence followed by the end of job command:

<ESC>%–12345X @PJL EOF <CR><LF>
<ESC>%–12345X

Notice that the final thing we send is the PJL escape sequence one more time, without anything after it (no newlines). Therefore a complete PJL command sequence would look like this:

<ESC>%–12345X@PJL JOB NAME = "My Print Job Name" <CR><LF>
@PJL ENTER LANGUAGE = PCL <CR><LF>
<PCL COMMANDS HERE>
<ESC>%–12345X @PJL EOF <CR><LF>
<ESC>%–12345X

That was pretty easy. PJL basically forms an envelope around PCL (or PostScript). There are a few other PJL commands, most importantly the SET command that is used to configure various printer options. This is not needed unless you want to switch the page size, change the number of copies, etc. More information can be found in the HP PJL Technical Reference Manual.

PCL Commands

The trickier part is sending the print data in the form of PCL commands. All PCL commands start with the <ESC> character followed by the command identifier. Note that PCL commands are not terminated by newline characters. Any text that follows a PCL command is simply printed as text on the page, unless it is preceded by the <ESC> character and recognized as another PCL command. Any newlines within the PCL commands are interpreted for printing.

The first PCL command you have to know is the reset command: <ESC>E

In general this is the first command you send to reset the printer and start a new page. For example, to start a new page and print "Hello World" at the top of the page you would send this:

<ESC>EHello World

Notice that there is no space between the PCL command and the "Hello World" text. It's not needed!

Moving Around The Page

Now, what if we want to print "Hello World" somewhere else on the page? In this case you can use the PCL move commands:

<ESC>*p150X
<ESC>*p150Y
Hello World

This moves 150 units along the X and Y axes respectively. Notice that no newline characters appear between the commands. I write out the text using newlines for readability, but they don't appear in the actual commands sent to the printer.

Since both move commands use the *p command prefix we can actually combine them into a single command, like this:

<ESC>*p150x150Y

Notice that the "x" is in lowercase. When commands with the same command prefix are combined, then only the last command suffix is spelled in uppercase. In this case "Y" is last, so it is spelled in uppercase and the "x" in-between is in lowercase.

So far so good. Now you are probably wondering, what are the units that I am moving around with? This depends on the printer defaults, but we can explicitly specify it using some handy PCL commands:

<ESC>&u150D
<ESC>*t150R

These two commands set the dots-per-inch (DPI) resolution of text and graphics operations respectively. In this case I am setting the resolution to 150 DPI. That means when I move 150 units I am moving 1 inch on the page along each axis. Nice!

Let's See Some Colors

Wouldn't it be nice to print in color? This requires a couple of PCL commands to be set up correctly. First we need to tell the printer to use the RGB color space:

<ESC>*v6W

This selects the RGB color space with 8-bits per pixel. Next we need to specify the color we want to use:

<ESC>*v255a0b0C

Notice that there are three components to this command: red (a), green (b) and blue (c). In this case I am selecting the color red with no green or blue. Finally I need to store the selected color in a color palette and select it for use:

<ESC>*v0i0S

This command first assigns the color to palette index 0 (the i command) and then selects that palette (the S command).

Very nice. If I were to write some text or draw something it would now come out in red. You can even combine all of these commands into a single command string since they all use the *v prefix:

<ESC>*v6w255a0b0c0i0S

Note that the "W" command to select the RGB color space is really only needed once and could be sent at the beginning right after the reset command. If you are printing a large document it can significantly reduce the document size to not include extra commands when not needed. That's also why you combine commands into one string, so you don't have to include the <ESC> character all the time.

Let's Draw Some Graphics

Now that we can draw text and use colors, how about some graphics? Here are the basic commands to fill a box on the page:

<ESC>*c300a150b5P

This fills a box 300 dots (2 inches) wide along the horizontal axis and 150 dots (1 inch) high along the vertical axis. The "5P" command at the end selects the current color palette. So in our case the box would be filled in red.

Using these commands you can also draw box outlines. You would simply fill very narrow boxes for each side of the box outline that you are drawing. The narrow box you are filling in effect becomes a line and four lines make ... another box! Makes sense, right?

Putting It All Together

I've provided a quick overview of the most useful commands and how they all fit together. There are many more PCL commands to select font family, size, style, etc. and also draw boxes in different fill patterns. You can find a reference of all these commands in the HP PCL5 Technical Reference Manual

PCL includes a number of common fonts. If you want to use other font families you have to first upload them to the printer, which is something that I didn't need to do. It's also possible to upload bitmap images or TIFF images to the printer, again something that I didn't get in to. All of that is explained in the reference manual.

Once I had enough experience with the basic PCL commands I put together a nice Java class similar to the "java.awt.Graphics" class. The constructor accepts an OutputStream as a parameter and the class will write all PCL commands to the output stream. It provides methods to start a new document, set the font/color, draw text, draw lines, etc.
While it's pretty basic this class does everything I needed. I could draw text with different styles and also draw little line and bar graphs. I can't share the code for this here, but hopefully my post gives you enough ideas to implement it yourself.

More Resources

Here are a few more useful resources:

blog moved to Posterous

It's been a long time since I've written anything on here. Maybe that's because the blog was running on a really old Drupal 4.7 installation and I didn't feel like updating it. Last week I finally bit the bullet and migrated the blog to Posterous. I like Posterous because of their clean interface and easy to use e-mail posting capabilities. Their handling of post attachments is also really smart; organizing images into galleries, previewing PDFs using Scribd, etc.

Unfortunately Posterous does not have direct import functionality for Drupal, but they do have an easy to use API. I threw together a quick PHP script that reads blog posts and comments from my old Drupal 4.7 blog and imports them into Posterous. I've attached the script to this post since it might be useful to someone else. One thing to note is that the script does not preserve post formatting, so you will have to reformat your posts once imported into Posterous. That's because Drupal does not store the filtered content in the database. I didn't have very many posts, so this wasn't a big deal, but if you are importing lots of posts then you probably want to modify the script to filter the content and add HTML formatting before sending it to Posterous.

Click here to download:
import-drupal-to-posterous.php (3 KB)

a better way to detect Java WebStart

So, just as I wrote that I wouldn't be posting much in future, I thought I would quickly post this little tidbit. There are various ways described online that you can use to detect if a client has Java WebStart installed. The problem is all of them require you to mix in VBScript for Internet Explorer and then use Javascript for the other browsers. There is a way you can support Internet Explorer and still use only Javascript. Check it out:

function jwsInstalled() {     
      // For Internet Explorer.
      if (navigator.userAgent.indexOf('MSIE') > -1) {
          try {
              var jws = new ActiveXObject('JavaWebStart.isInstalled');
              return true;
          }
          catch (e) {
              return false;
          }
      }

      // Firefox is happy with "x-java-jnlp-file". For Chrome and Safari
      // this does not work, instead I just check for "x-java-vm".
      // If they have a recent JVM installed, then they usually also have
      // Java WebStart installed.
      return navigator.mimeTypes &&
             navigator.mimeTypes.length &&
                 (navigator.mimeTypes['application/x-java-jnlp-file'] != null ||
                  navigator.mimeTypes['application/x-java-vm'] != null);
}

I use this to popup a little dialog and tell users to download a new JRE if Java WebStart is not installed. It works pretty well. And yes, it's 2009 and I'm still using Java WebStart ... although I do have a good reason for it. :-)

so it's called "printcasting"

I've been pretty busy lately and haven't worked on zinepal.com that much.

Last week I also found out about the Knight Foundation News Challenge. The Knight Foundation is a not-for-profit group that grants awards to new media and journalism projects through their News Challenge. Unfortunately the 2009 challenge closed on November 1st and I didn't have enough time to apply.

Last year the printcasting.com project was awarded a significant grant through this challenge. The interesting thing is that their ideas are pretty much exactly the same things I am trying to achieve with zinepal.com. Now I really wish I had heard about this challenge sooner.

But at least now I know what the whole concept behind zinepal.com is called: printcasting.

zinepal.com - create custom printable zines from any online content

zinepal.com is my latest project that I've been working on for half a year now. Zinepal enables you to easily create custom printable zines from any online content. While it is primarily intended for blog content it will work with any web page that provides substantial text or image content that can be isolated and reformatted for printing.

The Idea

There are two main ideas that motivated me to work on zinepal.com. The first is to bridge the gap between online media and the traditional paper media. Zinepal enables bloggers to easily make their content available as a printable zine. When readers print the blog zine the content is now reaching a whole new audience. Readers in coffee shops, on the bus, in the park ... all the places the Internet either doesn't go or is inconvenient to use. I mean, who wants to read the newspaper on their iPhone? This can create a viral effect as readers leave behind copies of the blog zine and new readers pick it up. For example, you may find a blog zine from local blogs in your favorite coffee shop, providing you with great alternative content that is relevant to you.

The other idea behind Zinepal is to cater to another group of Internet users. Currently you could broadly classify Internet users as content creators and content consumers. Content creators are the bloggers that regularly write on their blog. The consumers are the readers of blog content and other Internet news outlets. As a creator I may frequently write blog content that is not interesting to a larger audience. The consumers are now faced with the task of sorting through many blogs to find the small nuggets of content they are interested in. For example, some of my friends have hundreds of blogs in their feed readers and have to sort through all the uninteresting content to find the good stuff.

This is where the new group of Internet users comes in: the editors. As opposed to sites driven by popular opinion such as Digg or Reddit, the editors focus on their specific topics of interest and create zines based on this. As a reader I can then follow the zines of the editors I trust. I now have a human filter that does all the work of sorting through blogs for me. The advantage to the editors is the ability to gain recognition and readership for their custom zines, the same way good bloggers gain readership for their blog.

Technical Challenges

The biggest technical challenge for Zinepal was coming up with the technology to reliably extract and reformat content from all the different blogs and websites on the Internet. This was required due to the fact that most RSS or Atom feeds only include snippets of content in the feed. I've spent most of my time so far working on this technology and getting it to the point where it works reasonably well. It's still not perfect and I can think of a few more important enhancements to make, but at least for a start I think it is good enough.

Instead lately I have been focusing on the website part of Zinepal to enable users to actually start using the technology. So please, go ahead and visit zinepal.com to give it a try!

File Type Manager source code

Due to the renewed popularity of File Type Manager (mainly because of Windows Vista) I've decided to make the source code available. Maybe somebody else feels like working on this program some more. Keep in mind that I wrote this when in high school and just learning how to program, so it probably isn't the greatest code. Also it's written in Visual Basic 6. Ugh.

File Type Manager 2.0.1 Source Code

Note that I've licensed it under the LGPL. It includes an ActiveX control that displays the file types, so you could re-use that somewhere else if you wanted to.