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; /** *
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.
* *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.
* *{@link javax.imageio.ImageIO#setUseCache(boolean)} should be set to false
* 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).
The {@link javax.imageio.stream.ImageInputStream} from which the TGA
* is read. This may be null
if {@link javax.imageio.ImageReader#setInput(java.lang.Object)}
* (or the other forms of setInput()
) has not been called. The
* stream will be set litle-endian when it is set.
The {@link com.realityinteractive.imageio.tga.TGAHeader}. If null
* then the header has not been read since inputStream
was
* last set. This is created lazily.
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.
* * @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 } } /** *Create and read the {@link com.realityinteractive.imageio.tga.TGAHeader} * only if there is not one already.
* * @return theTGAHeader
(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;
}
/**
* Only a single image can be read by this reader. Validate the
* specified image index and if not 0
then {@link java.lang.IndexOutOfBoundsException}
* is thrown.
imageIndex
is not
* 0
*/
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/*Only a single image is supported.
* * @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; } /** *There is no stream metadata (i.e. null
is returned).
There is no image metadata (i.e. null
is returned).
Reads and returns an array of color mapped values. If the image does
* not contain a color map null
will be returned
TGAHeader
for the image
* @return the array of int
color map values or null
* 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; iValidate that the specified {@link javax.imageio.ImageReadParam} * contains only the default values. If non-default values are present, * {@link java.io.IOException} is thrown.
* * @param param theImageReadParam
to be validated
* @param head the TGAHeader
that contains information about
* the source image
* @throws IOException if the ImageReadParam
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
*/