ftp://ftp.uu.net/graphics/png/
.
The maintainers of the PNG specification can be contacted by e-mail at
png-info@uunet.uu.net
.
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. Additional chunk types may be proposed for
inclusion in this list by contacting the PNG specification maintainers at
png-info@uunet.uu.net
.
This document also describes data representations that do not occur in the core PNG format, but are used in one or more special-purpose chunks. New chunks should use these representations whenever applicable, in order to maximize portability and simplify decoders.
A floating-point value in this notation is represented by an ASCII text string in a standardized decimal floating-point format. The string is variable-length 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 that C-language "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.
Name Multiple Ordering constraints OK? oFFs No Before IDAT pCAL No Before IDAT sCAL No Before IDAT sPLT Yes Before IDAT gIFg Yes None gIFt Yes None gIFx Yes None fRAc Yes None
The chunk's contents are:
Image_position, X axis: 4 bytes (signed integer) Image_position, Y axis: 4 bytes (signed integer) Unit_specifier: 1 byteBoth 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 micrometerConversion note: one inch is equal to exactly 25,400 micrometers. A micrometer (also called a micron) is 1/1,000,000th of a 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 application-dependent.
If present, this chunk must precede the first IDAT chunk.
The pCAL chunk's contents are a text string (Purpose) that names the equation, original sample limits X0 and X1, an Equation_type, a text string (Unit_string), and a set of parameters for the equation:
n bytes: Purpose (Latin-1 text) 1 byte: null separator 4 bytes: X0 (signed integer) Lower limit of original sample range. This original sample value is mapped to the stored sample value 0. 4 bytes: X1 (signed integer) Upper limit of original sample range. This original sample value is mapped to the stored sample value (2^Sample_depth - 1). Must not equal X0. 1 byte: Equation_type (unsigned integer). 0: Linear mapping 1: Base-e exponential mapping 2: Arbitrary-base exponential mapping 3: Hypberbolic mapping 1 byte: N (unsigned integer), number of parameters. u bytes: Unit_string (Latin-1 string). Symbol or description of the unit, eg. K, Population Density, MPa, etc). A zero-length string can be used for dimensionless data. 1 byte: null separator p0 bytes: P0 (ASCII text). First parameter, a real number written as a text floating-point value, as described above. 1 byte: null separator p1 bytes: P1 (ASCII text). Second parameter. etc.There is no null separator after the final parameter (or after the Unit_string field, if N=0). The number of parameters present must agree with the N field and must be correct for the specified Equation_type.
The Purpose identifies the equation, which can permit applications or people to choose the appropriate one when more than one pCAL chunk is present (this could occur in a multiple-image file, but not in a PNG file). The Purpose string must follow the format of a tEXt keyword, i.e., 1-79 printable Latin-1 characters, without leading, trailing, or consecutive blanks. One way the Purpose field could be used s to identify the system of units. A Purpose string such as "SI" or "English" could be used in the pCAL chunk as well as in other chunk types, to permit a decoder to select an appropriate set of chunks based on the contents of their Purpose fields.
The Unit_string can have any number of Latin-1 characters, or no characters at all, and there is no limitation on the number and position of blanks.
The pCAL chunk defines two mappings:
The mapping algorithms are
Original_sample = (Stored_sample * (X1 - X0) + M/2) / M + X0using integer arithmetic, where (a/b) means (integer(floor(real(a)/real(b)))). Note that this is the same as the "/" operator in the C programming language when "a" and "b" are nonnegative, but not necessarily when "a" or "b" is negative.
if Equation_type = 0 then Physical_value = P0 + P1 * Original_sample/(X1-X0) else if Equation_type = 1 then Physical_value = P0 + P1 * EXP(P2 * Original_sample/(X1-X0)) else if Equation_type = 2 then Physical_value = P0 + P1 * P2^(Original_sample/(X1-X0)) else if Equation_type = 3 then Physical_value = P0 + P1*SINH(P2*(Original_sample - P3)/(X1-X0))using floating-point arithmetic, in which
SINH(x) = 0.5 * ( EXP(x) - EXP(-x) )
Stored_sample = ((Original_sample - X0) * M + (X1 - X0) / 2) / (X1 - X0) (limited to the range [0..M])This mapping is lossless and reversible when (ABS(X1-X0) <= M) and the original sample is in the range [X0..X1]. If (ABS(X1-X0) > M) then there can be no lossless reversible mapping, but the functions provide the best integer approximations to floating-point affine transformations.
For color_types 2, 3, and 6, the mapping algorithms are applied independently to each of the color sample values. In the case of color type 3 (indexed color), 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 either with either equation_type 1 or Equation_type 2:
X0 = 0 X0 = 0 X1 = M X1 = M Equation_type = 1 Equation_type = 2 N = 3 or with N = 3 P0 = 0 P0 = 0 P1 = min P1 = min P2 = LOGe(max/min) P2 = max/minEquation_types 1 and 2 are functionally equivalent; both are defined because authors may find one or the other more convenient.
Using Equation_type 3, floating-point data in the range [-v0..v1] 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. For example, floating-point data ranging from -10^31 to 10^31 (the usual range of floating-point numbers on 32-bit machines) can be represented with
X0 = 0 X1 = 65535 Equation_type = 3 N = 4 P0 = 0.0 P1 = 1.0e-30 P2 = 280.0 P3 = 32767.0The resolution near zero is about 10^-33, while the resolution around +/-10^31 is about 10^28. Everywhere the resolution is about 0.4 percent of the magnitude.
Applications should use double precision arithmetic (or take other precautions) while performing the mappings for Equation_type 1, 2, and 3, to prevent overflow of intermediate results when the parameter P1 is small and the exponential or power functions are 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 stream.
Unit_specifier: 1 byte Pixel_width: m bytes (floating value as ASCII string) Null separator: 1 byte Pixel_height: n bytes (floating value as ASCII string)Valid values for the Unit_specifier field are:
1: unit is the meter 2: unit is the radianFollowing 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 chunk, there is no trailing zero for the final string. Each of these strings contains a floating-point constant in the format specified above (Floating-Point Values). Both values are required to be greater than zero.
If present, this chunk must precede the first IDAT chunk.
This chunk's contents are a zero-byte-terminated text string that names the palette and a 1-byte sPLT_sample_depth integer, followed by a series of palette entries, each a six-byte or ten-byte series containing five unsigned integers:
n bytes: (Latin-1 text) Palette_name 1 byte: (null) terminator 1 byte: (unsigned integer) sPLT_sample_depth must be 8 or 16 1 or 2 bytes: (unsigned integer) Red_level 0: black etc. 255 or 65535: full red intensity 1 or 2 bytes: (unsigned integer) Green_level 1 or 2 bytes: (unsigned integer) Blue_level 1 or 2 bytes: (unsigned integer) Alpha 0: fully transparent etc. 255 or 65535: fully opaque 2 bytes: (unsigned integer) Frequency (relative frequency of occurrence) etc.There can be any number of entries; a decoder determines the number of entries from the remaining chunk length after the Palette_name field and its zero-byte terminator, and the sPLT_sample_depth byte. This length not divisible by six (if sPLT_sample_depth=8) or by ten (if sPLT_sample_depth=16) is an error. Entries must appear in decreasing order of "frequency". There is no requirement that the entries all be used by the image, nor that they all be different.
The Palette_name (e.g., "256 color including Macintosh default", "256 color including Windows-3.1 default", "Optimal 512") identifies the palette. It may help applications or people to choose the appropriate suggested palette when more than one appears in a PNG file. The Palette_name string must follow the same restrictions imposed on tEXt keywords: it must consist only of printable Latin-1 characters and must not have leading or trailing blanks, but can have single embedded blanks. There must be at least one and no more than 79 characters in the name. Names are case-sensitive.
The Red_level, Green_level, and Blue_level values are not premultiplied by alpha, nor are they precomposited against any background. This differs from the treatment of suggested palettes represented by PLTE: in a truecolor image that uses transparency, sPLT provides suggested uncomposited color values, while a suggested-palette PLTE provides suggested colors after compositing against the bKGD color. A decoder can build a target palette by compositing sPLT palette entries against any background color or set of background colors that it chooses. It can then composite the truecolor PNG image against the desired background, and finally quantize the composited image into the target palette.
Each Frequency entry is proportional to the fraction of pixels in the image that are closest to that palette entry, without regard to any compositing against a background palette. The exact scale factor is chosen by the encoder, but should be chosen so that the range of individual values reasonably fills the range 0 to 65535. It is acceptable to artificially inflate the Frequency values for "important" colors such as those in a company logo or in the facial features of a portrait. Zero is a valid value for Frequency, meaning the color is "least important" or that it is rarely if ever used. But when all of the Frequency values are zero, the "frequency" is undefined.
The palette uses 8 bits or 16 bits (1 or 2 bytes) per value according to the number given in the sPLT_sample_depth field, regardless of the image bit depth specification. Decoders wishing to construct a palette with a different bit depth can accomplish this by scaling the RGBA entries, as described under "Sample depth rescaling" in the PNG specification. The palette samples have the same gamma and chromaticity values as those of the PNG image.
The sPLT chunk can appear for any color type. Note that entries in sPLT can fall outside the colorspace of the PNG image; for example, in a grayscale PNG, sPLT entries would typically have R=G=B, but this is not required and decoders must not fail if it is not so. (But a decoder can simply ignore a sPLT that is not to its liking.) Similarly, sPLT entries can have nonopaque alpha values even when the PNG image does not use transparency.
In an indexed-color (color type 3) PNG, PLTE defines the full color range of the PNG image, but sPLT can be used to define alternative reduced palettes for viewers that are unable to display all the colors present in the PLTE chunk.
If sPLT appears, it must precede the first IDAT chunk. There can be multiple sPLT chunks, but if so they must have different palette_names.
Note: The core PNG specification recommends the use of PLTE and hIST chunks to define suggested palettes for truecolor images. This is still allowed, but sPLT provides a more flexible solution:
An encoder that uses sPLT may choose to write a PLTE/hIST suggested palette as well, for backwards compatibility with decoders that do not recognize sPLT. Note that hIST defines the frequency of PLTE entries, not the entries of sPLT.
When converting single-image GIFs to PNG, these chunks should be placed in the same relative position within the PNG file as the extension block has within the GIF file. Thus converters can translate GIF extensions as they are encountered. Note, however, that these chunks are ancillary, safe-to-copy; therefore it is possible that a PNG editor will rearrange their order. Conversion of multiple-image GIFs is a more complex problem that will be addressed in a future document. For now, such files can be converted to a sequence of single-image PNG files.
In a GIF file, an extension block is organized as a series of sub-blocks, where each sub-block is preceded by a length byte. PNG does not use sub-blocks, so the GIF data must be de-blocked by removal of the sub-block length bytes. In addition, the converter is expected to convert certain fields from GIF byte order (LSB first) to network byte order (MSB first), and to expand image-size-related fields from two bytes to four. Fields requiring format changes are marked in the descriptions below.
For brevity, the following chunk descriptions simply define the layout of the chunk fields and indicate the reformatting required. The semantics of the field contents remain the same as in GIF. Readers are referred to the GIF89a specification for details. It is available on CompuServe from GRAPHSUPPORT library 16, file GIF89A.DOC, and is also widely available on Internet.
Disposal_method: 1 byte User_input: 1 byte Delay_time: 2 bytes (byte order converted from GIF)Disposal_method indicates the way in which the graphic is to be treated after being displayed. User_input indicates whether user input is required before continuing. 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 byte-order-converted.
The Transparent Color Flag and Transparency 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.
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 bytesText_grid_left_position, Text_grid_top_position, Text_grid_width, and Text_grid_height specify the text area position and size in pixels. The converter must reformat these fields from 2 bytes LSB-first unsigned integers to 4 bytes MSB-first signed or unsigned integers. Note that GIF defines the position to be relative to the upper left corner of the logical screen. If an oFFs chunk is also present with Unit_specifier = 0 (pixels), 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 from the Text_grid_left_position and Text_grid_top_position gives the text area position relative to the main PNG image (when converting a GIF that has a text rendering block to PNG, it is best to convert the local image Left and Top values to oFFs values in pixels, rather than in micrometers.)
Character_cell_width and Character_cell_height give the dimensions of each character in pixels.
Text_foreground_color and Text_background_color give the colors to be used to render text foreground and background. Note that the GIF-to-PNG 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 that this data is not in GIF sub-block format, but is a continuous datastream.
Application_identifier: 8 bytes Authentication_code: 3 bytes Application_data: n bytesThe 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 application-specific data whose content is not defined by the GIF specification.
Note that GIF-to-PNG 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 de-blocking GIF sub-blocks.
Applications that formerly used GIF Application Extensions may define special-purpose PNG chunks to replace their application extensions. If a GIF-to-PNG 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.
twegner@phoenix.net
.
This chunk was registered with good intentions, on the understanding that a full specification would be forthcoming in a timely manner. Implementation and testing of the fRAc chunk have been delayed by unforeseen complications. The PNG maintainers do not intend to register any other future chunks until they have been fully specified.
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.
/* Sample code for the PNG pCAL chunk */ #include <math.h> /* Math.h supplies double precision exp(), pow(), and * sinh() functions. If your math.h doesn't supply sinh(), * use sinh(x)=(exp(x)+exp(-x))/2. */ unsigned short limit(long low, double x, long high) { if (low < high){ if(x < low)return low; else if (x > high) return high; else return x; } else { if(x < high)return high; else if( x > low) return low; else return x; } } int pCAL_encode (unsigned short *stored_sample, long n, float *physical_value, unsigned int m, int equation_type, long x0, long x1, float *p) /* returns 0 (success) * -1 (error, x0==x1) * -2 (unknown equation type) * input: * n: number of samples * physical_value[0..n-1] * m: PNG sample depth * equation_type: from pCAL chunk * x0, x1: stored sample to original sample mapping * p[]: equation parameters, from pCAL chunk * output: * stored_samples[0..n-1] (caller must allocate space) */ { double d,dm; /* force double precision arithmetic */ long isample, osample, k; d=x1-x0; dm=m; if (x1 != x0) { if(equation_type == 0){ for (k=0; k<n; k++) { isample=.5+d*(physical_value[k] - p[0])/p[1]; osample=limit(x0, isample, x1); stored_sample[k]= floor(((osample-x0)*dm +floor(d/2))/d); } } else if(equation_type == 1){ for (k=0; k<n; k++) { isample= .5+d*(log(physical_value[k] - p[0])/p[1])/p[2]; osample=limit(x0, isample, x1); stored_sample[k]= floor(((osample-x0)*dm +floor(d/2))/d); } } else if(equation_type == 2){ double factor; factor=d/log(p[2]); for (k=0; k<n; k++) { isample=.5+log((physical_value[k] -p[0])/p[1])*factor; osample=limit(x0, isample, x1); stored_sample[k]= floor(((osample-x0)*dm +floor(d/2))/d); } } else if(equation_type == 3){ for (k=0; k<n; k++) { isample= .5+p[3]+d*asinh((physical_value[k] -p[0])/p[1])/p[2]; osample=limit(x0, isample, x1); stored_sample[k]= floor(((osample-x0)*dm +floor(d/2))/d); } } else return (-2); /* ERROR, unknown equation type */ } else return (-1); /* ERROR, x0 == x1 */ return (0); } int pCAL_make_lut (float *physical_value, unsigned int m, int equation_type, long x0, long x1, float *p) /* returns 0 (success) * -1 (error, x0==x1) * -2 (unknown equation type) * input: * m: PNG sample depth * equation_type: from pCAL chunk * x0, x1: stored sample to original sample mapping * p[]: equation parameters, from pCAL chunk * output: * physical_value[0..m] (caller must allocate space) */ { double d, dm; /* force double precision arithmetic */ long sample, osample; d=x1-x0; dm=m; if (x1 != x0) { if(equation_type == 0){ for (sample=0; sample<=m; sample++){ osample=floor((sample*d+floor(dm/2))/dm) + x0; physical_value[sample] = p[0] + p[1]*osample/d; } } else if(equation_type == 1){ for (sample=0; sample<=m; sample++){ osample=floor((sample*d+floor(dm/2))/dm) + x0; physical_value[sample] = p[0] + p[1]*exp(p[2]*osample/d); } } else if(equation_type == 2){ for (sample=0; sample<=m; sample++){ osample=floor((sample*d+floor(dm/2))/dm) + x0; physical_value[sample] = p[0] + p[1]*pow(p[2],osample/d); } } else if(equation_type == 3){ for (sample=0; sample<=m; sample++){ osample=floor((sample*d+floor(dm/2))/dm) + x0; physical_value[sample] = p[0] + p[1]*sinh(p[2]*(osample-p[3])/d); } } else return (-2); /* ERROR, unknown equation type */ } else return (-1); /* ERROR, X0 == X1 */ return (0); }
We want to avoid any surprises due to differences in "C" compiler implementations. Also, if we were to depend upon division truncating toward zero, we'd have to account for a discontinuity at Original_sample value zero. Zero would represent twice as large a range of physical values: