MissingParameterException,
UnsupportedTypeException,
WrongFileFormatException,
WrongParameterException
{
DataInput in = getInputAsDataInput();
if (in == null)
{
throw new MissingParameterException("InputStream / DataInput object is missing.");
}
int formMagic = in.readInt();
if (formMagic != MAGIC_FORM)
{
throw new WrongFileFormatException("Cannot load image. The " +
"input stream is not a valid IFF file (wrong magic byte " +
"sequence).");
}
in.readInt(); // read and discard "file size" field
type = in.readInt();
if (type != MAGIC_ILBM && type != MAGIC_PBM)
{
throw new UnsupportedTypeException("Cannot load image. The " +
"input stream is an IFF file, but not of type ILBM or PBM" +
" (" + getChunkName(type) + ")");
}
PixelImage result = null;
boolean hasBMHD = false;
boolean hasCAMG = false;
do
{
int magic = in.readInt();
//System.out.println(chunkNameToString(magic));
int size = in.readInt();
// chunks must always have an even number of bytes
if ((size & 1) == 1)
{
size++;
}
//System.out.println("Chunk " + getChunkName(magic) + ", size=" + size);
switch(magic)
{
case(MAGIC_BMHD): // main header with width, height, bit depth
{
if (hasBMHD)
{
throw new InvalidFileStructureException("Error in " +
"IFF file: more than one BMHD chunk.");
}
if (size != SIZE_BMHD)
{
throw new InvalidFileStructureException("Cannot " +
"load image. The bitmap header chunk does not " +
"have the expected size.");
}
// image resolution in pixels
width = in.readShort();
height = in.readShort();
if (width < 1 || height < 1)
{
throw new InvalidFileStructureException("Cannot " +
"load image. The IFF file's bitmap header " +
"contains invalid width and height values: " +
width + ", " + height);
}
// next four bytes don't matter
in.skipBytes(4);
// color depth, 1..8 or 24
numPlanes = in.readByte();
if ((numPlanes != 24) && (numPlanes < 1 || numPlanes > 8))
{
throw new UnsupportedTypeException("Cannot load " +
"image, unsupported number of bits per pixel: " +
numPlanes);
}
//System.out.println("\nnum planes=" + numPlanes);
in.readByte(); // discard "masking" value
// compression type, must be 0 or 1
compression = in.readByte();
if (compression != COMPRESSION_NONE &&
compression != COMPRESSION_RLE)
{
throw new UnsupportedTypeException("Cannot load " +
"image, unsupported compression type: " +
compression);
}
//System.out.println(getCompressionName(compression));
in.skipBytes(9);
hasBMHD = true;
break;
}
case(MAGIC_BODY):
{
if (!hasBMHD)
{
// width still has its initialization value -1; no
// bitmap chunk was encountered
throw new InvalidFileStructureException("Cannot load image. Error in " +
"IFF input stream: No bitmap header chunk " +
"encountered before image body chunk.");
}
if (palette == null && (!rgb24))
{
// a missing color map is allowed only for truecolor images
throw new InvalidFileStructureException("Cannot load image. Error in " +
"IFF input stream: No colormap chunk " +
"encountered before image body chunk.");
}
result = loadImage(in);
break;
}
case(MAGIC_CAMG):
{
if (hasCAMG)
{
throw new InvalidFileStructureException("Cannot load image. Error in " +
"IFF input stream: More than one CAMG chunk.");
}
hasCAMG = true;
if (size < 4)
{
throw new InvalidFileStructureException("Cannot load" +
" image. CAMG must be at least four bytes large; " +
"found: " + size);
}
camg = in.readInt();
ham = (camg & 0x800) != 0;
ehb = (camg & 0x80) != 0;
//System.out.println("ham=" + ham);
in.skipBytes(size - 4);
break;
}
case(MAGIC_CMAP): // palette (color map)
{
if (palette != null)
{
throw new InvalidFileStructureException("Cannot " +
"load image. Error in IFF " +
"input stream: More than one palette.");
}
if (size < 3 || (size % 3) != 0)
{
throw new InvalidFileStructureException("Cannot " +
"load image. The size of the colormap is " +
"invalid: " + size);
}
int numColors = size / 3;
palette = new Palette(numColors, 255);
for (int i = 0; i < numColors; i++)
{
palette.putSample(Palette.INDEX_RED, i, in.readByte() & 0xff);
palette.putSample(Palette.INDEX_GREEN, i, in.readByte() & 0xff);
palette.putSample(Palette.INDEX_BLUE, i, in.readByte() & 0xff);
}
break;
}
default:
{
if (in.skipBytes(size) != size)
{
throw new IOException("Error skipping " + size +
" bytes of input stream.");
}
break;