1. Introduction
This document, together with the PNG specification [PNG], contains the entire list of registered "public" PNG chunks. The additional registered chunks appearing in this document are the oFFs, pCAL, sCAL, gIFg, gIFx, sTER, and fRAc chunks, plus the deprecated gIFt chunk.
Additional chunk types may be proposed for inclusion in this list by contacting the PNG specification maintainers at publicpng@w3.org or by raising an issue on their GitHub repository (preferred). Attention is drawn to the Guidelines for new chunk types.
Chunks described here are expected to be less widely supported than those defined in the basic specification. However, application authors are encouraged to use these chunk types whenever appropriate for their applications.
This document also describes data representations that do not occur in the core PNG format, but are used in one or more specialpurpose chunks. New chunks should use these representations whenever applicable, in order to maximize portability and simplify decoders.
2. Data Representation
2.1. Integer values
Refer to Section 7.1 of the PNG specification [PNG] for the format and range of integer values
2.2. Floatingpoint values
The core of PNG does not use floatingpoint numbers anywhere; it uses integers or, where applicable, fixedpoint fractional values. However, specialpurpose chunks may need to represent values that do not fit comfortably in fixedpoint notation. The textual floatingpoint notation defined here is recommended for use in all such cases. This representation is simple, has no a priori limits on range or precision, and is portable across all machines.
A floatingpoint value in this notation is represented by an ASCII text string in a standardized decimal floatingpoint format. The string is variablelength and must be terminated by a null (zero) character unless it is the last item in its chunk. The string consists of an optional sign ("+" or ""), an integer part, a fraction part beginning with a decimal point ("."), and an exponent part beginning with an "E" or "e" and optional sign. The integer, fraction, and exponent parts each contain one or more digits (ASCII "0" to "9"). Either the integer part or the fraction part, but not both, may be omitted. A decimal point is allowed, but not required, if there is no fraction part. The exponent part may be omitted. No spaces or any other character besides those specified may appear.
Note: in particular, Clanguage "F" and "L" suffixes are not allowed, the string "." is not allowed as a shorthand for 0 as in some other programming languages, and no commas or underscores are allowed. This format ought to be easily readable in all programming environments.
3. Summary of SpecialPurpose Chunks
This table summarizes some properties of the chunks described in this document. For standard chunks, see the PNG specification [PNG].
Name  Multiple OK?  Ordering constraints 

oFFs  No  Before IDAT 
pCAL  No  Before IDAT 
sCAL  No  Before IDAT 
gIFg  Yes  None 
gIFt  Yes  None (this chunk is deprecated) 
gIFx  Yes  None 
sTER  No  Before IDAT 
dSIG  Yes  In pairs, immediately after IHDR and before IEND 
fRAc  Yes  None 
4. Chunk Descriptions
4.1. oFFs Image offset
The oFFs chunk gives the position on a printed page at which the image should be output when printed alone. It can also be used to define the image’s location with respect to a larger screen or other applicationspecific coordinate system.
The oFFs chunk contains:
X position:  4 bytes (signed integer) 

Y position:  4 bytes (signed integer) 
Unit specifier:  1 byte 
Both position values are signed. The following values are legal for the unit specifier:
0:  unit is the pixel (true dimensions unspecified) 

1:  unit is the micrometer 
Note: for conversions, one inch is equal to exactly 25400 micrometers. A micrometer (also called a micron) is 10^{6} meter.
The X position is measured rightwards from the left edge of the page to the left edge of the image; the Y position is measured downwards from the top edge of the page to the top edge of the image. Note that negative values are permitted, and denote displacement in the opposite directions. Although oFFs can specify an image placement that is partially or wholly outside the page boundaries, the result of such placement is applicationdependent.
If present, this chunk must precede the first IDAT chunk.
4.2. pCAL Calibration of pixel values
When a PNG file is being used to store physical data other than color values, such as a twodimensional temperature field, the pCAL chunk can be used to record the relationship (mapping) between stored pixel samples, original samples, and actual physical values. The pCAL data might be used to construct a reference color bar beside the image, or to extract the original physical data values from the file. It is not expected to affect the way the pixels are displayed. Another method should be used if the encoder wants the decoder to modify the sample values for display purposes.
The pCAL chunk contains:
Calibration name:  179 bytes (character string) 

Null separator:  1 byte 
Original zero (x0):  4 bytes (signed integer) 
Original max (x1):  4 bytes (signed integer) 
Equation type:  1 byte 
Number of parameters:  1 byte 
Unit name:  0 or more bytes (character string) 
Null separator:  1 byte 
Parameter 0 (p0):  1 or more bytes (ASCII floatingpoint) 
Null separator:  1 byte 
Parameter 1 (p1):  1 or more bytes (ASCII floatingpoint) 
...etc... 
There is no null separator after the final parameter (or after the unit name, if there are zero parameters). The number of parameters field must agree with the actual number of parameters present in the chunk, and must be correct for the specified equation type (see below).
The calibration name can be any convenient name for referring to the mapping, and is subject to the same restrictions as the keyword in a PNG text chunk: it must contain only printable Latin1 [ISO/IEC88591] characters (decimal codes 33126 and 161255) and spaces (decimal code 32), but no leading, trailing, or consecutive spaces.
The calibration name can permit applications or people to choose the appropriate pCAL chunk when more than one is present (this could occur in a multiimage PNG file, but not in a static PNG file). For example, a calibration name of "SI" or "English" could be used to identify the system of units in the pCAL chunk as well as in other chunk types, to permit a decoder to select an appropriate set of chunks based on their names.
The pCAL chunk defines two mappings:

