diff --git a/imageio/imageio-iff/src/main/java/com/twelvemonkeys/imageio/plugins/iff/AbstractMultipaletteChunk.java b/imageio/imageio-iff/src/main/java/com/twelvemonkeys/imageio/plugins/iff/AbstractMultipaletteChunk.java
new file mode 100644
index 00000000..29cec373
--- /dev/null
+++ b/imageio/imageio-iff/src/main/java/com/twelvemonkeys/imageio/plugins/iff/AbstractMultipaletteChunk.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2012, 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.
+ */
+/*
+ * Parts of this code is based on ilbmtoppm.c
+ *
+ * Copyright (C) 1989 by Jef Poskanzer.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose and without fee is hereby granted, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation. This software is provided "as is" without express or
+ * implied warranty.
+ *
+ * Multipalette-support by Ingo Wilken (Ingo.Wilken@informatik.uni-oldenburg.de)
+ */
+
+package com.twelvemonkeys.imageio.plugins.iff;
+
+import java.awt.image.ColorModel;
+import java.awt.image.IndexColorModel;
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import java.lang.ref.WeakReference;
+
+/**
+ * AbstractMultiPaletteChunk
+ *
+ * @author Harald Kuhr
+ * @author last modified by $Author: haraldk$
+ * @version $Id: AbstractMultiPaletteChunk.java,v 1.0 30.03.12 15:57 haraldk Exp$
+ */
+abstract class AbstractMultiPaletteChunk extends IFFChunk implements MultiPalette {
+ /* scale factor maxval 15 -> maxval 255 */
+ static final int FACTOR_4BIT = 17;
+
+ protected MutableIndexColorModel.PaletteChange[] initialChanges;
+ protected MutableIndexColorModel.PaletteChange[][] changes;
+
+ protected WeakReference originalPalette;
+ protected MutableIndexColorModel mutablePalette;
+
+ public AbstractMultiPaletteChunk(int pChunkId, int pChunkLength) {
+ super(pChunkId, pChunkLength);
+ }
+
+ @Override
+ void readChunk(final DataInput pInput) throws IOException {
+ if (chunkId == IFF.CHUNK_SHAM) {
+ pInput.readUnsignedShort(); // Version, typically 0, skipped
+ }
+
+ int rows = chunkLength / 32; /* sizeof(word) * 16 */
+
+ changes = new MutableIndexColorModel.PaletteChange[rows][];
+
+ for (int row = 0; row < rows; row++) {
+ changes[row] = new MutableIndexColorModel.PaletteChange[16];
+
+ for (int i = 0; i < 16; i++) {
+ changes[row][i] = new MutableIndexColorModel.PaletteChange();
+ }
+
+ for (int i = 0; i < 16; i++ ) {
+ int data = pInput.readUnsignedShort();
+
+ changes[row][i].index = i;
+ changes[row][i].r = (byte) (((data & 0x0f00) >> 8) * FACTOR_4BIT);
+ changes[row][i].g = (byte) (((data & 0x00f0) >> 4) * FACTOR_4BIT);
+ changes[row][i].b = (byte) (((data & 0x000f) ) * FACTOR_4BIT);
+ }
+ }
+ }
+
+ @Override
+ void writeChunk(DataOutput pOutput) throws IOException {
+ throw new UnsupportedOperationException("Method writeChunk not implemented");
+ }
+
+
+ public ColorModel getColorModel(final IndexColorModel colorModel, final int rowIndex, final boolean laced) {
+ if (mutablePalette == null || originalPalette != null && originalPalette.get() != colorModel) {
+ originalPalette = new WeakReference(colorModel);
+ mutablePalette = new MutableIndexColorModel(colorModel);
+
+ if (initialChanges != null) {
+ mutablePalette.adjustColorMap(initialChanges);
+ }
+ }
+
+ int row = laced && skipLaced() ? rowIndex / 2 : rowIndex;
+ if (row < changes.length && changes[row] != null) {
+ mutablePalette.adjustColorMap(changes[row]);
+ }
+
+ return mutablePalette;
+ }
+
+ protected boolean skipLaced() {
+ return false;
+ }
+}
diff --git a/imageio/imageio-iff/src/main/java/com/twelvemonkeys/imageio/plugins/iff/BMHDChunk.java b/imageio/imageio-iff/src/main/java/com/twelvemonkeys/imageio/plugins/iff/BMHDChunk.java
index 7442108a..a784699f 100755
--- a/imageio/imageio-iff/src/main/java/com/twelvemonkeys/imageio/plugins/iff/BMHDChunk.java
+++ b/imageio/imageio-iff/src/main/java/com/twelvemonkeys/imageio/plugins/iff/BMHDChunk.java
@@ -40,7 +40,7 @@ import java.io.IOException;
* @author Harald Kuhr
* @version $Id: BMHDChunk.java,v 1.0 28.feb.2006 00:04:32 haku Exp$
*/
-class BMHDChunk extends IFFChunk {
+final class BMHDChunk extends IFFChunk {
//
// typedef UBYTE Masking; /* Choice of masking technique. */
//
diff --git a/imageio/imageio-iff/src/main/java/com/twelvemonkeys/imageio/plugins/iff/BODYChunk.java b/imageio/imageio-iff/src/main/java/com/twelvemonkeys/imageio/plugins/iff/BODYChunk.java
index 0e94d910..42a5bbf7 100755
--- a/imageio/imageio-iff/src/main/java/com/twelvemonkeys/imageio/plugins/iff/BODYChunk.java
+++ b/imageio/imageio-iff/src/main/java/com/twelvemonkeys/imageio/plugins/iff/BODYChunk.java
@@ -39,7 +39,7 @@ import java.io.DataOutput;
* @author Harald Kuhr
* @version $Id: BODYChunk.java,v 1.0 28.feb.2006 01:25:49 haku Exp$
*/
-class BODYChunk extends IFFChunk {
+final class BODYChunk extends IFFChunk {
protected BODYChunk(int pChunkLength) {
super(IFF.CHUNK_BODY, pChunkLength);
}
diff --git a/imageio/imageio-iff/src/main/java/com/twelvemonkeys/imageio/plugins/iff/CAMGChunk.java b/imageio/imageio-iff/src/main/java/com/twelvemonkeys/imageio/plugins/iff/CAMGChunk.java
index e42ee11d..a2e6818f 100755
--- a/imageio/imageio-iff/src/main/java/com/twelvemonkeys/imageio/plugins/iff/CAMGChunk.java
+++ b/imageio/imageio-iff/src/main/java/com/twelvemonkeys/imageio/plugins/iff/CAMGChunk.java
@@ -40,7 +40,7 @@ import java.io.IOException;
* @author Harald Kuhr
* @version $Id: CAMGChunk.java,v 1.0 28.feb.2006 02:10:07 haku Exp$
*/
-class CAMGChunk extends IFFChunk {
+final class CAMGChunk extends IFFChunk {
// HIRES=0x8000, LACE=0x4
// #define CAMG_HAM 0x800 /* hold and modify */
// #define CAMG_EHB 0x80 /* extra halfbrite */
@@ -55,6 +55,7 @@ class CAMGChunk extends IFFChunk {
if (chunkLength != 4) {
throw new IIOException("Unknown CAMG chunk length: " + chunkLength);
}
+
camg = pInput.readInt();
}
@@ -62,6 +63,14 @@ class CAMGChunk extends IFFChunk {
throw new InternalError("Not implemented: writeChunk()");
}
+ boolean isHires() {
+ return (camg & 0x8000) != 0;
+ }
+
+ boolean isLaced() {
+ return (camg & 0x4) != 0;
+ }
+
boolean isHAM() {
return (camg & 0x800) != 0;
}
diff --git a/imageio/imageio-iff/src/main/java/com/twelvemonkeys/imageio/plugins/iff/CMAPChunk.java b/imageio/imageio-iff/src/main/java/com/twelvemonkeys/imageio/plugins/iff/CMAPChunk.java
index 4171e524..eeb8d19c 100755
--- a/imageio/imageio-iff/src/main/java/com/twelvemonkeys/imageio/plugins/iff/CMAPChunk.java
+++ b/imageio/imageio-iff/src/main/java/com/twelvemonkeys/imageio/plugins/iff/CMAPChunk.java
@@ -45,7 +45,7 @@ import java.io.IOException;
* @author Harald Kuhr
* @version $Id: CMAPChunk.java,v 1.0 28.feb.2006 00:38:05 haku Exp$
*/
-class CMAPChunk extends IFFChunk {
+final class CMAPChunk extends IFFChunk {
// typedef struct {
// UBYTE red, green, blue; /* color intensities 0..255 */
diff --git a/imageio/imageio-iff/src/main/java/com/twelvemonkeys/imageio/plugins/iff/CTBLChunk.java b/imageio/imageio-iff/src/main/java/com/twelvemonkeys/imageio/plugins/iff/CTBLChunk.java
new file mode 100644
index 00000000..6062518f
--- /dev/null
+++ b/imageio/imageio-iff/src/main/java/com/twelvemonkeys/imageio/plugins/iff/CTBLChunk.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2012, 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;
+
+/**
+ * CTBLChunk
+ *
+ * @author Harald Kuhr
+ * @author last modified by $Author: haraldk$
+ * @version $Id: CTBLChunk.java,v 1.0 30.03.12 14:53 haraldk Exp$
+ */
+final class CTBLChunk extends AbstractMultiPaletteChunk {
+ protected CTBLChunk(int pChunkLength) {
+ super(IFF.CHUNK_CTBL, pChunkLength);
+ }
+}
diff --git a/imageio/imageio-iff/src/main/java/com/twelvemonkeys/imageio/plugins/iff/GRABChunk.java b/imageio/imageio-iff/src/main/java/com/twelvemonkeys/imageio/plugins/iff/GRABChunk.java
index efaa0015..bf69b27b 100755
--- a/imageio/imageio-iff/src/main/java/com/twelvemonkeys/imageio/plugins/iff/GRABChunk.java
+++ b/imageio/imageio-iff/src/main/java/com/twelvemonkeys/imageio/plugins/iff/GRABChunk.java
@@ -42,7 +42,7 @@ import java.io.IOException;
* @author Harald Kuhr
* @version $Id: GRABChunk.java,v 1.0 28.feb.2006 01:55:05 haku Exp$
*/
-class GRABChunk extends IFFChunk {
+final class GRABChunk extends IFFChunk {
// typedef struct {
// WORD x, y; /* relative coordinates (pixels) */
// } Point2D;
diff --git a/imageio/imageio-iff/src/main/java/com/twelvemonkeys/imageio/plugins/iff/GenericChunk.java b/imageio/imageio-iff/src/main/java/com/twelvemonkeys/imageio/plugins/iff/GenericChunk.java
index bb63d20d..78b5f3a1 100755
--- a/imageio/imageio-iff/src/main/java/com/twelvemonkeys/imageio/plugins/iff/GenericChunk.java
+++ b/imageio/imageio-iff/src/main/java/com/twelvemonkeys/imageio/plugins/iff/GenericChunk.java
@@ -39,7 +39,7 @@ import java.io.DataOutput;
* @author Harald Kuhr
* @version $Id: UnknownChunk.java,v 1.0 28.feb.2006 00:53:47 haku Exp$
*/
-class GenericChunk extends IFFChunk {
+final class GenericChunk extends IFFChunk {
byte[] data;
@@ -56,15 +56,7 @@ class GenericChunk extends IFFChunk {
void readChunk(DataInput pInput) throws IOException {
pInput.readFully(data, 0, data.length);
- int toSkip = chunkLength - data.length;
- while (toSkip > 0) {
- toSkip -= pInput.skipBytes(toSkip);
- }
-
- // Read pad
- if (chunkLength % 2 != 0) {
- pInput.readByte();
- }
+ skipData(pInput, chunkLength, data.length);
}
void writeChunk(DataOutput pOutput) throws IOException {
diff --git a/imageio/imageio-iff/src/main/java/com/twelvemonkeys/imageio/plugins/iff/IFF.java b/imageio/imageio-iff/src/main/java/com/twelvemonkeys/imageio/plugins/iff/IFF.java
index 504d5aa9..c9185d79 100755
--- a/imageio/imageio-iff/src/main/java/com/twelvemonkeys/imageio/plugins/iff/IFF.java
+++ b/imageio/imageio-iff/src/main/java/com/twelvemonkeys/imageio/plugins/iff/IFF.java
@@ -39,12 +39,22 @@ interface IFF {
/** IFF FORM group chunk */
int CHUNK_FORM = ('F' << 24) + ('O' << 16) + ('R' << 8) + 'M';
- /** IFF ILBM form type */
+ /** IFF ILBM form type (Interleaved bitmap) */
int TYPE_ILBM = ('I' << 24) + ('L' << 16) + ('B' << 8) + 'M';
- /** IFF PBM form type */
+ /** IFF PBM form type (Packed bitmap) */
int TYPE_PBM = ('P' << 24) + ('B' << 16) + ('M' << 8) + ' ';
+ // TODO:
+ /** IFF DEEP form type (TVPaint) */
+ int TYPE_DEEP = ('D' << 24) + ('E' << 16) + ('E' << 8) + 'P';
+ /** IFF RGB8 form type (TurboSilver) */
+ int TYPE_RGB8 = ('R' << 24) + ('G' << 16) + ('B' << 8) + '8';
+ /** IFF RGBN form type (TurboSilver) */
+ int TYPE_RGBN = ('R' << 24) + ('G' << 16) + ('B' << 8) + 'N';
+ /** IFF ACBM form type (Amiga Basic) */
+ int TYPE_ACBM = ('A' << 24) + ('C' << 16) + ('B' << 8) + 'M';
+
/** Bitmap Header chunk */
int CHUNK_BMHD = ('B' << 24) + ('M' << 16) + ('H' << 8) + 'D';
@@ -65,4 +75,53 @@ interface IFF {
/** Main data (body) chunk */
int CHUNK_BODY = ('B' << 24) + ('O' << 16) + ('D' << 8) + 'Y';
+
+ /** Junk (to allow garbage data in files, without re-writing the entire file) */
+ int CHUNK_JUNK = ('J' << 24) + ('U' << 16) + ('N' << 8) + 'K';
+
+ /** EA IFF 85 Generic Author chunk */
+ int CHUNK_AUTH = ('A' << 24) + ('U' << 16) + ('T' << 8) + 'H';
+ /** EA IFF 85 Generic character string chunk */
+ int CHUNK_CHRS = ('C' << 24) + ('H' << 16) + ('R' << 8) + 'S';
+ /** EA IFF 85 Generic Name of art, music, etc. chunk */
+ int CHUNK_NAME = ('N' << 24) + ('A' << 16) + ('M' << 8) + 'E';
+ /** EA IFF 85 Generic unformatted ASCII text chunk */
+ int CHUNK_TEXT = ('T' << 24) + ('E' << 16) + ('X' << 8) + 'T';
+ /** EA IFF 85 Generic Copyright text chunk */
+ int CHUNK_COPY = ('(' << 24) + ('c' << 16) + (')' << 8) + ' ';
+
+ /** color cycling */
+ int CHUNK_CRNG = ('C' << 24) + ('R' << 16) + ('N' << 8) + 'G';
+ /** color cycling */
+ int CHUNK_CCRT = ('C' << 24) + ('C' << 16) + ('R' << 8) + 'T';
+ /** Color Lookup Table chunk */
+ int CHUNK_CLUT = ('C' << 24) + ('L' << 16) + ('U' << 8) + 'T';
+ /** Dots per inch chunk */
+ int CHUNK_DPI = ('D' << 24) + ('P' << 16) + ('I' << 8) + ' ';
+ /** DPaint perspective chunk (EA) */
+ int CHUNK_DPPV = ('D' << 24) + ('P' << 16) + ('P' << 8) + 'V';
+ /** DPaint IV enhanced color cycle chunk (EA) */
+ int CHUNK_DRNG = ('D' << 24) + ('R' << 16) + ('N' << 8) + 'G';
+ /** Encapsulated Postscript chunk */
+ int CHUNK_EPSF = ('E' << 24) + ('P' << 16) + ('S' << 8) + 'F';
+ /** Cyan, Magenta, Yellow, & Black color map (Soft-Logik) */
+ int CHUNK_CMYK = ('C' << 24) + ('M' << 16) + ('Y' << 8) + 'K';
+ /** Color naming chunk (Soft-Logik) */
+ int CHUNK_CNAM = ('C' << 24) + ('N' << 16) + ('A' << 8) + 'M';
+ /** Line by line palette control information (Sebastiano Vigna) */
+ int CHUNK_PCHG = ('P' << 24) + ('C' << 16) + ('H' << 8) + 'G';
+ /** A mini duplicate ILBM used for preview (Gary Bonham) */
+ int CHUNK_PRVW = ('P' << 24) + ('R' << 16) + ('V' << 8) + 'W';
+ /** eXtended BitMap Information (Soft-Logik) */
+ int CHUNK_XBMI = ('X' << 24) + ('B' << 16) + ('M' << 8) + 'I';
+ /** Newtek Dynamic Ham color chunk */
+ int CHUNK_CTBL = ('C' << 24) + ('T' << 16) + ('B' << 8) + 'L';
+ /** Newtek Dynamic Ham chunk */
+ int CHUNK_DYCP = ('D' << 24) + ('Y' << 16) + ('C' << 8) + 'P';
+ /** Sliced HAM color chunk */
+ int CHUNK_SHAM = ('S' << 24) + ('H' << 16) + ('A' << 8) + 'M';
+ /** ACBM body chunk */
+ int CHUNK_ABIT = ('A' << 24) + ('B' << 16) + ('I' << 8) + 'T';
+ /** unofficial direct color */
+ int CHUNK_DCOL = ('D' << 24) + ('C' << 16) + ('O' << 8) + 'L';
}
diff --git a/imageio/imageio-iff/src/main/java/com/twelvemonkeys/imageio/plugins/iff/IFFChunk.java b/imageio/imageio-iff/src/main/java/com/twelvemonkeys/imageio/plugins/iff/IFFChunk.java
index f3fadd98..1c6b3982 100755
--- a/imageio/imageio-iff/src/main/java/com/twelvemonkeys/imageio/plugins/iff/IFFChunk.java
+++ b/imageio/imageio-iff/src/main/java/com/twelvemonkeys/imageio/plugins/iff/IFFChunk.java
@@ -52,6 +52,19 @@ abstract class IFFChunk {
abstract void writeChunk(DataOutput pOutput) throws IOException;
+ protected static void skipData(final DataInput pInput, final int chunkLength, final int dataReadSoFar) throws IOException {
+ int toSkip = chunkLength - dataReadSoFar;
+
+ while (toSkip > 0) {
+ toSkip -= pInput.skipBytes(toSkip);
+ }
+
+ // Read pad
+ if (chunkLength % 2 != 0) {
+ pInput.readByte();
+ }
+ }
+
public String toString() {
return IFFUtil.toChunkStr(chunkId) + " chunk (" + chunkLength + " bytes)";
}
diff --git a/imageio/imageio-iff/src/main/java/com/twelvemonkeys/imageio/plugins/iff/IFFImageReader.java b/imageio/imageio-iff/src/main/java/com/twelvemonkeys/imageio/plugins/iff/IFFImageReader.java
index 7a42ffd5..dc9446a0 100755
--- a/imageio/imageio-iff/src/main/java/com/twelvemonkeys/imageio/plugins/iff/IFFImageReader.java
+++ b/imageio/imageio-iff/src/main/java/com/twelvemonkeys/imageio/plugins/iff/IFFImageReader.java
@@ -28,6 +28,7 @@
package com.twelvemonkeys.imageio.plugins.iff;
+import com.twelvemonkeys.image.ResampleOp;
import com.twelvemonkeys.imageio.ImageReaderBase;
import com.twelvemonkeys.imageio.stream.BufferedImageInputStream;
import com.twelvemonkeys.imageio.util.IIOUtil;
@@ -94,7 +95,9 @@ public class IFFImageReader extends ImageReaderBase {
// http://home.comcast.net/~erniew/lwsdk/docs/filefmts/ilbm.html
// http://www.fileformat.info/format/iff/spec/7866a9f0e53c42309af667c5da3bd426/view.htm
// - Contains definitions of some "new" chunks, as well as alternative FORM types
- // http://amigan.1emu.net/reg/iff.html
+ // http://amigan.1emu.net/index/iff.html
+
+ // TODO: Allow reading rasters for HAM6/HAM8 and multipalette images that are expanded to RGB (24 bit) during read.
private BMHDChunk header;
private CMAPChunk colorMap;
@@ -102,6 +105,7 @@ public class IFFImageReader extends ImageReaderBase {
@SuppressWarnings({"FieldCanBeLocal"})
private GRABChunk grab;
private CAMGChunk viewPort;
+ private MultiPalette paletteChange;
private int formType;
private long bodyStart;
@@ -127,6 +131,7 @@ public class IFFImageReader extends ImageReaderBase {
protected void resetMembers() {
header = null;
colorMap = null;
+ paletteChange = null;
body = null;
viewPort = null;
formType = 0;
@@ -144,7 +149,7 @@ public class IFFImageReader extends ImageReaderBase {
formType = imageInput.readInt();
if (formType != IFF.TYPE_ILBM && formType != IFF.TYPE_PBM) {
- throw new IIOException("Only IFF (FORM) type ILBM and PBM supported: " + IFFUtil.toChunkStr(formType));
+ throw new IIOException("Only IFF FORM types ILBM and PBM supported: " + IFFUtil.toChunkStr(formType));
}
//System.out.println("IFF type FORM " + toChunkStr(type));
@@ -200,6 +205,57 @@ public class IFFImageReader extends ImageReaderBase {
//System.out.println(viewPort);
break;
+ case IFF.CHUNK_PCHG:
+ if (paletteChange instanceof PCHGChunk) {
+ throw new IIOException("Multiple PCHG chunks not allowed");
+ }
+
+ PCHGChunk pchg = new PCHGChunk(length);
+ pchg.readChunk(imageInput);
+
+ // Always prefer PCHG style palette changes
+ paletteChange = pchg;
+
+// System.out.println(paletteChange);
+ break;
+
+ case IFF.CHUNK_SHAM:
+ if (paletteChange instanceof SHAMChunk) {
+ throw new IIOException("Multiple SHAM chunks not allowed");
+ }
+
+ SHAMChunk sham = new SHAMChunk(length);
+ sham.readChunk(imageInput);
+
+ // NOTE: We prefer PHCG to SHAM style palette changes, if both are present
+ if (paletteChange == null) {
+ paletteChange = sham;
+ }
+
+// System.out.println(paletteChange);
+ break;
+
+ case IFF.CHUNK_CTBL:
+ if (paletteChange instanceof CTBLChunk) {
+ throw new IIOException("Multiple CTBL chunks not allowed");
+ }
+
+ CTBLChunk ctbl = new CTBLChunk(length);
+ ctbl.readChunk(imageInput);
+
+ // NOTE: We prefer PHCG to ctbl style palette changes, if both are present
+ if (paletteChange == null) {
+ paletteChange = ctbl;
+ }
+
+// System.out.println(paletteChange);
+ break;
+
+ case IFF.CHUNK_JUNK:
+ // Always skip junk chunks
+ IFFChunk.skipData(imageInput, length, 0);
+ break;
+
case IFF.CHUNK_BODY:
if (body != null) {
throw new IIOException("Multiple BODY chunks not allowed");
@@ -209,16 +265,15 @@ public class IFFImageReader extends ImageReaderBase {
bodyStart = imageInput.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
+ // TODO: We probably want to store ANNO, TEXT, AUTH, COPY etc chunks as Metadata
+ // SHAM, ANNO, DEST, SPRT and more
IFFChunk generic = new GenericChunk(chunkId, length);
generic.readChunk(imageInput);
- //System.out.println(generic);
+// System.out.println(generic);
break;
}
}
@@ -297,7 +352,7 @@ public class IFFImageReader extends ImageReaderBase {
case 8:
// 8 bit
// May be HAM8
- if (!isHAM()) {
+ if (!isConvertToRGB()) {
if (colorMap != null) {
IndexColorModel cm = colorMap.getIndexColorModel();
specifier = IndexedImageTypeSpecifier.createFromIndexColorModel(cm);
@@ -323,6 +378,10 @@ public class IFFImageReader extends ImageReaderBase {
return specifier;
}
+ private boolean isConvertToRGB() {
+ return isHAM() || isPCHG() || isSHAM();
+ }
+
private void readBody(final ImageReadParam pParam) throws IOException {
imageInput.seek(bodyStart);
byteRunStream = null;
@@ -361,7 +420,7 @@ public class IFFImageReader extends ImageReaderBase {
}
// Ensure band settings from param are compatible with images
- checkReadParamBandSettings(pParam, isHAM() ? 3 : 1, image.getSampleModel().getNumBands());
+ checkReadParamBandSettings(pParam, isConvertToRGB() ? 3 : 1, image.getSampleModel().getNumBands());
WritableRaster destination = image.getRaster();
if (destinationBands != null || offset.x != 0 || offset.y != 0) {
@@ -376,7 +435,7 @@ public class IFFImageReader extends ImageReaderBase {
ColorModel cm;
WritableRaster raster;
- if (isHAM()) {
+ if (isConvertToRGB()) {
// TODO: If HAM6, use type USHORT_444_RGB or 2BYTE_444_RGB?
// Or create a HAMColorModel, if at all possible?
// TYPE_3BYTE_BGR
@@ -398,9 +457,8 @@ public class IFFImageReader extends ImageReaderBase {
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);
+// System.out.println("PlaneData length: " + planeData.length);
+// System.out.println("Row length: " + row.length);
final byte[] data = ((DataBufferByte) raster.getDataBuffer()).getData();
@@ -433,6 +491,12 @@ public class IFFImageReader extends ImageReaderBase {
if (isHAM()) {
hamToRGB(row, pModel, data, 0);
}
+ else if (isConvertToRGB()) {
+ multiPaletteToRGB(srcY, row, pModel, data, 0);
+ }
+ else if (isSHAM()) {
+ throw new UnsupportedOperationException("SHAM not supported (yet)");
+ }
else {
raster.setDataElements(0, 0, width, 1, row);
}
@@ -449,7 +513,7 @@ public class IFFImageReader extends ImageReaderBase {
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
+ // Rasters are compatible, just write to destination
if (sourceXSubsampling == 1) {
destination.setRect(offset.x, dstY, sourceRow);
// dataElements = raster.getDataElements(aoi.x, 0, aoi.width, 1, dataElements);
@@ -609,10 +673,12 @@ public class IFFImageReader extends ImageReaderBase {
switch (header.compressionType) {
case BMHDChunk.COMPRESSION_NONE:
pInput.readFully(pData, pOffset, pPlaneWidth);
+
// Uncompressed rows must have even number of bytes
if ((header.bitplanes * pPlaneWidth) % 2 != 0) {
pInput.readByte();
}
+
break;
case BMHDChunk.COMPRESSION_BYTE_RUN:
@@ -630,6 +696,7 @@ public class IFFImageReader extends ImageReaderBase {
)
);
}
+
byteRunStream.readFully(pData, pOffset, pPlaneWidth);
break;
@@ -638,8 +705,25 @@ public class IFFImageReader extends ImageReaderBase {
}
}
- private void hamToRGB(final byte[] pIndexed, final IndexColorModel pModel,
- final byte[] pDest, final int pDestOffset) {
+ private void multiPaletteToRGB(final int srcY, final byte[] indexed, final IndexColorModel colorModel, final byte[] dest, final int destOffset) {
+ final int width = header.width;
+
+ // TODO: Assure we have applied color change for all rows up until rowIndex, in case of source region/subsampling
+ ColorModel palette = paletteChange.getColorModel(colorModel, srcY, isLaced());
+
+ for (int x = 0; x < width; x++) {
+ int pixel = indexed[x] & 0xff;
+
+ int rgb = palette.getRGB(pixel);
+
+ int offset = (x * 3) + destOffset;
+ dest[2 + offset] = (byte) ((rgb >> 16) & 0xff);
+ dest[1 + offset] = (byte) ((rgb >> 8) & 0xff);
+ dest[ offset] = (byte) ( rgb & 0xff);
+ }
+ }
+
+ private void hamToRGB(final byte[] indexed, final IndexColorModel colorModel, final byte[] dest, final int destOffset) {
final int bits = header.bitplanes;
final int width = header.width;
int lastRed = 0;
@@ -647,20 +731,18 @@ public class IFFImageReader extends ImageReaderBase {
int lastBlue = 0;
for (int x = 0; x < width; x++) {
- int pixel = pIndexed[x] & 0xff;
+ int pixel = indexed[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);
+ lastRed = colorModel.getRed(paletteIndex);
+ lastGreen = colorModel.getGreen(paletteIndex);
+ lastBlue = colorModel.getBlue(paletteIndex);
break;
case 0x01:// MODIFY BLUE
lastBlue = (lastBlue & colorMask) | (paletteIndex << indexShift);
@@ -672,29 +754,48 @@ public class IFFImageReader extends ImageReaderBase {
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;
+
+ int offset = (x * 3) + destOffset;
+ dest[2 + offset] = (byte) lastRed;
+ dest[1 + offset] = (byte) lastGreen;
+ dest[ offset] = (byte) lastBlue;
}
}
+ private boolean isSHAM() {
+ // TODO:
+ return false;
+ }
+
+ private boolean isPCHG() {
+ return paletteChange != null;
+ }
+
private boolean isHAM() {
return viewPort != null && viewPort.isHAM();
}
+ public boolean isLaced() {
+ return viewPort != null && viewPort.isLaced();
+ }
+
public static void main(String[] pArgs) throws IOException {
ImageReader reader = new IFFImageReader();
-// ImageInputStream input = ImageIO.createImageInputStream(new File(pArgs[0]));
- ImageInputStream input = new BufferedImageInputStream(ImageIO.createImageInputStream(new File(pArgs[0])));
- boolean canRead = reader.getOriginatingProvider().canDecodeInput(input);
+ boolean scale = false;
+ for (String arg : pArgs) {
+ if (arg.startsWith("-")) {
+ scale = true;
+ continue;
+ }
+ ImageInputStream input = new BufferedImageInputStream(ImageIO.createImageInputStream(new File(arg)));
+ boolean canRead = reader.getOriginatingProvider().canDecodeInput(input);
- System.out.println("Can read: " + canRead);
+ System.out.println("Can read: " + canRead);
- if (canRead) {
- reader.setInput(input);
- ImageReadParam param = reader.getDefaultReadParam();
+ 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));
@@ -702,10 +803,17 @@ public class IFFImageReader extends ImageReaderBase {
// 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);
+ BufferedImage image = reader.read(0, param);
+ System.out.println("image = " + image);
+
+ if (scale) {
+ image = new ResampleOp(image.getWidth() / 2, image.getHeight(), ResampleOp.FILTER_LANCZOS).filter(image, null);
+// image = ImageUtil.createResampled(image, image.getWidth(), image.getHeight() * 2, Image.SCALE_FAST);
+ }
+
+ showIt(image, arg);
+ }
- showIt(image, pArgs[0]);
}
}
}
diff --git a/imageio/imageio-iff/src/main/java/com/twelvemonkeys/imageio/plugins/iff/Multipalette.java b/imageio/imageio-iff/src/main/java/com/twelvemonkeys/imageio/plugins/iff/Multipalette.java
new file mode 100644
index 00000000..6130b25c
--- /dev/null
+++ b/imageio/imageio-iff/src/main/java/com/twelvemonkeys/imageio/plugins/iff/Multipalette.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2012, 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.awt.image.ColorModel;
+import java.awt.image.IndexColorModel;
+
+/**
+ * MultiPalette
+ *
+ * @author Harald Kuhr
+ * @author last modified by $Author: haraldk$
+ * @version $Id: MultiPalette.java,v 1.0 30.03.12 15:22 haraldk Exp$
+ */
+interface MultiPalette {
+ ColorModel getColorModel(IndexColorModel colorModel, int rowIndex, boolean laced);
+}
diff --git a/imageio/imageio-iff/src/main/java/com/twelvemonkeys/imageio/plugins/iff/MutableIndexColorModel.java b/imageio/imageio-iff/src/main/java/com/twelvemonkeys/imageio/plugins/iff/MutableIndexColorModel.java
new file mode 100644
index 00000000..37a54d96
--- /dev/null
+++ b/imageio/imageio-iff/src/main/java/com/twelvemonkeys/imageio/plugins/iff/MutableIndexColorModel.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2012, 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.
+ */
+/*
+ * Parts of this code is based on ilbmtoppm.c
+ *
+ * Copyright (C) 1989 by Jef Poskanzer.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose and without fee is hereby granted, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation. This software is provided "as is" without express or
+ * implied warranty.
+ *
+ * Multipalette-support by Ingo Wilken (Ingo.Wilken@informatik.uni-oldenburg.de)
+ */
+
+package com.twelvemonkeys.imageio.plugins.iff;
+
+import java.awt.image.ColorModel;
+import java.awt.image.IndexColorModel;
+
+/**
+ * A mutable indexed color model.
+ * For use with images that exploits Amiga hardware to change the color
+ * lookup table between scan lines.
+ *
+ * @author Harald Kuhr
+ * @author last modified by $Author: haraldk$
+ * @version $Id: MutableIndexColorModel.java,v 1.0 29.03.12 15:00 haraldk Exp$
+ */
+final class MutableIndexColorModel extends ColorModel {
+ final static int MP_REG_IGNORE = -1;
+
+ final int[] rgbs;
+
+ public MutableIndexColorModel(final IndexColorModel base) {
+ super(base.getPixelSize(), base.getComponentSize(), base.getColorSpace(), base.hasAlpha(), base.isAlphaPremultiplied(), base.getTransparency(), base.getTransferType());
+
+ this.rgbs = getRGBs(base);
+ }
+
+ private static int[] getRGBs(final IndexColorModel colorModel) {
+ int[] rgbs = new int[colorModel.getMapSize()];
+ colorModel.getRGBs(rgbs);
+ return rgbs;
+ }
+
+ public void adjustColorMap(final PaletteChange[] changes) {
+ for (int i = 0; i < changes.length; i++) {
+ int index = changes[i].index;
+
+ if (index >= rgbs.length) {
+ // TODO: Issue IIO warning
+ System.err.printf("warning - palette change register out of range\n");
+ System.err.printf(" change structure %d index=%d (max %d)\n", i, index, getMapSize() - 1);
+ System.err.printf(" ignoring it... colors might get messed up from here\n");
+ }
+ else if (index != MP_REG_IGNORE) {
+ updateRGB(index, ((changes[i].r & 0xff) << 16) | ((changes[i].g & 0xff) << 8) | (changes[i].b & 0xff));
+ }
+ }
+ }
+
+ @Override
+ public int getRGB(int pixel) {
+ return rgbs[pixel];
+ }
+
+ @Override
+ public int getRed(int pixel) {
+ return (rgbs[pixel] >> 16) & 0xff;
+ }
+
+ @Override
+ public int getGreen(int pixel) {
+ return (rgbs[pixel] >> 8) & 0xff;
+ }
+
+ @Override
+ public int getBlue(int pixel) {
+ return rgbs[pixel] & 0xff;
+ }
+
+ @Override
+ public int getAlpha(int pixel) {
+ return (rgbs[pixel] >> 24) & 0xff;
+ }
+
+ private void updateRGB(int index, int rgb) {
+ rgbs[index] = rgb;
+ }
+
+ public int getMapSize() {
+ return rgbs.length;
+ }
+
+ static class PaletteChange {
+ /* palette index to change */
+ public int index;
+ /* new colors for index */
+ public byte r;
+ public byte g;
+ public byte b;
+ }
+}
diff --git a/imageio/imageio-iff/src/main/java/com/twelvemonkeys/imageio/plugins/iff/PCHGChunk.java b/imageio/imageio-iff/src/main/java/com/twelvemonkeys/imageio/plugins/iff/PCHGChunk.java
new file mode 100644
index 00000000..441582db
--- /dev/null
+++ b/imageio/imageio-iff/src/main/java/com/twelvemonkeys/imageio/plugins/iff/PCHGChunk.java
@@ -0,0 +1,270 @@
+/*
+ * Copyright (c) 2012, 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.
+ */
+/*
+ * Parts of this code is based on ilbmtoppm.c
+ *
+ * Copyright (C) 1989 by Jef Poskanzer.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose and without fee is hereby granted, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation. This software is provided "as is" without express or
+ * implied warranty.
+ *
+ * Multipalette-support by Ingo Wilken (Ingo.Wilken@informatik.uni-oldenburg.de)
+ */
+package com.twelvemonkeys.imageio.plugins.iff;
+
+import javax.imageio.IIOException;
+import java.io.DataInput;
+import java.io.IOException;
+
+/**
+ * PCHGChunk
+ *
+ * @author Harald Kuhr
+ * @author last modified by $Author: haraldk$
+ * @version $Id: PCHGChunk.java,v 1.0 27.03.12 13:02 haraldk Exp$
+ */
+final class PCHGChunk extends AbstractMultiPaletteChunk {
+ // NOTE: Values from ilbm2ppm.
+ final static int PCHG_COMP_NONE = 0;
+ final static int PCHG_COMP_HUFFMAN = 1;
+
+ /** Use SmallLineChanges */
+ final static int PCHGF_12BIT = 1; // NOTE: The beta spec refers to this as PHCGF_4BIT
+ /** Use BigLineChanges */
+ final static int PCHGF_32BIT = 2;
+ /** meaningful only if PCHG_32BIT is on: use the Alpha channel info */
+ final static int PCHGF_USE_ALPHA = 4;
+
+ private int startLine;
+ private int changedLines;
+ private int lineCount;
+ private int totalChanges;
+ private int minReg;
+
+ public PCHGChunk(int pChunkLength) {
+ super(IFF.CHUNK_PCHG, pChunkLength);
+ }
+
+ @Override
+ void readChunk(final DataInput pInput) throws IOException {
+ int compression = pInput.readUnsignedShort();
+ int flags = pInput.readUnsignedShort();
+ startLine = pInput.readShort();
+ lineCount = pInput.readUnsignedShort();
+ changedLines = pInput.readUnsignedShort();
+ minReg = pInput.readUnsignedShort();
+ int maxReg = pInput.readUnsignedShort();
+ int maxChanges = pInput.readUnsignedShort(); // We don't really care, as we're not limited by the Amiga display hardware
+ totalChanges = pInput.readInt();
+
+// System.err.println("compression: " + compression);
+// System.err.println("flags: " + Integer.toBinaryString(flags));
+// System.err.println("startLine: " + startLine);
+// System.err.println("lineCount: " + lineCount);
+// System.err.println("changedLines: " + changedLines);
+// System.err.println("minReg: " + minReg);
+// System.err.println("maxReg: " + maxReg);
+// System.err.println("maxChanges: " + maxChanges);
+// System.err.println("totalChanges: " + totalChanges);
+
+ switch (compression) {
+ case PCHG_COMP_NONE:
+ byte[] data = new byte[chunkLength - 20];
+ pInput.readFully(data);
+
+ changes = new MutableIndexColorModel.PaletteChange[startLine + lineCount][];
+
+ if (startLine < 0) {
+ int numChanges = maxReg - minReg + 1;
+
+ initialChanges = new MutableIndexColorModel.PaletteChange[numChanges];
+ for (int i = 0; i < initialChanges.length; i++) {
+ initialChanges[i] = new MutableIndexColorModel.PaletteChange();
+ }
+
+ for (int i = 0; i < numChanges; i++) {
+ initialChanges[i].index = MutableIndexColorModel.MP_REG_IGNORE;
+ }
+ }
+
+ // TODO: Postpone conversion to actually needed
+ if ((flags & PCHGF_12BIT) != 0) {
+ convertSmallChanges(data);
+ }
+ else if ((flags & PCHGF_32BIT) != 0) {
+ System.err.println("BigLineChanges");
+
+ if ((flags & PCHGF_USE_ALPHA) != 0) {
+ System.err.println("Alpha should be used...");
+ }
+
+ // TODO: Implement 32 bit/alpha support
+ throw new UnsupportedOperationException("BigLineChanges not supported (yet)");
+ }
+
+ break;
+ case PCHG_COMP_HUFFMAN:
+ // TODO: Implement Huffman decoding
+ throw new IIOException("Huffman PCHG compression not supported");
+ default:
+ throw new IIOException("Unknown PCHG compression: " + compression);
+ }
+ }
+
+ private void convertSmallChanges(byte[] data) throws IIOException {
+ int thismask = 0;
+ int changeCount, reg;
+ int changeCount16, changeCount32;
+ int smallChange;
+ int totalchanges = 0;
+ int changedlines = changedLines;
+
+ int maskBytesLeft = 4 * ((lineCount + 31) / 32);
+
+ int maskIdx = 0;
+ int dataIdx = maskBytesLeft;
+ int dataBytesLeft = data.length - maskBytesLeft;
+
+ int bits = 0;
+ for (int row = startLine; changedlines != 0 && row < 0; row++) {
+ if (bits == 0) {
+ if (maskBytesLeft == 0) {
+ throw new IIOException("insufficient data in line mask");
+ }
+
+ thismask = data[maskIdx++];
+ --maskBytesLeft;
+ bits = 8;
+ }
+
+ if ((thismask & (1 << 7)) != 0) {
+ if (dataBytesLeft < 2) {
+ throw new IIOException("insufficient data in SmallLineChanges structures: " + dataBytesLeft);
+ }
+
+ changeCount16 = data[dataIdx++];
+ changeCount32 = data[dataIdx++];
+ dataBytesLeft -= 2;
+
+ changeCount = changeCount16 + changeCount32;
+
+ for (int i = 0; i < changeCount; i++) {
+ if (totalchanges >= this.totalChanges) {
+ throw new IIOException("insufficient data in SmallLineChanges structures (changeCount): " + totalchanges);
+ }
+ if (dataBytesLeft < 2) {
+ throw new IIOException("insufficient data in SmallLineChanges structures: " + dataBytesLeft);
+ }
+
+ smallChange = toShort(data, dataIdx);
+ dataIdx += 2;
+ dataBytesLeft -= 2;
+ reg = ((smallChange & 0xf000) >> 12) + (i >= changeCount16 ? 16 : 0);
+ initialChanges[reg - minReg].index = reg;
+ initialChanges[reg - minReg].r = (byte) (((smallChange & 0x0f00) >> 8) * FACTOR_4BIT);
+ initialChanges[reg - minReg].g = (byte) (((smallChange & 0x00f0) >> 4) * FACTOR_4BIT);
+ initialChanges[reg - minReg].b = (byte) (((smallChange & 0x000f) ) * FACTOR_4BIT);
+ ++totalchanges;
+ }
+
+ --changedlines;
+ }
+
+ thismask <<= 1;
+ bits--;
+ }
+
+ for (int row = startLine; changedlines != 0 && row < this.changes.length; row++) {
+ if (bits == 0) {
+ if (maskBytesLeft == 0) {
+ throw new IIOException("insufficient data in line mask");
+ }
+
+ thismask = data[maskIdx++];
+ --maskBytesLeft;
+ bits = 8;
+ }
+
+ if ((thismask & (1 << 7)) != 0) {
+ if (dataBytesLeft < 2) {
+ throw new IIOException("insufficient data in SmallLineChanges structures: " + dataBytesLeft);
+ }
+
+ changeCount16 = data[dataIdx++];
+ changeCount32 = data[dataIdx++];
+ dataBytesLeft -= 2;
+
+ changeCount = changeCount16 + changeCount32;
+
+ changes[row] = new MutableIndexColorModel.PaletteChange[changeCount];
+
+ for (int i = 0; i < changeCount; i++) {
+ changes[row][i] = new MutableIndexColorModel.PaletteChange();
+ }
+
+ for (int i = 0; i < changeCount; i++) {
+ if (totalchanges >= this.totalChanges) {
+ throw new IIOException("insufficient data in SmallLineChanges structures");
+ }
+ if (dataBytesLeft < 2) {
+ throw new IIOException("insufficient data in SmallLineChanges structures");
+ }
+
+ smallChange = toShort(data, dataIdx);
+ dataIdx += 2;
+ dataBytesLeft -= 2;
+ reg = ((smallChange & 0xf000) >> 12) + (i >= changeCount16 ? 16 : 0);
+ changes[row][i].index = reg;
+ changes[row][i].r = (byte) (((smallChange & 0x0f00) >> 8) * FACTOR_4BIT);
+ changes[row][i].g = (byte) (((smallChange & 0x00f0) >> 4) * FACTOR_4BIT);
+ changes[row][i].b = (byte) (((smallChange & 0x000f) ) * FACTOR_4BIT);
+ ++totalchanges;
+ }
+
+ --changedlines;
+ }
+
+ thismask <<= 1;
+ bits--;
+ }
+
+ if (totalchanges != this.totalChanges) {
+ // TODO: Issue IIO warning
+ System.err.printf("warning - got %d change structures, chunk header reports %d", totalchanges, this.totalChanges);
+ }
+ }
+
+ // TODO: Util method
+ private static short toShort(byte[] bytes, int idx) {
+ return (short) ((bytes[idx] & 0xff) << 8 | (bytes[idx + 1] & 0xff));
+ }
+}
diff --git a/imageio/imageio-iff/src/main/java/com/twelvemonkeys/imageio/plugins/iff/SHAMChunk.java b/imageio/imageio-iff/src/main/java/com/twelvemonkeys/imageio/plugins/iff/SHAMChunk.java
new file mode 100644
index 00000000..74b8805a
--- /dev/null
+++ b/imageio/imageio-iff/src/main/java/com/twelvemonkeys/imageio/plugins/iff/SHAMChunk.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2012, 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;
+
+/**
+ * SHAMChunk
+ *
+ * @author Harald Kuhr
+ * @author last modified by $Author: haraldk$
+ * @version $Id: SHAMChunk.java,v 1.0 30.03.12 14:53 haraldk Exp$
+ */
+final class SHAMChunk extends AbstractMultiPaletteChunk {
+ protected SHAMChunk(int pChunkLength) {
+ super(IFF.CHUNK_SHAM, pChunkLength);
+ }
+
+ @Override
+ protected boolean skipLaced() {
+ return true;
+ }
+}
diff --git a/imageio/imageio-iff/src/test/java/com/twelvemonkeys/imageio/plugins/iff/IFFImageReaderTest.java b/imageio/imageio-iff/src/test/java/com/twelvemonkeys/imageio/plugins/iff/IFFImageReaderTest.java
index 7767df92..37d9ea66 100755
--- a/imageio/imageio-iff/src/test/java/com/twelvemonkeys/imageio/plugins/iff/IFFImageReaderTest.java
+++ b/imageio/imageio-iff/src/test/java/com/twelvemonkeys/imageio/plugins/iff/IFFImageReaderTest.java
@@ -52,14 +52,18 @@ public class IFFImageReaderTest extends ImageReaderAbstractTestCase