使用 AffineTransform 旋转图像

问题描述 投票:0回答:4

我有一个名为

Airplane
的课程。在这个类中,我有变量
img
,它是
BufferedImage
类型。更重要的是,我有类
WorldMap
,它覆盖了函数
paintComponent(Graphics g)
:

@Override
public void paintComponent(Graphics g) {
    Graphics2D g2d = (Graphics2D) g;
    g2d.drawImage(mapa, 0, 0, getWidth(), getHeight(), null); 
    drawAirplanes(g2d);
}

功能

drawAirplanes()
看起来像这样:

private void drawAirplane(Graphics2D g){
    for(Samolot i: s){
        i.rotateAirplane();
        g.drawImage(i.getImg(),i.getX(),i.getY(),(int)i.getDim().getWidth(),(int)i.getDim().getHeight(),  null);
    }
}

它只需要1)旋转飞机(飞机对象内的BufferedImage)2)画他。

我的 Airplane.rotateAirplane() 函数如下所示:

 public void rotateSamolot() {
   AffineTransform tx = new AffineTransform();

   tx.translate(10,10); //10, 10 is height and width of img divide by 2
   tx.rotate(Math.PI / 2);
   tx.translate(-10,-10); 

   AffineTransformOp op = new AffineTransformOp(tx, AffineTransformOp.TYPE_BILINEAR);

   BufferedImage newImage =new BufferedImage(20, 20, img.getType()); //20, 20 is a height and width of img ofc
   op.filter(img, newImage);

       this.img = newImage;
 }

ofc 当我运行我的程序时,仅绘制

mapa
对象。当我删除这条车道时

this.img = newImage;

我也起飞了我的飞机,但没有旋转。

java swing graphics2d image-rotation affinetransform
4个回答
14
投票

(我可以看到)主要问题是

Graphics
上下文的平移,它偏移了旋转将发生的位置。

我“认为”旋转默认发生在

Graphics
上下文的左上角(0x0 位置,您已将其转换为其他位置),这可能会导致图像旋转到框架之外(或可视区域)

您应该提供一个发生旋转的“锚点”,通常,中心是我个人的偏好。

以下示例只有一个主图像(由于尺寸限制,我必须对其进行缩放,但您可能不需要这个)。然后我用它来生成一个“旋转”实例,其大小适合图像的大小。这对于 trig 来说很有趣 - 我从某个地方偷了代码,所以归功于该开发人员。

该示例允许您单击任意位置,它将更改旋转轴,因此您可以看到发生了什么。默认位置是窗格的中心...

Spinning

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.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
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.JSlider;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

public class SampleRotation {

    public static void main(String[] args) {
        new SampleRotation();
    }

    public SampleRotation() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                final RotationPane rotationPane = new RotationPane();
                final JSlider slider = new JSlider(0, 100);
                slider.addChangeListener(new ChangeListener() {
                    @Override
                    public void stateChanged(ChangeEvent e) {
                        double angle = 720d * (slider.getValue() / 100d);
                        rotationPane.setAngle(angle);
                    }
                });
                slider.setValue(0);

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(rotationPane);
                frame.add(slider, BorderLayout.SOUTH);
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class RotationPane extends JPanel {

        private BufferedImage img;
        private BufferedImage rotated;
        private double angle;
        private Point clickPoint;

        public RotationPane() {
            try {
                img = ImageIO.read(new File("/Users/swhitehead/Dropbox/MegaTokyo/issue459.jpg"));
                BufferedImage scaled = new BufferedImage(img.getWidth() / 2, img.getHeight() / 2, BufferedImage.TYPE_INT_ARGB);
                Graphics2D g2d = scaled.createGraphics();
                g2d.setTransform(AffineTransform.getScaleInstance(0.5d, 0.5d));
                g2d.drawImage(img, 0, 0, this);
                g2d.dispose();
                img = scaled;
                setAngle(0d);
            } catch (IOException ex) {
                ex.printStackTrace();
            }

            addMouseListener(new MouseAdapter() {

                @Override
                public void mouseClicked(MouseEvent e) {
                    clickPoint = e.getPoint();
                    repaint();
                }

            });

        }

        public void setAngle(double angle) {
            this.angle = angle;

            double rads = Math.toRadians(getAngle());
            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);

            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 = clickPoint == null ? w / 2 : clickPoint.x;
            int y = clickPoint == null ? h / 2 : clickPoint.y;

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

            repaint();
        }

        public double getAngle() {
            return angle;
        }