A mapping from the stored samples, which are unsigned integers in the range 0..max, where max=2^{bitdepth}1, to the original samples, which are signed integers. The x0 and x1 fields, together with the bit depth for the image, define this mapping.

A mapping from the original samples to the physical values, which are usually real numbers with units. This mapping is defined by x0, x1, the equation type, parameters, and unit name.
The mapping between the stored samples and the original samples is given by the following equations:
original_sample = ( stored_sample * ( x1  x0 ) + max / 2 ) / max + x0 stored_sample = (( original_sample  x0 ) * max + ( x1  x0 ) / 2 ) / ( x1  x0 ) clipped to the range 0. . max
In these equations,
"/" means integer division that rounds toward negative infinity,
so n/d = integer(floor(real(a)/real(b))))
.
Note that this is the same as
the "/" operator in the C programming language
when n and d are nonnegative,
but not necessarily when n or d is negative.
Notice that x0 and x1 are the original samples that correspond to the stored samples 0 and max, respectively. Encoders will usually set x0=0 and x1=max to indicate that the stored samples are equal to the original samples. Note that x0 is not constrained to be less than x1, and neither is constrained to be positive, but they must be different from each other.
This mapping is lossless and reversible
when abs(x1x0) <= max
and the original sample is in the range x0..x1
.
If abs(x1x0) > max
then there can be no lossless reversible mapping,
but the functions provide the best integer approximations
to floatingpoint affine transformations.
The mapping between the original samples and the physical values is given by one of several equations, depending on the equation type, which may have the following values:
0:  Linear mapping 

1:  Basee exponential mapping 
2:  Arbitrarybase exponential mapping 
3:  Hyperbolic mapping 
For equation type 0:
physical_value = p0 + p1 * original_sample / ( x1  x0 )
For equation type 1:
physical_value = p0 + p1 * exp ( p2 * original_sample / ( x1  x0 ))
For equation type 2:
physical_value = p0 + p1 * pow ( p2 , ( original_sample / ( x1  x0 )))
For equation type 3:
physical_value = p0 + p1 * sinh ( p2 * ( original_sample  p3 ) / ( x1  x0 ))
For these physical value equations, "/" means floatingpoint division.
The function exp(x)
is e
raised to the power of x
,
where e
is the base of the natural logarithms,
approximately 2.71828182846.
The exponential function exp()
is the inverse the natural logarithm function ln()
.
The function pow(x,y)
is x
raised to the power of y
.
physical_value = pow ( x , y ) = exp ( y * ln ( x ))
The function sinh(x)
is
the hyperbolic sine of x
.
physical_value = sinh ( x ) = 0.5 * ( exp ( x )  exp (  x ))
The units for the physical values are given by the unit name, which may contain any number of printable Latin1 characters, with no limitation on the number and position of blanks.
For color types 0 (gray) and 4 (grayalpha), the mappings apply to the gray sample values (but not to the alpha sample). For color types 2 (RGB), 3 (indexed RGB), and 6 (RGBA), the mappings apply independently to each of the red, green, and blue sample values (but not the alpha sample). In the case of color type 3 (indexed RGB), the mapping refers to the RGB samples and not to the index values.
Linear data can be expressed with equation type 0.
Pure logarithmic data can be expressed with either equation type 1 or 2:
Equation type 1  Equation type 2 

x0 = 0  x0 = 0 
x1 = max  x1 = max 
p0 = 0  p0 = 0 
p1 = bottom  p1 = bottom 
p2 = ln(top/bottom)  p2 = top/bottom 
Equation types 1 and 2 are functionally equivalent; both are defined because authors may find one or the other more convenient.
Using equation type 3, floatingpoint data can be reduced (with loss) to a set of integer samples such that the resolution of the stored data is roughly proportional to its magnitude.
Equation type 3 x0 = 0 x1 = 65535 p0 = 0.0 p1 = 1.0e30 p2 = 280.0 p3 = 32767.0
The resolution near zero is about 10^{33}, while the resolution near 10^{31} or 10^{31} is about 10^{28}. Everywhere, the resolution is about 0.4 percent of the magnitude.
p0 = 0 p1 = 1e30 p2 = 280 p3 = 32767
Applications should use double precision arithmetic
(or take other precautions)
while performing the mappings for equation types 1, 2, and 3,
to prevent overflow of intermediate results
when p1
is small
and the exp()
, pow()
, or sinh()
function is large.
If present, the pCAL chunk must appear before the first IDAT chunk. Only one instance of the pCAL chunk is permitted in a PNG datastream.
4.3. sCAL Physical scale of image subject
While the pHYs chunk is used to record the physical size of the image itself as it was scanned or as it should be printed, certain images (such as maps, photomicrographs, astronomical surveys, floor plans, and others) may benefit from knowing the actual physical dimensions of the image’s subject for remote measurement and other purposes. The sCAL chunk serves this need. It contains:
Unit specifier:  1 byte 

Pixel width:  1 or more bytes (ASCII floatingpoint) 
Null separator:  1 byte 
Pixel height:  1 or more bytes (ASCII floatingpoint) 
The following values are legal for the unit specifier:
1:  unit is the meter 

