Tech Notes

Tech Note #20130005

There are many older Postscript printers deployed in the field and still in use today, that only support Postscript 1. As well, there may be Postscript 3 printers deployed, whose idea of Postscript 3 does not exactly match the idea of the protocol that is currently implemented by CUPS.

When one attempts to print to one of these printers, using CUPS, the Postscript that is generated and sent to the printer can cause it to hang or crash. Quite often, one is given little clue as to what is happening, since all of the filters in the conversion/filter chain work properly and legitimate-looking output is generated if one uses cupsfilter to run the filter chain directly.

It is only when the generated output is sent to the printer that it fails. Often, an initial chunk of the Postscript file is sent to the printer with no problems and then the printer hangs. If the backend program is run directly, one can see the Postscript file being sent to the printer with no issues until it hangs.

Alternately, the Postscript that is generated can be sent to the printer without problems but the rendered image is incorrect. A classic example is the PDF-based printer test page which prints a black square where the CUPS logo should appear.

Problem Description:

Following the new PDF workflow scheme implemented by Canonical under the scope of The OpenPrinting Project, most files that are to be printed by CUPS are first converted into PDF files (this applies to plain text files, for example). The resulting PDF files must then be converted to postscript, since postscript is the coin of the realm or, if you prefer, lingua franca of CUPS-based printing.

The work of converting PDF files to Postscript files is undertaken by the pdftops filter, which is actually just a frontend that invokes one of a number of programs to do the actual conversion of the PDF input to Postscript output. Currently, the choices for actual conversion programs are Ghostscript, Poppler or Acrobat.

The pdftops filter reads the PPD that is associated with the printer. Using the information found in the PPD, it selects the actual conversion program to use and the options to pass that program so that the PDF input is converted to Postscript output that the printer can print. To make a long story short, this apparently doesn't work. Particularly in the case of Ghostscript, the generated Postscript can be Postscript 3 of a sort that Postscript 1 printers can't hack and that some Postscript 3 printers can't hack, for that matter, either.

In other cases, the size of the generated Postscript can be extremely large, thereby resulting in excessive transmission times when the Postscript file is sent to the printer. Or, the Postscript will print without any seeming problems but the printer will fail to render the page properly.

Problem Resolution:

We have modified the source for the pdftops program that is included in Version 1.0.34 of the filters supplied by The OpenPrinting Project. The modified file, pdftops-1.0.34.c.gz, can be downloaded and dropped into your filters build tree. If you have a different version of the filters, you can examine the downloaded source and look for the lines that are marked "//ew". Find the matching lines in your version of pdftops.c and apply the changes to your source.

We have described elsewhere, in Tech_20130003, how to obtain and build the filters source from The OpenPrinting Project. We'll assume that you've followed those instructions and are now ready to build the pdftops filter. Build it like this:

cd cups-filters-1.0.34
make pdftops

Once the pdftops filter is built, we can install it into the CUPS filters directory like this:

su
cp pdftops /usr/lib/cups/filter

The modified pdftops supports an extra parameter "gs1". This is in addition to the original "gs", "pdftops" and "acroread" parameters that it already supported. We didn't test the "acroread" parameter but between the first three, we now have a range of options that can be used to govern the type of Postscript that is generated. Hopefully, one or more of them might work. The choices are:

gs  Produces intermediate-sized files, using the ps2write output device of Ghostscript. Presumably, these are Postscript 3 files, if the printer claims to support it. These files crashed older Postscript printers.
   
gs1  For text files, produces reasonably-sized files. For the PDF-based printer test page (i.e. a page with images), produced a 35MB (i.e. huge) file that took about 10 minutes to transmit to the printer and render. Uses the pswrite output device of Ghostscript. These are Postscript 1 files which always print and render properly on older Postscript printers. Perfect for text and may, despite the slow speed, be your only option for images.
   
pdftops  For text files, produces reasonably-sized files. For the PDF-based printer test page (i.e. a page with images), produced a 150K file that transmitted smartly to the printer and printed right away. Unfortunately, the image didn't render properly with some images being replaced by a solid black square. Uses the pdftops Poppler program. The default is to produce Postscript 2 files which seem to print on older Postscript printers. If all you are interested in is text printing (i.e. no images), the print will render properly and this may be your best choice.

We're now in a position to do some tests to see which Postscript conversion methods might produce printer Postscript files that our printers are willing to accept. To test this, we pass the name of the converter to pdftops using the pdftops-renderer option. If you have the PDF-based printer test page hanging around, you can use it for the test like this:

cupsfilter -i application/vnd.cups-pdf-banner -m printer/foo \
  -o pdftops-renderer=gs -p /etc/cups/ppd/Laser.ppd \
  /usr/share/cups/data/testprint.pdf \
  >/home/jschmoe/testprint-rendergs.ps

This will give us the PDF-based test page rendered with Ghostscript as Postscript 3. Next, we can try Poppler:

cupsfilter -i application/vnd.cups-pdf-banner -m printer/foo \
  -o pdftops-renderer=pdftops -p /etc/cups/ppd/Laser.ppd \
  /usr/share/cups/data/testprint.pdf \
  >/home/jschmoe/testprint-renderpop.ps

Poppler renders by default as Postscript 2. Finally, we can try Ghostscript again:

cupsfilter -i application/vnd.cups-pdf-banner -m printer/foo \
  -o pdftops-renderer=gs1 -p /etc/cups/ppd/Laser.ppd \
  /usr/share/cups/data/testprint.pdf \
  >/home/jschmoe/testprint-rendergs1.ps

You'll end up with three test files. We used the PDF-based printer test page because it contains images and images are hardest on Postscript 1. You can compare the file sizes and see what the worst case will be like.

The next step is to send each of the files to the printer and see which ones work. To send convereted printer Postscript files directly to the printer, do something like this:

DEVICE_URI="lpd://prtserv/MyLaser" /usr/lib/cups/backend/lpd 1234 \
  jschmoe "Test lpd backend" 1 "" \
  /home/jschmoe/testprint-rendergs1.ps

Using this method, you can watch the print job's progress as the convereted printer Postscript file is sent directly to the printer. If it hangs at exactly the same percentage and doesn't continue within a few seconds, you know that the conversion generates Postscript that chokes the printer. Note that, after a print job chokes the pritner, you may want to power it off and back on, to ensure a hard reset, before sending it the next test. It couldn't hurt.

Assuming that you hit upon a rendering parameter that works for your printer, you can permanently set this value for the printer using the lpadmin command, for example like this:

lpadmin -p MyLaser -o pdftops-renderer-default=gs1

Alternately, if you don't prefer to have lpadmin monkey with your printers.conf file, and particularly you don't want it removing all of the comments that you've annotated it with, you can edit /etc/cups/printers.conf directly with your favorite text editor. Shut down the CUPS scheduler first and then set the printer parameter like this:

<DefaultPrinter MyLaser>
       .
       .
       .
  Option pdftops-renderer gs1
       .
       .
       .
  </Printer>

Once the parameter is set, restart the CUPS scheduler to see if the choice of renderer makes a difference.

If you don't hit upon a rendering method that works for your printer, you could try some more options on the Ghostscript or Poppler commands. Use the modifications made to pdftops.c for the gs1 option as a guide to how to do it.