I'm creating a domino game in java. I have the following code that loads, resizes and then display the domino image on the screen:
ImageIcon imageIcon = new ImageIcon("images\\4-4.png");
Image image = imageIcon.getImage();
Image newimg = image.getScaledInstance(60, 120, java.awt.Image.SCALE_SMOOTH);
imageIcon = new ImageIcon(newimg);
JLabel img = new JLabel(imageIcon);
img.setBounds(100, 100, 60, 120);
getContentPane().add(img);
What I want to do is rotate the image either 90 or -90 degrees. I've searched the internet but the examples I've found seems very complicated.
Any idea how I can rotate my image?
Btw, if you think that this is not the correct way to display dominoes in a domino game then please let me know. I'me a java newbie.
Rotating an image is non-trival, even just 90 degrees requires a certain amount of work.
So, based on pretty much every other question about rotating images, I'd start with something like...
public BufferedImage rotate(BufferedImage image, Double degrees) {
// Calculate the new size of the image based on the angle of rotaion
double radians = Math.toRadians(degrees);
double sin = Math.abs(Math.sin(radians));
double cos = Math.abs(Math.cos(radians));
int newWidth = (int) Math.round(image.getWidth() * cos + image.getHeight() * sin);
int newHeight = (int) Math.round(image.getWidth() * sin + image.getHeight() * cos);
// Create a new image
BufferedImage rotate = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = rotate.createGraphics();
// Calculate the "anchor" point around which the image will be rotated
int x = (newWidth - image.getWidth()) / 2;
int y = (newHeight - image.getHeight()) / 2;
// Transform the origin point around the anchor point
AffineTransform at = new AffineTransform();
at.setToRotation(radians, x + (image.getWidth() / 2), y + (image.getHeight() / 2));
at.translate(x, y);
g2d.setTransform(at);
// Paint the originl image
g2d.drawImage(image, 0, 0, null);
g2d.dispose();
return rotate;
}
While you're only rotate 90 degrees, this takes care of calculating the required size the new image needs in order to be able to paint the rotated image, at any angle.
It then simply makes use of AffineTransform to manipulate the origin point from which painting occurs - get use to this, you will do it a lot.
Then, I load the images, rotate them and display them...
try {
BufferedImage original = ImageIO.read(getClass().getResource("domino.jpg"));
BufferedImage rotated90 = rotate(original, 90.0d);
BufferedImage rotatedMinus90 = rotate(original, -90.0d);
JPanel panel = new JPanel();
panel.add(new JLabel(new ImageIcon(original)));
panel.add(new JLabel(new ImageIcon(rotated90)));
panel.add(new JLabel(new ImageIcon(rotatedMinus90)));
JOptionPane.showMessageDialog(null, panel, null, JOptionPane.PLAIN_MESSAGE, null);
} catch (IOException ex) {
ex.printStackTrace();
}
I prefer to use ImageIO to load images, because it throws an IOException when something goes wrong, rather then failing silently like ImageIcon.
You should also be embedding your resources within your application's context, this makes it easier to load them at runtime. Depending on IDE and how your project is set up, how you do this will change, but in "most" cases, you should be able to add the resource directly to your source directory (preferably in sub directory) and the IDE will make it available for you and package it when you export the project
Solution from: http://www.java2s.com/Code/Java/Advanced-Graphics/RotatingaBufferedImage.htm
AffineTransform tx = new AffineTransform();
tx.rotate(0.5, bufferedImage.getWidth() / 2, bufferedImage.getHeight() / 2);
AffineTransformOp op = new AffineTransformOp(tx,
AffineTransformOp.TYPE_BILINEAR);
bufferedImage = op.filter(bufferedImage, null);
Related
I'm trying to revolve a BufferedImage around its center. Here's my Code:
frame = new JFrame();
GridBagLayout gLayout = new GridBagLayout();
frame.getContentPane().setLayout(gLayout);
lbIm1 = new JLabel(new ImageIcon(img));
lbIm1.setPreferredSize(new Dimension(800, 800));
Timer timer = new Timer(100, e -> {
AffineTransform transform = new AffineTransform();
transform.translate(img.getWidth()/2, img.getHeight()/2);
transform.rotate(Math.toRadians(1), 0, 0);
transform.translate(-img.getWidth()/2, -img.getHeight()/2);
AffineTransformOp op = new AffineTransformOp(transform, AffineTransformOp.TYPE_BILINEAR);
BufferedImage rotatedImage = op.createCompatibleDestImage(img, img.getColorModel());
op.filter(img, rotatedImage);
lbIm1.setIcon(new ImageIcon(rotatedImage));
img = rotatedImage;
lbIm1.repaint();
});
timer.start();
c.fill = GridBagConstraints.HORIZONTAL;
c.gridx = 0;
c.gridy = 1;
frame.getContentPane().add(lbIm1, c);
frame.pack();
frame.setVisible(true);
The image size is 512 x 512. The problem in this code are:
The rotation is not exactly at center. It would rotate out of the screen.
The imagine became blurry over time.
I have searched online for a very long time and nothing seems to help. Any suggestions would be much appreciated. Thanks.
I would suggestion always rotating form the original image. Keep track of the total rotation.
int angleDegrees = 0;
That way there is less image quality degradation. Normally each time you use a bi-linear interpolation there will be some blurring.
AffineTransform transform = new AffineTransform();
angle += (angle + 1)%360;
transform.rotate(Math.toRad(angle), img.getWidth()/2, img.getHeight()/2);
AffineTransformOp op = new AffineTransformOp(transform, AffineTransformOp.TYPE_BILINEAR);
BufferedImage rotatedImage = op.createCompatibleDestImage(img, ColorModel.getRGBdefault());
op.filter(img, rotatedImage);
lbIm1.setIcon(new ImageIcon(rotatedImage));
lbIm1.repaint();
Note the icon is changing sizes because the destination image is large enough to hold the whole image. That means the center of the icon will appear to move.
If you create the destination image this way.
BufferedImage rotatedImage = new BufferedImage(img.getWidth(), img.getHeight(), BufferedImage.TYPE_INT_ARGB);
Then the destination will be cropped, but stay the same size. That way the center of the image doesn't appear to move.
The transform you're using, translate + rotate + translate back, work with this technique to. The 1 degree rotation causes some rounding error in the size of the image. So I wonder if that is why the image "runs away"
After rotating an image I have a problem like this. The image is partially cut and not displaying as expected.
Before rotating:
After rotating:
I am using this code for rotation:
AffineTransform tx = new AffineTransform();
tx.rotate(Math.toRadians(61), image.getWidth() / 2, image.getHeight() / 2);
AffineTransformOp op = new AffineTransformOp(
tx, AffineTransformOp.TYPE_BILINEAR);
image = op.filter(image, null);
I think you can use this as your style:
App-logo { animation: App-logo-spin infinite 20s linear;}
I'm using an ImageIcon in order to display an image in a JPanel. I need to implement zoom in / zoom out functions over that image.
If I use the following code it does the zoom out/in work, but the quality of the image reduces significantly due to the transparency.
BufferedImage resizedImage = new BufferedImage(newImageWidth, newImageHeight, BufferedImage.TYPE_INT_ARGB);
Graphics2D g = resizedImage.createGraphics();
g.drawImage(image, 0, 0, newImageWidth , newImageHeight , null);
g.dispose();
return resizedImage;
I have read that this other following code is a solution but it gives me the same result as above.
AffineTransform af = new AffineTransform();
af.scale(zoomLevel, zoomLevel);
AffineTransformOp operation = new AffineTransformOp(af, AffineTransformOp.TYPE_NEAREST_NEIGHBOR);
BufferedImage result = operation.filter((BufferedImage) image, null);
return result;
Any suggestion? Thanks in advance guys.
I am trying to rotate image. I am using this Java code:
BufferedImage oldImage = ImageIO.read(new FileInputStream("C:\\workspace\\test\\src\\10.JPG"));
BufferedImage newImage = new BufferedImage(oldImage.getHeight(), oldImage.getWidth(), oldImage.getType());
Graphics2D graphics = (Graphics2D) newImage.getGraphics();
graphics.rotate(Math.toRadians(90), newImage.getWidth() / 2, newImage.getHeight() / 2);
graphics.drawImage(oldImage, 0, 0, oldImage.getWidth(), oldImage.getHeight(), null);
ImageIO.write(newImage, "JPG", new FileOutputStream("C:\\workspace\\test\\src\\10_.JPG"));
But I see strange result:
Source:
Result:
Can you please help me with this problem?
It is not enough to switch the width and height of the image. You are rotating using the center of the image as the origin of rotation. Just try the same with a sheet of paper and you will see it works the same way. You must also move the paper a little bit, which means to apply a transform to fix this. So, immediately after the rotate call, do this:
graphics.translate((newImage.getWidth() - oldImage.getWidth()) / 2, (newImage.getHeight() - oldImage.getHeight()) / 2);
The new image has different sizes because of the rotate.
try this:
BufferedImage newImage = new BufferedImage( oldImage.getWidth(),oldImage.getHeight(),oldImage.getType());
Try getting bounds of your panel on which you do your drawing
Rectangle rect = this.getBounds();
And then do:
graphics.rotate(Math.toRadians(90), (rect.width - newImage.getWidth()) / 2, (rect.height - newImage.getHeight()) / 2);
Hope that could help
Cheers!
You can write like this it will be work.
BufferedImage newImage = new BufferedImage(oldImage.getWidth(), oldImage.getHeight(), oldImage.getType());
I think the place for width and height is wrong in your code.
I simply want to enable the user of my web site to change the orientation of a submitted photo from horizontal to vertical. Here's my code:
public static final void rotatePhoto(String jpgFilename){
BufferedImage originalImage = null, newImage=null;
try{
File file = new File(jpgFilename);
originalImage = ImageIO.read(file);
System.out.println("Photo.rotatePhoto(" +jpgFilename +") originalImage.getWidth(null)=" +originalImage.getWidth(null) +" originalImage.getHeight(null)=" +originalImage.getHeight(null) );
java.awt.image.AffineTransformOp opRotated = new java.awt.image.AffineTransformOp( java.awt.geom.AffineTransform.getQuadrantRotateInstance(1), null );
newImage = opRotated.createCompatibleDestImage(originalImage, originalImage.getColorModel());
opRotated.filter(originalImage, newImage);
}catch (IOException e){
}
/// Write result to file::::::::::::::::::::::::::::::::::::::::::::::::::::
try{
File outputfile = new File(testFilename);
ImageIO.write(newImage, "jpg", outputfile);
}catch(IOException ioE){
}
}
Problem is I get this error even though the System.out.println shows the width and height to be 640x480
java.awt.image.RasterFormatException: Transformed width (0) is less than or equal to 0.
java.awt.image.AffineTransformOp.createCompatibleDestImage(AffineTransformOp.java:447)
base.Photo.rotatePhoto(Photo.java:135)
base.ProcessContent.handleInput(ProcessContent.java:245)
servlets.ProcessServlet.doPost(ProcessServlet.java:74)
servlets.ProcessServlet.doGet(ProcessServlet.java:33)
javax.servlet.http.HttpServlet.service(HttpServlet.java:617)
javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
Any ideas or workarounds?
Try creating a new AffineTransform from scratch and using it in your AffineTransformOp constructor:
AffineTransform tx = new AffineTransform();
tx.rotate(Math.PI / 2, originalImage.getWidth() / 2, originalImage.getHeight() / 2);
AffineTransformOp op = new AffineTransformOp(tx, AffineTransformOp.TYPE_BILINEAR);
newImage = op.filter(originalImage, newImage);
You also have to make sure newImage contains the data returned by the filter() method.
Oddly enough, this will only work when you set the formatName in ImageIO.write() to "png". I tried using jpg and the result was a black picture.
By using: AffineTransform.getQuadrantRotateInstance(1);
Your AffineTransform is rotating by a positive number of quadrants by axis. That will mess up the Transform Operation since it depends on the x and y, whenever it creates the compatible image.
int w = r.x + r.width;
int h = r.y + r.height;
if (w <= 0) {
throw new RasterFormatException("Transformed width ("+w+
") is less than or equal to 0.");
}
I would recommend doing it yourself:
public final void rotatePhoto(String jpgFilename) throws IOException {
File file = new File(jpgFilename);
BufferedImage originalImage = ImageIO.read(file);
// You could use Math.PI / 2, depends on your input.
AffineTransform affineTransform = new AffineTransform();
affineTransform.rotate(Math.toRadians(90), originalImage.getWidth() / 2, originalImage.getHeight() / 2);
// Now lets make that transform an operation, and we use it.
AffineTransformOp opRotated = new AffineTransformOp(affineTransform, AffineTransformOp.TYPE_BILINEAR);
BufferedImage newImage = opRotated.filter(originalImage, null);
// Save the image.
File outputfile = new File("rotated.jpg");
ImageIO.write(newImage, "jpg", outputfile);
}
UPDATE: Btw, it has been answered before on How do I write a servlet which rotates images?