1

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!

XaolingBao
  • 1,034
  • 1
  • 18
  • 34
  • Possible duplicate of [AffineTransform truncates image, what do I wrong?](http://stackoverflow.com/questions/8719473/affinetransform-truncates-image-what-do-i-wrong). – Hovercraft Full Of Eels Dec 25 '15 at 03:36
  • Thank you very much, I will take a look at this. – XaolingBao Dec 25 '15 at 03:38
  • 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 Dec 25 '15 at 04:05

1 Answers1

2

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

Hovercraft Full Of Eels
  • 283,665
  • 25
  • 256
  • 373
  • I want to say thanks for this, but I actually solved my issue using your original problem. I essentially only need to know the rotation for 90, 180, and 270 so I did this – XaolingBao Dec 25 '15 at 04:11
  • @Lasagna: but when I tested my code again, my centers of rotation were off. These work better. – Hovercraft Full Of Eels Dec 25 '15 at 04:12
  • switch(degrees) { case 90: transform.rotate(-Math.PI/2, image.getWidth()/2, image.getWidth()/2); break; case 270: transform.rotate(Math.PI/2, image.getHeight()/2, image.getHeight()/2); break; case 180: transform.rotate(Math.PI, image.getWidth()/2, image.getHeight()/2); break; } – XaolingBao Dec 25 '15 at 04:12
  • I will try this as well, but figured I would post my findings :). – XaolingBao Dec 25 '15 at 04:12
  • So i tried this, and for some reason when trying values like "150" the image is cut off in both top and bottom. I also changed the quadrants to just regular rotation. Working something now, but thnaks for the tips to get me started. Granted I really only need 90, 180, 270. I don't see more for now :). – XaolingBao Dec 25 '15 at 04:51