Java:旋转图像
Posted
技术标签:
【中文标题】Java:旋转图像【英文标题】:Java: Rotating Images 【发布时间】:2012-01-28 04:50:00 【问题描述】:我需要能够单独旋转图像(在 java 中)。到目前为止,我唯一发现的是 g2d.drawImage(image, affinetransform, ImageObserver)。不幸的是,我需要在特定点绘制图像,并且没有方法可以使用 1. 单独旋转图像和 2. 允许我设置 x 和 y 的参数。任何帮助表示赞赏
【问题讨论】:
请看:Why is “Can someone help me?” not an actual question? 【参考方案1】:这就是你可以做到的。此代码假定存在一个名为“image”的缓冲图像(如您的评论所说)
// The required drawing location
int drawLocationX = 300;
int drawLocationY = 300;
// Rotation information
double rotationRequired = Math.toRadians (45);
double locationX = image.getWidth() / 2;
double locationY = image.getHeight() / 2;
AffineTransform tx = AffineTransform.getRotateInstance(rotationRequired, locationX, locationY);
AffineTransformOp op = new AffineTransformOp(tx, AffineTransformOp.TYPE_BILINEAR);
// Drawing the rotated image at the required drawing locations
g2d.drawImage(op.filter(image, null), drawLocationX, drawLocationY, null);
【讨论】:
为什么这么复杂?变换包含旋转和平移,所以只需使用g2d.drawImage(image, tx, ImageObserver)
和答案中的tx
。
谢谢,但它会切断一些图像。
关于如何规避截止问题的任何信息?【参考方案2】:
AffineTransform
实例可以连接(添加在一起)。因此,您可以进行组合“移至原点”、“旋转”和“移回所需位置”的变换。
【讨论】:
【参考方案3】:我对现有答案有点挣扎,因为我要旋转的图像并不总是正方形,此外,接受的答案有一条评论询问“有关如何规避截止问题的任何信息”,但没有得到回答。 因此,对于那些在旋转时遇到图像被裁剪问题的人来说,这里的代码对我有用:
public static BufferedImage rotate(BufferedImage bimg, Double angle)
double sin = Math.abs(Math.sin(Math.toRadians(angle))),
cos = Math.abs(Math.cos(Math.toRadians(angle)));
int w = bimg.getWidth();
int h = bimg.getHeight();
int neww = (int) Math.floor(w*cos + h*sin),
newh = (int) Math.floor(h*cos + w*sin);
BufferedImage rotated = new BufferedImage(neww, newh, bimg.getType());
Graphics2D graphic = rotated.createGraphics();
graphic.translate((neww-w)/2, (newh-h)/2);
graphic.rotate(Math.toRadians(angle), w/2, h/2);
graphic.drawRenderedImage(bimg, null);
graphic.dispose();
return rotated;
【讨论】:
嘿,它对我有用。唯一的问题是我无法让它围绕某个点旋转。我该怎么做? 这对我有用,谢谢!【参考方案4】:不使用如此复杂的draw语句的简单方法:
//Make a backup so that we can reset our graphics object after using it.
AffineTransform backup = g2d.getTransform();
//rx is the x coordinate for rotation, ry is the y coordinate for rotation, and angle
//is the angle to rotate the image. If you want to rotate around the center of an image,
//use the image's center x and y coordinates for rx and ry.
AffineTransform a = AffineTransform.getRotateInstance(angle, rx, ry);
//Set our Graphics2D object to the transform
g2d.setTransform(a);
//Draw our image like normal
g2d.drawImage(image, x, y, null);
//Reset our graphics object so we can draw with it again.
g2d.setTransform(backup);
【讨论】:
【参考方案5】:public static BufferedImage rotateCw( BufferedImage img )
int width = img.getWidth();
int height = img.getHeight();
BufferedImage newImage = new BufferedImage( height, width, img.getType() );
for( int i=0 ; i < width ; i++ )
for( int j=0 ; j < height ; j++ )
newImage.setRGB( height-1-j, i, img.getRGB(i,j) );
return newImage;
来自https://coderanch.com/t/485958/java/Rotating-buffered-image
【讨论】:
【参考方案6】:这是 90、180 和 270 度旋转的解决方案。
对于这些情况,AffineTransform 可能会引入一些损失/插值。
此解决方案是无损的,还可以处理(深奥?)超过 8 位/像素的颜色模型,而 BufferedImage.getRGB(int x, int y)
不能。
解决方案是逐像素进行的,其优点是编码简单。
可以逐行读取原始图像以获得性能,但它更复杂,所以我省略了。
import java.awt.image.BufferedImage;
import java.awt.image.WritableRaster;
/**
* N.B. this example uses the new switch/case/Arrow notation, which requires Java 14.
*/
public enum Rotation
CLOCKWISE_90,
CLOCKWISE_180,
CLOCKWISE_270;
public BufferedImage rotate(final BufferedImage original)
final int oW = original.getWidth();
final int oH = original.getHeight();
final BufferedImage rotated =
switch (this)
case CLOCKWISE_180 -> new BufferedImage(oW, oH, original.getType());
default -> new BufferedImage(oH, oW, original.getType());
;
final WritableRaster rasterOriginal = original.copyData(null);
final WritableRaster rasterRotated = rotated .copyData(null);
/*
* The Data for 1 Pixel...
*/
final int[] onePixel = new int[original.getSampleModel().getNumBands()];
/*
* Copy the Pixels one-by-one into the result...
*/
for (int x = 0; x < oW; x++)
for (int y = 0; y < oH; y++)
; rasterOriginal.getPixel( x, y, onePixel);
switch (this)
case CLOCKWISE_90 -> rasterRotated .setPixel(oH - 1 - y, x, onePixel);
case CLOCKWISE_270 -> rasterRotated .setPixel( y, oW - 1 - x, onePixel);
default -> rasterRotated .setPixel(oW - 1 - x, oH - 1 - y, onePixel);
;
rotated.setData(rasterRotated);
return rotated;
【讨论】:
【参考方案7】:抱歉,作为一个图形初学者,所有答案对于我来说都很难理解......
经过一番摆弄,这对我有用,而且很容易推理。
@Override
public void draw(Graphics2D g)
AffineTransform tr = new AffineTransform();
// X and Y are the coordinates of the image
tr.translate((int)getX(), (int)getY());
tr.rotate(
Math.toRadians(this.rotationAngle),
img.getWidth() / 2,
img.getHeight() / 2
);
// img is a BufferedImage instance
g.drawImage(img, tr, null);
我想如果你想旋转一个矩形图像,这个方法将不起作用并且会剪切图像,但我认为你应该创建方形 png 图像并旋转它。
【讨论】:
【参考方案8】:我认为最可靠和最简单的方法是不仅要旋转图像,还要旋转您正在使用的坐标。此代码将围绕左上角旋转一个 bufferedImage 并相应地绘制它而不进行裁剪,并且返回的图像将绘制在正确的位置。如果您知道向量和矩阵是什么,并查看旋转矩阵的***文章,您将很容易理解此代码。我还添加了一点手绘。在算法的第二部分,我们确定较大矩形的位置和尺寸,其中包含我们旋转的缓冲图像。我们定义的前 4 个点在技术上并未使用,但它们仍然可以帮助您了解这些点最初的位置。
public void drawRotated(final Graphics g, final BufferedImage bufferedImage, final int x, final int y, final int width, final int height, final double angle)
final Rectangle collision = new Rectangle(x, y, width, height);
final BufferedImage resize = resize(bufferedImage, collision.width, collision.height);
final BufferedImage rotate = rotate(resize, angle, collision);
g.drawImage(rotate, collision.x, collision.y, collision.width, collision.height, null);
public static BufferedImage resize(final BufferedImage bufferedImage, final int newWidth, final int newHeight)
final BufferedImage resized = new BufferedImage(newWidth, newHeight, bufferedImage.getType());
final Graphics g = resized.createGraphics();
g.drawImage(bufferedImage, 0, 0, newWidth, newHeight, null);
return resized;
public static BufferedImage rotate(final BufferedImage bufferedImage, final double angle, final Rectangle collision)
final double sin = Math.sin(Math.toRadians(angle));
final double cos = Math.cos(Math.toRadians(angle));
final int x1 = collision.x;
final int y1 = collision.y;
final int x2 = collision.x+collision.width;
final int y2 = collision.y;
final int x3 = collision.x;
final int y3 = collision.y+collision.height;
final int x4 = collision.x+collision.width;
final int y4 = collision.y+collision.height;
//turn all 4 points around the top left point
final int newx1 = collision.x;
final int newy1 = collision.y;
//the y component is 0
final int newx2 = (int) (collision.x+collision.width*cos);
final int newy2 = (int) (collision.y+collision.width*sin);
//the x component is 0
final int newx3 = (int) (collision.x-collision.height*sin);
final int newy3 = (int) (collision.y+collision.height*cos);
final int newx4 = (int) (collision.x+collision.width*cos-collision.height*sin);
final int newy4 = (int) (collision.y+collision.width*sin+collision.height*cos);
//determine the new position of our bigger rectangle containing our image
collision.x = Math.min(Math.min(newx1, newx2), Math.min(newx3, newx4));
collision.y = Math.min(Math.min(newy1, newy2), Math.min(newy3, newy4));
//determine the new dimensions of our bigger rectangle containing our image
collision.width = Math.max(Math.max(newx1, newx2), Math.max(newx3, newx4))-collision.x;
collision.height = Math.max(Math.max(newy1, newy2), Math.max(newy3, newy4))-collision.y;
final BufferedImage rotated = new BufferedImage(collision.width, collision.height, bufferedImage.getType());
final Graphics2D g2d = rotated.createGraphics();
g2d.translate(newx1- collision.x, newy1- collision.y);
g2d.rotate(Math.toRadians(angle), 0, 0);
g2d.drawRenderedImage(bufferedImage, null);
g2d.dispose();
return rotated;
【讨论】:
以上是关于Java:旋转图像的主要内容,如果未能解决你的问题,请参考以下文章