4

I am attempting to create a mosaic of images in Java. I calculate the size of the new image I'm creating, and then for each subimage that will be part of the mosaic, I do a paint call.

In pseudocode:

create buffered image big enough to hold entire mosaic
create Graphics2D context from that image

for each buffered subimage that will be a part of the mosaic
   draw the subimage on the graphics context of big bufferedimage
   g2.drawImage(myImage, x,y,width,height,null,null)

Is there a better way to do this? I'd hope there's some sort of direct copying operation available, since I don't want to transform or scale the subimages into the bigger image. Something akin to an arraycopy of the rasters of each subimage. I notice there's a setData method that takes in a Raster object, but the method notes that the Raster has to be in same coordinate space.

Any thoughts? This is a bit of a bottleneck in my program and I'd like it to be as fast as possible.

EDIT: It turns out I was wrong (as is often the case when assumptions are made without hard data) about where the bottleneck was. I had a bug where multiple 3MB pictures were being read over and over again rather than using the scaled down versions of the images cached in memory. My running time went from 50 minutes to 15 seconds when I made the fix.

I82Much
  • 26,901
  • 13
  • 88
  • 119

2 Answers2

3

Typically the drawImage() call will directly map on a hardware accelarated blit operation. Depending on the driver/graphics card and JVM you are using, also scaling should be hardware accelerated. However if you can avoid scaling you should of course.

If the sub-images do fit in the larger image you should be able to avoid scaling by choosing your width and height such that they are the same as that of the subimage, of course in this case you are better of using g.drawImage(Image img, int x, int y, ImageObserver observer).

Marc van Kempen
  • 546
  • 2
  • 7
-1

You could call

getPixels(int x, int y, int w, int h, int[] iArray)

on the Raster for the subimage and then

setPixels(int x, int y, int w, int h, int[] iArray)

on the WritableRaster for the larger image. As for efficiency or performance, though, I have no idea. You'd have to test it yourself. Of course, the images would have to be the same type (same color space, same resolution, etc.) but it sounds like you're already assuming that.

Adam Crume
  • 15,614
  • 8
  • 46
  • 50
  • 2
    I'd strongly recommend people use Marc's suggestion above as it allows the operation to stay in the hardware-accelerated pipeline. Pulling the pixels out of the image into a Java array and them pushing them back out again as suggested above actually requires two bad things; 1 it requires the images to be pulled out the volatile VRAM space and no longer be hardware accelerated (getRGB also does this) and it requires the pixel values to be converted to an int and pulled from native space into JVM space. This is probably the slowest way to copy pixel data from 1 image to another. – Riyad Kalla Mar 04 '12 at 16:51
  • 1
    NOTE: This is not a knock on Adam's suggestion, there are so many unknown idiosyncratic behaviors under the covers in Java images that unless you have dug through the Swing/Java2D APIs, you'd never know (they aren't mentioned in the Javadoc anywhere). – Riyad Kalla Mar 04 '12 at 16:52