Java 使用 AffineTransform 旋转图像
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/20275424/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Rotating Image with AffineTransform
提问by fa1thly
I have got class called Airplane
. Inside this class i have got variable img
which is a BufferedImage
type. What is more i have got class WorldMap
which overrides function paintComponent(Graphics g)
:
我有一个名为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);
}
Function drawAirplanes()
look like this:
函数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);
}
}
It simply need to 1) rotate airplane (BufferedImage inside Airplane object) 2) draw him.
它只需要1)旋转飞机(飞机对象内的BufferedImage)2)绘制他。
My Airplane.rotateAirplane() function looks like this:
我的 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 when im running my program only mapa
object is drawn. when im deleting this lane
ofc 当我运行我的程序时,只mapa
绘制对象。当我删除这条车道时
this.img = newImage;
this.img = newImage;
i have got ofc my airplane too but not rotated.
我也有我的飞机,但没有旋转。
采纳答案by MadProgrammer
The major problem (that I can see) is the translation of the Graphics
context which is offset the position that the rotation will take place.
主要问题(我可以看到)是Graphics
上下文的平移,它抵消了旋转将发生的位置。
I "think" rotation by default occurs at the top/left corner of the Graphics
context (where it's 0x0 position is, which you've translated to something else), this could be causing the image to be rotated out of frame (or viewable area)
我“认为”旋转默认发生在Graphics
上下文的上/左角(它是 0x0 位置,您已将其转换为其他位置),这可能会导致图像旋转出框架(或可见区域) )
You should provide a "anchor" point where the rotation takes place, typically, the centre is my personal preference.
您应该提供旋转发生的“锚”点,通常,中心是我个人的喜好。
The following example simply has a master image (due to size constraints I had to scale it, but you may not need this). I then use this to generate a "rotated" instance which is sized to allow the image to fit within in. This is a lot of fun with trig - I stole the code from somewhere, so credit to that developer.
下面的示例只有一个主图像(由于尺寸限制,我不得不对其进行缩放,但您可能不需要它)。然后我使用它来生成一个“旋转”实例,该实例的大小允许图像适合其中。trig 很有趣 - 我从某个地方窃取了代码,因此归功于该开发人员。
The example allows you to click any where and it will change the rotation pivot, so you can see what's going on. The default position is the centre of the pane...
该示例允许您单击任何位置,它将更改旋转轴心,因此您可以看到发生了什么。默认位置是窗格的中心...
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();
}
}
}
}
回答by Atreide
This is what worked for me (kinda copying from here and there):
这对我有用(有点从这里和那里复制):
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()); //20, 20 is a height and width of imag ofc
op.filter(imag, newImage);
//this.img = newImage;
return(newImage);
}