back to the main imgtops page

why use imgtops?

The original PostScript, released in 1985, had basically one way to represent image data: uncompressed 24-bit RGB triples, with each byte represented in ASCII as two hex digits. This requires 6 bytes per pixel plus additional overhead, which tends to make PostScript files with images very, very large.

Later revisions of PostScript (called "language levels") added all sorts of fancy decompressors and decoders that enable more efficient storage of image data. Language level 2 was released in 1991; nearly all PostScript devices in use today support it. Language level 3 is more recent (1998, I think), so there are still plenty of devices out there that don't support it. imgtops only outputs level 2 or higher PostScript; if you need level 1 compatibility you'll have to use something else (such as pnmtops). Its use of level 3 features is disabled by default but can be enabled with the "-3" option.

The only level 3 feature imgtops uses currently is the zlib-compatible /FlateDecode filter. This can significantly improve compression on non-JPEG images with large areas of solid color.

To see what your device supports, download this one-page PostScript document and print it. It will tell you what language level interpreter you have. If you use imgtops to make a file that uses level 3 features and you print it on a level 2 device, you'll see a gray box and a numeral "3" in place of the image.

Another issue affecting file size is how binary image data is represented. Traditionally PostScript files have been 7-bit clean, which is why image data was represented as ASCII hex digits. This means that each byte of data takes up two bytes in the output file. Level 2 introduced the more efficient ASCII85 encoding scheme, where every four bytes of data were represented with five printable ASCII characters (versus using eight with hex encoding — a 37% savings). imgtops uses ASCII85 by default, but if you are feeling particularly masochistic you can force hex encoding with the "-x" option.

It is also legal to embed binary data directly in the PostScript file, without any encoding at all. This is enabled with the "-8" option. It is off by default, because many PostScript document processors (such as gv, as far as I can tell) have been written to expect 7-bit clean input and choke on files with binary data.

the bake-off

Here's a comparison of the output of imgtops (version 0.9.1) versus two other similar utilities: convert from the ImageMagick package (version 5.4.7), and pnmtops from the Netpbm package (version 9.24).

The graphs show output file size. Note that convert's level 2 and 3 output failed on some images — the output was distorted or garbled when viewed with Ghostscript.

test name command comments
i2imgtops infile > outfile level 2 output
i3imgtops -3 infile > outfile allows level 3 output
ib2imgtops -8 infile > outfile level 2 output, binary data
ib3imgtops -8 -3 infile > outfile allows level 3 output, binary data
c1convert infile eps:outfile level 1 output
c2convert infile eps2:outfile level 2 output, no choice given about binary output
c3convert infile eps3:outfile level 3 output, no choice given about binary output
p1???topnm infile | pnmtops -noturn > outfile level 1 output
p2???topnm infile | pnmtops -noturn -rle > outfilelevel 1 output, with nonstandard RLE encoding

Here are the results. Note that in some cases the picture you see on this web page is not the actual input file used in the test; for that you'll have to use the text link below the picture.

grayscale JPEG

convert's output here is smaller than imgtops's; it seems to strip out some irrelevant JPEG markers. I might look into this more eventually.

input file

color JPEG

Same thing here as in the grayscale case.

input file


imgtops uses the /Indexed color space to represent paletted images very efficiently. Since this is a logo with lots of constant color areas, run-length encoding (level 2) or zlib compression (level 3) does the rest.

input file

another GIF

Same thing here.

input file

24-bit PNG

Here's an uncompressed photograph. The blue bars really show the impact of ASCII85 encoding versus hex.

input file

8-bit PNG

Here we have a 256-color image so a palette representation is used, but pixel values themselves don't compress so well as with the GIFs.

input file


Here's the hardest test: a TIFF image in the CMYK color space (rather than RGB). The other tools both convert it to RGB before outputting it; only imgtops actually outputs native CMYK PostScript.

input file

Doug Zongker
25 March 2003 Logo