Christopher B. Browne's Home Page
cbbrowne@acm.org

Printing Under Linux

Christopher Browne


Table of Contents
1. Frequently Asked Printing Questions
2. HP PCL References
3. Miscellaneous Printing Links
4. Printing Frameworks

1. Frequently Asked Printing Questions

This material is somewhat directed towards use with Linux, however there is none of it that cannot be trivially reapplied to other Unix-like operating systems. All of the utilities to which I make reference are available in source code form, mostly in C, and can readily be recompiled for use with other operating systems.

The gentle reader should also avail themself of the Linux Printing Web site - linuxprinting.org and the Printing HOWTO. Recent developments may be found at the VA Printing Summit; see also Grant Taylor's Summit Report

Q: Where are the printer drivers for my Frobozz WinPrinter?
Q: But Linux hackers are pretty studly and c00l d00dz. Why won't they support WinPrinters?
Q: What if the printer claims to support PCL?
Q: Are there any GDI printers that do work with Linux?
Q: What kind of printer should I buy for my Linux system?
Q: How do I get my PCL or some other non-Postscript printer to automatically handle Postscript output?
Q: How do I set up a print queue to handle Postscript for my PCL printer? I need one for text too... And one for TeX .dvi files?
Q: I want to print to a remote printer (for instance) with a JetDirect Card. I took a print queue like the one defined above, and redirected it to a remote printer. The print filters don't seem to be doing anything at all.
Q: My fonts look crummy when I use Ghostscript with my non- Postscript printer.

Q: Where are the printer drivers for my Frobozz WinPrinter?

A: These printers (also often known, rather misleadingly, as "GDI" printers) are not supported at all under Linux at this time This status is not likely to change at any point in the future.

