Creating the Gutenprint based printer driver

Article contributed by laplace on Sun, 2010-12-19 08:27

Gutenprint is a suite of printer drivers that can be used with UNIX and Linux print spooling systems, such as CUPS (Common UNIX Printing System), lpr, LPRng, and others. Gutenprint currently supports over 700 printer models.

Gutenprint was recently ported to Haiku, both increasing its printing capabilities, as well as extending its supported printer models. This article describes Gutenprint and the effort to port it to Haiku.

Extending the Haiku printer driver framework

Libprint, the printer driver framework, is used by native printer drivers such as Canon LIPS 3 and 4, HP PCL5 and PCL6, and Adobe PostScript. Exceptions are the Preview and the PDF printer driver.

This framework makes it very easy to add a new printer driver to Haiku. It provides the user interface for the page setup dialog, the print job setup dialog and a preview window. It performs the rendering of the page as a sequence of bitmap bands. The printer driver then converts the bitmap bands to a stream of data in a format that is understood by each printer.

The setup dialogs provide a fixed set of settings whose value ranges are configurable to match specific printer drivers. For example whether a printer is a color printer and the available paper sizes (Letter, A4, ...).

The page setup dialog in Figure 1 shows the values for paper size and resolution from Gutenprint.


Figure 1: Page Setup Dialog.

Gutenprint contains a meta model for the available settings of a printer model. Some of these settings can be mapped to existing settings provided by libprint. For the missing settings libprint had to be extended to show them in the job setup dialog and to persist them in the job settings.
Now libprint supports the following type of settings: A list of values visualized as a combo box, a boolean flag visualized as a check box and a value in a range of values visualized as a slider.

Figure 2 shows the job setup dialog. The settings inside the red rectangle are the missing settings from Gutenprint.


Figure 2: Job Setup Dialog.

Gutenprint categorizes settings from basic to advanced. In the printer driver only the basic settings are enabled. When the advanced settings are enabled there are so many that the setup dialog would get too large to fit on most screens because of a bug in the Layout API. As soon as this bug is fixed the advanced settings can be enabled.

Porting Gutenprint

Gutenprint consists at least of the core library, a GTK user interface, and support for CUPS, foomatic, GIMP and Ghostscript.

For the printer driver, only the core library is required. The Gutenprint core library provides an API to query the available printer models, to query and modify the printer model specific settings, and to convert an image on a page into a stream of printer specific data.

Porting Gutenprint to Haiku was relatively easy. The core built without any problems with both GCC2 and GCC4 once the configuration files had been created.
Gutenprint uses the "configure" script to support building on different platforms and in differnt configurations but the script does not support Haiku yet. So building on Haiku did not work at first. Since I did not have the knowledge of how to get the configure script working on Haiku, and I did not want to waste too much time in getting it to build, I decided to first try to build Gutenprint on OpenSuSE. There was no problem with that build. The configure script generated header and make files. In the header files macros are used for the configuration of the Gutenprint build.

After adapting the header files for Haiku and creating Jamfiles, the port was completed!

At runtime Gutenprint needs some data files that are part of Gutenprint source code repository. When the Haiku image is created these data files needed to be copied to the image as well. For example the list of printer models is stored in an XML file printers.xml.

Writing the printer driver

Since I had written native Haiku printer drivers using libprint in the past I am familiar with the printer driver framework. The driver was implemented step by step. After each step the added functionality could be tested. The steps outlined here might not be in chronological order.

I started with a printer driver skeleton by copying an existing driver and the removing the printer driver specific source code. The driver could be built soon but did not generate any output yet.

First the printer model selection dialog was implemented. Thanks to Ithamar R. Adema who implemented such a dialog for the PostScript driver, the user interface was already available as depicted in figure 3. Only the printer manufacturer and model had to be obtained from Gutenprint.


Figure 3: Printer Model Selection Dialog.

Then the settings needed for libprint where obtained from Gutenprint. At this point in time the other Gutenprint generic settings weren't supported yet. These were implemented in the last step.

At this step, the printer still did nothing. The bitmap bands for a page needed to be handed over to Gutenprint. Figure 4 shows an illustration of an image on a page. When all bitmap bands for a page are available Gutenprint is requested to print an image on the page. The position and size of the image are set and then Gutenprint uses a callback mechanism to request the size of the image in pixels and gets the pixels for the image to be printed line by line. The pixels are always encoded in RGB 8 bits per channel. For black and white printing Gutenprint is responsible for doing the color conversion. The maximum number of bytes temporarily required for a page in letter size in 300 DPI should be about 32 MiB and for 600 DPI it should be about 128 MiB. On modern hardware that should not be a problem.


Figure 4: The page with printable rectangle and an image enclosing the bitmap bands.

The bitmap band to Gutenprint image conversion worked on the second attempt printing a test page.
I had quite some difficulties to get the image positioning and size calculation right, as the unit is 1/72 Inches and the internal unit is 1/dpi where dpi is the currently selected resolution and at first I wanted it to be as exact as possible. The position and size should be a multiple of the greatest common divisor of 72 and dpi. However that is not always possible without truncation of the output image, because Gutenprint does not allow to place an image outside the printable rectangle (there is usually a margin of more or less 10/72 Inch around the paper where printing is not possible).
Now a not so accurate solution is implemented that stays within the paper margin limits, that seems to work good enough.

During the work on the Gutenprint driver most of the printing related user interfaces were updated to use the Layout API. This gets rid of font size sensitivity issues.
Also some bugs were fixed in the USB transport add-on and in libprint where the page contents did not rotate printing in landscape mode.

Lines of Code

The following table shows the lines of codes in revision 39800 of the header files, source files, their sum and the percentage of the sum to the total number of lines. The lines of codes includes empty lines and comments.

Component