2:  unit is the radian 
Following the unit specifier are two ASCII strings. The first string defines the physical width represented by one image pixel; the second string defines the physical height represented by one pixel. The two strings are separated by a zero byte (null character). As in the text chunks, there is no trailing zero byte for the final string. Each of these strings contains a floatingpoint constant in the format specified above (Floatingpoint values, Section 2.2). Both values are required to be greater than zero.
If present, this chunk must precede the first IDAT chunk.
4.4. gIFg GIF Graphic Control Extension
The gIFg chunk is provided for backward compatibility with the GIF89a Graphic Control Extension [GIF]. It contains:
Disposal Method:  1 byte 

User Input Flag:  1 byte 
Delay Time:  2 bytes (byte order converted from GIF) 
The Disposal Method indicates the way in which the graphic is to be treated after being displayed. The User Input Flag indicates whether user input is required before continuing. The Delay Time specifies the number of hundredths (1/100) of a second to delay before continuing with the processing of the datastream. Note that this field is to be byteorderconverted.
The "Transparent Color Flag" and "Transparent Color Index" fields found in the GIF89a Graphic Control Extension are omitted from gIFg. These fields should be converted using the transparency features of basic PNG.
The GIF specification allows at most one Graphic Control Extension to preceed each graphic rendering block. Because a static PNG file holds only one image, it is expected that gIFg will appear at most once, before IDAT, but there is no strict requirement.
Note: this chunk is provided solely to improve roundtripping when converting from animated GIF to static PNG. It has no effect on rendering of the PNG image. Including this chunk does not make the PNG animated.
4.5. gIFx GIF Application Extension
The gIFx chunk is provided for backward compatibility with the GIF89a Application Extension [GIF]. The Application Extension contains applicationspecific information. This chunk contains:
Application Identifier:  8 bytes 

Authentication Code:  3 bytes 
Application Data:  n bytes 
The Application Identifier is a sequence of eight printable ASCII characters used to identify the application creating the Application Extension. The Authentication Code is three additional bytes that the application may use to further validate the Application Extension. The remainder of the chunk is applicationspecific data whose content is not defined by the GIF specification.
Note that GIFtoPNG converters should not attempt to perform byte reordering on the contents of the Application Extension. The data is simply transcribed without any processing except for deblocking GIF subblocks.
Applications that formerly used GIF Application Extensions may define specialpurpose PNG chunks to replace their application extensions. If a GIFtoPNG converter recognizes the Application Identifier and is aware of a corresponding PNG chunk, it may choose to convert the Application Extension into that PNG chunk type rather than using gIFx.
4.6. sTER Indicator of Stereo Image
When present, the sTER chunk indicates that the datastream contains a stereo pair of subimages within a single PNG image.
The sTER chunk contains:
Mode:  1 byte 

The following values are legal for the mode specifier:
0:  crossfuse layout 

1:  divergingfuse layout 
The sTER chunk
with mode==0
or mode==1
indicates that the datastream contains two subimages,
encoded within a single PNG image.
They are arranged sidebyside,
with one subimage intended for presentation to the right eye
and the other subimage intended for presentation to the left eye.
The left edge of the right subimage must be on a column that is evenly divisible by eight, so that if interlacing is employed the two images will have coordinated interlacing. Padding columns between the two subimages must be introduced by the encoder if necessary. The sTER chunk imposes no requirements on the contents of the padding pixels. For compatibility with software not supporting sTER, it does not exempt the padding pixels from existing requirements; for example, in palette images, the padding pixels must be valid palette indices. The two subimages must have the same dimensions after removal of any padding.
When mode==0
,
the righteye image appears at the left
and the lefteye image appears at the right,
suitable for crosseyed free viewing.
When mode==1
,
the lefteye image appears at the left
and the righteye image appears at the right,
suitable for divergent (walleyed) free viewing.
Decoders that are aware of the sTER chunk may display the two images in any suitable manner, with or without the padding. Decoders that are not aware of the sTER chunk, and those that recognize the chunk but choose not to treat stereo pairs differently from regular PNG images, will naturally display them sidebyside in a manner suitable for free viewing.
If present, the sTER chunk must appear before the first IDAT chunk.
Given two subimages with width subimage_width
,
encoders can calculate the intersubimage padding
and total width W
using the following pseudocode:
padding := 7  (( subimage_width  1 ) mod 8 ) W := 2 * subimage_width + padding
Given an image with width W
,
decoders can calculate the subimage_width
and intersubimage padding
using the following pseudocode:
padding := 15  (( W  1 ) mod 16 ) if ( padding > 7 ) then error subimage_width := ( W  padding ) / 2
Decoders can assume that the samples in the left and right subimages are cosited, such that the subimages and their centers are coincident at the projection plane. Decoders can also assume that the left and right subimages are intended to be presented directly to the right and left eyes of the user/viewer without independent scaling, rotation or displacement. I.e., the subimages will be presented at the same size in the same relative position and orientation to each eye of the viewer.
Encoders should use the pHYs chunk to indicate the pixel’s size ratio when it is not 1:1.
It is recommended that encoders use the crossfusing layout (mode==0), especially when the image centers are separated by more than 65 millimeters when displayed on a typical monitor.
5. Chunks Not Described Here
5.1. dSIG Digital signature
The dSIG chunk provides a digital signature that guarantees that the contents of the portion of the entire datastream enclosed in a pair of such chunks has not changed since the digital signature was added.
This chunk is described in detail in a separate document, [dSIGspec], which is accompanied by an example provided in [dSIGexample].
5.2. fRAc Fractal image parameters
The fRAc chunk was intended to describe the parameters used to generate a fractal image. The specification for the contents of the fRAc chunk was being developed by Tim Wegner, twegner @ phoenix.net.
In the future, chunks will be fully specified before they are registered.
6. Text Chunk Keywords
6.1. Additional Registered Keywords
6.1.1. Collection
Name of a collection to which the image belongs. An image may belong to one or more collections, each named by a separate text chunk.
6.2. Keyword Syntax
All registered textual keywords in text chunks and all other chunk types are limited to the ASCII characters AZ, az, 09, space, and the following 20 symbols:
! " % & ' ( ) * + ,  . / : ; < = > ? _
but not the remaining 12 symbols:
# $ @ [ \ ] ^ ` {  } ~
This restricted set is the ISO646 "invariant" character set [[!ISO 646]]. These characters have the same numeric codes in all ISO character sets, including all national variants of ASCII.
7. Deprecated Chunks
The chunks listed in this section are registered, but deprecated. Encoders are discouraged from using them, and decoders are not encouraged to support them.
7.1. gIFt GIF Plain Text Extension
The gIFt chunk was originally provided for backward compatibility with the GIF89a Plain Text Extension [GIF], but gIFt is now deprecated because it suffers from some fundamental design flaws.

