4.20. GhostScript and the ifhp Filter

We saw in previous sections how to use GhostScript for format conversion. We will now explore more of the functionality of GhostScript and how it is integrated into the ifhp filter. We will choose a simple example: providing support for printing PostScript on an HP DeskJet 660 color printer.

We start by determining the options that GhostScript would need to do the format conversion. The gs --help option lists the output devices your version of GhostScript supports:

    h4: {208} % gs --help
    GNU GhostScript 5.10 (1998-12-17)
    Copyright (C) 1997 Aladdin Enterprises, Menlo Park, CA.  All rights reserved.
    Usage: gs [switches] [file1.ps file2.ps ...]
    Most frequently used switches: (you can use # in place of =)
     -dNOPAUSE           no pause after page   | -q       `quiet', fewer messages
     -g<width>x<height>  page size in pixels   | -r<res>  pixels/inch resolution
     -sDEVICE=<devname>  select device         | -dBATCH  exit after last file
     -sOutputFile=<file> select output file: - for stdout, |command for pipe,
                                             embed %d or %ld for page #
    Input formats: PostScript PostScriptLevel1 PostScriptLevel2 PDF
    Available devices:
       x11 x11alpha x11cmyk x11mono sxlcrt ap3250 appledmp bj10e bj200 bjc600
       bjc800 cdeskjet cdjcolor cdjmono cdj500 cdj550 cp50 declj250 deskjet
       djet500c dnj650c epson eps9mid eps9high epsonc ibmpro imagen iwhi iwlo
       iwlq jetp3852 laserjet la50 la70 la75 la75plus lbp8 lips3 ln03 lj250
       ljet2p ljet3 ljet3d ljet4 lj4dith ljetplus lp2563 m8510 necp6 oce9050
       oki182 paintjet pj pjetxl pjxl pjxl300 r4081 sj48 st800 stcolor t4693d2
       t4693d4 t4693d8 tek4696 xes dfaxhigh dfaxlow faxg3 faxg32d faxg4 tiffcrle
       tiffg3 tiffg32d tiffg4 bmpmono bmp16 bmp256 bmp16m cgmmono cgm8 cgm24 cif
       mgrmono mgrgray2 mgrgray4 mgrgray8 mgr4 mgr8 pcxmono pcxgray pcx16 pcx256
       pcx24b psmono pbm pbmraw pgm pgmraw pgnm pgnmraw pnm pnmraw ppm ppmraw
       sgirgb tifflzw tiffpack tiff12nc tiff24nc bit bitrgb bitcmyk pngmono
       pnggray png16 png256 png16m pdfwrite nullpage
    Search path:
       . : /usr/share/ghostscript/5.10 :
       /usr/share/ghostscript/fonts
    For more information, see /usr/share/ghostscript/5.10/doc/use.txt.
    Report bugs to ghost@aladdin.com; use the form in bug-form.txt.


As you can see, these names are not very intuitive, but the GhostScript printer support documentation at http://www.cs.wisc.edu/~ghost/printer.html or the documentation shipped with the GhostScript distribution has much more detail. We discover from this documentation that the cd550 driver supports a wide range of printers:

    cdj550
      HP DeskJet 550C (3.53)
      HP DeskJet 560C (3.53)
      HP DeskJet 600 (5.10) black (1bit/pixel) and color (32bit/pixel)
      HP DeskJet 660C (3.53)
      HP DeskJet 660C (5.10)
      HP DeskJet 682C (4.01) Use gamma=0.3
      HP DeskJet 683C (3.33, 4.03)
      HP DeskJet 693C (4.03) 24bit/pixel Is this a CMY or a CMYK printer?
        Probably CMYK in which case 32bit/pixel can be used.
      HP DeskJet 694C (5.03) Works in color. 690C, 692C, 693C and 694C
         are all software variations.
      HP DeskJet 695C (5.50) Works in color.
      HP DeskJet 850 (3.53) 300dpi CMYK (32bit/pixel) See also cdj850.
      HP DeskJet 870Cse (4.03) (16 or 32 bits/pixel) Use ljet4 device for B/W.
         See also cdj850.
      HP DeskJet 895Cxi (5.03, 5.50) Does not work with cdj850.
      HP DeskJet 970 (5.50) Some pages contain small black boxes,
         lines or missing characters.
      HP OfficeJet 590 (5.50)
      Olivetti jp450 (5.50)
      Xerox XJ6C (5.50)
      May work with other HP Color DeskJet printers that use a CMYK ink cartridge.
      Any printer that works with this device will probably work in black and white
        with djet500 and cdjmono.


Create the /tmp/testgs file with the following contents:

    #!/bin/sh
    gs_device=cdj550
    exec /usr/bin/gs -q -dSAFER -dBATCH -sDEVICE=${gs_device} \
      -sOutputFile=-


Run the following commands to process the /tmp/one.ps file and view the output with a text editor:

    h4: {209} % /tmp/testgs </tmp/one.ps >/tmp/out.img
    h4: {210} % vi /tmp/out.img
    ^[*rbC^[*t300R^[&l2aolE^[*o1d2Q....


As you see, we have done the conversion correctly. We could even pass the GhostScript device as a command line argument, in an environment variable, or extract it from the name of the executable. In practice it turns out that may need to specify not only the GhostScript device but also a set of resolution options to do conversions.

The ifhp filter's ghostscript printer support implements a robust version of this simple conversion filter. It uses the gs_device option to specify the GhostScript device and gs_options to specify the and additional options. It also uses the a2ps program to do text to PostScript conversion as well. Modify the lp printcap as shown below, and use lpc reread to restart the server.

    lp:sd=/var/spool/lpd/%P
      :force_localhost
      :lp=/tmp/lp
      :ifhp=model=ghostscript,gs_device=cdj550
      :filter=/usr/local/libexec/filters/ifhp


Print the file /tmp/one.ps, display the lpq status as shown below, and then display the output in /tmp/lp using a text editor such as vi or emacs that shows control characters:

    h4: {211} % cp /dev/null /tmp/lp
    h4: {212} % lpr /tmp/one.ps
    h4: {213} % lpq
     ....
     Filter_status: initial job type 'POSTSCRIPT' at 03:50:38.141
     Filter_status: job type 'raw', converter '/usr/bin/gs
       -dSAFER -dBATCH -q -sDEVICE=cdj550 -sOutputFile=- - ' at 03:50:38.141
     Filter_status: started converter '/usr/bin/gs
       -dSAFER -dBATCH -q -sDEVICE=cdj550 -sOutputFile=- - ' at 03:50:38.146
     Filter_status: converter done, output 1251 bytes at 03:50:38.790
    
    h4: {214} % vi /tmp/lp
    ^[*rbC^[*t300R^[&l2aolE^[*o1d2Q....


Next, print the file /tmp/hi, display the lpq status as shown below, and then display the output in /tmp/lp using a text editor such as vi or emacs that shows control characters:

    h4: {215} % cp /dev/null /tmp/lp
    h4: {216} % lpr /tmp/hi
    h4: {217} % lpq
     ....
     Filter_status: job type 'raw', converter
      '/usr/bin/a2ps -q -B -1 -M Letter --borders=no -o-
      | /usr/bin/gs -dSAFER -dBATCH -q
        -sDEVICE=cdj550 -sOutputFile=- - ' at 03:52:12.423
     Filter_status: started converter
      '/usr/bin/a2ps -q -B -1 -M Letter --borders=no -o-
      | /usr/bin/gs -dSAFER -dBATCH -q
        -sDEVICE=cdj550 -sOutputFile=- - ' at 03:52:12.426
     Filter_status: converter done, output 183 bytes at 03:52:13.206
    
    
    h4: {218} % vi /tmp/lp
    ^[*rbC^[*t300R^[&l2aolE^[*o1d2Q....


As shown by the lpq status above, the a2ps program was invoked to convert a text file into PostScript, which was then rasterized by GhostScript.