【问题标题】:Java: Rotating ImagesJava:旋转图像
【发布时间】:2022-01-09 01:45:16
【问题描述】:

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

【问题讨论】:

标签: java image swing rotation graphics2d


【解决方案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】:

    不使用如此复杂的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);
    

    【讨论】:

      【解决方案4】:

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

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

      【讨论】:

      • 嘿,它对我有用。唯一的问题是我无法让它围绕某个点旋转。我该怎么做?
      【解决方案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】:

        抱歉,作为图形初学者,我很难理解所有答案...

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

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

        【讨论】:

          【解决方案7】:

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

          【讨论】:

            【解决方案8】:

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

            【讨论】:

              猜你喜欢
              • 2012-08-23
              • 1970-01-01
              • 2013-09-05
              • 2015-09-16
              • 1970-01-01
              • 2018-08-24
              • 1970-01-01
              相关资源
              最近更新 更多