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

The gAMA Chunk

PNG's gAMA chunk basically says: if your overall display system's exponent (generally a combination of the system LUT exponent and the monitor or CRT exponent) is the same as the inverse of this gamma value, then the samples in the file are ready to go and need no further correction.[79] If not, the decoding correction can be computed from the product of the overall display-system exponent and the stored gamma value.

[79] Practically speaking, values that are within about 5% of each other may be considered ``the same.''

More precisely (and here we get into a bit of mathematics that will mainly be of interest to application developers), the stored gamma value represents the following relationship between the image samples and the desired output light intensity:

image_sample = light_outgamma


image_sample1 / gamma = light_out

Once again, bear in mind that light_out and image_sample are scaled to the interval between 0 and 1; that is, if the sample depth is 8 bits, the file samples range between 0 and 255, so image_sample is obtained by dividing a given file sample by 255, in floating-point arithmetic.

The decoding pipeline is represented by this expression:

image_sampledecoding_exponent * LUT_exponent * CRT_exponent = light_out

The decoding_exponent is simply the gamma correction that the application applies; the combination of the other two exponents is the ``overall display system's exponent,'' to use the language with which we began this section. Notice that the preceding equation and the one before it are very similar--in fact, they imply the following relationship between the exponents:

(1 / gamma) = decoding_exponent * LUT_exponent * CRT_exponent

or, equivalently:

decoding_exponent = 1 / (gamma * LUT_exponent * CRT_exponent)

The gamma relationship given in English at the beginning of this section simply says that if the product on the right side of this equation equals one (which means decoding_exponent also equals one), then no further conversion is necessary--the image samples are ready to go as is. On the other hand, if the right-hand side of the equation differs from one, then that value is decoding_exponent and is what the decoder uses to correct the image samples before sending them to the display system:

display_input = image_sampledecoding_exponent

Note that this procedure applies to each red, green, and blue value in a truecolor image or to each palette value in a colormapped PNG. But it does not apply to transparency values in an image with an alpha channel or a tRNS chunk; alpha samples are always assumed to be linear. Implementors should also be aware that there is no need to perform a computationally expensive exponentiation for every pixel in the image, or three times per pixel for an RGB image! At most, there are only 65,536 possible sample values (for a 16-bit grayscale or 48-bit RGB image) and usually no more than 256, which means that gamma correction can be accomplished via a simple lookup table computed when the gAMA chunk is read.

That brings us to the gAMA chunk itself. Its contents are quite simple: a 4-byte, unsigned integer equal to gamma multiplied by 100,000 and rounded to the nearest integer. So if gamma is 1/2.2 (or 0.45454545...), the value in the gAMA chunk is 45,455. There can be only one gAMA chunk, and it must appear before any IDATs and also before the PLTE chunk, if one is present.

As a practical matter, there is one more piece to the decoder half of the gamma puzzle. The issue of exponents for the lookup table and monitor on various systems is more complex than it should be, mainly because different systems use the term ``gamma'' in strange and sometimes sneaky ways. Table 10-1 summarizes the issue for some common platforms.

Table 10-1. Gamma Comparison Across Common Platforms

Platform LUT_exponent Default
CRT_exponent Default
PC 1.0 1.0 2.2 45,455
Macintosh g/2.61 1.8/2.61 2.2 65,909
SGI 1/g 1/1.7 2.2 77,273
NeXT 1/g 1/2.2 2.2 100,000

The key thing to note, aside from the differences in default gAMA values across platforms, is that both Mac OS and SGI IRIX allow the user to modify a ``system gamma'' setting that not only differs from the gamma definition we're using but also differs between platforms. These ``gamma'' values modify the lookup table, and SGI's is straightforward: LUT_exponent is simply the inverse of the SGI ``gamma'' value, which is denoted g in Table 10-1. (NeXT workstations use the same convention as SGI, but the only way to modify their setting is with third-party utilities.) The Macintosh, on the other hand, not only defines its ``gamma'' as directly proportional to LUT_exponent but also divides it by a constant factor (2.61). Thus, while the default Macintosh ``gamma'' of 1.8 appears close to SGI's default of 1.7, the actual lookup table exponents corresponding to these defaults are 1.8/2.61 and 1/1.7, respectively.

Last Update: 2010-Nov-26