calannap calannap - 4 months ago 14
Java Question

Array Index out of Bound in converting an array of pixels into a Image in Java

I have this method that I found on stackoverflow:

public static Image getImageFromArray(int[] pixels, int width, int height) {
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
WritableRaster raster = (WritableRaster) image.getData();
raster.setPixels(0,0,width,height,pixels);
return image;
}


using it like this:

image = getImageFromArray(dstpixels,img.getWidth(this),img.getHeight(this));


In order to debug I printed out Width, Height and length of dstpixels, here are the results:
700 389
272300

still I get this error
Exception in thread "AWT-EventQueue-0" java.lang.ArrayIndexOutOfBoundsException: 272300


on this exact line

raster.setPixels(0,0,width,height,pixels);


What am I missing?

Answer

It looks like Raster doesn't treat pixels as array in which each element represents single pixel. It treats it as array where each element contains single information about pixel.
So if it is ARGB type of image it looks like pixel array will contain info about first pixel in first four elements (at indexes [0,1,2,3]) where

  • R will be stored at position [0]
  • G at position [1]
  • B at position [2]
  • and A (alpha) at position [3].

Info about second pixel will be placed at [4,5,6,7] indexes, third [8,9,10,11] and so on.

So main problem from your question can be solved by assigning 4 times larger int[] pixel array than amount of pixels for ARGB type of image (for RGB 3 times larger).

Another problem in your code is that image.getData()

Returns the image as one large tile. The Raster returned is a copy of the image data is not updated if the image is changed.

(emphasis mine)

so manipulating data from that raster will not affect image. To update image with data from raster you need to add image.setData(raster); in your getImageFromArray method like

public static Image getImageFromArray(int[] pixels, int w, int h) {
    BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
    WritableRaster raster = (WritableRaster) image.getData();
    raster.setPixels(0,0,w,h,pixels);
    image.setData(raster); //<-- add this line
    return image;
}

OR don't use image.getData() at all and instead manipulate raster returned from image.getRaster().

Demo:

enter image description here

public static void main(String[] args) {
    int width = 200, height = 300;
    //array needs to be 4 times larger than amount of pixels
    int[] pixels = new int[4*width*height];
    for (int i = 0; i < pixels.length; i++) {
        //if (i%4==0){pixels[i]=255;}//R default 0
        //if (i%4==1){pixels[i]=255;}//G default 0
        if (i%4==2){pixels[i]=255;}//B default 0 
        //Alpha
        if (i%4==3){        
            pixels[i]=(int)(255*(i/4%width)/(double)width);
        }
    }
    Image image = getImageFromArray(pixels, width, height);
    showImage(image);
}
public static void showImage(Image img){
    JFrame frame = new JFrame();
    frame.setLayout(new FlowLayout());
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    JLabel lab = new JLabel(new ImageIcon(img));
    frame.add(lab);
    frame.pack();
    frame.setVisible(true);
}
public static Image getImageFromArray(int[] pixels, int w, int h) {
    BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
    WritableRaster raster = image.getRaster();
    raster.setPixels(0,0,w,h,pixels);
    return image;
}