-
Bug
-
Resolution: Unresolved
-
P4
-
7u25, 8-pool, 9
-
x86
-
linux
FULL PRODUCT VERSION :
java version "1.7.0_25"
Java(TM) SE Runtime Environment (build 1.7.0_25-b15)
Java HotSpot(TM) 64-Bit Server VM (build 23.25-b01, mixed mode)
ADDITIONAL OS VERSION INFORMATION :
Linux user 2.6.18-238.37.1.el5 #1 SMP Fri Apr 6 13:47:10 EDT 2012 x86_64 x86_64
A DESCRIPTION OF THE PROBLEM :
Our application uses Java Advanced Imaging API's to read images and construct BufferedImages, and then uses various BufferedImageOp implementations to alter the images before serializing for storage.
We encountered some images, with the following TiffInfo:
TIFF Directory at offset 0x5156 (20822)
Subfile Type: (0 = 0x0)
Image Width: 1728 Image Length: 2155
Resolution: 204, 196 pixels/inch
Bits/Sample: 1
Compression Scheme: LZW
Photometric Interpretation: palette color (RGB from colormap)
Orientation: row 0 top, col 0 lhs
Samples/Pixel: 1
Rows/Strip: 2155
Planar Configuration: single image plane
Page Number: 1-1
Color Map: (present)
DateTime: 2014/09/23 21:54:55
Tag 326: 0
Tag 327: 0
Tag 328: 0
Predictor: none 1 (0x1)
TIFF Directory at offset 0x1125a (70234)
Subfile Type: (0 = 0x0)
Image Width: 1728 Image Length: 2155
Resolution: 204, 196 pixels/inch
Bits/Sample: 1
Compression Scheme: LZW
Photometric Interpretation: palette color (RGB from colormap)
Orientation: row 0 top, col 0 lhs
Samples/Pixel: 1
Rows/Strip: 2155
Planar Configuration: single image plane
Page Number: 1-1
Color Map: (present)
DateTime: 2014/09/23 21:54:55
Tag 326: 0
Tag 327: 0
Tag 328: 0
Predictor: none 1 (0x1)
These images are processed by JAI and create a BufferedImage with the following implementations:
SampleModel: MultiPixelPackedSampleModel
ColorModel: IndexColorModel
Raster: SunWritableRaster
DataBuffer: DataBufferUShort
Once you have a handle on the BufferedImage instance, attempt to call the following method:
int[] java.awt.image.BufferedImage.getRGB(int startX, int startY, int w, int h, int[] rgbArray, int offset, int scansize)
A ClassCastException will result.
It appears there may be a defect in BufferedImage.getRGB, or related class, where it constructs the primitive array for retrieving the pixel data from the SampleModel. It uses the DataBuffer's storage datatype, provided by DataBufferUShort.getDataType(), which, in this case, is inconsistent with the datatype provided by the MultiPixelPackedSampleModel.getTransferType(). The inconsistency of dataTypes used results in an unchecked cast of short array to byte array.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Compile and run SSCCE
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
BufferedImage impl
SampleModel: MultiPixelPackedSampleModel
ColorModel: IndexColorModel
Raster: SunWritableRaster
DataBuffer: DataBufferUShort
Processed Without Exception
ACTUAL -
BufferedImage impl
SampleModel: MultiPixelPackedSampleModel
ColorModel: IndexColorModel
Raster: SunWritableRaster
DataBuffer: DataBufferUShort
Exception in thread "main" java.lang.ClassCastException: [S cannot be cast to [B
ERROR MESSAGES/STACK TRACES THAT OCCUR :
Exception in thread "main" java.lang.ClassCastException: [S cannot be cast to [B
at java.awt.image.MultiPixelPackedSampleModel.getDataElements(MultiPixelPackedSampleModel.java:473)
at java.awt.image.Raster.getDataElements(Raster.java:1466)
at java.awt.image.BufferedImage.getRGB(BufferedImage.java:988)
at jopari.tracker.util.image.SSCCE.main(SSCCE.java:26)
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.DataBuffer;
import java.awt.image.DataBufferUShort;
import java.awt.image.IndexColorModel;
import java.awt.image.MultiPixelPackedSampleModel;
import java.awt.image.Raster;
import java.awt.image.SampleModel;
import java.awt.image.WritableRaster;
public final class SSCCE
{
public static void main(String...args)
{
BufferedImage sourceImage = createExampleImage();
System.out.println("BufferedImage impl");
System.out.println("SampleModel: "+sourceImage.getSampleModel().getClass().getSimpleName());
System.out.println("ColorModel: "+sourceImage.getColorModel().getClass().getSimpleName());
System.out.println("Raster: "+sourceImage.getRaster().getClass().getSimpleName());
System.out.println("DataBuffer: "+sourceImage.getRaster().getDataBuffer().getClass().getSimpleName());
int width = sourceImage.getWidth();
int height = sourceImage.getHeight();
for(int y = 0; y < height; y++)
{
sourceImage.getRGB(0, y, width, 1, new int[width], 0, width);
}
System.out.println("Processed Without Exception");
}
private static BufferedImage createExampleImage()
{
final int width = 32;
final int height = 32;
short[] pixels = new short[width * height];
DataBuffer dataBuffer = new DataBufferUShort(pixels, width * height, 0);
SampleModel sampleModel = new MultiPixelPackedSampleModel(DataBuffer.TYPE_USHORT, width, height, 1);
WritableRaster raster = Raster.createWritableRaster(sampleModel, dataBuffer, null);
return new BufferedImage(createExampleColorModel(), raster, false, null);
}
private static ColorModel createExampleColorModel()
{
final int colorPalette = 2;
byte[] r = new byte[colorPalette];
byte[] g = new byte[colorPalette];
byte[] b = new byte[colorPalette];
for (int i = 0; i < colorPalette; i++)
{
r[i] = 0;
g[i] = 0;
b[i] = 0;
}
return new IndexColorModel(1, colorPalette, r, g, b);
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
A workaround that I found successful so far was to detect when the SampleModel implementation is an instance of MultiPixelPackedSampleModel and bypass the BufferedImage.getRGB implementation by creating my own and altering the one line of code that collects the data type from the DataBuffer and instead use the transfer type from the SampleModel.
int dataType = raster.getDataBuffer().getDataType();
replaced with
int dataType = getSampleModel().getTransferType();
java version "1.7.0_25"
Java(TM) SE Runtime Environment (build 1.7.0_25-b15)
Java HotSpot(TM) 64-Bit Server VM (build 23.25-b01, mixed mode)
ADDITIONAL OS VERSION INFORMATION :
Linux user 2.6.18-238.37.1.el5 #1 SMP Fri Apr 6 13:47:10 EDT 2012 x86_64 x86_64
A DESCRIPTION OF THE PROBLEM :
Our application uses Java Advanced Imaging API's to read images and construct BufferedImages, and then uses various BufferedImageOp implementations to alter the images before serializing for storage.
We encountered some images, with the following TiffInfo:
TIFF Directory at offset 0x5156 (20822)
Subfile Type: (0 = 0x0)
Image Width: 1728 Image Length: 2155
Resolution: 204, 196 pixels/inch
Bits/Sample: 1
Compression Scheme: LZW
Photometric Interpretation: palette color (RGB from colormap)
Orientation: row 0 top, col 0 lhs
Samples/Pixel: 1
Rows/Strip: 2155
Planar Configuration: single image plane
Page Number: 1-1
Color Map: (present)
DateTime: 2014/09/23 21:54:55
Tag 326: 0
Tag 327: 0
Tag 328: 0
Predictor: none 1 (0x1)
TIFF Directory at offset 0x1125a (70234)
Subfile Type: (0 = 0x0)
Image Width: 1728 Image Length: 2155
Resolution: 204, 196 pixels/inch
Bits/Sample: 1
Compression Scheme: LZW
Photometric Interpretation: palette color (RGB from colormap)
Orientation: row 0 top, col 0 lhs
Samples/Pixel: 1
Rows/Strip: 2155
Planar Configuration: single image plane
Page Number: 1-1
Color Map: (present)
DateTime: 2014/09/23 21:54:55
Tag 326: 0
Tag 327: 0
Tag 328: 0
Predictor: none 1 (0x1)
These images are processed by JAI and create a BufferedImage with the following implementations:
SampleModel: MultiPixelPackedSampleModel
ColorModel: IndexColorModel
Raster: SunWritableRaster
DataBuffer: DataBufferUShort
Once you have a handle on the BufferedImage instance, attempt to call the following method:
int[] java.awt.image.BufferedImage.getRGB(int startX, int startY, int w, int h, int[] rgbArray, int offset, int scansize)
A ClassCastException will result.
It appears there may be a defect in BufferedImage.getRGB, or related class, where it constructs the primitive array for retrieving the pixel data from the SampleModel. It uses the DataBuffer's storage datatype, provided by DataBufferUShort.getDataType(), which, in this case, is inconsistent with the datatype provided by the MultiPixelPackedSampleModel.getTransferType(). The inconsistency of dataTypes used results in an unchecked cast of short array to byte array.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Compile and run SSCCE
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
BufferedImage impl
SampleModel: MultiPixelPackedSampleModel
ColorModel: IndexColorModel
Raster: SunWritableRaster
DataBuffer: DataBufferUShort
Processed Without Exception
ACTUAL -
BufferedImage impl
SampleModel: MultiPixelPackedSampleModel
ColorModel: IndexColorModel
Raster: SunWritableRaster
DataBuffer: DataBufferUShort
Exception in thread "main" java.lang.ClassCastException: [S cannot be cast to [B
ERROR MESSAGES/STACK TRACES THAT OCCUR :
Exception in thread "main" java.lang.ClassCastException: [S cannot be cast to [B
at java.awt.image.MultiPixelPackedSampleModel.getDataElements(MultiPixelPackedSampleModel.java:473)
at java.awt.image.Raster.getDataElements(Raster.java:1466)
at java.awt.image.BufferedImage.getRGB(BufferedImage.java:988)
at jopari.tracker.util.image.SSCCE.main(SSCCE.java:26)
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.DataBuffer;
import java.awt.image.DataBufferUShort;
import java.awt.image.IndexColorModel;
import java.awt.image.MultiPixelPackedSampleModel;
import java.awt.image.Raster;
import java.awt.image.SampleModel;
import java.awt.image.WritableRaster;
public final class SSCCE
{
public static void main(String...args)
{
BufferedImage sourceImage = createExampleImage();
System.out.println("BufferedImage impl");
System.out.println("SampleModel: "+sourceImage.getSampleModel().getClass().getSimpleName());
System.out.println("ColorModel: "+sourceImage.getColorModel().getClass().getSimpleName());
System.out.println("Raster: "+sourceImage.getRaster().getClass().getSimpleName());
System.out.println("DataBuffer: "+sourceImage.getRaster().getDataBuffer().getClass().getSimpleName());
int width = sourceImage.getWidth();
int height = sourceImage.getHeight();
for(int y = 0; y < height; y++)
{
sourceImage.getRGB(0, y, width, 1, new int[width], 0, width);
}
System.out.println("Processed Without Exception");
}
private static BufferedImage createExampleImage()
{
final int width = 32;
final int height = 32;
short[] pixels = new short[width * height];
DataBuffer dataBuffer = new DataBufferUShort(pixels, width * height, 0);
SampleModel sampleModel = new MultiPixelPackedSampleModel(DataBuffer.TYPE_USHORT, width, height, 1);
WritableRaster raster = Raster.createWritableRaster(sampleModel, dataBuffer, null);
return new BufferedImage(createExampleColorModel(), raster, false, null);
}
private static ColorModel createExampleColorModel()
{
final int colorPalette = 2;
byte[] r = new byte[colorPalette];
byte[] g = new byte[colorPalette];
byte[] b = new byte[colorPalette];
for (int i = 0; i < colorPalette; i++)
{
r[i] = 0;
g[i] = 0;
b[i] = 0;
}
return new IndexColorModel(1, colorPalette, r, g, b);
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
A workaround that I found successful so far was to detect when the SampleModel implementation is an instance of MultiPixelPackedSampleModel and bypass the BufferedImage.getRGB implementation by creating my own and altering the one line of code that collects the data type from the DataBuffer and instead use the transfer type from the SampleModel.
int dataType = raster.getDataBuffer().getDataType();
replaced with
int dataType = getSampleModel().getTransferType();