Java:旋转图像

发布于 12-23 07:28 字数 156 浏览 6 评论 0原文

我需要能够单独旋转图像(在java中)。到目前为止我唯一发现的是 g2d.drawImage(image, affinetransform, ImageObserver )。不幸的是,我需要在特定点绘制图像,并且没有带有参数的方法:1. 单独旋转图像,2. 允许我设置 x 和 y。任何帮助表示赞赏

I need to be able to rotate images individually(in java). The only thing I have found so far is g2d.drawImage(image, affinetransform, ImageObserver ). Unfortunately, I need to draw the image at a specific point, and there is no method with an argument that 1.rotates the image separately and 2. allows me to set the x and y. any help is appreciated

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

盗琴音2024-12-30 07:28:55

您可以这样做。此代码假设存在名为“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);

This is how you can do it. This code assumes the existance of a buffered image called 'image' (like your comment says)

// 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);
相思故2024-12-30 07:28:55

AffineTransform 实例可以串联(添加在一起)。因此,您可以拥有一个结合了“移至原点”、“旋转”和“移回所需位置”的变换。

AffineTransform instances can be concatenated (added together). Therefore you can have a transform that combines 'shift to origin', 'rotate' and 'shift back to desired position'.

苏别ゝ2024-12-30 07:28:55

我对现有的答案有点挣扎,因为我要旋转的图像并不总是正方形,此外,接受的答案有一条评论询问“有关如何规避截止问题的任何信息”,但未得到答复。
因此,对于那些在旋转时遇到图像被裁剪问题的人来说,这里的代码对我有用:

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

I struggled a little with the existing answers because my image to be rotated is not always a square, furthermore the accepted answer has a comment asking "Any info on how to circumvent the cutoff problem" that is not answered.
So for those who had the issue of image being croped when rotated here is the code that worked for me :

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;
}
女中豪杰2024-12-30 07:28:55

一种简单的方法,无需使用如此复杂的绘制语句:

    //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);

A simple way to do it without the use of such a complicated draw statement:

    //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);
错爱2024-12-30 07:28:55
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 -图像

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

from https://coderanch.com/t/485958/java/Rotating-buffered-image

若有似无的小暗淡2024-12-30 07:28:55

这是 90°、180° 和 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;
    }
}

Here is a solution for rotations of 90, 180 & 270 degrees.

For these cases, the AffineTransform can introduce some loss/interpolation.

This solution is lossless & can also handle (esoteric?) Colour Models with more than 8 Bits/Pixel which BufferedImage.getRGB(int x, int y) cannot.

The solution proceeds on a pixel-by-pixel basis, which has the advantage of being simple to code.

It is possible to read the original Image row-by-row to gain performance, but its more complex, so I've left that out.

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;
    }
}
烟凡古楼2024-12-30 07:28:55

抱歉,但是对于我作为图形初学者来说,所有答案都很难理解......

经过一番摆弄,这对我来说很有效,而且很容易推理。

@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 图像并旋转它。

Sorry, but all the answers are difficult to understand for me as a beginner in graphics...

After some fiddling, this is working for me and it is easy to reason about.

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

I suppose that if you want to rotate a rectangular image this method wont work and will cut the image, but I thing you should create square png images and rotate that.

森林很绿却致人迷途2024-12-30 07:28:55

我认为最可靠和最简单的方法不仅是旋转图像,而且还旋转您正在使用的坐标。此代码会将 bufferedImage 围绕左上角旋转并相应地绘制它而不进行裁剪,并且返回的图像将绘制在正确的位置。如果您知道向量和矩阵是什么,并查看维基百科关于旋转矩阵的文章,您将很容易理解这段代码。我还添加了一些手绘图。在算法的第二部分中,我们确定较大矩形的位置和尺寸,其中包含旋转的 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;
}

I think the sturdiest and easiest approach is to not only rotate the image, but also the coordinates you're working with. This code will turn a bufferedImage around the topleft corner and draw it accordingly without cropping, and the returned image will be drawn in the right place. If you know what a vector and matrix are and look at the wikipedia article for rotation matrix you will understand this code easily. I also added a little hand drawing to it. In the 2nd part of the algorithm we determine the position and dimension of the bigger rectangle, which contains our rotated bufferedImage. The first 4 points we define are technically not used, but they still help you understand where the points are initially. Rotation hand drawing

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;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文