21

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.

Andrew Thompson
  • 168,117
  • 40
  • 217
  • 433

4 Answers4

37

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.

Community
  • 1
  • 1
Harry Joy
  • 58,650
  • 30
  • 162
  • 207
20

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);
}
Community
  • 1
  • 1
dacwe
  • 43,066
  • 12
  • 116
  • 140
5

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.

Durandal
  • 19,919
  • 4
  • 36
  • 70
  • I want to rotate the BufferedImage separately and then draw it with the Graphics. I have other things on the Graphics object that should not be rotated. –  Feb 07 '11 at 09:30
  • You can undo the transformation of the Graphics after drawing the image. – Durandal Feb 18 '11 at 10:35
  • 3
    @Durandal Are you sure `Graphics` has a rotate method? Or do you mean `g2d.rotate()`? – user3437460 Jul 16 '15 at 22:49
0

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);
    }
    angle %= 360;
    if (angle == 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;
}
public static BufferedImage rotateBufferedImage(String img, int angle) throws IOException {
    return rotateBufferedImage(Paths.get(img), angle);
}
public static BufferedImage rotateBufferedImage(Path img, int angle) throws IOException {
    return rotateBufferedImage(ImageIO.read(img.toFile()), angle);
}
Claude Martin
  • 745
  • 6
  • 21