You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@flex.apache.org by cf...@apache.org on 2012/10/25 21:01:49 UTC

svn commit: r1402274 [17/31] - in /incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext: ./ awt/ awt/color/ awt/font/ awt/g2d/ awt/geom/ awt/image/ awt/image/codec/ awt/image/codec/jpeg/ awt/image/codec/p...

Added: incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext/awt/image/codec/tiff/TIFFImage.java
URL: http://svn.apache.org/viewvc/incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext/awt/image/codec/tiff/TIFFImage.java?rev=1402274&view=auto
==============================================================================
--- incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext/awt/image/codec/tiff/TIFFImage.java (added)
+++ incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext/awt/image/codec/tiff/TIFFImage.java Thu Oct 25 19:01:43 2012
@@ -0,0 +1,1818 @@
+/*
+
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+ */
+package org.apache.flex.forks.batik.ext.awt.image.codec.tiff;
+
+import java.awt.Rectangle;
+import java.awt.Transparency;
+import java.awt.color.ColorSpace;
+import java.awt.image.ColorModel;
+import java.awt.image.ComponentColorModel;
+import java.awt.image.DataBuffer;
+import java.awt.image.DataBufferByte;
+import java.awt.image.DataBufferInt;
+import java.awt.image.DataBufferShort;
+import java.awt.image.DataBufferUShort;
+import java.awt.image.IndexColorModel;
+import java.awt.image.MultiPixelPackedSampleModel;
+import java.awt.image.PixelInterleavedSampleModel;
+import java.awt.image.Raster;
+import java.awt.image.SampleModel;
+import java.awt.image.WritableRaster;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.zip.DataFormatException;
+import java.util.zip.Inflater;
+
+import org.apache.flex.forks.batik.ext.awt.image.codec.util.SeekableStream;
+import org.apache.flex.forks.batik.ext.awt.image.rendered.AbstractRed;
+import org.apache.flex.forks.batik.ext.awt.image.rendered.CachableRed;
+
+import com.sun.image.codec.jpeg.JPEGCodec;
+import com.sun.image.codec.jpeg.JPEGDecodeParam;
+import com.sun.image.codec.jpeg.JPEGImageDecoder;
+
+/**
+ *
+ * @version $Id: TIFFImage.java 498740 2007-01-22 18:35:57Z dvholten $
+ */
+public class TIFFImage extends AbstractRed {
+
+    // Compression types
+    public static final int COMP_NONE      = 1;
+    public static final int COMP_FAX_G3_1D = 2;
+    public static final int COMP_FAX_G3_2D = 3;
+    public static final int COMP_FAX_G4_2D = 4;
+    public static final int COMP_LZW       = 5;
+    public static final int COMP_JPEG_OLD  = 6;
+    public static final int COMP_JPEG_TTN2 = 7;
+    public static final int COMP_PACKBITS  = 32773;
+    public static final int COMP_DEFLATE   = 32946;
+
+    // Image types
+    private static final int TYPE_UNSUPPORTED = -1;
+    private static final int TYPE_BILEVEL      = 0;
+    private static final int TYPE_GRAY_4BIT    = 1;
+    private static final int TYPE_GRAY         = 2;
+    private static final int TYPE_GRAY_ALPHA   = 3;
+    private static final int TYPE_PALETTE      = 4;
+    private static final int TYPE_RGB          = 5;
+    private static final int TYPE_RGB_ALPHA    = 6;
+    private static final int TYPE_YCBCR_SUB    = 7;
+    private static final int TYPE_GENERIC      = 8;
+
+    // Incidental tags
+    private static final int TIFF_JPEG_TABLES       = 347;
+    private static final int TIFF_YCBCR_SUBSAMPLING = 530;
+
+    SeekableStream stream;
+    int tileSize;
+    int tilesX, tilesY;
+    long[] tileOffsets;
+    long[] tileByteCounts;
+    char[] colormap;
+    int sampleSize;
+    int compression;
+    byte[] palette;
+    int numBands;
+
+    int chromaSubH;
+    int chromaSubV;
+
+    // Fax compression related variables
+    long tiffT4Options;
+    long tiffT6Options;
+    int fillOrder;
+
+    // LZW compression related variable
+    int predictor;
+
+    // TTN2 JPEG related variables
+    JPEGDecodeParam decodeParam = null;
+    boolean colorConvertJPEG = false;
+
+    // DEFLATE variables
+    Inflater inflater = null;
+
+    // Endian-ness indicator
+    boolean isBigEndian;
+
+    int imageType;
+    boolean isWhiteZero = false;
+    int dataType;
+
+    boolean decodePaletteAsShorts;
+    boolean tiled;
+
+    // Decoders
+    private TIFFFaxDecoder decoder = null;
+    private TIFFLZWDecoder lzwDecoder = null;
+
+    /**
+     * Decode a buffer of data into a Raster with the specified location.
+     *
+     * @param data buffer contain an interchange or abbreviated datastream.
+     * @param decodeParam decoding parameters; may be null unless the
+     *        data buffer contains an abbreviated datastream in which case
+     *        it may not be null or an error will occur.
+     * @param colorConvert whether to perform color conversion; in this
+     *        case that would be limited to YCbCr-to-RGB.
+     * @param minX the X position of the returned Raster.
+     * @param minY the Y position of the returned Raster.
+     */
+    private static final Raster decodeJPEG(byte[] data,
+                                           JPEGDecodeParam decodeParam,
+                                           boolean colorConvert,
+                                           int minX,
+                                           int minY) {
+        // Create an InputStream from the compressed data array.
+        ByteArrayInputStream jpegStream = new ByteArrayInputStream(data);
+
+        // Create a decoder.
+        JPEGImageDecoder decoder = decodeParam == null ?
+            JPEGCodec.createJPEGDecoder(jpegStream) :
+            JPEGCodec.createJPEGDecoder(jpegStream,
+                                        decodeParam);
+
+        // Decode the compressed data into a Raster.
+        Raster jpegRaster;
+        try {
+            jpegRaster = colorConvert ?
+                decoder.decodeAsBufferedImage().getWritableTile(0, 0) :
+                decoder.decodeAsRaster();
+        } catch (IOException ioe) {
+            throw new RuntimeException("TIFFImage13");
+        }
+
+        // Translate the decoded Raster to the specified location and return.
+        return jpegRaster.createTranslatedChild(minX, minY);
+    }
+
+    /**
+     * Inflates <code>deflated</code> into <code>inflated</code> using the
+     * <code>Inflater</code> constructed during class instantiation.
+     */
+    private final void inflate(byte[] deflated, byte[] inflated) {
+        inflater.setInput(deflated);
+        try {
+            inflater.inflate(inflated);
+        } catch(DataFormatException dfe) {
+            throw new RuntimeException("TIFFImage17"+": "+
+                                       dfe.getMessage());
+        }
+        inflater.reset();
+    }
+
+    private static SampleModel createPixelInterleavedSampleModel
+        (int dataType, int tileWidth, int tileHeight, int bands) {
+        int [] bandOffsets = new int[bands];
+        for (int i=0; i<bands; i++)
+            bandOffsets[i] = i;
+        return new PixelInterleavedSampleModel
+            (dataType, tileWidth, tileHeight, bands,
+             tileWidth*bands, bandOffsets);
+    }
+
+    /**
+     * Return as a long[] the value of a TIFF_LONG or TIFF_SHORT field.
+     */
+    private long[] getFieldAsLongs(TIFFField field) {
+        long[] value = null;
+
+        if(field.getType() == TIFFField.TIFF_SHORT) {
+            char[] charValue = field.getAsChars();
+            value = new long[charValue.length];
+            for(int i = 0; i < charValue.length; i++) {
+                value[i] = charValue[i]  & 0xffff;
+            }
+        } else if(field.getType() == TIFFField.TIFF_LONG) {
+            value = field.getAsLongs();
+        } else {
+            throw new RuntimeException();
+        }
+
+        return value;
+    }
+
+    /**
+     * Constructs a TIFFImage that acquires its data from a given
+     * SeekableStream and reads from a particular IFD of the stream.
+     * The index of the first IFD is 0.
+     *
+     * @param stream the SeekableStream to read from.
+     * @param param an instance of TIFFDecodeParam, or null.
+     * @param directory the index of the IFD to read from.
+     */
+    public TIFFImage(SeekableStream stream,
+                     TIFFDecodeParam param,
+                     int directory)
+        throws IOException {
+
+        this.stream = stream;
+        if (param == null) {
+            param = new TIFFDecodeParam();
+        }
+
+        decodePaletteAsShorts = param.getDecodePaletteAsShorts();
+
+        // Read the specified directory.
+        TIFFDirectory dir = param.getIFDOffset() == null ?
+            new TIFFDirectory(stream, directory) :
+            new TIFFDirectory(stream, param.getIFDOffset().longValue(),
+                              directory);
+
+        // Get the number of samples per pixel
+        TIFFField sfield = dir.getField(TIFFImageDecoder.TIFF_SAMPLES_PER_PIXEL);
+        int samplesPerPixel = sfield == null ? 1 : (int)sfield.getAsLong(0);
+
+        // Read the TIFF_PLANAR_CONFIGURATION field
+        TIFFField planarConfigurationField =
+            dir.getField(TIFFImageDecoder.TIFF_PLANAR_CONFIGURATION);
+        char[] planarConfiguration = planarConfigurationField == null ?
+            new char[] {1} :
+            planarConfigurationField.getAsChars();
+
+            // Support planar format (band sequential) only for 1 sample/pixel.
+            if (planarConfiguration[0] != 1 && samplesPerPixel != 1) {
+                throw new RuntimeException("TIFFImage0");
+            }
+
+            // Read the TIFF_BITS_PER_SAMPLE field
+            TIFFField bitsField =
+                dir.getField(TIFFImageDecoder.TIFF_BITS_PER_SAMPLE);
+            char[] bitsPerSample = null;
+            if(bitsField != null) {
+                bitsPerSample = bitsField.getAsChars();
+            } else {
+                bitsPerSample = new char[] {1};
+
+                // Ensure that all samples have the same bit depth.
+                for (int i = 1; i < bitsPerSample.length; i++) {
+                    if (bitsPerSample[i] != bitsPerSample[0]) {
+                        throw new RuntimeException("TIFFImage1");
+                    }
+                }
+            }
+            sampleSize = bitsPerSample[0];
+
+            // Read the TIFF_SAMPLE_FORMAT tag to see whether the data might be
+            // signed or floating point
+            TIFFField sampleFormatField =
+                dir.getField(TIFFImageDecoder.TIFF_SAMPLE_FORMAT);
+
+            char[] sampleFormat = null;
+            if (sampleFormatField != null) {
+                sampleFormat = sampleFormatField.getAsChars();
+
+                // Check that all the samples have the same format
+                for (int l=1; l<sampleFormat.length; l++) {
+                    if (sampleFormat[l] != sampleFormat[0]) {
+                        throw new RuntimeException("TIFFImage2");
+                    }
+                }
+
+            } else {
+                sampleFormat = new char[] {1};
+            }
+
+            // Set the data type based on the sample size and format.
+            boolean isValidDataFormat = false;
+            switch(sampleSize) {
+            case 1:
+            case 4:
+            case 8:
+                if(sampleFormat[0] != 3) {
+                    // Ignore whether signed or unsigned: treat all as unsigned.
+                    dataType = DataBuffer.TYPE_BYTE;
+                    isValidDataFormat = true;
+                }
+                break;
+            case 16:
+                if(sampleFormat[0] != 3) {
+                    dataType = sampleFormat[0] == 2 ?
+                        DataBuffer.TYPE_SHORT : DataBuffer.TYPE_USHORT;
+                    isValidDataFormat = true;
+                }
+                break;
+            case 32:
+              if (sampleFormat[0] == 3)
+                isValidDataFormat = false;
+              else {
+                dataType = DataBuffer.TYPE_INT;
+                isValidDataFormat = true;
+              }
+              break;
+            }
+
+            if(!isValidDataFormat) {
+                throw new RuntimeException("TIFFImage3");
+            }
+
+            // Figure out what compression if any, is being used.
+            TIFFField compField = dir.getField(TIFFImageDecoder.TIFF_COMPRESSION);
+            compression = compField == null ? COMP_NONE : compField.getAsInt(0);
+
+            // Get the photometric interpretation.
+            int photometricType = (int)dir.getFieldAsLong(
+                                                          TIFFImageDecoder.TIFF_PHOTOMETRIC_INTERPRETATION);
+
+            // Determine which kind of image we are dealing with.
+            imageType = TYPE_UNSUPPORTED;
+            switch(photometricType) {
+            case 0: // WhiteIsZero
+                isWhiteZero = true;
+            case 1: // BlackIsZero
+                if(sampleSize == 1 && samplesPerPixel == 1) {
+                    imageType = TYPE_BILEVEL;
+                } else if(sampleSize == 4 && samplesPerPixel == 1) {
+                    imageType = TYPE_GRAY_4BIT;
+                } else if(sampleSize % 8 == 0) {
+                    if(samplesPerPixel == 1) {
+                        imageType = TYPE_GRAY;
+                    } else if(samplesPerPixel == 2) {
+                        imageType = TYPE_GRAY_ALPHA;
+                    } else {
+                        imageType = TYPE_GENERIC;
+                    }
+                }
+                break;
+            case 2: // RGB
+                if(sampleSize % 8 == 0) {
+                    if(samplesPerPixel == 3) {
+                        imageType = TYPE_RGB;
+                    } else if(samplesPerPixel == 4) {
+                        imageType = TYPE_RGB_ALPHA;
+                    } else {
+                        imageType = TYPE_GENERIC;
+                    }
+                }
+                break;
+            case 3: // RGB Palette
+                if(samplesPerPixel == 1 &&
+                   (sampleSize == 4 || sampleSize == 8 || sampleSize == 16)) {
+                    imageType = TYPE_PALETTE;
+                }
+                break;
+            case 4: // Transparency mask
+                if(sampleSize == 1 && samplesPerPixel == 1) {
+                    imageType = TYPE_BILEVEL;
+                }
+                break;
+            case 6: // YCbCr
+                if(compression == COMP_JPEG_TTN2 &&
+                   sampleSize == 8 && samplesPerPixel == 3) {
+                    // Set color conversion flag.
+                    colorConvertJPEG = param.getJPEGDecompressYCbCrToRGB();
+
+                    // Set type to RGB if color converting.
+                    imageType = colorConvertJPEG ? TYPE_RGB : TYPE_GENERIC;
+                } else {
+                    TIFFField chromaField = dir.getField(TIFF_YCBCR_SUBSAMPLING);
+                    if(chromaField != null) {
+                        chromaSubH = chromaField.getAsInt(0);
+                        chromaSubV = chromaField.getAsInt(1);
+                    } else {
+                        chromaSubH = chromaSubV = 2;
+                    }
+
+                    if(chromaSubH*chromaSubV == 1) {
+                        imageType = TYPE_GENERIC;
+                    } else if(sampleSize == 8 && samplesPerPixel == 3) {
+                        imageType = TYPE_YCBCR_SUB;
+                    }
+                }
+                break;
+            default: // Other including CMYK, CIE L*a*b*, unknown.
+                if(sampleSize % 8 == 0) {
+                    imageType = TYPE_GENERIC;
+                }
+            }
+
+            // Bail out if not one of the supported types.
+            if(imageType == TYPE_UNSUPPORTED) {
+                throw new RuntimeException("TIFFImage4");
+            }
+
+            // Set basic image layout
+            Rectangle bounds = new Rectangle
+                (0, 0,
+                 (int)dir.getFieldAsLong(TIFFImageDecoder.TIFF_IMAGE_WIDTH),
+                 (int)dir.getFieldAsLong(TIFFImageDecoder.TIFF_IMAGE_LENGTH));
+
+            // Set a preliminary band count. This may be changed later as needed.
+            numBands = samplesPerPixel;
+
+            // Figure out if any extra samples are present.
+            TIFFField efield = dir.getField(TIFFImageDecoder.TIFF_EXTRA_SAMPLES);
+            int extraSamples = efield == null ? 0 : (int)efield.getAsLong(0);
+
+            int tileWidth, tileHeight;
+            if (dir.getField(TIFFImageDecoder.TIFF_TILE_OFFSETS) != null) {
+                tiled = true;
+                // Image is in tiled format
+                tileWidth =
+                    (int)dir.getFieldAsLong(TIFFImageDecoder.TIFF_TILE_WIDTH);
+                tileHeight =
+                    (int)dir.getFieldAsLong(TIFFImageDecoder.TIFF_TILE_LENGTH);
+                tileOffsets =
+                    (dir.getField(TIFFImageDecoder.TIFF_TILE_OFFSETS)).getAsLongs();
+                tileByteCounts =
+                    getFieldAsLongs(dir.getField(TIFFImageDecoder.TIFF_TILE_BYTE_COUNTS));
+
+            } else {
+                tiled = false;
+
+                // Image is in stripped format, looks like tiles to us
+                // Note: Some legacy files may have tile width and height
+                // written but use the strip offsets and byte counts fields
+                // instead of the tile offsets and byte counts. Therefore
+                // we default here to the tile dimensions if they are written.
+                tileWidth =
+                    dir.getField(TIFFImageDecoder.TIFF_TILE_WIDTH) != null ?
+                    (int)dir.getFieldAsLong(TIFFImageDecoder.TIFF_TILE_WIDTH) :
+                    bounds.width;
+                TIFFField field =
+                    dir.getField(TIFFImageDecoder.TIFF_ROWS_PER_STRIP);
+                if (field == null) {
+                    // Default is infinity (2^32 -1), basically the entire image
+
+                    tileHeight =
+                        dir.getField(TIFFImageDecoder.TIFF_TILE_LENGTH) != null ?
+                        (int)dir.getFieldAsLong(TIFFImageDecoder.TIFF_TILE_LENGTH):
+                        bounds.height;
+                } else {
+                    long l = field.getAsLong(0);
+                    long infinity = 1;
+                    infinity = (infinity << 32) - 1;
+                    if (l == infinity) {
+                        // 2^32 - 1 (effectively infinity, entire image is 1 strip)
+                        tileHeight = bounds.height;
+                    } else {
+                        tileHeight = (int)l;
+                    }
+                }
+
+                TIFFField tileOffsetsField =
+                    dir.getField(TIFFImageDecoder.TIFF_STRIP_OFFSETS);
+                if (tileOffsetsField == null) {
+                    throw new RuntimeException("TIFFImage5");
+                } else {
+                    tileOffsets = getFieldAsLongs(tileOffsetsField);
+                }
+
+                TIFFField tileByteCountsField =
+                    dir.getField(TIFFImageDecoder.TIFF_STRIP_BYTE_COUNTS);
+                if (tileByteCountsField == null) {
+                    throw new RuntimeException("TIFFImage6");
+                } else {
+                    tileByteCounts = getFieldAsLongs(tileByteCountsField);
+                }
+            }
+
+            // Calculate number of tiles and the tileSize in bytes
+            tilesX = (bounds.width + tileWidth - 1)/tileWidth;
+            tilesY = (bounds.height + tileHeight - 1)/tileHeight;
+            tileSize = tileWidth * tileHeight * numBands;
+
+            // Check whether big endian or little endian format is used.
+            isBigEndian = dir.isBigEndian();
+
+            TIFFField fillOrderField =
+                dir.getField(TIFFImageDecoder.TIFF_FILL_ORDER);
+            if (fillOrderField != null) {
+                fillOrder = fillOrderField.getAsInt(0);
+            } else {
+                // Default Fill Order
+                fillOrder = 1;
+            }
+
+            switch(compression) {
+            case COMP_NONE:
+            case COMP_PACKBITS:
+                // Do nothing.
+                break;
+            case COMP_DEFLATE:
+                inflater = new Inflater();
+                break;
+            case COMP_FAX_G3_1D:
+            case COMP_FAX_G3_2D:
+            case COMP_FAX_G4_2D:
+                if(sampleSize != 1) {
+                    throw new RuntimeException("TIFFImage7");
+                }
+
+                // Fax T.4 compression options
+                if (compression == 3) {
+                    TIFFField t4OptionsField =
+                        dir.getField(TIFFImageDecoder.TIFF_T4_OPTIONS);
+                    if (t4OptionsField != null) {
+                        tiffT4Options = t4OptionsField.getAsLong(0);
+                    } else {
+                        // Use default value
+                        tiffT4Options = 0;
+                    }
+                }
+
+                // Fax T.6 compression options
+                if (compression == 4) {
+                    TIFFField t6OptionsField =
+                        dir.getField(TIFFImageDecoder.TIFF_T6_OPTIONS);
+                    if (t6OptionsField != null) {
+                        tiffT6Options = t6OptionsField.getAsLong(0);
+                    } else {
+                        // Use default value
+                        tiffT6Options = 0;
+                    }
+                }
+
+                // Fax encoding, need to create the Fax decoder.
+                decoder = new TIFFFaxDecoder(fillOrder,
+                                             tileWidth, tileHeight);
+                break;
+
+            case COMP_LZW:
+                // LZW compression used, need to create the LZW decoder.
+                TIFFField predictorField =
+                    dir.getField(TIFFImageDecoder.TIFF_PREDICTOR);
+
+                if (predictorField == null) {
+                    predictor = 1;
+                } else {
+                    predictor = predictorField.getAsInt(0);
+
+                    if (predictor != 1 && predictor != 2) {
+                        throw new RuntimeException("TIFFImage8");
+                    }
+
+                    if (predictor == 2 && sampleSize != 8) {
+                        throw new RuntimeException(sampleSize +
+                                                   "TIFFImage9");
+                    }
+                }
+
+                lzwDecoder = new TIFFLZWDecoder(tileWidth, predictor,
+                                                samplesPerPixel);
+                break;
+
+            case COMP_JPEG_OLD:
+                throw new RuntimeException("TIFFImage15");
+
+            case COMP_JPEG_TTN2:
+                if(!(sampleSize == 8 &&
+                     ((imageType == TYPE_GRAY && samplesPerPixel == 1) ||
+                      (imageType == TYPE_PALETTE && samplesPerPixel == 1) ||
+                      (imageType == TYPE_RGB && samplesPerPixel == 3)))) {
+                    throw new RuntimeException("TIFFImage16");
+                }
+
+                // Create decodeParam from JPEGTables field if present.
+                if(dir.isTagPresent(TIFF_JPEG_TABLES)) {
+                    TIFFField jpegTableField = dir.getField(TIFF_JPEG_TABLES);
+                    byte[] jpegTable = jpegTableField.getAsBytes();
+                    ByteArrayInputStream tableStream =
+                        new ByteArrayInputStream(jpegTable);
+                    JPEGImageDecoder decoder =
+                        JPEGCodec.createJPEGDecoder(tableStream);
+                    decoder.decodeAsRaster();
+                    decodeParam = decoder.getJPEGDecodeParam();
+                }
+
+                break;
+            default:
+                throw new RuntimeException("TIFFImage10");
+            }
+
+            ColorModel  colorModel  = null;
+            SampleModel sampleModel = null;
+            switch(imageType) {
+            case TYPE_BILEVEL:
+            case TYPE_GRAY_4BIT:
+                sampleModel =
+                    new MultiPixelPackedSampleModel(dataType,
+                                                    tileWidth,
+                                                    tileHeight,
+                                                    sampleSize);
+                if(imageType == TYPE_BILEVEL) {
+                    byte[] map = new byte[] {(byte)(isWhiteZero ? 255 : 0),
+                                             (byte)(isWhiteZero ? 0 : 255)};
+                    colorModel = new IndexColorModel(1, 2, map, map, map);
+                } else {
+                    byte [] map = new byte[16];
+                    if (isWhiteZero) {
+                        for (int i=0; i<map.length; i++)
+                            map[i] = (byte)(255-(16*i));
+                    } else {
+                        for (int i=0; i<map.length; i++)
+                            map[i] = (byte)(16*i);
+                    }
+                    colorModel = new IndexColorModel(4, 16, map, map, map);
+                }
+                break;
+
+            case TYPE_GRAY:
+            case TYPE_GRAY_ALPHA:
+            case TYPE_RGB:
+            case TYPE_RGB_ALPHA:
+                // Create a pixel interleaved SampleModel with decreasing
+                // band offsets.
+                int[] reverseOffsets = new int[numBands];
+                for (int i=0; i<numBands; i++) {
+                    reverseOffsets[i] = numBands - 1 - i;
+                }
+                sampleModel = new PixelInterleavedSampleModel
+                    (dataType, tileWidth, tileHeight,
+                     numBands, numBands*tileWidth, reverseOffsets);
+
+                if(imageType == TYPE_GRAY) {
+                  colorModel = new ComponentColorModel
+                    (ColorSpace.getInstance(ColorSpace.CS_GRAY),
+                     new int[] { sampleSize }, false, false,
+                     Transparency.OPAQUE, dataType);
+                } else if (imageType == TYPE_RGB) {
+                  colorModel = new ComponentColorModel
+                    (ColorSpace.getInstance(ColorSpace.CS_sRGB),
+                     new int[] { sampleSize, sampleSize, sampleSize },
+                     false, false, Transparency.OPAQUE, dataType);
+                } else { // hasAlpha
+                    // Transparency.OPAQUE signifies image data that is
+                    // completely opaque, meaning that all pixels have an alpha
+                    // value of 1.0. So the extra band gets ignored, which is
+                    // what we want.
+                    int transparency = Transparency.OPAQUE;
+                    if(extraSamples == 1) { // associated (premultiplied) alpha
+                        transparency = Transparency.TRANSLUCENT;
+                    } else if(extraSamples == 2) { // unassociated alpha
+                        transparency = Transparency.BITMASK;
+                    }
+
+                    colorModel =
+                        createAlphaComponentColorModel(dataType,
+                                                       numBands,
+                                                       extraSamples == 1,
+                                                       transparency);
+                }
+                break;
+
+            case TYPE_GENERIC:
+            case TYPE_YCBCR_SUB:
+                // For this case we can't display the image, so we create a
+                // SampleModel with increasing bandOffsets, and keep the
+                // ColorModel as null, as there is no appropriate ColorModel.
+
+                int[] bandOffsets = new int[numBands];
+                for (int i=0; i<numBands; i++) {
+                    bandOffsets[i] = i;
+                }
+
+                sampleModel = new PixelInterleavedSampleModel
+                    (dataType, tileWidth, tileHeight,
+                     numBands, numBands * tileWidth, bandOffsets);
+                colorModel = null;
+                break;
+
+            case TYPE_PALETTE:
+                // Get the colormap
+                TIFFField cfield = dir.getField(TIFFImageDecoder.TIFF_COLORMAP);
+                if (cfield == null) {
+                    throw new RuntimeException("TIFFImage11");
+                } else {
+                    colormap = cfield.getAsChars();
+                }
+
+                // Could be either 1 or 3 bands depending on whether we use
+                // IndexColorModel or not.
+                if (decodePaletteAsShorts) {
+                    numBands = 3;
+
+                    // If no SampleFormat tag was specified and if the
+                    // sampleSize is less than or equal to 8, then the
+                    // dataType was initially set to byte, but now we want to
+                    // expand the palette as shorts, so the dataType should
+                    // be ushort.
+                    if (dataType == DataBuffer.TYPE_BYTE) {
+                        dataType = DataBuffer.TYPE_USHORT;
+                    }
+
+                    // Data will have to be unpacked into a 3 band short image
+                    // as we do not have a IndexColorModel that can deal with
+                    // a colormodel whose entries are of short data type.
+                    sampleModel = createPixelInterleavedSampleModel
+                        (dataType, tileWidth, tileHeight, numBands);
+
+                  colorModel = new ComponentColorModel
+                    (ColorSpace.getInstance(ColorSpace.CS_sRGB),
+                     new int[] { 16, 16, 16 }, false, false,
+                     Transparency.OPAQUE, dataType);
+
+                } else {
+
+                    numBands = 1;
+
+                    if (sampleSize == 4) {
+                        // Pixel data will not be unpacked, will use
+                        // MPPSM to store packed data and
+                        // IndexColorModel to do the unpacking.
+                        sampleModel = new MultiPixelPackedSampleModel
+                            (DataBuffer.TYPE_BYTE, tileWidth, tileHeight,
+                             sampleSize);
+                    } else if (sampleSize == 8) {
+
+                        sampleModel = createPixelInterleavedSampleModel
+                            (DataBuffer.TYPE_BYTE, tileWidth, tileHeight,
+                             numBands);
+                    } else if (sampleSize == 16) {
+
+                        // Here datatype has to be unsigned since we
+                        // are storing indices into the
+                        // IndexColorModel palette. Ofcourse the
+                        // actual palette entries are allowed to be
+                        // negative.
+                        dataType = DataBuffer.TYPE_USHORT;
+                        sampleModel = createPixelInterleavedSampleModel
+                            (DataBuffer.TYPE_USHORT, tileWidth, tileHeight,
+                             numBands);
+                    }
+
+                    int bandLength = colormap.length/3;
+                    byte[] r = new byte[bandLength];
+                    byte[] g = new byte[bandLength];
+                    byte[] b = new byte[bandLength];
+
+                    int gIndex = bandLength;
+                    int bIndex = bandLength * 2;
+
+                    if (dataType == DataBuffer.TYPE_SHORT) {
+
+                        for (int i=0; i<bandLength; i++) {
+                            r[i] = param.decodeSigned16BitsTo8Bits
+                                ((short)colormap[i]);
+                            g[i] = param.decodeSigned16BitsTo8Bits
+                                ((short)colormap[gIndex+i]);
+                            b[i] = param.decodeSigned16BitsTo8Bits
+                                ((short)colormap[bIndex+i]);
+                        }
+
+                    } else {
+
+                        for (int i=0; i<bandLength; i++) {
+                            r[i] = param.decode16BitsTo8Bits
+                                (colormap[i] & 0xffff);
+                            g[i] = param.decode16BitsTo8Bits
+                                (colormap[gIndex+i] & 0xffff);
+                            b[i] = param.decode16BitsTo8Bits
+                                (colormap[bIndex+i] & 0xffff);
+                        }
+
+                    }
+
+                    colorModel = new IndexColorModel(sampleSize,
+                                                     bandLength, r, g, b);
+                }
+                break;
+
+            default:
+                throw new RuntimeException("TIFFImage4");
+            }
+
+        Map properties = new HashMap();
+        // Set a property "tiff_directory".
+        properties.put("tiff_directory", dir);
+
+        // System.out.println("Constructed TIFF");
+
+        init((CachableRed)null, bounds, colorModel, sampleModel,
+             0, 0, properties);
+    }
+
+    /**
+     * Reads a private IFD from a given offset in the stream.  This
+     * method may be used to obtain IFDs that are referenced
+     * only by private tag values.
+     */
+    public TIFFDirectory getPrivateIFD(long offset) throws IOException {
+        return new TIFFDirectory(stream, offset, 0);
+    }
+
+
+    public WritableRaster copyData(WritableRaster wr) {
+        copyToRaster(wr);
+        return wr;
+    }
+
+
+    /**
+     * Returns tile (tileX, tileY) as a Raster.
+     */
+    public synchronized Raster getTile(int tileX, int tileY) {
+        if ((tileX < 0) || (tileX >= tilesX) ||
+            (tileY < 0) || (tileY >= tilesY)) {
+            throw new IllegalArgumentException("TIFFImage12");
+        }
+
+        // System.out.println("Called TIFF getTile:" + tileX + "," + tileY);
+
+
+        // Get the data array out of the DataBuffer
+        byte[] bdata = null;
+        short[] sdata = null;
+        int[] idata = null;
+
+        SampleModel sampleModel = getSampleModel();
+        WritableRaster tile = makeTile(tileX,tileY);
+
+        DataBuffer buffer = tile.getDataBuffer();
+
+        int dataType = sampleModel.getDataType();
+        if (dataType == DataBuffer.TYPE_BYTE) {
+            bdata = ((DataBufferByte)buffer).getData();
+        } else if (dataType == DataBuffer.TYPE_USHORT) {
+            sdata = ((DataBufferUShort)buffer).getData();
+        } else if (dataType == DataBuffer.TYPE_SHORT) {
+            sdata = ((DataBufferShort)buffer).getData();
+        } else if (dataType == DataBuffer.TYPE_INT) {
+            idata = ((DataBufferInt)buffer).getData();
+        }
+
+        // Variables used for swapping when converting from RGB to BGR
+        byte bswap;
+        short sswap;
+        int iswap;
+
+        // Save original file pointer position and seek to tile data location.
+        long save_offset = 0;
+        try {
+            save_offset = stream.getFilePointer();
+            stream.seek(tileOffsets[tileY*tilesX + tileX]);
+        } catch (IOException ioe) {
+            throw new RuntimeException("TIFFImage13");
+        }
+
+        // Number of bytes in this tile (strip) after compression.
+        int byteCount = (int)tileByteCounts[tileY*tilesX + tileX];
+
+        // Find out the number of bytes in the current tile
+        Rectangle newRect;
+        if (!tiled)
+            newRect = tile.getBounds();
+        else
+            newRect = new Rectangle(tile.getMinX(), tile.getMinY(),
+                                    tileWidth, tileHeight);
+
+        int unitsInThisTile = newRect.width * newRect.height * numBands;
+
+        // Allocate read buffer if needed.
+        byte[] data = compression != COMP_NONE || imageType == TYPE_PALETTE ?
+            new byte[byteCount] : null;
+
+        // Read the data, uncompressing as needed. There are four cases:
+        // bilevel, palette-RGB, 4-bit grayscale, and everything else.
+        if(imageType == TYPE_BILEVEL) { // bilevel
+            try {
+                if (compression == COMP_PACKBITS) {
+                    stream.readFully(data, 0, byteCount);
+
+                    // Since the decompressed data will still be packed
+                    // 8 pixels into 1 byte, calculate bytesInThisTile
+                    int bytesInThisTile;
+                    if ((newRect.width % 8) == 0) {
+                        bytesInThisTile = (newRect.width/8) * newRect.height;
+                    } else {
+                        bytesInThisTile =
+                            (newRect.width/8 + 1) * newRect.height;
+                    }
+                    decodePackbits(data, bytesInThisTile, bdata);
+                } else if (compression == COMP_LZW) {
+                    stream.readFully(data, 0, byteCount);
+                    lzwDecoder.decode(data, bdata, newRect.height);
+                } else if (compression == COMP_FAX_G3_1D) {
+                    stream.readFully(data, 0, byteCount);
+                    decoder.decode1D(bdata, data, 0, newRect.height);
+                } else if (compression == COMP_FAX_G3_2D) {
+                    stream.readFully(data, 0, byteCount);
+                    decoder.decode2D(bdata, data, 0, newRect.height,
+                                     tiffT4Options);
+                } else if (compression == COMP_FAX_G4_2D) {
+                    stream.readFully(data, 0, byteCount);
+                    decoder.decodeT6(bdata, data, 0, newRect.height,
+                                     tiffT6Options);
+                } else if (compression == COMP_DEFLATE) {
+                    stream.readFully(data, 0, byteCount);
+                    inflate(data, bdata);
+                } else if (compression == COMP_NONE) {
+                    stream.readFully(bdata, 0, byteCount);
+                }
+
+                stream.seek(save_offset);
+            } catch (IOException ioe) {
+                throw new RuntimeException("TIFFImage13");
+            }
+        } else if(imageType == TYPE_PALETTE) { // palette-RGB
+            if (sampleSize == 16) {
+
+                if (decodePaletteAsShorts) {
+
+                    short[] tempData= null;
+
+                    // At this point the data is 1 banded and will
+                    // become 3 banded only after we've done the palette
+                    // lookup, since unitsInThisTile was calculated with
+                    // 3 bands, we need to divide this by 3.
+                    int unitsBeforeLookup = unitsInThisTile / 3;
+
+                    // Since unitsBeforeLookup is the number of shorts,
+                    // but we do our decompression in terms of bytes, we
+                    // need to multiply it by 2 in order to figure out
+                    // how many bytes we'll get after decompression.
+                    int entries = unitsBeforeLookup * 2;
+
+                    // Read the data, if compressed, decode it, reset the pointer
+                    try {
+
+                        if (compression == COMP_PACKBITS) {
+
+                            stream.readFully(data, 0, byteCount);
+
+                            byte[] byteArray = new byte[entries];
+                            decodePackbits(data, entries, byteArray);
+                            tempData = new short[unitsBeforeLookup];
+                            interpretBytesAsShorts(byteArray, tempData,
+                                                   unitsBeforeLookup);
+
+                        }  else if (compression == COMP_LZW) {
+
+                            // Read in all the compressed data for this tile
+                            stream.readFully(data, 0, byteCount);
+
+                            byte[] byteArray = new byte[entries];
+                            lzwDecoder.decode(data, byteArray, newRect.height);
+                            tempData = new short[unitsBeforeLookup];
+                            interpretBytesAsShorts(byteArray, tempData,
+                                                   unitsBeforeLookup);
+
+                        }  else if (compression == COMP_DEFLATE) {
+
+                            stream.readFully(data, 0, byteCount);
+                            byte[] byteArray = new byte[entries];
+                            inflate(data, byteArray);
+                            tempData = new short[unitsBeforeLookup];
+                            interpretBytesAsShorts(byteArray, tempData,
+                                                   unitsBeforeLookup);
+
+                        } else if (compression == COMP_NONE) {
+
+                            // byteCount tells us how many bytes are there
+                            // in this tile, but we need to read in shorts,
+                            // which will take half the space, so while
+                            // allocating we divide byteCount by 2.
+                            tempData = new short[byteCount/2];
+                            readShorts(byteCount/2, tempData);
+                        }
+
+                        stream.seek(save_offset);
+
+                    } catch (IOException ioe) {
+                        throw new RuntimeException("TIFFImage13");
+                    }
+
+                    if (dataType == DataBuffer.TYPE_USHORT) {
+
+                        // Expand the palette image into an rgb image with ushort
+                        // data type.
+                        int cmapValue;
+                        int count = 0, lookup, len = colormap.length/3;
+                        int len2 = len * 2;
+                        for (int i=0; i<unitsBeforeLookup; i++) {
+                            // Get the index into the colormap
+                            lookup = tempData[i] & 0xffff;
+                            // Get the blue value
+                            cmapValue = colormap[lookup+len2];
+                            sdata[count++] = (short)(cmapValue & 0xffff);
+                            // Get the green value
+                            cmapValue = colormap[lookup+len];
+                            sdata[count++] = (short)(cmapValue & 0xffff);
+                            // Get the red value
+                            cmapValue = colormap[lookup];
+                            sdata[count++] = (short)(cmapValue & 0xffff);
+                        }
+
+                    } else if (dataType == DataBuffer.TYPE_SHORT) {
+
+                        // Expand the palette image into an rgb image with
+                        // short data type.
+                        int cmapValue;
+                        int count = 0, lookup, len = colormap.length/3;
+                        int len2 = len * 2;
+                        for (int i=0; i<unitsBeforeLookup; i++) {
+                            // Get the index into the colormap
+                            lookup = tempData[i] & 0xffff;
+                            // Get the blue value
+                            cmapValue = colormap[lookup+len2];
+                            sdata[count++] = (short)cmapValue;
+                            // Get the green value
+                            cmapValue = colormap[lookup+len];
+                            sdata[count++] = (short)cmapValue;
+                            // Get the red value
+                            cmapValue = colormap[lookup];
+                            sdata[count++] = (short)cmapValue;
+                        }
+                    }
+
+                } else {
+
+                    // No lookup being done here, when RGB values are needed,
+                    // the associated IndexColorModel can be used to get them.
+
+                    try {
+
+                        if (compression == COMP_PACKBITS) {
+
+                            stream.readFully(data, 0, byteCount);
+
+                            // Since unitsInThisTile is the number of shorts,
+                            // but we do our decompression in terms of bytes, we
+                            // need to multiply unitsInThisTile by 2 in order to
+                            // figure out how many bytes we'll get after
+                            // decompression.
+                            int bytesInThisTile = unitsInThisTile * 2;
+
+                            byte[] byteArray = new byte[bytesInThisTile];
+                            decodePackbits(data, bytesInThisTile, byteArray);
+                            interpretBytesAsShorts(byteArray, sdata,
+                                                   unitsInThisTile);
+
+                        } else if (compression == COMP_LZW) {
+
+                            stream.readFully(data, 0, byteCount);
+
+                            // Since unitsInThisTile is the number of shorts,
+                            // but we do our decompression in terms of bytes, we
+                            // need to multiply unitsInThisTile by 2 in order to
+                            // figure out how many bytes we'll get after
+                            // decompression.
+                            byte[] byteArray = new byte[unitsInThisTile * 2];
+                            lzwDecoder.decode(data, byteArray, newRect.height);
+                            interpretBytesAsShorts(byteArray, sdata,
+                                                   unitsInThisTile);
+
+                        }  else if (compression == COMP_DEFLATE) {
+
+                            stream.readFully(data, 0, byteCount);
+                            byte[] byteArray = new byte[unitsInThisTile * 2];
+                            inflate(data, byteArray);
+                            interpretBytesAsShorts(byteArray, sdata,
+                                                   unitsInThisTile);
+
+                        } else if (compression == COMP_NONE) {
+
+                            readShorts(byteCount/2, sdata);
+                        }
+
+                        stream.seek(save_offset);
+
+                    } catch (IOException ioe) {
+                        throw new RuntimeException("TIFFImage13");
+                    }
+                }
+
+            } else if (sampleSize == 8) {
+
+                if (decodePaletteAsShorts) {
+
+                    byte[] tempData= null;
+
+                    // At this point the data is 1 banded and will
+                    // become 3 banded only after we've done the palette
+                    // lookup, since unitsInThisTile was calculated with
+                    // 3 bands, we need to divide this by 3.
+                    int unitsBeforeLookup = unitsInThisTile / 3;
+
+                    // Read the data, if compressed, decode it, reset the pointer
+                    try {
+
+                        if (compression == COMP_PACKBITS) {
+
+                            stream.readFully(data, 0, byteCount);
+                            tempData = new byte[unitsBeforeLookup];
+                            decodePackbits(data, unitsBeforeLookup, tempData);
+
+                        }  else if (compression == COMP_LZW) {
+
+                            stream.readFully(data, 0, byteCount);
+                            tempData = new byte[unitsBeforeLookup];
+                            lzwDecoder.decode(data, tempData, newRect.height);
+
+                        } else if (compression == COMP_JPEG_TTN2) {
+
+                            stream.readFully(data, 0, byteCount);
+                            Raster tempTile = decodeJPEG(data,
+                                                         decodeParam,
+                                                         colorConvertJPEG,
+                                                         tile.getMinX(),
+                                                         tile.getMinY());
+                            int[] tempPixels = new int[unitsBeforeLookup];
+                            tempTile.getPixels(tile.getMinX(),
+                                               tile.getMinY(),
+                                               tile.getWidth(),
+                                               tile.getHeight(),
+                                               tempPixels);
+                            tempData = new byte[unitsBeforeLookup];
+                            for(int i = 0; i < unitsBeforeLookup; i++) {
+                                tempData[i] = (byte)tempPixels[i];
+                            }
+
+                        }  else if (compression == COMP_DEFLATE) {
+
+                            stream.readFully(data, 0, byteCount);
+                            tempData = new byte[unitsBeforeLookup];
+                            inflate(data, tempData);
+
+                        } else if (compression == COMP_NONE) {
+
+                            tempData = new byte[byteCount];
+                            stream.readFully(tempData, 0, byteCount);
+                        }
+
+                        stream.seek(save_offset);
+
+                    } catch (IOException ioe) {
+                        throw new RuntimeException("TIFFImage13");
+                    }
+
+                    // Expand the palette image into an rgb image with ushort
+                    // data type.
+                    int cmapValue;
+                    int count = 0, lookup, len = colormap.length/3;
+                    int len2 = len * 2;
+                    for (int i=0; i<unitsBeforeLookup; i++) {
+                        // Get the index into the colormap
+                        lookup = tempData[i] & 0xff;
+                        // Get the blue value
+                        cmapValue = colormap[lookup+len2];
+                        sdata[count++] = (short)(cmapValue & 0xffff);
+                        // Get the green value
+                        cmapValue = colormap[lookup+len];
+                        sdata[count++] = (short)(cmapValue & 0xffff);
+                        // Get the red value
+                        cmapValue = colormap[lookup];
+                        sdata[count++] = (short)(cmapValue & 0xffff);
+                    }
+                } else {
+
+                    // No lookup being done here, when RGB values are needed,
+                    // the associated IndexColorModel can be used to get them.
+
+                    try {
+
+                        if (compression == COMP_PACKBITS) {
+
+                            stream.readFully(data, 0, byteCount);
+                            decodePackbits(data, unitsInThisTile, bdata);
+
+                        } else if (compression == COMP_LZW) {
+
+                            stream.readFully(data, 0, byteCount);
+                            lzwDecoder.decode(data, bdata, newRect.height);
+
+                        } else if (compression == COMP_JPEG_TTN2) {
+
+                            stream.readFully(data, 0, byteCount);
+                            tile.setRect(decodeJPEG(data,
+                                                    decodeParam,
+                                                    colorConvertJPEG,
+                                                    tile.getMinX(),
+                                                    tile.getMinY()));
+
+                        }  else if (compression == COMP_DEFLATE) {
+
+                            stream.readFully(data, 0, byteCount);
+                            inflate(data, bdata);
+
+                        } else if (compression == COMP_NONE) {
+
+                            stream.readFully(bdata, 0, byteCount);
+                        }
+
+                        stream.seek(save_offset);
+
+                    } catch (IOException ioe) {
+                        throw new RuntimeException("TIFFImage13");
+                    }
+                }
+
+            } else if (sampleSize == 4) {
+
+                int padding = (newRect.width % 2 == 0) ? 0 : 1;
+                int bytesPostDecoding = ((newRect.width/2 + padding) *
+                                         newRect.height);
+
+                // Output short images
+                if (decodePaletteAsShorts) {
+
+                    byte[] tempData = null;
+
+                    try {
+                        stream.readFully(data, 0, byteCount);
+                        stream.seek(save_offset);
+                    } catch (IOException ioe) {
+                        throw new RuntimeException("TIFFImage13");
+                    }
+
+                    // If compressed, decode the data.
+                    if (compression == COMP_PACKBITS) {
+
+                        tempData = new byte[bytesPostDecoding];
+                        decodePackbits(data, bytesPostDecoding, tempData);
+
+                    }  else if (compression == COMP_LZW) {
+
+                        tempData = new byte[bytesPostDecoding];
+                        lzwDecoder.decode(data, tempData, newRect.height);
+
+                    }  else if (compression == COMP_DEFLATE) {
+
+                        tempData = new byte[bytesPostDecoding];
+                        inflate(data, tempData);
+
+                    } else if (compression == COMP_NONE) {
+
+                        tempData = data;
+                    }
+
+                    int bytes = unitsInThisTile / 3;
+
+                    // Unpack the 2 pixels packed into each byte.
+                    data = new byte[bytes];
+
+                    int srcCount = 0, dstCount = 0;
+                    for (int j=0; j<newRect.height; j++) {
+                        for (int i=0; i<newRect.width/2; i++) {
+                            data[dstCount++] =
+                                (byte)((tempData[srcCount] & 0xf0) >> 4);
+                            data[dstCount++] =
+                                (byte)(tempData[srcCount++] & 0x0f);
+                        }
+
+                        if (padding == 1) {
+                            data[dstCount++] =
+                                (byte)((tempData[srcCount++] & 0xf0) >> 4);
+                        }
+                    }
+
+                    int len = colormap.length/3;
+                    int len2 = len*2;
+                    int cmapValue, lookup;
+                    int count = 0;
+                    for (int i=0; i<bytes; i++) {
+                        lookup = data[i] & 0xff;
+                        cmapValue = colormap[lookup+len2];
+                        sdata[count++] = (short)(cmapValue & 0xffff);
+                        cmapValue = colormap[lookup+len];
+                        sdata[count++] = (short)(cmapValue & 0xffff);
+                        cmapValue = colormap[lookup];
+                        sdata[count++] = (short)(cmapValue & 0xffff);
+                    }
+                } else {
+
+                    // Output byte values, use IndexColorModel for unpacking
+                    try {
+
+                        // If compressed, decode the data.
+                        if (compression == COMP_PACKBITS) {
+
+                            stream.readFully(data, 0, byteCount);
+                            decodePackbits(data, bytesPostDecoding, bdata);
+
+                        }  else if (compression == COMP_LZW) {
+
+                            stream.readFully(data, 0, byteCount);
+                            lzwDecoder.decode(data, bdata, newRect.height);
+
+                        }  else if (compression == COMP_DEFLATE) {
+
+                            stream.readFully(data, 0, byteCount);
+                            inflate(data, bdata);
+
+                        } else if (compression == COMP_NONE) {
+
+                            stream.readFully(bdata, 0, byteCount);
+                        }
+
+                        stream.seek(save_offset);
+
+                    } catch (IOException ioe) {
+                        throw new RuntimeException("TIFFImage13");
+                    }
+                }
+            }
+        } else if(imageType == TYPE_GRAY_4BIT) { // 4-bit gray
+            try {
+                if (compression == COMP_PACKBITS) {
+
+                    stream.readFully(data, 0, byteCount);
+
+                    // Since the decompressed data will still be packed
+                    // 2 pixels into 1 byte, calculate bytesInThisTile
+                    int bytesInThisTile;
+                    if ((newRect.width % 8) == 0) {
+                        bytesInThisTile = (newRect.width/2) * newRect.height;
+                    } else {
+                        bytesInThisTile = (newRect.width/2 + 1) *
+                            newRect.height;
+                    }
+
+                    decodePackbits(data, bytesInThisTile, bdata);
+
+                } else if (compression == COMP_LZW) {
+
+                    stream.readFully(data, 0, byteCount);
+                    lzwDecoder.decode(data, bdata, newRect.height);
+
+                }  else if (compression == COMP_DEFLATE) {
+
+                    stream.readFully(data, 0, byteCount);
+                    inflate(data, bdata);
+
+                } else {
+
+                    stream.readFully(bdata, 0, byteCount);
+                }
+
+                stream.seek(save_offset);
+            } catch (IOException ioe) {
+                throw new RuntimeException("TIFFImage13");
+            }
+        } else { // everything else
+            try {
+
+                if (sampleSize == 8) {
+
+                    if (compression == COMP_NONE) {
+                        stream.readFully(bdata, 0, byteCount);
+
+                    } else if (compression == COMP_LZW) {
+
+                        stream.readFully(data, 0, byteCount);
+                        lzwDecoder.decode(data, bdata, newRect.height);
+
+                    } else if (compression == COMP_PACKBITS) {
+
+                        stream.readFully(data, 0, byteCount);
+                        decodePackbits(data, unitsInThisTile, bdata);
+
+                    } else if (compression == COMP_JPEG_TTN2) {
+
+                        stream.readFully(data, 0, byteCount);
+                        tile.setRect(decodeJPEG(data,
+                                                decodeParam,
+                                                colorConvertJPEG,
+                                                tile.getMinX(),
+                                                tile.getMinY()));
+                    } else if (compression == COMP_DEFLATE) {
+
+                        stream.readFully(data, 0, byteCount);
+                        inflate(data, bdata);
+                    }
+
+                } else if (sampleSize == 16) {
+
+                    if (compression == COMP_NONE) {
+
+                        readShorts(byteCount/2, sdata);
+
+                    } else if (compression == COMP_LZW) {
+
+                        stream.readFully(data, 0, byteCount);
+
+                        // Since unitsInThisTile is the number of shorts,
+                        // but we do our decompression in terms of bytes, we
+                        // need to multiply unitsInThisTile by 2 in order to
+                        // figure out how many bytes we'll get after
+                        // decompression.
+                        byte[] byteArray = new byte[unitsInThisTile * 2];
+                        lzwDecoder.decode(data, byteArray, newRect.height);
+                        interpretBytesAsShorts(byteArray, sdata,
+                                               unitsInThisTile);
+
+                    } else if (compression == COMP_PACKBITS) {
+
+                        stream.readFully(data, 0, byteCount);
+
+                        // Since unitsInThisTile is the number of shorts,
+                        // but we do our decompression in terms of bytes, we
+                        // need to multiply unitsInThisTile by 2 in order to
+                        // figure out how many bytes we'll get after
+                        // decompression.
+                        int bytesInThisTile = unitsInThisTile * 2;
+
+                        byte[] byteArray = new byte[bytesInThisTile];
+                        decodePackbits(data, bytesInThisTile, byteArray);
+                        interpretBytesAsShorts(byteArray, sdata,
+                                               unitsInThisTile);
+                    } else if (compression == COMP_DEFLATE) {
+
+                        stream.readFully(data, 0, byteCount);
+                        byte[] byteArray = new byte[unitsInThisTile * 2];
+                        inflate(data, byteArray);
+                        interpretBytesAsShorts(byteArray, sdata,
+                                               unitsInThisTile);
+
+                    }
+                } else if (sampleSize == 32 &&
+                           dataType == DataBuffer.TYPE_INT) { // redundant
+                    if (compression == COMP_NONE) {
+
+                        readInts(byteCount/4, idata);
+
+                    } else if (compression == COMP_LZW) {
+
+                        stream.readFully(data, 0, byteCount);
+
+                        // Since unitsInThisTile is the number of ints,
+                        // but we do our decompression in terms of bytes, we
+                        // need to multiply unitsInThisTile by 4 in order to
+                        // figure out how many bytes we'll get after
+                        // decompression.
+                        byte[] byteArray = new byte[unitsInThisTile * 4];
+                        lzwDecoder.decode(data, byteArray, newRect.height);
+                        interpretBytesAsInts(byteArray, idata,
+                                             unitsInThisTile);
+
+                    } else if (compression == COMP_PACKBITS) {
+
+                        stream.readFully(data, 0, byteCount);
+
+                        // Since unitsInThisTile is the number of ints,
+                        // but we do our decompression in terms of bytes, we
+                        // need to multiply unitsInThisTile by 4 in order to
+                        // figure out how many bytes we'll get after
+                        // decompression.
+                        int bytesInThisTile = unitsInThisTile * 4;
+
+                        byte[] byteArray = new byte[bytesInThisTile];
+                        decodePackbits(data, bytesInThisTile, byteArray);
+                        interpretBytesAsInts(byteArray, idata,
+                                             unitsInThisTile);
+                    } else if (compression == COMP_DEFLATE) {
+
+                        stream.readFully(data, 0, byteCount);
+                        byte[] byteArray = new byte[unitsInThisTile * 4];
+                        inflate(data, byteArray);
+                        interpretBytesAsInts(byteArray, idata,
+                                             unitsInThisTile);
+
+                    }
+                }
+
+                stream.seek(save_offset);
+
+            } catch (IOException ioe) {
+                throw new RuntimeException("TIFFImage13");
+            }
+
+            // Modify the data for certain special cases.
+            switch(imageType) {
+            case TYPE_GRAY:
+            case TYPE_GRAY_ALPHA:
+                if(isWhiteZero) {
+                    // Since we are using a ComponentColorModel with this
+                    // image, we need to change the WhiteIsZero data to
+                    // BlackIsZero data so it will display properly.
+                    if (dataType == DataBuffer.TYPE_BYTE &&
+                        !(getColorModel() instanceof IndexColorModel)) {
+
+                        for (int l = 0; l < bdata.length; l += numBands) {
+                            bdata[l] = (byte)(255 - bdata[l]);
+                        }
+                    } else if (dataType == DataBuffer.TYPE_USHORT) {
+
+                        int ushortMax = Short.MAX_VALUE - Short.MIN_VALUE;
+                        for (int l = 0; l < sdata.length; l += numBands) {
+                            sdata[l] = (short)(ushortMax - sdata[l]);
+                        }
+
+                    } else if (dataType == DataBuffer.TYPE_SHORT) {
+
+                        for (int l = 0; l < sdata.length; l += numBands) {
+                            sdata[l] = (short)(~sdata[l]);
+                        }
+                    } else if (dataType == DataBuffer.TYPE_INT) {
+
+                        long uintMax = ((long)Integer.MAX_VALUE -
+                                        (long)Integer.MIN_VALUE);
+                        for (int l = 0; l < idata.length; l += numBands) {
+                            idata[l] = (int)(uintMax - idata[l]);
+                        }
+                    }
+                }
+                break;
+            case TYPE_RGB:
+                // Change RGB to BGR order, as Java2D displays that faster.
+                // Unnecessary for JPEG-in-TIFF as the decoder handles it.
+                if (sampleSize == 8 && compression != COMP_JPEG_TTN2) {
+                    for (int i=0; i<unitsInThisTile; i+=3) {
+                        bswap = bdata[i];
+                        bdata[i] = bdata[i+2];
+                        bdata[i+2] = bswap;
+                    }
+                } else if (sampleSize == 16) {
+                    for (int i=0; i<unitsInThisTile; i+=3) {
+                        sswap = sdata[i];
+                        sdata[i] = sdata[i+2];
+                        sdata[i+2] = sswap;
+                    }
+                } else if (sampleSize == 32) {
+                    if(dataType == DataBuffer.TYPE_INT) {
+                        for (int i=0; i<unitsInThisTile; i+=3) {
+                            iswap = idata[i];
+                            idata[i] = idata[i+2];
+                            idata[i+2] = iswap;
+                        }
+                    }
+                }
+                break;
+            case TYPE_RGB_ALPHA:
+                // Convert from RGBA to ABGR for Java2D
+                if (sampleSize == 8) {
+                    for (int i=0; i<unitsInThisTile; i+=4) {
+                        // Swap R and A
+                        bswap = bdata[i];
+                        bdata[i] = bdata[i+3];
+                        bdata[i+3] = bswap;
+
+                        // Swap G and B
+                        bswap = bdata[i+1];
+                        bdata[i+1] = bdata[i+2];
+                        bdata[i+2] = bswap;
+                    }
+                } else if (sampleSize == 16) {
+                    for (int i=0; i<unitsInThisTile; i+=4) {
+                        // Swap R and A
+                        sswap = sdata[i];
+                        sdata[i] = sdata[i+3];
+                        sdata[i+3] = sswap;
+
+                        // Swap G and B
+                        sswap = sdata[i+1];
+                        sdata[i+1] = sdata[i+2];
+                        sdata[i+2] = sswap;
+                    }
+                } else if (sampleSize == 32) {
+                    if(dataType == DataBuffer.TYPE_INT) {
+                        for (int i=0; i<unitsInThisTile; i+=4) {
+                            // Swap R and A
+                            iswap = idata[i];
+                            idata[i] = idata[i+3];
+                            idata[i+3] = iswap;
+
+                            // Swap G and B
+                            iswap = idata[i+1];
+                            idata[i+1] = idata[i+2];
+                            idata[i+2] = iswap;
+                        }
+                    }
+                }
+                break;
+            case TYPE_YCBCR_SUB:
+                // Post-processing for YCbCr with subsampled chrominance:
+                // simply replicate the chroma channels for displayability.
+                int pixelsPerDataUnit = chromaSubH*chromaSubV;
+
+                int numH = newRect.width/chromaSubH;
+                int numV = newRect.height/chromaSubV;
+
+                byte[] tempData = new byte[numH*numV*(pixelsPerDataUnit + 2)];
+                System.arraycopy(bdata, 0, tempData, 0, tempData.length);
+
+                int samplesPerDataUnit = pixelsPerDataUnit*3;
+                int[] pixels = new int[samplesPerDataUnit];
+
+                int bOffset = 0;
+                int offsetCb = pixelsPerDataUnit;
+                int offsetCr = offsetCb + 1;
+
+                int y = newRect.y;
+                for(int j = 0; j < numV; j++) {
+                    int x = newRect.x;
+                    for(int i = 0; i < numH; i++) {
+                        int Cb = tempData[bOffset + offsetCb];
+                        int Cr = tempData[bOffset + offsetCr];
+                        int k = 0;
+                        while(k < samplesPerDataUnit) {
+                            pixels[k++] = tempData[bOffset++];
+                            pixels[k++] = Cb;
+                            pixels[k++] = Cr;
+                        }
+                        bOffset += 2;
+                        tile.setPixels(x, y, chromaSubH, chromaSubV, pixels);
+                        x += chromaSubH;
+                    }
+                    y += chromaSubV;
+                }
+
+                break;
+            }
+        }
+
+        return tile;
+    }
+
+    private void readShorts(int shortCount, short[] shortArray) {
+
+        // Since each short consists of 2 bytes, we need a
+        // byte array of double size
+        int byteCount = 2 * shortCount;
+        byte[] byteArray = new byte[byteCount];
+
+        try {
+            stream.readFully(byteArray, 0, byteCount);
+        } catch (IOException ioe) {
+            throw new RuntimeException("TIFFImage13");
+        }
+
+        interpretBytesAsShorts(byteArray, shortArray, shortCount);
+    }
+
+    private void readInts(int intCount, int[] intArray) {
+
+        // Since each int consists of 4 bytes, we need a
+        // byte array of quadruple size
+        int byteCount = 4 * intCount;
+        byte[] byteArray = new byte[byteCount];
+
+        try {
+            stream.readFully(byteArray, 0, byteCount);
+        } catch (IOException ioe) {
+            throw new RuntimeException("TIFFImage13");
+        }
+
+        interpretBytesAsInts(byteArray, intArray, intCount);
+    }
+
+    // Method to interpret a byte array to a short array, depending on
+    // whether the bytes are stored in a big endian or little endian format.
+    private void interpretBytesAsShorts(byte[] byteArray,
+                                        short[] shortArray,
+                                        int shortCount) {
+
+        int j = 0;
+        int firstByte, secondByte;
+
+        if (isBigEndian) {
+
+            for (int i=0; i<shortCount; i++) {
+                firstByte = byteArray[j++] & 0xff;
+                secondByte = byteArray[j++] & 0xff;
+                shortArray[i] = (short)((firstByte << 8) + secondByte);
+            }
+
+        } else {
+
+            for (int i=0; i<shortCount; i++) {
+                firstByte = byteArray[j++] & 0xff;
+                secondByte = byteArray[j++] & 0xff;
+                shortArray[i] = (short)((secondByte << 8) + firstByte);
+            }
+        }
+    }
+
+    // Method to interpret a byte array to a int array, depending on
+    // whether the bytes are stored in a big endian or little endian format.
+    private void interpretBytesAsInts(byte[] byteArray,
+                                      int[] intArray,
+                                      int intCount) {
+
+        int j = 0;
+
+        if (isBigEndian) {
+
+            for (int i=0; i<intCount; i++) {
+                intArray[i] = (((byteArray[j++] & 0xff) << 24) |
+                               ((byteArray[j++] & 0xff) << 16) |
+                               ((byteArray[j++] & 0xff) << 8) |
+                               ( byteArray[j++] & 0xff));
+            }
+
+        } else {
+
+            for (int i=0; i<intCount; i++) {
+                intArray[i] = ((byteArray[j++] & 0xff) |
+                              ((byteArray[j++] & 0xff) << 8) |
+                              ((byteArray[j++] & 0xff) << 16) |
+                              ((byteArray[j++] & 0xff) << 24));
+            }
+        }
+    }
+
+    // Uncompress packbits compressed image data.
+    private byte[] decodePackbits(byte[] data, int arraySize, byte[] dst) {
+
+        if (dst == null) {
+            dst = new byte[arraySize];
+        }
+
+        int srcCount = 0, dstCount = 0;
+        byte repeat, b;
+
+        try {
+
+            while (dstCount < arraySize) {
+
+                b = data[srcCount++];
+
+                if (b >= 0 && b <= 127) {
+
+                    // literal run packet
+                    for (int i=0; i<(b + 1); i++) {
+                        dst[dstCount++] = data[srcCount++];
+                    }
+
+                } else if (b <= -1 && b >= -127) {
+
+                    // 2 byte encoded run packet
+                    repeat = data[srcCount++];
+                    for (int i=0; i<(-b + 1); i++) {
+                        dst[dstCount++] = repeat;
+                    }
+
+                } else {
+                    // no-op packet. Do nothing
+                    srcCount++;
+                }
+            }
+        } catch (java.lang.ArrayIndexOutOfBoundsException ae) {
+            throw new RuntimeException("TIFFImage14");
+        }
+
+        return dst;
+    }
+
+    // Need a createColorModel().
+    // Create ComponentColorModel for TYPE_RGB images
+    private ComponentColorModel createAlphaComponentColorModel
+    (int dataType, int numBands,
+     boolean isAlphaPremultiplied, int transparency) {
+
+        ComponentColorModel ccm = null;
+        int[] RGBBits = null;
+        ColorSpace cs = null;
+        switch(numBands) {
+            case 2: // gray+alpha
+                cs = ColorSpace.getInstance(ColorSpace.CS_GRAY);
+                break;
+            case 4: // RGB+alpha
+                cs = ColorSpace.getInstance(ColorSpace.CS_sRGB);
+                break;
+            default:
+                throw new IllegalArgumentException();
+        }
+
+        int componentSize = 0;
+        switch(dataType) {
+            case DataBuffer.TYPE_BYTE:
+                componentSize = 8;
+                break;
+            case DataBuffer.TYPE_USHORT:
+            case DataBuffer.TYPE_SHORT:
+                componentSize = 16;
+                break;
+            case DataBuffer.TYPE_INT:
+                componentSize = 32;
+                break;
+            default:
+                throw new IllegalArgumentException();
+        }
+
+        RGBBits = new int[numBands];
+        for(int i = 0; i < numBands; i++) {
+            RGBBits[i] = componentSize;
+        }
+
+        ccm = new ComponentColorModel(cs,
+                                      RGBBits,
+                                      true,
+                                      isAlphaPremultiplied,
+                                      transparency,
+                                      dataType);
+
+
+        return ccm;
+    }
+
+}

