【问题标题】:Java Image Cut OffJava 图像截断
【发布时间】:2012-02-02 00:38:19
【问题描述】:

与上次相同的问题,但我会提供更多详细信息。 我目前正在使用以下方式旋转图像:

 int rotateNum //in main class

 double rotationRequired = Math.toRadians(rotateNum);

    double locationX = img.getWidth(this) / 2;
    double locationY = img.getHeight(this) / 2;
    AffineTransform tx = AffineTransform.getRotateInstance(rotationRequired, locationX, locationY);
    AffineTransformOp op = new AffineTransformOp(tx, AffineTransformOp.TYPE_BILINEAR);


    g2d.drawImage(op.filter((BufferedImage)img, null), imgX, imgY, null);

然后我实际上正在使用以下方法旋转图像:

double deltaX = (double)(imgY - otherImg.imgY);
double deltaY = (double)(imgX - otherImg.imgX);
rotateNum = (int)(180 * Math.atan2(deltaY, deltaX) / Math.PI);

我的图片大小不一。较小的图像不会被截断(意味着被空白区域截断),但较大的图像在左侧或右侧会被截断。调整图像大小不起作用,我使用 GIMP。

示例图片: 之前(忽略左边的灰色区域)

之后: 见侧面的截止

【问题讨论】:

    标签: java image graphics rotation


    【解决方案1】:

    问题是您的源图像不完全是二次的。当你使用 at.rotate(-rad, width/2, height/2); 实现 AffineTransform 旋转时,它与:

    at.translate(width/2,height/2);
    at.rotate(rads);
    at.translate(-width/2,-height/2);
    

    因此,当它执行最后一行时,它会转换为原点。如果宽度大于 y(反之亦然),则变换的原点将被转换为比长度更大的边更小的距离。

    例如,如果您的宽度为 30,高度为 60,则原点将设置为 (-15,-30),从原始设置的变换开始。所以,当你翻译它时,比如说,90度,图像最终会得到“宽度”60和“高度”30,但是根据原点,图像原始底部将被绘制在(-30,0),所以它在 X 轴上溢出了 -15 的 AffineTransform。然后这部分图像将被剪切。

    要更正此问题,您可以改用以下代码:

    double degreesToRotate = 90;
    double locationX =bufferedImage.getWidth() / 2;
    double locationY = bufferedImage.getHeight() / 2;
    
    double diff = Math.abs(bufferedImage.getWidth() - bufferedImage.getHeight());
    
    //To correct the set of origin point and the overflow
    double rotationRequired = Math.toRadians(degreesToRotate);
    double unitX = Math.abs(Math.cos(rotationRequired));
    double unitY = Math.abs(Math.sin(rotationRequired));
    
    double correctUx = unitX;
    double correctUy = unitY;
    
    //if the height is greater than the width, so you have to 'change' the axis to correct the overflow
    if(bufferedImage.getWidth() < bufferedImage.getHeight()){
        correctUx = unitY;
        correctUy = unitX;
    }
    
    int posAffineTransformOpX = posX-(int)(locationX)-(int)(correctUx*diff);
    int posAffineTransformOpY = posY-(int)(locationY)-(int)(correctUy*diff);
    
    //translate the image center to same diff that dislocates the origin, to correct its point set
    AffineTransform objTrans = new AffineTransform();
    objTrans.translate(correctUx*diff, correctUy*diff);
    objTrans.rotate(rotationRequired, locationX, locationY);
    
    AffineTransformOp op = new AffineTransformOp(objTrans, AffineTransformOp.TYPE_BILINEAR);
    
    // Drawing the rotated image at the required drawing locations
    graphic2dObj.drawImage(op.filter(bufferedImage, null), posAffineTransformOpX, posAffineTransformOpY, null);
    

    希望对您有所帮助。

    【讨论】:

    • 在您的回答@LucasBorsatto 中,您有 2 个幻数:posX 和 posY。那些是指什么,它们是从哪里获得的?
    【解决方案2】:

    我认为重要的不是图像的大小,而是它的偏心度:更方形的图像比更胖或更薄的图像问题更少。

    我认为您的问题是您的旋转中心不应该是 [width / 2, height / 2] ——这不是那么简单。想象一下位于大正方形左上部的图像,正方形边的长度将是图像的宽度或高度,以较大者为准。每当您旋转图像时,这就是旋转的内容。

    例如,请看我的回复:https://stackoverflow.com/a/8720123/522444

    【讨论】:

      【解决方案3】:

      不幸的是,这是 java 所做的事情。解决方法之一是将形状设为正方形,这样在旋转时不会发生剪裁。

      David 的“Killer game programming in Java”一书books_google_killer+game+programming+clipping+rotating 涵盖了这个问题,如果您想做任何 Java 游戏编程(即使它有点旧),这本书很棒 )。

      Edit :: 将图像转换为正方形可以通过图像编辑软件或通过 java 本身对原始图像进行。也许滚动您自己的旋转方法可以检查此类碰撞..

      【讨论】:

        【解决方案4】:

        旋转图像也可能会影响图像的大小。这是我很久以前在旧的 Sun 论坛上找到的一些代码(我忘记了原始海报)。它重新计算以给定的旋转角度显示图像所需的大小:

        import java.awt.*;
        import java.awt.geom.*;
        import java.awt.image.*;
        import java.io.*;
        import java.net.*;
        import javax.imageio.*;
        import javax.swing.*;
        
        public class RotateImage {
            public static void main(String[] args) throws IOException {
                URL url = new URL("https://blogs.oracle.com/jag/resource/JagHeadshot-small.jpg");
                BufferedImage original = ImageIO.read(url);
                GraphicsConfiguration gc = getDefaultConfiguration();
                BufferedImage rotated1 = tilt(original, -Math.PI/2, gc);
                BufferedImage rotated2 = tilt(original, +Math.PI/4, gc);
                BufferedImage rotated3 = tilt(original, Math.PI, gc);
                display(original, rotated1, rotated2, rotated3);
            }
        
            public static BufferedImage tilt(BufferedImage image, double angle, GraphicsConfiguration gc) {
                double sin = Math.abs(Math.sin(angle)), cos = Math.abs(Math.cos(angle));
                int w = image.getWidth(), h = image.getHeight();
                int neww = (int)Math.floor(w*cos+h*sin), newh = (int)Math.floor(h*cos+w*sin);
                int transparency = image.getColorModel().getTransparency();
                System.out.println(transparency);
        //        BufferedImage result = gc.createCompatibleImage(neww, newh, transparency);
                BufferedImage result = gc.createCompatibleImage(neww, newh, Transparency.TRANSLUCENT);
                Graphics2D g = result.createGraphics();
                g.translate((neww-w)/2, (newh-h)/2);
                g.rotate(angle, w/2, h/2);
                g.drawRenderedImage(image, null);
                return result;
            }
        
            public static GraphicsConfiguration getDefaultConfiguration() {
                GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
                GraphicsDevice gd = ge.getDefaultScreenDevice();
                return gd.getDefaultConfiguration();
            }
        
            public static void display(BufferedImage im1, BufferedImage im2, BufferedImage im3, BufferedImage im4) {
                JPanel cp = new JPanel(new GridLayout(2,2));
                addImage(cp, im1, "original");
                addImage(cp, im2, "rotate -PI/2");
                addImage(cp, im3, "rotate +PI/4");
                addImage(cp, im4, "rotate PI");
        
                JFrame f = new JFrame("RotateImage");
                f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                f.setContentPane(cp);
                f.pack();
                f.setLocationRelativeTo(null);
                f.setVisible(true);
            }
        
            static void addImage(Container cp, BufferedImage im, String title) {
                JLabel lbl = new JLabel(new ImageIcon(im));
                lbl.setBorder(BorderFactory.createTitledBorder(title));
                cp.add(lbl);
            }
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-10-10
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多