java - Girar BufferedImage Inside JPanel
swing rotation (2)
No hay mucho para seguir, pero dos cosas vienen a la mente. Es posible que la imagen no se haya renderizado en la posición correcta después de haberla girado y dos, no se deshace del contexto de Graphics
cuando haya terminado con ella (no es que crea que deba tener un efecto, pero nunca saber).
Este es un ejemplo simple que representa el resultado a través de paintComponent
, pero el concepto es el mismo.
Utiliza una AffineTransformation
para rotar la imagen.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
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.JSlider;
import javax.swing.UIManager;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
public class TestRotateImage {
public static void main(String[] args) {
new TestRotateImage();
}
public TestRotateImage() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception ex) {
}
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private JSlider slider;
private BufferedImage image;
public TestPane() {
setLayout(new BorderLayout());
try {
image = ImageIO.read(new File("/path/to/your/image"));
} catch (IOException ex) {
ex.printStackTrace();
}
slider = new JSlider();
slider.setMinimum(0);
slider.setMaximum(360);
slider.setMinorTickSpacing(5);
slider.setMajorTickSpacing(10);
slider.setValue(0);
add(slider, BorderLayout.SOUTH);
slider.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
repaint();
}
});
}
@Override
public Dimension getPreferredSize() {
return image == null ? new Dimension(200, 200) : new Dimension(image.getWidth(), image.getHeight());
}
public double getAngle() {
return Math.toRadians(slider.getValue());
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setColor(Color.RED);
g2d.drawLine(getWidth() / 2, 0, getWidth() / 2, getHeight());
g2d.drawLine(0, getHeight() / 2, getWidth(), getHeight() / 2);
g2d.setColor(Color.BLACK);
int x = (getWidth() - image.getWidth()) / 2;
int y = (getHeight() - image.getHeight()) / 2;
AffineTransform at = new AffineTransform();
at.setToRotation(getAngle(), x + (image.getWidth() / 2), y + (image.getHeight() / 2));
at.translate(x, y);
g2d.setTransform(at);
g2d.drawImage(image, 0, 0, this);
g2d.dispose();
}
}
}
Actualizar usando un JLabel
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics2D;
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.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.UIManager;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
public class TestRotateImage {
public static void main(String[] args) {
new TestRotateImage();
}
public TestRotateImage() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception ex) {
}
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private JSlider slider;
private BufferedImage image;
private JLabel label;
public TestPane() {
setLayout(new BorderLayout());
label = new JLabel();
label.setHorizontalAlignment(JLabel.CENTER);
label.setVerticalAlignment(JLabel.CENTER);
try {
image = ImageIO.read(new File("/path/to/your/image"));
label.setIcon(new ImageIcon(image));
} catch (IOException ex) {
ex.printStackTrace();
}
add(label);
slider = new JSlider();
slider.setMinimum(0);
slider.setMaximum(360);
slider.setMinorTickSpacing(5);
slider.setMajorTickSpacing(10);
slider.setValue(0);
add(slider, BorderLayout.SOUTH);
slider.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
double radians = Math.toRadians(slider.getValue());
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);
BufferedImage rotate = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = rotate.createGraphics();
int x = (newWidth - image.getWidth()) / 2;
int y = (newHeight - image.getHeight()) / 2;
AffineTransform at = new AffineTransform();
at.setToRotation(getAngle(), x + (image.getWidth() / 2), y + (image.getHeight() / 2));
at.translate(x, y);
g2d.setTransform(at);
g2d.drawImage(image, 0, 0, TestPane.this);
g2d.dispose();
label.setIcon(new ImageIcon(rotate));
}
});
}
@Override
public Dimension getPreferredSize() {
return image == null ? new Dimension(200, 200) : new Dimension(image.getWidth(), image.getHeight());
}
public double getAngle() {
return Math.toRadians(slider.getValue());
}
}
}
Estoy tratando de rotar una BufferedImage
y mostrarla dentro de un JLabel
(que está dentro de un JPanel
). El resultado actual produce un cuadrado blanco girado 10 grados sobre un fondo negro, pero la imagen no está presente dentro del cuadrado. Sé que myPicture
no está en blanco, ya que myPicture
se muestra correctamente dentro del JPanel
cuando no se gira.
Aquí está el código:
int w = myPicture.getWidth();
int h = myPicture.getHeight();
BufferedImage newImage = new BufferedImage(w, h, myPicture.getType());
Graphics2D graphic = newImage.createGraphics();
graphic.rotate(Math.toRadians(10), w/2, h/2);
graphic.drawImage(myPicture, null, 0, 0);
picLabel.setIcon(new ImageIcon(newImage));
Resolví mi propio problema. El problema radica en el código:
myPicture.getType()
Dado que hay una gran variabilidad en los tipos de imágenes que puede poner en el programa, los resultados serán impredecibles cuando comience a dibujar en la nueva Imagen Buffered. Resolví el problema estableciendo el tipo explícitamente, que en mi caso requería
BufferedImage.TYPE_INT_ARGB
entonces la declaración completa decía:
BufferedImage newImage = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);