# HG changeset patch # User bpb # Date 1484950201 28800 # Fri Jan 20 14:10:01 2017 -0800 # Node ID 96e7e30432f8ad4bfb963e5f61131ffc7a311fc6 # Parent d4150b065b15c00493dfa7fb1de0fea7387a136c 8145019: Exceptions from TIFFImageReader.read() when loading bit depth test images Summary: Fix some problems reading unusual bit depth images relating to setting the correct ImageTypeSpecifier and reformatting discontiguous data Reviewed-by: XXX diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFDecompressor.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFDecompressor.java --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFDecompressor.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFDecompressor.java @@ -156,6 +156,11 @@ 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; @@ -446,24 +451,19 @@ * 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, @@ -581,14 +581,15 @@ * 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; } @@ -682,6 +683,7 @@ * of the supplied {@code WritableRaster}. */ private static void reformatDiscontiguousData(byte[] buf, + int[] bitsPerSample, int stride, int w, int h, @@ -691,7 +693,6 @@ // Get SampleModel info. SampleModel sm = raster.getSampleModel(); int numBands = sm.getNumBands(); - int[] sampleSize = sm.getSampleSize(); // Initialize input stream. ByteArrayInputStream is = new ByteArrayInputStream(buf); @@ -705,7 +706,7 @@ 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); } } @@ -806,8 +807,15 @@ 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, @@ -1082,6 +1090,7 @@ cm = createComponentCM(cs, samplesPerPixel, + bitsPerSample, dataType, hasAlpha, alphaPremultiplied); @@ -1089,6 +1098,7 @@ ColorSpace cs = new BogusColorSpace(samplesPerPixel); cm = createComponentCM(cs, samplesPerPixel, + bitsPerSample, dataType, false, // hasAlpha false); // alphaPremultiplied @@ -1119,17 +1129,23 @@ 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] == @@ -1147,6 +1163,13 @@ } 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); @@ -1169,21 +1192,24 @@ 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] == @@ -1196,20 +1222,28 @@ true, alphaPremultiplied); } + } + + // Arbitrary Interleaved. + int dataType = + getDataTypeFromNumBits(maxBitsPerSample, isSigned); + SampleModel sm = createInterleavedSM(dataType, + samplesPerPixel); + ColorSpace cs; + if (samplesPerPixel <= 2) { + cs = ColorSpace.getInstance(ColorSpace.CS_GRAY); + } else if (samplesPerPixel <= 4) { + cs = rgb; } else { - // Arbitrary Interleaved. - int dataType = - getDataTypeFromNumBits(maxBitsPerSample, isSigned); - SampleModel sm = createInterleavedSM(dataType, - samplesPerPixel); - ColorSpace cs = new BogusColorSpace(samplesPerPixel); - ColorModel cm = createComponentCM(cs, - samplesPerPixel, - dataType, - false, // hasAlpha - false); // alphaPremultiplied - return new ImageTypeSpecifier(cm, sm); + cs = new BogusColorSpace(samplesPerPixel); } + ColorModel cm = createComponentCM(cs, + samplesPerPixel, + bitsPerSample, + dataType, + false, // hasAlpha + false); // alphaPremultiplied + return new ImageTypeSpecifier(cm, sm); } return null; @@ -1285,6 +1319,14 @@ } /** + * 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. * *

If this method is called, the {@code beginDecoding} @@ -2488,7 +2530,7 @@ // 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, @@ -2537,11 +2579,19 @@ } 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); } diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageReader.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageReader.java --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageReader.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageReader.java @@ -1113,6 +1113,7 @@ long offset = getTileOrStripOffset(tileIndex); long byteCount = getTileOrStripByteCount(tileIndex); + decompressor.setPlanarBand(band); decompressor.setStream(stream); decompressor.setOffset(offset); decompressor.setByteCount((int) byteCount);