        @Override
        public Dimension getPreferredSize() {
            return img == null ? new Dimension(200, 200) : new Dimension(img.getWidth(this), img.getHeight(this));
        }

        @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.setColor(Color.RED);

                x = clickPoint == null ? getWidth() / 2 : clickPoint.x;
                y = clickPoint == null ? getHeight()/ 2 : clickPoint.y;

                x -= 5;
                y -= 5;

                g2d.drawOval(x, y, 10, 10);
                g2d.dispose();
            }
        }        
    }    
}

1
投票

这对我有用(有点从这里和那里复制):

public BufferedImage rotateImag (BufferedImage imag, int n) { //n rotation in gradians

        double rotationRequired = Math.toRadians (n);
        double locationX = imag.getWidth() / 2;
        double locationY = imag.getHeight() / 2;
        AffineTransform tx = AffineTransform.getRotateInstance(rotationRequired, locationX, locationY);
        AffineTransformOp op = new AffineTransformOp(tx, AffineTransformOp.TYPE_BILINEAR);         
       BufferedImage newImage =new BufferedImage(imag.getWidth(), imag.getHeight(), imag.getType()); 
       op.filter(imag, newImage);

           //this.img = newImage;
       return(newImage);
     }

0
投票

当您已经完成旋转时,您无法简单地平移回来。你可以做的是:通过 Graphics g2 = g.create() 创建一个新的 Graphics 对象,对 g2 进行平移/旋转,然后将 g2 扔掉。这样就不会影响原来的Graphics g状态。


0
投票

我尝试使用@Atreide的答案。当我旋转图像时,图像被剪裁了。

我需要一种旋转图像的方法,这样无论旋转角度如何,整个图像都是可见的。

这是我的意思的一个例子。

三角形已旋转 57.3 度或 1 弧度。

我需要做的是将三角形图像复制到足够大的图像以容纳任何旋转角度的图像。然后我可以在其中心点旋转复制的图像。

这是我使用的代码。我正在以中心点旋转三角形。

/**
 * <p>
 * This method will rotate an image.
 * </p>
 * <p>
 * First, the image is copied to an image large enough to hold the rotated
 * image at any angle. Then, the copied image is rotated.
 * </p>
 * 
 * @param image    - The image to be rotated.
 * @param rotation - The rotation angle in radians. A positive value rotates
 *                 the image clockwise. A negative value rotates the image
 *                 counterclockwise.
 * @return The rotated image
 */
public BufferedImage rotateImage(BufferedImage image, double rotation) {
    double newWidthD = getNewImageWidth(image);
    double halfWidthD = newWidthD / 2.0;
    int newWidthI = (int) newWidthD;

    BufferedImage newImage = translateImage(image, newWidthI);
    BufferedImage outputImage = new BufferedImage(newWidthI, newWidthI,
            image.getType());
    AffineTransform tx = AffineTransform.getRotateInstance(rotation,
            halfWidthD, halfWidthD);
    AffineTransformOp op = new AffineTransformOp(tx,
            AffineTransformOp.TYPE_BILINEAR);
    op.filter(newImage, outputImage);

    return (outputImage);
}

/**
 * This method calculates the width of the new image. Basically, calculate
 * the hypotenuse of the width and height of the image.
 * 
 * @param image - The original image
 * @return The width and height of the square that can hold the image
 *         rotated at any angle.
 */
private double getNewImageWidth(BufferedImage image) {
    int width = image.getWidth();
    int height = image.getHeight();

    double newWidth = width * width + height * height;
    newWidth = Math.ceil(Math.pow(newWidth, 0.5));

    return newWidth;
}

/**
 * This method copies the image to a new image. The original image is placed
 * in the center of the new image. The rest of the image is filled with
 * transparent pixels.
 * 
 * @param image - The original image.
 * @param newWidth - the width and height of the new image.
 * @return The translated image
 */
private BufferedImage translateImage(BufferedImage image, int newWidth) {
    BufferedImage newImage = new BufferedImage(newWidth, newWidth,
            BufferedImage.TYPE_INT_ARGB);
    Graphics2D g2d = (Graphics2D) newImage.getGraphics();
    g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
            RenderingHints.VALUE_ANTIALIAS_ON);
    g2d.setColor(new Color(0, 0, 0, 0));
    g2d.fillRect(0, 0, newWidth, newWidth);
    int x = (newWidth - image.getWidth()) / 2;
    int y = (newWidth - image.getHeight()) / 2;
    g2d.drawImage(image, x, y, this);
    g2d.dispose();

    return newImage;
}
© www.soinside.com 2019 - 2024. All rights reserved.