GIF considers a Plain Text Extension to be a Graphic Rendering Block, just like an image, so a GIF datastream containing an image and a Plain Text Extension is really a multiimage datastream with ordering issues (like associating each Graphic Control Extension with the proper Graphic Rendering Block). PNG, being a singleimage format with no provisions for handling these ordering issues, is not equipped to contain both IDAT and gIFt simultaneously. Since IDAT is required, gIFt must be discouraged.

The Text Foreground Color and Text Background Color fields of the Plain Text Extension are converted to RGB, rather than being converted to RGBA or left as palette indexes. Therefore, transparency information can be lost.
The gIFt chunk contains:
Text Grid Left Position:  4 bytes (signed integer, byte order and size converted) 

Text Grid Top Position:  4 bytes (signed integer, byte order and size converted) 
Text Grid Width:  4 bytes (unsigned integer, byte order and size converted) 
Text Grid Height:  4 bytes (unsigned integer, byte order and size converted) 
Character Cell Width:  1 byte 
Character Cell Height:  1 byte 
Text Foreground Color:  3 bytes (R,G,B samples) 
Text Background Color:  3 bytes (R,G,B samples) 
Plain Text Data:  n bytes 
Text Grid Left Position, Top Position, Width, and Height specify the text area position and size in pixels. The converter must reformat these fields from 2byte LSBfirst unsigned integers to 4byte MSBfirst signed or unsigned integers.
Note: GIF defines the position to be relative to the upper left corner of the logical screen. If an oFFs chunk is also present, a decoder should assume that the oFFs chunk defines the offset of the image relative to the GIF logical screen; hence subtracting the oFFs values (converted from micrometers to pixels if necessary) from the Text Grid Left and Top Positions gives the text area position relative to the main PNG image.
Character Cell Width and Height give the dimensions of each character in pixels.
Text Foreground and Background Color give the colors to be used to render text foreground and background.
Note: the GIFtoPNG converter must replace the palette index values found in the GIF Plain Text Extension block with the corresponding palette entry.
The remainder of the chunk is the text to be displayed.
Note: this data is not in GIF subblock format, but is a continuous datastream.
8. Security Considerations
The normal precautions (see the Security considerations section of the PNG specification) should be taken when displaying text contained in the sCAL calibration name, pCAL unit name, or any ASCII floatingpoint fields.
Applications must take care to avoid underflow and overflow of intermediate results when converting data from one form to another according to the pCAL mappings.
9. Appendix: Sample code
This appendix provides some sample code that can be used in encoding and decoding PNG chunks. It does not form a part of the specification. In the event of a discrepancy between the sample code in this appendix and the chunk definition, the chunk definition prevails.
9.1. pCAL Sample code
#if 0 pcal.c 0.2.2 (Sat 19 Dec 1998) Adam M. Costello <amc @ cs.berkeley.edu> This is public domain example code for computing the mappings defined for the PNG pCAL chunk. #endif #if __STDC__ != 1 #error This code relies on ANSI C conformance. #endif #include <limits.h>#include <math.h>#include <stdio.h>#include <stdlib.h>/* In this program a type named uintN denotes an unsigned */ /* type that handles at least all values 0 through (2^N)1. */ /* A type named intN denotes a signed type that handles at */ /* least all values 12^(N1) through 2^(N1)1. It is not */ /* necessarily the smallest such type; we are more concerned */ /* with speed. */ typedef unsigned int uint16 ; #if UINT_MAX >= 0xffffffff typedef unsigned int uint32 ; #else typedef unsigned long uint32 ; #endif #if INT_MAX >= 0x7fffffff && INT_MIN + 0x7fffffff <= 0 typedef int int32 ; #else typedef long int32 ; #endif /* Testing for 48bit integers is tricky because we cannot */ /* safely use constants greater than 0xffffffff. Also, */ /* shifting by the entire width of a type is undefined, so */ /* for unsigned int, which might be only 16 bits wide, we */ /* must shift in two steps. */ #if (UINT_MAX  0xffff) >> 8 >> 8 >= 0xffffffff typedef unsigned int uint48 ; #define HAVE_UINT48 1 #elif (ULONG_MAX  0xffff) >> 16 >= 0xffffffff typedef unsigned long uint48 ; #define HAVE_UINT48 1 #elif defined(ULLONG_MAX) #if (ULLONG_MAX  0xffff) >> 16 >= 0xffffffff typedef unsigned long long uint48 ; #define HAVE_UINT48 1 #endif #else #define HAVE_UINT48 0 #endif /*******************/ /* Program failure */ void fail ( const char * msg ) { fputs ( msg , stderr ); fputc ( '\n' , stderr ); exit ( EXIT_FAILURE ); } /*************************/ /* Check max, x0, and x1 */ int samp_params_ok ( uint16 max , int32 x0 , int32 x1 ) /* Returns 1 if max, x0, and x1 have */ /* allowed values, 0 otherwise. */ { const int32 xlimit = 0x7fffffff ; return max > 0 && max <= 0xffff && x0 <= xlimit && x0 >=  xlimit && x1 <= xlimit && x1 >=  xlimit && x0 != x1 ; } /***********************************************/ /* Map from stored samples to original samples */ int32 stored_to_orig ( uint16 stored , uint16 max , int32 x0 , int32 x1 ) #if 0 Returns the original sample corresponding to the given stored sample, which must be <= max. The parameters max, x0, and x1 must have been approved by samp_params_ok(). The pCAL spec says: orig = (stored * (x1x0) + max/2) / max + x0 [1] Equivalently: orig = (stored * (x1x0) + max/2) / max + (x0x1)  (x0x1) + x0 orig = (stored * (x1x0) + max * (x0x1) + max/2) / max  (x0x1) + x0 orig = ((max  stored) * (x0x1) + max/2) / max + x1 So we can check whether x0 < x1 and coerce the formula so that the numerators and denominators are always nonnegative: orig = (offset * xspan + max/2) / max + xbottom [2] This will come in handy later. But the multiplication and the subtraction can overflow, so we have to be trickier. For the subtraction, we can convert to unsigned integers. For the multiplication, we can use 48bit integers if we have them, otherwise observe that: b = (b/c)*c + b%c a*b = a*(b/c)*c + a*(b%c) ; let d = a*(b%c) (a*b)/c = a*(b/c) + d/c remainder d%c [3] These are true no matter which way the division rounds. If (a*b)/c is inrange, a*(b/c) is guaranteed to be inrange if b/c rounds toward zero. Here is another observation: sum{x_i} / c = sum{x_i / c} + sum{x_i % c} / c [4] This one also avoids overflow if the division rounds toward zero. The pCAL spec requires rounding toward infinity. ANSI C leaves the rounding direction implementationdefined except when both the numerator and denominator are nonnegative, in which case it rounds downward. So if we arrange for all numerators and denominators to be nonnegative, everything works. Starting with equation 2 and applying identity 4, then 3, we obtain the final formula: d = offset * (xspan % max) xoffset = offset * (xspan / max) + d/max + (d%max + max/2) / max orig = xoffset + xbottom #endif { uint16 offset ; uint32 xspan , q , r , d , xoffset ; int32 xbottom ; if ( stored > max ) fail ( "stored_to_orig: stored > max" ); if ( x1 >= x0 ) { xbottom = x0 ; xspan = ( uint32 ) x1  ( uint32 ) x0 ; offset = stored ; } else { xbottom = x1 ; xspan = ( uint32 ) x0  ( uint32 ) x1 ; offset = max  stored ; } /* We knew xspan would fit in a uint32, but we needed to */ /* cast x0 and x1 before subtracting because otherwise the */ /* subtraction could overflow, and ANSI doesn't say what */ /* the result will be in that case. */ /* Let's optimize two common simple cases */ /* before handling the general case: */ if ( xspan == max ) { xoffset = offset ; } else if ( xspan <= 0xffff ) { /* Equation 2 won't overflow and does only one division. */ xoffset = ( offset * xspan + ( max >> 1 )) / max ; } else { #if HAVE_UINT48 /* We can use equation 2 and do one uint48 */ /* division instead of three uint32 divisions. */ xoffset = ( offset * ( uint48 ) xspan + ( max >> 1 )) / max ; #else q = xspan / max ; r = xspan % max ; /* Hopefully those were compiled into one instruction. */ d = offset * r ; xoffset = offset * q + d / max + ( d % max + ( max >> 1 )) / max ; #endif } /* xoffset might not fit in an int32, but we know the sum */ /* xbottom + xoffset will, so we can do the addition on */ /* unsigned integers and then cast. */ return ( int32 )(( uint32 ) xbottom + xoffset ); } /***********************************************/ /* Map from original samples to stored samples */ uint16 orig_to_stored ( int32 orig , uint16 max , int32 x0 , int32 x1 ) #if 0 Returns the stored sample corresponding to the given original sample. The parameters max, x0, and x1 must have been approved by samp_params_ok(). The pCAL spec says: stored = ((orig  x0) * max + (x1x0)/2) / (x1x0) clipped to the range 0..max Notice that all three terms are nonnegative, or else all are nonpositive. Just as in stored_to_orig(), we can avoid overflow and rounding problems by transforming the equation to use unsigned quantities: stored = (xoffset * max + xspan/2) / xspan #endif { uint32 xoffset , xspan ; if ( x0 < x1 ) { if ( orig < x0 ) return 0 ; if ( orig > x1 ) return max ; xspan = ( uint32 ) x1  ( uint32 ) x0 ; xoffset = ( uint32 ) orig  ( uint32 ) x0 ; } else { if ( orig < x1 ) return 0 ; if ( orig > x0 ) return max ; xspan = ( uint32 ) x0  ( uint32 ) x1 ; xoffset = ( uint32 ) x0  ( uint32 ) orig ; } /* For 16bit xspan the calculation is straightforward: */ if ( xspan <= 0xffff ) return ( xoffset * max + ( xspan >> 1 )) / xspan ; /* Otherwise, the numerator is more than 32 bits and the */ /* denominator is more than 16 bits. The tricks we played */ /* in stored_to_orig() depended on the denominator being */ /* 16bit, so they won't help us here. */ #if HAVE_UINT48 return (( uint48 ) xoffset * max + ( xspan >> 1 )) / xspan ; #else /* Doing the exact integer calculation with 32bit */ /* arithmetic would be very difficult. But xspan > 0xffff */ /* implies xspan > max, in which case the pCAL spec says */ /* "there can be no lossless reversible mapping, but the */ /* functions provide the best integer approximations to */ /* floatingpoint affine transformations." So why insist */ /* on using the integer calculation? Let's just use */ /* floatingpoint. */ return (( double ) xoffset * max + ( xspan >> 1 )) / xspan ; #endif } /*********************************************/ /* Check x0, x1, eqtype, n, and p[0]..p[n1] */ int phys_params_ok ( int32 x0 , int32 x1 , int eqtype , int n , double * p ) /* Returns 1 if x0, x1, eqtype, n, and p[0]..p[n1] */ /* have allowed values, 0 otherwise. */ { if ( ! samp_params_ok ( 1 , x0 , x1 )) return 0 ; switch ( eqtype ) { case 0 : return n == 2 ; case 1 : return n == 3 ; case 2 : break ; case 3 : return n == 4 ; } /* eqtype is 2, check for pow() domain error: */ if ( p [ 2 ] > 0 ) return 1 ; if ( p [ 2 ] < 0 ) return 0 ; return ( x0 <= x1 ) ? ( x0 > 0 && x1 > 0 ) : ( x0 < 0 && x1 < 0 ); } /************************************************/ /* Map from original samples to physical values */ double orig_to_phys ( int32 orig , int32 x0 , int32 x1 , int eqtype , double * p ) /* Returns the physical value corresponding to the given */ /* original sample. The parameters x0, x1, eqtype, and p[] */ /* must have been approved by phys_params_ok(). The array */ /* p[] must hold enough parameters for the equation type. */ { double xdiff , f ; xdiff = ( double ) x1  x0 ; switch ( eqtype ) { case 0 : f = orig / xdiff ; break ; case 1 : f = exp ( p [ 2 ] * orig / xdiff ); break ; case 2 : f = pow ( p [ 2 ], orig / xdiff ); break ; case 3 : f = sinh ( p [ 2 ] * ( orig  p [ 3 ]) / xdiff ); break ; default : fail ( "orig_to_phys: unknown equation type" ); } return p [ 0 ] + p [ 1 ] * f ; }
9.2. Fixedpoint gamma correction
#if 0 pcal.c 0.2.2 (Sat 19 Dec 1998) Adam M. Costello <amc @ cs.berkeley.edu> This is public domain example code for computing the mappings defined for the PNG pCAL chunk. #endif #if __STDC__ != 1 #error This code relies on ANSI C conformance. #endif #include <limits.h>#include <math.h>#include <stdio.h>#include <stdlib.h>/* In this program a type named uintN denotes an unsigned */ /* type that handles at least all values 0 through (2^N)1. */ /* A type named intN denotes a signed type that handles at */ /* least all values 12^(N1) through 2^(N1)1. It is not */ /* necessarily the smallest such type; we are more concerned */ /* with speed. */ typedef unsigned int uint16 ; #if UINT_MAX >= 0xffffffff typedef unsigned int uint32 ; #else typedef unsigned long uint32 ; #endif #if INT_MAX >= 0x7fffffff && INT_MIN + 0x7fffffff <= 0 typedef int int32 ; #else typedef long int32 ; #endif /* Testing for 48bit integers is tricky because we cannot */ /* safely use constants greater than 0xffffffff. Also, */ /* shifting by the entire width of a type is undefined, so */ /* for unsigned int, which might be only 16 bits wide, we */ /* must shift in two steps. */ #if (UINT_MAX  0xffff) >> 8 >> 8 >= 0xffffffff typedef unsigned int uint48 ; #define HAVE_UINT48 1 #elif (ULONG_MAX  0xffff) >> 16 >= 0xffffffff typedef unsigned long uint48 ; #define HAVE_UINT48 1 #elif defined(ULLONG_MAX) #if (ULLONG_MAX  0xffff) >> 16 >= 0xffffffff typedef unsigned long long uint48 ; #define HAVE_UINT48 1 #endif #else #define HAVE_UINT48 0 #endif /*******************/ /* Program failure */ void fail ( const char * msg ) { fputs ( msg , stderr ); fputc ( '\n' , stderr ); exit ( EXIT_FAILURE ); } /*************************/ /* Check max, x0, and x1 */ int samp_params_ok ( uint16 max , int32 x0 , int32 x1 ) /* Returns 1 if max, x0, and x1 have */ /* allowed values, 0 otherwise. */ { const int32 xlimit = 0x7fffffff ; return max > 0 && max <= 0xffff && x0 <= xlimit && x0 >=  xlimit && x1 <= xlimit && x1 >=  xlimit && x0 != x1 ; } /***********************************************/ /* Map from stored samples to original samples */ int32 stored_to_orig ( uint16 stored , uint16 max , int32 x0 , int32 x1 ) #if 0 Returns the original sample corresponding to the given stored sample, which must be <= max. The parameters max, x0, and x1 must have been approved by samp_params_ok(). The pCAL spec says: orig = (stored * (x1x0) + max/2) / max + x0 [1] Equivalently: orig = (stored * (x1x0) + max/2) / max + (x0x1)  (x0x1) + x0 orig = (stored * (x1x0) + max * (x0x1) + max/2) / max  (x0x1) + x0 orig = ((max  stored) * (x0x1) + max/2) / max + x1 So we can check whether x0 < x1 and coerce the formula so that the numerators and denominators are always nonnegative: orig = (offset * xspan + max/2) / max + xbottom [2] This will come in handy later. But the multiplication and the subtraction can overflow, so we have to be trickier. For the subtraction, we can convert to unsigned integers. For the multiplication, we can use 48bit integers if we have them, otherwise observe that: b = (b/c)*c + b%c a*b = a*(b/c)*c + a*(b%c) ; let d = a*(b%c) (a*b)/c = a*(b/c) + d/c remainder d%c [3] These are true no matter which way the division rounds. If (a*b)/c is inrange, a*(b/c) is guaranteed to be inrange if b/c rounds toward zero. Here is another observation: sum{x_i} / c = sum{x_i / c} + sum{x_i % c} / c [4] This one also avoids overflow if the division rounds toward zero. The pCAL spec requires rounding toward infinity. ANSI C leaves the rounding direction implementationdefined except when both the numerator and denominator are nonnegative, in which case it rounds downward. So if we arrange for all numerators and denominators to be nonnegative, everything works. Starting with equation 2 and applying identity 4, then 3, we obtain the final formula: d = offset * (xspan % max) xoffset = offset * (xspan / max) + d/max + (d%max + max/2) / max orig = xoffset + xbottom #endif { uint16 offset ; uint32 xspan , q , r , d , xoffset ; int32 xbottom ; if ( stored > max ) fail ( "stored_to_orig: stored > max" ); if ( x1 >= x0 ) { xbottom = x0 ; xspan = ( uint32 ) x1  ( uint32 ) x0 ; offset = stored ; } else { xbottom = x1 ; xspan = ( uint32 ) x0  ( uint32 ) x1 ; offset = max  stored ; } /* We knew xspan would fit in a uint32, but we needed to */ /* cast x0 and x1 before subtracting because otherwise the */ /* subtraction could overflow, and ANSI doesn't say what */ /* the result will be in that case. */ /* Let's optimize two common simple cases */ /* before handling the general case: */ if ( xspan == max ) { xoffset = offset ; } else if ( xspan <= 0xffff ) { /* Equation 2 won't overflow and does only one division. */ xoffset = ( offset * xspan + ( max >> 1 )) / max ; } else { #if HAVE_UINT48 /* We can use equation 2 and do one uint48 */ /* division instead of three uint32 divisions. */ xoffset = ( offset * ( uint48 ) xspan + ( max >> 1 )) / max ; #else q = xspan / max ; r = xspan % max ; /* Hopefully those were compiled into one instruction. */ d = offset * r ; xoffset = offset * q + d / max + ( d % max + ( max >> 1 )) / max ; #endif } /* xoffset might not fit in an int32, but we know the sum */ /* xbottom + xoffset will, so we can do the addition on */ /* unsigned integers and then cast. */ return ( int32 )(( uint32 ) xbottom + xoffset ); } /***********************************************/ /* Map from original samples to stored samples */ uint16 orig_to_stored ( int32 orig , uint16 max , int32 x0 , int32 x1 ) #if 0 Returns the stored sample corresponding to the given original sample. The parameters max, x0, and x1 must have been approved by samp_params_ok(). The pCAL spec says: stored = ((orig  x0) * max + (x1x0)/2) / (x1x0) clipped to the range 0..max Notice that all three terms are nonnegative, or else all are nonpositive. Just as in stored_to_orig(), we can avoid overflow and rounding problems by transforming the equation to use unsigned quantities: stored = (xoffset * max + xspan/2) / xspan #endif { uint32 xoffset , xspan ; if ( x0 < x1 ) { if ( orig < x0 ) return 0 ; if ( orig > x1 ) return max ; xspan = ( uint32 ) x1  ( uint32 ) x0 ; xoffset = ( uint32 ) orig  ( uint32 ) x0 ; } else { if ( orig < x1 ) return 0 ; if ( orig > x0 ) return max ; xspan = ( uint32 ) x0  ( uint32 ) x1 ; xoffset = ( uint32 ) x0  ( uint32 ) orig ; } /* For 16bit xspan the calculation is straightforward: */ if ( xspan <= 0xffff ) return ( xoffset * max + ( xspan >> 1 )) / xspan ; /* Otherwise, the numerator is more than 32 bits and the */ /* denominator is more than 16 bits. The tricks we played */ /* in stored_to_orig() depended on the denominator being */ /* 16bit, so they won't help us here. */ #if HAVE_UINT48 return (( uint48 ) xoffset * max + ( xspan >> 1 )) / xspan ; #else /* Doing the exact integer calculation with 32bit */ /* arithmetic would be very difficult. But xspan > 0xffff */ /* implies xspan > max, in which case the pCAL spec says */ /* "there can be no lossless reversible mapping, but the */ /* functions provide the best integer approximations to */ /* floatingpoint affine transformations." So why insist */ /* on using the integer calculation? Let's just use */ /* floatingpoint. */ return (( double ) xoffset * max + ( xspan >> 1 )) / xspan ; #endif } /*********************************************/ /* Check x0, x1, eqtype, n, and p[0]..p[n1] */ int phys_params_ok ( int32 x0 , int32 x1 , int eqtype , int n , double * p ) /* Returns 1 if x0, x1, eqtype, n, and p[0]..p[n1] */ /* have allowed values, 0 otherwise. */ { if ( ! samp_params_ok ( 1 , x0 , x1 )) return 0 ; switch ( eqtype ) { case 0 : return n == 2 ; case 1 : return n == 3 ; case 2 : break ; case 3 : return n == 4 ; } /* eqtype is 2, check for pow() domain error: */ if ( p [ 2 ] > 0 ) return 1 ; if ( p [ 2 ] < 0 ) return 0 ; return ( x0 <= x1 ) ? ( x0 > 0 && x1 > 0 ) : ( x0 < 0 && x1 < 0 ); } /************************************************/ /* Map from original samples to physical values */ double orig_to_phys ( int32 orig , int32 x0 , int32 x1 , int eqtype , double * p ) /* Returns the physical value corresponding to the given */ /* original sample. The parameters x0, x1, eqtype, and p[] */ /* must have been approved by phys_params_ok(). The array */ /* p[] must hold enough parameters for the equation type. */ { double xdiff , f ; xdiff = ( double ) x1  x0 ; switch ( eqtype ) { case 0 : f = orig / xdiff ; break ; case 1 : f = exp ( p [ 2 ] * orig / xdiff ); break ; case 2 : f = pow ( p [ 2 ], orig / xdiff ); break ; case 3 : f = sinh ( p [ 2 ] * ( orig  p [ 3 ]) / xdiff ); break ; default : fail ( "orig_to_phys: unknown equation type" ); } return p [ 0 ] + p [ 1 ] * f ; }
10. Rationale
10.1. pCAL Rationale
This section gives the reasoning behind some of the design decisions in the pCAL chunk. It does not form a part of the specification.
10.1.1. Redundant equation types
Equation types 1 and 2 seem to be equivalent. Why have both?
We don’t want to force people
to do the exponentiation using ln()
and exp()
, since pow()
may provide better accuracy
in some floatingpoint math libraries.
We also don’t want to force people
using base10 logs
to store a sufficiently accurate value
of ln(10)
in the pCAL chunk.
When the base is e
,
we don’t want to force people
to encode a sufficiently accurate value
of e
in the pCAL chunk,
or to use pow()
when exp()
is sufficient.
10.1.2. What are x0
and x1
for?
First, x0
and x1
provide a way
to recover the original data,
losslessly,
when the original range is not a power of two.
Sometimes the digitized values
do not have a range that fills the full depth of a PNG.
x0=0
and x1=800
we can recover the original samples,
and we indicate the precision of the data. Even if the original data had a range identical to a valid PNG image sample, like 0 (black) to 65535 (white), one might want to create a derived image by stretching the contrast in a limited intensity range containing the important details.
x0=46000
and x1.4.200
,
we can recover the original data samples
that fell between 46000 and 47000. 10.1.3. Integer division
Why define integer divison to round toward negative infinity? This is different from many C implementations and from all Fortran implementations, which round toward zero.
We cannot leave the choice unspecified.
If we were to specify rounding toward zero,
we’d have to account for a discontinuity
at zero.
A division by positive d
would map the 2d1
values from (d1)
through d1
to zero,
but would map only d
values
to any other value;
for example, 3d
through 4d1
would be mapped to 3.
Achieving lossless mappings
in spite of this anomaly
would be difficult.
11. Appendix: Revision History
 24 Jan Dec 2022 (version 1.6.0)
 Moved eXIF to main PNG document
 Converted source document to Bikeshed

