mirror of
https://github.com/haraldk/TwelveMonkeys.git
synced 2025-10-04 19:34:48 -04:00
Adding the twelvemonkeys-imageio sub-project
This commit is contained in:
25
twelvemonkeys-imageio/iff/license.txt
Executable file
25
twelvemonkeys-imageio/iff/license.txt
Executable file
@@ -0,0 +1,25 @@
|
||||
Copyright (c) 2009, Harald Kuhr
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
* Redistributions 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 "TwelveMonkeys" nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
32
twelvemonkeys-imageio/iff/pom.xml
Executable file
32
twelvemonkeys-imageio/iff/pom.xml
Executable file
@@ -0,0 +1,32 @@
|
||||
<?xml version="1.0"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||
<artifactId>twelvemonkeys-imageio-iff</artifactId>
|
||||
<version>2.1</version>
|
||||
<name>TwelveMonkeys ImageIO IFF plugin</name>
|
||||
<description>
|
||||
ImageIO plugin for Amiga/Electronic Arts Interchange Filed Format (IFF)
|
||||
type ILBM and PBM format.
|
||||
</description>
|
||||
|
||||
<parent>
|
||||
<artifactId>twelvemonkeys-imageio</artifactId>
|
||||
<groupId>com.twelvemonkeys</groupId>
|
||||
<version>2.1</version>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||
<artifactId>twelvemonkeys-imageio-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||
<artifactId>twelvemonkeys-imageio-core</artifactId>
|
||||
<classifier>tests</classifier>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
@@ -0,0 +1,180 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions 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 "TwelveMonkeys" nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.imageio.plugins.iff;
|
||||
|
||||
import javax.imageio.IIOException;
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* BMHDChunk
|
||||
* <p/>
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @version $Id: BMHDChunk.java,v 1.0 28.feb.2006 00:04:32 haku Exp$
|
||||
*/
|
||||
class BMHDChunk extends IFFChunk {
|
||||
//
|
||||
// typedef UBYTE Masking; /* Choice of masking technique. */
|
||||
//
|
||||
// #define mskNone 0
|
||||
// #define mskHasMask 1
|
||||
// #define mskHasTransparentColor 2
|
||||
// #define mskLasso 3
|
||||
//
|
||||
// typedef UBYTE Compression; /* Choice of compression algorithm
|
||||
// applied to the rows of all source and mask planes. "cmpByteRun1"
|
||||
// is the byte run encoding described in Appendix C. Do not compress
|
||||
// across rows! */
|
||||
// #define cmpNone 0
|
||||
// #define cmpByteRun1 1
|
||||
//
|
||||
// typedef struct {
|
||||
// UWORD w, h; /* raster width & height in pixels */
|
||||
// WORD x, y; /* pixel position for this image */
|
||||
// UBYTE nPlanes; /* # source bitplanes */
|
||||
// Masking masking;
|
||||
// Compression compression;
|
||||
// UBYTE pad1; /* unused; ignore on read, write as 0 */
|
||||
// UWORD transparentColor; /* transparent "color number" (sort of) */
|
||||
// UBYTE xAspect, yAspect; /* pixel aspect, a ratio width : height */
|
||||
// WORD pageWidth, pageHeight; /* source "page" size in pixels */
|
||||
// } BitMapHeader;*/
|
||||
|
||||
static final int MASK_NONE = 0;
|
||||
static final int MASK_HAS_MASK = 1;
|
||||
static final int MASK_TRANSPARENT_COLOR = 2;
|
||||
static final int MASK_LASSO = 3;
|
||||
|
||||
static final int COMPRESSION_NONE = 0;
|
||||
// RLE
|
||||
static final int COMPRESSION_BYTE_RUN = 1;
|
||||
|
||||
// NOTE: Each row of the image is stored in an integral number of 16 bit
|
||||
// words. The number of words per row is words=((w+15)/16)
|
||||
|
||||
// Dimensions of raster
|
||||
int mWidth;
|
||||
int mHeight;
|
||||
|
||||
// Source offsets
|
||||
// Hmm.. Consider making these Image.properties?
|
||||
int mXPos;
|
||||
int mYPos;
|
||||
|
||||
// The number of source bitplanes in the BODY chunk (see below) is stored in
|
||||
// nPlanes. An ILBM with a CMAP but no BODY and nPlanes = 0 is the
|
||||
// recommended way to store a color map.
|
||||
int mBitplanes;
|
||||
|
||||
int mMaskType;
|
||||
int mCompressionType;
|
||||
|
||||
int mTransparentIndex;
|
||||
|
||||
// NOTE: Typical values are 10:11 (320 x 200)
|
||||
int mXAspect;
|
||||
int mYAspect;
|
||||
|
||||
// Source page dimension
|
||||
// NOTE: The image may be larger than the page, probably ignore these
|
||||
int mPageWidth;
|
||||
int mPageHeight;
|
||||
|
||||
protected BMHDChunk(int pChunkLength) {
|
||||
super(IFF.CHUNK_BMHD, pChunkLength);
|
||||
}
|
||||
|
||||
protected BMHDChunk(int pWidth, int pHeight, int pBitplanes,
|
||||
int pMaskType, int pCompressionType,
|
||||
int pTransparentIndex) {
|
||||
super(IFF.CHUNK_BMHD, 20);
|
||||
mWidth = pWidth;
|
||||
mHeight = pHeight;
|
||||
mXPos = 0;
|
||||
mYPos = 0;
|
||||
mBitplanes = pBitplanes;
|
||||
mMaskType = pMaskType;
|
||||
mCompressionType = pCompressionType;
|
||||
mTransparentIndex = pTransparentIndex;
|
||||
mXAspect = 1;
|
||||
mYAspect = 1;
|
||||
mPageWidth = Math.min(pWidth, Short.MAX_VALUE); // For some reason, these are signed?
|
||||
mPageHeight = Math.min(pHeight, Short.MAX_VALUE);
|
||||
}
|
||||
|
||||
void readChunk(DataInput pInput) throws IOException {
|
||||
if (mChunkLength != 20) {
|
||||
throw new IIOException("Unknown BMHD chunk length: " + mChunkLength);
|
||||
}
|
||||
mWidth = pInput.readUnsignedShort();
|
||||
mHeight = pInput.readUnsignedShort();
|
||||
mXPos = pInput.readShort();
|
||||
mYPos = pInput.readShort();
|
||||
mBitplanes = pInput.readUnsignedByte();
|
||||
mMaskType = pInput.readUnsignedByte();
|
||||
mCompressionType = pInput.readUnsignedByte();
|
||||
pInput.readByte(); // PAD
|
||||
mTransparentIndex = pInput.readUnsignedShort();
|
||||
mXAspect = pInput.readUnsignedByte();
|
||||
mYAspect = pInput.readUnsignedByte();
|
||||
mPageWidth = pInput.readShort();
|
||||
mPageHeight = pInput.readShort();
|
||||
}
|
||||
|
||||
void writeChunk(DataOutput pOutput) throws IOException {
|
||||
pOutput.writeInt(mChunkId);
|
||||
pOutput.writeInt(mChunkLength);
|
||||
|
||||
pOutput.writeShort(mWidth);
|
||||
pOutput.writeShort(mHeight);
|
||||
pOutput.writeShort(mXPos);
|
||||
pOutput.writeShort(mYPos);
|
||||
pOutput.writeByte(mBitplanes);
|
||||
pOutput.writeByte(mMaskType);
|
||||
pOutput.writeByte(mCompressionType);
|
||||
pOutput.writeByte(0); // PAD
|
||||
pOutput.writeShort(mTransparentIndex);
|
||||
pOutput.writeByte(mXAspect);
|
||||
pOutput.writeByte(mYAspect);
|
||||
pOutput.writeShort(mPageWidth);
|
||||
pOutput.writeShort(mPageHeight);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return super.toString()
|
||||
+ " {w=" + mWidth + ", h=" + mHeight
|
||||
+ ", x=" + mXPos + ", y=" + mYPos
|
||||
+ ", planes=" + mBitplanes + ", mask=" + mMaskType
|
||||
+ ", compression=" + mCompressionType + ", trans=" + mTransparentIndex
|
||||
+ ", xAspect=" + mXAspect + ", yAspect=" + mYAspect
|
||||
+ ", pageWidth=" + mPageWidth + ", pageHeight=" + mPageHeight + "}";
|
||||
}
|
||||
}
|
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions 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 "TwelveMonkeys" nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.imageio.plugins.iff;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.IOException;
|
||||
import java.io.DataOutput;
|
||||
|
||||
/**
|
||||
* BODYChunk
|
||||
* <p/>
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @version $Id: BODYChunk.java,v 1.0 28.feb.2006 01:25:49 haku Exp$
|
||||
*/
|
||||
class BODYChunk extends IFFChunk {
|
||||
|
||||
protected BODYChunk(int pChunkLength) {
|
||||
super(IFF.CHUNK_BODY, pChunkLength);
|
||||
}
|
||||
|
||||
void readChunk(DataInput pInput) throws IOException {
|
||||
throw new InternalError("BODY chunk should only be read from IFFImageReader");
|
||||
}
|
||||
|
||||
void writeChunk(DataOutput pOutput) throws IOException {
|
||||
throw new InternalError("BODY chunk should only be written from IFFImageWriter");
|
||||
}
|
||||
}
|
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions 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 "TwelveMonkeys" nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.imageio.plugins.iff;
|
||||
|
||||
import javax.imageio.IIOException;
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* CAMGChunk
|
||||
* <p/>
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @version $Id: CAMGChunk.java,v 1.0 28.feb.2006 02:10:07 haku Exp$
|
||||
*/
|
||||
class CAMGChunk extends IFFChunk {
|
||||
|
||||
// #define CAMG_HAM 0x800 /* hold and modify */
|
||||
// #define CAMG_EHB 0x80 /* extra halfbrite */
|
||||
|
||||
private int mCAMG;
|
||||
|
||||
public CAMGChunk(int pLength) {
|
||||
super(IFF.CHUNK_CAMG, pLength);
|
||||
}
|
||||
|
||||
void readChunk(DataInput pInput) throws IOException {
|
||||
if (mChunkLength != 4) {
|
||||
throw new IIOException("Unknown CAMG chunk length: " + mChunkLength);
|
||||
}
|
||||
mCAMG = pInput.readInt();
|
||||
}
|
||||
|
||||
void writeChunk(DataOutput pOutput) throws IOException {
|
||||
throw new InternalError("Not implemented: writeChunk()");
|
||||
}
|
||||
|
||||
boolean isHAM() {
|
||||
return (mCAMG & 0x800) != 0;
|
||||
}
|
||||
|
||||
boolean isEHB() {
|
||||
return (mCAMG & 0x80) != 0;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return super.toString() + " {mode=" + (isHAM() ? "HAM" : isEHB() ? "EHB" : "Normal") + "}";
|
||||
}
|
||||
}
|
@@ -0,0 +1,170 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions 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 "TwelveMonkeys" nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.imageio.plugins.iff;
|
||||
|
||||
import com.twelvemonkeys.image.InverseColorMapIndexColorModel;
|
||||
|
||||
import javax.imageio.IIOException;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.IndexColorModel;
|
||||
import java.awt.image.WritableRaster;
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* CMAPChunk
|
||||
* <p/>
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @version $Id: CMAPChunk.java,v 1.0 28.feb.2006 00:38:05 haku Exp$
|
||||
*/
|
||||
class CMAPChunk extends IFFChunk {
|
||||
|
||||
// typedef struct {
|
||||
// UBYTE red, green, blue; /* color intensities 0..255 */
|
||||
// } ColorRegister; /* size = 3 bytes */
|
||||
//
|
||||
// typedef ColorRegister ColorMap[n]; /* size = 3n bytes */
|
||||
|
||||
|
||||
byte[] mReds;
|
||||
byte[] mGreens;
|
||||
byte[] mBlues;
|
||||
|
||||
boolean mEHB;
|
||||
|
||||
final private BMHDChunk mHeader;
|
||||
final private CAMGChunk mCamg;
|
||||
private IndexColorModel mModel;
|
||||
|
||||
protected CMAPChunk(int pChunkLength, BMHDChunk pHeader, CAMGChunk pCamg) {
|
||||
super(IFF.CHUNK_CMAP, pChunkLength);
|
||||
mHeader = pHeader;
|
||||
mCamg = pCamg;
|
||||
}
|
||||
|
||||
public CMAPChunk(IndexColorModel pModel) {
|
||||
super(IFF.CHUNK_CMAP, pModel.getMapSize() * 3);
|
||||
mModel = pModel;
|
||||
mHeader = null;
|
||||
mCamg = null;
|
||||
}
|
||||
|
||||
void readChunk(DataInput pInput) throws IOException {
|
||||
int numColors = mChunkLength / 3;
|
||||
int paletteSize = numColors;
|
||||
|
||||
boolean isEHB = mCamg != null && mCamg.isEHB();
|
||||
if (isEHB) {
|
||||
if (numColors == 32) {
|
||||
paletteSize = 64;
|
||||
}
|
||||
else {
|
||||
throw new IIOException("Unknown number of colors for EHB: " + numColors);
|
||||
}
|
||||
}
|
||||
|
||||
mReds = new byte[paletteSize];
|
||||
mGreens = mReds.clone();
|
||||
mBlues = mReds.clone();
|
||||
|
||||
for (int i = 0; i < numColors; i++) {
|
||||
mReds[i] = pInput.readByte();
|
||||
mGreens[i] = pInput.readByte();
|
||||
mBlues[i] = pInput.readByte();
|
||||
}
|
||||
if (isEHB) {
|
||||
for (int i = 0; i < numColors; i++) {
|
||||
mReds[i + numColors] = (byte) ((mReds[i] & 0xff) / 2);
|
||||
mGreens[i + numColors] = (byte) ((mGreens[i] & 0xff) / 2);
|
||||
mBlues[i + numColors] = (byte) ((mBlues[i] & 0xff) / 2);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: When reading in a CMAP for 8-bit-per-gun display or
|
||||
// manipulation, you may want to assume that any CMAP which has 0 values
|
||||
// for the low bits of all guns for all registers was stored shifted
|
||||
// rather than scaled, and provide your own scaling.
|
||||
// Use defaults if the color map is absent or has fewer color registers
|
||||
// than you need. Ignore any extra color registers.
|
||||
|
||||
// R8 := (Rn x 255 ) / maxColor
|
||||
|
||||
// All chunks are WORD aligned (even sized), may need to read pad...
|
||||
if (mChunkLength % 2 != 0) {
|
||||
pInput.readByte();
|
||||
}
|
||||
|
||||
// TODO: Bitmask transparency
|
||||
// Would it work to double to numbers of colors, and create an indexcolormodel,
|
||||
// with alpha, where all colors above the original color is all transparent?
|
||||
// This is a waste of time and space, of course...
|
||||
int trans = mHeader.mMaskType == BMHDChunk.MASK_TRANSPARENT_COLOR ? mHeader.mTransparentIndex : -1;
|
||||
mModel = new InverseColorMapIndexColorModel(mHeader.mBitplanes, mReds.length, mReds, mGreens, mBlues, trans);
|
||||
}
|
||||
|
||||
void writeChunk(DataOutput pOutput) throws IOException {
|
||||
pOutput.writeInt(mChunkId);
|
||||
pOutput.writeInt(mChunkLength);
|
||||
|
||||
final int length = mModel.getMapSize();
|
||||
|
||||
for (int i = 0; i < length; i++) {
|
||||
pOutput.writeByte(mModel.getRed(i));
|
||||
pOutput.writeByte(mModel.getGreen(i));
|
||||
pOutput.writeByte(mModel.getBlue(i));
|
||||
}
|
||||
|
||||
if (mChunkLength % 2 != 0) {
|
||||
pOutput.writeByte(0); // PAD
|
||||
}
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return super.toString() + " {colorMap=" + mModel + "}";
|
||||
}
|
||||
|
||||
IndexColorModel getIndexColorModel() {
|
||||
return mModel;
|
||||
}
|
||||
|
||||
public BufferedImage createPaletteImage() {
|
||||
// Create a 1 x colors.length image
|
||||
IndexColorModel cm = getIndexColorModel();
|
||||
WritableRaster raster = cm.createCompatibleWritableRaster(cm.getMapSize(), 1);
|
||||
byte[] pixel = null;
|
||||
for (int x = 0; x < cm.getMapSize(); x++) {
|
||||
pixel = (byte[]) cm.getDataElements(cm.getRGB(x), pixel);
|
||||
raster.setDataElements(x, 0, pixel);
|
||||
}
|
||||
|
||||
return new BufferedImage(cm, raster, cm.isAlphaPremultiplied(), null);
|
||||
}
|
||||
}
|
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions 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 "TwelveMonkeys" nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.imageio.plugins.iff;
|
||||
|
||||
import javax.imageio.IIOException;
|
||||
import java.awt.*;
|
||||
import java.awt.geom.Point2D;
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* GRABChunk
|
||||
* <p/>
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @version $Id: GRABChunk.java,v 1.0 28.feb.2006 01:55:05 haku Exp$
|
||||
*/
|
||||
class GRABChunk extends IFFChunk {
|
||||
// typedef struct {
|
||||
// WORD x, y; /* relative coordinates (pixels) */
|
||||
// } Point2D;
|
||||
|
||||
Point2D mPoint;
|
||||
|
||||
protected GRABChunk(int pChunkLength) {
|
||||
super(IFF.CHUNK_GRAB, pChunkLength);
|
||||
}
|
||||
|
||||
protected GRABChunk(Point2D pPoint) {
|
||||
super(IFF.CHUNK_GRAB, 4);
|
||||
mPoint = pPoint;
|
||||
}
|
||||
|
||||
void readChunk(DataInput pInput) throws IOException {
|
||||
if (mChunkLength != 4) {
|
||||
throw new IIOException("Unknown GRAB chunk size: " + mChunkLength);
|
||||
}
|
||||
mPoint = new Point(pInput.readShort(), pInput.readShort());
|
||||
}
|
||||
|
||||
void writeChunk(DataOutput pOutput) throws IOException {
|
||||
pOutput.writeShort((int) mPoint.getX());
|
||||
pOutput.writeShort((int) mPoint.getY());
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return super.toString() + " {point=" + mPoint + "}";
|
||||
}
|
||||
}
|
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions 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 "TwelveMonkeys" nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.imageio.plugins.iff;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.IOException;
|
||||
import java.io.DataOutput;
|
||||
|
||||
/**
|
||||
* UnknownChunk
|
||||
* <p/>
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @version $Id: UnknownChunk.java,v 1.0 28.feb.2006 00:53:47 haku Exp$
|
||||
*/
|
||||
class GenericChunk extends IFFChunk {
|
||||
|
||||
byte[] mData;
|
||||
|
||||
protected GenericChunk(int pChunkId, int pChunkLength) {
|
||||
super(pChunkId, pChunkLength);
|
||||
mData = new byte[pChunkLength <= 50 ? pChunkLength : 47];
|
||||
}
|
||||
|
||||
protected GenericChunk(int pChunkId, byte[] pChunkData) {
|
||||
super(pChunkId, pChunkData.length);
|
||||
mData = pChunkData;
|
||||
}
|
||||
|
||||
void readChunk(DataInput pInput) throws IOException {
|
||||
pInput.readFully(mData, 0, mData.length);
|
||||
|
||||
int toSkip = mChunkLength - mData.length;
|
||||
while (toSkip > 0) {
|
||||
toSkip -= pInput.skipBytes(toSkip);
|
||||
}
|
||||
|
||||
// Read pad
|
||||
if (mChunkLength % 2 != 0) {
|
||||
pInput.readByte();
|
||||
}
|
||||
}
|
||||
|
||||
void writeChunk(DataOutput pOutput) throws IOException {
|
||||
pOutput.writeInt(mChunkId);
|
||||
pOutput.writeInt(mChunkLength);
|
||||
pOutput.write(mData, 0, mData.length);
|
||||
|
||||
if (mData.length % 2 != 0) {
|
||||
pOutput.writeByte(0); // PAD
|
||||
}
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return super.toString() + " {value=\""
|
||||
+ new String(mData, 0, mData.length <= 50 ? mData.length : 47)
|
||||
+ (mChunkLength <= 50 ? "" : "...") + "\"}";
|
||||
}
|
||||
}
|
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions 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 "TwelveMonkeys" nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.imageio.plugins.iff;
|
||||
|
||||
/**
|
||||
* IFF format constants.
|
||||
* <p/>
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @version $Id: IFF.java,v 1.0 07.mar.2006 15:31:48 haku Exp$
|
||||
*/
|
||||
interface IFF {
|
||||
/** IFF FORM group chunk */
|
||||
int CHUNK_FORM = ('F' << 24) + ('O' << 16) + ('R' << 8) + 'M';
|
||||
|
||||
/** IFF ILBM form type */
|
||||
int TYPE_ILBM = ('I' << 24) + ('L' << 16) + ('B' << 8) + 'M';
|
||||
|
||||
/** IFF PBM form type */
|
||||
int TYPE_PBM = ('P' << 24) + ('B' << 16) + ('M' << 8) + ' ';
|
||||
|
||||
/** Bitmap Header chunk */
|
||||
int CHUNK_BMHD = ('B' << 24) + ('M' << 16) + ('H' << 8) + 'D';
|
||||
|
||||
/** Color map chunk */
|
||||
int CHUNK_CMAP = ('C' << 24) + ('M' << 16) + ('A' << 8) + 'P';
|
||||
|
||||
/** Hotspot chunk (cursors, brushes) */
|
||||
int CHUNK_GRAB = ('G' << 24) + ('R' << 16) + ('A' << 8) + 'B';
|
||||
|
||||
/** Destination merge data chunk */
|
||||
int CHUNK_DEST = ('D' << 24) + ('E' << 16) + ('S' << 8) + 'T';
|
||||
|
||||
/** Sprite information chunk */
|
||||
int CHUNK_SPRT = ('S' << 24) + ('P' << 16) + ('R' << 8) + 'T';
|
||||
|
||||
/** Commodore Amiga viewport mode chunk (used to determine HAM and EHB modes) */
|
||||
int CHUNK_CAMG = ('C' << 24) + ('A' << 16) + ('M' << 8) + 'G';
|
||||
|
||||
/** Main data (body) chunk */
|
||||
int CHUNK_BODY = ('B' << 24) + ('O' << 16) + ('D' << 8) + 'Y';
|
||||
}
|
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions 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 "TwelveMonkeys" nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.imageio.plugins.iff;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.IOException;
|
||||
import java.io.DataOutput;
|
||||
|
||||
/**
|
||||
* IFFChunk
|
||||
* <p/>
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @version $Id: IFFChunk.java,v 1.0 28.feb.2006 00:00:45 haku Exp$
|
||||
*/
|
||||
abstract class IFFChunk {
|
||||
int mChunkId;
|
||||
int mChunkLength;
|
||||
|
||||
protected IFFChunk(int pChunkId, int pChunkLength) {
|
||||
mChunkId = pChunkId;
|
||||
mChunkLength = pChunkLength;
|
||||
}
|
||||
|
||||
abstract void readChunk(DataInput pInput) throws IOException;
|
||||
|
||||
abstract void writeChunk(DataOutput pOutput) throws IOException;
|
||||
|
||||
public String toString() {
|
||||
return IFFUtil.toChunkStr(mChunkId) + " chunk (" + mChunkLength + " bytes)";
|
||||
}
|
||||
}
|
@@ -0,0 +1,693 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions 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 "TwelveMonkeys" nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.imageio.plugins.iff;
|
||||
|
||||
import com.twelvemonkeys.imageio.ImageReaderBase;
|
||||
import com.twelvemonkeys.imageio.stream.BufferedImageInputStream;
|
||||
import com.twelvemonkeys.imageio.util.IIOUtil;
|
||||
import com.twelvemonkeys.imageio.util.IndexedImageTypeSpecifier;
|
||||
import com.twelvemonkeys.io.enc.DecoderStream;
|
||||
import com.twelvemonkeys.io.enc.PackBitsDecoder;
|
||||
|
||||
import javax.imageio.*;
|
||||
import javax.imageio.spi.ImageReaderSpi;
|
||||
import javax.imageio.stream.ImageInputStream;
|
||||
import java.awt.*;
|
||||
import java.awt.color.ColorSpace;
|
||||
import java.awt.image.*;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Reader for Amiga (Electronic Arts) IFF ILBM (InterLeaved BitMap) and PBM
|
||||
* format (Packed BitMap).
|
||||
* The IFF format (Interchange File Format) is the standard file format
|
||||
* supported by allmost all image software for the Amiga computer.
|
||||
* <p/>
|
||||
* This reader supports the original palette-based 1-8 bit formats, including
|
||||
* EHB (Extra Halfbright), HAM (Hold and Modify), and the more recent "deep"
|
||||
* formats, 8 bit gray, 24 bit RGB and 32 bit ARGB.
|
||||
* Uncompressed and ByteRun1 compressed (run lenght encoding) files are
|
||||
* supported.
|
||||
* <p/>
|
||||
* Palette based images are read as {@code BufferedImage} of
|
||||
* {@link BufferedImage#TYPE_BYTE_INDEXED TYPE_BYTE_INDEXED} or
|
||||
* {@link BufferedImage#TYPE_BYTE_BINARY BufferedImage#}
|
||||
* depending on the bit depth.
|
||||
* Gray images are read as
|
||||
* {@link BufferedImage#TYPE_BYTE_GRAY TYPE_BYTE_GRAY}.
|
||||
* 24 bit true-color images are read as
|
||||
* {@link BufferedImage#TYPE_3BYTE_BGR TYPE_3BYTE_BGR}.
|
||||
* 32 bit true-color images are read as
|
||||
* {@link BufferedImage#TYPE_4BYTE_ABGR TYPE_4BYTE_ABGR}.
|
||||
* <p/>
|
||||
* Issues: HAM and HAM8 (Hold and Modify) formats are converted to RGB (24 bit),
|
||||
* as it seems to be very hard to create an {@code IndexColorModel} subclass
|
||||
* that would correctly describe these formats.
|
||||
* These formats utilizes the special display hardware in the Amiga computers.
|
||||
* HAM (6 bits) needs 12 bits storage/pixel, if unpacked to RGB (4 bits/gun).
|
||||
* HAM8 (8 bits) needs 18 bits storage/pixel, if unpacked to RGB (6 bits/gun).
|
||||
* See <a href="http://en.wikipedia.org/wiki/Hold_And_Modify">Wikipedia: HAM</a>
|
||||
* for more information.
|
||||
* <br/>
|
||||
* EHB palette is expanded to an {@link IndexColorModel} with 64 entries.
|
||||
* See <a href="http://en.wikipedia.org/wiki/Extra_Half-Brite">Wikipedia: EHB</a>
|
||||
* for more information.
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haku $
|
||||
* @version $Id: IFFImageReader.java,v 1.0 29.aug.2004 20:26:58 haku Exp $
|
||||
* @see <a href="http://en.wikipedia.org/wiki/Interchange_File_Format">Wikipedia: IFF</a>
|
||||
* @see <a href="http://en.wikipedia.org/wiki/ILBM">Wikipedia: IFF ILBM</a>
|
||||
*/
|
||||
public class IFFImageReader extends ImageReaderBase {
|
||||
|
||||
private BMHDChunk mHeader;
|
||||
private CMAPChunk mColorMap;
|
||||
private BODYChunk mBody;
|
||||
private GRABChunk mGrab;
|
||||
private CAMGChunk mViewPort;
|
||||
private int mFormType;
|
||||
private long mBodyStart;
|
||||
|
||||
private BufferedImage mImage;
|
||||
private DataInputStream mByteRunStream;
|
||||
|
||||
public IFFImageReader() {
|
||||
super(IFFImageReaderSpi.sharedProvider());
|
||||
}
|
||||
|
||||
protected IFFImageReader(ImageReaderSpi pProvider) {
|
||||
super(pProvider);
|
||||
}
|
||||
|
||||
private void init(int pIndex) throws IOException {
|
||||
checkBounds(pIndex);
|
||||
|
||||
if (mHeader == null) {
|
||||
readMeta();
|
||||
}
|
||||
}
|
||||
|
||||
protected void resetMembers() {
|
||||
mHeader = null;
|
||||
mColorMap = null;
|
||||
mBody = null;
|
||||
mViewPort = null;
|
||||
mFormType = 0;
|
||||
|
||||
mImage = null;
|
||||
mByteRunStream = null;
|
||||
}
|
||||
|
||||
private void readMeta() throws IOException {
|
||||
if (mImageInput.readInt() != IFF.CHUNK_FORM) {
|
||||
throw new IIOException("Unknown file format for IFFImageReader");
|
||||
}
|
||||
|
||||
int remaining = mImageInput.readInt() - 4; // We'll read 4 more in a sec
|
||||
|
||||
mFormType = mImageInput.readInt();
|
||||
if (mFormType != IFF.TYPE_ILBM && mFormType != IFF.TYPE_PBM) {
|
||||
throw new IIOException("Only IFF (FORM) type ILBM and PBM supported: " + IFFUtil.toChunkStr(mFormType));
|
||||
}
|
||||
|
||||
//System.out.println("IFF type FORM " + toChunkStr(type));
|
||||
|
||||
mGrab = null;
|
||||
mViewPort = null;
|
||||
|
||||
while (remaining > 0) {
|
||||
int chunkId = mImageInput.readInt();
|
||||
int length = mImageInput.readInt();
|
||||
|
||||
remaining -= 8;
|
||||
remaining -= length % 2 == 0 ? length : length + 1;
|
||||
|
||||
//System.out.println("Next chunk: " + toChunkStr(chunkId) + " lenght: " + length);
|
||||
//System.out.println("Remaining bytes after chunk: " + remaining);
|
||||
|
||||
switch (chunkId) {
|
||||
case IFF.CHUNK_BMHD:
|
||||
if (mHeader != null) {
|
||||
throw new IIOException("Multiple BMHD chunks not allowed");
|
||||
}
|
||||
|
||||
mHeader = new BMHDChunk(length);
|
||||
mHeader.readChunk(mImageInput);
|
||||
|
||||
//System.out.println(mHeader);
|
||||
break;
|
||||
case IFF.CHUNK_CMAP:
|
||||
if (mColorMap != null) {
|
||||
throw new IIOException("Multiple CMAP chunks not allowed");
|
||||
}
|
||||
mColorMap = new CMAPChunk(length, mHeader, mViewPort);
|
||||
mColorMap.readChunk(mImageInput);
|
||||
|
||||
//System.out.println(mColorMap);
|
||||
break;
|
||||
case IFF.CHUNK_GRAB:
|
||||
if (mGrab != null) {
|
||||
throw new IIOException("Multiple GRAB chunks not allowed");
|
||||
}
|
||||
mGrab = new GRABChunk(length);
|
||||
mGrab.readChunk(mImageInput);
|
||||
|
||||
//System.out.println(mGrab);
|
||||
break;
|
||||
case IFF.CHUNK_CAMG:
|
||||
if (mViewPort != null) {
|
||||
throw new IIOException("Multiple CAMG chunks not allowed");
|
||||
}
|
||||
mViewPort = new CAMGChunk(length);
|
||||
mViewPort.readChunk(mImageInput);
|
||||
|
||||
//System.out.println(mViewPort);
|
||||
break;
|
||||
case IFF.CHUNK_BODY:
|
||||
if (mBody != null) {
|
||||
throw new IIOException("Multiple BODY chunks not allowed");
|
||||
}
|
||||
|
||||
mBody = new BODYChunk(length);
|
||||
mBodyStart = mImageInput.getStreamPosition();
|
||||
|
||||
// NOTE: We don't read the body here, it's done later in the
|
||||
// read(int, ImageReadParam) method
|
||||
|
||||
// Done reading meta
|
||||
return;
|
||||
default:
|
||||
// TODO: We probably want to store anno chunks as Metadata
|
||||
// ANNO, DEST, SPRT and more
|
||||
IFFChunk generic = new GenericChunk(chunkId, length);
|
||||
generic.readChunk(mImageInput);
|
||||
|
||||
//System.out.println(generic);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public BufferedImage read(int pIndex, ImageReadParam pParam) throws IOException {
|
||||
init(pIndex);
|
||||
|
||||
processImageStarted(pIndex);
|
||||
|
||||
mImage = getDestination(pParam, getImageTypes(pIndex), mHeader.mWidth, mHeader.mHeight);
|
||||
//System.out.println(mBody);
|
||||
if (mBody != null) {
|
||||
//System.out.println("Read body");
|
||||
readBody(pParam);
|
||||
}
|
||||
else {
|
||||
// In the rare case of an ILBM containing nothing but a CMAP
|
||||
//System.out.println(mColorMap);
|
||||
if (mColorMap != null) {
|
||||
//System.out.println("Creating palette!");
|
||||
mImage = mColorMap.createPaletteImage();
|
||||
}
|
||||
}
|
||||
|
||||
BufferedImage result = mImage;
|
||||
|
||||
processImageComplete();
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public int getWidth(int pIndex) throws IOException {
|
||||
init(pIndex);
|
||||
return mHeader.mWidth;
|
||||
}
|
||||
|
||||
public int getHeight(int pIndex) throws IOException {
|
||||
init(pIndex);
|
||||
return mHeader.mHeight;
|
||||
}
|
||||
|
||||
public Iterator<ImageTypeSpecifier> getImageTypes(int pIndex) throws IOException {
|
||||
init(pIndex);
|
||||
|
||||
List<ImageTypeSpecifier> types = Arrays.asList(
|
||||
getRawImageType(pIndex),
|
||||
ImageTypeSpecifier.createFromBufferedImageType(mHeader.mBitplanes == 32 ? BufferedImage.TYPE_4BYTE_ABGR : BufferedImage.TYPE_3BYTE_BGR)
|
||||
// TODO: ImageTypeSpecifier.createFromBufferedImageType(mHeader.mBitplanes == 32 ? BufferedImage.TYPE_INT_ARGB : BufferedImage.TYPE_INT_RGB),
|
||||
// TODO: Allow 32 bit always. Allow RGB and discard alpha, if present?
|
||||
);
|
||||
return types.iterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImageTypeSpecifier getRawImageType(int pIndex) throws IOException {
|
||||
init(pIndex);
|
||||
// TODO: Stay DRY...
|
||||
// TODO: Use this for creating the Image/Buffer in the read code below...
|
||||
// NOTE: mColorMap may be null for 8 bit (gray), 24 bit or 32 bit only
|
||||
ImageTypeSpecifier specifier;
|
||||
switch (mHeader.mBitplanes) {
|
||||
case 1:
|
||||
// 1 bit
|
||||
case 2:
|
||||
// 2 bit
|
||||
case 3:
|
||||
case 4:
|
||||
// 4 bit
|
||||
case 5:
|
||||
case 6:
|
||||
// May be HAM6
|
||||
// May be EHB
|
||||
case 7:
|
||||
case 8:
|
||||
// 8 bit
|
||||
// May be HAM8
|
||||
if (!isHAM()) {
|
||||
IndexColorModel cm = mColorMap.getIndexColorModel();
|
||||
if (cm != null) {
|
||||
specifier = IndexedImageTypeSpecifier.createFromIndexColorModel(cm);
|
||||
break;
|
||||
}
|
||||
else {
|
||||
specifier = ImageTypeSpecifier.createFromBufferedImageType(BufferedImage.TYPE_BYTE_GRAY);
|
||||
break;
|
||||
}
|
||||
}
|
||||
case 24:
|
||||
// 24 bit RGB
|
||||
specifier = ImageTypeSpecifier.createFromBufferedImageType(BufferedImage.TYPE_3BYTE_BGR);
|
||||
break;
|
||||
case 32:
|
||||
// 32 bit ARGB
|
||||
specifier = ImageTypeSpecifier.createFromBufferedImageType(BufferedImage.TYPE_4BYTE_ABGR);
|
||||
break;
|
||||
default:
|
||||
throw new IIOException("Bit depth not implemented: " + mHeader.mBitplanes);
|
||||
}
|
||||
return specifier;
|
||||
}
|
||||
|
||||
private void readBody(ImageReadParam pParam) throws IOException {
|
||||
mImageInput.seek(mBodyStart); // 8 for the header before length in stream
|
||||
mByteRunStream = null;
|
||||
|
||||
// NOTE: mColorMap may be null for 8 bit (gray), 24 bit or 32 bit only
|
||||
if (mColorMap != null) {
|
||||
IndexColorModel cm = mColorMap.getIndexColorModel();
|
||||
readIndexed(pParam, mImageInput, cm);
|
||||
}
|
||||
else {
|
||||
readTrueColor(pParam, mImageInput);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void readIndexed(ImageReadParam pParam, final ImageInputStream pInput, final IndexColorModel pModel) throws IOException {
|
||||
final int width = mHeader.mWidth;
|
||||
final int height = mHeader.mHeight;
|
||||
|
||||
final Rectangle aoi = getSourceRegion(pParam, width, height);
|
||||
final Point offset = pParam == null ? new Point(0, 0) : pParam.getDestinationOffset();
|
||||
|
||||
// Set everything to default values
|
||||
int sourceXSubsampling = 1;
|
||||
int sourceYSubsampling = 1;
|
||||
int[] sourceBands = null;
|
||||
int[] destinationBands = null;
|
||||
|
||||
// Get values from the ImageReadParam, if any
|
||||
if (pParam != null) {
|
||||
sourceXSubsampling = pParam.getSourceXSubsampling();
|
||||
sourceYSubsampling = pParam.getSourceYSubsampling();
|
||||
|
||||
sourceBands = pParam.getSourceBands();
|
||||
destinationBands = pParam.getDestinationBands();
|
||||
}
|
||||
|
||||
// Ensure band settings from param are compatible with images
|
||||
checkReadParamBandSettings(pParam, isHAM() ? 3 : 1, mImage.getSampleModel().getNumBands());
|
||||
|
||||
WritableRaster destination = mImage.getRaster();
|
||||
if (destinationBands != null || offset.x != 0 || offset.y != 0) {
|
||||
destination = destination.createWritableChild(0, 0, destination.getWidth(), destination.getHeight(), offset.x, offset.y, destinationBands);
|
||||
}
|
||||
|
||||
int planeWidth = (width + 7) / 8;
|
||||
final byte[] planeData = new byte[8 * planeWidth];
|
||||
|
||||
ColorModel cm;
|
||||
WritableRaster raster;
|
||||
|
||||
if (isHAM()) {
|
||||
// TODO: If HAM6, use type USHORT_444_RGB or 2BYTE_444_RGB?
|
||||
// Or create a HAMColorModel, if at all possible?
|
||||
// TYPE_3BYTE_BGR
|
||||
cm = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB), new int[]{8, 8, 8},
|
||||
false, false, Transparency.OPAQUE, DataBuffer.TYPE_BYTE);
|
||||
// Create a byte raster with BGR order
|
||||
raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, width, 1, width * 3, 3, new int[]{2, 1, 0}, null);
|
||||
}
|
||||
else {
|
||||
// TYPE_BYTE_BINARY or TYPE_BYTE_INDEXED
|
||||
cm = pModel;
|
||||
raster = pModel.createCompatibleWritableRaster(width, 1);
|
||||
}
|
||||
Raster sourceRow = raster.createChild(aoi.x, 0, aoi.width, 1, 0, 0, sourceBands);
|
||||
|
||||
final byte[] row = new byte[width * 8];
|
||||
|
||||
//System.out.println("Data length: " + data.length);
|
||||
//System.out.println("PlaneData length: " + planeData.length * planeData[0].length);
|
||||
//System.out.println("Row length: " + row.length);
|
||||
|
||||
final byte[] data = ((DataBufferByte) raster.getDataBuffer()).getData();
|
||||
|
||||
final int planes = mHeader.mBitplanes;
|
||||
|
||||
Object dataElements = null;
|
||||
Object outDataElements = null;
|
||||
ColorConvertOp converter = null;
|
||||
|
||||
for (int srcY = 0; srcY < height; srcY++) {
|
||||
|
||||
for (int p = 0; p < planes; p++) {
|
||||
try {
|
||||
readPlaneData(pInput, planeData, p * planeWidth, planeWidth);
|
||||
}
|
||||
catch (IOException e) {
|
||||
// TODO: Add warning? Probbably a bug somewhere, should not catch!
|
||||
}
|
||||
}
|
||||
|
||||
// Skip rows outside AOI
|
||||
if (srcY < aoi.y || (srcY - aoi.y) % sourceYSubsampling != 0) {
|
||||
continue;
|
||||
}
|
||||
else if (srcY >= (aoi.y + aoi.height)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mFormType == IFF.TYPE_ILBM) {
|
||||
int pixelPos = 0;
|
||||
int planePos = 0;
|
||||
for (int i = 0; i < planeWidth; i++) {
|
||||
IFFUtil.bitRotateCW(planeData, planePos, planeWidth, row, pixelPos, 1);
|
||||
pixelPos += 8;
|
||||
planePos++;
|
||||
}
|
||||
|
||||
if (isHAM()) {
|
||||
hamToRGB(row, pModel, data, 0);
|
||||
}
|
||||
else {
|
||||
raster.setDataElements(0, 0, width, 1, row);
|
||||
}
|
||||
}
|
||||
else /*if (mType == IFFImageReader.TYPE_PBM)*/ {
|
||||
// TODO: Arraycopy might not be neccessary, if it's okay with row larger than width
|
||||
System.arraycopy(planeData, 0, row, 0, mHeader.mBitplanes * planeWidth);
|
||||
raster.setDataElements(0, 0, width, 1, row);
|
||||
}
|
||||
|
||||
int dstY = (srcY - aoi.y) / sourceYSubsampling;
|
||||
// Handle non-converting raster as special case for performance
|
||||
if (cm.isCompatibleRaster(destination)) {
|
||||
// Rasters are compatible, just write to destinaiton
|
||||
if (sourceXSubsampling == 1) {
|
||||
destination.setRect(offset.x, dstY, sourceRow);
|
||||
// dataElements = raster.getDataElements(aoi.x, 0, aoi.width, 1, dataElements);
|
||||
// destination.setDataElements(offset.x, offset.y + (srcY - aoi.y) / sourceYSubsampling, aoi.width, 1, dataElements);
|
||||
}
|
||||
else {
|
||||
for (int srcX = 0; srcX < sourceRow.getWidth(); srcX += sourceXSubsampling) {
|
||||
dataElements = sourceRow.getDataElements(srcX, 0, dataElements);
|
||||
int dstX = /*offset.x +*/ srcX / sourceXSubsampling;
|
||||
destination.setDataElements(dstX, dstY, dataElements);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (cm instanceof IndexColorModel) {
|
||||
// TODO: Optimize this thing... Maybe it's faster to just get the data indexed, and use drawImage?
|
||||
IndexColorModel icm = (IndexColorModel) cm;
|
||||
|
||||
for (int srcX = 0; srcX < sourceRow.getWidth(); srcX += sourceXSubsampling) {
|
||||
dataElements = sourceRow.getDataElements(srcX, 0, dataElements);
|
||||
int rgb = icm.getRGB(dataElements);
|
||||
outDataElements = mImage.getColorModel().getDataElements(rgb, outDataElements);
|
||||
int dstX = srcX / sourceXSubsampling;
|
||||
destination.setDataElements(dstX, dstY, outDataElements);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// TODO: This branch is never tested, and is probably "dead"
|
||||
// ColorConvertOp
|
||||
if (converter == null) {
|
||||
converter = new ColorConvertOp(cm.getColorSpace(), mImage.getColorModel().getColorSpace(), null);
|
||||
}
|
||||
converter.filter(
|
||||
raster.createChild(aoi.x, 0, aoi.width, 1, 0, 0, null),
|
||||
destination.createWritableChild(offset.x, offset.y + srcY - aoi.y, aoi.width, 1, 0, 0, null)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
processImageProgress(srcY * 100f / mHeader.mWidth);
|
||||
if (abortRequested()) {
|
||||
processReadAborted();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// One row from each of the 24 bitplanes is written before moving to the
|
||||
// next scanline. For each scanline, the red bitplane rows are stored first,
|
||||
// followed by green and blue. The first plane holds the least significant
|
||||
// bit of the red value for each pixel, and the last holds the most
|
||||
// significant bit of the blue value.
|
||||
private void readTrueColor(ImageReadParam pParam, final ImageInputStream pInput) throws IOException {
|
||||
final int width = mHeader.mWidth;
|
||||
final int height = mHeader.mHeight;
|
||||
|
||||
final Rectangle aoi = getSourceRegion(pParam, width, height);
|
||||
final Point offset = pParam == null ? new Point(0, 0) : pParam.getDestinationOffset();
|
||||
|
||||
// Set everything to default values
|
||||
int sourceXSubsampling = 1;
|
||||
int sourceYSubsampling = 1;
|
||||
int[] sourceBands = null;
|
||||
int[] destinationBands = null;
|
||||
|
||||
// Get values from the ImageReadParam, if any
|
||||
if (pParam != null) {
|
||||
sourceXSubsampling = pParam.getSourceXSubsampling();
|
||||
sourceYSubsampling = pParam.getSourceYSubsampling();
|
||||
|
||||
sourceBands = pParam.getSourceBands();
|
||||
destinationBands = pParam.getDestinationBands();
|
||||
}
|
||||
|
||||
// Ensure band settings from param are compatible with images
|
||||
checkReadParamBandSettings(pParam, mHeader.mBitplanes / 8, mImage.getSampleModel().getNumBands());
|
||||
|
||||
int planeWidth = (width + 7) / 8;
|
||||
|
||||
final byte[] planeData = new byte[8 * planeWidth];
|
||||
|
||||
WritableRaster destination = mImage.getRaster();
|
||||
if (destinationBands != null || offset.x != 0 || offset.y != 0) {
|
||||
destination = destination.createWritableChild(0, 0, destination.getWidth(), destination.getHeight(), offset.x, offset.y, destinationBands);
|
||||
}
|
||||
WritableRaster raster = mImage.getRaster().createCompatibleWritableRaster(width, 1);
|
||||
Raster sourceRow = raster.createChild(aoi.x, 0, aoi.width, 1, 0, 0, sourceBands);
|
||||
|
||||
final byte[] data = ((DataBufferByte) raster.getDataBuffer()).getData();
|
||||
final int channels = (mHeader.mBitplanes + 7) / 8;
|
||||
final int planesPerChannel = 8;
|
||||
Object dataElements = null;
|
||||
|
||||
for (int srcY = 0; srcY < height; srcY++) {
|
||||
for (int c = 0; c < channels; c++) {
|
||||
|
||||
for (int p = 0; p < planesPerChannel; p++) {
|
||||
readPlaneData(pInput, planeData, p * planeWidth, planeWidth);
|
||||
}
|
||||
|
||||
// Skip rows outside AOI
|
||||
if (srcY < aoi.y || (srcY - aoi.y) % sourceYSubsampling != 0) {
|
||||
continue;
|
||||
}
|
||||
else if (srcY >= (aoi.y + aoi.height)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mFormType == IFF.TYPE_ILBM) {
|
||||
// NOTE: Using (channels - c - 1) instead of just c,
|
||||
// effectively reverses the channel order from RGBA to ABGR
|
||||
int off = (channels - c - 1);
|
||||
|
||||
int pixelPos = 0;
|
||||
int planePos = 0;
|
||||
for (int i = 0; i < planeWidth; i++) {
|
||||
IFFUtil.bitRotateCW(planeData, planePos, planeWidth, data, off + pixelPos * channels, channels);
|
||||
pixelPos += 8;
|
||||
planePos++;
|
||||
}
|
||||
}
|
||||
else /*if (mType == IFFImageReader.TYPE_PBM)*/ {
|
||||
System.arraycopy(planeData, 0, data, srcY * 8 * planeWidth, planeWidth);
|
||||
}
|
||||
}
|
||||
|
||||
int dstY = (srcY - aoi.y) / sourceYSubsampling;
|
||||
// TODO: Support conversion to INT (A)RGB rasters (maybe using ColorConvertOp?)
|
||||
// TODO: Avoid createChild if no region?
|
||||
if (sourceXSubsampling == 1) {
|
||||
destination.setRect(0, dstY, sourceRow);
|
||||
// dataElements = raster.getDataElements(aoi.x, 0, aoi.width, 1, dataElements);
|
||||
// destination.setDataElements(offset.x, offset.y + (srcY - aoi.y) / sourceYSubsampling, aoi.width, 1, dataElements);
|
||||
}
|
||||
else {
|
||||
for (int srcX = 0; srcX < sourceRow.getWidth(); srcX += sourceXSubsampling) {
|
||||
dataElements = sourceRow.getDataElements(srcX, 0, dataElements);
|
||||
int dstX = srcX / sourceXSubsampling;
|
||||
destination.setDataElements(dstX, dstY, dataElements);
|
||||
}
|
||||
}
|
||||
|
||||
processImageProgress(srcY * 100f / mHeader.mWidth);
|
||||
if (abortRequested()) {
|
||||
processReadAborted();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void readPlaneData(final ImageInputStream pInput, final byte[] pData, final int pOffset, final int pPlaneWidth)
|
||||
throws IOException {
|
||||
|
||||
switch (mHeader.mCompressionType) {
|
||||
case BMHDChunk.COMPRESSION_NONE:
|
||||
pInput.readFully(pData, pOffset, pPlaneWidth);
|
||||
// Uncompressed rows must have even number of bytes
|
||||
if ((mHeader.mBitplanes * pPlaneWidth) % 2 != 0) {
|
||||
pInput.readByte();
|
||||
}
|
||||
break;
|
||||
|
||||
case BMHDChunk.COMPRESSION_BYTE_RUN:
|
||||
if (mByteRunStream == null) {
|
||||
mByteRunStream = new DataInputStream(new DecoderStream(
|
||||
IIOUtil.createStreamAdapter(pInput, mBody.mChunkLength),
|
||||
new PackBitsDecoder(true)
|
||||
));
|
||||
}
|
||||
mByteRunStream.readFully(pData, pOffset, pPlaneWidth);
|
||||
break;
|
||||
default:
|
||||
throw new IIOException("Unknown compression type: " + mHeader.mCompressionType);
|
||||
}
|
||||
}
|
||||
|
||||
private void hamToRGB(final byte[] pIndexed, final IndexColorModel pModel,
|
||||
final byte[] pDest, final int pDestOffset) {
|
||||
final int bits = mHeader.mBitplanes;
|
||||
final int width = mHeader.mWidth;
|
||||
int lastRed = 0;
|
||||
int lastGreen = 0;
|
||||
int lastBlue = 0;
|
||||
|
||||
for (int x = 0; x < width; x++) {
|
||||
int pixel = pIndexed[x] & 0xff;
|
||||
|
||||
//System.out.println("--> ham" + bits);
|
||||
int paletteIndex = bits == 6 ? pixel & 0x0f : pixel & 0x3f;
|
||||
int indexShift = bits == 6 ? 4 : 2;
|
||||
int colorMask = bits == 6 ? 0x0f : 0x03;
|
||||
//System.out.println("palette index=" + paletteIndex);
|
||||
|
||||
// Get Hold and Modify bits
|
||||
switch ((pixel >> (8 - indexShift)) & 0x03) {
|
||||
case 0x00:// HOLD
|
||||
lastRed = pModel.getRed(paletteIndex);
|
||||
lastGreen = pModel.getGreen(paletteIndex);
|
||||
lastBlue = pModel.getBlue(paletteIndex);
|
||||
break;
|
||||
case 0x01:// MODIFY BLUE
|
||||
lastBlue = (lastBlue & colorMask) | (paletteIndex << indexShift);
|
||||
break;
|
||||
case 0x02:// MODIFY RED
|
||||
lastRed = (lastRed & colorMask) | (paletteIndex << indexShift);
|
||||
break;
|
||||
case 0x03:// MODIFY GREEN
|
||||
lastGreen = (lastGreen & colorMask) | (paletteIndex << indexShift);
|
||||
break;
|
||||
}
|
||||
int offset = (x * 3) + pDestOffset;
|
||||
pDest[2 + offset] = (byte) lastRed;
|
||||
pDest[1 + offset] = (byte) lastGreen;
|
||||
pDest[offset] = (byte) lastBlue;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isHAM() {
|
||||
return mViewPort != null && mViewPort.isHAM();
|
||||
}
|
||||
|
||||
public static void main(String[] pArgs) throws IOException {
|
||||
ImageReader reader = new IFFImageReader(new IFFImageReaderSpi());
|
||||
|
||||
// ImageInputStream input = ImageIO.createImageInputStream(new File(pArgs[0]));
|
||||
ImageInputStream input = new BufferedImageInputStream(ImageIO.createImageInputStream(new File(pArgs[0])));
|
||||
boolean canRead = reader.getOriginatingProvider().canDecodeInput(input);
|
||||
|
||||
System.out.println("Can read: " + canRead);
|
||||
|
||||
if (canRead) {
|
||||
reader.setInput(input);
|
||||
ImageReadParam param = reader.getDefaultReadParam();
|
||||
// param.setSourceRegion(new Rectangle(0, 0, 160, 200));
|
||||
// param.setSourceRegion(new Rectangle(160, 200, 160, 200));
|
||||
// param.setSourceRegion(new Rectangle(80, 100, 160, 200));
|
||||
// param.setDestinationOffset(new Point(80, 100));
|
||||
// param.setSourceSubsampling(3, 3, 0, 0);
|
||||
// param.setSourceBands(new int[]{0, 1, 2});
|
||||
// param.setDestinationBands(new int[]{1, 0, 2});
|
||||
BufferedImage image = reader.read(0, param);
|
||||
System.out.println("image = " + image);
|
||||
|
||||
showIt(image, "");
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions 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 "TwelveMonkeys" nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.imageio.plugins.iff;
|
||||
|
||||
import javax.imageio.ImageReader;
|
||||
import javax.imageio.spi.ImageReaderSpi;
|
||||
import javax.imageio.stream.ImageInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* IFFImageReaderSpi
|
||||
* <p/>
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @version $Id: IFFImageWriterSpi.java,v 1.0 28.feb.2006 19:21:05 haku Exp$
|
||||
*/
|
||||
public class IFFImageReaderSpi extends ImageReaderSpi {
|
||||
|
||||
static IFFImageReaderSpi mSharedInstance;
|
||||
|
||||
/**
|
||||
* Creates an IFFImageReaderSpi
|
||||
*/
|
||||
public IFFImageReaderSpi() {
|
||||
super(
|
||||
"TwelveMonkeys",
|
||||
"2.0",
|
||||
new String[]{"iff", "IFF"},
|
||||
new String[]{"iff", "lbm", "ham", "ham8", "ilbm"},
|
||||
new String[]{"image/iff", "image/x-iff"},
|
||||
"com.twelvemonkeys.imageio.plugins.iff.IFFImageReader",
|
||||
STANDARD_INPUT_TYPE,
|
||||
new String[]{"com.twelvemonkeys.imageio.plugins.iff.IFFImageWriterSpi"},
|
||||
true, null, null, null, null,
|
||||
true, null, null, null, null
|
||||
);
|
||||
|
||||
if (mSharedInstance == null) {
|
||||
mSharedInstance = this;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean canDecodeInput(Object pSource) throws IOException {
|
||||
return pSource instanceof ImageInputStream && canDecode((ImageInputStream) pSource);
|
||||
}
|
||||
|
||||
private static boolean canDecode(ImageInputStream pInput) throws IOException {
|
||||
pInput.mark();
|
||||
|
||||
try {
|
||||
// Is it IFF
|
||||
if (pInput.readInt() == IFF.CHUNK_FORM) {
|
||||
pInput.readInt();// Skip length field
|
||||
|
||||
int type = pInput.readInt();
|
||||
|
||||
// Is it ILBM or PBM
|
||||
if (type == IFF.TYPE_ILBM || type == IFF.TYPE_PBM) {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
finally {
|
||||
pInput.reset();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
public ImageReader createReaderInstance(Object pExtension) throws IOException {
|
||||
return new IFFImageReader(this);
|
||||
}
|
||||
|
||||
public String getDescription(Locale pLocale) {
|
||||
return "Amiga (Electronic Arts) Image Interchange Format (IFF) image reader";
|
||||
}
|
||||
|
||||
public static ImageReaderSpi sharedProvider() {
|
||||
if (mSharedInstance == null) {
|
||||
new IFFImageReaderSpi();
|
||||
}
|
||||
|
||||
return mSharedInstance;
|
||||
}
|
||||
}
|
@@ -0,0 +1,269 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions 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 "TwelveMonkeys" nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.imageio.plugins.iff;
|
||||
|
||||
import com.twelvemonkeys.imageio.ImageWriterBase;
|
||||
import com.twelvemonkeys.imageio.util.IIOUtil;
|
||||
import com.twelvemonkeys.io.FastByteArrayOutputStream;
|
||||
import com.twelvemonkeys.io.enc.EncoderStream;
|
||||
import com.twelvemonkeys.io.enc.PackBitsEncoder;
|
||||
|
||||
import javax.imageio.*;
|
||||
import javax.imageio.metadata.IIOMetadata;
|
||||
import javax.imageio.spi.ImageWriterSpi;
|
||||
import java.awt.*;
|
||||
import java.awt.image.*;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
/**
|
||||
* Writer for Amiga (Electronic Arts) IFF ILBM (InterLeaved BitMap) format.
|
||||
* The IFF format (Interchange File Format) is the standard file format
|
||||
* supported by allmost all image software for the Amiga computer.
|
||||
* <p/>
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @version $Id: IFFImageWriter.java,v 1.0 02.mar.2006 13:32:30 haku Exp$
|
||||
*
|
||||
* @see <a href="http://en.wikipedia.org/wiki/Interchange_File_Format">Wikipedia: IFF</a>
|
||||
* @see <a href="http://en.wikipedia.org/wiki/ILBM">Wikipedia: IFF ILBM</a>
|
||||
*/
|
||||
public class IFFImageWriter extends ImageWriterBase {
|
||||
|
||||
private static final byte[] ANNO_DATA = "Written by TwelveMonkeys IFFImageWriter 1.0 for Java (javax.imageio).".getBytes();
|
||||
|
||||
public IFFImageWriter() {
|
||||
this(null);
|
||||
}
|
||||
|
||||
protected IFFImageWriter(ImageWriterSpi pProvider) {
|
||||
super(pProvider);
|
||||
}
|
||||
|
||||
public IIOMetadata getDefaultImageMetadata(ImageTypeSpecifier imageType, ImageWriteParam param) {
|
||||
throw new UnsupportedOperationException("Method getDefaultImageMetadata not implemented");// TODO: Implement
|
||||
}
|
||||
|
||||
public IIOMetadata convertImageMetadata(IIOMetadata inData, ImageTypeSpecifier imageType, ImageWriteParam param) {
|
||||
throw new UnsupportedOperationException("Method convertImageMetadata not implemented");// TODO: Implement
|
||||
}
|
||||
|
||||
public void write(IIOMetadata pStreamMetadata, IIOImage pImage, ImageWriteParam pParam) throws IOException {
|
||||
assertOutput();
|
||||
|
||||
if (pImage.hasRaster()) {
|
||||
throw new UnsupportedOperationException("Cannot write raster");
|
||||
}
|
||||
|
||||
processImageStarted(0);
|
||||
|
||||
// Prepare image data to be written
|
||||
ByteArrayOutputStream imageData = new FastByteArrayOutputStream(1024);
|
||||
packImageData(imageData, pImage.getRenderedImage(), pParam);
|
||||
|
||||
//System.out.println("Image data: " + imageData.size());
|
||||
|
||||
// Write metadata
|
||||
writeMeta(pImage.getRenderedImage(), imageData.size());
|
||||
|
||||
// Write image data
|
||||
writeBody(imageData);
|
||||
|
||||
processImageComplete();
|
||||
}
|
||||
|
||||
private void writeBody(ByteArrayOutputStream pImageData) throws IOException {
|
||||
mImageOutput.writeInt(IFF.CHUNK_BODY);
|
||||
mImageOutput.writeInt(pImageData.size());
|
||||
|
||||
// NOTE: This is much faster than mOutput.write(pImageData.toByteArray())
|
||||
// as the data array is not duplicated
|
||||
pImageData.writeTo(IIOUtil.createStreamAdapter(mImageOutput));
|
||||
|
||||
if (pImageData.size() % 2 == 0) {
|
||||
mImageOutput.writeByte(0); // PAD
|
||||
}
|
||||
|
||||
// NOTE: Most progress is done in packImageData, however, as we need to
|
||||
// buffer, to write correct size, we defer the last 10 percent until now.
|
||||
processImageProgress(100f);
|
||||
|
||||
mImageOutput.flush();
|
||||
}
|
||||
|
||||
private void packImageData(OutputStream pOutput, RenderedImage pImage, ImageWriteParam pParam) throws IOException {
|
||||
// TODO: Allow param to dictate uncompressed
|
||||
// TODO: Subsample/AOI
|
||||
final boolean compress = shouldCompress(pImage);
|
||||
final OutputStream output = compress ? new EncoderStream(pOutput, new PackBitsEncoder(), true) : pOutput;
|
||||
final ColorModel model = pImage.getColorModel();
|
||||
final Raster raster = pImage.getData();
|
||||
|
||||
final int width = pImage.getWidth();
|
||||
final int height = pImage.getHeight();
|
||||
|
||||
// Store each row of pixels
|
||||
// 0. Loop pr channel
|
||||
// 1. Convert to planar
|
||||
// 2. Perform byteRun1 compression for each plane separately
|
||||
// 3. Write the plane data for each plane
|
||||
|
||||
final int planeWidth = (width + 7) / 8;
|
||||
final byte[] planeData = new byte[8 * planeWidth];
|
||||
final int channels = (model.getPixelSize() + 7) / 8;
|
||||
final int planesPerChannel = channels == 1 ? model.getPixelSize() : 8;
|
||||
int[] pixels = new int[8 * planeWidth];
|
||||
|
||||
// NOTE: I'm a little unsure if this is correct for 4 channel (RGBA)
|
||||
// data, but it is at least consistent with the IFFImageReader for now...
|
||||
for (int y = 0; y < height; y++) {
|
||||
for (int c = 0; c < channels; c++) {
|
||||
pixels = raster.getSamples(0, y, width, 1, c, pixels);
|
||||
|
||||
int pixelPos = 0;
|
||||
int planePos = 0;
|
||||
for (int i = 0; i < planeWidth; i++) {
|
||||
IFFUtil.bitRotateCCW(pixels, pixelPos, 1,
|
||||
planeData, planePos, planeWidth);
|
||||
pixelPos += 8;
|
||||
planePos++;
|
||||
}
|
||||
|
||||
for (int p = 0; p < planesPerChannel; p++) {
|
||||
output.write(planeData, p * planeWidth, planeWidth);
|
||||
|
||||
if (!compress && planeWidth % 2 != 0) {
|
||||
output.write(0); // PAD
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
processImageProgress(y * 90f / height);
|
||||
}
|
||||
|
||||
output.flush();
|
||||
}
|
||||
|
||||
private void writeMeta(RenderedImage pImage, int pBodyLength) throws IOException {
|
||||
// Annotation ANNO chunk, 8 + annoData.length bytes
|
||||
GenericChunk anno = new GenericChunk(IFFUtil.toInt("ANNO".getBytes()), ANNO_DATA);
|
||||
|
||||
ColorModel cm = pImage.getColorModel();
|
||||
IndexColorModel icm = null;
|
||||
|
||||
// Bitmap header BMHD chunk, 8 + 20 bytes
|
||||
// By default, don't compress narrow images
|
||||
int compression = shouldCompress(pImage) ? BMHDChunk.COMPRESSION_BYTE_RUN : BMHDChunk.COMPRESSION_NONE;
|
||||
|
||||
BMHDChunk header;
|
||||
if (cm instanceof IndexColorModel) {
|
||||
//System.out.println("IndexColorModel");
|
||||
icm = (IndexColorModel) cm;
|
||||
int trans = icm.getTransparency() == Transparency.BITMASK ? BMHDChunk.MASK_TRANSPARENT_COLOR : BMHDChunk.MASK_NONE;
|
||||
int transPixel = icm.getTransparency() == Transparency.BITMASK ? icm.getTransparentPixel() : 0;
|
||||
header = new BMHDChunk(pImage.getWidth(), pImage.getHeight(), icm.getPixelSize(),
|
||||
trans, compression, transPixel);
|
||||
}
|
||||
else {
|
||||
//System.out.println(cm.getClass().getName());
|
||||
header = new BMHDChunk(pImage.getWidth(), pImage.getHeight(), cm.getPixelSize(),
|
||||
BMHDChunk.MASK_NONE, compression, 0);
|
||||
}
|
||||
|
||||
// Colormap CMAP chunk, 8 + icm.getMapSize() * 3 bytes (+ 1 optional pad).
|
||||
CMAPChunk cmap = null;
|
||||
if (icm != null) {
|
||||
//System.out.println("CMAP!");
|
||||
cmap = new CMAPChunk(icm);
|
||||
}
|
||||
|
||||
// ILBM(4) + anno(8+len) + header(8+20) + cmap(8+len)? + body(8+len);
|
||||
int size = 4 + 8 + anno.mChunkLength + 28 + 8 + pBodyLength;
|
||||
if (cmap != null) {
|
||||
size += 8 + cmap.mChunkLength;
|
||||
}
|
||||
|
||||
mImageOutput.writeInt(IFF.CHUNK_FORM);
|
||||
mImageOutput.writeInt(size);
|
||||
|
||||
mImageOutput.writeInt(IFF.TYPE_ILBM);
|
||||
|
||||
anno.writeChunk(mImageOutput);
|
||||
header.writeChunk(mImageOutput);
|
||||
if (cmap != null) {
|
||||
//System.out.println("CMAP written");
|
||||
cmap.writeChunk(mImageOutput);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private boolean shouldCompress(RenderedImage pImage) {
|
||||
return pImage.getWidth() >= 32;
|
||||
}
|
||||
|
||||
public static void main(String[] pArgs) throws IOException {
|
||||
BufferedImage image = ImageIO.read(new File(pArgs[0]));
|
||||
|
||||
ImageWriter writer = new IFFImageWriter(new IFFImageWriterSpi());
|
||||
writer.setOutput(ImageIO.createImageOutputStream(new File(pArgs[1])));
|
||||
//writer.addIIOWriteProgressListener(new ProgressListenerBase() {
|
||||
// int mCurrPct = 0;
|
||||
//
|
||||
// public void imageComplete(ImageWriter pSource) {
|
||||
// mCurrPct = 100;
|
||||
// printProgress(mCurrPct);
|
||||
// }
|
||||
//
|
||||
// public void imageProgress(ImageWriter pSource, float pPercentageDone) {
|
||||
// if ((int) pPercentageDone > mCurrPct) {
|
||||
// printProgress((int) pPercentageDone);
|
||||
// mCurrPct = (int) pPercentageDone;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// private void printProgress(int pCurrPct) {
|
||||
// if (mCurrPct == 0) {
|
||||
// System.out.print("[");
|
||||
// }
|
||||
// for (int i = mCurrPct / 2; i < pCurrPct / 2; i++) {
|
||||
// System.out.print(".");
|
||||
// }
|
||||
// if (mCurrPct == 100) {
|
||||
// System.out.println("]");
|
||||
// }
|
||||
// }
|
||||
//});
|
||||
|
||||
//image = com.twelvemonkeys.image.ImageUtil.toBuffered(image, BufferedImage.TYPE_INT_ARGB);
|
||||
|
||||
writer.write(image);
|
||||
}
|
||||
}
|
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions 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 "TwelveMonkeys" nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.imageio.plugins.iff;
|
||||
|
||||
import javax.imageio.ImageTypeSpecifier;
|
||||
import javax.imageio.ImageWriter;
|
||||
import javax.imageio.spi.ImageWriterSpi;
|
||||
import java.io.IOException;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* IFFImageWriterSpi
|
||||
* <p/>
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @version $Id: IFFImageWriterSpi.java,v 1.0 02.mar.2006 19:21:05 haku Exp$
|
||||
*/
|
||||
public class IFFImageWriterSpi extends ImageWriterSpi {
|
||||
|
||||
/**
|
||||
* Creates an IFFImageWriterSpi
|
||||
*/
|
||||
public IFFImageWriterSpi() {
|
||||
super(
|
||||
"TwelveMonkeys",
|
||||
"$Revision: 1.0 $",
|
||||
new String[]{"iff", "IFF"},
|
||||
new String[]{"iff", "lbm", "ham", "ham8", "ilbm"},
|
||||
new String[]{"image/iff", "image/x-iff"},
|
||||
"com.twelvemonkeys.imageio.plugins.iff.IFFImageWriter",
|
||||
STANDARD_OUTPUT_TYPE,
|
||||
new String[]{"com.twelvemonkeys.imageio.plugins.iff.IFFImageReaderSpi"},
|
||||
true, null, null, null, null,
|
||||
true, null, null, null, null
|
||||
);
|
||||
}
|
||||
|
||||
public boolean canEncodeImage(ImageTypeSpecifier pType) {
|
||||
// TODO: Probably can't store 16 bit types etc...
|
||||
return true;
|
||||
}
|
||||
|
||||
public ImageWriter createWriterInstance(Object pExtension) throws IOException {
|
||||
return new IFFImageWriter(this);
|
||||
}
|
||||
|
||||
public String getDescription(Locale pLocale) {
|
||||
return "Amiga (Electronic Arts) IFF image writer";
|
||||
}
|
||||
}
|
@@ -0,0 +1,255 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions 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 "TwelveMonkeys" nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
/*
|
||||
* Fast 90-degree bit rotation routines.
|
||||
*
|
||||
* Based on Sue-Ken Yap, "A Fast 90-Degree Bitmap Rotator," in GRAPHICS
|
||||
* GEMS II, James Arvo ed., Academic Press, 1991, ISBN 0-12-064480-0.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.imageio.plugins.iff;
|
||||
|
||||
/**
|
||||
* IFFUtil
|
||||
* <p/>
|
||||
* Bit rotate methods based on Sue-Ken Yap, "A Fast 90-Degree Bitmap Rotator,"
|
||||
* in GRAPHICS GEMS II, James Arvo ed., Academic Press, 1991, ISBN 0-12-064480-0.
|
||||
*
|
||||
* @author Unascribed (C version)
|
||||
* @author Harald Kuhr (Java port)
|
||||
* @version $Id: IFFUtil.java,v 1.0 06.mar.2006 13:31:35 haku Exp$
|
||||
*/
|
||||
class IFFUtil {
|
||||
|
||||
/**
|
||||
* Creates a rotation table
|
||||
* @param n
|
||||
*
|
||||
* @return the rotation table
|
||||
*/
|
||||
static private long[] rtable(int n) {
|
||||
return new long[]{
|
||||
0x00000000l << n, 0x00000001l << n, 0x00000100l << n, 0x00000101l << n,
|
||||
0x00010000l << n, 0x00010001l << n, 0x00010100l << n, 0x00010101l << n,
|
||||
0x01000000l << n, 0x01000001l << n, 0x01000100l << n, 0x01000101l << n,
|
||||
0x01010000l << n, 0x01010001l << n, 0x01010100l << n, 0x01010101l << n};
|
||||
}
|
||||
|
||||
static private final long[][] RTABLE = {
|
||||
rtable(0), rtable(1), rtable(2), rtable(3),
|
||||
rtable(4), rtable(5), rtable(6), rtable(7)
|
||||
};
|
||||
|
||||
/**
|
||||
* Rotate bits clockwise.
|
||||
* The IFFImageReader uses this to convert pixel bits from planar to chunky.
|
||||
* Bits from the source are rotated 90 degrees clockwise written to the
|
||||
* destination.
|
||||
*
|
||||
* @param pSrc source pixel data
|
||||
* @param pSrcPos starting index of 8 x 8 bit source tile
|
||||
* @param pSrcStep byte offset between adjacent rows in source
|
||||
* @param pDst destination pixel data
|
||||
* @param pDstPos starting index of 8 x 8 bit destination tile
|
||||
* @param pDstStep byte offset between adjacent rows in destination
|
||||
*/
|
||||
static void bitRotateCW(final byte[] pSrc, int pSrcPos, int pSrcStep,
|
||||
final byte[] pDst, int pDstPos, int pDstStep) {
|
||||
int idx = pSrcPos;
|
||||
|
||||
int lonyb;
|
||||
int hinyb;
|
||||
long lo = 0;
|
||||
long hi = 0;
|
||||
|
||||
for (int i = 0; i < 8; i++) {
|
||||
lonyb = pSrc[idx] & 0xF;
|
||||
hinyb = (pSrc[idx] >> 4) & 0xF;
|
||||
lo |= RTABLE[i][lonyb];
|
||||
hi |= RTABLE[i][hinyb];
|
||||
idx += pSrcStep;
|
||||
}
|
||||
|
||||
idx = pDstPos;
|
||||
|
||||
pDst[idx] = (byte)((hi >> 24) & 0xFF);
|
||||
idx += pDstStep;
|
||||
if (idx < pDst.length) {
|
||||
pDst[idx] = (byte)((hi >> 16) & 0xFF);
|
||||
idx += pDstStep;
|
||||
if (idx < pDst.length) {
|
||||
pDst[idx] = (byte)((hi >> 8) & 0xFF);
|
||||
idx += pDstStep;
|
||||
if (idx < pDst.length) {
|
||||
pDst[idx] = (byte)(hi & 0xFF);
|
||||
idx += pDstStep;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (idx < pDst.length) {
|
||||
pDst[idx] = (byte)((lo >> 24) & 0xFF);
|
||||
idx += pDstStep;
|
||||
if (idx < pDst.length) {
|
||||
pDst[idx] = (byte)((lo >> 16) & 0xFF);
|
||||
idx += pDstStep;
|
||||
if (idx < pDst.length) {
|
||||
pDst[idx] = (byte)((lo >> 8) & 0xFF);
|
||||
idx += pDstStep;
|
||||
if (idx < pDst.length) {
|
||||
pDst[idx] = (byte)(lo & 0xFF);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Rotate bits counterclockwise.
|
||||
* The IFFImageWriter uses this to convert pixel bits from chunky to planar.
|
||||
*
|
||||
* @param pSrc source pixel data (only lower 8 bits used)
|
||||
* @param pSrcPos starting index of 8 x 8 bit source tile
|
||||
* @param pSrcStep byte offset between adjacent rows in source
|
||||
* @param pDst destination pixel data
|
||||
* @param pDstPos starting index of 8 x 8 bit destination tile
|
||||
* @param pDstStep byte offset between adjacent rows in destination
|
||||
*/
|
||||
static void bitRotateCCW(final int[] pSrc, int pSrcPos, int pSrcStep,
|
||||
final byte[] pDst, int pDstPos, int pDstStep) {
|
||||
int idx = pSrcPos;
|
||||
|
||||
int lonyb;
|
||||
int hinyb;
|
||||
long lo = 0;
|
||||
long hi = 0;
|
||||
|
||||
for (int i = 7; i >= 0; i--) {
|
||||
lonyb = pSrc[idx] & 0xF;
|
||||
hinyb = (pSrc[idx] >> 4) & 0xF;
|
||||
lo |= RTABLE[i][lonyb];
|
||||
hi |= RTABLE[i][hinyb];
|
||||
idx += pSrcStep;
|
||||
}
|
||||
|
||||
idx = pDstPos;
|
||||
|
||||
pDst[idx] = (byte)(lo & 0xFF);
|
||||
idx += pDstStep;
|
||||
pDst[idx] = (byte)((lo >> 8) & 0xFF);
|
||||
idx += pDstStep;
|
||||
pDst[idx] = (byte)((lo >> 16) & 0xFF);
|
||||
idx += pDstStep;
|
||||
pDst[idx] = (byte)((lo >> 24) & 0xFF);
|
||||
|
||||
idx += pDstStep;
|
||||
|
||||
pDst[idx] = (byte)(hi & 0xFF);
|
||||
idx += pDstStep;
|
||||
pDst[idx] = (byte)((hi >> 8) & 0xFF);
|
||||
idx += pDstStep;
|
||||
pDst[idx] = (byte)((hi >> 16) & 0xFF);
|
||||
idx += pDstStep;
|
||||
pDst[idx] = (byte)((hi >> 24) & 0xFF);
|
||||
}
|
||||
|
||||
/**
|
||||
* Rotate bits counterclockwise.
|
||||
* The IFFImageWriter uses this to convert pixel bits from chunky to planar.
|
||||
*
|
||||
* @param pSrc source pixel data
|
||||
* @param pSrcPos starting index of 8 x 8 bit source tile
|
||||
* @param pSrcStep byte offset between adjacent rows in source
|
||||
* @param pDst destination pixel data
|
||||
* @param pDstPos starting index of 8 x 8 bit destination tile
|
||||
* @param pDstStep byte offset between adjacent rows in destination
|
||||
*/
|
||||
static void bitRotateCCW(final byte[] pSrc, int pSrcPos, int pSrcStep,
|
||||
final byte[] pDst, int pDstPos, int pDstStep) {
|
||||
int idx = pSrcPos;
|
||||
|
||||
int lonyb;
|
||||
int hinyb;
|
||||
long lo = 0;
|
||||
long hi = 0;
|
||||
|
||||
for (int i = 7; i >= 0; i--) {
|
||||
lonyb = pSrc[idx] & 0xF;
|
||||
hinyb = (pSrc[idx] >> 4) & 0xF;
|
||||
lo |= RTABLE[i][lonyb];
|
||||
hi |= IFFUtil.RTABLE[i][hinyb];
|
||||
idx += pSrcStep;
|
||||
}
|
||||
|
||||
idx = pDstPos;
|
||||
|
||||
pDst[idx] = (byte)(lo & 0xFF);
|
||||
idx += pDstStep;
|
||||
pDst[idx] = (byte)((lo >> 8) & 0xFF);
|
||||
idx += pDstStep;
|
||||
pDst[idx] = (byte)((lo >> 16) & 0xFF);
|
||||
idx += pDstStep;
|
||||
pDst[idx] = (byte)((lo >> 24) & 0xFF);
|
||||
|
||||
idx += pDstStep;
|
||||
|
||||
pDst[idx] = (byte)(hi & 0xFF);
|
||||
idx += pDstStep;
|
||||
pDst[idx] = (byte)((hi >> 8) & 0xFF);
|
||||
idx += pDstStep;
|
||||
pDst[idx] = (byte)((hi >> 16) & 0xFF);
|
||||
idx += pDstStep;
|
||||
pDst[idx] = (byte)((hi >> 24) & 0xFF);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a byte array to an int.
|
||||
*
|
||||
* @param pBytes a byte array of length 4
|
||||
* @return the bytes converted to an int
|
||||
*
|
||||
* @throws ArrayIndexOutOfBoundsException if length is < 4
|
||||
*/
|
||||
static int toInt(final byte[] pBytes) {
|
||||
return (pBytes[0] & 0xff) << 24 | (pBytes[1] & 0xff) << 16
|
||||
| (pBytes[2] & 0xff) << 8 | (pBytes[3] & 0xff);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an int to a four letter String.
|
||||
*
|
||||
* @param pChunkId
|
||||
* @return a String
|
||||
*/
|
||||
static String toChunkStr(int pChunkId) {
|
||||
return new String(new byte[] {(byte) ((pChunkId & 0xff000000) >> 24),
|
||||
(byte) ((pChunkId & 0x00ff0000) >> 16),
|
||||
(byte) ((pChunkId & 0x0000ff00) >> 8),
|
||||
(byte) ((pChunkId & 0x000000ff))});
|
||||
}
|
||||
}
|
@@ -0,0 +1 @@
|
||||
com.twelvemonkeys.imageio.plugins.iff.IFFImageReaderSpi
|
@@ -0,0 +1 @@
|
||||
com.twelvemonkeys.imageio.plugins.iff.IFFImageWriterSpi
|
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions 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 "TwelveMonkeys" nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.imageio.plugins.iff;
|
||||
|
||||
import com.twelvemonkeys.imageio.util.ImageReaderAbstractTestCase;
|
||||
|
||||
import javax.imageio.spi.ImageReaderSpi;
|
||||
import java.awt.*;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* IFFImageReaderTestCase
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haraldk$
|
||||
* @version $Id: IFFImageReaderTestCase.java,v 1.0 Apr 1, 2008 10:39:17 PM haraldk Exp$
|
||||
*/
|
||||
public class IFFImageReaderTestCase extends ImageReaderAbstractTestCase<IFFImageReader> {
|
||||
// TODO: Need test for IFF PBM
|
||||
protected List<TestData> getTestData() {
|
||||
return Arrays.asList(
|
||||
// 32 bit - Ok
|
||||
new TestData(getClassLoaderResource("/iff/test.iff"), new Dimension(300, 200)), // 32 bit
|
||||
// 24 bit - Ok
|
||||
new TestData(getClassLoaderResource("/iff/survivor.iff"), new Dimension(800, 600)), // 24 bit
|
||||
// HAM6 - Ok (a lot of visual "fringe", would be interesting to see on a real HAM display)
|
||||
new TestData(getClassLoaderResource("/iff/A4000T_HAM6.IFF"), new Dimension(320, 512)), // ham6
|
||||
// HAM8 - Passes tests, but visuals are trashed. Have other HAM8 files that are ok
|
||||
new TestData(getClassLoaderResource("/iff/A4000T_HAM8.IFF"), new Dimension(628, 512)), // ham8
|
||||
// 8 color indexed - Passes tests, but trashed. Must be something special with these images
|
||||
new TestData(getClassLoaderResource("/iff/AmigaBig.iff"), new Dimension(300, 200)), // 8 color
|
||||
// 8 color indexed - Ok
|
||||
new TestData(getClassLoaderResource("/iff/AmigaAmiga.iff"), new Dimension(200, 150)), // 8 color
|
||||
// Breaks completely... Could be bug in the packbits decoder?
|
||||
new TestData(getClassLoaderResource("/iff/Abyss.iff"), new Dimension(320, 400))
|
||||
);
|
||||
}
|
||||
|
||||
protected ImageReaderSpi createProvider() {
|
||||
return new IFFImageReaderSpi();
|
||||
}
|
||||
|
||||
protected Class<IFFImageReader> getReaderClass() {
|
||||
return IFFImageReader.class;
|
||||
}
|
||||
|
||||
protected List<String> getFormatNames() {
|
||||
return Arrays.asList("iff");
|
||||
}
|
||||
|
||||
protected List<String> getSuffixes() {
|
||||
return Arrays.asList("iff", "ilbm", "ham", "ham8", "lbm");
|
||||
}
|
||||
|
||||
protected List<String> getMIMETypes() {
|
||||
return Arrays.asList("image/iff", "image/x-iff");
|
||||
}
|
||||
}
|
BIN
twelvemonkeys-imageio/iff/src/test/resources/iff/A4000T_HAM6.IFF
Executable file
BIN
twelvemonkeys-imageio/iff/src/test/resources/iff/A4000T_HAM6.IFF
Executable file
Binary file not shown.
BIN
twelvemonkeys-imageio/iff/src/test/resources/iff/A4000T_HAM8.IFF
Executable file
BIN
twelvemonkeys-imageio/iff/src/test/resources/iff/A4000T_HAM8.IFF
Executable file
Binary file not shown.
BIN
twelvemonkeys-imageio/iff/src/test/resources/iff/Abyss.iff
Executable file
BIN
twelvemonkeys-imageio/iff/src/test/resources/iff/Abyss.iff
Executable file
Binary file not shown.
BIN
twelvemonkeys-imageio/iff/src/test/resources/iff/AmigaAmiga.iff
Executable file
BIN
twelvemonkeys-imageio/iff/src/test/resources/iff/AmigaAmiga.iff
Executable file
Binary file not shown.
BIN
twelvemonkeys-imageio/iff/src/test/resources/iff/AmigaBig.iff
Executable file
BIN
twelvemonkeys-imageio/iff/src/test/resources/iff/AmigaBig.iff
Executable file
Binary file not shown.
BIN
twelvemonkeys-imageio/iff/src/test/resources/iff/survivor.iff
Executable file
BIN
twelvemonkeys-imageio/iff/src/test/resources/iff/survivor.iff
Executable file
Binary file not shown.
BIN
twelvemonkeys-imageio/iff/src/test/resources/iff/test.iff
Executable file
BIN
twelvemonkeys-imageio/iff/src/test/resources/iff/test.iff
Executable file
Binary file not shown.
4
twelvemonkeys-imageio/iff/todo.txt
Executable file
4
twelvemonkeys-imageio/iff/todo.txt
Executable file
@@ -0,0 +1,4 @@
|
||||
- Fix the crashes with "java.io.EOFException: Unexpected end of PackBits stream"
|
||||
- Fix the bugs with trashed images
|
||||
- Have a look at Werner Randelshofer's ANIM applet, maybe we can "borrow" the the ANIM support. :-)
|
||||
DONE:
|
Reference in New Issue
Block a user