Porting Gutenprint-based Printer Drivers to Haiku

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 .h .cpp .h + .cpp Percentage
Gutenprint (libgutenprint) 5.720 45.413 51.133 77,7%
Haiku printer driver framework (libprint)

3.202 8.418 11.620 17,7%
Haiku Gutenprint printer driver (Gutenprint) 689 2.344 3.033 4,6%
Total 9.611 56.175 65.786 100%

Table 1: Lines of Codes.

For the extension of libprint about 1538 lines were added.

Not all lines were new code because the code style in libprint was changed to conform to the

Haiku coding style.

The total number of lines increased between revision 36173

and 39800 in libprint and

Gutenprint printer driver to 4.571.

Copyright 2010 Michael Pfeiffer (a.k.a. laplace)

Lector: Andrew Hudson

This article will be also hosted at haiku-os.org

43 Comments

  1. 2010-12-23 1:08 am
  2. 2010-12-23 1:19 am
    • 2010-12-23 1:26 am
    • 2010-12-23 1:32 am
      • 2010-12-23 6:58 am
  3. 2010-12-23 1:43 am
    • 2010-12-23 9:54 pm
      • 2010-12-24 3:33 am
        • 2010-12-24 5:15 am
          • 2010-12-24 4:37 pm
          • 2010-12-24 4:51 pm
          • 2010-12-24 8:27 pm
        • 2010-12-24 12:26 pm
          • 2010-12-25 12:15 am
    • 2010-12-24 8:51 pm
      • 2010-12-24 9:36 pm
        • 2010-12-25 9:29 am
          • 2010-12-26 2:57 am
          • 2010-12-26 9:42 am
          • 2010-12-27 10:14 pm
          • 2010-12-28 4:22 am
          • 2010-12-28 6:04 pm
  4. 2010-12-23 2:02 am
    • 2010-12-23 5:20 am
      • 2010-12-23 7:00 am
        • 2010-12-23 1:46 pm
        • 2010-12-23 6:17 pm
          • 2010-12-24 3:41 am
  5. 2010-12-23 10:00 am
    • 2010-12-23 10:21 am
      • 2010-12-23 10:47 am
        • 2010-12-23 3:08 pm
        • 2010-12-23 6:02 pm
    • 2010-12-23 10:55 am
      • 2010-12-23 11:09 am
  6. 2010-12-24 3:11 am
    • 2010-12-24 4:26 am
  7. 2010-12-24 5:53 pm
    • 2010-12-24 8:52 pm
      • 2010-12-24 9:13 pm
        • 2010-12-24 10:23 pm
          • 2010-12-27 12:09 am
  8. 2010-12-24 10:43 pm