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

发布于 2024-07-26 03:43:50 字数 423 浏览 8 评论 0原文

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

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

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

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

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

I'm trying to create thumbnails for uploaded images in a JRuby/Rails app using the Image Voodoo plugin - the problem is the resized thumbnails look like... ass.

It seems that the code to generate the thumbnails is absolutely doing everything correctly to set the interpolation rendering hint to "bicubic", but it isn't honoring them on our dev environment (OS X), or on the production web server (Linux).

I've extracted out the code to generate the thumbnails, rewritten it as a straight Java app (ie kicked off from a main() method) with the interpolation rendering hint explicitly set to "bicubic", and have reproduced the (lack of) bicubic and bilinear resizing.

As expected on both OS X and Linux the thumbanils are ugly and pixelated, but on Windows, it resizes the images nicely with bicubic interpolation used.

Is there any JVM environment setting and/or additional libraries that I'm missing to make it work? I'm doing a lot of banging of head against wall for this one.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

仅此而已 2024-08-02 03:43:50

我意识到这个问题不久前就被问过,但以防万一其他人仍然遇到这个问题。

缩略图看起来像屁股的原因有两个原因(主要是第一个):

  • 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 类(全静态且易于使用)让您可以控制一切。

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

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 为你做这一切,而不必担心任何事情”。

I realize this question was asked a while ago, but incase anyone else is still running into this.

The reason the thumbnails look like ass are caused by two things (primarily the first one):

  • Non-incremental image scaling in Java is very rough, throws a lot of pixel data out and averages the result once regardless of the rendering hint.
  • Processing a poorly supported BufferedImage type in Java2D (typically GIFs) can result in very poor looking/dithered results.

As it turns out the old AreaAveragingScaleFilter does a decent job of making good looking thumbnails, but it is slow and deprecated by the Java2D team -- unfortunately they didn't replace it with any nice out-of-the-box alternative and left us sort of on our own.

Chris Campbell (from the Java2D team) addressed this a few years ago with the concept of incremental scaling -- instead of going from your starting resolution to the target resolution in one operation, you do it in steps, and the result looks much better.

Given that the code for this is decently large, I wrote all the best-practices up into a library called imgscalr and released it under the Apache 2 license.

The most basic usage looks like this:

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

In this use-case the library uses what is called it's "automatic" scaling mode and will fit the resulting image (honoring it's proportions) within a bounding box of 640x640. So if the image is not a square and is a standard 4:3 image, it will resize it to 640x480 -- the argument is just it's largest dimension.

There are a slew of other methods on the Scalr class (all static and easy to use) that allow you to control everything.

For the best looking thumbnails possible, the command would look like this:

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

The Scalr.OP_ANTIALIAS is optional, but a lot of users feel that when you scale down to a small enough thumbnail in Java, some of the transitions between pixel values are a little too discrete and make the image look "sharp", so a lot of users asked for a way to soften the thumbnail a bit.

That is done through a ConvolveOp and if you have never used them before, trying to figure out the right "kernel" to use is... a pain in the ass. That OP_ANTIALIAS constant defined on the class it the best looking anti-aliasing op I found after a week of testing with another user who had deployed imgscalr into their social network in Brazil (used to scale the profile photos). I included it to make everyone's life a bit easier.

Also, ontop of all these examples, you might have noticed when you scale GIFs and some other types of images (BMPs) that sometimes the scaled result looks TERRIBLE compared to the original... that is because of the image being in a poorly supported BufferedImage type and Java2D falling back to using it's software rendering pipeline instead of the hardware accelerated one for better supported image types.

imgscalr will take care of all of that for you and keep the image in the best supported image type possible to avoid that.

Anyway, that is a REALLY long way of saying "You can use imgscalr to do all that for you and not have to worry about anything".

楠木可依 2024-08-02 03:43:50

也许这对您来说是一个解决方案:

public BufferedImage resizeImage(BufferedImage source, int width, int height)
{
     BufferedImage result = new BufferedImage(widht, height, BufferedImage.TYPE_INT_ARGB);
     Graphics g = result.getGraphics();
     g.drawImage(source, 0, 0, widht, height, null);
     g.dispose();
     return result;
}

maybe is this a solution for you:

public BufferedImage resizeImage(BufferedImage source, int width, int height)
{
     BufferedImage result = new BufferedImage(widht, height, BufferedImage.TYPE_INT_ARGB);
     Graphics g = result.getGraphics();
     g.drawImage(source, 0, 0, widht, height, null);
     g.dispose();
     return result;
}
忘你却要生生世世 2024-08-02 03:43:50

最后,升级到最新版本的 ImageVoodoo 似乎提高了质量。

查看源代码,看起来他们正在做一些时髦的 AWT 渲染,然后将其拉出来。 令人讨厌,但似乎有效。

仍然不如 ImageMagick,但比以前更好了。

In the end, upgrading to the latest version of ImageVoodoo seemed to improve quality.

Looking through the source code, it looks like they're doing some funky AWT rendering, and then pulling that out. Nasty, but it seems to work.

Still not as good as ImageMagick, but better than it was.

长亭外,古道边 2024-08-02 03:43:50

@Riyad,增量扩展的代码并不是“相当大”,而是相当小(正如您从 2007 年的帖子中看到的那样,http://today.java.net/pub/a/today/2007/04/ 03/perils-of-image-getscaledinstance.html#creating-scaled-instances)拥有一个提供其他选项的库可能很有用,但让一个库使用一个库是无意义的。

@Riyad, the code for incremental scaling isn't "decently large", it's quite small (As you can see from a post back in 2007, http://today.java.net/pub/a/today/2007/04/03/perils-of-image-getscaledinstance.html#creating-scaled-instances) having a library that gives other options might be useful, but making a library to use a library is nonsense.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文