 | Level: Intermediate Ian Shields, Senior Programmer,
IBM
07 Feb 2007 Have you ever tried to print DVI or other files in Linux® and gotten
an "unsupported format" message? This tip shows you how to combine
existing tools to make a CUPS print filter for printing DVI files.
The Common UNIX Printing System (CUPS) is the print spooler used on many Linux
and UNIX® systems today. You can use the filters provided with CUPS to format and
print many types of files on a wide variety of printers. But what happens if CUPS
doesn't support the kind of file you want to print? You can first convert the file
to something that CUPS will print, such as PostScript or PDF. Or, you can create a
filter so the CUPS printing system will recognize your file and print it
correctly. This article, excerpted from the
LPI
exam 102 prep: Printing tutorial,
shows you how to create a simple filter.
MIME types and CUPS
So how does CUPS determine the filter to use for formatting a particular file
type? CUPS uses MIME (Multipurpose Internet Mail Extensions) types to determine
the appropriate conversion filter when printing a file. Note that other printing
packages may use the magic number mechanism as used by the
file command. See the man pages for
file or magic for more
details.
MIME types are used for transmitting various files as mail attachments. They
consist of a type, such as text or image, and a subtype, such as html, postscript
gif, or jpeg. The type and subtype are separated by a semicolon (;). Optional
parameters may include information such as character set encoding or language.
CUPS uses rules from /etc/cups/mime.types to determine the type of a file and then
uses a suitable filter chosen from those listed in /etc/cups/conv.types for the
given MIME type. MIME types are registered with IANA, the Internet Assigned
Numbers Authority. If you need a type that is not registered, prefix the subtype
with 'x-'. Some image type examples are shown in Listing 1.
Listing 1. Some MIME type entries from
/etc/cups/mime.types
image/gif gif string(0,GIF87a) string(0,GIF89a)
image/png png string(0,<89>PNG)
image/jpeg jpeg jpg jpe string(0,<FFD8FF>) &&\
(char(3,0xe0) char(3,0xe1) char(3,0xe2) char(3,0xe3)\
char(3,0xe4) char(3,0xe5) char(3,0xe6) char(3,0xe7)\
char(3,0xe8) char(3,0xe9) char(3,0xea) char(3,0xeb)\
char(3,0xec) char(3,0xed) char(3,0xee) char(3,0xef))
image/tiff tiff tif string(0,MM) string(0,II)
image/x-photocd pcd string(2048,PCD_IPI)
image/x-portable-anymap pnm
|
The format of the entries is beyond the scope of this article. Check the files
/usr/share/mime/magic or /usr/share/file/magic for some insight on how the
magic numbers are used to identify files.
Once the MIME type of a file has been determined, the correct filter is found
using the /etc/cups/mime.convs file. Lines in this file have four entries: a
source and destination MIME type, a cost, and the name of the filter. The
least-cost filter is used. Some examples are shown in Listing 2.
Listing 2. Filter entries from
/etc/cups/mime.convs
text/plain application/postscript 33 texttops
text/html application/postscript 33 texttops
image/gif application/vnd.cups-postscript 66 imagetops
image/png application/vnd.cups-postscript 66 imagetops
image/jpeg application/vnd.cups-postscript 66 imagetops
image/tiff application/vnd.cups-postscript 66 imagetops
image/x-bitmap application/vnd.cups-postscript 66 imagetops
|
If a suitable filter cannot be found, your attempt to print a file will result in
an error message. If you are using a printer daemon other than CUPS, you may get
unexpected output instead. Listing 3 shows how this works with a DVI file (the
normal output from TeX and LaTex).
Listing 3. Printing an unsupported file type
[ian@attic4 ~]$ lpr samp1.dvi
lpr: Unsupported format 'application/octet-stream'!
|
A DVI filter for CUPS printing
Fortunately, the tetex package that provides TeX and LaTeX also provides a
conversion utility, dvips, to convert from DVI to
PostScript. Unfortunately, it won't work as a filter because it does not know how
to handle the arguments that a CUPS filter must handle, namely, job id, user, job
title, number of copies, and job options. The first filter in a filter pipeline
will also have an additional parameter, the filename, if the input comes from a
file.
The solution is to create a wrapper script that will be the filter. The
dvips command does not accept input from stdin, so the
script may need to create a temporary file and copy stdin to that file before
calling dvips. A possible script is shown in Listing 4.
Listing 4. A CUPS DVI to PostScript filter script
#!/bin/bash
# CUPS filter to process DVI files using dvips
# Create a sandbox for working if input on stdin
if [ $# -lt 6 ]; then
sandbox=${TMPDIR-/tmp}/cups-dvitops.$$
(umask 077 && mkdir $sandbox) || {
echo "Cannot create temporary directory! Exiting." 1>&2
exit 1
}
fn="$sandbox/cups-dvitops.$$"
cat > "$fn"
else
fn="$6"
fi
# Call dvips quietly, securely and with output to stdout
dvips -R -q -o - "$fn"
# Erase sandbox if we created one
if [ $# -lt 6 ]; then
rm -rf "$sandbox"
fi
|
Recall that CUPS uses two files in /etc/cups to determine the MIME type and
filter to use. These files will be overwritten whenever you reinstall or upgrade
CUPS. Fortunately, CUPS will read all files with an extension of .types or
.convs whenever it starts or restarts. So you should create a pair of files for
your new filter, for example /etc/cups/dvitops.types and /etc/cups/dvitops.convs.
Listing 5 shows the two configuration files for the DVI filter.
Listing 5. Configuration files for CUPS dvitops
filter
[ian@attic4 ~]$ cat /etc/cups/dvitops.types
# Local MIME definition for DVI files
application/x-dvi dvi string(0,<F702>)
[ian@attic4 ~]$ cat /etc/cups/dvitops.convs
# Local DVI to PostScript filter for CUPS
application/x-dvi application/postscript 50 dvitops
|
Listing 5 says that DVI files are identified by having the hexadecimal digits F7 and
02 in the first two positions and that such files should be processed by the
dvitops filter.
Next, as root, copy the script above in /usr/lib/cups/filter/dvitops, and make
sure it is world readable and executable (-rwxr-xr-x). The name you give the
script must match that in the /etc/cups/dvitops.convs file above. If you are
running SELinux in enforcing mode, you should also run
restorecon in the /usr/lib/cups/filter directory to
update the security contexts. Otherwise, your lpr
command will appear to work, but your file will not print.
Finally, use the restart option with the cups script located in /etc/rc.d/init.d
or /etc/init.d, to restart CUPS and use your new filter.
If you are using an older print spooler, you will probably use either the
magicfilter or apsfilter as input filters to convert various input files to
PostScript format for printing to a PostScript printer or, using Ghostscript, to a
non-PostScript printer.
Learn more
If you'd like to know more about printing in Linux, read
LPI
exam 102 prep: Printing tutorial,
from which this article was excerpted, or see the other
Resources below. Don't forget to
rate this page.
Resources Learn
Get products and technologies
Discuss
About the author  | 
|  | Ian Shields works on a multitude of Linux projects for the developerWorks Linux zone. He is a Senior Programmer at IBM at the Research Triangle Park, NC. He joined IBM in Canberra, Australia, as a Systems Engineer in 1973, and has since worked on communications systems and pervasive computing in Montreal, Canada, and RTP, NC. He has several patents. His undergraduate degree is in pure mathematics and philosophy from the Australian National University. He has an M.S. and Ph.D. in computer science from North Carolina State University. |
Rate this page
|  |