Проблемы с вращением BufferedImage
У меня есть некоторые проблемы с вращением изображений в Java с использованием класса AffineTransform.
У меня есть следующий метод для создания повернутой (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, по часовой стрелке и против часовой стрелки.
симптомы моих проблем отображаются здесь:
http://perp.se/so/rotate_problems.html
Итак, вращение работает нормально, но результирующие изображения не привязаны к правильным координатам (или, как следует выразиться). И поскольку я действительно не знаю, что, черт возьми, я делаю в первую очередь (моя линейная алгебра слаба), я не знаю, как решить это самостоятельно.
Я попытался с некоторой случайной возней с экземпляром AffineTransform, но это не помогло мне (конечно). Я пробовал гуглить (и искать так), но все примеры, которые я видел, в основном используют тот же подход, что и я... что не работает для мне.
благодарен за советы.
4 ответов
если вы должны выразить преобразование как одно вращение, точка привязки зависит от направления вращения: либо (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
.
поскольку вам нужно только вращение на 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;
}
Это также позволяет избежать обрезки краев прямоугольных изображений.
вы можете попробовать альтернативный appoach и создать значок из изображения, а затем использовать Повернуть Значок.
или вы можете попробовать этот старый код, который я нашел на форумах 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);
}
}
Я не знаю, Может ли это быть вашей проблемой.
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);