A codec to read and write image files in the native image file format of
Palm OS,
an operating system for handheld devices.
Supported file types when loading
This codec reads uncompressed, scan line compressed and RLE compressed Palm files
with bit depths of 1, 2, 4, 8 and 16 bits per pixel.
Not supported are the Packbits compression algorithm or any color depths other
then the aforementioned.
Supported image types when saving
Compression types
Uncompressed,
Scan line and
RLE are written.
When saving an image as a Palm, the image data classes will be mapped to file types as follows:
BilevelImage
: will be saved as a 1 bit per pixel, monochrome file.Gray8Image
: will be saved as an 8 bits per pixel file with a custom
palette which will contain the 256 shades of gray from black - (0, 0, 0) - to
white - (255, 255, 255).Paletted8Image
: it is first checked if the image is using the
Palm system 8 bits per pixel palette. If so, an 8 bits per pixel file
with no custom palette is written, otherwise an 8 bits per pixel file
with a custom palette (of the original length) is written.
RGB24Image
: will be saved as a 16 bits per pixel, direct color file.
Some information will get lost when converting from 24 to 16 bits per pixel.
Instead of 256 shades for each red, green and blue (and thus, 2563 = 16,777,216
possible colors) the resulting file will only
use 32 shades of red and blue and 64 shades of green (65,536 possible colors).
I/O objects
This codec supports all the I/O classes that are considered in ImageCodec.
If you save images and want a correct
compressed size field
in the resulting Palm file, make sure to give a RandomAccessFile object to
the codec.
Or simply use
setFile(String,CodecMode)
which does that automatically.
File extension
This codec suggests
.palm
as file extension for this file format.
This is by no means official, but I find it helpful.
Transparency information
The transparency index in a Palm file is saved and loaded, but a loaded index
is not stored in the image object as there is no support for transparency information of
any kind in PixelImage yet.
The RGB transparency color that is present in a file only in direct color mode
is read but not written.
Bounds
The bounds concept of ImageCodec is supported so that you can load or save
only part of an image.
Open questions on the Palm file format
- How does Packbits compression work? Where can I get sample files or a Windows
converter that writes those?
- How is FLAG_4_BYTE_FIELDS interpreted? When are four byte fields used?
- When loading a 4 bpp Palm image file without a custom palette,
how is the decoder supposed to know whether to take the predefined
color or grayscale palette with 16 entries?
Known problems
- Unfortunately, the Palm image file format does not include a signature that
makes it easy to identify such a file. Various checks on allowed combinations of
color depth, compression type etc. will prevent the codec from trying to interpret
all files as Palm image files, but there is still a probability of false
identification.
Usage examples
Load an image from a Palm image file:
PalmCodec codec = new PalmCodec();
codec.setFile("test.palm", CodecMode.LOAD);
codec.process();
PixelImage image = codec.getImage();
codec.close();
Save an image to a Palm file using RLE compression:
PalmCodec codec = new PalmCodec();
codec.setImage(image);
codec.setCompression(PalmCodec.COMPRESSION_RLE);
codec.setFile("out.palm", CodecMode.SAVE);
codec.process();
codec.close();
Background
The code is based on:
- the specification
Palm
Native Image Format,
- the source code of the utilities
pnmtopalm
and
palmtopnm
that are part of the
Netpbm package, - Palm OS Compressed Bitmaps by Ken Krugler,
a Palm Developer Knowledge Base article on the scan line compression algorithm and
- Palm OS Bitmaps,
also part of the Palm Developer Knowledge Base, contains general information on the
structure of Palm images.
I also received helpful feedback and test images from Bill Janssen.
COMPRESSION_NONE
public static final int COMPRESSION_NONE
Constant for compression type Uncompressed.
COMPRESSION_PACKBITS
public static final int COMPRESSION_PACKBITS
Constant for compression type Packbits.
COMPRESSION_RLE
public static final int COMPRESSION_RLE
Constant for compression type RLE (run length encoding).
COMPRESSION_SCANLINE
public static final int COMPRESSION_SCANLINE
Constant for compression type Scanline.
FLAG_COLOR_TABLE
private static final int FLAG_COLOR_TABLE
FLAG_COMPRESSED
private static final int FLAG_COMPRESSED
FLAG_DIRECT_COLOR
private static final int FLAG_DIRECT_COLOR
FLAG_TRANSPARENCY
private static final int FLAG_TRANSPARENCY
PALM_SYSTEM_PALETTE_16_COLOR
private static final short[][] PALM_SYSTEM_PALETTE_16_COLOR
PALM_SYSTEM_PALETTE_16_GRAY
private static final short[][] PALM_SYSTEM_PALETTE_16_GRAY
PALM_SYSTEM_PALETTE_256
private static final short[][] PALM_SYSTEM_PALETTE_256
PALM_SYSTEM_PALETTE_4_GRAY
private static final short[][] PALM_SYSTEM_PALETTE_4_GRAY
bitsPerPixel
private int bitsPerPixel
blueBits
private int blueBits
bytesPerRow
private int bytesPerRow
compressedDataOffset
private long compressedDataOffset
compression
private int compression
greenBits
private int greenBits
redBits
private int redBits
transColor
private byte[] transColor
transparencyIndex
private int transparencyIndex
version
private int version
createPalette
private static Palette createPalette(short[][] data)
createSystem2BitGrayscalePalette
public static Palette createSystem2BitGrayscalePalette()
Creates the 2 bits per pixel Palm system palette with grayscale values.
This palette is used when no custom palette is defined in a 2 bpp image.
- Palm's default palette for 2 bits per pixel (grayscale), with 4 entries
createSystem4BitColorPalette
public static Palette createSystem4BitColorPalette()
Creates the 4 bits per pixel Palm system palette with color values.
This palette (or the 4 bpp grayscale palette) is used when no custom palette is defined in a 4 bpp image.
- Palm's default palette for 4 bits per pixel (color), with 16 entries
createSystem4BitGrayscalePalette
public static Palette createSystem4BitGrayscalePalette()
Creates the 4 bits per pixel Palm system palette with grayscale values.
This palette (or the 4 bpp color palette) is used when no custom palette is defined in a 4 bpp image.
- Palm's default palette for 4 bits per pixel (grayscale), with 16 entries
createSystem8BitPalette
public static Palette createSystem8BitPalette()
Creates the 8 bits per pixel Palm system palette.
This palette is used when no custom palette is defined in an 8 bpp image.
- Palm's default palette for 8 bits per pixel, with 256 entries
getCompression
public int getCompression()
Returns the Palm compression method.
This should be one of the COMPRESSION_xyz constants of this class.
- integer value with the compression method (found in a file when
loading or to be used for saving)
getTransparencyIndex
public int getTransparencyIndex()
Returns the transpareny index if one is available (
hasTransparencyIndex()
returns
true
) or an undefined value otherwise.
hasTransparencyIndex
public boolean hasTransparencyIndex()
- transparency index, a positive value that is a valid index into the palette
invertBilevelData
private void invertBilevelData(byte[] row)
isEqualPalette
private static boolean isEqualPalette(Palette palette,
short[][] data)
isPalmSystemPalette256
public static boolean isPalmSystemPalette256(Palette palette)
Returns if the argument palette is the Palm system palette
with 256 colors.
- if the argument is an 8 bits per pixel Palm system palette
isPalmSystemPaletteColor16
public static boolean isPalmSystemPaletteColor16(Palette palette)
Returns if the argument palette is the Palm system color palette
with 16 entries.
isPalmSystemPaletteGray16
public static boolean isPalmSystemPaletteGray16(Palette palette)
Returns if the argument palette is the Palm system grayscale palette
with 16 entries.
isPalmSystemPaletteGray4
public static boolean isPalmSystemPaletteGray4(Palette palette)
Returns if the argument palette is the Palm system grayscale palette
with 4 entries.
removeTransparencyIndex
public void removeTransparencyIndex()
Removes the transparency index if one has been set.
save
private void save(DataOutput out,
BilevelImage image)
throws IOException
save
private void save(DataOutput out,
Gray8Image image)
throws IOException
save
private void save(DataOutput out,
Paletted8Image image)
throws IOException
save
private void save(DataOutput out,
RGB24Image image)
throws IOException
saveFinalCompressedSize
private void saveFinalCompressedSize(DataOutput out)
throws IOException
saveHeader
private void saveHeader(DataOutput out)
throws IOException
saveInitialCompressedSize
private void saveInitialCompressedSize(DataOutput out)
throws IOException
savePalette
private void savePalette(DataOutput out,
Palette palette)
throws IOException
saveRow
private void saveRow(DataOutput out,
boolean firstRow,
byte[] row,
byte[] prev)
throws IOException
saveRowRLE
private void saveRowRLE(DataOutput out,
byte[] row)
throws IOException
saveRowScanLine
private void saveRowScanLine(DataOutput out,
boolean firstRow,
byte[] row,
byte[] prev)
throws IOException
setCompression
public void setCompression(int newCompressionType)
Sets the compression algorithm to be used for saving an image.
newCompressionType
- int value that is one of the COMPRESSION_xyz constants of this class
setCorrectVersion
private void setCorrectVersion()
setFile
public void setFile(String fileName,
CodecMode codecMode)
throws IOException,
UnsupportedCodecModeException
Reuses super.setFile when used for CodecMode.LOAD, but
creates a RandomAccessFile instead of a FileOutputStream
in write mode so that the compressed size can be written
correcly (requires a seek operation).
- setFile in interface ImageCodec
fileName
- name of the file to be openedcodecMode
- defines whether this codec object is to be used for loading or saving
setTransparencyIndex
public void setTransparencyIndex(int newIndex)
Sets a new transparency index when saving an image.
If this method is called, the argument value is used as an index
into the palette for a color that is supposed to be transparent.
When the resulting Palm image file is drawn onto some background,
all pixels in the color pointed to by the transparency index are not
supposed to be overdrawn so that the background is visisble at
those places.
newIndex
- the new transparency index, must be smaller than the number of entries in the palette
store
private void store(PixelImage image,
int y,
byte[] row)