public static BufferedImage rotate(Image image, double angle, int cx, int cy){
int width = image.getWidth(null);
int height = image.getHeight(null);
//The bounds of the image
int minX, minY, maxX, maxY;
minX = minY = maxX = maxY = 0;
//create an array containing the corners of the image
//In the order TL,TR,BR,BL
int[] corners = { 0, 0, width, 0, width, height, 0, height };
double theta = Math.toRadians(angle);
for(int i=0;i<corners.length;i+=2){
//Rotates the given point theta radians around (cx,cy)
int x = (int)(Math.cos(theta)*(corners[i]-cx) -
Math.sin(theta)*(corners[i+1]-cy)+cx);
int y = (int)(Math.sin(theta)*(corners[i]-cx) +
Math.cos(theta)*(corners[i+1]-cy)+cy);
//Update our bounds
if(x>maxX) maxX = x;
if(x<minX) minX = x;
if(y>maxY) maxY = y;
if(y<minY) minY = y;
}
//Where the center of the old image should be on the image we are
//just about to create so that the image is all in viewable space.
cx = (int)(cx-minX);
cy = (int)(cy-minY);
//Create a new image such that when we roate the old image, no pixels
//will have a negative x or y coordinate.
BufferedImage bi = createBufferedImage(maxX-minX, maxY-minY, true);
Graphics2D g2 = bi.createGraphics();
//Finally start the rotation process
AffineTransform at = new AffineTransform();
at.rotate(theta,cx,cy);
g2.setTransform(at);
g2.drawImage(image,-minX,-minY,null);
g2.dispose();
return toBufferedImage(bi);
}