旋转BufferedImage时如何产生清晰的绘画效果?

rth*_*sen 25 java interpolation bufferedimage transformation transform

一种尝试的方法是使用TexturePaintg.fillRect()绘制图像.然而,这需要您在每次绘制图像时创建一个新的TexturePaint和Rectangle2D对象,这是不理想的 - 并且无论如何都没有帮助.

当我使用时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);
Run Code Online (Sandbox Code Playgroud)

我正在用AffineTransform一把牌旋转成一个风扇.什么是快速绘制好看图像的最佳方法?

这是一个截图:
模糊旋转的示例
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);
}
Run Code Online (Sandbox Code Playgroud)

我应该如何区别对待?谢谢.

编辑:
没有RenderingHints的手的示例
没有RenderingHints

设置AA提示没有区别.此外,在创建图像时设置RenderingHints也没有区别.只有当它们被旋转AffineTransform并使用时g.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];
  }
Run Code Online (Sandbox Code Playgroud)

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

所以问题变成了...... 当旋转BufferedImage时,如何产生清晰的绘画结果?

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

Bounty-Edit: 好的,经过多次讨论,我做了一些测试.svg卡片,看看SVG Salamander将如何渲染它们.不幸的是,表现很糟糕.我的实现足够干净,看到双缓冲的BufferedImage,这幅画非常快.这意味着我已经完整的循环,我回到了原来的问题.

我会给那些可以给我一个解决方案以获得尖锐的BufferedImage旋转的50分.建议在绘画之前使图像比它们需要的更大并缩小尺寸,并使用双三次插值.如果这些是唯一可能的解决方案,那么我真的不知道从哪里开始,我可能只需要处理模糊的旋转 - 因为这两者都会造成性能挫折.

如果我能找到一种方法可以做到这一点,我可以完成我的游戏.谢谢大家.:)

rth*_*sen 9

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

然后,当您绘制图像时,请立即调整大小:

g.drawImage(bufferedImage, x, y, desiredWidth, desiredHeight, observer);
Run Code Online (Sandbox Code Playgroud)

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

建议归功于圭多.


小智 5

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

如果大量旋转和动画是UI的一部分,则栅格化图像可能是错误的技术; 特别是有大量曲线的复杂图像.等到你尝试扩展你的游说.我可能会建议查看基于矢量的图形库.它们将呈现您想要的各种效果,而不会产生伪影.

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

  • @paranoid:我想我已经在某个地方看过公共领域的SVG图像扑克牌,所以已经有适合您的图片了.让我看看我是否能再次找到它们.**编辑:**这里有一些:[svg-cards](http://svg-cards.sourceforge.net/) (2认同)