How to turn a graphics2D object into a BufferedImage

Is there a simple way to take a Graphics 2D I have drawn and turn it into a BufferedImage?MArk
[122 byte] By [markee1] at [2007-9-26 6:28:00]
# 1
Why not just draw onto the BufferdImage too? Or draw only on the bufferedimage and then blit that to the screen?
ericew at 2007-7-1 15:33:53 > top of Java-index,Security,Cryptography...
# 2
Thanks for the suggestion. I want to appply a clip tothe image which I have (so I get a clipped image) and I have been unable to see how I can do this to a BufferedImage, only a g2 object. Can it be done?Regards,MArk
markee1 at 2007-7-1 15:33:53 > top of Java-index,Security,Cryptography...
# 3

OK, you're confusing me...you could draw to the BufferedImage first, then draw the BufferedImage to the screen. First:

// A BufferedImage of dimensions x by y. The type can be whatever you choose.

BufferedImage myImage = new BufferedImage(x, y, BufferedImage.TYPE_INT_RGB);

// Create a graphics reference to the BufferedImage.

Graphics2D myGraphics = myImage.createGraphics();

Then, later, whenever you're drawing to you component:

public void paint(Graphics g) {

// Draw whatever you want to your BufferedImage.

myGraphics.draw(...);

// Set the clipping for your on-screen graphics.

g.setClip(x, y, w, h);

// Draw your BufferedImage to the screen.

g.drawImage(myImage, x, y, null);

}

Does that help at all?

Michael Bishop

mbishop78 at 2007-7-1 15:33:53 > top of Java-index,Security,Cryptography...
# 4

How do I then get the clipped image out of g?

What I want to do is to take an image, apply the clip

and then be able to save the clipped image.

I could do this by checking each point in image against clip and setting to background colour if not inside clip. I want to do

image = g.extractAsBufferedImage();

Regards,

MArk

markee1 at 2007-7-1 15:33:53 > top of Java-index,Security,Cryptography...
# 5
Oh, you could do something like this:BufferedImage clippedImage = myImage.getSubimage(x, y, w, h); Where x,y,w,h are the bounds for the clipped area. You don't necessarily have to draw it to the screen to get a clipped image.Michael Bishop
mbishop78 at 2007-7-1 15:33:53 > top of Java-index,Security,Cryptography...
# 6
I've used that for rectangles but I want to clip it to an irregular path. The renderer does this if you set the clip and plot it for g2.I cannot see how to apply it to the image directly.MArk
markee1 at 2007-7-1 15:33:53 > top of Java-index,Security,Cryptography...
# 7
You could always use setClip() on g2 before you draw your image. That way, only the clipped region would be drawn.Michael Bishop
mbishop78 at 2007-7-1 15:33:53 > top of Java-index,Security,Cryptography...
# 8
Which is what I have. Now can I turn the g2 into aBufferedImage (in other words get a screen shot of it)?Regards,MArk
markee1 at 2007-7-1 15:33:53 > top of Java-index,Security,Cryptography...
# 9

OK, once again, you'd have this I believe:

BufferedImage myImage = new BufferedImage(x, y, BufferedImage.TYPE_INT_ARGB);

Graphics2D g2 = myImage.createGraphics();

g2.setClip(...);

g2.draw(...)

If you set the clip on the BufferedImage before you draw to it, anything you draw will only be applied if it's in the clipped region. To get it on screen:

public void paint(Graphics g) {

g.drawImage(myImage, 0, 0, null);

}

Although I'm not sure, that should draw your already-clipped BufferedImage to the screen.

Michael Bishop

mbishop78 at 2007-7-1 15:33:53 > top of Java-index,Security,Cryptography...
# 10

Thank-you for persevering with me!

As an example, I have a square image with a circular clip over part of the image. I want to save just the clipped part of the image to disk as an image, not the whole thing.

How can I extract a sub-image which is a clipped version of the original?

Regards,

MArk

markee1 at 2007-7-1 15:33:53 > top of Java-index,Security,Cryptography...
# 11

OK, I understand now. First of all, a subimage has to be rectangular. You can't get a subimage that's an irregular shape. If you want a transparent background, we'll approach that later. First:

// Create a BufferedImage for your original image.

BufferedImage wholeImage = new BufferedImage(x, y, BufferedImage.TYPE_INT_ARGB);

Graphics2D g2 = offScreen.createGraphics();

// Set the clip region to draw in.

g2.setClip(...);

// Draw your entire picture to the offscreen image.

g2.draw(...);

// Now we want a bounding box for your clipped region.

Rectangle clipRect = g2.getClipBounds();

// Get a subimage from your original image that contains the clipped region.

BufferedImage clippedImage = wholeImage.getSubimage(clipRect.getX(), clipRect.getY(), clipRect.getWidth(), clipRect.getHeight());

Now you have a subimage that has the proper bounds to contain your clipped image in the smallest rectangle possible. The second image can be written to disk. The TYPE_INT_ARGB implies an alpha channel that gives you a transparent background so there's no bounding "square" wherever you decide to draw your subimage. Does this help?

Michael Bishop

