Turn an array of pixels into an Image object with Java's ImageIO?
Asked Answered
C

6

28

I'm currently turning an array of pixel values (originally created with a java.awt.image.PixelGrabber object) into an Image object using the following code:

public Image getImageFromArray(int[] pixels, int width, int height) {
    MemoryImageSource mis = new MemoryImageSource(width, height, pixels, 0, width);
    Toolkit tk = Toolkit.getDefaultToolkit();
    return tk.createImage(mis);
}

Is it possible to achieve the same result using classes from the ImageIO package(s) so I don't have to use the AWT Toolkit?

Toolkit.getDefaultToolkit() does not seem to be 100% reliable and will sometimes throw an AWTError, whereas the ImageIO classes should always be available, which is why I'm interested in changing my method.

Carob answered 24/9, 2008 at 0:0 Comment(0)
S
29

You can create the image without using ImageIO. Just create a BufferedImage using an image type matching the contents of the pixel array.

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;
        }

When working with the PixelGrabber, don't forget to extract the RGBA info from the pixel array before calling getImageFromArray. There's an example of this in the handlepixelmethod in the PixelGrabber javadoc. Once you do that, make sure the image type in the BufferedImage constructor to BufferedImage.TYPE_INT_ARGB.

Siding answered 24/9, 2008 at 2:8 Comment(6)
Thanks bcash, but I get a java.lang.ArrayIndexOutOfBoundsException when I try that code. Any ideas?Carob
I think this is close, we might need more details from Chris with details? this looks like it should work... What are your ints? are they RGB? ARGB? some kind of packed format?Expanse
The pixels are coming from a PixelGrabber as such: int[] pixels = new int[width * height]; PixelGrabber pg = new PixelGrabber(img, 0, 0, width, height, pixels, 0, width); pg.grabPixels();Carob
Chris, you're getting an AOOB exception because the size of the BufferedImage "image" is width * height * 3, because the it's of type int RGB. See the edit.Siding
When I tried this code, I got a black image. It's like the raster.setPixels did not affect the BufferedImage at all.Voltaism
As @haraldK (in below posts) has notified, Java documentation mentions that BufferedImage.getData() returns a Raster and BufferedImage.getRaster() returns a WritableRaster. So if you use getData() seems that it returns a copy and after setPixels() you must put it back using BufferedImage.setData() which is an overhead. So its better to use getRaster() and work with it.Veron
K
7

Using the raster I got an ArrayIndexOutOfBoundsException even when I created the BufferedImage with TYPE_INT_ARGB. However, using the setRGB(...) method of BufferedImage worked for me.

Kier answered 29/4, 2009 at 22:53 Comment(2)
I had a similar issue, even though the array size of the input and output matched. I ended up using setRGB too. It might be trivially slower but it works. The wouldn't think Alpha vs. non-alpha should change the array size though since its simply the 2 most significant bytes on the individual int.Gabelle
How can Use setRGB() in the above code ? Thank You...Laundry
J
3

JavaDoc on BufferedImage.getData() says: "a Raster that is a copy of the image data."

This code works for me but I doubt in it's efficiency:

        // Получаем картинку из массива.
        int[] pixels = new int[width*height];
            // Рисуем диагональ.
            for (int j = 0; j < height; j++) {
                for (int i = 0; i < width; i++) {
                    if (i == j) {
                        pixels[j*width + i] = Color.RED.getRGB();
                    }
                    else {
                        pixels[j*width + i] = Color.BLUE.getRGB();
                        //pixels[j*width + i] = 0x00000000;
                    }
                }
            }

BufferedImage pixelImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);    
    pixelImage.setRGB(0, 0, width, height, pixels, 0, width);
Jurgen answered 3/2, 2011 at 10:14 Comment(1)
..or use getRaster() instead of getData().Kloof
S
2

I've had good success using java.awt.Robot to grab a screen shot (or a segment of the screen), but to work with ImageIO, you'll need to store it in a BufferedImage instead of the memory image source. Then you can call one static method of ImageIO and save the file. Try something like:

// Capture whole screen
Rectangle region = new Rectangle(Toolkit.getDefaultToolkit().getScreenSize());
BufferedImage capturedImage = new Robot().createScreenCapture(region);

// Save as PNG
File imageFile = new File("capturedImage.png");
ImageIO.write(capturedImage, "png", imageFile);
Sumy answered 24/9, 2008 at 1:51 Comment(0)
K
0

As this is one of the highest voted question tagged with ImageIO on SO, I think there's still room for a better solution, even if the question is old. :-)

Have a look at the BufferedImageFactory.java class from my open source imageio project at GitHub.

With it, you can simply write:

BufferedImage image = new BufferedImageFactory(image).getBufferedImage();

The other good thing is that this approach, as a worst case, has about the same performance (time) as the PixelGrabber-based examples already in this thread. For most of the common cases (typically JPEG), it's about twice as fast. In any case, it uses less memory.

As a side bonus, the color model and pixel layout of the original image is kept, instead of translated to int ARGB with default color model. This might save additional memory.

(PS: The factory also supports subsampling, region-of-interest and progress listeners if anyone's interested. :-)

Kloof answered 4/6, 2013 at 20:9 Comment(0)
O
0

I had the same problem of everyone else trying to apply the correct answer of this question, my int array actually get an OutOfboundException where i fixed it adding one more index because the length of the array has to be widht*height*3 after this i could not get the image so i fixed it setting the raster to the image

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);
        image.setData(raster); 
        return image;
    }

And you can see the image if u show it on a label on a jframe like this

    JFrame frame = new JFrame();
    frame.getContentPane().setLayout(new FlowLayout());
    frame.getContentPane().add(new JLabel(new ImageIcon(image)));
    frame.pack();
    frame.setVisible(true);

setting the image on the imageIcon(). Last advice you can try to change the Bufferedimage.TYPE_INT_ARGB to something else that matches the image you got the array from this type is very important i had an array of 0 and -1 so I used this type BufferedImage.TYPE_3BYTE_BGR

Orfield answered 21/6, 2016 at 15:21 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.