Conversion to PNG from other image formats (or even from PNG) remains a popular approach for the simple reason that other formats have traditionally been better supported by applications. Even with good, current application support for PNG, users typically have large archives of older images, at least some of which may they desire to convert to PNG format.
Just as one would like to see certain basic PNG features supported in image editors (which may be thought of as a special case of conversion utilities, converting and optionally modifying a previously saved image file) one would like certain basic PNG features supported in converters. These include:
Clearly, different users have different needs, but fundamental things that should be preserved when converting between image formats include the basic pixel information, transparency, and text. Items in the preceding list that involve optimization and compression of PNG images can be dealt with after the initial conversion is complete, but restoring text or transparency information that was lost in translation is tedious and to be avoided if at all possible.
In the next few sections, we will look at a number of conversion utilities in some detail. Most of these are command-line programs--not because we want the reader to suffer, but because dedicated converters such as these typically do the best job and are often capable of batch (automated) conversions. I have also listed many image viewers with conversion capabilities in Chapter 3, “Applications: Image Viewers” and several image editors in Chapter 4, “Applications: Image Editors”; thse are, by necessity, graphical and may be preferable for the casual user.
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, 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.
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.
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. 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.
Possibly the most complete conversion program in existence, at least with respect to support for PNG features, is pnmtopng. In conjunction with its inverse, pngtopnm, and the rest of the NetPBM suite, it is capable of handling basic conversions to and from virtually any image format. But pnmtopng really shines as a tool for adding and modifying PNG chunk information, including such things as text annotations, palette optimization, and support for adding or removing alpha (transparency) channels.
Currently, the latest version of pnmtopng is 2.37.2, released in March 1999; it can be found on the PNG home site, http://www.libpng.org/pub/png/apps/pnmtopng.html, along with pointers to the libraries on which it depends.
Written and maintained by Alexander Lehmann and Willem van Schaik with contributions and fixes from others, pnmtopng is primarily a Unix-based tool, which unfortunately limits its usefulness to a minority of computer users. But other parts of the NetPBM suite have been ported to OS/2 and Windows, and it is likely that a future release of both pnmtopng and NetPBM will be more portable and may even include ready-to-go executables.
To begin explaining some of pnmtopng's features, it is first necessary to describe a little about the PBM format itself. If one wishes to be able to convert any of 100 possible image formats into any other, there are two options: write 10,000 individual converters to go directly from format A to format B for all possible pairs of A and B; or write only 200 converters, 100 to go from each of the image formats into some intermediate representation and another 100 to convert back from that intermediate format into the 100 target formats. Once the intermediate format exists, one need not stop at conversion programs; generic utilities to manipulate images suddenly become possible--for example, quantization, smoothing, cropping, contrast enhancement, and so on.
PBMplus/NetPBM is that intermediate format. It was originally designed by Jef Poskanzer and released as the PBMplus suite, with later “interim” packages released as NetPBM by Bill Davidsen. Since there has never been another PBMplus release, I will henceforth refer to the format as NetPBM, the name by which it is now most commonly known. The format is quite simple: three lines of text header--which may additionally include one or more comment lines--followed by the uncompressed image data. The image data may be stored as either text or binary values; the latter is more efficient and far more commonly used, but the existence of the text format means that one can actually create images or color palettes in an ordinary text editor. There are also three basic NetPBM image flavors: bilevel (or black and white), which is referred to as a portable bitmap or PBM file; grayscale, called a portable graymap or PGM; and truecolor (RGB), referred to as a portable pixmap or PPM file. Programs that can deal with more than one flavor usually have “PNM” in their names; this stands for portable anymap. There is currently no “real” PNM format; it is a virtual format and a convenient catchall name.
One notable feature missing from the NetPBM format is provision for alpha channels; this is a known limitation  with implications for converting between formats that support transparency, such as PNG, GIF, and TIFF. pnmtopng gets around this to some extent by the simple expedient of storing transparency information in a separate grayscale file. Before we get into that, let's look at some simpler cases.
pnmtopng is a command-line program, and, thanks to its Unix heritage, it is designed to operate as part of a multicommand pipeline. Unix pipes are a slick method of connecting the output of one program into the input of another; in principle there is no limit to how long such a chain can be, although in practice the amount of system resources that are available may constrain things. Here is a simple example that converts a GIF image into PNG:
giftopnm foo.gif | pnmtopng > foo.png
The file foo.gif is read by giftopnm (part of the NetPBM suite) and converted to NetPBM format, then piped into the input of pnmtopng, which converts the image to PNG format. Since there are no more programs to be run, pnmtopng's output is redirected into a file--in this case, foo.png.
Observant readers will recall that GIF images are always palette-based, yet I didn't say anything about palettes in describing the NetPBM format. In fact, NetPBM has no concept of palettes; giftopnm usually converts GIF images into PPM format (the RGB flavor). Fortunately, pnmtopng is smart enough to count the colors in an image and automatically write a palette-based PNG image if there are 256 or fewer colors. It will likewise detect if a color image is actually composed only of gray values; in that case, it will write either a grayscale PNG or a palette-based one, depending on which can be written with the fewest bits. This automatic checking comes at a cost, however: because it requires inspection of every pixel, it can be quite slow for large images. pnmtopng therefore includes a -force option to skip the checking. With this option, the previous example would result in a 24-bit truecolor PNG:
giftopnm foo.gif | pnmtopng -force > foo24.png
tifftopnm foo.tiff | pnmtopng > foo-was-tiff.png djpeg foo.jpg | pnmtopng > foo-was-jpeg.png
But these are all trivial conversions. Suppose I would like to convert an existing NetPBM image into an interlaced PNG, including gamma information, a timestamp, and some text--say, the author's name, the title of the image, its copyright, and perhaps the date on which the original photograph was taken. The first thing we need to do is create a small text file containing the text information. pnmtopng treats the first word on any line that does not begin with a blank (either a space or a tab character) as the keyword, with the actual text following. The text may stretch over several lines, and keywords with spaces in them must be quoted. Thus the following text file, containing four keywords and their corresponding values, would suffice:
Title The Incredible and Rarely Seen Foo Author Greg Roelofs Copyright This image is hereby placed in the public domain by its author. "Creation Time" 4 July 1976 is the date on which this particular Foo was photographed.
Note that leading blanks (or “white space”), including any between the keywords and subsequent text, will not be included in the PNG text chunks. But any newlines (or “carriage returns,” loosely speaking) will be included exactly as typed; thus, there will be one in the Copyright text chunk, right before the word “public,” and another in the Creation Time text chunk, immediately after “1976.” In addition, there is currently a bug in pnmtopng: when all of the text corresponding to a keyword appears on a line following the keyword--that is, the keyword is immediately followed by a carriage return--the program will sometimes crash. The problem will almost certainly be fixed by the time this book reaches print, but in the meantime, it can be avoided by adding a space after the keyword.
So assuming the text file were named comments.txt (and contains no keywords followed immediately by newlines), the following command would create the PNG image with the specified text and other information:
pnmtopng -interlace -gamma 0.65909 -text comments.txt \ -time 1998-10-25 21:00:00 foo.ppm > foo.png
The first option is self-explanatory: the PNG image will be interlaced. For the -gamma option, we've used a value that corresponds to a typical Macintosh; we're imagining that the original image was scanned and tweaked on a Mac before being converted to PPM format (foo.ppm) on some other system. The -time option requires a little more explanation. First, note that it is distinct from the “Creation Time” text chunk we included; the -time option will write the special PNG tIME chunk, which represents the time the image was last modified. But the last modification time is clearly the time the image was converted into PNG format, so pnmtopng really should not require the user to specify the time information explicitly. This is particularly true, given that PNG's time chunk is supposed to be in Coordinated Universal Time, and most users are unlikely to know how to convert to that.
 With luck, this oversight will also be corrected in the next release of the program.