mbishop78 at 2007-7-1 15:33:53 > top of Java-index,Security,Cryptography...
# 12
Excellent stuff! I'll give it a go and see how it works.Thank-you.Regards,MArk
markee1 at 2007-7-1 15:33:53 > top of Java-index,Security,Cryptography...
# 13
No problem...if something doesn't work...we'll keep trying.Michael Bishop
mbishop78 at 2007-7-1 15:33:53 > top of Java-index,Security,Cryptography...
# 14
it should be:Graphics2D g2 = wholeImage.createGraphics();
rherlitz at 2007-7-1 15:33:53 > top of Java-index,Security,Cryptography...
# 15

I thought you might like to see the code. It is slightly complicated by the fact that I have a clipping shape which is upside down so I plot everything upside down to allow for this.

All I need to do now is to rotate the final image 180 degrees so it is not upside down and save image as a transparent JPEG - any thoughts?

Regards,

MArk

/**

* draw image on offscreen image so we can scale, rotate,crop

*/

private BufferedImage clip(BufferedImage current_image,int max_x,int max_y,GraphicsState current_graphics_state){

//create offscreen buffers

BufferedImage offscreen=new BufferedImage(max_x,max_y,BufferedImage.TYPE_INT_ARGB);

Graphics2D g2=offscreen.createGraphics();

//objects with my clip and my CTM array (contains x,y co-ords)

Area current_shape=current_graphics_state.getClippingShape();

float[][] CTM=current_graphics_state.CTM;

//image dimensions

float raw_w=current_image.getWidth();

float raw_h=current_image.getHeight();

//get X and Y displacements

float x1=CTM[2][0];

float y1=CTM[2][1];

//calculate scaled width & height using pythagoras theorem

int w=(int)Math.sqrt((CTM[0][0]*CTM[0][0])+(CTM[0][1]*CTM[0][1]));

int h=(int)Math.sqrt((CTM[1][0]*CTM[1][0])+(CTM[1][1]*CTM[1][1]));

//workout scaling required

float sx=w/raw_w;

float sy=h/raw_h;

//work out amount of turn in radians

double theta=Math.atan2(CTM[0][1],CTM[0][0]);

//set clip

current_shape.transform(AffineTransform.getTranslateInstance(-x1,-y1));

g2.setClip(current_shape);

//transform and draw offscreen

AffineTransform at1=new AffineTransform();

at1.translate((double)0,(double)h);

at1.scale((double)sx,(double)-sy);

at1.rotate(-theta,0,raw_h);

g2.drawImage(current_image,at1,null);

//get info on clipped size

Rectangle clipped_rect=g2.getClipBounds();

int r_x=(int) clipped_rect.getX();

int r_y=(int) clipped_rect.getY();

int r_w=(int) clipped_rect.getWidth();

int r_h=(int) clipped_rect.getHeight();

//make sure valid

if(r_x<0){

r_w=r_w+r_x;

r_x=0;

}

if(r_y<0){

r_h=r_h+r_y;

r_y=0;

}

if(r_h+r_y>=offscreen.getHeight()){

r_h=offscreen.getHeight()-r_y;

}

if(r_w+r_x>=offscreen.getWidth()){

r_w=offscreen.getWidth()-r_x;

}

//extract image

BufferedImage return_image=offscreen.getSubimage(r_x,r_y,r_w,r_h);

//possible code to flip - does not work yet as makes image twice the size

/**

AffineTransform at_flip=AffineTransform.getScaleInstance(1,1);

AffineTransformOp flip= new AffineTransformOp(at_flip,null);

//return_image=flip.filter(return_image,null);

//remove excess added by rotation

//int x=return_image.getWidth()/2;

//int y=return_image.getHeight();

//return_image=return_image.getSubimage(x,0,x,y/2);

*/

return return_image;

}

markee1 at 2007-7-1 15:33:55 > top of Java-index,Security,Cryptography...
# 16

Hrm, I actually did this once for Pacman. But I ended up pre-rendering him and abandoning the AffineTransform idea. Give this a try:

// Get a rotate transform that's anchored in the center of the image and turned 180 degrees.

AffineTransform rotateTransform = AffineTransform.getRotateInstance(Math.toRadians(180), imageCenterX, imageCenterY);

// Get a TransformOp using the above transform.

AffineTransformOp rotateOp = new AffineTransformOp(rotateTransform, null);

// Apply the changes to the final image.

return_image = rotateOp.filter(offScreen.getSubimage(r_x, r_y, r_w, r_h), return_image);

Michael Bishop

mbishop78 at 2007-7-1 15:33:55 > top of Java-index,Security,Cryptography...
# 17
I dont think a JPEG can be transparent. Only gifs and pngs and such... Someone correct me if im wrong.M
MickeyB at 2007-7-1 15:33:55 > top of Java-index,Security,Cryptography...
# 18
Thank-you. I will give it a try :-)
markee1 at 2007-7-1 15:33:55 > top of Java-index,Security,Cryptography...
# 19
jpegs can be transparent
JDunlop at 2007-7-1 15:33:55 > top of Java-index,Security,Cryptography...
# 20
JPEG's do not contain the information for transparnecy, only GIF, PNG, TIFF?, and possibly BMP's.
ericew at 2007-7-1 15:33:55 > top of Java-index,Security,Cryptography...
# 21
Thank you very much guys, This discussion helped my lotregards
abdusalam2000 at 2007-7-1 15:33:55 > top of Java-index,Security,Cryptography...
# 22
We'll send you the invoice for professional services then ;-)MArk
markee1 at 2007-7-1 15:33:55 > top of Java-index,Security,Cryptography...