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.

*/ private int idLength; /** *

The image identifier with length idLength.

*/ private byte[] id; /** *

Does this TGA have an associated color map? 1 indicates * that there is a color map. 0 indicates no color map.

*/ private boolean hasColorMap; /** *

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 bytes.

*/ private int colorMapEntrySize; /** *

The computed size of the color map field in bytes. This * is determined from the numberColorMapEntries and * colorMapEntrySize.

*/ private int colorMapSize; /** *

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).

*/ private int colorMapDataOffset; /** *

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 the ImageInputStream 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).

* * @param inputStream the 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.

*/ public int getIdLength() { return idLength; } /** *

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).

*/ public boolean isLeftToRight() { return leftToRight; } /** *

Returns if this image is bottom-to-top (true) or top-to- * bottom (false).

*/ public boolean isBottomToTop() { return bottomToTop; } /** *

Retrieves the offset to the color map data. If there is no color * map ({@link #hasColorMap()} returns false) then this is * undefined.

*/ public int getColorMapDataOffset() { return colorMapDataOffset; } /** *

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 */