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