package johnny.tests;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;
import java.awt.image.BufferedImage;
/**
* Class for rotating <code>BufferedImage</code>s.
*/
public final class ImageRotater {
/**
* Private constructor.
*/
private ImageRotater() {
}
/**
* Rotates image and adjust image size.
*/
public static BufferedImage rotateImage(BufferedImage src, double degrees) {
Point srcSize = new Point(src.getWidth(), src.getHeight());
Point dstSize = rectangleExtendAfterRotation(srcSize.x, srcSize.y,
degrees);
int correctionX = dstSize.x - srcSize.x;
int correctionY = dstSize.y - srcSize.y;
AffineTransform affineTransform = AffineTransform.getRotateInstance(
Math.toRadians(degrees), srcSize.x / 2 + correctionX / 2,
srcSize.y / 2 + correctionY / 2);
BufferedImage rotatedImage = new BufferedImage(dstSize.x, dstSize.y,
src.getType());
Graphics2D g = (Graphics2D) rotatedImage.getGraphics();
g.setTransform(affineTransform);
g.drawImage(src, correctionX / 2, correctionY / 2, null);
return rotatedImage;
}
/**
* Calculates the size of the canvas, that a justified rectangle needs after
* rotation.
*
* @param width
* of the rectangle
* @param height
* of the rectangle
* @param d
* rotation in degrees
* @return
*/
private static Point rectangleExtendAfterRotation(int width, int height,
double d) {
Point2D.Double center = new Point2D.Double((double) width / 2,
(double) height / 2);
double degree = Math.toRadians(d);
// get rotated corners
Point2D.Double newCorner1 = rotatedPoint(new Point2D.Double(0, 0),
center, degree);
Point2D.Double newCorner2 = rotatedPoint(new Point2D.Double(width, 0),
center, degree);
Point2D.Double newCorner3 = rotatedPoint(new Point2D.Double(width,
height), center, degree);
Point2D.Double newCorner4 = rotatedPoint(new Point2D.Double(0, height),
center, degree);
// get extend of rotated rectangle
double minX = Math.min(Math.min(newCorner1.x, newCorner2.x),
Math.min(newCorner3.x, newCorner4.x));
double maxX = Math.max(Math.max(newCorner1.x, newCorner2.x),
Math.max(newCorner3.x, newCorner4.x));
double minY = Math.min(Math.min(newCorner1.y, newCorner2.y),
Math.min(newCorner3.y, newCorner4.y));
double maxY = Math.max(Math.max(newCorner1.y, newCorner2.y),
Math.max(newCorner3.y, newCorner4.y));
return new Point((int) (Math.ceil(maxX) - Math.floor(minX)),
(int) (Math.ceil(maxY) - Math.floor(minY)));
}
/**
* Rotates one point around another by a specified degree.
*
* @param pointToBeRotated
* @param centerTobeRotatedAround
* @param degree
* in radians
* @return rotated point
*/
private static Point2D.Double rotatedPoint(Point2D.Double pointToBeRotated,
Point2D.Double centerTobeRotatedAround, double degree) {
double dstAngle = Math.atan2(pointToBeRotated.x
- centerTobeRotatedAround.x, pointToBeRotated.y
- centerTobeRotatedAround.y)
+ degree;
double circleDistance = distance(centerTobeRotatedAround.x,
centerTobeRotatedAround.y, pointToBeRotated.x,
pointToBeRotated.y);
return new Point2D.Double(centerTobeRotatedAround.x
+ Math.sin(dstAngle) * circleDistance,
centerTobeRotatedAround.y + Math.cos(dstAngle) * circleDistance);
}
/**
* Calculates the distance from one point to another.
*/
private static double distance(double x1, double y1, double x2, double y2) {
return Math.sqrt((y2 - y1) * (y2 - y1) + (x2 - x1) * (x2 - x1));
}
/**
* Rotates an image 90° clockwise.
*
* @param src
* @return
*/
public static BufferedImage rotateImageRight(BufferedImage src) {
return tiltImage(src, true);
}
/**
* Rotates an image 90° counter-clockwise.
*
* @param srcImage
* @return
*/
public static BufferedImage rotateImageLeft(BufferedImage src) {
return tiltImage(src, false);
}
/**
* Rotate image 90°.
*/
private static BufferedImage tiltImage(BufferedImage src, boolean clockwise) {
BufferedImage rotatedImage = new BufferedImage(src.getHeight(),
src.getWidth(), src.getType());
AffineTransform affineTransform;
if (clockwise)
affineTransform = AffineTransform.getRotateInstance(
Math.toRadians(90), rotatedImage.getWidth() / 2d,
src.getHeight() / 2d);
else
affineTransform = AffineTransform.getRotateInstance(
Math.toRadians(270), src.getWidth() / 2d,
rotatedImage.getHeight() / 2d);
Graphics2D g = (Graphics2D) rotatedImage.getGraphics();
g.setTransform(affineTransform);
g.drawImage(src, 0, 0, null);
return rotatedImage;
}
}