15 July 2017 (version 1.5.0)
 Added the
eXIf
chunk  Replaced ftp://www.simplesystems.org/pub/png/documents/ URL with http://libpng.download/documents/
 Added the

12 June 2017 (version 1.4.1):
 Changed "name=" markup to "id=" in order to pass w3c validation
 Removed incorrect nroffstyle page numbers from Table of Contents
 Added internal links in the Table of Contents
 Added reference to RFC2119 for interpretation of "should", etc.
 Removed trailing blanks
 Added "Collection" keyword which was approved in 2004.
 Added Cosmin Truta (who suggested the Collection keyword) to Credits

1 May 2008 (version 1.4.0):
 Added the
dSIG
chunk.
 Added the

31 August 2006 (version 1.3.0):
 Added the
sTER
chunk.
 Added the

14 July 1999 (version 1.2.0):
 Deleted the
iTXt
chunk, which has been moved to the core spec.
 Deleted the

9 February 1999 (version 1.1.1):
 Added the
iTXt
chunk  Limited the character set for future registered keywords
 Added the

30 December 1998 (version 1.1.0):
 Added
pCAL
chunk and related sample code  Deprecated the
gIFT
chunk  Added sample gammacorrection code that uses integer arithmetic
 Added
 11 March 1996 (version 0.96): First public release
12. Credits
12.1. Editors

Chris Lilley, chris @ w3.org

Glenn RandersPehrson, glennrp @ users.sourceforge.net (versions 1.1 to 1.5)

Tom Lane, tgl @ sss.pgh.pa.us (edited the first release of this document)
12.2. Contributors
Names of contributors not already listed in the PNG specification are presented in alphabetical order:
 Adeluc, www.adeluc.com, png @ adeluc.com
 Brendan Bolles
 Todd French,
tfrench @ sandia.gov
 Phil Harvey
 Nancy M. RandersPehrson
 Alaric B. Snell,
alaric @ alaricsnell.com
 Michael Stokes
 Jason Summers
 Cosmin Truta,
cosmin @ cs.toronto.edu
 Pavel Zlatovratskii
12.3. Trademarks
GIF is a service mark of CompuServe Incorporated. PostScript is a trademark of Adobe Systems.