Rotate a buffered image in Java
Solution 1
As always, the Internet to the rescue. So, this is some code which I hobbled together from other resources/post/blogs which will return a new image which is sized so it will contain the rotated image
public BufferedImage rotateImageByDegrees(BufferedImage img, double angle) {
double rads = Math.toRadians(angle);
double sin = Math.abs(Math.sin(rads)), cos = Math.abs(Math.cos(rads));
int w = img.getWidth();
int h = img.getHeight();
int newWidth = (int) Math.floor(w * cos + h * sin);
int newHeight = (int) Math.floor(h * cos + w * sin);
BufferedImage rotated = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = rotated.createGraphics();
AffineTransform at = new AffineTransform();
at.translate((newWidth - w) / 2, (newHeight - h) / 2);
int x = w / 2;
int y = h / 2;
at.rotate(rads, x, y);
g2d.setTransform(at);
g2d.drawImage(img, 0, 0, this);
g2d.setColor(Color.RED);
g2d.drawRect(0, 0, newWidth - 1, newHeight - 1);
g2d.dispose();
return rotated;
}
Updated
So, using this PNG:
And this code...
package javaapplication1.pkg040;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private BufferedImage master;
private BufferedImage rotated;
public TestPane() {
try {
master = ImageIO.read(new File("/Volumes/Disk02/Dropbox/MegaTokyo/Miho_Small.png"));
rotated = rotateImageByDegrees(master, 0.0);
} catch (IOException ex) {
ex.printStackTrace();
}
Timer timer = new Timer(40, new ActionListener() {
private double angle = 0;
private double delta = 1.0;
@Override
public void actionPerformed(ActionEvent e) {
angle += delta;
rotated = rotateImageByDegrees(master, angle);
repaint();
}
});
timer.start();
}
@Override
public Dimension getPreferredSize() {
return master == null
? new Dimension(200, 200)
: new Dimension(master.getWidth(), master.getHeight());
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (rotated != null) {
Graphics2D g2d = (Graphics2D) g.create();
int x = (getWidth() - rotated.getWidth()) / 2;
int y = (getHeight() - rotated.getHeight()) / 2;
g2d.drawImage(rotated, x, y, this);
g2d.dispose();
}
}
public BufferedImage rotateImageByDegrees(BufferedImage img, double angle) {
double rads = Math.toRadians(angle);
double sin = Math.abs(Math.sin(rads)), cos = Math.abs(Math.cos(rads));
int w = img.getWidth();
int h = img.getHeight();
int newWidth = (int) Math.floor(w * cos + h * sin);
int newHeight = (int) Math.floor(h * cos + w * sin);
BufferedImage rotated = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = rotated.createGraphics();
AffineTransform at = new AffineTransform();
at.translate((newWidth - w) / 2, (newHeight - h) / 2);
int x = w / 2;
int y = h / 2;
at.rotate(rads, x, y);
g2d.setTransform(at);
g2d.drawImage(img, 0, 0, this);
g2d.dispose();
return rotated;
}
}
}
I can generate something like...
Solution 2
You get jumbled image result because you are drawing the rotated image into the input image itself. Instead you need to create graphic from a new BufferedImage.
public static BufferedImage rotate(BufferedImage bimg, double angle) {
int w = bimg.getWidth();
int h = bimg.getHeight();
BufferedImage rotated = new BufferedImage(w, h, bimg.getType());
Graphics2D graphic = rotated.createGraphics();
graphic.rotate(Math.toRadians(angle), w/2, h/2);
graphic.drawImage(bimg, null, 0, 0);
graphic.dispose();
return rotated;
}
Note that if you want to avoid getting cropped corners, you need to adjust width & height of the output BufferedImage.
Zugor
Updated on July 27, 2022Comments
-
Zugor almost 2 years
I am trying to rotate a buffered image in java. Here is the code I am using:
public static BufferedImage rotate(BufferedImage bimg, double angle) { int w = bimg.getWidth(); int h = bimg.getHeight(); Graphics2D graphic = bimg.createGraphics(); graphic.rotate(Math.toRadians(angle), w / 2, h / 2); graphic.drawImage(bimg, null, 0, 0); graphic.dispose(); return bimg; }
I have looked a numerous stack overflow questions and answers on this topic and not been able to figure out why the image is chopped up the way it is when I try to rotate it. Here is an example showing a loaded image: loaded image
After I click the rotate button which calls the above function with the buffered image and a 90.0 for the angle: chopped up image
Can someone help me understand what is happening and how to fix it?
-
Zugor almost 8 yearsI am uncertain how the line GraphicsConfiguration gc = getDefaultConfiguration(); works. I googled it and see you need the GraphicsEnvironment and then GraphicsDevice. Not sure how to use it. I copied the function in the recommended link and it causes an error.
-
Zugor almost 8 yearsOddly enough the images that I am working with will not rotate and lock up my program. The images are created by converting values in a binary file to grayscale and then stored in a bufferedimage. I tried one that I saved to PNG and it failed to rotate as well. The only images that will rotate are ones loaded from a JPEG format. Any thoughts?
-
MadProgrammer almost 8 yearsSo, I've re-tested the code using a PNG based image and it works fine for me. I suggest you consider asking a new question and provide a runnable example which demonstrates your problem as it would seem to more related to "how" you're using the code, from my perspective
-
Richard Barker almost 8 years@MadProgrammer Fair points all around. I'd rather know why as well but my thought was if you knew who, you could find out why. Ah, but.... c`est la vie.
-
GitPhilter over 3 years@MadProgrammer: I have a question regarding your code: In the rotateImagesByDegree(...) , almost at the bottom there is the line: g2d.drawImage(img, 0, 0, this); This quite confueses me, as it seems as if the original image (un-rotated) is painted. Then above in the paintComponent, there is : g2d.drawImage(rotated, x, y, this); The code works fine, but could you please elaborate why you have two paint-statements? Thanks.
-
MadProgrammer over 3 years@GitPhilter Did you see the line
g2d.setTransform(at);
? This is applying a transformation to theGraphics
context, which defines the rotation logic -
GitPhilter over 3 years@MadProgrammer Yes, I see it. I don´t know if we are talking about the same thing, though. I wanted to understand why there are TWO different paint-statements in two different spots. Why can we not just always paint the rotated image in the paintComponent()? Whats the logic behind this?
-
MadProgrammer over 3 years@GitPhilter Ok, so
rotateImageByDegrees
is taking the original image and rotating it by a set number of degrees. This generates a newBufferedImage
.paintComponent
is simply painting the rotated image to the screen, so you can see the result. So, you could takerotateImageByDegrees
and rotate an image and, I don't know, save it or do what ever you want - or, if you wanted to, as the example does, animate it