Java2D:缩放问题

8

我是一名经验较丰富的Java程序员,但在Java2D方面相对较新。我正在尝试缩放图像,但结果质量很差。该图像是面板的预览,因此包含文本和文本字段等内容。我将始终进行缩小,而不是放大。

目前,我正在使用以下代码:

g.drawImage(panelImage, 0, 0, scaledWidth, scaledHeight, null);

在这里,panelImage是完整的预览(BufferedImage),scaledWidth和scaledHeight是相应的目标尺寸。我似乎会在文本和文本字段等物体的边缘失去很多细节。

有没有更好的调用方法来缩放图像?

谢谢, 约翰

4个回答

11
我可以提出的建议是,首先将图像调整大小到单独的BufferedImage上。原因是,可以获得BufferedImageGraphics2D对象,以产生更好质量的缩放图像。 Graphics2D可以接受“渲染提示”,这些提示指示Graphics2D对象应该执行图像处理的方式。setRenderingHint方法是可以用于设置这些渲染提示的方法之一。可以使用RenderingHints类中的渲染提示。
然后,使用该Graphics2D对象,可以使用先前指定的渲染提示绘制图像到BufferedImage中。
一个简单(未经测试)的代码如下:
BufferedImage scaledImage = new BufferedImage(
    scaledWidth,
    scaledHeight,
    BufferedImage.TYPE_INT_RGB
);

Graphics2D g = scaledImage.createGraphics();
g.setRenderingHints(
    RenderingHints.Key.KEY_INTERPOLATION,
    RenderingHints.VALUE_INTERPOLATION_BICUBIC
);

g.drawImage(panelImage, 0, 0, scaledWidth, scaledHeight, null);
g.dispose();

其他值得关注的渲染提示包括:

The Java Tutorials中的Controlling Rendering Quality章节还提供了更多关于如何控制Graphics2D对象的渲染质量的信息。

而对于处理图形界面的一般性信息,强烈推荐Chet Haase和Romain Guy的Filthy Rich Clients。该书中有一个章节讨论缩放图像的问题,似乎非常相关。


谢谢,我有那本书的副本,我刚刚开始阅读其中的章节。在发布之前应该想到去那里看看。我完全忘记了缩放的渲染提示。谢谢!John - Johnathan
不客气 :) 第98-113页涉及图像缩放,并包括一些很好的示例。对我特别感兴趣的是第104页介绍的渐进双线性缩放的想法。 - coobird
是的,我看到了,但我不认为我的应用程序真的需要它。BICUBIC或BILINEAR对我来说已经足够好了。是时候进行实验了! - Johnathan

2
也许你应该打电话给:
 g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);

并且

g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

1
Coobird说得对,你需要逐步缩小(最好使用BICUBIC)来获得足够小的缩略图的好看结果。Image.getScaledInstance曾经使用AREA_AVERAGED方法来实现这一点,但它比原始提出者Chris Campbell在他的“Perils of Image.getScaledInstance()”文章中提出的逐步缩小方法要慢得多。
请原谅我在这里自我推销,但我将一些“本地Java最佳实践”滚动到了一个名为imgscalr的库中,当涉及到图像缩放时。
它在Apache 2许可下可用,源代码都在GitHub上;该库的目标是使本地Java中的图像缩放变得非常简单(1个类,5个静态方法),并确保获得最佳外观结果(这是您最初想要的),最快的结果(在大型图像之间进行缩放时很棒)或两者之间的平衡,并让库决定使用哪一个。
我只是想要一个可以“调整我的图像并离开我的方式”的库,经过几天阅读所有这些帖子以解决痛点(也是我的痛点),只是回来分享这项工作,希望能帮助其他人。

原始网站目前没有回应,似乎该库的官方存储库在这里 https://github.com/rkalla/imgscalr。 - Damien B
是的,你找到了正确的仓库——我关闭了所有旧的“Buzz Media”相关内容(我已经有约5年时间没有维护它们了),并将它们全部移动到了我的个人仓库空间。它也在默认的Maven仓库中。 - Riyad Kalla

0

Coobird 的想法是正确的。我也会尝试使用 RenderingHints.VALUE_INTERPOLATION_BILINEAR 插值,看看效果是否更好。不过在放大时,双三次插值效果更好。当缩小图像时,最好采用逐步缩小的方法。首先将分辨率减半,然后再减半,直到接近所需分辨率(即不能再减半,否则图像会变得太小)。最后一步是缩放到所需分辨率。

例如,假设您的输入图像为800x600,您想将其缩小到160x120

  1. 缩小50%。--> 400x300
  2. 缩小50%。--> 200x150
  3. 缩小到160x120

分步缩小有什么优点?请详细说明:D - Thorbjørn Ravn Andersen
这里有关于该主题的一些内容:http://www.nobel-joergensen.com/roller/java/entry/downscaling_images_in_java除此之外,根据我的经验,逐步缩小图像可以获得更好的最终结果。值得至少尝试一下。 :) - MH114
1
这就是“渐进双线性缩放”的理念——通过多步进行双线性缩放,保留每个像素的信息,而不是通过单步双线性重缩图像来丢弃它们。 - coobird
@coobird:好的,谢谢!知道这个技术的正确名称很好。 - MH114

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接