The PNG Guide is an eBook based on Greg Roelofs' book, originally published by O'Reilly.



pngcrush

What may be the most useful conversion tool of all knows nothing of any image format other than PNG; it converts PNGs into other PNGs. pngcrush, by Glenn Randers-Pehrson, is a program for optimizing PNG images--specifically, for reducing their size as much as possible, although it can also perform simple housekeeping tasks such as removing or replacing specific chunks,[29] or adding gamma-correction information or simple transparency. It is an invaluable tool for use in conjunction with other converters and with commercial image editors, which may not always produce optimal PNG files.

[29] PNG's fundamental chunk structure is described in Chapter 8, "PNG Basics".

pngcrush is currently available as a command-line, shareware program in DOS and Linux x86 flavors. The DOS version works under Windows 95/98/NT and can handle long filenames; it may also run in an OS/2 DOS box, but without long-filename support. The current release, as of January 1999, is version 1.1.3 which has a home page at http://pmt.sourceforge.net/pngcrush/.

The simplest pngcrush operation is a basic ``crush'' on a single file, specifying the output filename:

pngcrush foo.png foo-crushed.png

This results in output that looks something like the following:

pngcrush 1.1.3, Copyright (C) 1998, Glenn Randers-Pehrson.
 | This program was built with libpng version 1.0.3,
 |    Copyright (c) Guy Eric Schalnat, Group 42 Inc.,
 |    Copyright (c) 1996, 1997 Andreas Dilger,
 |    Copyright (c) 1998, 1999, Glenn Randers-Pehrson,
 | and zlib version 1.1.3, Copyright (c) 1998,
 |    Jean-loup Gailly and Mark Adler.

   foo.png IDAT length in input file =   148723
   IDAT length with method 1 (fm 0 zl 4 zs 0)=   147533
   IDAT length with method 2 (fm 1 zl 4 zs 0)=   124710
   IDAT length with method 3 (fm 5 zl 4 zs 1)=   110589
   IDAT length with method 9 (fm 5 zl 2 zs 2)=   880073
   IDAT length with method 10 (fm 5 zl 9 zs 1)=    85820
   best pngcrush method = 10 for foo-crushed.png (42.36% reduction)

   overall result: 42.36% reduction, 62903 bytes

pngcrush typically tries the five or six compression approaches that are, according to its heuristics, the most likely to compress the best. This involves varying the different filter and compression settings allowed by the PNG format (described in Chapter 9, "Compression and Filtering"). If pngcrush finds a method that produces a smaller file than the original, it saves the new file with that approach. (A 42% reduction as shown in the previous output is typical only of cases in which the original file was compressed particularly poorly.) Note that pngcrush operates completely losslessly with respect to the image data; the only loss of information it intentionally allows is the explicit removal or replacement of chunks at the user's direction (though a limitation in versions of the PNG reference library prior to 1.0.6 also caused the accidental deletion of unknown, safe-to-copy chunks). We'll come back to that shortly.

pngcrush also supports a truly brute-force approach that currently tests 102 different methods but may add more in the future. This rarely improves compression by more than a tenth of a percent over the default approach, but for busy sites looking to conserve bandwidth, saving even a dozen bytes may be well worth the cost of a very lengthy--but one-time--pngcrush session. The brute-force method is invoked with the -brute option, logically enough:

pngcrush -brute foo.png foo-crushed.png

In general, a site optimizing its content will want to crush all of its PNG images (by using batch-mode conversion), and pngcrush includes two options to support batch conversion. The first allows one to specify a new extension for converted images, which will be created in the same directory as the original:

pngcrush -e -crushed.png foo.png foo2.png foo3.png foo4.png

This example crushes four images, foo.png through foo4.png, giving them the extension -crushed.png; thus the output names are foo-crushed.png, foo2-crushed.png, and so on. Such an approach is handy for casual use, since an alphabetical directory listing will (usually) list the original and crushed versions in pairs, allowing quick, after-the-fact inspection of the changes in file sizes. But because it involves renaming files, this is probably not the preferred approach for a web site. The alternative is pngcrush's -d option, which allows one to specify an output directory in which to place the crushed images:

pngcrush -d crushed_images foo.png foo2.png foo3.png foo4.png

This example crushes the same four images, but leaves their filenames unchanged. The new versions will go in the crushed_images subdirectory, which will be created if it does not already exist.

The -rem option allows one to remove PNG chunks. This is quite handy, and is often a great way to trim a few dozen bytes from files (which can make a big difference in the case of small web graphics), but it does require knowledge of PNG's chunk names. The following example removes any timestamp chunks and both compressed and uncompressed text chunks from foo.png and places the result in the crushed subdirectory:

pngcrush -d crushed -rem tIME -rem zTXt -rem tEXt -rem iTXt foo.png

Note that this approach is somewhat akin to doing surgery with a hatchet: one has no control over specific instances of the listed chunks in the case of those (like zTXt, tEXt, and iTXt) that may appear more than once. In particular, the tEXt or iTXt chunk is where copyright info usually appears, and that is usually not something one wants to remove.[30]

[30] Of course, if a copyright is also embedded in the image data itself, the text version may be superfluous.

One last option is worth a quick look. pngcrush's -g option allows one to set the gamma value of the image, which in turn provides for cross-platform consistency of the overall brightness of the image. Chapter 10, "Gamma Correction and Precision Color" covers gamma and color correction in more detail, but the effect will be familiar to any site that uses both Macintoshes and PCs: images that look good on Macs tend to look too dark on PCs, and images that look good on PCs tend to look too bright and washed out on Macs. The solution is to include information about the system on which the image was created, and PNG's gAMA chunk is the simplest and most effective means of doing so. Unfortunately, not all image editors support gamma in PNG, and as you saw in the previous chapter, some of those that do support it store the wrong value. A site that has just received a batch of PNG images from its Mac-based design department might do something like the following:

pngcrush -d crushed -replace_gamma 0.65909 mac.png mac2.png mac3.png

For images from a PC-based design group, the corresponding command is:

pngcrush -d crushed -replace_gamma 0.45455 pc.png pc2.png pc3.png

In addition to optimizing the sizes of the images, these examples strip any existing gamma information out of the files, on the assumption that the values are known to be wrong and replace it with values that are appropriate for stock Macs (with a factory-default ``system gamma'' value of 1.8) or stock PCs. If it is known that the images that have gamma information are correct, use the -g option instead; it will add a gAMA chunk only to those images that do not already have one.

I should note that pngcrush is still a relatively new utility, and it does have a number of rough edges yet. For example, if an output file already exists, it will be overwritten without warning. There is also no recursion, no support for wildcards other than what the operating system provides (i.e., only under Unix), and no way to set a default extension or directory for crushed files (say, via an environment variable). The program's extended options also assume a fairly advanced knowledge of PNG files--for example, the official names of PNG chunks, in the case of the -rem option, or the numerical color types used internally by PNG, or the precise palette index of the color to be made transparent, in the case of the -trns option.[31] Nor is there yet support for counting colors in images and automatically converting from, say, RGB to palette format, although this is planned for a future version. But these are relatively minor user interface issues that will undoubtedly improve as the application matures. As regards its primary purpose of squeezing PNG images as tightly as possible, pngcrush is quite capable, and is likely to become an indispensable addition to the toolchest of any image-wrangler.

[31] Newer versions of pngcrush will print the palette, including indices, when given both the -n (``no crush'') and -verbose options.




Last Update: 2010-Nov-26