Citrix Internship
Matthew Johnson
JICA Universal Printer Driver
This is what I've been doing for the last 11 weeks of my holiday, mostly working
on the Universal Printer Driver for the Java ICA Client
ICA Printing
MetaFrame applications need to be able to print to client-attached
printers. However:
This used to be done by installing the printer driver on the MetaFrame server,
and sending raw data to the printer on the client. However:
- Buggy drivers crash server
- Java can't easily detect drivers
Until now you have been having to enter the printer driver name by hand,
which isn't always obvious
- Some printers don't have drivers on the server
Universal Printer Driver
We want a server driver that will work for all client printers.
- Based on the fact that client printers always have drivers on the client.
- Use a generic driver on the server that is known good, and push that format to the client. HP's PCL language was chosen for this.
- However, the clients need to be able to render PCL to the local driver format on the client.
- There is also a generic PostScript driver if the client has a PostScript compatible printer
This will also be used for Operating Systems which support PostScript natively, such as Linux
However...
- The Java Client has no support for UPD, and Java cannot itself print PCL
This was the situation when I started, and the brief I was given was to write
such a driver for the JICA client.
I spent much of my first week investigating what APIs Java provided for printing,
and what was involved in rendering PCL.
Printing in Java
Printing is done by drawing into a Graphics2D object,
so I have written a renderer to take PCL, parse it in Java,
and then draw the result to a Graphics2D object. This is
connected to the printer.
The interface is actually the same no matter what you are rendering the
graphics to. This makes it very easy to test the renderer without having to print.
The Graphics2D API provides interfaces for
- Drawing scaled & transformed rasters
- Automatic coordinate system transforms
- No need to buffer full-page images
These made several things a lot easier than they might have been
and mean that the file we produce is relatively efficient
- Built-in vector graphics rendering (UPD-2)
- Rendering of TrueType fonts (UPD-2)
Since I only had time to implement UPD-1 (PCL 4) rendering, I didn't
use these, however they will be very useful in extending the UPD in
later releases of JICA to support HP/GL graphics and TrueType fonts.
You can see here my code rendering a printed page from IE into a pane of a window in Java.
This was the test-harness I used for a lot of my testing
The Driver Architecture
This is how I designed the Printer driver. I tried to keep it fast and simple,
but yet also generic enough to handle all the PCL 5 features.
- Simple
- Extensible
- Modularised
- Object Oriented
Architecture - Extensible
I designed the UPD to be extensible from PCL 4 to the more advanced PCL 5, so
that it could be easily extended in the future.
Architecture - Modularised
The driver is broken into two parts, the parser, and the renderer.
The parser is a standard recursive-descent style parser,
which takes the PCL and returns a stream of objects representing
all the commands or streams of character codes in the PCL.
These then get passed to the rendering layer, which executes the
commands in the order they are passed and performs caching for
multiple passes.
Java uses a multi-pass approach to printing, so my renderer gets called
multiple times per page. It uses a lot of caching of the command objects,
and of the images they produce to speed up multiple passes of each page.
This has some amount of memory overhead, but most of the data requires caching
over the length of one page anyway for transparency checking.
There are several caches in use, but the use of references allows the data
to only be stored once, and be referenced multiple times.
Architecture - OO
The code for the renderer is implemented via methods in the stateless
stream of objects, and state is held in an environment object, which
holds a Hashtable of various values, and is used to hold state for
multi-command items (like raster graphics).
There is a hierarchy of data classes which allows up-casting
to make the controlling methods very general
The right hand tree is the important one, where all the classes
for the parts of the PCL stream are represented.
The result
- 5000 lines of code
The majority of which got written in about 4 weeks, a lot of time
was spent producing little volume of code, but working out some
particularly annoying bugs.
- Enabled UPD printing to non-PostScript printers on Windows
Unix platforms can usually process PostScript natively in their
printing layer, so can all use the PostScript UPD.
- Slightly slower than the Windows native client
- Smaller resulting print job than Windows native client
The JICA UPD should improve noticeably over the Windows native client one
when comparing UPD-2. The Windows client has to do a lot more by hand, when
the Java one can use the Graphics2D API directly. Most of these features aren't
used by the current, PCL 4, driver.
- Graphics2D allows Java to perform some optimisations
- Easily extensible to UPD-2 in future releases
And since just before FFB last week,
- Included in the Hudson release of the Java ICA client
The test team are currently running tests of the latest build of Hudson,
which includes UPD support. Thankfully there haven't been very many CPRs
yet (-:
Problems 1PCL Specifications
- I was working from a PCL 5 spec, trying to implement a PCL 4 driver.
- Very old original spec
- Aggregated from all versions of PCL
This was very annoying. The PCL standard appears very badly designed, mostly because
it has evolved from all the previous versions of the standard, and hence has a lot
of obsolete parts, and there are some rather obscure things for compatibility reasons.
Problems 2Java
- Inefficient printing of native transparency
- Had to be implemented by hand
There are facilities for doing 1bbp transparency in Java, which I needed, but
they are very inefficient, taking up to 10 times as long and producing 10 times
the size of printer file as doing the same thing by hand, which is what I did.
- Programmatic errors in Graphics2D
- Clipping and margins
- Still unsolved problems - reporting bugs to Sun
We are reporting these as bugs to Sun, since they are reproducible in test programs,
and at the moment they are unresolved, and produce small, but unfortunately noticeable,
errors in the print. The effect is mainly noticeable when printing landscape.
Working in Citrix
I've thoroughly enjoyed working at Citrix. Some of the things which have highlighted this are:
- Choice of working tools:
Being allowed to use Debian GNU/Linux and vim to do development, has made me a lot more
comfortable and made it easier to be productive, since it is what I am used to using.
- Recreation;
The facilities Citrix provide for employees are excellent - the provision of food, pool tables etc
makes it an enjoyable place to work
- Friendly People:
Everyone is very friendly and helpful - particularly in my group. This creates a good working atmosphere,
and was nice to encounter.
Things I've Learnt
- My knowledge of Java, and the tools we were using has been extended
- Encouraging that I could do what initially seemed quite a large and fairly complicated project
- I Would definitely recommend it to others looking for an internship
Just to keep Tosha happy:Farah Fawcett