【问题标题】:java rotating bufferedimages fastjava快速旋转缓冲图像
【发布时间】:2015-08-18 20:05:17
【问题描述】:

我开发了一个游戏,旋转图像目前大部分时间都花在了计算一帧的过程中。为了优化,我正在寻找旋转缓冲图像的最快方法。我已经尝试了下面显示的两种方法。

最慢的方法:

public static BufferedImage rotate(BufferedImage imgOld, int deg){                                               //Parameter for this method are the picture to rotate and the rotation in degrees

     AffineTransform at = AffineTransform.getRotateInstance(Math.toRadians(deg), (int)(imgOld.getWidth()/2), (int)(imgOld.getHeight()/2));       //initialize and configure transformation
     BufferedImage imgNew = new BufferedImage(imgOld.getWidth(), imgOld.getHeight(), imgOld.getType());                                          //create new bufferedimage with the properties of the image to rotate
     Graphics2D g = (Graphics2D) imgNew.getGraphics();                                                                                           //create Graphics
     g.setTransform(at);                                                                                                                         //apply transformation
     g.drawImage(imgOld, 0, 0, null);                                                                                                            //draw rotated image                       
     g.dispose();
     imgOld.flush();
     return imgNew;
}   

稍微快一点的方法:

 public static BufferedImage rotate(BufferedImage imgOld, int deg){                                                 //parameter same as method above                                                                

        BufferedImage imgNew = new BufferedImage(imgOld.getWidth(), imgOld.getHeight(), imgOld.getType());              //create new buffered image                
        Graphics2D g = (Graphics2D) imgNew.getGraphics();                                                               //create new graphics 
        g.rotate(QaDMath.toRadians(deg), imgOld.getWidth()/2, imgOld.getHeight()/2);                                    //configure rotation
        g.drawImage(imgOld, 0, 0, null);                                                                                //draw rotated image
        return imgNew;                                                                                                  //return rotated image                  
    }       

}

我发现了许多与旋转图像相关的主题,但没有一个讨论最快、最多的解决方案。 我希望我没有错过任何主题,这不是重复的。

希望有比我更熟练的人知道解决方案

【问题讨论】:

  • 您需要在运行时旋转它们吗?您是否可以提前生成您需要的旋转图像,然后只使用旋转适当数量的版本?
  • 我也想过这个选项,但担心几千张图片对于java使用的内存来说太多了

标签: java image optimization rotation bufferedimage


【解决方案1】:

我猜问题的一部分是您不断创建新的 BufferedImages 来进行旋转。这会导致您进行两次绘画,一次是在 BufferedImage 上绘画,第二次是在框架上绘画 BufferedImage。

您可以尝试仅绘制旋转的现有 BufferedImage。例如,您可以使用Rotated Icon,然后使用

绘制图标
rotated.paintIcon(...);

每当您需要旋转您刚刚使用的图像时:

rotated.setDegrees(...);

简单示例:

import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.event.*;

public class Rotation3 extends JPanel
{
    private Icon icon;
    private RotatedIcon rotated;
    private int degrees;

    public Rotation3(Image image)
    {
        icon = new ImageIcon( image );
        rotated = new RotatedIcon(icon, 0);
        rotated.setCircularIcon( true );
        setDegrees( 0 );
        setPreferredSize( new Dimension(600, 600) );
    }

    @Override
    protected void paintComponent(Graphics g)
    {
        super.paintComponent(g);

        double radians = Math.toRadians( degrees );

        // translate x/y so Icon rotated around a specific point (300, 300)

        int x = 300 - (rotated.getIconWidth() / 2);
        int y = 300 - (rotated.getIconHeight() / 2);
        rotated.paintIcon(this, g, x, y);

        g.setColor(Color.RED);
        g.fillOval(295, 295, 10, 10);
    }

    public void setDegrees(int degrees)
    {
        this.degrees = degrees;
        rotated.setDegrees(degrees);
        repaint();
    }

    public static void main(String[] args)
    {
        EventQueue.invokeLater(new Runnable()
        {
            public void run()
            {
                try
                {
                    String path = "dukewavered.gif";
                    ClassLoader cl = Rotation3.class.getClassLoader();
                    BufferedImage bi = ImageIO.read(cl.getResourceAsStream(path));
                    final Rotation3 r = new Rotation3(bi);

                    final JSlider slider = new JSlider(JSlider.HORIZONTAL, 0, 360, 0);
                    slider.addChangeListener(new ChangeListener()
                    {
                        public void stateChanged(ChangeEvent e)
                        {
                            int value = slider.getValue();
                            r.setDegrees( value );
                        }
                    });

                    JFrame f = new JFrame();
                    f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                    f.add(new JScrollPane(r));
                    f.add(slider, BorderLayout.SOUTH);
                    f.pack();
                    f.setLocationRelativeTo(null);
                    f.setVisible(true);
                }
                catch(IOException e)
                {
                    System.out.println(e);
                }
            }
        });
    }
}

只需拖动滑块即可查看旋转。

【讨论】:

  • 似乎是个好主意,但我的编译器的 RotatedIcon 有问题。你也写了这门课还是我错过了一个图书馆?
  • @ManuelPrinz 我真的不认为你需要使用RotatedIcon。使用这种方法的性能提升来自于仅绘制旋转到屏幕的图像,而不是创建图像的旋转版本(包括内存分配等),然后绘制旋转后的图像。
  • 我肯定会尝试这个建议,但在整个游戏中实施它并测试帧速率需要几天时间,但我会再次回复它的效果如何。感谢您的提示。
  • @ManuelPrinz, Did you write this class - 是的,这就是我提供课程链接的原因。
  • I don't really think you need to use the RotatedIcon. - 正确。该类的重点是具有可重用的代码和一个简单的 API,您可以在任何可以使用图标的地方使用它,而无需重新创建自定义绘画。
猜你喜欢
  • 2016-10-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多