【问题标题】:Problems rotating BufferedImage旋转 BufferedImage 的问题
【发布时间】:2010-02-13 10:07:47
【问题描述】:

我在使用 AffineTransform 类在 Java 中旋转图像时遇到了一些问题。

我有以下方法来创建图像的旋转(90 度)副本:

private BufferedImage createRotatedCopy(BufferedImage img, Rotation rotation) {
    int w = img.getWidth();
    int h = img.getHeight();

    BufferedImage rot = new BufferedImage(h, w, BufferedImage.TYPE_INT_RGB);

    double theta;
    switch (rotation) {
        case CLOCKWISE:
            theta = Math.PI / 2;
            break;
        case COUNTERCLOCKWISE:
            theta = -Math.PI / 2;
            break;
        default:
            throw new AssertionError();
    }

    AffineTransform xform = AffineTransform.getRotateInstance(theta, w / 2, h / 2);
    Graphics2D g = (Graphics2D) rot.createGraphics();
    g.drawImage(img, xform, null);
    g.dispose();

    return rot;
}

Rotation 是一个简单的枚举,其值为 NONE、CLOCKWISE 和 COUNTERCLOCKWISE。

这里显示了我的问题的症状:

http://perp.se/so/rotate_problems.html

所以,旋转工作正常,但生成的图像没有锚定到正确的坐标(或者应该如何放置)。而且由于我一开始并不真正知道自己在做什么(我的线性代数很弱),所以我不知道如何自己解决这个问题。

我尝试过随机摆弄 AffineTransform 实例,但它并没有帮助我(当然)。我试过谷歌搜索(和搜索 SO),但我看到的所有示例基本上都使用与我相同的方法......这对我不起作用。

感谢您的建议。

【问题讨论】:

标签: java image rotation affinetransform


【解决方案1】:

如果必须将变换表示为单次旋转,则锚点取决于旋转方向:(w/2, w/2)(h/2, h/2)

但用translate; rotate; translate 表示可能更简单,例如

AffineTransform xform = new AffineTransform();
xform.translate(0.5*h, 0.5*w);
xform.rotate(theta);
xform.translate(-0.5*w, -0.5*h);

还可以考虑使用getQuadrantRotateInstance 而不是getRotateInstance

【讨论】:

  • 我明白你在说什么,我也试过了。然而,问题仍然存在。它们仍然被绘制在目标区域的“外部”,尽管可以说是在水平的“另一侧”。如果不清楚我的意思,我可以提供更多截图。
  • @perp,你是对的,已修复。我已经测试了新版本,它可以工作。
  • 像魅力一样工作!我想我也对现在发生的事情有了更好的了解。谢谢!
  • 如果可以帮助任何人:应用此解决方案后,我的图像仍然被部分裁剪,但仅在一个轴上。问题不在于变换,而是由于我使用了错误的图像类型。所以也考虑一下:)
【解决方案2】:

由于您只需要 90 度旋转,您可以避免使用 AffineTransform 的东西:

public BufferedImage rotate90DX(BufferedImage bi) {
    int width = bi.getWidth();
    int height = bi.getHeight();
    BufferedImage biFlip = new BufferedImage(height, width, bi.getType());
    for(int i=0; i<width; i++)
        for(int j=0; j<height; j++)
            biFlip.setRGB(height-1-j, width-1-i, bi.getRGB(i, j));
    return biFlip;
}

这也避免了切割矩形图像的边缘。

发件人:http://snippets.dzone.com/posts/show/2936

【讨论】:

  • 请注意,强制直接访问 RGB 像素值会将图像从 Java2D 中的加速管道中取出。这种方法可能会给您想要的结果,但速度要慢得多。
  • 啊哈。不知道那个。谢谢
  • 我测试了这段代码,它不仅可以旋转图像,还可以左右改变(就像在镜子里一样)
【解决方案3】:

您可以尝试另一种方法并从图像创建一个图标,然后使用Rotated Icon

或者你可以试试我在 Sun 论坛上找到的旧代码:

import java.awt.*;
import java.awt.geom.*;
import java.awt.image.*;
import java.io.*;
import java.net.*;
import javax.imageio.*;
import javax.swing.*;

public class RotateImage {
    public static void main(String[] args) throws IOException {
        URL url = new URL("https://blogs.oracle.com/jag/resource/JagHeadshot-small.jpg");
        BufferedImage original = ImageIO.read(url);
        GraphicsConfiguration gc = getDefaultConfiguration();
        BufferedImage rotated1 = tilt(original, -Math.PI/2, gc);
        BufferedImage rotated2 = tilt(original, +Math.PI/4, gc);
        BufferedImage rotated3 = tilt(original, Math.PI, gc);
        display(original, rotated1, rotated2, rotated3);
    }

    public static BufferedImage tilt(BufferedImage image, double angle, GraphicsConfiguration gc) {
        double sin = Math.abs(Math.sin(angle)), cos = Math.abs(Math.cos(angle));
        int w = image.getWidth(), h = image.getHeight();
        int neww = (int)Math.floor(w*cos+h*sin), newh = (int)Math.floor(h*cos+w*sin);
        int transparency = image.getColorModel().getTransparency();
        BufferedImage result = gc.createCompatibleImage(neww, newh, transparency);
        Graphics2D g = result.createGraphics();
        g.translate((neww-w)/2, (newh-h)/2);
        g.rotate(angle, w/2, h/2);
        g.drawRenderedImage(image, null);
        return result;
    }

    public static GraphicsConfiguration getDefaultConfiguration() {
        GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
        GraphicsDevice gd = ge.getDefaultScreenDevice();
        return gd.getDefaultConfiguration();
    }

    public static void display(BufferedImage im1, BufferedImage im2, BufferedImage im3, BufferedImage im4) {
        JPanel cp = new JPanel(new GridLayout(2,2));
        addImage(cp, im1, "original");
        addImage(cp, im2, "rotate -PI/2");
        addImage(cp, im3, "rotate +PI/4");
        addImage(cp, im4, "rotate PI");

        JFrame f = new JFrame("RotateImage");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setContentPane(cp);
        f.pack();
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    }

    static void addImage(Container cp, BufferedImage im, String title) {
        JLabel lbl = new JLabel(new ImageIcon(im));
        lbl.setBorder(BorderFactory.createTitledBorder(title));
        cp.add(lbl);
    }
}

【讨论】:

    【解决方案4】:

    我不知道这是否是你的问题。

    AffineTransform xform = AffineTransform.getRotateInstance(theta, w / 2, h / 2);
    

    为什么不试试呢?

    AffineTransform xform = AffineTransform.getRotateInstance(theta);
    

    g.transform(AffineTransform.getRotateInstance(theta));
    g.drawImage(img, 0, 0, w/2, h/2, null, null);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-07-13
      • 1970-01-01
      • 2014-01-23
      • 2017-03-25
      相关资源
      最近更新 更多