======================================= Proposed Revision of PNG Gamma Handling draft 1.2.3 (Sat 22 Aug 1998) ======================================= editor: Adam M. Costello authors in alphabetical order: John Bowler Adam M. Costello Chris Lilley Dave Martindale Glenn Randers-Pehrson Michael Stokes Description =========== This is a set of edits to be applied to the PNG 1.0 spec to fix the gamma handling. It uses the RFC 2083 text version as its basis. Format ====== Lines beginning with ">" are quoted for context purposes and don't need to be changed. Lines beginning with "-" are to be removed. Lines beginning with "?" are new text that is *not* to be inserted, unless we change our minds. Lines containing only "..." indicate skipped material that doesn't need to be changed. Other non-blank lines are to be inserted. Principles ========== The principles assumed by this proposal are as follows: * gAMA should relate sample values with light output from the display device. This is strongly advocated by Dave Martindale, in opposition to the only alternative under consideration, which would be to relate sample values with CRT input. * There should be only one "gamma", which is the exponent mapping desired display output to file samples. Other power functions have "exponents". No one feels strongly for or against this. * CRTs have a transfer function that can be approximated by a power function with exponent 2.2. This is the claim of the sRGB spec, which is gaining widespread acceptance. * An image ready for display on a CRT should have a gAMA value of 45455. Adam Costello argues that 50000 is more compatible with the existing spec, but John Bowler argues that 45000 or 45455 is more compatible with existing practice. Dave Martindale and Glenn Randers-Pehrson both like 45455 for aesthetic reasons. * Adjusting for viewing conditions requires more complex models than power functions, so it should be considered to be above and beyond "gamma handling". We don't really understand it ourselves, so this spec should not attempt to say how it is done. * The sRGB chunk should be in the main spec. Although it logically goes with gAMA and cHRM, it appears at the end of the ancillary chunks section so that the other chunk sections don't need to be renumbered, so that citations to them don't break. * The iCCP chunk should be in the main spec, right after the sRGB chunk. * A sample cannot be "linear". Only a function can be linear. A sample must be proportional to something. This is especially true considering that scene intensity and display output intensity are not, in general, linearly related. Unresolved Issues ================= * The color handling stuff has barely been touched. Is it still valid under the new model (using the display output as the reference rather than the camera input), or does it need more edits? * Should we refer to CIE 122? * Should we say anything about constructing gamma correction tables using fixed-point math? Edits ===== > PNG (Portable Network Graphics) Specification - Version 1.0 Version 1.1 ... > 1. Introduction ... - In this specification, the word "must" indicates a mandatory - requirement, while "should" indicates recommended behavior. The words "must", "required", "should", "recommended", "may", and "optional" in this document are to be interpreted as described in [RFC-2119], which is consistent with their plain English meanings. The word "can" carries the same force as "may". ... > 2.1. Integers and byte order ... Unless otherwise stated, four-byte unsigned integers are limited to the range 0 to (2^31)-1 to accommodate languages that have difficulty with unsigned four-byte values. Similarly, four-byte signed integers are limited to the range -((2^31)-1) to (2^31)-1 to accommodate languages that have difficulty with the value -2^31. > See Rationale: Byte order (Section 12.5). > 2.2. Color values - Sample values are not necessarily linear; the gAMA chunk specifies - the gamma characteristic of the source device, and viewers are - strongly encouraged to compensate properly. Sample values are not necessarily proportional to light intensity; the gAMA chunk specifies the relationship between sample values and display output intensity, and viewers are strongly encouraged to compensate properly. ... > 2.7. Gamma correction - PNG images can specify, via the gAMA chunk, the gamma - characteristic of the image with respect to the original scene. - Display programs are strongly encouraged to use this information, - plus information about the display device they are using and room - lighting, to present the image to the viewer in a way that - reproduces what the image's original author saw as closely as - possible. PNG images can specify, via the gAMA chunk, the power function relating the desired display output with the image samples. Display programs are strongly encouraged to use this information, plus information about the display system they are using, to present the image to the viewer in a way that reproduces what the image's original author saw as closely as possible. > Gamma correction is not applied to the alpha channel, if any. > Alpha samples always represent a linear fraction of full opacity. > > For high-precision applications, the exact chromaticity of the RGB > data in a PNG image can be specified via the cHRM chunk, allowing > more accurate color matching than gamma correction alone will > provide. See Color Tutorial (Chapter 14) if you aren't already > familiar with color representation issues. If the RGB data conforms to the sRGB specification [sRGB], this can be indicated with the sRGB chunk, enabling even more accurate reproduction. Alternately, the iCCP chunk can be used to embed an ICC profile [ICC] containing highly detailed color space information. > See Rationale: Why gamma? (Section 12.7), Recommendations for > Encoders: Encoder gamma handling (Section 9.2), and > Recommendations for Decoders: Decoder gamma handling (Section > 10.5). ... > 2.8. Text strings ... - ISO 8859-1 (Latin-1) is the character set recommended for use in - text strings [ISO-8859]. This character set is a superset of 7- - bit ASCII. ISO/IEC 8859-1 (Latin-1) is the character set recommended for use in text strings [ISO/IEC-8859-1]. This character set is a superset of 7-bit ASCII. ... > 4.2.1. bKGD Background color ... > For color types 0 and 4 (grayscale, with or without alpha), > bKGD contains: > > Gray: 2 bytes, range 0 .. (2^bitdepth)-1 - (For consistency, 2 bytes are used regardless of the image bit - depth.) (If the image bit depth is less than 16, the least significant bits are used and the others are 0.) > The value is the gray level to be used as background. > For color types 2 and 6 (truecolor, with or without alpha), > bKGD contains: > > Red: 2 bytes, range 0 .. (2^bitdepth)-1 > Green: 2 bytes, range 0 .. (2^bitdepth)-1 > Blue: 2 bytes, range 0 .. (2^bitdepth)-1 - (For consistency, 2 bytes per sample are used regardless of the - image bit depth.) (If the image bit depth is less than 16, the least significant bits are used and the others are 0.) > This is the RGB color to be used as > background. ... > 4.2.2. cHRM Primary chromaticities and white point ... > If the cHRM chunk appears, it must precede the first IDAT > chunk, and it must also precede the PLTE chunk if present. An sRGB chunk or iCCP chunk, when present and recognized, overrides the cHRM chunk. See Sections 4.2.11 and 4.2.12. ... - 4.2.3. gAMA Image gamma 4.2.3. gAMA Gamma - The gAMA chunk specifies the gamma of the camera (or simulated - camera) that produced the image, and thus the gamma of the - image with respect to the original scene. More precisely, the - gAMA chunk encodes the file_gamma value, as defined in Gamma - Tutorial (Chapter 13). - - The gAMA chunk contains: - - Image gamma: 4 bytes - - The value is encoded as a 4-byte unsigned integer, representing - gamma times 100000. For example, a gamma of 0.45 would be - stored as the integer 45000. The gAMA chunk specifies the relationship between the image samples and the desired display output intensity as a power function: sample = light_out ^ gamma Here sample and light_out are normalized to the range 0.0 (minimum intensity) to 1.0 (maximum intensity). Therefore: sample = integer_sample / (2^bitdepth - 1) The gAMA chunk contains: Gamma: 4 bytes The value is encoded as a 4-byte unsigned integer, representing gamma times 100000. For example, a gamma of 1/2.2 would be stored as 45455. The gamma value has no effect on alpha samples, which are always a linear fraction of full opacity. > If the encoder does not know the image's gamma value, it should > not write a gAMA chunk; the absence of a gAMA chunk indicates > that the gamma is unknown. Technically, "desired display output intensity" is not specific enough; one needs to specify the viewing conditions under which the output is desired. gAMA assumes the reference viewing conditions of the sRGB specification [sRGB], which are based on ISO standards [ISO-3664]. Adjusting for different viewing conditions is a complex process normally handled by a Color Management System (CMS). If this adjustment is not performed, the error is usually small. Applications desiring high color fidelity may wish to use an sRGB chunk (Section 4.2.11) or an iCCP chunk (Section 4.2.12). > If the gAMA chunk appears, it must precede the first IDAT > chunk, and it must also precede the PLTE chunk if present. An sRGB chunk or iCCP chunk, when present and recognized, overrides the gAMA chunk. See Sections 4.2.11 and 4.2.12. > See Gamma correction (Section 2.7), Recommendations for > Encoders: Encoder gamma handling (Section 9.2), and > Recommendations for Decoders: Decoder gamma handling (Section > 10.5). ... > 4.2.7. tEXt Textual data ... - Both keyword and text are interpreted according to the ISO - 8859-1 (Latin-1) character set [ISO-8859]. Both keyword and text are interpreted according to the ISO/IEC 8859-1 (Latin-1) character set [ISO/IEC-8859-1]. > The text string can > contain any Latin-1 character. Newlines in the text string > should be represented by a single linefeed character (decimal > 10); use of other control characters in the text is > discouraged. ... > 4.2.9. tRNS Transparency ... > For color type 0 (grayscale), the tRNS chunk contains a single > gray level value, stored in the format: > > Gray: 2 bytes, range 0 .. (2^bitdepth)-1 - (For consistency, 2 bytes are used regardless of the image bit - depth.) (If the image bit depth is less than 16, the least significant bits are used and the others are 0.) > Pixels of the specified gray level are to be treated as > transparent (equivalent to alpha value 0); all other pixels are > to be treated as fully opaque (alpha value (2^bitdepth)-1). > > For color type 2 (truecolor), the tRNS chunk contains a single > RGB color value, stored in the format: > > Red: 2 bytes, range 0 .. (2^bitdepth)-1 > Green: 2 bytes, range 0 .. (2^bitdepth)-1 > Blue: 2 bytes, range 0 .. (2^bitdepth)-1 - (For consistency, 2 bytes per sample are used regardless of the - image bit depth.) (If the image bit depth is less than 16, the least significant bits are used and the others are 0.) > Pixels of the specified color value are to be > treated as transparent (equivalent to alpha value 0); all other > pixels are to be treated as fully opaque (alpha value > 2^bitdepth)-1). ... 4.2.11. sRGB Standard RGB If the sRGB chunk is present, the image samples conform to the sRGB color space [sRGB], and should be displayed using the specified rendering intent as defined by the International Color Consortium [ICC]. The sRGB chunk contains: Rendering intent: 1 byte The following values are legal for the rendering intent: 0: Perceptual For images preferring good adaptation to the output device gamut at the expense of colorimetric accuracy, like photographs. 1: Relative colorimetric For images requiring color appearance matching (relative to the output device white point), like logos. 2: Saturation For images preferring preservation of saturation at the expense of hue and lightness, like charts and graphs. 3: Absolute colorimetric For images requiring preservation of absolute colorimetry, like proofs (previews of images destined for a different output device). An application that creates the sRGB chunk should also create gAMA and cHRM chunks for compatibility with applications that do not use the sRGB chunk. In this situation, only the following values may be used: gAMA: Gamma: 45455 cHRM: White Point x: 31270 White Point y: 32900 Red x: 64000 Red y: 33000 Green x: 30000 Green y: 60000 Blue x: 15000 Blue y: 6000 When the sRGB chunk is present, applications that recognize it and are capable of color management [ICC] must ignore the gAMA and cHRM chunks and use the sRGB chunk instead. Applications that recognize the sRGB chunk but are not capable of full-fledged color management must also ignore the gAMA and cHRM chunks, because the applications already know what values those chunks should contain. The applications must therefore use the values of gAMA and cHRM given above as if they had appeared in gAMA and cHRM chunks. If the sRGB chunk appears, it must precede the first IDAT chunk, and it must also precede the PLTE chunk if present. 4.2.12. iCCP Embedded ICC profile If the iCCP chunk is present, the image samples conform to the color space represented by the embedded International Color Consortium profile as defined by the ICC [ICC]. The color space of the ICC profile must be an RGB color space for color images (PNG color types 2, 3, and 6), or a monochrome grayscale color space for grayscale images (PNG color types 0 and 4). The iCCP chunk contains: Profile name: 1-79 bytes (character string) Null separator: 1 byte Compression method: 1 byte Compressed profile: n bytes The format is like the zTXt chunk. The profile name can be any convenient name for referring to the profile, and is subject to the same restrictions as a tEXt keyword: it must contain only printable Latin-1 [ISO/IEC-8859-1] characters (33-126 and 161-255) and spaces (32), but no leading, trailing, or consecutive spaces. The only value presently defined for the compression method byte is 0, meaning zlib datastream with deflate compression. Decompression of the remainder of the chunk yields the ICC profile. An application that creates the iCCP chunk should also create gAMA and cHRM chunks that approximate the ICC profile's transfer function, for compatibility with applications that do not use the iCCP chunk. When the iCCP chunk is present, applications that recognize it and are capable of color management [ICC] should ignore the gAMA and cHRM chunks and use the iCCP chunk instead, but applications incapable of full-fledged color management should use the gAMA and cHRM chunks if present. A file should contain at most one embedded profile, whether explicit like iCCP or implicit like sRGB. If the iCCP chunk appears, it must precede the first IDAT chunk, and it must also precede the PLTE chunk if present. > 4.3. Summary of standard chunks > Name Multiple Ordering constraints > OK? > > cHRM No Before PLTE and IDAT > gAMA No Before PLTE and IDAT > sBIT No Before PLTE and IDAT > bKGD No After PLTE; before IDAT > hIST No After PLTE; before IDAT > tRNS No After PLTE; before IDAT > pHYs No Before IDAT > tIME No None > tEXt Yes None > zTXt Yes None sRGB No Before PLTE and IDAT iCCP No Before PLTE and IDAT ... > 5. Deflate/Inflate Compression ... - PNG also uses zlib datastreams in zTXt chunks. In a zTXt chunk, the - remainder of the chunk following the compression method byte is a - zlib datastream as specified above. This datastream decompresses to - the user-readable text described by the chunk's keyword. Unlike the - image data, such datastreams are not split across chunks; each zTXt - chunk contains an independent zlib datastream. PNG also uses zlib datastreams in zTXt and iCCP chunks, where the remainder of the chunk following the compression method byte is a zlib datastream as specified above. Unlike the image data, such datastreams are not split across chunks; each zTXt or iCCP chunk contains an independent zlib datastream. ... > 9.2. Encoder gamma handling > See Gamma Tutorial (Chapter 13) if you aren't already familiar > with gamma issues. Encoders capable of full-fledged color management [ICC] will perform more sophisticated calculations than those described here. Encoders that know that their image samples conform to the sRGB specification [sRGB] should use the sRGB chunk and not perform gamma handling. Otherwise, this section applies. The encoder has two gamma-related decisions to make. First, it must decide how to transform whatever image samples it has into the image samples that will go into the PNG file. Second, it must decide what value to write into the gAMA chunk. The rule for the second decision is simply to write whatever value will cause a decoder to do what you want. See Recommendations for Decoders: Decoder gamma handling (Section 10.5). - Proper handling of gamma encoding and the gAMA chunk in an encoder - depends on the prior history of the sample values and on whether - these values have already been quantized to integers. - - If the encoder has access to sample intensity values in floating- - point or high-precision integer form (perhaps from a computer - image renderer), then it is recommended that the encoder perform - its own gamma encoding before quantizing the data to integer - values for storage in the file. Applying gamma encoding at this - stage results in images with fewer banding artifacts at a given - sample depth, or allows smaller samples while retaining the same - visual quality. - - A linear intensity level, expressed as a floating-point value in - the range 0 to 1, can be converted to a gamma-encoded sample value - by - - sample = ROUND((intensity ^ encoder_gamma) * MAXSAMPLE) - - The file_gamma value to be written in the PNG gAMA chunk is the - same as encoder_gamma in this equation, since we are assuming the - initial intensity value is linear (in effect, camera_gamma is - 1.0). The first decision depends on the nature of the image samples and their precision. If the samples represent light intensity in floating point or high-precision integer form (perhaps from a computer image renderer), then the encoder may perform "gamma encoding" (applying a power function with exponent less than 1) before quantizing the data to integer values for output to the file. This results in fewer banding artifacts at a given sample depth, or allows smaller samples while retaining the same visual quality. An intensity level expressed as a floating point value in the range 0 to 1 can be converted to a file image sample by sample = intensity ^ encoding_exponent integer_sample = ROUND(sample * (2^bitdepth - 1)) If the intensity in the equation is the desired display output intensity, then encoding_exponent is the gamma value to be written to the file, by the definition of gAMA (Section 4.2.3). But if the intensity available to the encoder is the original scene intensity, another transformation may be needed. Sometimes the displayed image should have higher contrast than the original image; in other words, the end-to-end transfer function from original scene to display output should have an exponent greater than 1. In this case, gamma = encoding_exponent / end_to_end_exponent If you don't know whether the conditions under which the original image was captured (or calculated) warrant such a contrast change, you may assume that display intensities are proportional to original scene intensities; in other words, end_to_end_exponent is 1, so gamma and encoding_exponent are equal. - If the image is being written to a file only, the encoder_gamma - value can be selected somewhat arbitrarily. Values of 0.45 or 0.5 - are generally good choices because they are common in video - systems, and so most PNG decoders should do a good job displaying - such images. If the image is being written to a file only, the encoder is free to choose the encoding_exponent. Choosing a value that causes the gamma value in the gAMA chunk to be 1/2.2 is often a reasonable choice because it minimizes the work for a decoder displaying on a typical video monitor. - Some image renderers may simultaneously write the image to a PNG - file and display it on-screen. The displayed pixels should be - gamma corrected for the display system and viewing conditions in - use, so that the user sees a proper representation of the intended - scene. An appropriate gamma correction value is - - screen_gc = viewing_gamma / display_gamma - - If the renderer wants to write the same gamma-corrected sample - values to the PNG file, avoiding a separate gamma-encoding step - for file output, then this screen_gc value should be written in - the gAMA chunk. This will allow a PNG decoder to reproduce what - the file's originator saw on screen during rendering (provided the - decoder properly supports arbitrary values in a gAMA chunk). Some image renderers may simultaneously write the image to a PNG file and display it on-screen. The displayed pixels should be appropriate for the display system, so that the user sees a proper representation of the intended scene. If the renderer wants to write the displayed sample values to the PNG file, avoiding a separate gamma encoding step for file output, then the renderer should approximate the transfer function of the display system by a power function, and write the reciprocal of the exponent into the gAMA chunk. This will allow a PNG decoder to reproduce what the file's originator saw on screen during rendering. - However, it is equally reasonable for a renderer to apply gamma - correction for screen display using a gamma appropriate to the - viewing conditions, and to separately gamma-encode the sample - values for file storage using a standard value of gamma such as - 0.5. In fact, this is preferable, since some PNG decoders may not - accurately display images with unusual gAMA values. However, it is equally reasonable for a renderer to compute displayed pixels appropriate for the display device, and to perform separate gamma encoding for file storage, arranging to have a value in the gAMA chunk more appropriate to the future use of the image. > Computer graphics renderers often do not perform gamma encoding, > instead making sample values directly proportional to scene light > intensity. - If the PNG encoder receives sample values that have - already been quantized into linear-light integer values, there is If the PNG encoder receives intensity samples that have already been quantized into integers, there is > no point in doing gamma encoding on them; that would just result > in further loss of information. The encoder should just write the > sample values to the PNG file. This does not imply that the gAMA chunk should contain a gamma value of 1.0, because the desired end-to-end transfer function from scene intensity to display output intensity is not necessarily linear. The desired gamma value is probably not far from 1.0, however. It may depend on whether the scene being rendered is a daylight scene or an indoor scene, etc. - This "linear" sample encoding is - equivalent to gamma encoding with a gamma of 1.0, so graphics - programs that produce linear samples should always emit a gAMA - chunk specifying a gamma of 1.0. - - When the sample values come directly from a piece of hardware, the - correct gAMA value is determined by the gamma characteristic of - the hardware. In the case of video digitizers (rame grabbers"), - gAMA should be 0.45 or 0.5 for NTSC (possibly less for PAL or - SECAM) since video camera transfer functions are standardized. - Image scanners are less predictable. Their output samples may be - linear (gamma 1.0) since CCD sensors themselves are linear, or the - scanner hardware may have already applied gamma correction - designed to compensate for dot gain in subsequent printing (gamma - of about 0.57), or the scanner may have corrected the samples for - display on a CRT (gamma of 0.4-0.5). You will need to refer to - the scanner's manual, or even scan a calibrated gray wedge, to - determine what a particular scanner does. When the sample values come directly from a piece of hardware, the correct gamma value can in principle be inferred from the transfer function of the hardware and the lighting conditions of the scene. In the case of video digitizers ("frame grabbers"), the samples are probably in the sRGB color space, because the sRGB specification was designed to be compatible with video standards. Image scanners are less predictable. Their output samples may be proportional to the input light intensity because CCD sensors themselves are linear, or the scanner hardware may have already applied a power function designed to compensate for dot gain in subsequent printing (an exponent of about 0.57), or the scanner may have corrected the samples for display on a monitor. The device documentation might describe the transformation performed, or might describe the target display or printer for the image data (which might be configurable). You can also scan a calibrated target and use calibration software to determine the behavior of the device. Remember that gamma relates file samples to desired display output, not to scanner input. - File format converters generally should not attempt to convert - supplied images to a different gamma. Store the data in the PNG - file without conversion, and record the source gamma if it is - known. File format converters generally should not attempt to convert supplied images to a different gamma. Store the data in the PNG file without conversion, and deduce the gamma value from information in the source file if possible. > Gamma alteration at file conversion time causes re- > quantization of the set of intensity levels that are represented, > introducing further roundoff error with little benefit. It's > almost always better to just copy the sample values intact from > the input to the output file. - In some cases, the supplied image may be in an image format (e.g., - TIFF) that can describe the gamma characteristic of the image. In - such cases, a file format converter is strongly encouraged to - write a PNG gAMA chunk that corresponds to the known gamma of the - source image. Note that some file formats specify the gamma of - the display system, not the camera. If the input file's gamma - value is greater than 1.0, it is almost certainly a display system - gamma, and you should use its reciprocal for the PNG gAMA. If the source file format describes the gamma characteristic of the image, a file format converter is strongly encouraged to write a PNG gAMA chunk. Note that some file formats specify the exponent of the function mapping file samples to display output rather than the other direction. If the source file's gamma value is greater than 1.0, it is probably a display system exponent, and you should use its reciprocal for the PNG gamma. If the source file format records the relationship between image samples and something other than display output, then deducing the PNG gamma value will be more complex. - If the encoder or file format converter does not know how an image - was originally created, but does know that the image has been - displayed satisfactorily on a display with gamma display_gamma - under lighting conditions where a particular viewing_gamma is - appropriate, then the image can be marked as having the - file_gamma: - - file_gamma = viewing_gamma / display_gamma Regardless of how an image was originally created, if an encoder or file format converter knows that the image has been displayed satisfactorily using a display system whose transfer function can be approximated by a power function with exponent display_exponent, then the image can be marked as having the gamma value: gamma = 1 / display_exponent - This will allow viewers of the PNG file to see the same image that - the person running the file format converter saw. Although this - may not be precisely the correct value of the image gamma, it's - better to write a gAMA chunk with an approximately right value - than to omit the chunk and force PNG decoders to guess at an - appropriate gamma. It's better to write a gAMA chunk with an approximately right value than to omit the chunk and force PNG decoders to guess at an appropriate gamma. - On the other hand, if the image file is being converted as part of - a "bulk" conversion, with no one looking at each image, then it is - better to omit the gAMA chunk entirely. If the image gamma has to - be guessed at, leave it to the decoder to do the guessing. On the other hand, if the encoder has no way to infer the gamma value, then it is better to omit the gAMA chunk entirely. If the image gamma has to be guessed at, leave it to the decoder to do the guessing. > Gamma does not apply to alpha samples; alpha is always represented > linearly. > > See also Recommendations for Decoders: Decoder gamma handling > (Section 10.5). > 9.3. Encoder color handling > See Color Tutorial (Chapter 14) if you aren't already familiar > with color issues. Encoders that know that their image samples conform to the sRGB specification [sRGB] are strongly encouraged to use the sRGB chunk. Otherwise, this section applies. ... - Scanners that produce PNG files as output should insert the filter - chromaticities into a cHRM chunk and the camera_gamma into a gAMA - chunk. Scanners that produce PNG files as output should insert the filter chromaticities into a cHRM chunk. ... - PhotoCD also - uses the SMPTE-170M transfer function, which is closely - approximated by a gAMA of 0.5. PhotoCD also uses the SMPTE-170M transfer function. ... > 10.5. Decoder gamma handling > See Gamma Tutorial (Chapter 13) if you aren't already familiar > with gamma issues. Decoders capable of full-fledged color management [ICC] will perform more sophisticated calculations than what is described here. Otherwise, this section applies. - To produce correct tone reproduction, a good image display program - should take into account the gammas of the image file and the - display device, as well as the viewing_gamma appropriate to the - lighting conditions near the display. This can be done by - calculating - - gbright = insample / MAXINSAMPLE - bright = gbright ^ (1.0 / file_gamma) - vbright = bright ^ viewing_gamma - gcvideo = vbright ^ (1.0 / display_gamma) - fbval = ROUND(gcvideo * MAXFBVAL) - - where MAXINSAMPLE is the maximum sample value in the file (255 for - 8-bit, 65535 for 16-bit, etc), MAXFBVAL is the maximum value of a - frame buffer sample (255 for 8-bit, 31 for 5-bit, etc), insample - is the value of the sample in the PNG file, and fbval is the value - to write into the frame buffer. The first line converts from - integer samples into a normalized 0 to 1 floating point value, the - second undoes the gamma encoding of the image file to produce a - linear intensity value, the third adjusts for the viewing - conditions, the fourth corrects for the display system's gamma - value, and the fifth converts to an integer frame buffer sample. - In practice, the second through fourth lines can be merged into - - gcvideo = gbright^(viewing_gamma / (file_gamma*display_gamma)) For an image display program to produce correct tone reproduction, it is necessary to take into account the relationship between file samples and display output, and the transfer function of the display system. This can be done by calculating sample = integer_sample / (2^bitdepth - 1.0) display_output = sample ^ (1.0 / gamma) display_input = inverse_display_transfer(display_output) framebuf_sample = ROUND(display_input * MAX_FRAMEBUF_SAMPLE) where integer_sample is the sample value from the file, framebuf_sample is the value to write into the frame buffer, and MAX_FRAMEBUF_SAMPLE is the maximum value of a frame buffer sample (255 for 8-bit, 31 for 5-bit, etc). The first line converts an integer sample into a normalized 0-to-1 floating point value, the second converts to a value proportional to the desired display output intensity, the third accounts for the display system's transfer function, and the fourth converts to an integer frame buffer sample. A step could be inserted between the second and third to adjust display_output to account for the difference between the actual viewing conditions and the reference viewing conditions. However, this adjustment requires accounting for veiling glare, black mapping, and color appearance models, none of which can be well approximated by power functions. The calculations are not described here. If viewing conditions are ignored, the error will usually be small. Typically, the display transfer function can be approximated by a power function with exponent display_exponent, in which case the second and third lines can be merged into display_input = sample ^ (1.0 / (gamma * display_exponent)) = sample ^ decoding_exponent > so as to perform only one power calculation. For color images, the > entire calculation is performed separately for R, G, and B values. The value of gamma can be taken directly from the gAMA chunk. Alternatively, an application may wish to allow the user to adjust the appearance of the displayed image by influencing the value of gamma. For example, the user could manually set a parameter called user_exponent that defaults to 1.0, and the application could set gamma = gamma_from_file / user_exponent decoding_exponent = 1.0 / (gamma * display_exponent) = user_exponent / (gamma_from_file * display_exponent) The user would set user_exponent greater than 1 to darken the mid-level tones, or less than 1 to lighten them. > It is not necessary to perform transcendental math for every > pixel. Instead, compute a lookup table that gives the correct > output value for every possible sample value. This requires only > 256 calculations per image (for 8-bit accuracy), not one or three > calculations per pixel. For an indexed-color image, a one-time > correction of the palette is sufficient, unless the image uses > transparency and is being displayed against a nonuniform > background. - In some cases even the cost of computing a gamma lookup table may - be a concern. In these cases, viewers are encouraged to have - precomputed gamma correction tables for file_gamma values of 1.0 - and 0.5 with some reasonable choice of viewing_gamma and - display_gamma, and to use the table closest to the gamma indicated - in the file. This will produce acceptable results for the majority - of real files. ? In some cases even the cost of computing a gamma lookup table may ? be a concern. In these cases, viewers can have precomputed gamma ? correction tables for gamma values of 1.0 (typical of rendered ? images), 1/2.2 (typical of images produced on PC clones), and ? 1.45/2.2 (typical of images produced on Macintosh computers), with ? some reasonable choice of display_exponent, and to use the table ? closest to the gamma indicated in the file. This will produce ? acceptable results for the majority of real files. ? If floating-point calculations are not possible, gamma correction ? tables can be computed using fixed-point arithmetic and a ? precomputed table of logarithms. Example code is available at ? ftp://ftp.uu.net/graphics/png/gamma-lookup.c. - When the incoming image has unknown gamma (no gAMA chunk), choose - a likely default file_gamma value, but allow the user to select a - new one if the result proves too dark or too light. When the incoming image has unknown gamma (gAMA and sRGB both absent), choose a likely default gamma value, but allow the user to select a new one if the result proves too dark or too light. - In practice, it is often difficult to determine what value of - display_gamma should be used. In systems with no built-in gamma - correction, the display_gamma is determined entirely by the CRT. - Assuming a CRT_gamma of 2.5 is recommended, unless you have - detailed calibration measurements of this particular CRT - available. In practice, it is often difficult to determine what value of display_exponent should be used. In systems with no built-in gamma correction, the display_exponent is determined entirely by the CRT. Assume a CRT_exponent of 2.2 unless detailed calibration measurements of this particular CRT are available. - However, many modern frame buffers have lookup tables that are - used to perform gamma correction, and on these systems the - display_gamma value should be the gamma of the lookup table and - CRT combined. You may not be able to find out what the lookup - table contains from within an image viewer application, so you may - have to ask the user what the system's gamma value is. - Unfortunately, different manufacturers use different ways of - specifying what should go into the lookup table, so interpretation - of the system gamma value is system-dependent. Gamma Tutorial - (Chapter 13) gives some examples. Many modern frame buffers have lookup tables that are used to perform gamma correction, and on these systems the display_exponent value should be the exponent of the lookup table and CRT combined. You may not be able to find out what the lookup table contains from within an image viewer application, so you may have to ask the user what the display system's exponent is. Unfortunately, different manufacturers use different ways of specifying what should go into the lookup table, so interpretation of the system "gamma" value is system-dependent. Gamma Tutorial (Chapter 13) gives some examples. - The response of real displays is actually more complex than can be - described by a single number (display_gamma). If actual - measurements of the monitor's light output as a function of - voltage input are available, the fourth and fifth lines of the - computation above can be replaced by a lookup in these - measurements, to find the actual frame buffer value that most - nearly gives the desired brightness. The response of real displays is actually more complex than can be described by a single number (display_exponent). If actual measurements of the monitor's light output as a function of voltage input are available, the third and fourth lines of the computation above can be replaced by a lookup in these measurements, to find the actual frame buffer value that most nearly gives the desired brightness. - The value of viewing_gamma depends on lighting conditions; see - Gamma Tutorial (Chapter 13) for more detail. Ideally, a viewer - would allow the user to specify viewing_gamma, either directly - numerically, or via selecting from "bright surround", "dim - surround", and "dark surround" conditions. Viewers that don't - want to do this should just assume a value for viewing_gamma of - 1.0, since most computer displays live in brightly-lit rooms. - - When viewing images that are digitized from video, or that are - destined to become video frames, the user might want to set the - viewing_gamma to about 1.25 regardless of the actual level of room - lighting. This value of viewing_gamma is "built into" NTSC video - practice, and displaying an image with that viewing_gamma allows - the user to see what a TV set would show under the current room - lighting conditions. (This is not the same thing as trying to - obtain the most accurate rendition of the content of the scene, - which would require adjusting viewing_gamma to correspond to the - room lighting level.) This is another reason viewers might want - to allow users to adjust viewing_gamma directly. > 10.8. Alpha channel processing ... > where alpha and the input and output sample values are expressed > as fractions in the range 0 to 1. This computation should be > performed with - linear (non-gamma-encoded) sample values. intensity samples (not gamma-encoded samples). > For > color images, the computation is done separately for R, G, and B > samples. > > The following code illustrates the general case of compositing a > foreground image over a background image. It assumes that you > have the original pixel data available for the background image, > and that output is to a frame buffer for display. Other variants > are possible; see the comments below the code. The code allows the sample depths and gamma values of foreground and background images to be different, and not necessarily suited to the display system. Don't assume everything is the same without checking. - The code allows - the sample depths and gamma values of foreground image, background - image, and frame buffer/CRT all to be different. Don't assume - they are the same without checking. ... - 21 gcvideo = pow(comppix,viewing_gamma/display_gamma); 21 gcvideo = pow(comppix, 1.0/display_exponent); ... > 27 for (i = 0; i < 3; i++) { > /* > * Convert foreground and background to floating * point, then undo gamma encoding. - * point, then linearize (undo gamma encoding). ... - 33 gcvideo = pow(comppix,viewing_gamma/display_gamma); 33 gcvideo = pow(comppix, 1.0/display_exponent); ... > * If the original pixel values of the background image are no > longer available, only processed frame buffer pixels left by > display of the background image, then lines 30 and 31 need > to extract intensity from the frame buffer pixel values > using code like > /* - * Decode frame buffer value back into linear space. * Convert frame buffer value into intensity sample. > */ > gcvideo = (float) fbpix[i] / fb_maxsample; linbg = pow(gcvideo, display_exponent); - linbg = pow(gcvideo, display_gamma / viewing_gamma); > However, some roundoff error can result, so it is better to > have the original background pixels available if at all > possible. ... > 11. Glossary ... > Gamma - The brightness of mid-level tones in an image. More precisely, a - parameter that describes the shape of the transfer function for - one or more stages in an imaging pipeline. The transfer function - is given by the expression - - output = input ^ gamma - - where both input and output are scaled to the range 0 to 1. Informally, a measure of the brightness of mid-level tones in an image. Outside this specification, the term "gamma" is often used as the exponent of a power function that is the transfer function of any stage(s) of an imaging pipeline: output = input ^ gamma Within this specification, gamma refers specifically to the function from display output to image samples. ... > 12.7. Why gamma? - It might seem natural to standardize on storing sample values that - are linearly proportional to light intensity (that is, have gamma - of 1.0). But in fact, it is common for images to have a gamma of - less than 1. There are three good reasons for this: It might seem natural to standardize on storing sample values proportional to display output intensity (that is, have gamma of 1.0). But in fact, it is common for images to have a gamma of less than 1. There are three good reasons for this: - * For reasons detailed in Gamma Tutorial (Chapter 13), all - video cameras apply a "gamma correction" function to the - intensity information. This causes the video signal to have - a gamma of about 0.5 relative to the light intensity in the - original scene. Thus, images obtained by frame-grabbing - video already have a gamma of about 0.5. * CRTs have a transfer function with an exponent of 2.2, and video signals are designed to be sent directly to CRTs. Therefore, images obtained by frame-grabbing video already have a gamma of 1/2.2. ... > * Many images are created on PCs or workstations with no gamma > correction hardware and no software willing to provide gamma > correction either. In these cases, the images have had > their lighting and color chosen to look best on this > platform --- they can be thought of as having "manual" gamma > correction built in. To see what the image author intended, it is necessary to treat such images as having a gamma value of 1/2.2 (assuming the author was using a CRT). - To see what the image author intended, - it is necessary to treat such images as having a file_gamma - value in the range 0.4-0.6, depending on the room lighting - level that the author was working in. - In practice, image gamma values around 1.0 and around 0.5 are both - widely found. Older image standards such as GIF often do not - account for this fact. The JFIF standard specifies that images in - that format should use linear samples, but many JFIF images found - on the Internet actually have a gamma somewhere near 0.4 or 0.5. - The variety of images found and the variety of systems that people - display them on have led to widespread problems with images - appearing "too dark" or "too light". In practice, image gamma values around 1.0, 1/2.2, and 1/1.45 are all widely found. Older image standards such as GIF and JFIF often do not account for this fact. The exchange of images among a variety of systems has led to widespread problems with images appearing "too dark" or "too light". ... > Since there will always be images with no gamma or an incorrect > recorded gamma, good viewers will need to incorporate gamma > adjustment code anyway. Gamma correction at viewing time is thus > the right way to go. Historical note: Version 1.0 of this specification used the gAMA chunk to express the relationship between the file samples and the "original scene intensity" (camera input) rather than the desired display output intensity. This was changed in version 1.1 for the following reasons: * The decoder needs to know the desired display output in order to do its job, but there was not enough information in the file to convert from the original scene to the display output. The version 1.0 specification claimed that the conversion depended only on viewing conditions at the display, but that was an error; it also depends on conditions at the camera. * Faithful reproduction of the original scene is not always the goal. Sometimes deliberate distortion is desired. * For hand-drawn images there is no "original scene". Because the gamma-related recommendations in version 1.0 were imprecise, it was not clear what value to put in a gAMA chunk in common situations. For an image drawn on a CRT display with no LUT under unknown viewing conditions, an argument could be made for any value between 40000 and 50000. Real applications were observed to write 45000 or 45455, and the latter is recommended by the current specification. ... > 13. Appendix: Gamma Tutorial > (This appendix is not part of the formal PNG specification.) > > It would be convenient for graphics programmers if all of the > components of an imaging system were linear. The voltage coming from > an electronic camera would be directly proportional to the intensity > (power) of light in the scene, the light emitted by a CRT would be > directly proportional to its input voltage, and so on. However, > real-world devices do not behave in this way. All CRT displays, > almost all photographic film, and many electronic cameras have > nonlinear signal-to-light-intensity or intensity-to-signal > characteristics. > > Fortunately, all of these nonlinear devices have a transfer function > that is approximated fairly well by a single type of mathematical > function: a power function. This power function has the general > equation - output = input ^ gamma output = input ^ exponent - where ^ denotes exponentiation, and "gamma" (often printed using the - Greek letter gamma, thus the name) is simply the exponent of the - power function. where ^ denotes exponentiation. The exponent is often called "gamma" and denoted by the Greek letter gamma. > By convention, "input" and "output" are both scaled to the range > 0..1, with 0 representing black and 1 representing maximum white (or > red, etc). Normalized in this way, the power function is completely - described by a single number, the exponent "gamma". described by the exponent. - So, given a particular device, we can measure its output as a - function of its input, fit a power function to this measured transfer - function, extract the exponent, and call it gamma. We often say - "this device has a gamma of 2.5" as a shorthand for "this device has - a power-law response with an exponent of 2.5". We can also talk - about the gamma of a mathematical transform, or of a lookup table in - a frame buffer, so long as the input and output of the thing are - related by the power-law expression above. So, given a particular device, we can measure its output as a function of its input, fit a power function to this measured transfer function, and extract the exponent. People often say "this device has a gamma of 2.2" as a shorthand for "this device has a power-law response with an exponent of 2.2". People also talk about the gamma of a mathematical transform, or of a lookup table in a frame buffer, if its input and output are related by the power-law expression above. But using the term "gamma" to refer to the exponents of transfer functions of many different stages in imaging pipelines has led to confusion. Therefore, this specification uses "gamma" to refer specifically to the function from display output to image samples, and simply uses "exponent" when referring to other functions. - How do gammas combine? How do exponents combine? > Real imaging systems will have several components, and more than > one of these can be nonlinear. If all of the components have > transfer characteristics that are power functions, then the > transfer function of the entire system is also a power function. The exponent of the whole system's transfer function is just the product of all of the individual exponents of the separate stages in the system. - The exponent (gamma) of the whole system's transfer function is - just the product of all of the individual exponents (gammas) of - the separate stages in the system. > Also, stages that are linear pose no problem, since a power > function with an exponent of 1.0 is really a linear function. So > a linear transfer function is just a special case of a power function, with an exponent of 1.0. - function, with a gamma of 1.0. > Thus, as long as our imaging system contains only stages with > linear and power-law transfer functions, we can meaningfully talk about the exponent of the entire system. This is indeed the case with most real imaging systems. - about the gamma of the entire system. This is indeed the case - with most real imaging systems. - What should overall gamma be? What should the end-to-end exponent be? - If the overall gamma of an imaging system is 1.0, its output is - linearly proportional to its input. If the end-to-end exponent of an imaging system is 1.0, its output is proportional to its input. > This means that the ratio > between the intensities of any two areas in the reproduced image > will be the same as it was in the original scene. It might seem > that this should always be the goal of an imaging system: to > accurately reproduce the tones of the original scene. Alas, that > is not the case. - When the reproduced image is to be viewed in "bright surround" - conditions, where other white objects nearby in the room have - about the same brightness as white in the image, then an overall - gamma of 1.0 does indeed give real-looking reproduction of a - natural scene. Photographic prints viewed under room light and - computer displays in bright room light are typical "bright - surround" viewing conditions. - - However, sometimes images are intended to be viewed in "dark - surround" conditions, where the room is substantially black except - for the image. This is typical of the way movies and slides - (transparencies) are viewed by projection. Under these - circumstances, an accurate reproduction of the original scene - results in an image that human viewers judge as "flat" and lacking - in contrast. It turns out that the projected image needs to have - a gamma of about 1.5 relative to the original scene for viewers to - judge it "natural". Thus, slide film is designed to have a gamma - of about 1.5, not 1.0. - - There is also an intermediate condition called "dim surround", - where the rest of the room is still visible to the viewer, but is - noticeably darker than the reproduced image itself. This is - typical of television viewing, at least in the evening, as well as - subdued-light computer work areas. In dim surround conditions, - the reproduced image needs to have a gamma of about 1.25 relative - to the original scene in order to look natural. - - The requirement for boosted contrast (gamma) in dark surround - conditions is due to the way the human visual system works, and - applies equally well to computer monitors. Thus, a PNG viewer - trying to achieve the maximum realism for the images it displays - really needs to know what the room lighting conditions are, and - adjust the gamma of the displayed image accordingly. - - If asking the user about room lighting conditions is inappropriate - or too difficult, just assume that the overall gamma - (viewing_gamma as defined below) should be 1.0 or 1.25. That's - all that most systems that implement gamma correction do. One complication is that the response of the human visual system to low light levels is not a scaled-down version of its response to high light levels. Therefore, if the display device emits less intense light than entered the capture device (as is usually the case for television cameras and television sets, for example), an end-to-end linear response will not produce an image that appears correct. There are also other perceptual factors, like the affect of the ambient light level and the field of view surrounding the display, and physical factors, like reflectance of ambient light off the display. Good end-to-end exponents are determined from experience. For example, for photographic prints it's about 1.0; for slides intended to be projected in a dark room it's about 1.5; for television it's about 1.14. - What is a CRT's gamma? What is a CRT's exponent? - All CRT displays have a power-law transfer characteristic with a - gamma of about 2.5. All CRT displays have a power-law transfer function with an exponent of about 2.2. > This is due to the physical processes > involved in controlling the electron beam in the electron gun, and > has nothing to do with the phosphor. > > An exception to this rule is fancy "calibrated" CRTs that have > internal electronics to alter their transfer function. If you > have one of these, you probably should believe what the manufacturer tells you its exponent is. But in all other cases, assuming 2.2 is likely to be pretty accurate. - manufacturer tells you its gamma is. But in all other cases, - assuming 2.5 is likely to be pretty accurate. - There are various images around that purport to measure gamma, There are various images around that purport to measure a display system's exponent, > usually by comparing the intensity of an area containing > alternating white and black with a series of areas of continuous > gray of different intensity. These are usually not reliable. > Test images that use a "checkerboard" pattern of black and white > are the worst, because a single white pixel will be reproduced > considerably darker than a large area of white. An image that > uses alternating black and white horizontal lines (such as the > "gamma.png" test image at > ftp://ftp.uu.net/graphics/png/images/suite/gamma.png) is much > better, but even it may be inaccurate at high "picture" settings > on some CRTs. > > If you have a good photometer, you can measure the actual light > output of a CRT as a function of input voltage and fit a power > function to the measurements. However, note that this procedure > is very sensitive to the CRT's black level adjustment, somewhat > sensitive to its picture adjustment, and also affected by ambient > light. Furthermore, CRTs spread some light from bright areas of > an image into nearby darker areas; a single bright spot against a > black background may be seen to have a "halo". Your measuring > technique will need to minimize the effects of this. - Because of the difficulty of measuring gamma, using either test - images or measuring equipment, you're usually better off just - assuming gamma is 2.5 rather than trying to measure it. Because of the difficulty of measuring the exponent, using either test images or measuring equipment, you're usually better off just assuming 2.2 rather than trying to measure it. > What is gamma correction? - A CRT has a gamma of 2.5, and we can't change that. To get an - overall gamma of 1.0 (or somewhere near that) for an imaging - system, we need to have at least one other component of the "image - pipeline" that is nonlinear. If, in fact, there is only one - nonlinear stage in addition to the CRT, then it's traditional to - say that the CRT has a certain gamma, and that the other nonlinear - stage provides "gamma correction" to compensate for the CRT. - However, exactly where the "correction" is done depends on - circumstance. A CRT has an exponent of 2.2, and we can't change that. To get an end-to-end exponent closer to 1, we need to have at least one other component of the "image pipeline" that is nonlinear. If, in fact, there is only one nonlinear stage in addition to the CRT, then it's traditional to say that the other nonlinear stage provides "gamma correction" to compensate for the CRT. However, exactly where the "correction" is done depends on circumstance. - In all broadcast video systems, gamma correction is done in the - camera. This choice was made in the days when television - electronics were all analog, and a good gamma-correction circuit - was expensive to build. The original NTSC video standard required - cameras to have a transfer function with a gamma of 1/2.2, or - about 0.45. Recently, a more complex two-part transfer function - has been adopted [SMPTE-170M], but its behavior can be well - approximated by a power function with a gamma of 0.5. When the - resulting image is displayed on a CRT with a gamma of 2.5, the - image on screen ends up with a gamma of about 1.25 relative to the - original scene, which is appropriate for "dim surround" viewing. In all broadcast video systems, gamma correction is done in the camera. This choice was made because it was more cost effective to place the expensive processing in the small number of capture devices (studio television cameras) than in the large number of broadcast receivers. The original NTSC video standard required cameras to have a transfer function with an exponent of 1/2.2, or about 0.45. Recently, a more complex two-part transfer function has been adopted [SMPTE-170M], but its behavior can be well approximated by a power function with an exponent of 0.52. When the resulting image is displayed on a CRT with an exponent of 2.2, the end-to-end exponent is about 1.14, which has been found to be appropriate for typical television studio conditions and television viewing conditions. - These days, video signals are often digitized and stored in - computer frame buffers. This works fine, but remember that gamma - correction is "built into" the video signal, and so the digitized - video has a gamma of about 0.5 relative to the original scene. These days, video signals are often digitized and stored in computer frame buffers. The digital image is intended to be sent through a CRT, which has exponent 2.2, so the image has a gamma of 1/2.2. - Computer rendering programs often produce linear samples. To - display these correctly, intensity on the CRT needs to be directly - proportional to the sample values in the frame buffer. This can - be done with a special hardware lookup table between the frame - buffer and the CRT hardware. The lookup table (often called LUT) - is loaded with a mapping that implements a power function with a - gamma of 0.4, thus providing "gamma correction" for the CRT gamma. Computer rendering programs often produce samples proportional to scene intensity. Suppose the desired end-to-end exponent is near 1, and the program would like to write its samples directly into the frame buffer. For correct display, the CRT output intensity must be nearly proportional to the sample values in the frame buffer. This can be done with a special hardware lookup table between the frame buffer and the CRT hardware. The lookup table (often called LUT) is loaded with a mapping that implements a power function with an exponent near 1/2.2, providing "gamma correction" for the CRT gamma. > Thus, gamma correction sometimes happens before the frame buffer, > sometimes after. - As long as images created in a particular - environment are always displayed in that environment, everything As long as images created on a particular platform are always displayed on that platform, everything > is fine. But when people try to exchange images, differences in > gamma correction conventions often result in images that seem far > too bright and washed out, or far too dark and contrasty. > Gamma-encoded samples are good > So, is it better to do gamma correction before or after the frame > buffer? > > In an ideal world, sample values would be stored in floating > point, there would be lots of precision, and it wouldn't really > matter much. But in reality, we're always trying to store images > in as few bits as we can. - If we decide to use samples that are linearly proportional to If we decide to use samples proportional to > intensity, and do the gamma correction in the frame buffer LUT, it > turns out that we need to use at least 12 bits for each of red, > green, and blue to have enough precision in intensity. With any > less than that, we will sometimes see "contour bands" or "Mach > bands" in the darker areas of the image, where two adjacent sample > values are still far enough apart in intensity for the difference > to be visible. > > However, through an interesting coincidence, the human eye's > subjective perception of brightness is related to the physical > stimulation of light intensity in a manner that is very much like > the power function used for gamma correction. If we apply gamma > correction to measured (or calculated) light intensity before > quantizing to an integer for storage in a frame buffer, we can get > away with using many fewer bits to store the image. In fact, 8 > bits per color is almost always sufficient to avoid contouring > artifacts. This is because, since gamma correction is so closely > related to human perception, we are assigning our 256 available > sample codes to intensity values in a manner that approximates how > visible those intensity changes are to the eye. Compared to a - linear-sample image, we allocate fewer sample values to brighter linearly encoded image, we allocate fewer sample values to brighter > parts of the tonal range and more sample values to the darker > portions of the tonal range. > > Thus, for the same apparent image quality, images using gamma- > encoded sample values need only about two-thirds as many bits of storage as images using linearly encoded samples. - storage as images using linear samples. > General gamma handling > When more than two nonlinear transfer functions are involved in > the image pipeline, the term "gamma correction" becomes too vague. > If we consider a pipeline that involves capturing (or calculating) > an image, storing it in an image file, reading the file, and > displaying the image on some sort of display screen, there are at > least 5 places in the pipeline that could have nonlinear transfer functions. Let's give a specific name to each exponent: - functions. Let's give each a specific name for their - characteristic gamma: - camera_gamma - the characteristic of the image sensor - - encoding_gamma - the gamma of any transformation performed by the software - writing the image file - - decoding_gamma - the gamma of any transformation performed by the software - reading the image file - - LUT_gamma - the gamma of the frame buffer LUT, if present - - CRT_gamma - the gamma of the CRT, generally 2.5 camera_exponent the exponent of the image sensor encoding_exponent the exponent of any transformation performed by the software writing the image file decoding_exponent the exponent of any transformation performed by the software reading the image file LUT_exponent the exponent of the frame buffer LUT, if present CRT_exponent the exponent of the CRT, generally 2.2 > In addition, let's add a few other names: - file_gamma - the gamma of the image in the file, relative to the original - scene. This is - - file_gamma = camera_gamma * encoding_gamma - - display_gamma - the gamma of the "display system" downstream of the frame - buffer. This is - - display_gamma = LUT_gamma * CRT_gamma - - viewing_gamma - the overall gamma that we want to obtain to produce pleasing - images --- generally 1.0 to 1.5. display_exponent the exponent of the "display system" downstream of the frame buffer display_exponent = LUT_exponent * CRT_exponent gamma the exponent of the function mapping display output intensity to file samples gamma = 1.0 / (decoding_exponent * display_exponent) end_to_end_exponent the exponent of the function mapping image sensor input intensity to display output intensity, generally 1.0 to 1.5 - The file_gamma value, as defined above, is what goes in the gAMA - chunk in a PNG file. If file_gamma is not 1.0, we know that gamma - correction has been done on the sample values in the file, and we - could call them "gamma corrected" samples. However, since there - can be so many different values of gamma in the image display - chain, and some of them are not known at the time the image is - written, the samples are not really being "corrected" for a - specific display condition. We are really using a power function - in the process of encoding an intensity range into a small integer - field, and so it is more correct to say "gamma encoded" samples - instead of "gamma corrected" samples. - When displaying an image file, the image decoding program is - responsible for making the overall gamma of the system equal to - the desired viewing_gamma, by selecting the decoding_gamma - appropriately. When displaying a PNG file, the gAMA chunk - provides the file_gamma value. The display_gamma may be known for - this machine, or it might be obtained from the system software, or - the user might have to be asked what it is. The correct - viewing_gamma depends on lighting conditions, and that will - generally have to come from the user. When displaying an image file, the image decoding program is responsible for making gamma equal to the value specified in the gAMA chunk, by selecting the decoding_exponent appropriately: decoding_exponent = 1.0 / (gamma * display_exponent) The display_exponent might be known for this machine, or it might be obtained from the system software, or the user might have to be asked what it is. - Ultimately, you should have - - file_gamma * decoding_gamma * display_gamma = viewing_gamma > Some specific examples - In digital video systems, camera_gamma is about 0.5 by declaration - of the various video standards documents. CRT_gamma is 2.5 as - usual, while encoding_gamma, decoding_gamma, and LUT_gamma are all - 1.0. As a result, viewing_gamma ends up being about 1.25. In digital video systems, camera_exponent is about 0.52 by declaration of the various video standards documents. CRT_exponent is 2.2 as usual, while encoding_exponent, decoding_exponent, and LUT_exponent are all 1.0. As a result, end_to_end_exponent ends up being about 1.14. - On frame buffers that have hardware gamma correction tables, and - that are calibrated to display linear samples correctly, - display_gamma is 1.0. On frame buffers that have hardware gamma correction tables, and that are calibrated to display samples that are proportional to display output intensity, display_exponent is 1.0. - Many workstations and X terminals and PC displays lack gamma - correction lookup tables. Here, LUT_gamma is always 1.0, so - display_gamma is 2.5. Many workstations and X terminals and PC clones lack gamma correction lookup tables. Here, LUT_exponent is always 1.0, so display_exponent is 2.2. - On the Macintosh, there is a LUT. By default, it is loaded with a - table whose gamma is about 0.72, giving a display_gamma (LUT and - CRT combined) of about 1.8. Some Macs have a "Gamma" control - panel that allows gamma to be changed to 1.0, 1.2, 1.4, 1.8, or - 2.2. These settings load alternate LUTs that are designed to give - a display_gamma that is equal to the label on the selected button. - Thus, the "Gamma" control panel setting can be used directly as - display_gamma in decoder calculations. On the Macintosh, there is a LUT. By default, it is loaded with a table whose exponent is 1/1.45, giving a display_exponent (LUT and CRT combined) of about 1.52. Some Macs have a "Gamma" control panel with selections labeled 1.0, 1.2, 1.4, 1.8, or 2.2. These settings load alternate LUTs, but beware: the selection labeled with the value g loads a LUT with exponent g/2.61, yielding display_exponent = (g/2.61) * 2.2 - On recent SGI systems, there is a hardware gamma-correction table - whose contents are controlled by the (privileged) "gamma" program. - The gamma of the table is actually the reciprocal of the number - that "gamma" prints, and it does not include the CRT gamma. To - obtain the display_gamma, you need to find the SGI system gamma - (either by looking in a file, or asking the user) and then - calculating On recent SGI systems, there is a hardware gamma-correction table whose contents are controlled by the (privileged) "gamma" program. The exponent of the table is actually the reciprocal of the number g that "gamma" prints. You can obtain g from the file /etc/config/system.glGammaVal and calculate display_exponent = 2.2 / g - You will find SGI systems with the system gamma set to 1.0 and 2.2 You will find SGI systems with g set to 1.0 and 2.2 > (or higher), but the default when machines are shipped is 1.7. On NeXT systems the LUT has exponent 1/2.2 by default. In summary, for images designed to need no correction on these platforms: platform LUT_exponent default LUT_exponent default gAMA PC clone 1.0 1.0 45455 Macintosh g/2.61 1.8/2.61 = 1/1.45 65909 SGI 1/g 1/1.7 77273 NeXT 1/g 1/2.2 100000 The default gAMA values assume a CRT display. - A note about video gamma A note about video camera transfer functions > The original NTSC video standards specified a simple power-law - camera transfer function with a gamma of 1/2.2 or 0.45. camera transfer function with an exponent of 1/2.2 (about 0.45). > This is > not possible to implement exactly in analog hardware because the > function has infinite slope at x=0, so all cameras deviated to > some degree from this ideal. More recently, a new camera transfer > function that is physically realizable has been accepted as a > standard [SMPTE-170M]. It is > > Vout = 4.5 * Vin if Vin < 0.018 > Vout = 1.099 * (Vin^0.45) - 0.099 if Vin >= 0.018 > > where Vin and Vout are measured on a scale of 0 to 1. Although > the exponent remains 0.45, the multiplication and subtraction > change the shape of the transfer function, so it is no longer a > pure power function. It can be well approximated, however, by a power function with exponent 0.52. - If you want to perform extremely precise - calculations on video signals, you should use the expression above - (or its inverse, as required). - However, PNG does not provide a way to specify that an image uses - this exact transfer function; the gAMA chunk always assumes a pure - power-law function. If we plot the two-part transfer function - above along with the family of pure power functions, we find that - a power function with a gamma of about 0.5 to 0.52 (not 0.45) most - closely approximates the transfer function. Thus, when writing a - PNG file with data obtained from digitizing the output of a modern - video camera, the gAMA chunk should contain 0.5 or 0.52, not 0.45. - The remaining difference between the true transfer function and - the power function is insignificant for almost all purposes. (In - fact, the alignment errors in most cameras are likely to be larger - than the difference between these functions.) The designers of - PNG deemed the simplicity and flexibility of a power-law - definition of gAMA to be more important than being able to - describe the SMPTE-170M transfer curve exactly. - The PAL and SECAM video standards specify a power-law camera - transfer function with a gamma of 1/2.8 or 0.36 --- not the 1/2.2 - of NTSC. However, this is too low in practice, so real cameras - are likely to have their gamma set close to NTSC practice. Just - guessing 0.45 or 0.5 is likely to give you viewable results, but - if you want precise values you'll probably have to measure the - particular camera. The PAL and SECAM video standards specify a power-law camera transfer function with an exponent of 1/2.8 (about 0.36). However, this is too low in practice, so real cameras are likely to have exponents close to NTSC practice. > Further reading - If you have access to the World Wide Web, read Charles Poynton's - excellent "Gamma FAQ" [GAMMA-FAQ] for more information about - gamma. Charles Poynton's "Gamma FAQ" [GAMMA-FAQ] is a excellent source of information about gamma, although it claims that CRTs have an exponent of 2.5. See also his book [DIGITAL-VIDEO]. > 14. Appendix: Color Tutorial ... > Calibrated, device-dependent color > Traditionally, image file formats have used uncalibrated, device- > dependent color. If the precise details of the original display > device are known, it becomes possible to convert the device- > dependent colors of a particular image to device-independent ones. > Making simplifying assumptions, such as working with CRTs (which > are much easier than printers), all we need to know are the XYZ values of each primary color and the CRT_exponent. - values of each primary color and the CRT_gamma. ... > What are chromaticity and luminance? ... > The Y value of an XYZ color is directly proportional to its > absolute brightness and is called the luminance of the color. We > can describe a color either by XYZ coordinates or by chromaticity > x,y plus luminance Y. The XYZ form has the advantage that it is linearly related to RGB intensities. - linearly related to (linear, gamma=1.0) RGB color spaces. ... - Here we assume we are working with linear RGB floating point data - in the range 0..1. If the gamma is not 1.0, make it so on the - floating point data. Then convert source_RGB to XYZ by matrix - multiplication: RGB intensity samples normalized to the range 0..1 can be converted to XYZ by matrix multiplication. (If you have gamma-encoded RGB samples, first undo the gamma encoding.) ... > 16. Appendix: Online Resources - PNG home page PNG web site - There is a World Wide Web home page for PNG at - http://quest.jpl.nasa.gov/PNG/. This page is a central location - for current information about PNG and PNG-related tools. There is a World Wide Web site for PNG at http://www.cdrom.com/pub/png/. This page is a central location for current information about PNG and PNG-related tools. > 17. Appendix: Revision History ... Changes since version 1.0 (W3C Recommendation 01-October-1996, RFC 2083 January 1997) * Redefined gAMA to be in terms of the desired display output rather than the original scene, and revised all discussions of gamma and references to gamma accordingly * Added the sRGB and iCCP chunks * Updated the PNG web site URL and authors' email addresses > 18. References ... [DIGITAL-VIDEO] Poynton, Charles, A Technical Introduction to Digital Video, John Wiley & Sons, 1996. ISBN 0-471-12253-X. ... [ICC] The International Color Consortium ... [ISO-3664] International Organization for Standardization, "Photography --- Illumination Conditions for Viewing Colour Transparencies and their Representation", IS 3664, 1975. - [ISO-8859] - International Organization for Standardization, "Information - Processing --- 8-bit Single-Byte Coded Graphic Character Sets --- - Part 1: Latin Alphabet No. 1", IS 8859-1, 1987. [ISO/IEC-8859-1] International Organization for Standardization and International Electrotechnical Commission, "Information Technology --- 8-bit Single-Byte Coded Graphic Character Sets --- Part 1: Latin Alphabet No. 1", IS 8859-1, 1998. > Also see sample files at > ftp://ftp.uu.net/graphics/png/documents/iso_8859-1.* ... [RFC-2119] Bradner, Scott, "Key words for use in RFCs to Indicate Requirement Levels", RFC 2119, Harvard University, March 1997. ... [sRGB] Stokes, Michael, Matthew Anderson, Srinivasan Chandrasekar, and Ricardo Motta, A Standard Default Color Space for the Internet - sRGB. The key portions of this document are being adopted with revisions into: International Electrotechnical Commission, "Colour Measurement and Management in Multimedia Systems and Equipment - Part 2-1: Default RGB Colour Space - sRGB", IEC 61966-2-1. > 19. Credits ... > * Mark Adler, madler@alumni.caltech.edu > * Thomas Boutell, boutell@boutell.com * John Bowler, jbowler@acm.org > * Christian Brunschen, cb@df.lth.se > * Adam M. Costello, amc@cs.berkeley.edu > * Lee Daniel Crocker, lee@piclab.com > * Andreas Dilger, adilger@enel.ucalgary.ca > * Oliver Fromme, fromme@rz.tu-clausthal.de - * Jean-loup Gailly, gzip@prep.ai.mit.edu * Jean-loup Gailly, jloup@gzip.org > * Chris Herborth, chrish@qnx.com > * Alex Jakulin, Aleks.Jakulin@snet.fri.uni-lj.si > * Neal Kettler, kettler@cs.colostate.edu > * Tom Lane, tgl@sss.pgh.pa.us > * Alexander Lehmann, alex@hal.rhein-main.de > * Chris Lilley, chris@w3.org > * Dave Martindale, davem@cs.ubc.ca - * Owen Mortensen, 104707.650@compuserve.com * Owen Mortensen, ojm@acm.org > * Keith S. Pickens, ksp@swri.edu > * Robert P. Poole, lionboy@primenet.com > * Glenn Randers-Pehrson, glennrp@arl.mil or > randeg@alumni.rpi.edu > * Greg Roelofs, newt@pobox.com - * Willem van Schaik, willem@gintic.gov.sg * Willem van Schaik, willem@schaik.com > * Guy Schalnat > * Paul Schmidt, pschmidt@photodex.com > * Tim Wegner, twegner@phoenix.net > * Jeremy Wohl, jeremyw@anders.com ... > COPYRIGHT NOTICE - Copyright (c) 1996 by: Massachusetts Institute of Technology (MIT) Copyright (c) 1996, 1998 by: Massachusetts Institute of Technology (MIT) ...