/**
* Constant to specify that the bounding box should be not be changed
* for any angle of rotation when creating the rotated image. This
* means the returned image will be the same size as the given image.
* Of course, that also means the corners of the image may be cut off.
*/
public static final int NO_BOUNDING_BOX = 0;
/**
* Constant to specify that the exact bounding box should be used for
* the specified angle of rotation when creating the rotated image.
* This is the default option. When used, the rotated image may be
* larger then the source image, but no larger then needed to fit the
* rotated image exactly. Therefore, rotating the same image to various
* angles may result in varying image sizes.
*/
public static final int EXACT_BOUNDING_BOX = 1;
/**
* Constant to specify that the largest bounding box should be used when
* creating the rotated image. When used, the rotated image will be
* larger then the source image, but all rotated images of that same
* source image will be the same size, regardless of the angle of
* rotation. This may result in significant "empty space" between the
* edge of the returned image and the actual drawn pixel areas.
*/
public static final int LARGEST_BOUNDING_BOX = 2;
/**
* Rotates the specified image the specified number of degrees. The
* rotation is performed around the center point of the image.
*
* @param img the image to rotate
* @param degrees the degrees to rotate
* @param bbm the bounding box mode, default is EXACT_BOUNDING_BOX
* @param background the background paint (texture, color or gradient),
* can be null
* @return the image
* @see #NO_BOUNDING_BOX
* @see #EXACT_BOUNDING_BOX
* @see #LARGEST_BOUNDING_BOX
*/
public static BufferedImage rotateDegrees(Image img, double degrees, int bbm, Paint background) {
return rotateRadians(img, Math.toRadians(degrees), bbm, background);
}
/**
* Rotates the specified image the specified number of radians. The
* rotation is performed around the center point of the image. This
* method is provided for convenience of applications using radians.
* For most people, degrees is simpler to use.
*
* @param img the image to rotate
* @param radians the radians to rotate
* @param bbm the bounding box mode, default is EXACT_BOUNDING_BOX
* @param background the background paint (texture, color or gradient),
* can be null
* @return the image
* @see #NO_BOUNDING_BOX
* @see #EXACT_BOUNDING_BOX
* @see #LARGEST_BOUNDING_BOX
*/
public static BufferedImage rotateRadians(Image img, double radians, int bbm, Paint background) {
// get the original image's width and height
int iw = img.getWidth(null);
int ih = img.getHeight(null);
// calculate the new image's size based on bounding box mode
Dimension dim;
if(bbm == NO_BOUNDING_BOX) {
dim = new Dimension(iw, ih);
} else if(bbm == LARGEST_BOUNDING_BOX) {
dim = getLargestBoundingBox(iw, ih);
} else { // EXACT_BOUNDING_BOX
dim = getBoundingBox(iw, ih, Math.toDegrees(radians));
}
// get the new image's width and height
int w = dim.width;
int h = dim.height;
// get the location to draw the original image on the new image
int x = (w/2)-(iw/2);
int y = (h/2)-(ih/2);
// need to copy the given image to a new BufferedImage because
// it is, in most cases, going to be a larger image so it
// needs to be drawn centered on the larger image
BufferedImage bi = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = bi.createGraphics();
// set some rendering hints for better looking images
g2d.setRenderingHints(renderingHints);
// draw the background paint, if necessary
if(background != null) {
g2d.setPaint(background);
g2d.fillRect(0, 0, w, h);
}
// if not rotating, just draw it normally, else create a transform
if(radians == 0.0) {
g2d.drawImage(img, x, y, iw, ih, null);
} else {
g2d.rotate(radians, w/2, h/2);
g2d.translate(x, y);
g2d.drawImage(img, 0, 0, iw, ih, null);
}
g2d.dispose();
return bi;
}
/**
* Gets the largest bounding box size that can hold an image of the
* specified size at any angle of rotation.
*
* @param width the image width
* @param height the image height
* @return the bounding box size
*/
public static Dimension getLargestBoundingBox(int width, int height) {
// The largest bounding box is the largest area needed to fit the
// specified image at any angle or rotation. This is simpler then
// getting the bounding box for a given angle because the largest
// box will put the corner of the image box directly along the
// vertical or horizontal axis from the image center point. The
// distance between the image rectangle's center and any corner
// is the hypotenuse of a right triangle who's other sides are
// half the width (a) and half the height (b) of the rectangle.
// A little a^2 + b^2 = c^2 calculation and we get the length of
// the hypotenuse. Double that to get a square within which the
// image can be rotated at any angle without clipping the image.
double a = (double)width / 2.0;
double b = (double)height / 2.0;
// use Math.ceil() to round up to an int value
int c = (int)Math.ceil(Math.sqrt((a * a) + (b * b)) * 2.0);
return new Dimension(c, c);
}
/**
* Gets the optimal/smallest bounding box size that can hold an image of
* the specified size at the specified angle of rotation.
*
* @param width the image width
* @param height the image height
* @return the bounding box size
*/
public static Dimension getBoundingBox(int width, int height, double degrees) {
degrees = normalizeDegrees(degrees);
// if no rotation or 180 degrees, the size won't change
if(degrees == 0.0 || degrees == 180.0) {
return new Dimension(width, height);
}
// if 90 or 270 (quarter or 3-quarter rotations) the width becomes
// the height, and vice versa
if(degrees == 90.0 || degrees == 270.0) {
return new Dimension(height, width);
}
// for any other rotation, we need to do some trigonometry,
// derived from description found at:
// http://www.codeproject.com/csharp/rotateimage.asp
double radians = Math.toRadians(degrees);
double aW = Math.abs(Math.cos(radians) * width);
double oW = Math.abs(Math.sin(radians) * width);
double aH = Math.abs(Math.cos(radians) * height);
double oH = Math.abs(Math.sin(radians) * height);
// use Math.ceil() to round up to an int value
int w = (int)Math.ceil(aW + oH);
int h = (int)Math.ceil(oW + aH);
return new Dimension(w, h);
}
posted on 2005-09-22 07:26
Pudgy's World 阅读(246)
评论(0) 编辑 收藏 所属分类:
Computer