< prev index next >

src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFDecompressor.java

Print this page

        

@@ -154,10 +154,15 @@
      * {@code true} if the image is encoded using separate planes.
      */
     protected boolean planar;
 
     /**
+     * The planar band to decode; ignored for chunky (interleaved) images.
+     */
+    protected int planarBand = 0;
+
+    /**
      * The value of the {@code SamplesPerPixel} tag.
      */
     protected int samplesPerPixel;
 
     /**

@@ -444,28 +449,23 @@
 
     /**
      * Create a {@code ComponentColorModel} for use in creating
      * an {@code ImageTypeSpecifier}.
      */
-    // This code was copied from javax.imageio.ImageTypeSpecifier.
+    // This code was inspired by the method of the same name in
+    // javax.imageio.ImageTypeSpecifier
     static ColorModel createComponentCM(ColorSpace colorSpace,
                                         int numBands,
+                                        int[] bitsPerSample,
                                         int dataType,
                                         boolean hasAlpha,
                                         boolean isAlphaPremultiplied) {
         int transparency =
             hasAlpha ? Transparency.TRANSLUCENT : Transparency.OPAQUE;
 
-        int[] numBits = new int[numBands];
-        int bits = DataBuffer.getDataTypeSize(dataType);
-
-        for (int i = 0; i < numBands; i++) {
-            numBits[i] = bits;
-        }
-
         return new ComponentColorModel(colorSpace,
-                                       numBits,
+                                       bitsPerSample,
                                        hasAlpha,
                                        isAlphaPremultiplied,
                                        transparency,
                                        dataType);
     }

@@ -579,18 +579,19 @@
 
     /**
      * Determines whether the {@code DataBuffer} is filled without
      * any interspersed padding bits.
      */
