package com.realityinteractive.imageio.tga; /* * TGAHeader.java * Copyright (c) 2003 Reality Interactive, Inc. * See bottom of file for license and warranty information. * Created on Sep 26, 2003 */ import java.io.IOException; import javax.imageio.stream.ImageInputStream; /** *
The header to a TGA image file.
* *See format, * format or * format * for header information.
* * @author Rob Grzywinski rgrzywinski@realityinteractive.com * @version $Id: TGAHeader.java,v 1.1 2005/04/12 11:23:53 ornedan Exp $ * @since 1.0 */ public class TGAHeader { /** *The length of the TGA identifier. This is a byte
in
* length.
The image identifier with length idLength
.
Does this TGA have an associated color map? 1
indicates
* that there is a color map. 0
indicates no color map.
The type of image. See the image type constants in {@link com.realityinteractive.imageio.tga.TGAConstants} * for allowed values.
*/ private int imageType; /** *An image is compressed if its image type is {@link TGAConstants#RLE_COLOR_MAP}, * {@link TGAConstants#RLE_TRUE_COLOR}, or {@link TGAConstants#RLE_MONO}.
*/ private boolean isCompressed; /** *The index of the first color map entry.
*/ private int firstColorMapEntryIndex; /** *The total number of color map entries.
*/ private int numberColorMapEntries; /** *The number of bits per color map entry.
*/ private int bitsPerColorMapEntry; /** *The computed size of a color map entry in byte
s.
The computed size of the color map field in byte
s. This
* is determined from the numberColorMapEntries
and
* colorMapEntrySize
.
The horizontal coordinate for the lower-left corner of the image.
*/ private int xOrigin; /** *The vertical coordinate for the lower-left corner of the image.
*/ private int yOrigin; /** *The width of the image in pixels.
*/ private int width; /** *The height of the image in pixels.
*/ private int height; /** *The number of bits per pixel.
*/ private int bitsPerPixel; /** *The number of attribute bits per pixel.
*/ private int imageDescriptor; /** *The horizontal ordering of the pixels as determined from the image * descriptor. By default the order is left to right.
*/ // NOTE: true -> left-to-right; false -> right-to-left private boolean leftToRight; /** *The horizontal ordering of the pixels as determined from the image * descriptor. By default the order is left to right.
*/ // NOTE: true -> bottom-to-top; false -> top-to-bottom private boolean bottomToTop; /** *The offset to the color map data. This value is not defined if there
* is no color map (see hasColorMap
).
The offset to the pixel data.
*/ private int pixelDataOffset; // ========================================================================= /** *Constructs a TGA header that will be populated by setters or directly * (via a static "factory" method).
*/ public TGAHeader() {} /** *Constructs and populates a TGA header from the specified {@link javax.imageio.stream.ImageInputStream}.
* * @param inputStream theImageInputStream
from which the
* header data is read
* @throws IOException if there was an I/O error while reading the header
* data
*/
public TGAHeader(final ImageInputStream inputStream)
throws IOException
{
// read the data
readHeader(inputStream);
}
/**
* Reads and populates the header from the specifed {@link javax.imageio.stream.ImageInputStream}. * Any existing values will be over written.
* *The ImageInputStream
will be changed as a result of this
* operation (the offset will be moved).
ImageInputStream
from which the
* header data is read
* @throws IOException if there was an I/O error while reading the header
* data
*/
public void readHeader(final ImageInputStream inputStream)
throws IOException
{
// read in the header as per the spec
idLength = inputStream.readUnsignedByte();
hasColorMap = (inputStream.readUnsignedByte() == 1); // 1 == true, 0 == false
imageType = inputStream.readUnsignedByte();
firstColorMapEntryIndex = inputStream.readUnsignedShort();
numberColorMapEntries = inputStream.readUnsignedShort();
bitsPerColorMapEntry = inputStream.readByte();
xOrigin = inputStream.readUnsignedShort();
yOrigin = inputStream.readUnsignedShort();
width = inputStream.readUnsignedShort();
height = inputStream.readUnsignedShort();
bitsPerPixel = inputStream.readByte();
imageDescriptor = inputStream.readByte();
// determine if the image is compressed
isCompressed = ( (imageType == TGAConstants.RLE_COLOR_MAP) ||
(imageType == TGAConstants.RLE_TRUE_COLOR) ||
(imageType == TGAConstants.RLE_MONO) );
// compute the size of the color map field in bytes
switch(bitsPerColorMapEntry)
{
case 8:
default:
colorMapEntrySize = 1;
break;
case 15:
case 16:
colorMapEntrySize = 2;
break;
case 24:
case 32:
colorMapEntrySize = 3;
break;
}
colorMapSize = colorMapEntrySize * numberColorMapEntries; // in bytes
// set the pixel ordering from the imageDescriptor bit mask
// (bit set indicates false)
leftToRight = ((imageDescriptor & TGAConstants.LEFT_RIGHT_BIT) == 0);
bottomToTop = ((imageDescriptor & TGAConstants.BOTTOM_TOP_BIT) == 0);
// read the image id based whose length is idLength
if(idLength > 0)
{
// allocate the space for the id
id = new byte[idLength];
// read the id
inputStream.read(id, 0, idLength);
} /* else -- the idLength was not positive */
// compute the color map and pixel data offsets. The color map data
// offset is the current offset.
// NOTE: the conversion to int is OK since the maximum size of the
// color map data is 65536 bytes.
final long currentOffset = inputStream.getStreamPosition();
colorMapDataOffset = (int)currentOffset;
if(hasColorMap)
{
// there is a color map so the pixel data offset is the current
// offset + the size of the color map data
pixelDataOffset = colorMapDataOffset + colorMapSize;
} else /* there is no color map */
{
// there is no color map so the pixel data offset is the current
// offset
pixelDataOffset = (int)currentOffset;
}
}
/**
* The length of the TGA identifier. This is a byte
in
* length.
Does this TGA have an associated color map?
*/ public boolean hasColorMap() { return hasColorMap; } /** *Retrieves the type of image. See the image type constants in {@link com.realityinteractive.imageio.tga.TGAConstants} * for allowed values.
*/ public int getImageType() { return imageType; } /** *Retrieves a string that represents the image type.
*/ public String getImageTypeString() { switch(imageType) { case TGAConstants.NO_IMAGE: return "NO IMAGE"; case TGAConstants.COLOR_MAP: return "COLOR MAP"; case TGAConstants.TRUE_COLOR: return "TRUE COLOR"; case TGAConstants.MONO: return "MONOCHROME"; case TGAConstants.RLE_COLOR_MAP: return "RLE COMPRESSED COLOR MAP"; case TGAConstants.RLE_TRUE_COLOR: return "RLE COMPRESSED TRUE COLOR"; case TGAConstants.RLE_MONO: return "RLE COMPRESSED MONOCHROME"; default: return "UNKNOWN"; } } /** *Retrieves if this image is compressed. If the image type is * {@link TGAConstants#RLE_COLOR_MAP}, {@link TGAConstants#RLE_TRUE_COLOR}, * or {@link TGAConstants#RLE_MONO} then the image is compressed.
*/ public boolean isCompressed() { return isCompressed; } /** *Retrieves the index of the first color map entry.
*/ public int getFirstColorMapEntryIndex() { return firstColorMapEntryIndex; } /** *Retrieves ttotal number of color map entries.
*/ public int getColorMapLength() { return numberColorMapEntries; } /** *Retrieves the number of bits per color map entry.
*/ public int getBitsPerColorMapEntry() { return bitsPerColorMapEntry; } /** *Retrieves the horizontal coordinate for the lower-left corner of the * image.
*/ public int getXOrigin() { return xOrigin; } /** *Retrieves the vertical coordinate for the lower-left corner of the image.
*/ public int getYOrigin() { return yOrigin; } /** *Retrieves the width of the image in pixels.
*/ public int getWidth() { return width; } /** *Retrieves the height of the image in pixels.
*/ public int getHeight() { return height; } /** *Retrieves the number of bits per pixel.
*/ public int getBitsPerPixel() { return bitsPerPixel; } /** *Retrieves the number of samples per pixel.
*/ public int getSamplesPerPixel() { // FIXME: this is overly simplistic but it is accurate return (bitsPerPixel == 32) ? 4 : 3; } /** *Retrieves the number of attribute bits per pixel.
*/ public int getImageDescriptor() { return imageDescriptor; } /** *Returns if this image is left-to-right (true
) or right-
* to-left (false
).
Returns if this image is bottom-to-top (true
) or top-to-
* bottom (false
).
Retrieves the offset to the color map data. If there is no color
* map ({@link #hasColorMap()} returns false
) then this is
* undefined.
Retrieves the offset to the pixel data.
*/ public int getPixelDataOffset() { return pixelDataOffset; } // ========================================================================= /** *Retrieves a string useful for debugging.
* * @return a string useful for debugging */ public String debugString() { return "TGAHeader[" + "type=" + getImageTypeString() + ", " + (hasColorMap ? ("firstColorMapEntryIndex=" + firstColorMapEntryIndex + ", " + "numberColorMapEntries=" + numberColorMapEntries + ", " + "bitsPerColorMapEntry=" + bitsPerColorMapEntry + ", " + "totalColorMapEntrySize=" + colorMapSize + ", " ) : "") + "isCompressed=" + isCompressed + ", " + "xOrigin=" + xOrigin + ", " + "yOrigin=" + yOrigin + ", " + "width=" + width + ", " + "height=" + height + ", " + "bitsPerPixel=" + bitsPerPixel + ", " + "samplesPerPixel=" + getSamplesPerPixel() + "]"; } } // ============================================================================= /* This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */