如何在旋转缓冲图像时产生清晰的绘画效果?

一种尝试的方法是使用和绘制图像。但是,这需要您在每次绘制图像时创建一个新的 TexturePaint 和 Rectangle2D 对象,这并不理想 - 无论如何都无济于事。TexturePaintg.fillRect()

当我使用时,旋转的图像看起来是模糊/柔和的。g.drawImage(BufferedImage,...)

我熟悉 RenderingHints 和双缓冲(我想这就是我正在做的事情),我只是发现很难相信你不能在 Java 中轻松有效地旋转图像,从而产生清晰的结果。

用于使用的代码如下所示。TexturePaint

Grahics2D g2d = (Graphics2D)g; 
g2d.setPaint(new TexturePaint(bufferedImage, new Rectangle2D.Float(0,0,50,50)));
g2d.fillRect(0,0,50,50);

我用手将一手牌旋转成扇子。快速绘制好看图像的最佳方法是什么?AffineTransform

这是一个截图:
Example of blurred rotations
9很清晰,但其余的卡片绝对没有那么清晰。

问题可能出在创建每个卡映像并将其存储在数组中时。
以下是我目前的做法:

// i from 0 to 52, card codes.
...
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice gs = ge.getDefaultScreenDevice();
GraphicsConfiguration gc = gs.getDefaultConfiguration();
BufferedImage img = gc.createCompatibleImage(86, 126, Transparency.TRANSLUCENT);

    Graphics2D g = img.createGraphics();
    setRenderingHints(g);
    g.drawImage(shadow, 0, 0, 86, 126, null);
    g.drawImage(white, 3, 3, 80, 120, null);
    g.drawImage(suit, 3, 3, 80, 120, null);
    g.drawImage(value, 3, 3, 80, 120, null);
    g.dispose();

    cardImages[i] = img;
}

private void setRenderingHints(Graphics2D g){
    g.setRenderingHint(KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
    g.setRenderingHint(KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
    g.setRenderingHint(KEY_ANTIALIASING, VALUE_ANTIALIAS_ON);
}

我应该如何以不同的方式处理这个问题?谢谢。

编辑:
Example of hand without RenderingHints
无渲染效果

设置 AA 提示没有任何区别。此外,在创建图像时设置渲染效果也没有区别。只有当它们被旋转和使用绘画时,它们才会变得模糊。
上图显示了默认(最近邻)和双线性插值之间的差异。AffineTransformg.drawImage(...)

以下是我目前绘制它们的方式(比TexturePaint快得多):

// GamePanel.java
private void paintCard(Graphics2D g, int code, int x, int y){
    g.drawImage(imageLoader.getCard(code), x, y, 86, 126, null);
  }

// ImageLoader.java
public BufferedImage getCard(int code){
    return cardImages[code];
  }

我所有的卡片都是80x120,阴影.png是86x126,以便在卡片周围留下3px的半透明阴影。我知道这不是一个逼真的影子,但看起来还不错。

所以问题就变成了...如何在旋转缓冲图像时产生清晰的绘画效果?

参考前面一个关于扇形卡手的问题:
如何在Java中检测Image对象上的鼠标单击事件?

赏金编辑:好吧,经过多次讨论,我做了一些测试.svg卡片,看看SVG蝾螈将如何渲染它们。不幸的是,性能很糟糕。我的实现足够干净,因为使用双缓冲缓冲图像的绘画速度非常快。这意味着我已经走了整整一圈,我又回到了原来的问题。

我会把50个赏金给任何能给我一个解决方案的人,以获得清晰的BufferedImage旋转。建议是使图像大于需要的大小,并在绘画前缩小比例,并使用双三次插值。如果这些是唯一可能的解决方案,那么我真的不知道该从哪里开始,我可能只需要处理模糊的旋转 - 因为这两个都会带来性能挫折。

如果我能找到一种方法来做好这件事,我就可以完成我的比赛。谢谢大家。:)


答案 1

旋转栅格化图像(如缓冲图像)时,会丢失数据。最好的解决方案是保存比您需要的图像更大的图像,并在绘制图像时动态缩小。我发现你需要的1.5倍大小是一个很好的起点。

然后,在绘制图像时,动态调整大小:

g.drawImage(bufferedImage, x, y, desiredWidth, desiredHeight, observer);

建议使用双线性插值进行旋转。

建议的功劳归于圭多。


答案 2

这个建议可能在你的设计中有点晚,但可能值得一提。

如果 UI 中有很多旋转和动画,则栅格化图像可能是错误的技术;特别是对于具有大量曲线的复杂图像。只需等到您尝试缩放画布即可。我可能会建议看看一个基于矢量的图形库。它们将渲染您想要的效果,同时减少伪影的可能性。

http://xmlgraphics.apache.org/batik/using/swing.htm


推荐