Working in a BufferedImage's int[] pixels array
Asked Answered
F

2

6

When working with BufferedImage using the setRGB and getRGB methods, I noticed two things:

  1. the setRGB and getRGB methods can be incredibly slow on some systems (as much as two orders of magnitude slower than modifiyng the int[] array).

  2. there are no guarantee that a getRGB following a setRGB will give back the same pixel you passed

This last point is basically pretty clear from the JavaDoc of setRGB, which states:

...For images with an IndexColorModel, the index with the nearest color is chosen.

Seen I can work directly in a BufferedImage's int[] pixels, which I can access to by doing, for example:

 int[] a = ((DataBufferInt) tmp.getRaster().getDataBuffer()).getData();

I was wondering: are there any known drawbacks/gotchas when directly manipulating pixels in the int[]?

Footlight answered 3/12, 2010 at 18:26 Comment(0)
R
4

The whole point of getData() giving you access to the backing int array is precisely for this optimization, so the benefits most likely outweigh the drawbacks.

The drawbacks depend on how you're using the buffered image. If you're drawing it to the screen while you're editing it, you may encounter some artifacts on the screen (like pixels not colored in time), in which case you should consider double buffering (which does involve copying over the entire image for every refresh).

Raconteur answered 3/12, 2010 at 18:38 Comment(4)
+1 but could you give more information about how the double buffering should/could be done?Footlight
How you do the double buffering depends on several factors, such as what you're displaying, how large it is, what the graphics engine is, how fast a refresh rate you want, if you can take advantage of what's provided by your graphics card, etc. But a basic way of doing this would be to have one buffer that you modify, and one that you display, copying over the modified buffer when you're done making modifications. A good way to do this is to copy the data in the modification buffer to a temp buffer first so that assigning the display buffer to the temp buffer is a fast operation.Raconteur
There's a readers/writers problem in there, where you have to make sure you're not trying to display a buffer that's being copied. If you're doing all of this in a single thread, you can get away with something like if (doneCopying) { displayBuf = tmpBuf; } draw(displayBuf);Raconteur
thanks a lot for the info, I'll probably create one of these days a detailed question about how to do double-buffering in my specific case.Footlight
F
0

Not sure if this is relevant for your question, but you will run into problems when the BufferedImage was created using the method getSubimage(int x, int y, int w, int h).

Returns a subimage defined by a specified rectangular region. The returned BufferedImage shares the same data array as the original image.

The methods getTileGridXOffset() and getTileGridYOffset() return the offset then despite being described as

Returns the x offset of the tile grid relative to the origin, For example, the x coordinate of the location of tile (0, 0). This is always zero.

but because you can't (as far as I know) access the scanlineStride field of the raster you won't be able to get the correct index for the array.

Flagitious answered 8/9, 2016 at 23:19 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.