-    private static boolean isDataBufferBitContiguous(SampleModel sm)
+    private static boolean isDataBufferBitContiguous(SampleModel sm,
+        int[] bitsPerSample)
         throws IIOException {
         int dataTypeSize = getDataTypeSize(sm.getDataType());
 
         if(sm instanceof ComponentSampleModel) {
             int numBands = sm.getNumBands();
             for(int i = 0; i < numBands; i++) {
-                if(sm.getSampleSize(i) != dataTypeSize) {
+                if(bitsPerSample[i] != dataTypeSize) {
                     // Sample does not fill data element.
                     return false;
                 }
             }
         } else if(sm instanceof MultiPixelPackedSampleModel) {

@@ -680,20 +681,20 @@
     /**
      * Reformats bit-discontiguous data into the {@code DataBuffer}
      * of the supplied {@code WritableRaster}.
      */
     private static void reformatDiscontiguousData(byte[] buf,
+                                                  int[] bitsPerSample,
                                                   int stride,
                                                   int w,
                                                   int h,
                                                   WritableRaster raster)
         throws IOException {
 
         // Get SampleModel info.
         SampleModel sm = raster.getSampleModel();
         int numBands = sm.getNumBands();
-        int[] sampleSize = sm.getSampleSize();
 
         // Initialize input stream.
         ByteArrayInputStream is = new ByteArrayInputStream(buf);
         ImageInputStream iis = new MemoryCacheImageInputStream(is);
 

@@ -703,11 +704,11 @@
         for(int j = 0; j < h; j++, y++) {
             iis.seek(iisPosition);
             int x = raster.getMinX();
             for(int i = 0; i < w; i++, x++) {
                 for(int b = 0; b < numBands; b++) {
-                    long bits = iis.readBits(sampleSize[b]);
+                    long bits = iis.readBits(bitsPerSample[b]);
                     raster.setSample(x, y, b, (int)bits);
                 }
             }
             iisPosition += stride;
         }

@@ -804,12 +805,19 @@
                     redLut[i] = (byte)((colorMap[i]*255)/65535);
                     greenLut[i] = (byte)((colorMap[mapSize + i]*255)/65535);
                     blueLut[i] = (byte)((colorMap[2*mapSize + i]*255)/65535);
                 }
 
-                int dataType = bitsPerSample[0] == 8 ?
-                    DataBuffer.TYPE_BYTE : DataBuffer.TYPE_USHORT;
+                int dataType;
+                if (bitsPerSample[0] <= 8) {
+                    dataType = DataBuffer.TYPE_BYTE;
+                } else if (sampleFormat[0] ==
+                    BaselineTIFFTagSet.SAMPLE_FORMAT_SIGNED_INTEGER) {
+                    dataType = DataBuffer.TYPE_SHORT;
+                } else {
+                    dataType = DataBuffer.TYPE_USHORT;
+                }
                 return ImageTypeSpecifier.createIndexed(redLut,
                                                         greenLut,
                                                         blueLut,
                                                         alphaLut,
                                                         bitsPerSample[0],

@@ -1080,17 +1088,19 @@
                             alphaPremultiplied = true;
                         }
 
                         cm = createComponentCM(cs,
                                                samplesPerPixel,
+                                               bitsPerSample,
                                                dataType,
                                                hasAlpha,
                                                alphaPremultiplied);
                     } else {
                         ColorSpace cs = new BogusColorSpace(samplesPerPixel);
                         cm = createComponentCM(cs,
                                                samplesPerPixel,
+                                               bitsPerSample,
                                                dataType,
                                                false, // hasAlpha
                                                false); // alphaPremultiplied
                     }
                     return new ImageTypeSpecifier(cm, sm);

@@ -1117,21 +1127,27 @@
             boolean isSigned =
                 (sampleFormat[0] ==
                  BaselineTIFFTagSet.SAMPLE_FORMAT_SIGNED_INTEGER);
 
             // Grayscale
-            if(samplesPerPixel == 1) {
-                int dataType =
-                    getDataTypeFromNumBits(maxBitsPerSample, isSigned);
+            if(samplesPerPixel == 1 &&
+                (bitsPerSample[0] == 1 || bitsPerSample[0] == 2 ||
+                 bitsPerSample[0] == 4 || bitsPerSample[0] == 8 ||
+                 bitsPerSample[0] == 16)) {
+                int dataType = getDataTypeFromNumBits(maxBitsPerSample, isSigned);
 
-                return ImageTypeSpecifier.createGrayscale(maxBitsPerSample,
+                return ImageTypeSpecifier.createGrayscale(bitsPerSample[0],
                                                           dataType,
                                                           isSigned);
             }
 
             // Gray-alpha
-            if (samplesPerPixel == 2) {
+            if (samplesPerPixel == 2 &&
+                bitsPerSample[0] == bitsPerSample[1] &&
+                (bitsPerSample[0] == 1 || bitsPerSample[0] == 2 ||
+                 bitsPerSample[0] == 4 || bitsPerSample[0] == 8 ||
+                 bitsPerSample[0] == 16)) {
                 boolean alphaPremultiplied = false;
                 if (extraSamples != null &&
                     extraSamples[0] ==
                     BaselineTIFFTagSet.EXTRA_SAMPLES_ASSOCIATED_ALPHA) {
                     alphaPremultiplied = true;

@@ -1145,10 +1161,17 @@
                                                           false,
                                                           alphaPremultiplied);
             }
 
             if (samplesPerPixel == 3 || samplesPerPixel == 4) {
+                int dataType = getDataTypeFromNumBits(maxBitsPerSample, isSigned);
+                int dataTypeSize;
+                try {
+                    dataTypeSize = getDataTypeSize(dataType);
+                } catch (IIOException ignored) {
+                    dataTypeSize = maxBitsPerSample;
+                }
                 if(totalBits <= 32 && !isSigned) {
                     // Packed RGB or RGBA
                     int redMask = createMask(bitsPerSample, 0);
                     int greenMask = createMask(bitsPerSample, 1);
                     int blueMask = createMask(bitsPerSample, 2);

@@ -1167,25 +1190,28 @@
                                                            greenMask,
                                                            blueMask,
                                                            alphaMask,
                                                            transferType,
                                                            alphaPremultiplied);
-                } else if(samplesPerPixel == 3) {
+                } else if(samplesPerPixel == 3 &&
+                    dataTypeSize == bitsPerSample[0] &&
+                    bitsPerSample[0] == bitsPerSample[1] &&
+                    bitsPerSample[1] == bitsPerSample[2]) {
                     // Interleaved RGB
                     int[] bandOffsets = new int[] {0, 1, 2};
-                    int dataType =
-                        getDataTypeFromNumBits(maxBitsPerSample, isSigned);
                     return ImageTypeSpecifier.createInterleaved(rgb,
                                                                 bandOffsets,
                                                                 dataType,
                                                                 false,
                                                                 false);
-                } else if(samplesPerPixel == 4) {
+                } else if(samplesPerPixel == 4 &&
+                    dataTypeSize == bitsPerSample[0] &&
+                    bitsPerSample[0] == bitsPerSample[1] &&
+                    bitsPerSample[1] == bitsPerSample[2] &&
+                    bitsPerSample[2] == bitsPerSample[3]) {
                     // Interleaved RGBA
                     int[] bandOffsets = new int[] {0, 1, 2, 3};
-                    int dataType =
-                        getDataTypeFromNumBits(maxBitsPerSample, isSigned);
                     boolean alphaPremultiplied = false;
                     if (extraSamples != null &&
                         extraSamples[0] ==
                         BaselineTIFFTagSet.EXTRA_SAMPLES_ASSOCIATED_ALPHA) {
                         alphaPremultiplied = true;

@@ -1194,25 +1220,33 @@
                                                                 bandOffsets,
                                                                 dataType,
                                                                 true,
                                                                 alphaPremultiplied);
                 }
-            } else {
+            }
+
                 // Arbitrary Interleaved.
                 int dataType =
                     getDataTypeFromNumBits(maxBitsPerSample, isSigned);
                 SampleModel sm = createInterleavedSM(dataType,
                                                      samplesPerPixel);
-                ColorSpace cs = new BogusColorSpace(samplesPerPixel);
+            ColorSpace cs;
+            if (samplesPerPixel <= 2) {
+                cs = ColorSpace.getInstance(ColorSpace.CS_GRAY);
+            } else if (samplesPerPixel <= 4) {
+                cs = rgb;
+            } else {
+                cs = new BogusColorSpace(samplesPerPixel);
+            }
                 ColorModel cm = createComponentCM(cs,
                                                   samplesPerPixel,
+                                              bitsPerSample,
                                                   dataType,
                                                   false, // hasAlpha
                                                   false); // alphaPremultiplied
                 return new ImageTypeSpecifier(cm, sm);
             }
-        }
 
         return null;
     }
 
     /**

@@ -1283,10 +1317,18 @@
     public void setPlanar(boolean planar) {
         this.planar = planar;
     }
 
     /**
+     * Sets the index of the planar configuration band to be decoded. This value
+     * is ignored for chunky (interleaved) images.
+     *
+     * @param the index of the planar band to decode
+     */
+    public void setPlanarBand(int planarBand) { this.planarBand = planarBand; }
+
+    /**
      * Sets the value of the {@code samplesPerPixel} field.
      *
      * <p> If this method is called, the {@code beginDecoding}
      * method must be called prior to calling any of the decode
      * methods.

@@ -2486,11 +2528,11 @@
             SampleModel sm = ras.getSampleModel();
 
             // Branch based on whether data are bit-contiguous, i.e.,
             // data are packaed as tightly as possible leaving no unused
             // bits except at the end of a row.
-            if(isDataBufferBitContiguous(sm)) {
+            if(isDataBufferBitContiguous(sm, bitsPerSample)) {
                 // Use byte or float data directly.
                 if (byteData != null) {
                     decodeRaw(byteData, dstOffset,
                               pixelBitStride, scanlineStride);
                 } else if (floatData != null) {

@@ -2535,15 +2577,23 @@
                     }
                 }
             } else {
                 // Read discontiguous data into bytes and set the samples
                 // into the Raster.
-                int bpp = getBitsPerPixel(sm);
+                int bpp;
+                if (planar) {
+                    bpp = bitsPerSample[planarBand];
+                } else {
+                    bpp = 0;
+                    for (int bps : bitsPerSample) {
+                        bpp += bps;
+                    }
+                }
                 int bytesPerRow = (bpp*srcWidth + 7)/8;
                 byte[] buf = new byte[bytesPerRow*srcHeight];
                 decodeRaw(buf, 0, bpp, bytesPerRow);
-                reformatDiscontiguousData(buf, bytesPerRow,
+                reformatDiscontiguousData(buf, bitsPerSample, bytesPerRow,
                                           srcWidth, srcHeight,
                                           ras);
             }
         }
 
< prev index next >