WinPrinters are only supported under Microsoft Windows, and even then commonly only for particular versions (typically 3.1x and '95). Do not assume that drivers exist for your favorite variant, particularly if that variant is Windows NT.

Don't buy one regardless of platform. You may have to spend as much as $100 more for a "real" printer. You are better off if you do so. You will wind up with a substantially better product that you can use for years to come. I've owned 3 printers over the past 15 years. The oldest, a Mannesmann Tally Spirit 80, bought in the early 1980s, is still operational and usable to this day.

Q: But Linux hackers are pretty studly and c00l d00dz. Why won't they support WinPrinters?

A: There are two major problems that strongly discourage WinPrinter support. To explain this requires explaining a few things about WinPrinters and the architecture of printing under Microsoft Windows.

Be aware that WinPrinters are not a single sort of printer where there would be a single printer driver.

WinPrinters assume a computer system architecture where the critical design point is the Windows "GDI" API.

GDI is the programming interface Microsoft uses to render graphics for onscreen presentation. Thus far, this is (arguably) a "good" thing. If you want to print based on "What You See Is What You Get," then it is perfectly sensible to capture the information at that point and pass it, in that form, to the printing subsystem.

Note

The X Window System has not generally used such a subsystem, although Display Postscript/Display Ghostscript may become a more "open" analogue. Since X11R6.3, X does have a printing extension that works by exporting images to a special printing server, Xprt. It does not appear that many applications have been created to use this facility.

The printer manufacturers then design their printer and its interface to take data in the form of "GDI API calls," and pass it on to the printer. If this was all that there was to it, and the printer directly accepted some representation of GDI API calls, this would be fine.

However, GDI is not the control language that the printer speaks; it is an internal representation used inside Microsoft Windows. The printer driver must do a further translation, turning GDI calls into something else, where that something else is a private bitmapped format generally unique to their printer. The layer of indirection is fairly annoying, but is not yet the major problem.

  • Major Problem #1 - GDI is NOT "Open"

    It is "not open" in two senses:

    • It represents an interface that sits really fairly hidden inside Windows. It is an interface between the "graphics rendering" layer inside Windows and the printer drivers provided by printer vendors.

      That's pretty hidden inside Windows, and supposing we got documentation for it, that would be helpful for interfacing Windows to Windows print drivers, which is quite useless from a "making it work with Linux" perspective.

    • Not only is the interface in a somewhat obscure place, but vendors have not been responsive to requests for specifications.

      It is not impossible that this may be the result of agreements with Microsoft not to disclose such information, but that could be a paranoid fantasy and doesn't need to be truth.

      These certainly are cheap printers, the manufacturers certainly don't want to spend any money providing any more support than they absolutely have to, and with the low profit margins, they could care less if they lose sales of a mere few thousand printers that Linux, Macintosh, OS/2, and other systems would result in.

      The absence of specifications is quite a massive problem. Different manufacturers have created different underlying "printer control languges;" different models of printers even from the same manufacturer may have different protocols.

    If it was merely the printer control languages at issue, that would be merely an annoyance. Linux developers could reverse-engineer the formats by printing things out from Windows to a file, and examining the file carefully. However, if you do so, and then try to print the file, you may find something interesting, which is that the document may not print properly from Windows. This brings us to the second major problem.

  • Major Problem #2 - Real Time Requirements

    WinPrinters often require printer "drivers" that satisfy strict timing requirements for the transmission of data to the printer, and the manufacturers refuse to release those requirements.

    In order to save the little bit of money that you saved on the printer, they have reduced the buffers that normally can store half a page or more of data to a mere one or two raster lines. (They have omitted what probably represents $5 worth of circuitry.) As a result, printer "drivers" have to supply data at exactly the rate that the printer requires. Under Linux, printed output gets streamed to the /dev/lp device with the presumption that the device is smart enough to buffer it, and respond appropriately to indicate when the buffer is full. And that if data is delayed, the printer will wait for more data. WinPrinters have so little memory that they don't handle this very well.

    In order to get Linux to handle this would require creation of printer-specific kernel modules that are cognizant of the exact timing required by the individual printer. (This might be parameterized, but we really can't be sure. The schemes are not standardized.) Windows is doing something equivalent internally; this of course has adverse effects on system performance while printing is going on.

In short, the manufacturers have cut the prices on the printers slightly at the cost to you, the user, of providing something that is not likely to be reusable on another system, not even one running a Microsoft OS - Will they have drivers for Windows '98 or Windows NT 5.0? - and which has an adverse impact on system performance.

A: Here's perhaps the best brief description I've seen on why one should not buy a WinPrinter; Thomas M. Breuel writes:

In article 342AB307.624AB52C@a-vip.com Roland Bruns, rb@a-vip.com writes:

I have got a Seikosha GDI laser printer. Problem is GDI, so I can't use Standard drivers. Does anybody know how to run a GDI printer under Linux? Are there special GDI drivers or is it Windows only? :(

GDI printers put a lot of their intelligence into Windows-specific drivers. That is terrific for the manufacturers because they can save a few dollars on circuitry in the printer, and because they can stop supporting the printer in the next release of Windows, forcing you to throw away your perfectly good hardware. They also generally place a higher load on the system, making it more difficult to work while you are printing.

Buying one of those printers is an expensive mistake. Spend a little bit more money and buy a printer with a well-defined, standard interface and command set (PostScript, PCL, or Epson). Such a printer will likely give you reliable service for many years to come, not just with today's version of Windows.

A: Following up to the above, there's a further reason why these sorts of printer drivers don't get written: disinterest.

Developers of free software tend to develop the things that they care to develop. They "scratch" whatever "itches" they have.

Saving $100 by buying a cheap (arguably shoddy) printer, and then having to do a whole lot of development work to support it, and then running the risk that it'll break down in a year or two and not be replaceable because the manufacturer stopped making it is not exactly the sort of project to get people to shout and rejoice. As a result, such projects don't often happen.

There are of course some counterexamples. For instance, the document Adventures in Linux Programming outlines one fellow's "adventures" in successfully getting his GDI printer to work with Linux. He had to go to pretty extreme lengths, and the result was likely a lot more educational than it was practical.

Q: What if the printer claims to support PCL?

A: Be very careful if you want to consider a printer that claims to support both HP PCL and GDI.

In some cases, the box label claims that both are supported. This may not directly be true.

It is common for the PCL support to come in the form of an MS-Windows driver that converts PCL into the printer's native format. This is of no value unless you are using this driver from within Windows.

It is therefore common for the specifications to indicate Supports PCL for MS-DOS under MS-Windows or Supports MS-DOS running under MS-Windows. Those sorts of phrases should be regarded as Warning Labels, indicating that the printer is unlikely ever to be compatible with anything other than the versions of Windows marked on the box.

Q: Are there any GDI printers that do work with Linux?

A: There are a few printers that support both a "GDI mode" and an HP PCL mode that are usable with Linux and other operating systems.

HP's 5L and 6L both seem to provide a "GDI" format, but certainly work quite nicely with Linux in their PCL mode, providing the printer's full resolution and functionality in PCL mode.

HP has the Deskjet 720 and 820 that use what they call "Printing Performance Architecture (PPA)" for which Unix drivers apparently do exist.

Okidata has some laser printers that similarly support both "GDI" and PCL; they can reportedly function acceptably with Linux. Unfortunately, I hear that the PCL support only provides 300DPI resolution, whereas 600DPI resolution requires use of the Windows-only GDI control format.

These are the only exceptions of which I am aware.

Q: What kind of printer should I buy for my Linux system?

A: The answer to this is necessarily a trade-off, depending on whether you require high reliability, printing speed, low price, or some other particular functionality characteristics (such as printing in colour). I've not looked closely at colour printers; apparently the Epson Stylus series comes recommended; the 300, 400, 600, and 800 all are reported to function pretty well.

In the world of black and white, I've worked with pretty much every variety of printer that exists outside of the really high end stuff. (e.g. High speed/high resolution printers with price tags of tens of thousands of dollars...)

Common choices over the last dozen or so years include:

  • Dot Matrix/Tractor Feed printers

    They're cheap; they're necessary if working with preprinted tractor feed or multicopy form paper. Unfortunately they're noisy, pretty slow, and generally don't provide very high resolution.

    If you need one, get one. Avoid if possible.

  • Ink jet printers

    I used an HP DJ500 for many years, and was quite pleased with it. Ink jet printers require high quality paper to give decent results, and are fairly expensive to "feed," particularly for the newer colour versions. The ink has a tendancy to run, which is unfortunate. But under favorable conditions, they do provide near-laser quality. Virtually all of them speak HP's PCL language, and can be readily used with Linux.

    A decent choice overall.

  • Bubble Jet printers

    These are not terribly different from ink jets; the difference these days may merely be marketing terminology. Behaviour is very similar to ink jets, with the caveat that many of the newer ones do not support other than "Windows 3.x and 95" operating systems. Like the ink jets, paper and ink costs make for a fairly high per-page cost, making up somewhat for the cheap price.

    Cheaper than the Ink jets, these are often quite usable.

  • PCL-based Laser Printers

    I presently use an HP5L laser printer of this variety; this class of printers is my favorite variety to hook to networks. Many of these printers permit dropping in a "print server" card, allowing you to put the printer on an Ethernet network and print from a variety of computers. These printers provide good results with cheap photocopier paper; toner cartridges are individually expensive, but handle thousands of pages making for low per-page costs. They're generally much faster than ink/bubble jet printers, and generally provide better output even with cheap paper.

    The HP6L is also reported to work nicely in 600DPI mode with Linux with Ghostscript and the ljet4 device driver ( Gunars Lucans )

  • Postscript Laser Printers

    These are the "Cadillacs" of printers; generally flush with memory, fast, and highly compatible with all sorts of computer systems. They tend to be priced several hundred dollars higher than their PCL brethren, which is a difficult premium to justify for home use. But I've specified them for clients for use on commercial LANs as the cost is readily justified by the improved robustness in a commercial environment.

    For home use, it is readily arguable that it would be more effective to buy a PCL printer, spend (say) $50 of the savings on extra memory for the host that the printer is connected to, and run Ghostscript on that system to translate Postscript into PCL . With the added benefit that the memory can be used for other things when you're not printing anything, thus improving overall system performance.

  • GDI Laser Printers

    As discussed under Where are the printer drivers for my <em>Frobozz</em> WinPrinter? these are a completely inappropriate choice, as they do not work under Linux. I would disrecommend them for use even for those people that are using MS-Windows, as they involve serious functionality compromises.

    A completely horrible choice.

    For more canonical/authoritative information on GDI, see Microsoft SDK docs on Windows GDI

A: Quite a lot of additional printer drivers have been created over the last few years, largely associated with "spin-off" projects that add drivers to Ghostscript

The projects include the following:

Q: How do I get my PCL or some other non-Postscript printer to automatically handle Postscript output?

A: Many, many, many Unix-based programs assume you have a Postscript printer.

The program Ghostscript can be used to convert Postscript into the formats required by a fairly wide variety of printing devices, including PCL , various Epson formats, some graphics formats such as JPEG and TIFF, and Group 3 fax. (And that's just off the top of my head; those are just the most commonly used ones.)

If you have data in Postscript form, it can be filtered through Ghostscript to get something that these sorts of printers can natively recognize.

The documentation to Ghostscript provides ample samples of how to integrate this into a print queue; if I present an "integration" example here, it may not work consistently with your version of Ghostscript . Read Your Famous Documentation!

Briefly, if I have a file, test.ps that I want to test out, I'll try the following with my HP5L: gs -sDEVICE=ljet4 -sOutputFile=test.lj - < test.ps

[various messages likely occur, including a list of what fonts Ghostscript goes off and reads...]

lpr test.lj

I suggest this sort of approach for testing out documents that you may be having problems printing; for general printing, I suggest using one of the "magic filters" described next, as they provide a fundamentally more powerful approach.

Q: How do I set up a print queue to handle Postscript for my PCL printer? I need one for text too... And one for TeX .dvi files?

A: Some people have come up with a really clever idea that avoids the need for a proliferation of print queues that is commonly called a magic filter.

The idea is that you hook up a filter to the print queue that recognizes what kind of file you are trying to print, and automatically invokes translation programs to turn the file into the format that your printer can handle.

The model:

  • The user sends a file to the print queue.

  • The print system invokes the magic filter.

  • The filter detects the type of file.

  • The filter typically invokes the appropriate converter (or perhaps a sequence of several converters) to convert the file to PostScript.

  • Ghostscript is then run on the converted file.

  • The resulting output, ready for your printer, is submitted to the printer.

All of these operations are transparent to the user. It works well because most file types that are printable have a PostScript converter.

For instance, if you're using a PCL printer:

  • Postscript output could be processed using Ghostscript into PCL

  • .dvi files, produced by TeX (or groff) would be processed using dvips, and passed back to be recognized as Postscript (and then processed using Ghostscript )

  • TeX files could be processed using TeX, producing .dvi files. These would then be fed back in, getting turned into Postscript and then PCL...

  • Images in GIF, JPEG, TIFF, PBM, and many other formats can be translated into Postscript using the NetPBM utilities, and then passed back to be handled using Ghostscript ...

  • Manual pages could be processed using GROFF, producing .dvi data, to be passed back in, ...

  • ASCII text can be processed to avoid the "staircase effect," and then passed on through...

  • PCL data can be recognized and passed thru...

  • And other automagical stuff...

Q: I want to print to a remote printer (for instance) with a JetDirect Card. I took a print queue like the one defined above, and redirected it to a remote printer. The print filters don't seem to be doing anything at all.

A: The LPD protocol assumes that filtering is to be done on the final host at which printing takes place. If the final host is a "dumb" print server, then there's nothing there to do the filtering. Here's a sample of how one might go about setting this all up...

I'll presume here that you have two hosts:

  • A Linux box, on which you can install magicfilter. The hostname is "linux.example.org."

  • A remote HP Jet Direct print server that has a queue that talks to an HP LJ4. The hostname is "printhost.example.org," and the queue is called "raw".

  • Install magicfilter or its equivalent on linux.example.org. On my system, this gives me some filters in /usr/lib/magicfilter. The important one is called ljet4-filter.

  • Create an additional filter in /usr/lib/magicfilter

    Its purpose is to turn print jobs from whatever format they started in into PCL5, using magicfilter, and then to pass it on to a print queue (-Plj4) that references the print server.

        #!/bin/sh
        cat | /usr/lib/magicfilter/ljet4-filter | lpr -Plj4

  • Create two print queues on linux.example.org, with /etc/printcap entries looking like:

        # /etc/printcap
        lp|processmagic:\
          :sd=/var/spool/lpd/magic:\
          :mx#0:\
          :if=/usr/lib/magicfilter/my-filter:\
          :lp=/dev/null:
        # Sample Printcap entry for a HP JetDirect card
        lp|mcps|mecaps|Meca Lab HP IIIs (Postscript):\
          :lp=/dev/null:
          :sd=/var/spool/lpd/lp4:\
          :rm=printhost.example.org:\
          :mx#0:\
          :sh:\
          :sf:

  • Test the lp4 queue using some "raw" PCL to see if it works.

    For instance, if you've got a Postscript file, you might try: gs -sDEVICE=ljet4 -sOutputFile=sample.pcl - < sample.ps lpr -Plp4 sample.pcl

    Make sure that works first.

  • Then you may want to stop the ljet4 queue so that files build up there, and print some jobs via: lpr -Pprocessmagic sample.ps

    This should translate the file using magicfilter into PCL, and put an entry into the queue for lp4.

Once you get this working, you can have any number of machines with /etc/printcap looking like:

    magic:\
       :sd=/var/spool/lpd/magic:\
       :mx#0:\
       :rm=linux.example.org:\
       :rp=processmagic:\
       :lp=/dev/null:

On any of these other hosts, lpr -Pmagic somefile.somewhere

will punt the print jobs to the magic queue on linux.example.org , which will filter it into PCL and pass it on to the lp4 queue on linux.example.org, which will send it over to the print server to actually print it.

If you want to have the printer connected to the Linux box, then things obviously simplify. The lp4 can be redefined to reference the local printer. (Actually, it can get folded together into the magic entry, but who's counting print queues?)

The creation of newer LPR clients arguably makes this approach obsolete, as the LPR clients can do the filtering. This approach is still useful if you're:

  • Using software that passes data straight to LPD print queues,

  • On a Unix systems where you need to use a traditional LPR implementation,

  • Submitting from a "box" where it's not reasonable to do the filtering locally,

  • Wanting to explicitly split the processing apart, creating data on one "box" and filtering it on another. Call this "multi-tier client/server computing."

  • I want to do "load balancing;" I have three identical printers, with print queues called realprinter1, realprinter2, and realprinter3, and would like to keep them as busy as possible.

    Create another print queue called "anyprinter" with an /etc/printcap entry that looks like:

        anyprinter:\
          :sd=/var/spool/lpd/anyprinter:\
          :mx#0:\
          :if=/usr/lib/magicfilter/any-filter:\
          :lp=/dev/null:

    where /usr/lib/magicfilter/any-filter is a script that looks like the following:

        #!/usr/bin/perl
        # Print filter...
        # Figure out which queue to drop data to...
        $size1 = `lpq -Prealprinter1 | wc`;
        $size2 = `lpq -Prealprinter2 | wc`;
        $size3 = `lpq -Prealprinter3 | wc`;
        
        # Pick the queue with the smallest number of entries
        $proposed = "1"; $size = $size1;
        if ($size > $size2) {
         $proposed = "2"; size = $size2;
        }
        if ($size > $size3) {
         $proposed = "3"; size = $size3;
        }
        
        open(OUT, "|lpr -Prealprinter$proposed ");
        while ($line = <>) {
         print OUT $line;
        }

    More sophisticated analysis could be done on "queue size;" it might be better to examine the total sizes of jobs on the three queues, and assign new jobs to the queue with the least "outstanding material." If the queues are consistently busy, there should be little difference.

    The "worst case" is if two "really huge" jobs that might each occupy the printer for on the order of hours both get dropped into one queue, and then other queues run out of material, thus meaning that jobs are waiting whilst queues remain empty.

    An arguably-better alternative would be for jobs to "block" in the anyprinter queue until one of the real print queues become free, only being submitted when a queue is available. This could be done by changing the script to the following:

        #!/usr/bin/perl
        # Print filter...
        $done = "N";
        while ($done eq "N") {
         $size1 = `lpq -Prealprinter1 | wc`;
         if ($size1 <= 1) {
          @print_out("realprinter1");
          $done = "Y";
         }
         $size2 = `lpq -Prealprinter2 | wc`;
         if ($size2 <= 1) {
          @print_out("realprinter2");
          $done = "Y";
         }
         $size3 = `lpq -Prealprinter3 | wc`;
         if ($size3 <= 1) {
          @print_out("realprinter3");
          $done = "Y";
         }
         if ($done eq "N") {
          sleep 10; # Wait a little while...
         }
        }
        
        # Print the job...
        sub print_out {
         my($printer) = @_;
         open(OUT, "|lpr -P$printer ");
         while ($line = <>) {
          print OUT $line;
         }
        }

  • I'm trying to run a program designed for "generic Unix" that expects to use lp to print things rather than lpr.

    The "free" Unix-like operating systems all commonly use the RFC 1179 - LPD Daemon protocol to handle print queues.

    System 5 Unix, and other systems based on it use a different system called LP.

    A cursory comparison would suggest that LPD is a simpler protocol, less suited for "complex" printing requirements. LP provides a more sophisticated set of tools for controlling printers and their behaviour (including things such as tray, form, form factor, and format selection). This must be tempered by the consideration that LPD allows use of general Unix filters in print stream processing.

    In reality, they are of pretty similar "power," it's just that LP probably provides, by default, a few more "control switches" than LPD.

    Another difference is that it doesn't appear that LP provides a natural networked protocol for printing to remote hosts. That being said, decent LP implementations will typically provide a way to do this, probably by using the LPD protocol... This last difference that strongly encourages use of LPD is the fact that many companies sell "print servers" that grok the LPD protocol. Far fewer are compatible with LP.

    The only implementations of LP that I know of are commercial packages based on the code that once belonged to ATT, once owner of Unix. There never has been an IETF standard for LP, unlike LPD, and there was little incentive to recreate LP for the "free" world. (Much as there was not much incentive to recreate SCCS when the free RCS revision control software was available and good.)

Q: My fonts look crummy when I use Ghostscript with my non- Postscript printer.

A:

Note

This used to be a common problem; due to font upgrades, it shouldn't be a common problem for Linux users anymore.

There has been a common complaint that things printed using Ghostscript "look lousy." This was the result of the fact that Ghostscript came with a set of free bitmapped fonts that don't scale well. This wasn't the fault of the Ghostscript software; it's merely that nobody had made any decent "Adobe 35" substitute fonts freely available.

As of version 4.03, Ghostscript includes a set of nicely scalable T1 fonts compatible with the "Traditional Adobe 35 fonts":

These fonts were contributed by: URW++ Design and Development Incorporated, Poppenbuetteler Bogen 29A, D-22399 Hamburg, Germany, tel. +49 (40) 60 60 50, fax +49 (40) 60 60 51 11.

Look for the Ghostscript FAQ for more details.

If you upgrade to a recent version of Ghostscript and get a recent set of fonts, this will resolve the problem.

Google

If this was useful, let others know by an Affero rating

Contact me at cbbrowne@acm.org