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