/* * Copyright (c) 2003-2005 Sun Microsystems, Inc. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * - Redistribution of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistribution in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of Sun Microsystems, Inc. or the names of * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * This software is provided "AS IS," without a warranty of any kind. ALL * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. * * You acknowledge that this software is not designed or intended for use * in the design, construction, operation or maintenance of any nuclear * facility. * * Sun gratefully acknowledges that this software was originally authored * and developed by Kenneth Bradley Russell and Christopher John Kline. */ package com.sun.opengl.util.texture.spi; import java.io.*; import java.nio.*; import java.nio.channels.*; import javax.media.opengl.*; import com.sun.opengl.util.*; import com.sun.opengl.util.texture.spi.*; import com.sun.opengl.util.texture.*; /** * Targa image reader and writer adapted from sources of the Jimi image I/O class library. * *

* * Image decoder for image data stored in TGA file format. * Currently only the original TGA file format is supported. This is * because the new TGA format has data at the end of the file, getting * to the end of a file in an InputStream orient environment presents * several difficulties which are avoided at the moment. * *

* * This is a simple decoder and is only setup to load a single image * from the input stream * *

* * @author Robin Luiten * @author Kenneth Russell * @version $Revision$ */ public class TGAImage { private Header header; private int format; private int bpp; private ByteBuffer data; private TGAImage(Header header) { this.header = header; } /** * This class reads in all of the TGA image header in addition it also * reads in the imageID field as it is convenient to handle that here. * * @author Robin Luiten * @version 1.1 */ public static class Header { /** Set of possible file format TGA types */ public final static int TYPE_NEW = 0; public final static int TYPE_OLD = 1; public final static int TYPE_UNK = 2; // cant rewind stream so unknown for now. /** Set of possible image types in TGA file */ public final static int NO_IMAGE = 0; // no image data public final static int UCOLORMAPPED = 1; // uncompressed color mapped image public final static int UTRUECOLOR = 2; // uncompressed true color image public final static int UBLACKWHITE = 3; // uncompressed black and white image public final static int COLORMAPPED = 9; // compressed color mapped image public final static int TRUECOLOR = 10; // compressed true color image public final static int BLACKWHITE = 11; // compressed black and white image /** Field image descriptor bitfield values definitions */ public final static int ID_ATTRIBPERPIXEL = 0xF; public final static int ID_RIGHTTOLEFT = 0x10; public final static int ID_TOPTOBOTTOM = 0x20; public final static int ID_INTERLEAVE = 0xC0; /** Field image descriptor / interleave values */ public final static int I_NOTINTERLEAVED = 0; public final static int I_TWOWAY = 1; public final static int I_FOURWAY = 2; /** Type of this TGA file format */ private int tgaType; /** initial TGA image data fields */ private int idLength; // byte value private int colorMapType; // byte value private int imageType; // byte value /** TGA image colour map fields */ private int firstEntryIndex; private int colorMapLength; private byte colorMapEntrySize; /** TGA image specification fields */ private int xOrigin; private int yOrigin; private int width; private int height; private byte pixelDepth; private byte imageDescriptor; private byte[] imageIDbuf; private String imageID; // For construction from user data Header() { tgaType = TYPE_OLD; // dont try and get footer. } Header(LEDataInputStream in) throws IOException { int ret; tgaType = TYPE_OLD; // dont try and get footer. // initial header fields idLength = in.readUnsignedByte(); colorMapType = in.readUnsignedByte(); imageType = in.readUnsignedByte(); // color map header fields firstEntryIndex = in.readUnsignedShort(); colorMapLength = in.readUnsignedShort(); colorMapEntrySize = in.readByte(); // TGA image specification fields xOrigin = in.readUnsignedShort(); yOrigin = in.readUnsignedShort(); width = in.readUnsignedShort(); height = in.readUnsignedShort(); pixelDepth = in.readByte(); imageDescriptor = in.readByte(); if (idLength > 0) { imageIDbuf = new byte[idLength]; in.read(imageIDbuf, 0, idLength); imageID = new String(imageIDbuf, "US-ASCII"); } } public int tgaType() { return tgaType; } /** initial TGA image data fields */ public int idLength() { return idLength; } public int colorMapType() { return colorMapType; } public int imageType() { return imageType; } /** TGA image colour map fields */ public int firstEntryIndex() { return firstEntryIndex; } public int colorMapLength() { return colorMapLength; } public byte colorMapEntrySize() { return colorMapEntrySize; } /** TGA image specification fields */ public int xOrigin() { return xOrigin; } public int yOrigin() { return yOrigin; } public int width() { return width; } public int height() { return height; } public byte pixelDepth() { return pixelDepth; } public byte imageDescriptor() { return imageDescriptor; } /** bitfields in imageDescriptor */ public byte attribPerPixel() { return (byte)(imageDescriptor & ID_ATTRIBPERPIXEL); } public boolean rightToLeft() { return ((imageDescriptor & ID_RIGHTTOLEFT) != 0); } public boolean topToBottom() { return ((imageDescriptor & ID_TOPTOBOTTOM) != 0); } public byte interleave() { return (byte)((imageDescriptor & ID_INTERLEAVE) >> 6); } public byte[] imageIDbuf() { return imageIDbuf; } public String imageID() { return imageID; } public String toString() { return "TGA Header " + " id length: " + idLength + " color map type: "+ colorMapType + " image type: "+ imageType + " first entry index: " + firstEntryIndex + " color map length: " + colorMapLength + " color map entry size: " + colorMapEntrySize + " x Origin: " + xOrigin + " y Origin: " + yOrigin + " width: "+ width + " height: "+ height + " pixel depth: "+ pixelDepth + " image descriptor: "+ imageDescriptor + (imageIDbuf == null ? "" : (" ID String: " + imageID)); } public int size() { return 18 + idLength; } // buf must be in little-endian byte order private void write(ByteBuffer buf) { buf.put((byte) idLength); buf.put((byte) colorMapType); buf.put((byte) imageType); buf.putShort((short) firstEntryIndex); buf.putShort((short) colorMapLength); buf.put((byte) colorMapEntrySize); buf.putShort((short) xOrigin); buf.putShort((short) yOrigin); buf.putShort((short) width); buf.putShort((short) height); buf.put((byte) pixelDepth); buf.put((byte) imageDescriptor); if (idLength > 0) { try { byte[] chars = imageID.getBytes("US-ASCII"); buf.put(chars); } catch (UnsupportedEncodingException e) { throw new RuntimeException(e); } } } } /** * Identifies the image type of the tga image data and loads * it into the JimiImage structure. This was taken from the * prototype and modified for the new Jimi structure */ private void decodeImage(LEDataInputStream dIn) throws IOException { switch (header.imageType()) { case Header.UCOLORMAPPED: throw new IOException("TGADecoder Uncompressed Colormapped images not supported"); case Header.UTRUECOLOR: // pixelDepth 15, 16, 24 and 32 switch (header.pixelDepth) { case 16: throw new IOException("TGADecoder Compressed 16-bit True Color images not supported"); case 24: case 32: decodeRGBImageU24_32(dIn); break; } break; case Header.UBLACKWHITE: throw new IOException("TGADecoder Uncompressed Grayscale images not supported"); case Header.COLORMAPPED: throw new IOException("TGADecoder Compressed Colormapped images not supported"); case Header.TRUECOLOR: throw new IOException("TGADecoder Compressed True Color images not supported"); case Header.BLACKWHITE: throw new IOException("TGADecoder Compressed Grayscale images not supported"); } } /** * This assumes that the body is for a 24 bit or 32 bit for a * RGB or ARGB image respectively. */ private void decodeRGBImageU24_32(LEDataInputStream dIn) throws IOException { int i; // row index int j; // column index int y; // output row index int raw; // index through the raw input buffer int rawWidth = header.width() * (header.pixelDepth() / 8); byte[] rawBuf = new byte[rawWidth]; byte[] tmpData = new byte[rawWidth * header.height()]; for (i = 0; i < header.height(); ++i) { dIn.readFully(rawBuf, 0, rawWidth); if (header.topToBottom()) y = header.height - i - 1; // range 0 to (header.height - 1) else y = i; System.arraycopy(rawBuf, 0, tmpData, y * rawWidth, rawBuf.length); } if (header.pixelDepth() == 24) { bpp=3; if(GLProfile.isGL2()) { format = GL2.GL_BGR; } else { format = GL.GL_RGB; swapBGR(tmpData, rawWidth, header.height(), bpp); } } else { assert header.pixelDepth() == 32; bpp=4; if(GLProfile.isGL2()) { format = GL2.GL_BGRA; } else { format = GL.GL_RGBA; swapBGR(tmpData, rawWidth, header.height(), bpp); } } data = ByteBuffer.wrap(tmpData); } private static void swapBGR(byte[] data, int bWidth, int height, int bpp) { byte r,b; int k; for(int i=0; i