clip an image

Lets say I am doing all of my drawing to a graphics contect g, If I wish to draw a portion of an image I do the following:


g.setClip(0,0,someWidth, someHeight);
g.drawImage(someImage, x,y, this);
g.setClip(0,0,screenWidth, screenHeight);
 
//continue normal draw operations here

This is how I currently acheive this, but was wondering why is there not a g.drawImage(image, x,y, clipping area, this) method, or is there?

there is: here

or, you can just create a permanent version of your clip with BufferedImage’s getSubimage method

I looked at that, but all the drawImage methods seem to scale the image. A I missing something? Does one of the drawImage draws only a clipped portion of my Image? Which one is it?

Hi,
You are trying to draw only the part of the image from (in image coords)
(0,0) to (someWidth -x , someHeight - y)

You can use the method that woogley said.


g.drawImage(someImage,x,y,someWidth, someHeight, 0,0,someWidth-x, someHeight-y,this);

If the area of the destination rectangle is equal to the source rectangle, there is no scaling.

Rafael.-

other than the clipping methods you’re using with setClip and the drawImage method, the only other way to achieve the same effect is to use the getSubimage method in BufferedImage, which just crops the image.

I wrote an example of that here

however, it is best to use the clipping methods inside the Graphics2D class, since it allows you to clip any Shape rather than just silly rectangle :wink:

in fact, a few years back (2003 i think), I made a lavalampy sort of thing with Graphics2D clips: here (sorry, its an applet, I used to be an applet activist… ;))

Ah ok I get it now. What im trying to do is draw a frame out of my sprite sheet. Not sure if the best approach is the drawImage or getSubImage. Which one is better? My images are buffered.

well, it depends. in both examples I gave you in my last post, the clips were pretty much always moving. in that case, the getSubimage method and the drawImage method are practically the same.

drawImage will crop the section of the image every time you call it, so if your clip object is always in movement, that’s fine. but if you’re setting a permanent clip, I would use getSubimage to save the clip to another BufferedImage object and then you can just draw than whenever you want (so java only has to “crop” the image one time).

so, in both scenarious, getSubimage turns out to be equal and/or better than the drawImage method, so I would just stick with getSubimage.

when it comes to NON rectangular clips, the best way to go is with the Graphics2D clipping methods with the Shape class… but that’s more computationally expensive and it is computed on each rendering call.

I get it now, but the thing is is that I will have a different clip range every other frame, so as to get the full animation (using a sprite sheet). So I guess i will stcik with the drawImage, since I need to reclip the image constantly, and getting the subImage sounds like it would create a new mage every time.

if the sprite animation isnt like massive… why not just cache each individual frame into an image array? then you can access it with imgArray[frame] any time you want =o

Hehe, its pretty big, 5 unique directions, 10 frames per direction, plus 1 direction with about 5 frames :slight_smile:

Don’t use getSubImage for your drawing routines… make separate images from your sprite sheet and then draw with those images. Just as Woogly says… cache the individual frames.

Drawing a sub-image is not as fast.

Is that really better than clipping the area of the sprite sheet? performance wise? Hum… I guess switching from one reference to another would be faster than constantly re clipping the same sprite.

From a performance perspective, why are you even considering this issue?

The calculations necessary in the underlying pipeline are identical when comparing a clipped blit Vs a subrectangle blit.

The only issue you should be considering, is whether your blit will be hardware accelerated, as this will give you performance gains of between 100times, to 1000times the speed. (that is 10000% to 100000% the speed of an unaccelerated blit)

From the perspective of design, you should completely ignore the ‘subrectangle’ caabilities that BufferedImage offer.
These api functions are not offered to give any kind of performance benefit, they are mearly convenience methods so that higher level programming need not concern itself with the complication of calculating the correct clip rectangle necessary to draw a particular sub-rectangle.
Use the clipping capabilities offered by the Graphics[2D] classes - thats what it is there for.

caching the results of a subimage from a BufferedImage means you only have to perform the operation that one time - which will always be faster than clipping it over and over on each render …

You are talking about a difference of a handful of additions/subtractions.

I’d love to see a benchmark that demonstrated drawing a subrect was any faster than drawing the entire image with an equivalent clip.

I agree that caching multiple overlapping images on a single image will be faster than individually drawing the overlapping images (obviously).

But if you are talking about painting part of a single image, then wouldn’t sub-image & setting the clip be the same? Remember there is always a clip applied to drawing anything on the screen - the device (screen rectangle) clip.

If what you say is true, drawing an image that is bigger than the screen is quicker than drawing an image the same size… hmm shouldn’t be too hard to make a bench-mark - I’ll do it if I can find time. I bet there’s no difference.

I think you guys are misreading me. I will definitely benchmark this later so you see what I mean.

picture a spritesheet, okay? you only want to draw a clip of that image. my theory is, caching each little sprite frame into an array of subImages would be faster than clipping the spritesheet at every render.

drawing a cached subimage is faster because there isn’t any clipping done, java is just drawing a regular image, that happens to have been cropped beforehand from the spritesheet. :wink:

The operations performed to achieve the result are functionally identical in both cases - however I expect repeatedly clipping the single image will be everso-marginally faster.
A simple blit such as :-

g.setClip(dstX,dstY,srcWidth,srcHeight);
g.drawImage(img, dstX-srcX, dstY-srcY, null);

From a very superficial view, this approach will touch the same 2 areas of memory each time you do a blit.
(writing to the clip fields in the Graphics object ‘g’, and reading from the member fields in BufferedImage ‘img’)
But - however many part of the img you draw, you will only ever be touching the same 2 areas of memory.

The subrectangle approach will not touch the Graphics objects clipping members - however, each time a different subrectangle is drawn - you will be reading member variables from a different wrapper object - consequently you will be jumping all over memory.
This IMO has a higher probability of causing cache misses.

I still very much doubt this difference will be detectable though, as there are far far larger overheads involved in the pipeline that will eclipse such a tiny speed difference.

However - for the comparison to be completely fair (and functionally equivalent in all cases), I suppose the setClip approach should realy be doing the followiing :-

Shape oldClip = g.getClip();
g.clipRect(dstX,dstY,srcWidth,srcHeight);
g.drawImage(img, dstX-srcX, dstY-srcY, null);
g.setClip(oldClip);

So, if you do benchmark the 2 approaches - use this approach, not the simplified version.

okay, here is the benchmark: http://woogley.net/misc/Clipping/

it appears (on my system, at least), that subimaging is ~3x faster than clipping. you can find the benchmark program on the webpage

happy coding :wink:

Great work, thanks for publishing that. Its very clear. Experiments like that should all be put in one place around here somewhere.

I wonder whether it is the setting & resetting of the clip that takes the extra time or the computation to figure out what part of the image inside the clip. Probably the latter I guess.