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

Pixel Calibration (pCAL)

  • Status:   officially registered (PNG Extensions)
  • Location:   after PLTE, before first IDAT
  • Multiple:   no

The pCAL chunk is currently the only registered scientific-visualization extension to PNG, though it was moved into the regular PNG Extensions document as part of the general PNG spec revision process in October 1998. It is also the most mathematical of any approved chunk. Its purpose is to efficiently encode the relevant conversions between the integer samples in a PNG file and the physical quantity being represented by the image. Two conversions are represented: a linear conversion between the PNG samples and the original samples and a more general conversion from the original samples to the physical values they represent. The first mapping is often the identity mapping (i.e., the original samples are equal to the PNG samples), but it need not be.

The layout of the pCAL chunk is presented in Table 11-7.

Table 11-7. pCAL Chunk

Field Length and Valid Range
Calibration name 1-79 bytes (Latin-1 text)
Null separator 1 byte
Original zero, X0 4 bytes (signed integer)
Original maximum, X1 4 bytes (signed integer)
Equation type 1 byte
Number of parameters, N 1 byte
Unit name n bytes (Latin-1 text)
Null separator 1 byte
Parameter 0, P0 p0 bytes (ASCII floating-point text)
Null separator 1 byte
... ...
Parameter L, PL pL bytes (ASCII floating-point text)
(Note: L = N-1)

The unit name is a label, such as kg/(m^3) or Mpc, that applies to the physical quantity represented by the image samples. Dimensionless data may either include a descriptive string (e.g., ``fractal iteration count'') or leave the unit field a null string. There are no restrictions on the length of the unit name.

The X0 and X1 parameters encode the linear conversion. For an 8-bit sample depth, the PNG samples range from 0 to 255; more generally, they range from 0 to M, where M = 2bit depth - 1. Most often, X0 will equal 0 and X1 will equal M, indicating that the PNG samples are the same as the original samples. But this need not be the case, and either of X0 or X1 may be positive or negative; the only restriction is that they may not be equal to each other. The conversion is done using integer arithmetic, according to the following equation:

original_sample = (PNG_sample * (X1-X0) + M/2) / M + X0

The inverse mapping is:

PNG_sample = ((original_sample - X0) * M + (X1-X0)/2) / (X1-X0)

Note that integer arithmetic here means that fractional values are rounded toward minus infinity, not toward zero; there's no difference for positive values, but for negative values, there is. Also keep in mind that the PNG samples are limited to the range [0,M] regardless of what the inverse mapping might give.

The more general conversion, between original samples and actual physical values, can be represented by one of four possible equation types: linear (type 0), exponential (type 1), exponential with arbitrary base (type 2), or hyperbolic sinusoidal (type 3). The number of parameters required by each is 2, 3, 3, and 4, respectively, and the parameters are stored in the same ASCII floating-point format as described for the sCAL chunk earlier. The equations use floating-point arithmetic, not integer, and are given by:

[0]   physical_value = P0 + P1 * original_sample/(X1-X0)

[1]   physical_value = P0 + P1 * eP2 * original_sample/(X1-X0)

[2]   physical_value = P0 + P1 * P2original_sample/(X1-X0)

[3]   physical_value = P0 + P1 * sinh(P2*(original_sample - P3)/(X1-X0))

Equation types 1 and 2 are equivalent in the sense that the same types of functions can be represented by either one; both are defined for convenience. For RGB or RGBA image types, the equations are applied to each of the color sample values independently, while for palette images, the equations are applied to the color sample values in the palette, not to the index values.

Equation type 3 may seem odd, but it allows floating-point data to be reduced to integer data in such a way that the resolution of the integer data is roughly proportional to the magnitude of the original floating-point data. That is, for 32-bit original data and 16-bit PNG samples, the resolution near zero is around 10-33, and near ±1031 it is around 1028. To put it another way, the resolution everywhere is about 0.4% (or 1/256) of the magnitude.

Last Update: 2010-Nov-26