Updated Release Archive
Updated Release Archive. Fixed Mage-killer prereqs. Removed old LETO & ConvoCC related files. Added organized spell scroll store. Fixed Gloura spellbook. Various TLK fixes. Reorganized Repo. Removed invalid user folders. Added DocGen back in.
This commit is contained in:
@@ -0,0 +1,88 @@
|
||||
package com.realityinteractive.imageio.tga;
|
||||
|
||||
/*
|
||||
* TGAConstants.java
|
||||
* Copyright (c) 2003 Reality Interactive, Inc.
|
||||
* See bottom of file for license and warranty information.
|
||||
* Created on Sep 26, 2003
|
||||
*/
|
||||
|
||||
/**
|
||||
* <p>Various header and such constants for the TGA image format.</p>
|
||||
*
|
||||
* @author Rob Grzywinski <a href="mailto:rgrzywinski@realityinteractive.com">rgrzywinski@realityinteractive.com</a>
|
||||
* @version $Id: TGAConstants.java,v 1.1 2005/04/12 11:23:53 ornedan Exp $
|
||||
* @since 1.0
|
||||
*/
|
||||
public interface TGAConstants
|
||||
{
|
||||
// =========================================================================
|
||||
// image types
|
||||
/**
|
||||
* <p>An image type indicating no image data.</p>
|
||||
*/
|
||||
int NO_IMAGE = 0;
|
||||
|
||||
/**
|
||||
* <p>An image type indicating an uncompressed color mapped (indexed) image.</p>
|
||||
*/
|
||||
int COLOR_MAP = 1;
|
||||
|
||||
/**
|
||||
* <p>An image type indicating an uncompressed true-color image.</p>
|
||||
*/
|
||||
int TRUE_COLOR = 2;
|
||||
|
||||
/**
|
||||
* <p>An image type indicating a black and white (monochrome) image.</p>
|
||||
*/
|
||||
int MONO = 3;
|
||||
|
||||
/**
|
||||
* <p>An image type indicating an RLE (run-length encoded) color-mapped
|
||||
* (indexed) image.</p>
|
||||
*/
|
||||
int RLE_COLOR_MAP = 9;
|
||||
|
||||
/**
|
||||
* <p>An image type indicating an RLE (run-length encoded) true-color
|
||||
* image.</p>
|
||||
*/
|
||||
int RLE_TRUE_COLOR = 10;
|
||||
|
||||
/**
|
||||
* <p>An image type indicating an RLE (run-length encoded) black and white
|
||||
* (monochrome) image.</p>
|
||||
*/
|
||||
int RLE_MONO = 11;
|
||||
|
||||
// =========================================================================
|
||||
// Image descriptor bit
|
||||
/**
|
||||
* <p>The bit of the image descriptor field (5.5) indicating that the first
|
||||
* pixel should be at the left or the right.</p>
|
||||
*/
|
||||
int LEFT_RIGHT_BIT = 0x10;
|
||||
|
||||
/**
|
||||
* <p>The bit of the image descriptor field (5.5) indicating that the first
|
||||
* pixel should be at the bottom or the top.</p>
|
||||
*/
|
||||
int BOTTOM_TOP_BIT = 0x20;
|
||||
}
|
||||
// =============================================================================
|
||||
/*
|
||||
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
|
||||
*/
|
@@ -0,0 +1,479 @@
|
||||
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;
|
||||
|
||||
/**
|
||||
* <p>The header to a TGA image file.</p>
|
||||
*
|
||||
* <p>See <a href="http://organicbit.com/closecombat/formats/tga.html">format</a>,
|
||||
* <a href="http://www.opennet.ru/docs/formats/targa.pdf">format</a> or
|
||||
* <a href="http://netghost.narod.ru/gff/graphics/summary/tga.htm">format</a>
|
||||
* for header information.</p>
|
||||
*
|
||||
* @author Rob Grzywinski <a href="mailto:rgrzywinski@realityinteractive.com">rgrzywinski@realityinteractive.com</a>
|
||||
* @version $Id: TGAHeader.java,v 1.1 2005/04/12 11:23:53 ornedan Exp $
|
||||
* @since 1.0
|
||||
*/
|
||||
public class TGAHeader
|
||||
{
|
||||
/**
|
||||
* <p>The length of the TGA identifier. This is a <code>byte</code> in
|
||||
* length.</p>
|
||||
*/
|
||||
private int idLength;
|
||||
|
||||
/**
|
||||
* <p>The image identifier with length <code>idLength</code>.</p>
|
||||
*/
|
||||
private byte[] id;
|
||||
|
||||
/**
|
||||
* <p>Does this TGA have an associated color map? <code>1</code> indicates
|
||||
* that there is a color map. <code>0</code> indicates no color map.</p>
|
||||
*/
|
||||
private boolean hasColorMap;
|
||||
|
||||
/**
|
||||
* <p>The type of image. See the image type constants in {@link com.realityinteractive.imageio.tga.TGAConstants}
|
||||
* for allowed values.</p>
|
||||
*/
|
||||
private int imageType;
|
||||
|
||||
/**
|
||||
* <p>An image is compressed if its image type is {@link TGAConstants#RLE_COLOR_MAP},
|
||||
* {@link TGAConstants#RLE_TRUE_COLOR}, or {@link TGAConstants#RLE_MONO}.</p>
|
||||
*/
|
||||
private boolean isCompressed;
|
||||
|
||||
/**
|
||||
* <p>The index of the first color map entry.</p>
|
||||
*/
|
||||
private int firstColorMapEntryIndex;
|
||||
|
||||
/**
|
||||
* <p>The total number of color map entries.</p>
|
||||
*/
|
||||
private int numberColorMapEntries;
|
||||
|
||||
/**
|
||||
* <p>The number of bits per color map entry.</p>
|
||||
*/
|
||||
private int bitsPerColorMapEntry;
|
||||
|
||||
/**
|
||||
* <p>The computed size of a color map entry in <code>byte</code>s.</p>
|
||||
*/
|
||||
private int colorMapEntrySize;
|
||||
|
||||
/**
|
||||
* <p>The computed size of the color map field in <code>byte</code>s. This
|
||||
* is determined from the <code>numberColorMapEntries</code> and
|
||||
* <code>colorMapEntrySize</code>.</p>
|
||||
*/
|
||||
private int colorMapSize;
|
||||
|
||||
/**
|
||||
* <p>The horizontal coordinate for the lower-left corner of the image.</p>
|
||||
*/
|
||||
private int xOrigin;
|
||||
|
||||
/**
|
||||
* <p>The vertical coordinate for the lower-left corner of the image.</p>
|
||||
*/
|
||||
private int yOrigin;
|
||||
|
||||
/**
|
||||
* <p>The width of the image in pixels.</p>
|
||||
*/
|
||||
private int width;
|
||||
|
||||
/**
|
||||
* <p>The height of the image in pixels.</p>
|
||||
*/
|
||||
private int height;
|
||||
|
||||
/**
|
||||
* <p>The number of bits per pixel.</p>
|
||||
*/
|
||||
private int bitsPerPixel;
|
||||
|
||||
/**
|
||||
* <p>The number of attribute bits per pixel.</p>
|
||||
*/
|
||||
private int imageDescriptor;
|
||||
|
||||
/**
|
||||
* <p>The horizontal ordering of the pixels as determined from the image
|
||||
* descriptor. By default the order is left to right.</p>
|
||||
*/
|
||||
// NOTE: true -> left-to-right; false -> right-to-left
|
||||
private boolean leftToRight;
|
||||
|
||||
/**
|
||||
* <p>The horizontal ordering of the pixels as determined from the image
|
||||
* descriptor. By default the order is left to right.</p>
|
||||
*/
|
||||
// NOTE: true -> bottom-to-top; false -> top-to-bottom
|
||||
private boolean bottomToTop;
|
||||
|
||||
/**
|
||||
* <p>The offset to the color map data. This value is not defined if there
|
||||
* is no color map (see <code>hasColorMap</code>).</p>
|
||||
*/
|
||||
private int colorMapDataOffset;
|
||||
|
||||
/**
|
||||
* <p>The offset to the pixel data.</p>
|
||||
*/
|
||||
private int pixelDataOffset;
|
||||
|
||||
// =========================================================================
|
||||
/**
|
||||
* <p>Constructs a TGA header that will be populated by setters or directly
|
||||
* (via a static "factory" method).</p>
|
||||
*/
|
||||
public TGAHeader() {}
|
||||
|
||||
/**
|
||||
* <p>Constructs and populates a TGA header from the specified {@link javax.imageio.stream.ImageInputStream}.</p>
|
||||
*
|
||||
* @param inputStream the <code>ImageInputStream</code> 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Reads and populates the header from the specifed {@link javax.imageio.stream.ImageInputStream}.
|
||||
* Any existing values will be over written.</p>
|
||||
*
|
||||
* <p>The <code>ImageInputStream</code> will be changed as a result of this
|
||||
* operation (the offset will be moved).</p>
|
||||
*
|
||||
* @param inputStream the <code>ImageInputStream</code> 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;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>The length of the TGA identifier. This is a <code>byte</code> in
|
||||
* length.</p>
|
||||
*/
|
||||
public int getIdLength()
|
||||
{
|
||||
return idLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Does this TGA have an associated color map?</p>
|
||||
*/
|
||||
public boolean hasColorMap()
|
||||
{
|
||||
return hasColorMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Retrieves the type of image. See the image type constants in {@link com.realityinteractive.imageio.tga.TGAConstants}
|
||||
* for allowed values.</p>
|
||||
*/
|
||||
public int getImageType()
|
||||
{
|
||||
return imageType;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Retrieves a string that represents the image type.</p>
|
||||
*/
|
||||
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";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>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.</p>
|
||||
*/
|
||||
public boolean isCompressed()
|
||||
{
|
||||
return isCompressed;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Retrieves the index of the first color map entry.</p>
|
||||
*/
|
||||
public int getFirstColorMapEntryIndex()
|
||||
{
|
||||
return firstColorMapEntryIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Retrieves ttotal number of color map entries.</p>
|
||||
*/
|
||||
public int getColorMapLength()
|
||||
{
|
||||
return numberColorMapEntries;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Retrieves the number of bits per color map entry.</p>
|
||||
*/
|
||||
public int getBitsPerColorMapEntry()
|
||||
{
|
||||
return bitsPerColorMapEntry;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Retrieves the horizontal coordinate for the lower-left corner of the
|
||||
* image.</p>
|
||||
*/
|
||||
public int getXOrigin()
|
||||
{
|
||||
return xOrigin;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Retrieves the vertical coordinate for the lower-left corner of the image.</p>
|
||||
*/
|
||||
public int getYOrigin()
|
||||
{
|
||||
return yOrigin;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Retrieves the width of the image in pixels.</p>
|
||||
*/
|
||||
public int getWidth()
|
||||
{
|
||||
return width;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Retrieves the height of the image in pixels.</p>
|
||||
*/
|
||||
public int getHeight()
|
||||
{
|
||||
return height;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Retrieves the number of bits per pixel.</p>
|
||||
*/
|
||||
public int getBitsPerPixel()
|
||||
{
|
||||
return bitsPerPixel;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Retrieves the number of samples per pixel.</p>
|
||||
*/
|
||||
public int getSamplesPerPixel()
|
||||
{
|
||||
// FIXME: this is overly simplistic but it is accurate
|
||||
return (bitsPerPixel == 32) ? 4 : 3;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Retrieves the number of attribute bits per pixel.</p>
|
||||
*/
|
||||
public int getImageDescriptor()
|
||||
{
|
||||
return imageDescriptor;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Returns if this image is left-to-right (<code>true</code>) or right-
|
||||
* to-left (<code>false</code>).</p>
|
||||
*/
|
||||
public boolean isLeftToRight()
|
||||
{
|
||||
return leftToRight;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Returns if this image is bottom-to-top (<code>true</code>) or top-to-
|
||||
* bottom (<code>false</code>).</p>
|
||||
*/
|
||||
public boolean isBottomToTop()
|
||||
{
|
||||
return bottomToTop;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Retrieves the offset to the color map data. If there is no color
|
||||
* map ({@link #hasColorMap()} returns <code>false</code>) then this is
|
||||
* undefined.</p>
|
||||
*/
|
||||
public int getColorMapDataOffset()
|
||||
{
|
||||
return colorMapDataOffset;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Retrieves the offset to the pixel data.</p>
|
||||
*/
|
||||
public int getPixelDataOffset()
|
||||
{
|
||||
return pixelDataOffset;
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
/**
|
||||
* <p>Retrieves a string useful for debugging.</p>
|
||||
*
|
||||
* @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
|
||||
*/
|
@@ -0,0 +1,131 @@
|
||||
package com.realityinteractive.imageio.tga;
|
||||
|
||||
/*
|
||||
* TGAImageMetadata.java
|
||||
* Copyright (c) 2003 Reality Interactive, Inc.
|
||||
* See bottom of file for license and warranty information.
|
||||
* Created on Sep 27, 2003
|
||||
*/
|
||||
|
||||
import javax.imageio.metadata.IIOInvalidTreeException;
|
||||
import javax.imageio.metadata.IIOMetadata;
|
||||
import javax.imageio.metadata.IIOMetadataFormat;
|
||||
import javax.imageio.metadata.IIOMetadataNode;
|
||||
|
||||
import org.w3c.dom.Node;
|
||||
|
||||
/**
|
||||
* <p>The image metadata for a TGA image type. At this time there are no
|
||||
* elements in the format (i.e. {@link javax.imageio.metadata.IIOMetadataFormat#canNodeAppear(java.lang.String, javax.imageio.ImageTypeSpecifier)}
|
||||
* always returns <code>false</code>).</p>
|
||||
*
|
||||
* @author Rob Grzywinski <a href="mailto:rgrzywinski@realityinteractive.com">rgrzywinski@realityinteractive.com</a>
|
||||
* @version $Id: TGAImageMetadata.java,v 1.1 2005/04/12 11:23:53 ornedan Exp $
|
||||
* @since 1.0
|
||||
*/
|
||||
// NOTE: this is currently unused
|
||||
public class TGAImageMetadata extends IIOMetadata
|
||||
{
|
||||
// =========================================================================
|
||||
/**
|
||||
* @see javax.imageio.metadata.IIOMetadata#IIOMetadata()
|
||||
*/
|
||||
public TGAImageMetadata()
|
||||
{
|
||||
super(TGAImageReaderSpi.SUPPORTS_STANDARD_IMAGE_METADATA_FORMAT,
|
||||
TGAImageReaderSpi.NATIVE_IMAGE_METADATA_FORMAT_NAME,
|
||||
TGAImageReaderSpi.NATIVE_IMAGE_METADATA_FORMAT_CLASSNAME,
|
||||
TGAImageReaderSpi.EXTRA_IMAGE_METADATA_FORMAT_NAMES,
|
||||
TGAImageReaderSpi.EXTRA_IMAGE_METADATA_FORMAT_CLASSNAMES);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Ensure that the specified format name is supported by this metadata.
|
||||
* If the format is not supported {@link java.lang.IllegalArgumentException}
|
||||
* is thrown.</p>
|
||||
*
|
||||
* @param formatName the name of the metadata format that is to be validated
|
||||
*/
|
||||
private void checkFormatName(final String formatName)
|
||||
{
|
||||
// if the format name is not known, throw an exception
|
||||
if(!TGAImageReaderSpi.NATIVE_IMAGE_METADATA_FORMAT_NAME.equals(formatName))
|
||||
{
|
||||
throw new IllegalArgumentException("Unknown image metadata format name \"" + formatName + "\"."); // FIXME: localize
|
||||
} /* else -- the format name is valid */
|
||||
}
|
||||
|
||||
/**
|
||||
* @see javax.imageio.metadata.IIOMetadata#getAsTree(java.lang.String)
|
||||
*/
|
||||
public Node getAsTree(final String formatName)
|
||||
{
|
||||
// validate the format name (this will throw if invalid)
|
||||
checkFormatName(formatName);
|
||||
|
||||
// create and return a root node
|
||||
// NOTE: there are no children at this time
|
||||
final IIOMetadataNode root = new IIOMetadataNode(TGAImageReaderSpi.NATIVE_IMAGE_METADATA_FORMAT_NAME);
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see javax.imageio.metadata.IIOMetadata#getMetadataFormat(java.lang.String)
|
||||
*/
|
||||
public IIOMetadataFormat getMetadataFormat(final String formatName)
|
||||
{
|
||||
// validate the format name (this will throw if invalid)
|
||||
checkFormatName(formatName);
|
||||
|
||||
// return the metadata format
|
||||
return TGAImageMetadataFormat.getInstance();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>This is read-only metadata.</p>
|
||||
*
|
||||
* @see javax.imageio.metadata.IIOMetadata#isReadOnly()
|
||||
*/
|
||||
public boolean isReadOnly()
|
||||
{
|
||||
// see javadoc
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see javax.imageio.metadata.IIOMetadata#mergeTree(java.lang.String, org.w3c.dom.Node)
|
||||
*/
|
||||
public void mergeTree(final String formatName, final Node root)
|
||||
throws IIOInvalidTreeException
|
||||
{
|
||||
// validate the format name (this will throw if invalid)
|
||||
checkFormatName(formatName);
|
||||
|
||||
// since there are no elements in the tree, there is nothing to merge
|
||||
}
|
||||
|
||||
/**
|
||||
* @see javax.imageio.metadata.IIOMetadata#reset()
|
||||
*/
|
||||
public void reset()
|
||||
{
|
||||
// NOTE: nothing to do since there are no elements
|
||||
}
|
||||
}
|
||||
// =============================================================================
|
||||
/*
|
||||
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
|
||||
*/
|
@@ -0,0 +1,88 @@
|
||||
package com.realityinteractive.imageio.tga;
|
||||
|
||||
/*
|
||||
* TGAImageMetadataFormat.java
|
||||
* Copyright (c) 2003 Reality Interactive, Inc.
|
||||
* See bottom of file for license and warranty information.
|
||||
* Created on Sep 27, 2003
|
||||
*/
|
||||
|
||||
import javax.imageio.ImageTypeSpecifier;
|
||||
import javax.imageio.metadata.IIOMetadataFormatImpl;
|
||||
|
||||
/**
|
||||
* <p>The image metadata format for a TGA image type. At this time there are
|
||||
* no elements in the format (i.e. {@link javax.imageio.metadata.IIOMetadataFormat#canNodeAppear(java.lang.String, javax.imageio.ImageTypeSpecifier)}
|
||||
* always returns <code>false</code>).</p>
|
||||
*
|
||||
* @author Rob Grzywinski <a href="mailto:rgrzywinski@realityinteractive.com">rgrzywinski@realityinteractive.com</a>
|
||||
* @version $Id: TGAImageMetadataFormat.java,v 1.1 2005/04/12 11:23:53 ornedan Exp $
|
||||
* @since 1.0
|
||||
*/
|
||||
// NOTE: this is currently unused
|
||||
public class TGAImageMetadataFormat extends IIOMetadataFormatImpl
|
||||
{
|
||||
/**
|
||||
* <p>The singleton instance of this {@linkjavax.imageio.metadata.IIOMetadataFormat}.
|
||||
* It is created lazily.</p>
|
||||
*/
|
||||
private static TGAImageMetadataFormat instance;
|
||||
|
||||
// =========================================================================
|
||||
/**
|
||||
* <p>A private constructor to enforce the singleton pattern.</p>
|
||||
*/
|
||||
private TGAImageMetadataFormat()
|
||||
{
|
||||
// set the name of the root document node. The child elements may
|
||||
// repeat
|
||||
super(TGAImageReaderSpi.NATIVE_IMAGE_METADATA_FORMAT_NAME,
|
||||
CHILD_POLICY_REPEAT);
|
||||
|
||||
// TODO: add the full metadata
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Retrieves the singleton instance of <code>TGAMetadataformat</code>.
|
||||
* The instance is created lazily.</p>
|
||||
*
|
||||
* @return the singleton instnace
|
||||
*/
|
||||
public static synchronized TGAImageMetadataFormat getInstance()
|
||||
{
|
||||
// if the instance doesn't already exist then create it
|
||||
if(instance == null)
|
||||
{
|
||||
instance = new TGAImageMetadataFormat();
|
||||
} /* else -- there is a singleton instance */
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
/**
|
||||
* @see javax.imageio.metadata.IIOMetadataFormat#canNodeAppear(java.lang.String, javax.imageio.ImageTypeSpecifier)
|
||||
*/
|
||||
public boolean canNodeAppear(final String elementName,
|
||||
final ImageTypeSpecifier imageType)
|
||||
{
|
||||
// NOTE: since there are no elements, none are allowed
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// =============================================================================
|
||||
/*
|
||||
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
|
||||
*/
|
@@ -0,0 +1,648 @@
|
||||
package com.realityinteractive.imageio.tga;
|
||||
|
||||
/*
|
||||
* TGAImageReader.java
|
||||
* Copyright (c) 2003 Reality Interactive, Inc.
|
||||
* See bottom of file for license and warranty information.
|
||||
* Created on Sep 26, 2003
|
||||
*/
|
||||
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.color.ColorSpace;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.DataBuffer;
|
||||
import java.awt.image.DataBufferInt;
|
||||
import java.awt.image.WritableRaster;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import javax.imageio.ImageReadParam;
|
||||
import javax.imageio.ImageReader;
|
||||
import javax.imageio.ImageTypeSpecifier;
|
||||
import javax.imageio.metadata.IIOMetadata;
|
||||
import javax.imageio.spi.ImageReaderSpi;
|
||||
import javax.imageio.stream.ImageInputStream;
|
||||
|
||||
/**
|
||||
* <p>The {@link javax.imageio.ImageReader} that exposes the TGA image reading.
|
||||
* 8, 15, 16, 24 and 32 bit true color or color mapped (RLE compressed or
|
||||
* uncompressed) are supported. Monochrome images are not supported.</p>
|
||||
*
|
||||
* <p>Great care should be employed with {@link javax.imageio.ImageReadParam}s.
|
||||
* Little to no effort has been made to correctly handle sub-sampling or
|
||||
* specified bands.</p>
|
||||
*
|
||||
* <p>{@link javax.imageio.ImageIO#setUseCache(boolean)} should be set to <code>false</code>
|
||||
* when using this reader. Also, {@link javax.imageio.ImageIO#read(java.io.InputStream)}
|
||||
* is the preferred read method if used against a buffered array (for performance
|
||||
* reasons).</p>
|
||||
*
|
||||
* @author Rob Grzywinski <a href="mailto:rgrzywinski@realityinteractive.com">rgrzywinski@realityinteractive.com</a>
|
||||
* @version $Id: TGAImageReader.java,v 1.1 2005/04/12 11:23:53 ornedan Exp $
|
||||
* @since 1.0
|
||||
*/
|
||||
// TODO: incorporate the x and y origins
|
||||
public class TGAImageReader extends ImageReader
|
||||
{
|
||||
/**
|
||||
* <p>The {@link javax.imageio.stream.ImageInputStream} from which the TGA
|
||||
* is read. This may be <code>null</code> if {@link javax.imageio.ImageReader#setInput(java.lang.Object)}
|
||||
* (or the other forms of <code>setInput()</code>) has not been called. The
|
||||
* stream will be set litle-endian when it is set.</p>
|
||||
*/
|
||||
private ImageInputStream inputStream;
|
||||
|
||||
/**
|
||||
* <p>The {@link com.realityinteractive.imageio.tga.TGAHeader}. If <code>null</code>
|
||||
* then the header has not been read since <code>inputStream</code> was
|
||||
* last set. This is created lazily.</p>
|
||||
*/
|
||||
private TGAHeader header;
|
||||
|
||||
// =========================================================================
|
||||
/**
|
||||
* @see javax.imageio.ImageReader#ImageReader(javax.imageio.spi.ImageReaderSpi)
|
||||
*/
|
||||
public TGAImageReader(final ImageReaderSpi originatingProvider)
|
||||
{
|
||||
super(originatingProvider);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Store the input if it is an {@link javax.imageio.stream.ImageInputStream}.
|
||||
* Otherwise {@link java.lang.IllegalArgumentException} is thrown. The
|
||||
* stream is set to little-endian byte ordering.</p>
|
||||
*
|
||||
* @see javax.imageio.ImageReader#setInput(java.lang.Object, boolean, boolean)
|
||||
*/
|
||||
// NOTE: can't read the header in here as there would be no place for
|
||||
// exceptions to go. It must be read lazily.
|
||||
public void setInput(final Object input, final boolean seekForwardOnly,
|
||||
final boolean ignoreMetadata)
|
||||
{
|
||||
// delegate to the partent
|
||||
super.setInput(input, seekForwardOnly, ignoreMetadata);
|
||||
|
||||
// if the input is null clear the inputStream and header
|
||||
if(input == null)
|
||||
{
|
||||
inputStream = null;
|
||||
header = null;
|
||||
} /* else -- the input is non-null */
|
||||
|
||||
// only ImageInputStream are allowed. If other throw IllegalArgumentException
|
||||
if(input instanceof ImageInputStream)
|
||||
{
|
||||
// set the inputStream
|
||||
inputStream = (ImageInputStream)input;
|
||||
|
||||
// put the ImageInputStream into little-endian ("Intel byte ordering")
|
||||
// byte ordering
|
||||
inputStream.setByteOrder(ByteOrder.LITTLE_ENDIAN);
|
||||
|
||||
} else /* input is not an instance of ImageInputStream */
|
||||
{
|
||||
throw new IllegalArgumentException("Only ImageInputStreams are accepted."); // FIXME: localize
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Create and read the {@link com.realityinteractive.imageio.tga.TGAHeader}
|
||||
* only if there is not one already.</p>
|
||||
*
|
||||
* @return the <code>TGAHeader</code> (for convenience)
|
||||
* @throws IOException if there is an I/O error while reading the header
|
||||
*/
|
||||
private synchronized TGAHeader getHeader()
|
||||
throws IOException
|
||||
{
|
||||
// if there is already a header (non-null) then there is nothing to be
|
||||
// done
|
||||
if(header != null)
|
||||
return header;
|
||||
/* else -- there is no header */
|
||||
|
||||
// ensure that there is an ImageInputStream from which the header is
|
||||
// read
|
||||
if(inputStream == null)
|
||||
throw new IllegalStateException("There is no ImageInputStream from which the header can be read."); // FIXME: localize
|
||||
/* else -- there is an input stream */
|
||||
|
||||
header = new TGAHeader(inputStream);
|
||||
|
||||
return header;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Only a single image can be read by this reader. Validate the
|
||||
* specified image index and if not <code>0</code> then {@link java.lang.IndexOutOfBoundsException}
|
||||
* is thrown.</p>
|
||||
*
|
||||
* @param imageIndex the index of the image to validate
|
||||
* @throws IndexOutOfBoundsException if the <code>imageIndex</code> is not
|
||||
* <code>0</code>
|
||||
*/
|
||||
private void checkImageIndex(final int imageIndex)
|
||||
{
|
||||
// if the imageIndex is not 0 then throw an exception
|
||||
if(imageIndex != 0)
|
||||
throw new IndexOutOfBoundsException("Image index out of bounds (" + imageIndex + " != 0)."); // FIXME: localize
|
||||
/* else -- the index is in bounds */
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// Required ImageReader methods
|
||||
/**
|
||||
* @see javax.imageio.ImageReader#getImageTypes(int)
|
||||
*/
|
||||
public Iterator/*<ImageTypeSpecifier>*/ getImageTypes(final int imageIndex)
|
||||
throws IOException
|
||||
{
|
||||
// validate the imageIndex (this will throw if invalid)
|
||||
checkImageIndex(imageIndex);
|
||||
|
||||
// read / get the header
|
||||
final TGAHeader header = getHeader();
|
||||
|
||||
// get the ImageTypeSpecifier for the image type
|
||||
// FIXME: finish
|
||||
final ImageTypeSpecifier imageTypeSpecifier;
|
||||
switch(header.getImageType())
|
||||
{
|
||||
case TGAConstants.COLOR_MAP:
|
||||
case TGAConstants.RLE_COLOR_MAP:
|
||||
case TGAConstants.TRUE_COLOR:
|
||||
case TGAConstants.RLE_TRUE_COLOR:
|
||||
{
|
||||
// determine if there is an alpha mask based on the number of
|
||||
// samples per pixel
|
||||
final int alphaMask;
|
||||
if(header.getSamplesPerPixel() == 4)
|
||||
alphaMask = 0xFF000000;
|
||||
else /* no alpha channel (less than 32 bits or 4 samples) */
|
||||
alphaMask = 0;
|
||||
|
||||
// packed RGB(A) pixel data (more specifically (A)BGR)
|
||||
// TODO: split on 16, 24, and 32 bit images otherwise there
|
||||
// will be wasted space
|
||||
final ColorSpace rgb = ColorSpace.getInstance(ColorSpace.CS_sRGB);
|
||||
imageTypeSpecifier = ImageTypeSpecifier.createPacked(rgb,
|
||||
0x000000FF,
|
||||
0x0000FF00,
|
||||
0x00FF0000,
|
||||
alphaMask,
|
||||
DataBuffer.TYPE_INT,
|
||||
false /*not pre-multiplied by an alpha*/);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case TGAConstants.MONO:
|
||||
case TGAConstants.RLE_MONO:
|
||||
throw new IllegalArgumentException("Monochrome image type not supported.");
|
||||
|
||||
case TGAConstants.NO_IMAGE:
|
||||
default:
|
||||
throw new IllegalArgumentException("The image type is not known."); // FIXME: localize
|
||||
}
|
||||
|
||||
// create a list and add the ImageTypeSpecifier to it
|
||||
final List/*<ImageTypeSpecifier>*/ imageSpecifiers = new ArrayList/*<ImageTypeSpecifier>*/();
|
||||
imageSpecifiers.add(imageTypeSpecifier);
|
||||
|
||||
return imageSpecifiers.iterator();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Only a single image is supported.</p>
|
||||
*
|
||||
* @see javax.imageio.ImageReader#getNumImages(boolean)
|
||||
*/
|
||||
public int getNumImages(final boolean allowSearch)
|
||||
throws IOException
|
||||
{
|
||||
// see javadoc
|
||||
// NOTE: 1 is returned regardless if a search is allowed or not
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>There is no stream metadata (i.e. <code>null</code> is returned).</p>
|
||||
*
|
||||
* @see javax.imageio.ImageReader#getStreamMetadata()
|
||||
*/
|
||||
public IIOMetadata getStreamMetadata()
|
||||
throws IOException
|
||||
{
|
||||
// see javadoc
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>There is no image metadata (i.e. <code>null</code> is returned).</p>
|
||||
*
|
||||
* @see javax.imageio.ImageReader#getImageMetadata(int)
|
||||
*/
|
||||
public IIOMetadata getImageMetadata(final int imageIndex)
|
||||
throws IOException
|
||||
{
|
||||
// see javadoc
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see javax.imageio.ImageReader#getHeight(int)
|
||||
*/
|
||||
public int getHeight(final int imageIndex)
|
||||
throws IOException
|
||||
{
|
||||
// validate the imageIndex (this will throw if invalid)
|
||||
checkImageIndex(imageIndex);
|
||||
|
||||
// get the header and return the height
|
||||
return getHeader().getHeight();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see javax.imageio.ImageReader#getWidth(int)
|
||||
*/
|
||||
public int getWidth(final int imageIndex)
|
||||
throws IOException
|
||||
{
|
||||
// validate the imageIndex (this will throw if invalid)
|
||||
checkImageIndex(imageIndex);
|
||||
|
||||
// get the header and return the width
|
||||
return getHeader().getHeight();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see javax.imageio.ImageReader#read(int, javax.imageio.ImageReadParam)
|
||||
*/
|
||||
public BufferedImage read(final int imageIndex, final ImageReadParam param)
|
||||
throws IOException
|
||||
{
|
||||
// ensure that the image is of a supported type
|
||||
// NOTE: this will implicitly ensure that the imageIndex is valid
|
||||
final Iterator imageTypes = getImageTypes(imageIndex);
|
||||
if(!imageTypes.hasNext())
|
||||
{
|
||||
throw new IOException("Unsupported Image Type");
|
||||
}
|
||||
|
||||
// read and get the header
|
||||
final TGAHeader header = getHeader();
|
||||
|
||||
// ensure that the ImageReadParam hasn't been set to other than the
|
||||
// defaults (this will throw if not acceptible)
|
||||
checkImageReadParam(param, header);
|
||||
|
||||
// get the height and width from the header for convenience
|
||||
final int width = header.getWidth();
|
||||
final int height = header.getHeight();
|
||||
|
||||
// read the color map data. If the image does not contain a color map
|
||||
// then null will be returned.
|
||||
final int[] colorMap = readColorMap(header);
|
||||
|
||||
// seek to the pixel data offset
|
||||
// TODO: read the color map
|
||||
inputStream.seek(header.getPixelDataOffset());
|
||||
|
||||
// get the destination image and WritableRaster for the image type and
|
||||
// size
|
||||
final BufferedImage image = getDestination(param, imageTypes,
|
||||
width, height);
|
||||
final WritableRaster imageRaster = image.getRaster();
|
||||
|
||||
// get and validate the number of image bands
|
||||
final int numberOfImageBands = image.getSampleModel().getNumBands();
|
||||
checkReadParamBandSettings(param, header.getSamplesPerPixel(),
|
||||
numberOfImageBands);
|
||||
|
||||
// get the destination bands
|
||||
final int[] destinationBands;
|
||||
if(param != null)
|
||||
{
|
||||
// there is an ImageReadParam -- use its destination bands
|
||||
destinationBands = param.getDestinationBands();
|
||||
} else
|
||||
{
|
||||
// there are no destination bands
|
||||
destinationBands = null;
|
||||
}
|
||||
|
||||
// create the destination WritableRaster
|
||||
final WritableRaster raster = imageRaster.createWritableChild(0, 0,
|
||||
width,
|
||||
height,
|
||||
0, 0,
|
||||
destinationBands);
|
||||
|
||||
// set up to read the data
|
||||
final int[] intData = ((DataBufferInt)raster.getDataBuffer()).getData(); // CHECK: is this valid / acceptible?
|
||||
int index = 0; // the index in the intData array
|
||||
int runLength = 0; // the number of pixels in a run length
|
||||
boolean readPixel = true; // if true then a raw pixel is read. Used by the RLE.
|
||||
boolean isRaw = false; // if true then the next pixels should be read. Used by the RLE.
|
||||
int pixel = 0; // the current pixel data
|
||||
|
||||
// TODO: break out the case of 32 bit non-RLE as it can be read
|
||||
// directly and 24 bit non-RLE as it can be read simply. If
|
||||
// subsampling and ROI's are implemented then selection must be
|
||||
// done per pixel for RLE otherwise it's possible to miss the
|
||||
// repetition count field.
|
||||
|
||||
// TODO: account for TGAHeader.firstColorMapEntryIndex
|
||||
|
||||
// loop over the rows
|
||||
// TODO: this should be destinationROI.height (right?)
|
||||
for(int y=0; y<height; y++)
|
||||
{
|
||||
// if the image is flipped top-to-bottom then set the index in
|
||||
// intData appropriately
|
||||
if(header.isBottomToTop())
|
||||
//index = y;
|
||||
index = (height - y) - 1;
|
||||
else /* is top-to-bottom */
|
||||
index = y;
|
||||
//index = (height - y) - 1;
|
||||
|
||||
// account for the width
|
||||
// TODO: this doesn't take into account the destination size or bands
|
||||
index *= width;
|
||||
|
||||
// loop over the columns
|
||||
// TODO: this should be destinationROI.width (right?)
|
||||
// NOTE: *if* destinations are used the RLE will break as this will
|
||||
// cause the repetition count field to be missed.
|
||||
for(int x=0; x<width; x++)
|
||||
{
|
||||
// if the image is compressed (run length encoded) then determine
|
||||
// if a pixel should be read or if the current one should be
|
||||
// used (using the current one is part of the RLE'ing).
|
||||
if(header.isCompressed())
|
||||
{
|
||||
// if there is a non-zero run length then there are still
|
||||
// compressed pixels
|
||||
if(runLength > 0)
|
||||
{
|
||||
// decrement the run length and flag that a pixel should
|
||||
// not be read
|
||||
// NOTE: a pixel is only read from the input if the
|
||||
// packet was raw. If it was a run length packet
|
||||
// then the previous (current) pixel is used.
|
||||
runLength--;
|
||||
readPixel = isRaw;
|
||||
} else /* non-positive run length */
|
||||
{
|
||||
// read the repetition count field
|
||||
runLength = inputStream.readByte() & 0xFF; // unsigned
|
||||
|
||||
// determine which packet type: raw or runlength
|
||||
isRaw = ( (runLength & 0x80) == 0); // bit 7 == 0 -> raw; bit 7 == 1 -> runlength
|
||||
|
||||
// if a run length packet then shift to get the number
|
||||
if(!isRaw)
|
||||
runLength -= 0x80;
|
||||
/* else -- is raw so there's no need to shift */
|
||||
|
||||
// the next field is always read (it's the pixel data)
|
||||
readPixel = true;
|
||||
}
|
||||
}
|
||||
|
||||
// read the next pixel
|
||||
// NOTE: only don't read when in a run length packet
|
||||
if(readPixel)
|
||||
{
|
||||
// NOTE: the alpha must hav a default value since it is
|
||||
// not guaranteed to be present for each pixel read
|
||||
int red = 0, green = 0, blue = 0, alpha = 0xFF;
|
||||
|
||||
// read based on the number of bits per pixel
|
||||
switch(header.getBitsPerPixel())
|
||||
{
|
||||
// grey scale (R = G = B)
|
||||
case 8:
|
||||
default:
|
||||
{
|
||||
// read the data -- it is either the color map index
|
||||
// or the color for each pixel
|
||||
final int data = inputStream.readByte() & 0xFF; // unsigned
|
||||
|
||||
// if the image is a color mapped image then the
|
||||
// resulting pixel is pulled from the color map,
|
||||
// otherwise each pixel gets the data
|
||||
if(header.hasColorMap())
|
||||
{
|
||||
// the pixel is pulled from the color map
|
||||
// CHECK: do sanity bounds check?
|
||||
pixel = colorMap[data];
|
||||
} else /* no color map */
|
||||
{
|
||||
// each color component is set to the color
|
||||
red = green = blue = data;
|
||||
|
||||
// combine each component into the result
|
||||
pixel = (red << 0) | (green << 8) | (blue << 16);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// 5-5-5 (RGB)
|
||||
case 15:
|
||||
case 16:
|
||||
{
|
||||
// read the two bytes
|
||||
final int data = inputStream.readShort() & 0xFFFF; // unsigned
|
||||
|
||||
// get each color component -- each is 5 bits
|
||||
red = ((data >> 10) & 0x1F) << 3;
|
||||
green = ((data >> 5) & 0x1F) << 3;
|
||||
blue = (data & 0x1F) << 3;
|
||||
|
||||
// combine each component into the result
|
||||
pixel = (red << 0) | (green << 8) | (blue << 16);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// true color RGB(A) (8 bits per pixel)
|
||||
case 24:
|
||||
case 32:
|
||||
// read each color component -- the alpha is only
|
||||
// read if there are 32 bits per pixel
|
||||
blue = inputStream.readByte() & 0xFF; // unsigned
|
||||
green = inputStream.readByte() & 0xFF; // unsigned
|
||||
red = inputStream.readByte() & 0xFF; // unsigned
|
||||
if(header.getBitsPerPixel() == 32)
|
||||
alpha = (inputStream.readByte() & 0xFF); // unsigned
|
||||
/* else -- 24 bits per pixel (i.e. no alpha) */
|
||||
|
||||
// combine each component into the result
|
||||
pixel = (red << 0) | (green << 8) | (blue << 16) | (alpha << 24);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// put the pixel in the data array
|
||||
intData[index] = pixel;
|
||||
|
||||
// advance to the next pixel
|
||||
// TODO: the right-to-left switch
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Reads and returns an array of color mapped values. If the image does
|
||||
* not contain a color map <code>null</code> will be returned</p>
|
||||
*
|
||||
* @param header the <code>TGAHeader</code> for the image
|
||||
* @return the array of <code>int</code> color map values or <code>null</code>
|
||||
* if the image does not contain a color map
|
||||
* @throws IOException if there is an I/O error while reading the color map
|
||||
*/
|
||||
private int[] readColorMap(final TGAHeader header)
|
||||
throws IOException
|
||||
{
|
||||
// determine if the image contains a color map. If not, return null
|
||||
if(!header.hasColorMap())
|
||||
return null;
|
||||
/* else -- there is a color map */
|
||||
|
||||
// seek to the start of the color map in the input stream
|
||||
inputStream.seek(header.getColorMapDataOffset());
|
||||
|
||||
// get the number of colros in the color map and the number of bits
|
||||
// per color map entry
|
||||
final int numberOfColors = header.getColorMapLength();
|
||||
final int bitsPerEntry = header.getBitsPerColorMapEntry();
|
||||
|
||||
// create the array that will contain the color map data
|
||||
// CHECK: why is tge explicit +1 needed here ?!?
|
||||
final int[] colorMap = new int[numberOfColors + 1];
|
||||
|
||||
// read each color map entry
|
||||
for(int i=0; i<numberOfColors; i++)
|
||||
{
|
||||
int red = 0, green = 0, blue = 0;
|
||||
|
||||
// read based on the number of bits per color map entry
|
||||
switch(bitsPerEntry)
|
||||
{
|
||||
// grey scale (R = G = B)
|
||||
case 8:
|
||||
default:
|
||||
{
|
||||
final int data = inputStream.readByte() & 0xFF; // unsigned
|
||||
red = green = blue = data;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// 5-5-5 (RGB)
|
||||
case 15:
|
||||
case 16:
|
||||
{
|
||||
// read the two bytes
|
||||
final int data = inputStream.readShort() & 0xFFFF; // unsigned
|
||||
|
||||
// get each color component -- each is 5 bits
|
||||
red = ((data >> 10) & 0x1F) << 3;
|
||||
green = ((data >> 5) & 0x1F) << 3;
|
||||
blue = (data & 0x1F) << 3;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// true color RGB(A) (8 bits per pixel)
|
||||
case 24:
|
||||
case 32:
|
||||
// read each color component
|
||||
// CHECK: is there an alpha?!?
|
||||
blue = inputStream.readByte() & 0xFF; // unsigned
|
||||
green = inputStream.readByte() & 0xFF; // unsigned
|
||||
red = inputStream.readByte() & 0xFF; // unsigned
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// combine each component into the result
|
||||
colorMap[i] = (red << 0) | (green << 8) | (blue << 16);
|
||||
}
|
||||
|
||||
return colorMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Validate that the specified {@link javax.imageio.ImageReadParam}
|
||||
* contains only the default values. If non-default values are present,
|
||||
* {@link java.io.IOException} is thrown.</p>
|
||||
*
|
||||
* @param param the <code>ImageReadParam</code> to be validated
|
||||
* @param head the <code>TGAHeader</code> that contains information about
|
||||
* the source image
|
||||
* @throws IOException if the <code>ImageReadParam</code> contains non-default
|
||||
* values
|
||||
*/
|
||||
private void checkImageReadParam(final ImageReadParam param,
|
||||
final TGAHeader header)
|
||||
throws IOException
|
||||
{
|
||||
if(param != null)
|
||||
{
|
||||
// get the image height and width from the header for convenience
|
||||
final int width = header.getWidth();
|
||||
final int height = header.getHeight();
|
||||
|
||||
// ensure that the param contains only the defaults
|
||||
final Rectangle sourceROI = param.getSourceRegion();
|
||||
if( (sourceROI != null) &&
|
||||
( (sourceROI.x != 0) || (sourceROI.y != 0) ||
|
||||
(sourceROI.width != width) || (sourceROI.height != height) ) )
|
||||
{
|
||||
throw new IOException("The source region of interest is not the default."); // FIXME: localize
|
||||
} /* else -- the source ROI is the default */
|
||||
|
||||
final Rectangle destinationROI = param.getSourceRegion();
|
||||
if( (destinationROI != null) &&
|
||||
( (destinationROI.x != 0) || (destinationROI.y != 0) ||
|
||||
(destinationROI.width != width) || (destinationROI.height != height) ) )
|
||||
{
|
||||
throw new IOException("The destination region of interest is not the default."); // FIXME: localize
|
||||
} /* else -- the destination ROI is the default */
|
||||
|
||||
if( (param.getSourceXSubsampling() != 1) ||
|
||||
(param.getSourceYSubsampling() != 1) )
|
||||
{
|
||||
throw new IOException("Source sub-sampling is not supported."); // FIXME: localize
|
||||
} /* else -- sub-sampling is the default */
|
||||
} /* else -- the ImageReadParam is null so the defaults *are* used */
|
||||
}
|
||||
}
|
||||
// =============================================================================
|
||||
/*
|
||||
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
|
||||
*/
|
@@ -0,0 +1,227 @@
|
||||
package com.realityinteractive.imageio.tga;
|
||||
|
||||
/*
|
||||
* TGAImageReaderSpi.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 java.util.Locale;
|
||||
|
||||
import javax.imageio.ImageReader;
|
||||
import javax.imageio.spi.ImageReaderSpi;
|
||||
import javax.imageio.stream.ImageInputStream;
|
||||
|
||||
/**
|
||||
* <p>A service provider for reading TGA images. Only {@link javax.imageio.stream.ImageInputStream}
|
||||
* input types are allowed. See {@link com.realityinteractive.imageio.tga.TGAImageReader}
|
||||
* for supported features.</p>
|
||||
*
|
||||
* @author Rob Grzywinski <a href="mailto:rgrzywinski@realityinteractive.com">rgrzywinski@realityinteractive.com</a>
|
||||
* @version $Id: TGAImageReaderSpi.java,v 1.1 2005/04/12 11:23:53 ornedan Exp $
|
||||
* @since 1.0
|
||||
*/
|
||||
public class TGAImageReaderSpi extends ImageReaderSpi
|
||||
{
|
||||
// =========================================================================
|
||||
// NOTE: these should be package (default protected) as it is used
|
||||
// frequently elsewhere
|
||||
/**
|
||||
* <p>The vendor name: Reality Interactive, Inc.</p>
|
||||
*/
|
||||
static final String VENDOR_NAME = "Reality Interactive, Inc.";
|
||||
|
||||
/**
|
||||
* <p>The plugin version number.</p>
|
||||
*/
|
||||
static final String VERSION = "1.00";
|
||||
|
||||
/**
|
||||
* <p>The class name for the TGA image reader.</p>
|
||||
*/
|
||||
static final String READER_CLASSNAME =
|
||||
"com.realityinteractive.imageio.tga.TGAImageReader";
|
||||
|
||||
/**
|
||||
* <p>The format names.</p>
|
||||
*/
|
||||
static final String[] FORMAT_NAMES = { "tga", "targa" };
|
||||
|
||||
/**
|
||||
* <p>The canonical suffix names.</p>
|
||||
*/
|
||||
static final String[] SUFFIXES = { "tga", "targa" };
|
||||
|
||||
/**
|
||||
* <p>The supported mime types.</p>
|
||||
*/
|
||||
static final String[] MIME_TYPES =
|
||||
{ "application/tga", "application/x-tga", "application/x-targa",
|
||||
"image/tga", "image/x-tga", "image/targa", "image/x-targa" };
|
||||
|
||||
/**
|
||||
* <p>This is a read-only TGA plugin.</p>
|
||||
*/
|
||||
static final String[] WRITER_SPI_CLASSNAMES = null;
|
||||
|
||||
/**
|
||||
* <p>The standard stream metadata format is not supported.</p>
|
||||
*/
|
||||
static final boolean SUPPORTS_STANDARD_STREAM_METADATA_FORMAT = false;
|
||||
|
||||
/**
|
||||
* <p>There is no "native" stream metadata formats supported by the TGA
|
||||
* plugin.</p>
|
||||
*/
|
||||
static final String NATIVE_STREAM_METADATA_FORMAT_NAME = null;
|
||||
|
||||
/**
|
||||
* <p>There is no "native" stream metadata formats supported by the TGA
|
||||
* plugin.</p>
|
||||
*/
|
||||
static final String NATIVE_STREAM_METADATA_FORMAT_CLASSNAME = null;
|
||||
|
||||
/**
|
||||
* <p>There are no stream metadata formats other than the standard.</p>
|
||||
*/
|
||||
static final String[] EXTRA_STREAM_METADATA_FORMAT_NAMES = null;
|
||||
|
||||
/**
|
||||
* <p>There are no stream metadata formats other than the standard.</p>
|
||||
*/
|
||||
static final String[] EXTRA_STREAM_METADATA_FORMAT_CLASSNAMES = null;
|
||||
|
||||
/**
|
||||
* <p>The standard image metadata format is not supported.</p>
|
||||
*/
|
||||
static final boolean SUPPORTS_STANDARD_IMAGE_METADATA_FORMAT = false;
|
||||
|
||||
/**
|
||||
* <p>There are no "native" image metadata formats supported by the TGA
|
||||
* plugin.</p>
|
||||
*/
|
||||
static final String NATIVE_IMAGE_METADATA_FORMAT_NAME = null;
|
||||
|
||||
/**
|
||||
* <p>There are no "native" image metadata formats supported by the TGA
|
||||
* plugin.</p>
|
||||
*/
|
||||
static final String NATIVE_IMAGE_METADATA_FORMAT_CLASSNAME = null;
|
||||
|
||||
/**
|
||||
* <p>There are no image metadata formats supported other than the standard.</p>
|
||||
*/
|
||||
static final String[] EXTRA_IMAGE_METADATA_FORMAT_NAMES = null;
|
||||
|
||||
/**
|
||||
* <p>There are no image metadata formats supported other than the standard.</p>
|
||||
*/
|
||||
static final String[] EXTRA_IMAGE_METADATA_FORMAT_CLASSNAMES = null;
|
||||
|
||||
// =========================================================================
|
||||
/**
|
||||
* <p>Constructs an {@link javax.imageio.spi.ImageReaderSpi} that accepts
|
||||
* {@link javax.imageio.stream.ImageInputStream} as its input type.</p>
|
||||
*
|
||||
* @see javax.imageio.spi.ImageReaderSpi#ImageReaderSpi()
|
||||
*/
|
||||
public TGAImageReaderSpi()
|
||||
{
|
||||
super(VENDOR_NAME, VERSION, FORMAT_NAMES, SUFFIXES, MIME_TYPES,
|
||||
READER_CLASSNAME,
|
||||
ImageReaderSpi.STANDARD_INPUT_TYPE,
|
||||
WRITER_SPI_CLASSNAMES,
|
||||
SUPPORTS_STANDARD_STREAM_METADATA_FORMAT,
|
||||
NATIVE_STREAM_METADATA_FORMAT_NAME,
|
||||
NATIVE_STREAM_METADATA_FORMAT_CLASSNAME,
|
||||
EXTRA_STREAM_METADATA_FORMAT_NAMES,
|
||||
EXTRA_STREAM_METADATA_FORMAT_CLASSNAMES,
|
||||
SUPPORTS_STANDARD_IMAGE_METADATA_FORMAT,
|
||||
NATIVE_IMAGE_METADATA_FORMAT_NAME,
|
||||
NATIVE_IMAGE_METADATA_FORMAT_CLASSNAME,
|
||||
EXTRA_IMAGE_METADATA_FORMAT_NAMES,
|
||||
EXTRA_IMAGE_METADATA_FORMAT_CLASSNAMES);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see javax.imageio.spi.ImageReaderSpi#canDecodeInput(java.lang.Object)
|
||||
*/
|
||||
public boolean canDecodeInput(final Object source)
|
||||
throws IOException
|
||||
{
|
||||
// NOTE: the input source must be left in the same state as it started
|
||||
// at (mark() and reset() should be used on ImageInputStream)
|
||||
|
||||
// ensure that the input type is a ImageInputStream as that is all that
|
||||
// is supported
|
||||
if(!(source instanceof ImageInputStream))
|
||||
return false;
|
||||
/* else -- source is a ImageInputStream */
|
||||
|
||||
// cast to ImageInputStream for convenience
|
||||
final ImageInputStream inputStream = (ImageInputStream)source;
|
||||
|
||||
try
|
||||
{
|
||||
// set a mark at the current position so that the stream can be reset
|
||||
inputStream.mark();
|
||||
|
||||
// there's no ideidentifiable header on a TGA file so a punt must
|
||||
// occur. This will attempt to read the image type and if it is
|
||||
// not known or allowed then false is returned.
|
||||
// NOTE: 1.0.0 only supports un/compressed true color
|
||||
inputStream.readUnsignedByte(); // idLength
|
||||
inputStream.readUnsignedByte(); // has color map
|
||||
final int imageType = inputStream.readUnsignedByte();
|
||||
if( (imageType != TGAConstants.TRUE_COLOR) &&
|
||||
(imageType != TGAConstants.RLE_TRUE_COLOR) &&
|
||||
(imageType != TGAConstants.COLOR_MAP) &&
|
||||
(imageType != TGAConstants.RLE_COLOR_MAP) )
|
||||
{
|
||||
return false;
|
||||
} /* else -- it's *possible* (though not known) that this is a TGA */
|
||||
|
||||
return true;
|
||||
} finally
|
||||
{
|
||||
// reset so that the ImageInputStream is put back where it was
|
||||
inputStream.reset();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see javax.imageio.spi.ImageReaderSpi#createReaderInstance(java.lang.Object)
|
||||
*/
|
||||
public ImageReader createReaderInstance(final Object extension)
|
||||
throws IOException
|
||||
{
|
||||
// construct and return an ImageReader using this SPI
|
||||
return new TGAImageReader(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see javax.imageio.spi.IIOServiceProvider#getDescription(java.util.Locale)
|
||||
*/
|
||||
public String getDescription(final Locale locale)
|
||||
{
|
||||
return "TGA"; // FIXME: localize
|
||||
}
|
||||
}
|
||||
// =============================================================================
|
||||
/*
|
||||
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
|
||||
*/
|
Reference in New Issue
Block a user