【问题标题】:Rotate a buffered image in Java在 Java 中旋转缓冲图像
【发布时间】:2016-10-12 00:01:59
【问题描述】:

我正在尝试在 java 中旋转缓冲图像。这是我正在使用的代码:

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

我查看了有关此主题的大量堆栈溢出问题和答案,但无法弄清楚为什么图像会像我尝试旋转它时那样被切碎。这是一个显示加载图像的示例: loaded image

单击旋转按钮后,该按钮使用缓冲图像调用上述函数,角度为 90.0: chopped up image

有人可以帮助我了解正在发生的事情以及如何解决它吗?

【问题讨论】:

    标签: java rotation bufferedimage graphics2d image-rotation


    【解决方案1】:

    与往常一样,互联网来救援。所以,这是我从其他资源/帖子/博客中蹒跚而行的一些代码,它将返回一个新图像,该图像的大小将包含旋转后的图像

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

    更新

    所以,使用这个 PNG:

    还有这段代码……

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

    我可以生成类似...

    【讨论】:

    • 奇怪的是,我正在使用的图像不会旋转并锁定我的程序。这些图像是通过将二进制文件中的值转换为灰度来创建的,然后存储在缓冲图像中。我尝试了一个保存到 PNG 的文件,但它也无法旋转。唯一会旋转的图像是从 JPEG 格式加载的图像。有什么想法吗?
    • 所以,我使用基于 PNG 的图像重新测试了代码,它对我来说效果很好。我建议您考虑提出一个新问题并提供一个可运行的示例来演示您的问题,因为从我的角度来看,它似乎与您使用代码的“方式”更相关
    • @MadProgrammer Fair 无处不在。我也想知道为什么,但我的想法是,如果你知道是谁,你就能找出原因。啊,但是.... c`est la vie.
    • @GitPhilter 你看到g2d.setTransform(at);这行了吗?这是对 Graphics 上下文应用一个转换,它定义了旋转逻辑
    • @GitPhilter 好的,所以rotateImageByDegrees 正在获取原始图像并将其旋转一定度数。这会生成一个新的BufferedImagepaintComponent 只是将旋转后的图像绘制到屏幕上,因此您可以看到结果。因此,您可以使用 rotateImageByDegrees 并旋转图像,我不知道,保存它或做任何您想做的事情 - 或者,如果您愿意,就像示例一样,为它制作动画
    【解决方案2】:

    您会得到混乱的图像结果,因为您将旋转后的图像绘制到输入图像本身。相反,您需要从新的 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;
    }
    

    请注意,如果您想避免出现裁剪角,则需要调整输出 BufferedImage 的宽度和高度。

    【讨论】:

      【解决方案3】:

      此代码从文件中读取图像,将其旋转一定角度,然后写入另一个文件。它适用于具有透明度的 png 图像:

      public static void main(String[] args) throws IOException {
          BufferedImage image = ImageIO.read(
                  Test.class.getResourceAsStream("/resources/image.png"));
      
          BufferedImage rotated = rotateImage(image, 45);
      
          ImageIO.write(rotated, "png",
                  new FileOutputStream("resources/rotated.png"));
      }
      
      private static BufferedImage rotateImage(BufferedImage buffImage, double angle) {
          double radian = Math.toRadians(angle);
          double sin = Math.abs(Math.sin(radian));
          double cos = Math.abs(Math.cos(radian));
      
          int width = buffImage.getWidth();
          int height = buffImage.getHeight();
      
          int nWidth = (int) Math.floor((double) width * cos + (double) height * sin);
          int nHeight = (int) Math.floor((double) height * cos + (double) width * sin);
      
          BufferedImage rotatedImage = new BufferedImage(
                  nWidth, nHeight, BufferedImage.TYPE_INT_ARGB);
      
          Graphics2D graphics = rotatedImage.createGraphics();
      
          graphics.setRenderingHint(
                  RenderingHints.KEY_INTERPOLATION,
                  RenderingHints.VALUE_INTERPOLATION_BICUBIC);
      
          graphics.translate((nWidth - width) / 2, (nHeight - height) / 2);
          // rotation around the center point
          graphics.rotate(radian, (double) (width / 2), (double) (height / 2));
          graphics.drawImage(buffImage, 0, 0, null);
          graphics.dispose();
      
          return rotatedImage;
      }
      
      image.png rotated.png (45º) ⟳ rotated.png (-45º) ⟲

      【讨论】:

        【解决方案4】:

        您必须考虑调整大小以及输出的新宽度和高度。见:https://stackoverflow.com/a/4787898/5420880

        【讨论】:

        • 我不确定 GraphicsConfiguration gc = getDefaultConfiguration();作品。我用谷歌搜索,发现你需要 GraphicsEnvironment,然后是 GraphicsDevice。不知道如何使用它。我复制了推荐链接中的函数,它会导致错误。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-07-06
        • 1970-01-01
        • 1970-01-01
        • 2013-02-25
        相关资源
        最近更新 更多