我这里有一个尺寸为2156x1728的黑/白png文件,我希望使用AffineTransform旋转90度。生成的图像没有正确的比例。这里有一些示例代码(假设我已成功将png文件加载到BufferedImage中):
public BufferedImage transform(BufferedImage image){
System.out.println("Input width: "+ image.getWidth());
System.out.println("Input height: "+ image.getHeight());
AffineTransform affineTransform = new AffineTransform();
affineTransform.setToQuadrantRotation(1, image.getWidth() / 2, image.getHeight() / 2);
AffineTransformOp opRotated = new AffineTransformOp(affineTransform, AffineTransformOp.TYPE_BILINEAR);
BufferedImage transformedImage = opRotated.createCompatibleDestImage(image, image.getColorModel());
System.out.println("Resulting width: "+ transformedImage.getWidth());
System.out.println("Resulting height: "+ transformedImage.getHeight());
transformedImage = opRotated.filter(image, transformedImage);
return transformedImage;
}
输出相应:
输入宽度:2156
输入高度:1728
结果宽度:1942
结果身高:1942年
旋转如何返回完全不相关的尺寸?
答案 0 :(得分:6)
我不是这方面的专家,但为什么不创建一个正确大小的BufferedImage?另请注意,您的旋转中心不正确。您将需要在[w / 2,w / 2]或[h / 2,h / 2]的中心上旋转(宽度为w,高度为h),具体取决于您要旋转的象限,1或3 ,以及图像的相对高度和宽度。例如:
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
public class RotateImage {
public static final String IMAGE_PATH = "http://duke.kenai.com/"
+ "models/Duke3DprogressionSmall.jpg";
public static void main(String[] args) {
try {
URL imageUrl = new URL(IMAGE_PATH);
BufferedImage img0 = ImageIO.read(imageUrl);
ImageIcon icon0 = new ImageIcon(img0);
int numquadrants = 1;
BufferedImage img1 = transform(img0, numquadrants );
ImageIcon icon1 = new ImageIcon(img1);
JOptionPane.showMessageDialog(null, new JLabel(icon0));
JOptionPane.showMessageDialog(null, new JLabel(icon1));
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public static BufferedImage transform(BufferedImage image, int numquadrants) {
int w0 = image.getWidth();
int h0 = image.getHeight();
int w1 = w0;
int h1 = h0;
int centerX = w0 / 2;
int centerY = h0 / 2;
if (numquadrants % 2 == 1) {
w1 = h0;
h1 = w0;
}
if (numquadrants % 4 == 1) {
if (w0 > h0) {
centerX = h0 / 2;
centerY = h0 / 2;
} else if (h0 > w0) {
centerX = w0 / 2;
centerY = w0 / 2;
}
// if h0 == w0, then use default
} else if (numquadrants % 4 == 3) {
if (w0 > h0) {
centerX = w0 / 2;
centerY = w0 / 2;
} else if (h0 > w0) {
centerX = h0 / 2;
centerY = h0 / 2;
}
// if h0 == w0, then use default
}
AffineTransform affineTransform = new AffineTransform();
affineTransform.setToQuadrantRotation(numquadrants, centerX, centerY);
AffineTransformOp opRotated = new AffineTransformOp(affineTransform,
AffineTransformOp.TYPE_BILINEAR);
BufferedImage transformedImage = new BufferedImage(w1, h1,
image.getType());
transformedImage = opRotated.filter(image, transformedImage);
return transformedImage;
}
}
编辑1
你问:
你能解释一下为什么它必须是[w / 2,w / 2]或[h / 2,h / 2]吗?
为了解释这一点,最好对矩形进行可视化和物理操作:
切出一张长方形纸,将其放在一张纸上,使其左上角位于纸张的左上角 - 这就是您在屏幕上的图像。现在检查一下你需要旋转那个矩形1或3个象限的位置,使它的新左上角覆盖在纸张的上方,你就会明白为什么需要使用[w / 2,w / 2]或[h / 2,h / 2]。
答案 1 :(得分:4)
上述解决方案存在宽度问题;图像的高度 以下代码独立于w> h || h>瓦特
public static BufferedImage rotateImage(BufferedImage image, int quadrants) {
int w0 = image.getWidth();
int h0 = image.getHeight();
int w1 = w0;
int h1 = h0;
int centerX = w0 / 2;
int centerY = h0 / 2;
if (quadrants % 2 == 1) {
w1 = h0;
h1 = w0;
}
if (quadrants % 4 == 1) {
centerX = h0 / 2;
centerY = h0 / 2;
} else if (quadrants % 4 == 3) {
centerX = w0 / 2;
centerY = w0 / 2;
}
AffineTransform affineTransform = new AffineTransform();
affineTransform.setToQuadrantRotation(quadrants, centerX, centerY);
AffineTransformOp opRotated = new AffineTransformOp(affineTransform,
AffineTransformOp.TYPE_BILINEAR);
BufferedImage transformedImage = new BufferedImage(w1, h1,
image.getType());
transformedImage = opRotated.filter(image, transformedImage);
return transformedImage;
}
答案 2 :(得分:0)
furykid's回答很棒并帮了我很多忙。但它并不是那么完美。如果图像是矩形,则生成的旋转图像可能在一侧包含一些额外的黑色像素。
我尝试了一张Marty Feldman照片,原版和结果可在此链接中查看: Marty Feldman rotation tests
在黑色背景上很难看到,但在任何图像编辑软件上,很容易看到生成图像右侧和底部的黑色小边框。对于某些人来说这可能不是问题,但是如果它适合您,那么这里是固定代码(我保留了原文作为评论以便于比较):
public BufferedImage rotateImage(BufferedImage image, int quadrants) {
int w0 = image.getWidth();
int h0 = image.getHeight();
/* These are not necessary anymore
* int w1 = w0;
* int h1 = h0;
*/
int centerX = w0 / 2;
int centerY = h0 / 2;
/* This is not necessary anymore
* if (quadrants % 2 == 1) {
* w1 = h0;
* h1 = w0;
* }
*/
//System.out.println("Original dimensions: "+w0+", "+h0);
//System.out.println("Rotated dimensions: "+w1+", "+h1);
if (quadrants % 4 == 1) {
centerX = h0 / 2;
centerY = h0 / 2;
} else if (quadrants % 4 == 3) {
centerX = w0 / 2;
centerY = w0 / 2;
}
//System.out.println("CenterX: "+centerX);
//System.out.println("CenterY: "+centerY);
AffineTransform affineTransform = new AffineTransform();
affineTransform.setToQuadrantRotation(quadrants, centerX, centerY);
AffineTransformOp opRotated = new AffineTransformOp(affineTransform,
AffineTransformOp.TYPE_BILINEAR);
/*Old code for comparison
//BufferedImage transformedImage = new BufferedImage(w1, h1,image.getType());
//transformedImage = opRotated.filter(image, transformedImage);
*/
BufferedImage transformedImage = opRotated.filter(image, null);
return transformedImage;
}
警告:提前意见。我不确定为什么会发生这种情况,但我有猜测。 如果你能更好地解释,请编辑。
我相信这个"故障的原因"是因为奇怪的尺寸。 在计算新
BufferedImage
的尺寸时,如果正确值为136.5,则高度273将生成136的centerY。 这可能会导致旋转发生在略微偏离中心的位置。但是,通过将null
发送到filter
作为目标图片,"使用源BufferedImage
"创建ColorModel
,这似乎有效最好的。