Problems rotating BufferedImage

perp picture perp · Feb 13, 2010 · Viewed 19.9k times · Source

I have some problems with rotating images in Java using the AffineTransform class.

I have the following method for creating a rotated (90 degrees) copy of an image:

private BufferedImage createRotatedCopy(BufferedImage img, Rotation rotation) {
    int w = img.getWidth();
    int h = img.getHeight();

    BufferedImage rot = new BufferedImage(h, w, BufferedImage.TYPE_INT_RGB);

    double theta;
    switch (rotation) {
        case CLOCKWISE:
            theta = Math.PI / 2;
            break;
        case COUNTERCLOCKWISE:
            theta = -Math.PI / 2;
            break;
        default:
            throw new AssertionError();
    }

    AffineTransform xform = AffineTransform.getRotateInstance(theta, w / 2, h / 2);
    Graphics2D g = (Graphics2D) rot.createGraphics();
    g.drawImage(img, xform, null);
    g.dispose();

    return rot;
}

Rotation is a simple enum with the values NONE, CLOCKWISE and COUNTERCLOCKWISE.

The symptoms of my problems are displayed here:

http://perp.se/so/rotate_problems.html

So, the rotation works OK, but the resulting images aren't anchored to the correct coordinates (or how one should put it). And since I don't really know what the heck I'm doing in the first place (my linear algebra is weak), I don't know how to solve this on my own.

I've tried with some random fiddling with the AffineTransform instance, but it hasn't helped me (of course). I've tried googling (and searching SO), but all examples I've seen basically use the same approach as I do... which doesn't work for me.

Thankful for advice.

Answer

finnw picture finnw · Feb 13, 2010

If you must express the transform as a single rotation, the anchor point depends on the direction of rotation: Either (w/2, w/2) or (h/2, h/2).

But it's probably simpler to express as translate; rotate; translate, e.g.

AffineTransform xform = new AffineTransform();
xform.translate(0.5*h, 0.5*w);
xform.rotate(theta);
xform.translate(-0.5*w, -0.5*h);

Also consider using getQuadrantRotateInstance instead of getRotateInstance.