Transparency is one of PNG's major strengths, so let's take a look at some of pnmtopng's options there. Suppose that we wish to vignette our treasured foo image--that is, we would like to apply an oval mask to it that gradually fades to complete transparency, in effect transforming our image from rectangular to rounded. This is easily accomplished by creating the oval mask as a grayscale (PGM) image, where white represents the regions that will be completely opaque (i.e., the main subject matter of the image) and black the outer, transparent regions. Then give the following command:
pnmtopng -alpha ovalmask.pgm foo.ppm > foo.png
This will ordinarily create a 32-bit RGBA image--in other words, truecolor with a full alpha channel. But if it happens that the combination of the original RGB image and the mask produces at most 256 RGBA combinations, pnmtopng is smart enough to detect that and write a palette-based image with transparency information instead. Moreover, it will automatically arrange the palette and transparency entries so that all of the completely opaque colors are at the end of the palette; the corresponding transparency entries may then be omitted, resulting in a smaller file.
In some cases, the transparency mask contains only fully opaque and fully transparent values, and it may happen (usually by design) that the parts of the underlying image that correspond to the transparent region are all one color, even though there may be thousands of colors in the opaque part. pnmtopng will again detect this, creating a palette-based image with just one transparency entry if possible; if there are too many colors, it will instead write a full grayscale or RGB image with a single color marked transparent. This results in a PNG file that's much more compact than one with a full alpha channel.
Transparent images intended for display only on web browsers will always have some sort of background specified as part of the web page, but for images that may be rendered by a standalone viewer, it is often desirable to include an explicit background color in the image. The -background option provides that capability; it accepts a color argument in almost any format allowed by MIT's X Window System, including English text (assuming the X color database file can be found). Thus, the following three commands are equivalent (the -alpha ovalmask.pgm option has been omitted for brevity):
pnmtopng -background rgbi:1.0/0.855/0.726 foo.ppm > foo.png pnmtopng -background "peach puff" foo.ppm > foo.png pnmtopng -background "#ffdab9" foo.ppm > foo.png
For most users, the second form is probably the most easily understood but the least precise. Making it precise requires the finely honed ability to find the X color-database file, which can be difficult when it exists and impossible when it doesn't
 (it is also explicitly platform-dependent; that is, the same color name is allowed to have different RGB values on different machines). Therefore, the first form is likely to be the most useful. It specifies the RGB values of the background color as decimal fractions between 0.0 and 1.0. The values are separated by forward slashes (/) and prefixed by rgbi:. The third form is the old-style hexadecimal format that is favored by programmers but almost no one else. (It also happens to be the format used in the demo programs I present in Chapter 13, “Reading PNG Images” and Chapter 14, “Reading PNG Images Progressively” on reading PNG images. Oh, the embarrassment.) The hex value need not be placed in quotation marks on a command line, but within a shell script it should be quoted, or the hash character (#) will be treated as the beginning of a comment.
pnmtopng also potentially supports the creation of 16-bit-per-sample images (that is, 16-bit grayscale, 32-bit gray+alpha, 48-bit RGB or 64-bit RGBA), but only with text (ASCII) NetPBM files, and only if the underlying NetPBM library supports 16-bit images, which is not the default behavior. The requirement to use ASCII format for the 16-bit NetPBM image files is a current limitation of the NetPBM suite. As with transparency and palettes, pnmtopng detects if 16-bit samples are really just scaled 8-bit samples; if so, it will automatically convert the image back to 8-bit samples unless the -force option is given. It can also be instructed to convert true 16-bit samples to 8-bit with the -downsample option.
Other supported features include chromaticity information, histograms, compressed text, explicit single-color transparency, physical pixel dimensions, and special compression options. Quantization of truecolor images to 256 or fewer colors is not supported by pnmtopng itself, but it is a straightforward part of the standard NetPBM package. For example, to quantize a 24-bit TIFF image to the 256 best colors, dither the result, and save it as a palette-based PNG, one can use:
tifftopnm foo.tiff | ppmquant -fs 256 | pnmtopng > foo.png
The -fs option to ppmquant instructs it to use Floyd-Steinberg dithering, which generally looks very nice but does require a fair amount of computation. The 256 parameter indicates the number of colors to be used in the final version; any value may be used (web-savvy designers might wish to use a smaller number of colors), but only values of 256 or less will result in a palette-based PNG image. What about images with an alpha channel? Unfortunately, those who wish to quantize 32-bit RGBA images down to a 256-entry “RGBA palette” are stuck for now. The ppmquant algorithm can easily be modified to support RGBA values in addition to ordinary RGB, but until NetPBM itself is updated, there is no way to pipe transparency information from one NetPBM utility into another.
For users of very large images, one other point is worth mentioning: pnmtopng currently reads the entire image into memory buffers before doing anything with it, which means that a 4000 × 4000 RGBA image would require 64 megabytes of real and/or virtual memory just for the uncompressed image itself. But all is not lost; in Chapter 15, “Writing PNG Images”, I present a very simple-minded NetPBM-to-PNG converter, and one of its design goals was the ability to convert images on the fly, requiring only a very small memory footprint. (Of course, this only works if the PNG image is not interlaced.) The demo program also has a -time option that automatically records the current time in the proper format, as well as one or two other potentially handy features.
For simple batch conversion of GIF images into PNGs, pnmtopng is not only overkill but also somewhat tricky to automate. Such a task is more readily handled by gif2png, a special-purpose conversion program written by Alexander Lehmann. Besides the raw image pixels, there are three GIF features that translate directly into PNG features: transparency, text (comments), and interlacing. gif2png handles the first two automatically; only interlacing is not detected and automatically applied to the output image, although the program does include a -i option to force interlacing.
The simplest usage of gif2png is to give it the name of a GIF image:
The program will convert the image to a noninterlaced PNG, preserving any transparency, comments, and “graphic control” or “application extension” information. It will also add its own text chunk with the Software keyword, and it will automatically change the file extension from .gif to .png. There is one important caveat, however: the current version, gif2png 0.6, does not check for an existing file of the same name and will overwrite any such file without warning.
Because gif2png renames the files it converts without user input, it can be used to convert a whole directory of GIF files in a single command. Under Unix, where the shell expands wildcard filenames (“globbing”), this is as simple as:
On other operating systems, the filenames must be specified explicitly:
gif2png a.gif b.gif c.gif d.gif e.gif foo.gif foo2.gif
To prevent gif2png from adding a Software text chunk to the output image(s), use the -s option:
gif2png -s foo.gif
To do the same conversion but to an interlaced PNG, include the -i option:
gif2png -s -i foo.gif gif2png -si foo.gif
gif2png does have a few drawbacks, as might be expected given its pre-1.0 version number. In addition to the problem of overwriting existing files, gif2png's conversion of GIF transparency information is less than ideal; although it gets the job done, the program copies over the GIF palette without modification, which can result in useless transparency entries in the PNG file. For example, a 256-color GIF image whose last palette entry is the transparent one would result in a 256-entry transparency chunk in the PNG file, where one entry would suffice; in other words, it can waste up to 255 bytes in the output file. gif2png is also rather verbose and provides no option to keep it quiet; in fact, its progress meter (a simple percentage value, updated repeatedly) is supposed to be enabled only when the -p option is given, but it actually is on by default and can only be turned off with -p.
Despite all this, the program is quite stable and useful. It even converts GIF comments from IBM codepage 437 to PNG's Latin-1 format, and it will convert animated GIFs into multiple single-image PNGs. A planned option that would have automatically deleted the GIF input images after conversion was never implemented, nor was the capability of converting GIF Plain Text Extensions into PNG gIFt chunks. But these are minor issues; in fact, the gIFt chunk was officially declared Bad (that is, deprecated) in October 1998, so its lack of support in gif2png turned out to be prescient. Indeed, the only major problem with the program is the fact that it reads GIFs in the first place. It is therefore (according to Unisys) subject to the LZW patent and its associated licensing issues. Unisys initially claimed that freeware GIF programs would be granted a free LZW license, but that later changed, which was directly responsible for the cessation of further development on gif2png.
The gif2png source code and ready-to-go binaries for Linux can be found at http://www.catb.org/~esr/gif2png/. (Older binaries for DOS, OS/2, Amiga, and Macintosh may still exist elsewhere on the Web.) A graphical port written by Nigel Stewart for 32-bit Windows, called The Exorcist, supports drag and drop and is available from its own home page: http://www.nigels.com/exorcist/Exorcist.html. Version 1.1 is the latest release.
The corresponding special-purpose conversion program for TIFF images was written by Willem van Schaik and is called, predictably, Tiff2png. By a strange coincidence, its latest version is also 0.6, but the program is perhaps slightly less robust than gif2png. This is primarily due to the fact that the TIFF format is hugely complex, supporting multiple forms of text annotations, both gamma and color correction, several flavors of transparency, many different sample depths, and numerous other options that might conceivably be carried over into a PNG image with a little effort (or, more likely, a lot of it).
Tiff2png's main features as a conversion program are its support for TIFF sample depths up to 16 bits and its support for transparency and alpha channels. Unlike gif2png, Tiff2png requires an explicit output filename and is therefore somewhat less convenient for batch conversions:
tiff2png foo.tiff foo.png
It is also completely quiet by default, although it supports a -v option to turn on its verbose mode:
tiff2png -v foo.tiff foo.png Tiff2png: foo.tiff TIFF Directory at offset 0x10008 Image Width: 128 Image Length: 128 Resolution: 72, 72 pixels/inch Bits/Sample: 8 Compression Scheme: None Photometric Interpretation: RGB color Extra Samples: 1<assoc-alpha> Samples/Pixel: 4 Rows/Strip: 16 Planar Configuration: single image plane Tiff2png: 128x128x32 image Tiff2png: 8 bits/sample, 4 samples/pixel Tiff2png: maxval=255 Tiff2png: color-type = truecolor + alpha Tiff2png: bit-depth = 8
Unfortunately, Tiff2png does not distinguish between associated (premultiplied) alpha and unassociated alpha. The latter is the only form supported by PNG, but Tiff2png will happily store an associated alpha channel without conversion, as in the previous example.
The program also appears not to handle Intel-format (“little-endian”: see the section entitled “Implementation” in Chapter 7, “History of the Portable Network Graphics Format”) TIFF images with 16-bit samples correctly, instead storing the samples as is--which effectively means they are inverted, given that PNG samples must be stored in “big-endian” format. But lacking any such sample images, I was unable to verify this.
At any rate, Tiff2png is capable of converting at least some TIFF images with alpha transparency correctly, which gives it an advantage over the current NetPBM suite and pnmtopng. Although TIFF is subject to the same LZW licensing issues GIF is, it supports several other compression methods (including no compression) and is therefore less of a problem for program authors. In Tiff2png's case, all TIFF manipulations are handled via Sam Leffler's free libtiff library, which means Tiff2png itself can be updated at will without worrying about the sorts of legal issues that plagued gif2png. Source code for Tiff2png can be found on the PNG home site, http://www.libpng.org/pub/png/apps/tiff2png.html, but there are presently no prebuilt executables.
Finally, we should take a look at an extremely useful PNG utility that is not usually considered a conversion tool:pngcheck. pngcheck prints the chunks in a PNG file, along with their contents, in many cases; one can loosely think of it as a utility that “converts PNG images to text,” although it does so in such a way that they could never be converted back to PNG format. (In particular, it provides no way to print the actual pixel data, although it can print just about everything else.)
Originally written by Alexander Lehmann as a simple tool to check PNG images for corruption, such as might occur if the file were transferred in text mode, pngcheck was subsequently extended by Andreas Dilger, Greg Roelofs, and others, evolving into a nearly complete PNG syntax checker and content dumper. The latest versions (1.99-grr1 is current as of this writing) even include partial support for MNG files, the multi-image PNG extension described in Chapter 12, “Multiple-Image Network Graphics” (Multiple-Image Network Graphics). pngcheck is most often used to understand why a particular image is larger than expected--perhaps a 16-color image was saved in 24-bit RGB format instead of palette format, or a truecolor image was saved with minimal compression and no filtering. But it can also be used simply to test PNG files and print their dimensions, image types, and approximate compression ratios.
The most basic use of pngcheck involves giving it one or more filenames and no options, like so:
pngcheck foo.png foo2.png foo3.png
This results in output similar to the following, except that here the lines have been wrapped to fit the page:
No errors detected in foo.png (578x802, 24-bit RGB, interlaced, 54.7%). No errors detected in foo2.png (32x32, 4-bit colormap, interlaced, 36.1%). No errors detected in foo3.png (32x32, 64-bit RGB+alpha, non-interlaced, 58.1%).
An image that has been corrupted in some way might cause an error message such as the following:
foo4.png: File is CORRUPTED by text conversion. foo4.png: Chunk name 00 0d 49 48 doesn't conform to naming rules.
But pngcheck is most useful for seeing what's inside a PNG image. The -v option, for verbose mode, prints the name of each chunk within the file, along with some basic information wherever appropriate. Because it can be a tad lengthy, it is often a good idea to pipe the program's verbose output through a paging filter such as more. The following example works on both Unix-based systems and DOS, OS/2, and Windows command lines:
pngcheck -v imgcomp.png | more File: imgcomp.png (34163 bytes) chunk IHDR at offset 0x0000c, length 13 640 x 480 image, 32-bit RGB+alpha, non-interlaced chunk gAMA at offset 0x00025, length 4: 0.45455 chunk IDAT at offset 0x00035, length 8192 zlib: deflated, 32K window, default compression chunk IDAT at offset 0x02041, length 8192 chunk IDAT at offset 0x0404d, length 8192 chunk IDAT at offset 0x06059, length 8192 chunk IDAT at offset 0x08065, length 1274 chunk IEND at offset 0x0856b, length 0 No errors detected in imgcomp.png (97.2% compression).
In this example, we see a fairly basic PNG file, a truecolor image with an alpha channel, composed of only four chunk types: the required IHDR, IDAT, and IEND chunks (described in Chapter 8, “PNG Basics”), plus the optional but highly recommended gamma-correction chunk, gAMA (Chapter 10, “Gamma Correction and Precision Color”). Because the image primarily consists of solid-colored regions and simple gradients, it compressed unusually well; this probably indicates that dynamic filtering was used, but there is no way to be certain, given the preceding information.
However, pngcheck can optionally use the zlib compression library in order to look inside the compressed image data. In this case, it supports a -vv option (“very verbose”) that prints out all of the preceding information plus filtering information. The filter output can be extremely long; for just the first IDAT chunk in the preceding example, it looks like this:
chunk IDAT at offset 0x00035, length 8192 zlib: deflated, 32K window, default compression zlib line filters (0 none, 1 sub, 2 up, 3 avg, 4 paeth): 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 1 2 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 4 4 4 4 4 4 4 4 4 4 4 4 1 4 1 4 1 4 2 4 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 4 4 4 2 (200 out of 480)
The details are too complex to cover right now, but filtering and compression are discussed in Chapter 9, “Compression and Filtering”. All that matters here is that different filters have been used for different rows in the image, indicating that some sort of dynamic filtering was applied (which is generally good). Unfiltered images, on the other hand, will have all zeros for the filter numbers, and statically filtered images will use only a single filter type. In most cases, that means the image is not compressed as well as it could be. One major exception, however, is palette-based images; they rarely respond well to filtering, and most programs don't try.
pngcheck also supports more specific types of output. Its -p option, for example, is another rather verbose case; it prints the contents of the palette and optional transparency chunks for colormapped images. This can be useful in conjunction with a program such as pngcrush, for example, when one wishes to specify a particular color as transparent, but more commonly it is used to check whether the transparency chunk is full of needless opaque values. Consider the following example:
pngcheck -p foo5.png File: foo5.png (146 bytes) PLTE chunk: 4 palette entries 0: ( 0,255, 0) = (0x00,0xff,0x00) 1: (255, 0, 0) = (0xff,0x00,0x00) 2: (255,255, 0) = (0xff,0xff,0x00) 3: ( 0, 0,255) = (0x00,0x00,0xff) tRNS chunk: 3 transparency entries 0: 255 = 0xff 1: 255 = 0xff 2: 0 = 0x00
No errors detected in foo5.png (32x32, 2-bit colormap, non-interlaced, 43.0%).
Here we have a four-color image: bright green, red, yellow, and blue. The colors of the palette are listed as RGB triplets in both decimal and hexadecimal (base 16) for convenience. The palette itself is unremarkable; what is more interesting is the transparency chunk, tRNS. It includes three entries, but the first two have the value 255, which indicates that the corresponding palette entries should be treated as completely opaque. But all palette entries are considered opaque unless explicitly given a non-opaque transparency value--in other words, any transparency entries with the value 255 are redundant and represent wasted space. In this case, the only non-opaque entry corresponds to the third color, yellow; a smart PNG-writing program would have reordered the palette so that yellow was the first entry, thus shaving two bytes off the file. It is not uncommon to be able to save 100 or more bytes in this manner, which can represent 10% to 20% of the file size for small web graphics. In rare cases, it may be worthwhile to waste a few transparency entries so that the most common pixels in the image are all at the beginning of the palette (i.e., so they all have index values near zero); with filtering enabled, the compression engine may be able to make up the difference and then some. But as of early 1999, filtering has yet to be demonstrated effective on essentially any kind of palette-based image, so the possibility of recovering wasted transparency entries with improved compression is a rather tenuous one.
The other type of verbose pngcheck output is more useful to ordinary users, not just content developers trying to optimize things. The -t option prints not only text chunks' keywords but also their contents:
pngcheck -t ct1n0g04.png File: ct1n0g04.png (796 bytes) Title:PngSuite Author:Willem A.J. van Schaik (email@example.com) Copyright:Copyright Willem van Schaik, Singapore 1995 Description:A compilation of a set of images created to test the various color-types of the PNG format. Included are black&white, color, paletted, with alpha channel, with transparency formats. All bit-depths allowed according to the spec are present. Software:Created on a NeXTstation color using "pnmtopng". Disclaimer:Freeware. No errors detected in ct1n0g04.png (32x32, 4-bit grayscale, non-interlaced, -55.5%).
This example, using one of Willem van Schaik's test images from the PNG Suite, contains six text chunks with keywords Title, Author, Copyright, Description, Software, and Disclaimer. The content of each chunk immediately follows the keyword and colon; this is not the most readable approach, but the information is available and usually understandable with only a little squinting. One deficiency of the current version is that it does not display the contents of compressed text chunks (zTXt), even when using the zlib compression library. This is promised to be fixed in a future version, however.
The latest version of pngcheck can be found at the PNG home site, http://www.libpng.org/pub/png/apps/pngcheck.html.
The converters we've discussed so far barely scratch the surface of what is available. If one includes image editors and viewers that can convert images in addition to dedicated conversion tools, there are well over one hundred applications capable of converting to and from the PNG format.
[38b] Many of these were listed in the previous two chapters and are well worth considering, particularly for users who may be uncomfortable dealing with command-line programs.
Here is a list of some of the other dedicated (or nearly dedicated) image converters that support PNG. The most recent version as of January 1999 is given wherever possible.
Version 5.50, Aladdin Enterprises. Available for Unix, VMS, OS/2, Windows 9x/NT, and Mac 68k/PPC; older versions available for Windows 3.x, DOS, Amiga, Atari, and possibly Acorn RISC OS; write-only support for PNGs.
Icons Control 95
http://www.aminet.org/pub/aminet/gfx/conv/PicCon250.lha http://www.aminet.org/pub/aminet/util/dtype/PNG dt.lha http://www.aminet.org/pub/aminet/util/dtype/akPNG-dt.lha http://home.t-online.de/home/Andreas Kleinert/support.htm
Version 3.25, Andreas Kleinert. Available for Amiga 68k/PPC; write-only support for PNGs; supports interlacing and single-color transparency. PNG-Box is a graphical “any to PNG” conversion utility that uses Andreas's own SuperView Library for its image support instead of datatypes.
http://www.amigaworld.com/support/png-box/ http://home.t-online.de/home/Andreas Kleinert/support.htm http://www.aminet.org/pub/aminet/gfx/conv/PNG-Box.lha
Version of March 10, 1995, Lee Daniel Crocker. Available as portable source code (does not require libpng or zlib); read-only support for PNGs (converts to TIFF); full gamma support (writes TIFF TransferFunction tag); full alpha support for true alpha channels (no palette-alpha or “cheap transparency” support).
Version 3.0, Ulead Systems. Available for 32-bit Windows; read/write support for PNGs; full alpha support, including at least single-color palette transparency (not clear whether full RGBA -palette translucency is supported); reportedly cannot write 1-bit (bilevel) images.
Version 0.04b, Darren Salt. Available for Acorn RISC OS; write-only support for PNGs; full alpha support via secondary sprite that is used as a transparency mask or alpha channel; supports interlacing and background color. An older version was reported to produce streaks in conversions of newer (post-RPC) sprites, but this appears to be fixed in the current release.
New conversion utilities and updated information on the ones listed here can be found at the Image-Conversion Applications with PNG Support web page at the PNG home site, http://www.libpng.org/pub/png/pngapcv.html. This URL is expected to be stable for years, but of course there are no guarantees on the World Wide Web! Use a search engine to look for the title string or for one of the more oddly named utilities listed if the link should ever break.
 For real suffering, write a book.
 Of course, if a copyright is also embedded in the image data itself, the text version may be superfluous.
 Newer versions of pngcrush will print the palette, including indices, when given both the -n (“no crush”) and -verbose options.
 NetPBM originated as the PBMplus package, last released in December 1991. Subsequent third-party contributions from the Internet were gathered together and released as NetPBM in 1993 and early 1994, containing some 200 utilities for converting and manipulating images. The package has lain dormant since then, aside from the occasional appearance of utilities to support new image formats like PNG, but further news on this front is expected in 1999.
 Alpha support is a major reason behind the expected NetPBM revisions in 1999.
 The example here corresponds to 1:00 p.m. in the US/Pacific time zone. But had the conversion taken place at 1:00 p.m. on the previous day, it would have been specified as 20:00:00 in Universal Time, thanks to the fact that daylight saving time had not yet ended.
 For the record, it lives in /usr/openwin/lib/X11/rgb.txt on Sun systems, /usr/X11R6/lib/X11/rgb.txt on most Linux and FreeBSD systems, and /usr/lib/X11/rgb.txt on “generic” Unix/X11 systems.
 The compression ratio is computed by dividing the total file size by the nominal size of the uncompressed IDAT data, which means the presence of ancillary information or even a required palette can produce negative compression ratios--i.e., “expansion”--in small images. In other words, don't take it too seriously.
 One of the images used on the VRML98 web site had 211 transparency entries, of which 210 were unnecessary.
[38b] As of mid-2003, the number has more than doubled; the PNG home site lists all of them. Perhaps not surprisingly, however, the five discussed above are still among the best.