0

I have a method that I want to rotate an image when the user enters the number of degrees to rotate it. The method does that, but the thing is it's rotating the image so that the new image lays on top of the old one (which I don't want it to do; I just want the new image by itself). The RotateTest is just an abbreviated form of the class with all of the methods needed in the ButtonListener class that should be relevant to rotating the image.

public class RotateTest {
    public Rotate() {
        try {
            String path = "default.jpg";
            File imageFile = new File(path);
            imageURL = imageFile.toURI().toURL();
            image = ImageIO.read(imageURL);
            this.imageLabel = new JLabel(imageLabel);
        } catch (IOException e) { }
    }

    public void setAngle(double angle) {
        this.angle = angle;
    }

    public void setImage(BufferedImage img) {
        this.image = img;
    }

private class ButtonListener implements ActionListener {
    public void actionPerformed(ActionEvent event) {
        boolean doAgain = true;
        Artsy artsy = new Artsy();
    if(event.getSource() == rotate) {
            //need something for cancel!
            do {
                String angleString = JOptionPane.showInputDialog("Please enter your angle in degrees.");
                double angle = Double.parseDouble(angleString);
                if(angle < 0) {
                    angle = 360 + angle;
                }
                setAngle(getAngle() + angle);
                setImage(artsy.doRotate(image, angle));
                revalidate();
                repaint();
                System.out.println("The angle is " + getAngle());
            } while(JOptionPane.OK_OPTION == 1);
        }
        else {
            if(doAgain) {
                setImage(artsy.doRotate(image, 360 - getAngle()));
                doAgain = false;
                setAngle(0);
            }
            revalidate();
            repaint();
            System.out.println("The angle is " + getAngle());
        }
}

}

And this is the other class with the method that rotates the image:

public class Artsy {
    public BufferedImage doRotate(BufferedImage src, double angle) {    
        angle = Math.toRadians(angle);
        Graphics2D g = (Graphics2D) src.getGraphics();      
        int w = src.getWidth();
        int h = src.getHeight();
        AffineTransform trans = new AffineTransform();
        trans.rotate(angle, w / 2, h / 2);
        AffineTransformOp scaleOp = new AffineTransformOp(trans, AffineTransformOp.TYPE_BILINEAR);
        g.drawImage(scaleOp.filter(src, null), 0, 0, null);
        g.dispose();
        return src;
    }
}

Thank you!!

mKorbel
  • 109,525
  • 20
  • 134
  • 319
user3337808
  • 11
  • 1
  • 4

1 Answers1

0

Your code seems correct to me, i can't see an obvious mistake. Nevertheless the following function is working for my to rotate images so it should also be a solution for you:

public static BufferedImage rotate(BufferedImage srcImage, double angle)
{
    double sin = Math.abs(Math.sin(Math.toRadians(angle))), cos = Math.abs(Math.cos(Math.toRadians(angle)));

    int originWidth = srcImage.getWidth(), originHeight = srcImage.getHeight();

    int newWidth = (int) Math.floor(originWidth * cos + originHeight * sin), newHeight = (int) Math.floor(originHeight * cos + originWidth * sin);

    BufferedImage newImage = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_ARGB);
    Graphics2D g = newImage.createGraphics();

    g.translate((newWidth - originWidth) / 2, (newHeight - originHeight) / 2);
    g.rotate(Math.toRadians(angle), originWidth / 2, originHeight / 2);
    g.drawImage(srcImage, 0, 0, null);
    g.dispose();

    return newImage;
}

A helper function:

/**
 * Converts an Icon to an Image
 */
public static Image iconToImage(Icon icon) {
    if (icon instanceof ImageIcon) {
        return ((ImageIcon) icon).getImage();
    }
    else {
        int w = icon.getIconWidth();
        int h = icon.getIconHeight();
        GraphicsEnvironment ge =
                GraphicsEnvironment.getLocalGraphicsEnvironment();
        GraphicsDevice gd = ge.getDefaultScreenDevice();
        GraphicsConfiguration gc = gd.getDefaultConfiguration();
        BufferedImage image = gc.createCompatibleImage(w, h);
        Graphics2D g = image.createGraphics();
        icon.paintIcon(null, g, 0, 0);
        g.dispose();
        return image;
    }
}

Example usage to rotate the JLabels icon for 90 degrees clockwise:

BufferedImage buImg = new BufferedImage(imageLabel.getIcon().getIconWidth(), imageLabel.getIcon().getIconHeight(), BufferedImage.TYPE_INT_ARGB);
buImg.getGraphics().drawImage(iconToImage(imageLabel.getIcon()), 0, 0, null);
imageLabel.setIcon(new ImageIcon(rotate(buImg, 90)));
alex
  • 5,516
  • 2
  • 36
  • 60
  • Thank you!! I don't really need to use a JLabel since I'm using paint, but it's nice to see how it's done for future references. I there a way to set an anchor point that the image rotates around (preferably the center)? Right now if I rotate 90 degrees and then 45 degrees and then press the reset button (which is the else statement in the actionPerformed method) the top left corner moves to the middle of the image instead of the top left. Is there a way to fix this? Thanks! – user3337808 Mar 26 '14 at 14:49
  • To offer an resetfunction, i would just save the origin picture in an extra variable and set it back to it, when pressing the reset button. If you wan't to offer an undo function, just can e.g. log the actions performed and invert it when undoing like: rotate 20; rotate -10; [undo] -> rotate -1 * -10; [undo] rotate -1 * 20 etc. – alex Mar 27 '14 at 09:45