在JPanel中旋转BufferedImage

我想旋转一个BufferedImage并将其显示在一个JLabel (这是一个JPanel )。 目前的结果产生一个黑色背景旋转10度的白色方形,但图像不存在于广场内。 我知道myPicture不是空白的,因为当不旋转的时候, myPicture本身在JPanel内部正确显示。

这里是代码:

 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)); 

还有很多事情要做,但是有两点让我们想起来。 有可能在旋转图像后,图像没有被正确渲染,而当你完成后, Graphics上下文不会被处理(不是我相信它应该有效果,但是你永远不会知道)。

这是一个简单的例子,通过paintComponent呈现结果,但概念是相同的。

它使用AffineTransformation旋转图像。

在这里输入图像描述

 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(); } } } 

使用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()); } } } 

我解决了我自己的问题。 问题出在代码中:

 myPicture.getType() 

由于图像types的变化很大,所以在开始绘制新的BufferedImage时,结果将变得不可预知。 我通过明确地设置types来解决问题,这在我的情况下是必需的

 BufferedImage.TYPE_INT_ARGB 

所以完整的陈述如下:

 BufferedImage newImage = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);