Images are stored as an array of unsigned characters. Ideally, they would be in a structure,
but the limitations of C prevents an efficient definition of a structure for an image
while still allowing a compile-time declaration of the data for an image.
The effective definition of the structure is as follows (with no padding between members):
typedef struct { // // Specifies the format of the image data; will be one of // IMAGE_FMT_1BPP_UNCOMP, IMAGE_FMT_4BPP_UNCOMP, IMAGE_FMT_8BPP_UNCOMP, // IMAGE_FMT_1BPP_COMP, IMAGE_FMT_4BPP_COMP, or IMAGE_FMT_8BPP_COMP. // The xxx_COMP varieties indicate that the image data is compressed. // unsigned char ucFormat; // // The width of the image in pixels. // unsigned short usWidth; // // The height of the image in pixels. // unsigned short usHeight; // // The image data. This is the structure member that C can not handle // efficiently at compile time. // unsigned char pucData[];
// 1bpp : No Palette in pucData[] : < use Context->ulBackground and Context->ulForeground
// 4bpp : ulPaletteColorNum : PaletteColor[0][3] .. PaletteColor[15][3]
// 8bpp : ulPaletteColorNum : PaletteColor[0][3] .. PaletteColor[255][3]
} tImage;
The format of the image data is dependent upon the number of bits per pixel
and the use of compression.
When compression is used, the uncompressed data will match the data
that would appear in the image data for non-compressed images.
For 1 bit per pixel images,
the image data is simply a sequence of bytes that describe the pixels in the image.
Bits that are on represent pixels that should be drawn in the foreground color,
and bits that are off represent pixels that should be drawn in the background color.
The data is organized in row major order,
with the first byte containing the left-most 8 pixels of the first scan line.
The most significant bit of each byte corresponds to the left-most pixel,
and padding bits are added at the end each scan line (if required)
in order to ensure that each scan line starts at the beginning of a byte.
For 4 bits per pixel images,
the first byte of the image data is the number of actual palette entries
which is actually stored as N - 1; in other words, an 8 entry palette will have 7 in this byte.
The next bytes are the palette for the image, which each entry being organized as
a blue byte followed by a green byte followed by a red byte. < B G R >
Following the palette is the actual image data, where each nibble corresponds to an entry in the palette.
The bytes are organized the same as for 1 bit per pixel images,
and the most significant nibble of each byte corresponds to the left-most pixel.
For 8 bits per pixel images,
the format is the same as 4 bits per pixel images
with a larger palette and each byte containing exactly one pixel.
When the image data is compressed, the Lempel-Ziv-Storer-Szymanski algorithm < LZSS >
is used to compress the data.
This algorithm was originally published in the Journal of the ACM, 29(4):928-951, October 1982.
The essence of this algorithm is to use the N most recent output bytes as a dictionary;
the next encoded byte is either a literal byte (which is directly output) or
a dictionary reference of up to M sequential bytes.
For highly regular images (such as would be used for typical graphical controls), this works very well.
The compressed data is arranged as a sequence of 9 byte chunks.
The first byte is a set of flags that indicate if the next 8 bytes
are literal or dictionary references (one bit per byte).
The most significant bit of the flags corresponds to the first byte.
If the flag is clear, the byte is a literal;
if it is set, the byte is a dictionary reference
where the upper five bits are the dictionary offset and
the lower three bits are the reference length (where 0 is 2 bytes, 1 is 3 bytes, and so on).
Since a one byte dictionary reference takes one byte to encode, it is always stored as a literal
so that length is able to range from 2 through 9 (providing a longer possible dictionary reference).
The last 9 byte chunk may be truncated if all 8 data bytes are not required to encode the entire data sequence.
A utility (pnmtoc) is provided to assist in converting images into this format; it is documented in chapter 13.