AffineTransform会截断图片,我有什么不对?

我这里有一个尺寸为2156×1728的黑/白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年

旋转如何返回完全不相关的尺寸?

我不是这方面的专家,但为什么不创建一个正确大小的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://sofzh.miximages.com/java/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]。

上述解决方案存在图像的高度和高度问题,下面的代码与w> h ||无关 h> w

 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; } 

furykid的答案很棒,对我帮助很大。 但它并不是那么完美。 如果图像是矩形,则生成的旋转图像可能在一侧包含一些额外的黑色像素。

我尝试了一张Marty Feldman照片,原版和结果可以在这个链接中查看: Marty Feldman旋转测试

在黑色背景上很难看到,但在任何图像编辑软件上,很容易看到所得图像右侧和底部的黑色小边框。 对于某些人来说这可能不是问题,但是如果它适合你,这里是固定代码( 为了便于比较,我保留原文作为注释 ):

 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的尺寸时,高度为273将生成136的centerY,例如,当正确值为136.5时。 这可能会导致旋转发生在略微偏离中心的位置。 但是,通过向filter发送null作为目标图像,“使用源ColorModel创建BufferedImage ”,这似乎效果最好。