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:旋转图像的主要内容,如果未能解决你的问题,请参考以下文章

在 Java 中旋转缓冲图像

在java中将图像旋转90度[重复]

打印在 Java 中旋转的图像会增加伪影

java 48.旋转图像(#)。java

java 48.旋转图像(#)。java

java 48.旋转图像(#)。java