1
votes

What I'm trying to do:

I am looking to transform an image by rotating it by either 90, 180, or 270 degrees.


What's happening:

For some reason when I am rotating a 640x360 pixel image, 90 degrees, I end up getting a 500x500 image, instead of a 360x640 image, so the image gets re-sized for some reason...

I also tried a 5000 x 2000 or so image, and I got a 4800x4800 image as a result when rotated.

180 works correctly and produces the same size as no rotation, but 90 and 270 don't work...


What I've noticed

I noticed that degrees isn't the exactly the same as the Radian value, so I'm trying to use Radians instead.

I've noticed that using Math.toRadians(90) results in a clockwise rotation, and not a couterclockwise rotation... I'm curious why the positive rotation is clockwise, and not counterclockwise?


Code:

public static BufferedImage rotateImage(BufferedImage image) throws IOException

{
        AffineTransform transform = new AffineTransform();


        transform.rotate(Math.PI/2, image.getWidth()/2, image.getHeight()/2);
        AffineTransformOp op = new AffineTransformOp(transform, AffineTransformOp.TYPE_BILINEAR);
        image = op.filter(image, null);



             ImageIO.write(image,"PNG",new File("C:\\a.png"));
             return image;
}

Any advice is appreciated, thank you for your time!

1
Thank you very much, I will take a look at this.XaolingBao
From what I read, it seems that the rotation itself makes it so that the rotation occurs offscreen, so it clips some of the image? I would assume that if the picture was tall, and you rotated it -90, so that it rotated 90* CCW, it would actually cut off part of the image on the right, not the left... I figured out something for myself, I think it will work...!XaolingBao

1 Answers

2
votes

Oops, my equations to center the rotation are wrong in the previous example. To summarize:

  • You must rotate into a rotated BufferedImage, that is, a BufferedImage whose width and height are swapped from the original image.
  • You can't rotate around the center, but rather around a point that will place the new image at the 0, 0 point. That is the center of the major axis, centerX = Math.max(w0, h0) / 2;, or the minor axis, centerX = Math.min(w0, h0) / 2; depending on if you're rotating to the 1st or 3rd quadrant. For e.g.

import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;

import javax.imageio.ImageIO;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;

public class TestAffineTransform {
    private static final String IMG_PATH = "https://upload.wikimedia.org/wikipedia/commons/thumb"
            + "/4/42/MerryOldSanta.jpg/220px-MerryOldSanta.jpg";
    private static BufferedImage originalImg;

    public static void main(String[] args) {
        try {
            URL imgUrl = new URL(IMG_PATH);
            originalImg = ImageIO.read(imgUrl);
            BufferedImage nextRotImg = transform(originalImg, 1);

            final Icon originalIcon = new ImageIcon(originalImg);
            final Icon nextRotIcon = new ImageIcon(nextRotImg);

            SwingUtilities.invokeLater(() -> {
                JOptionPane.showMessageDialog(null, originalIcon);
                JOptionPane.showMessageDialog(null, nextRotIcon);
            });
        } catch (IOException e) {
            e.printStackTrace();
            System.exit(-1);
        }

    }

    public static BufferedImage transform(BufferedImage image, int numquadrants) {
        int w0 = image.getWidth();
        int h0 = image.getHeight();
        int w1 = w0;
        int h1 = h0;

        int centerX = w0 / 2;
        int centerY = h0 / 2;

        if (numquadrants % 2 == 1) {
            w1 = h0;
            h1 = w0;

            if (numquadrants % 4 == 1) {
                centerX = Math.max(w0, h0) / 2;
            } else {
                centerX = Math.min(w0, h0) / 2;
            }

            centerY = centerX;
        }

        AffineTransform affineTransform = new AffineTransform();
        affineTransform.setToQuadrantRotation(numquadrants, centerX, centerY);

        AffineTransformOp opRotated = new AffineTransformOp(affineTransform, AffineTransformOp.TYPE_BILINEAR);

        BufferedImage transformedImage = new BufferedImage(w1, h1, image.getType());

        opRotated.filter(image, transformedImage);
        return transformedImage;
    }

}

Which displays:

St Nick

and then displays:

St Nick 2