'Rotating BufferedImage instances

I am having trouble getting a rotated BufferedImage to display. I think the rotation is working just fine, but I can't actually draw it to the screen. My code:

Class extends JPanel {
    BufferedImage img;
    int rotation = 0;

    public void paintComponent(Graphics g) {
        g.clearRect(0, 0, getWidth(), getHeight());
        img2d = img.createGraphics();
        img2d.rotate(Math.toRadians(rotation), img.getWidth() / 2, img.getHeight() / 2);
        g.drawImage(img, imgx, imgy, null);
        this.repaint();
    }
}

This is not working for me. I could not find any way to draw the rotated img2d onto g.

EDIT: I have multiple objects that are being drawn onto g, so I can't rotate that. I need to be able to rotate things individually.



Solution 1:[1]

I would use Graphics2D.drawImage(image, affinetranform, imageobserver).

The code example below rotates and translates an image to the center of the component. This is a screenshot of the result:

screenshot

public static void main(String[] args) throws IOException {
    JFrame frame = new JFrame("Test");

    frame.add(new JComponent() {
        BufferedImage image = ImageIO.read(
                new URL("http://upload.wikimedia.org/wikipedia/en/2/24/Lenna.png"));

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);

            // create the transform, note that the transformations happen
            // in reversed order (so check them backwards)
            AffineTransform at = new AffineTransform();

            // 4. translate it to the center of the component
            at.translate(getWidth() / 2, getHeight() / 2);

            // 3. do the actual rotation
            at.rotate(Math.PI / 4);

            // 2. just a scale because this image is big
            at.scale(0.5, 0.5);

            // 1. translate the object so that you rotate it around the 
            //    center (easier :))
            at.translate(-image.getWidth() / 2, -image.getHeight() / 2);

            // draw the image
            Graphics2D g2d = (Graphics2D) g;
            g2d.drawImage(image, at, null);

            // continue drawing other stuff (non-transformed)
            //...
        }
    });

    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setSize(400, 400);
    frame.setVisible(true);
}

Solution 2:[2]

Maybe you should try using AffineTransform like this:

AffineTransform transform = new AffineTransform();
transform.rotate(radians, bufferedImage.getWidth() / 2, bufferedImage.getHeight() / 2);
AffineTransformOp op = new AffineTransformOp(transform, AffineTransformOp.TYPE_BILINEAR);
bufferedImage = op.filter(bufferedImage, null);

Hope this helps.

Solution 3:[3]

You are rotating the graphics for drawing into your image, not the image. Thats why you see no effect. Apply the rotation to the graphics you are painting on and it will draw the image rotated:

public void paintComponent(Graphics g) {
    g.clearRect(0, 0, getWidth(), getHeight());
    g.rotate(Math.toRadians(rotation), img.getWidth() / 2, img.getHeight() / 2);
    g.drawImage(img, imgx, imgy, null);
    this.repaint();
}

This will probably not draw entirely what you expect, the rotation will revolve around the coordinate origin. For the image to be rotate around its center you need to apply a coordinate translation before the rotation, for example:

g.translate(imgx >> 1, imgy >> 1);

The Graphics2D Tutorial has some more examples.

Solution 4:[4]

I know this question is old but I came up with a solution that has some advantages:

  • creates image of correct size.
  • correct offset.
  • does not unnecessarily rotate by 0° or 360°.
  • works for negative angles (e.g. -90°).
  • works when input is BufferedImage.TYPE_CUSTOM.

As it is, it is assumed that the angle is a multiple of 90°. The only improvement that one might need is to use an Enum for angle instead of just int.

Here's my code:

public static BufferedImage rotateBufferedImage(BufferedImage img, int angle) {
    if (angle < 0) {
        angle = 360 + (angle % 360);
    }
    if ((angle %= 360) == 0) {
        return img;
    }

    final boolean r180 = angle == 180;
    if (angle != 90 && !r180 && angle != 270)
        throw new IllegalArgumentException("Invalid angle.");
    final int w = r180 ? img.getWidth() : img.getHeight();
    final int h = r180 ? img.getHeight() : img.getWidth();
    final int type = img.getType() == BufferedImage.TYPE_CUSTOM ? BufferedImage.TYPE_INT_ARGB : img.getType();
    final BufferedImage rotated = new BufferedImage(w, h, type);
    final Graphics2D graphic = rotated.createGraphics();
    graphic.rotate(Math.toRadians(angle), w / 2d, h / 2d);
    final int offset = r180 ? 0 : (w - h) / 2;
    graphic.drawImage(img, null, offset, -offset);
    graphic.dispose();
    return rotated;
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Community
Solution 2 Community
Solution 3 Durandal
Solution 4