Propchange: incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext/awt/image/codec/tiff/TIFFImage.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext/awt/image/codec/tiff/TIFFImageDecoder.java
URL: http://svn.apache.org/viewvc/incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext/awt/image/codec/tiff/TIFFImageDecoder.java?rev=1402274&view=auto
==============================================================================
--- incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext/awt/image/codec/tiff/TIFFImageDecoder.java (added)
+++ incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext/awt/image/codec/tiff/TIFFImageDecoder.java Thu Oct 25 19:01:43 2012
@@ -0,0 +1,88 @@
+/*
+
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+ */
+package org.apache.flex.forks.batik.ext.awt.image.codec.tiff;
+
+import java.awt.image.RenderedImage;
+import java.io.IOException;
+
+import org.apache.flex.forks.batik.ext.awt.image.codec.util.ImageDecodeParam;
+import org.apache.flex.forks.batik.ext.awt.image.codec.util.ImageDecoderImpl;
+import org.apache.flex.forks.batik.ext.awt.image.codec.util.SeekableStream;
+
+/**
+ * A baseline TIFF reader. The reader has some functionality in addition to
+ * the baseline specifications for Bilevel images, for which the group 3 and
+ * group 4 decompression schemes have been implemented. Support for LZW
+ * decompression has also been added. Support for Horizontal differencing
+ * predictor decoding is also included, when used with LZW compression.
+ * However, this support is limited to data with bitsPerSample value of 8.
+ * When reading in RGB images, support for alpha and extraSamples being
+ * present has been added. Support for reading in images with 16 bit samples
+ * has been added. Support for the SampleFormat tag (signed samples as well
+ * as floating-point samples) has also been added. In all other cases, support
+ * is limited to Baseline specifications.
+ *
+ * @version $Id: TIFFImageDecoder.java 498740 2007-01-22 18:35:57Z dvholten $
+ */
+public class TIFFImageDecoder extends ImageDecoderImpl {
+
+    // All the TIFF tags that we care about
+    public static final int TIFF_IMAGE_WIDTH                = 256;
+    public static final int TIFF_IMAGE_LENGTH               = 257;
+    public static final int TIFF_BITS_PER_SAMPLE            = 258;
+    public static final int TIFF_COMPRESSION                = 259;
+    public static final int TIFF_PHOTOMETRIC_INTERPRETATION = 262;
+    public static final int TIFF_FILL_ORDER                 = 266;
+    public static final int TIFF_STRIP_OFFSETS              = 273;
+    public static final int TIFF_SAMPLES_PER_PIXEL          = 277;
+    public static final int TIFF_ROWS_PER_STRIP             = 278;
+    public static final int TIFF_STRIP_BYTE_COUNTS          = 279;
+    public static final int TIFF_X_RESOLUTION               = 282;
+    public static final int TIFF_Y_RESOLUTION               = 283;
+    public static final int TIFF_PLANAR_CONFIGURATION       = 284;
+    public static final int TIFF_T4_OPTIONS                 = 292;
+    public static final int TIFF_T6_OPTIONS                 = 293;
+    public static final int TIFF_RESOLUTION_UNIT            = 296;
+    public static final int TIFF_PREDICTOR                  = 317;
+    public static final int TIFF_COLORMAP                   = 320;
+    public static final int TIFF_TILE_WIDTH                 = 322;
+    public static final int TIFF_TILE_LENGTH                = 323;
+    public static final int TIFF_TILE_OFFSETS               = 324;
+    public static final int TIFF_TILE_BYTE_COUNTS           = 325;
+    public static final int TIFF_EXTRA_SAMPLES              = 338;
+    public static final int TIFF_SAMPLE_FORMAT              = 339;
+    public static final int TIFF_S_MIN_SAMPLE_VALUE         = 340;
+    public static final int TIFF_S_MAX_SAMPLE_VALUE         = 341;
+
+    public TIFFImageDecoder(SeekableStream input,
+                            ImageDecodeParam param) {
+        super(input, param);
+    }
+
+    public int getNumPages() throws IOException {
+        return TIFFDirectory.getNumDirectories(input);
+    }
+
+    public RenderedImage decodeAsRenderedImage(int page) throws IOException {
+        if  ((page < 0) || (page >= getNumPages())) {
+            throw new IOException("TIFFImageDecoder0");
+        }
+        return new TIFFImage(input, (TIFFDecodeParam)param, page);
+    }
+}

Propchange: incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext/awt/image/codec/tiff/TIFFImageDecoder.java
------------------------------------------------------------------------------
    svn:eol-style = native