This page contains a short summary of the Palm native image format. Thanks to Ross Thompson for the corrections, the gif conversion C-programm, and the description of the compression formats!
2 byte quantities are packed in "big endian" order (most significant byte first.
Offset (bytes) | Size (bytes) | Name | Description |
---|---|---|---|
0 | 2 | width | Width of the image (pixels) |
2 | 2 | height | Height of the image (pixels) |
4 | 2 | rowBytes | Number of bytes in each row of the image (must be even) |
6 | 2 | flags | 0x8000: Compressed 0x4000: hasColorTable 0x2000: Transparency |
8 | 1 | pixel size | The size of a pixel in bits (1, 2, 4 or 8); n bits allow 2n colors |
9 | 1 | version | The version number of the data structure. 0: Palm OS 1 1: Palm OS 3, no transparency, no RLE compression. 2: Palm OS 3.5; transparency and RLE compression supported |
10 | 2 | nextDepthOffset | Palm images may consist of a set of structures for different screen color depths. If so, this field contains the number of four byte words to the start of the next image from the start of this structure |
12 | 1 | transparent index | Index of the transparent color if the transparent flag is set. Not used in versions 0 or 1 |
13 | 1 | compression type | Type of compression, not supported for versions 0 or 1: 0: ScanLine 1: RLE |
14 | 2 | reserved | Reserved for future extensions |
16 | variable | data | Color table and Image data |
If the image has a color table, the next two bytes determine the number of four byte color table entries of the following structure:
The actual pixel data are represented as a byte vector, where 1 to 8 pixel values are stored in one byte, depending on the bit size of a pixel. If multiple pixels are in a single byte, the most significant bits correspond to the left-most pixel. Pixel values are indexes into a color table. If no color table is provided with the image, the system color table is used. For uncompressed images, the scanlines are exactly rowBytes long. For compressed images, a two byte integer precedes the pixel data, which indicates the length of the image data (pixel data + 2 bytes for the count.)
Scanline compression takes advantage of similarity on the vertical axis. Each raster (after the first) only needs to provide data bytes that are different from the previous scan line. This is best described with an example. Let us assume we are trying to draw diagonal lines two pixels wide. (For simplicity, we will use 8 bit pixels in the example, though such an image really only requires 1 bit pixels.)
The uncompressed data for this (13x13) image might look like this (169 bytes):
25 25 88 88 25 25 88 88 25 25 88 88 25 25 88 88 25 25 88 88 25 25 88 88 25 25 88 88 25 25 88 88 25 25 88 88 25 25 88 88 25 25 88 88 25 25 88 88 25 25 88 88 25 25 88 88 25 25 88 88 25 25 88 88 25 25 88 88 25 25 88 88 25 25 88 88 25 25 88 88 25 25 88 88 25 25 88 88 25 25 88 88 25 25 88 88 25 25 88 88 25 25 88 88 25 25 88 88 25 25 88 88 25 25 88 88 25 25 88 88 25 25 88 88 25 25 88 88 25 25 88 88 25 25 88 88 25 25 88 88 25 25 88 88 25 25 88 88 25 25 88 88 25 25 88 88 25 25 88 88 25 25 88 88 25 25 88 88 25
Starting for the moment with the second raster, we see that every other byte is the same as the corresponding byte from the previous raster. We encode the first 8 bytes of the second raster by first writing a flag byte that indicates we will be supplying only the second, fourth, sixth, and eighth bytes. This byte is binary 01010101, or 0x55. We then supply only the bytes that correspond to bits set for the flag word. Generalizing this to the entire second raster, we obtain (with flag bytes in bold)
55 88 25 88 25 50 88 25
The only gimick is that the first row has no prior row, so it must be specified completely. So, the representation of the first row would be
FF 25 25 88 88 25 25 88 88 F8 25 25 88 88 25
So, the image data (including the two byte length at the top) would be represented (in 119 bytes) thus:
00 77 FF 25 25 88 88 25 25 88 88 F8 25 25 88 88 25 55 88 25 88 25 50 88 25 AA 88 25 88 25 A8 88 25 88 55 25 88 25 88 50 25 88 AA 25 88 25 88 A8 25 88 25 55 88 25 88 25 50 88 25 AA 88 25 88 25 A8 88 25 88 55 25 88 25 88 50 25 88 AA 25 88 25 88 A8 25 88 25 55 88 25 88 25 50 88 25 AA 88 25 88 25 A8 88 25 88 55 25 88 25 88 50 25 88 AA 25 88 25 88 A8 25 88 25
(Note: The formatting and spacing is for readability only.)
Encoding the above example with run length encoding would yeild the following (184 bytes, including the two byte length):
00 B8 02 25 02 88 02 25 02 88 02 25 02 88 01 25 01 25 02 88 02 25 02 88 02 25 02 88 02 25 02 88 02 25 02 88 02 25 02 88 02 25 01 88 01 88 02 25 02 88 02 25 02 88 02 25 02 88 02 25 02 88 02 25 02 88 02 25 02 88 01 25 01 25 02 88 02 25 02 88 02 25 02 88 02 25 02 88 02 25 02 88 02 25 02 88 02 25 01 88 01 88 02 25 02 88 02 25 02 88 02 25 02 88 02 25 02 88 02 25 02 88 02 25 02 88 01 25 01 25 02 88 02 25 02 88 02 25 02 88 02 25 02 88 02 25 02 88 02 25 02 88 02 25 01 88 01 88 02 25 02 88 02 25 02 88 02 25 02 88 02 25 02 88 02 25 02 88 02 25 02 88 01 25
(That is, for the first row, there would be "two" bytes of "0x25", "two" bytes of "0x88", and so forth.)