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


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.[36]

[36] 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.

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.[37] 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:

[37] It will also print the contents of the optional histogram and suggested-palette chunks; see Chapter 11, "PNG Options and Extensions", for details.

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,

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.[38] 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.

[38] One of the images used on the VRML98 web site had 211 transparency entries, of which 210 were unnecessary.

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)
Author:Willem A.J. van Schaik
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".
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,

Last Update: 2010-Nov-26