Java 2D 图像调整大小忽略双三次/双线性插值渲染提示 (OS X + linux)

标签 java image resize 2d bicubic

我正在尝试使用 Image Voodoo 插件在 JRuby/Rails 应用程序中为上传的图像创建缩略图 - 问题是调整大小的缩略图看起来像......屁股。

似乎生成缩略图的代码绝对正确地完成了将插值渲染提示设置为“双三次”的所有操作,但它并没有在我们的开发环境 (OS X) 或生产网络服务器上兑现它们(Linux)。

我提取了生成缩略图的代码,将其重写为一个直接的 Java 应用程序(即从 main() 方法开始),并将插值渲染提示明确设置为“双三次”,并重现了 (缺少)双三次和双线性调整大小。

正如预期的那样,在 OS X 和 Linux 上,缩略图都很丑陋且像素化,但在 Windows 上,它使用双三次插值很好地调整了图像的大小。

是否缺少任何 JVM 环境设置和/或其他库以使其正常工作?为此,我做了很多头撞墙的 Action 。

最佳答案

我知道这个问题不久前有人问过,但以防其他人仍然遇到这个问题。

缩略图看起来像屁股的原因是由两件事造成的(主要是第一件事):

  • Java 中的非增量图像缩放非常粗糙,无论渲染提示如何,都会抛出大量像素数据并对结果进行一次平均。
  • 在 Java2D 中处理支持不佳的 BufferedImage 类型(通常是 GIF)可能会导致外观非常差/抖动的结果。

事实证明旧AreaAveragingScaleFilter在制作漂亮的缩略图方面做得不错,但它很慢并且被 Java2D 团队弃用了——不幸的是他们没有用任何开箱即用的替代品来代替它,让我们有点孤军奋战。

Chris Campbell(来自 Java2D 团队)在几年前用增量缩放的概念解决了这个问题——不是在一次操作中从起始分辨率到目标分辨率,而是分步进行,结果看起来好多了。

鉴于此代码相当大,我将所有最佳实践写入一个名为 imgscalr 的库中并在 Apache 2 许可下发布。

最基本的用法如下所示:

BufferedImage img = ImageIO.read(...); // load image
BufferedImage scaledImg = Scalr.resize(img, 640);

在此用例中,库使用所谓的“自动”缩放模式,并将生成的图像(符合其比例)放入 640x640 的边界框内。因此,如果图像不是正方形而是标准的 4:3 图像,它会将其调整为 640x480——参数只是它的最大尺寸。

Scalr class 上还有许多其他方法(所有静态且易于使用)让您可以控制一切。

为了获得最好看的缩略图,命令如下所示:

BufferedImage img = ImageIO.read(...); // load image
BufferedImage scaledImg = Scalr.resize(img, Method.QUALITY, 
                                       150, 100, Scalr.OP_ANTIALIAS);

Scalr.OP_ANTIALIAS 是可选的,但很多用户觉得当您在 Java 中缩小到足够小的缩略图时,像素值之间的一些过渡有点过于离散,使图像看起来“锐利”,所以很多用户要求一种方法来软化缩略图。

这是通过 ConvolveOp 完成的如果您以前从未使用过它们,那么试图找出要使用的正确“内核”是……一件令人头疼的事情。在类上定义的 OP_ANTIALIAS 常量是我在与另一个将 imgscalr 部署到他们在巴西的社交网络(用于缩放个人资料照片)的用户进行一周测试后发现的最好看的抗锯齿操作。我将其包括在内是为了让每个人的生活更轻松一些。

此外,在所有这些示例之上,您可能已经注意到,当您缩放 GIF 和某些其他类型的图像 (BMP) 时,有时缩放后的结果与原始图像相比看起来很糟糕...这是因为图像位于支持不佳的 BufferedImage 类型和 Java2D 回退到使用它的软件渲染管道而不是硬件加速管道以获得更好支持的图像类型。

imgscalr 将为您处理所有这一切,并尽可能将图像保持为最受支持的图像类型,以避免出现这种情况。

无论如何,“您可以使用 imgscalr 为您完成所有这些工作,而不必担心任何事情”,这是一个很长的说法。

关于Java 2D 图像调整大小忽略双三次/双线性插值渲染提示 (OS X + linux),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1087236/

相关文章:

java - java 中对象与原始传递如何工作(在集合的上下文中)?

java - JAX-WS Web 服务线程安全和性能问题

r - 如何从R中的灰度图像获取像素矩阵?

调整其父窗口大小时的 WPF GridSplitter 行为

java - GWT:SplitLayoutPanel UiBinder

java - 服务器和 java servlet 可以在没有用户交互的情况下发送自动电子邮件吗?

java - 在不退出的情况下设置 Java 退出代码

jquery - 定位不同大小/比例的img并填充到div中

swift - Clipped Image 在框架外调用 TapAction

jquery-ui - 如何调整 jQuery 日期选择器的大小?