0

I'm trying to rotate a bunch of BufferedImage instances, the rotate works, but what's odd is that they change their position. Here's a snippet of how I do it.

BufferedImage philo1=ImageIO.read(new File("D:\\philo1.png"));
public void paint(Graphics g)
{
    super.paint(g);
    Graphics2D g2d = (Graphics2D)g;
    AffineTransform old = g2d.getTransform();
    g2d.rotate(Math.toRadians(15),philo1.getWidth()/2,philo1.getHeight()/2);
    g.drawImage(philo1,172, 48, 50, 50,this);
    g2d.setTransform(old);
}

the result is like this(with and without the rotation):

Before the rotation After the rotation

What could be causing this? I suspect the reason is that I'm forcing the size of the image when I draw it, that's why it draws it in a different position, as I'm calling the rotation method before drawing. If this is the case, how can I solve this?

Amine
  • 1,396
  • 4
  • 15
  • 32
  • Looks to be because you are referencing the image by a corner. When you rotate it, the canvas size has now become larger. Instead of placing the image relative the corner, place it relative to the center. – Matt Clark Oct 30 '17 at 22:26
  • You're not rotating the image, you rotating the entire `Graphics` context for the component – MadProgrammer Oct 30 '17 at 22:27
  • A better solution would be to rotate the image within it's own context, for [example, something like this](https://stackoverflow.com/questions/37758061/rotate-a-buffered-image-in-java/37758533#37758533). This will generate a new image, rotated (and sized) based on your needs – MadProgrammer Oct 30 '17 at 22:29

1 Answers1

1

The basic problem is, you're trying to rotate the entire Graphics context around the centre point of the image, if it were been drawn from the top/left corner of the context (0x0), but the image is offset.

Because rotating images with virtual space is so much fun, I prefer to generate a new image rotated within its own context and then simply paint that. For example

If that seems like to much work, then you will need to first translate the Graphics context in such away that the top/left corner is where the image is to be painted from, then you'll be able to rotate the image simple around it's centre/anchor point, for example:

Various container sizes

import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class Test {

    public static void main(String[] args) {
        new Test();
    }

    public Test() {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    JFrame frame = new JFrame();
                    frame.add(new TestPane());
                    frame.pack();
                    frame.setLocationRelativeTo(null);
                    frame.setVisible(true);
                } catch (IOException ex) {
                    ex.printStackTrace();
                }
            }
        });
    }

    public class TestPane extends JPanel {

        private BufferedImage img;
        private double rotationByDegrees = 45.0;

        public TestPane() throws IOException {
            img = ImageIO.read(new File("/Users/shanewhitehead/Downloads/L05HK.png"));
        }

        @Override
        public Dimension getPreferredSize() {
            return img == null ? super.getPreferredSize() : new Dimension(img.getWidth(), img.getHeight());
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            if (img != null) {
                Graphics2D g2d = (Graphics2D) g.create();
                int x = (getWidth() - img.getWidth()) / 2;
                int y = (getHeight() - img.getHeight()) / 2;
                g2d.translate(x, y);
                g2d.rotate(Math.toRadians(rotationByDegrees), img.getWidth() / 2, img.getHeight() / 2);
                g2d.drawImage(img, 0, 0, this);
                g2d.dispose();
            }
        }

    }

}

Note: You could also use a AffineTransform, but I've just kept it simple

MadProgrammer
  • 343,457
  • 22
  • 230
  • 366