1

I wrote a method to read images. I loop through a List of image-files and read them. After some iteration an ArrayIndexOutOfBoundsException appears when calling the Raster.setRect(Raster raster) method. The dimension and the bounds of the images are fine - see stacktrace.

public static BufferedImage readImage(File imageFile) {

    // Find a suitable ImageReader
    Iterator<ImageReader> readers = ImageIO.getImageReadersBySuffix("jpg");
    ImageReader reader = null;
    while (readers.hasNext()) {
        reader = (ImageReader) readers.next();
        if (reader.canReadRaster()) {
            break;
        }
    }

    // Stream the image file (the original CMYK image)
    ImageInputStream input = null;
    try {
        input = ImageIO.createImageInputStream(imageFile);
    } catch (IOException e) {
        logger.error("Error creating InputStream on File {}", imageFile
                .getName());
        e.printStackTrace();
    }
    reader.setInput(input);

    // Read the image raster
    Raster raster = null;
    try {
        raster = reader.readRaster(0, null);
    } catch (IOException e) {
        logger
                .error("Error reading Raster of file {}", imageFile
                        .getName());
        e.printStackTrace();
    }

    // Create a new RGB image
    BufferedImage bi = new BufferedImage(raster.getWidth(), raster
            .getHeight(), BufferedImage.TYPE_INT_RGB);

    // Fill the new image with the old raster
    logger.debug("Height {} and width {} of original raster", raster
            .getHeight(), raster.getWidth());
    logger.debug("Height {} and width {} of new raster", bi.getRaster()
            .getHeight(), bi.getRaster().getWidth());
    logger.debug("NumBands original raster {}", bi.getRaster().getBounds());
    logger.debug("NumBands new raster {}", bi.getRaster().getBounds());
    bi.getRaster().setRect(raster);

    // Close and flush the reader
    try {
        input.close();
    } catch (IOException e) {
        logger.error("Error closing the reader for file {}", imageFile
                .getName());
        e.printStackTrace();
    }

    return bi;
}

Here the stacktrace:

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 310
at java.awt.image.SinglePixelPackedSampleModel.setPixels(SinglePixelPackedSampleModel.java:689)
at java.awt.image.WritableRaster.setPixels(WritableRaster.java:565)
at java.awt.image.WritableRaster.setRect(WritableRaster.java:467)
at java.awt.image.WritableRaster.setRect(WritableRaster.java:403)
at .. .utils.ImageUtils.readImage(ImageUtils.java:228)
at .. .image.scripts.ImageMatchingScript.main(ImageMatchingScript.java:86)

All the images have the same dimension 371x310

Here the debug information I printed:

13:53:17.065 [main] DEBUG .. .ImageUtils - Height 371 and width 310 of original raster
13:53:17.065 [main] DEBUG .. .ImageUtils - Height 371 and width 310 of new raster
13:53:17.065 [main] DEBUG .. .ImageUtils - NumBands original raster java.awt.Rectangle[x=0,y=0,width=310,height=371]
13:53:17.065 [main] DEBUG .. .ImageUtils - NumBands new raster java.awt.Rectangle[x=0,y=0,width=310,height=371]

The documentation says: ArrayIndexOutOfBoundsException - if the coordinates are not in bounds, or if fArray is too small to hold the input.

For me the dimensions/bounds seem fine, maybe its a problem with the fArray?

cesmarch
  • 341
  • 2
  • 8

1 Answers1

2

I imagine the problem is not with the image dimensions, but with the number of bands in the raster. You create your BufferedImage.TYPE_INT_RGB. Probably the failing image is a PNG with alpha channel, the raster has an additional band in that case.

I wonder why your are doing the loading in this convoluted way, why not just use ImageIo.read(InputStream)? That will give you a BufferedImage, no need to convert it yourself.

Edit: Try this method for reading and converting to RGB:

InputStream input = null;
try {
input = new FileInputStream(...); // whatever your source is
    BufferedImage rawImage = ImageIO.read(input);
    if (rawImage == null)
        return null;
    BufferedImage rgbImage = new BufferedImage(rawImage.getWidth(null), rawImage.getHeight(null), BufferedImage.TYPE_INT_RGB);
    Graphics g = rgbImage.createGraphics();
    // if rawImage contains alpha, consider filling the rgbImage with a default BG color here
    g.drawImage(rawImage, 0, 0, null);
    g.dispose();
    rawImage.flush();
    return rgbImage;
} catch (Exception e) {
// handle error
    return null;
} finally {
    // close input if open
    if (input != null) {
        try {
            input.close();
        } catch (IOException e) {}
    }
}

Just whacked the code together, may contain typos. This way you can get RGB image, regardless what the source file was without needing to even think about the source image properties.

Spotlight
  • 472
  • 1
  • 11
  • 22
Durandal
  • 19,919
  • 4
  • 36
  • 70
  • You were on the right path: I checked the bands of both images. 14:59:49.334 [main] DEBUG .. .utils.ImageUtils - NumBands original raster 1 14:59:49.334 [main] DEBUG .. .fraud.utils.ImageUtils - NumBands new raster 3 I use this way of reading because I have Images ariving in CMYK. Trying to edit the code to fix this – cesmarch Mar 07 '12 at 13:56
  • Thanks for your code, but it still doesn't work with CMYK JPGs. Since I use JavaCV/OpenCV in my project I decided to use their Read-Method for Images and their conversion Method to BufferedImages. Performance is acceptable. – cesmarch Mar 07 '12 at 15:51
  • It seems CMYK is not supported out of the box with ImageIO. I remember having a similar problem with PHP when somebody uploaded a CMYK jpg to a CMS and suprise the image broke when scaled by the CMS. However, it looks like somebody already solved the problem for ImageIO: http://www.randelshofer.ch/blog/2011/08/reading-cmyk-jpeg-images-with-java-imageio/ If you still have trouble the link may help. – Durandal Mar 07 '12 at 16:15