使用Java JAI缩放图像

7

我需要使用Java JAI缩放图像。目前,我正在使用以下代码:

private static RenderedOp scale(RenderedOp image, float scale) {
    ParameterBlock scaleParams = new ParameterBlock();
    scaleParams.addSource(image);
    scaleParams.add(scale).add(scale).add(0.0f).add(0.0f);
    scaleParams.add(Interpolation.getInstance(Interpolation.INTERP_BICUBIC_2));

    // Quality related hints when scaling the image
    RenderingHints scalingHints = new RenderingHints(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
    scalingHints.put(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
    scalingHints.put(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
    scalingHints.put(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
    scalingHints.put(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
    scalingHints.put(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
    scalingHints.put(JAI.KEY_BORDER_EXTENDER, BorderExtender.createInstance(BorderExtender.BORDER_COPY));

    return JAI.create("scale", scaleParams, scalingHints);
}

很不幸,这导致非常糟糕的结果,特别是因为我经常需要使用小于0.5的比例因子缩放图像... 有什么建议吗?

这行代码看起来可疑 scaleParams.add(scale).add(scale).add(0.0f).add(0.0f); - whatnick
一些样本结果来说明你所说的“不好”的含义,也有助于确定你所遇到的工件类型。 - whatnick
有没有不使用 AffineTransformOp 的理由?请参见 http://stackoverflow.com/questions/4216635 - trashgod
1
@whatnick,你肯定从没用过JAI,那是相当标准的;@Myniva:请定义“bad”。 - Mark Elliot
@mark-e中的“bad”表示别名(http://en.wikipedia.org/wiki/Aliasing)。 - Basil
1
我找到了另一篇涵盖此问题的文章:http://blogs.warwick.ac.uk/mmannion/entry/using_subsample_averaging/ 我会尽快尝试这个解决方案,并在这里报告结果。 - Basil
3个回答

16
我猜想你正在尝试将较大的图像缩小到缩略图大小或者进行类似于原始图像到缩放图像的巨大变化?如果是这样,实际上Chris Campbell在2007年就曾经讨论过这个问题(我并不指望你知道这件事,只是想指出这是一个常见的问题),因为新的Java2D缩放方法(RenderingHints.VALUE_INTERPOLATION_*)没有提供与当时弃用的Image.getScaledInstance(SCALE_AREA_AVERAGING或SCALE_SMOOTH)方法相当的等效方法。结果证明,旧版Java 1.1 Image.getScaledInstance方法中的SCALE_AREA_AVERAGING或SCALE_SMOOTH方法是一个相当昂贵、多步骤的操作,在后台执行了很多工作来生成那个漂亮的图像。Chris指出,使用Java2D获取相同结果的新的和“正确”的方法是一个逐渐缩小图像的过程,直到达到所需的图像大小,最好使用更高质量的比例,如RenderHints.VALUE_INTERPOLATION_BICUBIC或BILINEAR。结果几乎与人们想要的原始Image.getScaledInstance方法一样。我实际上在几个月前寻找这个答案,当时我正在编写一个图像托管服务,惊讶于“如何在Java中制作漂亮的缩略图?”这个简单问题变得如此复杂。最终,我创建了一个小型的Java库(Apache 2,开源),使用“最佳实践”实现了3种不同的图像缩放方法,包括Chris建议的逐渐缩小的方法。

这个库叫做imgscalr。你可以简单地下载并使用它,如下所示:

BufferedImage thumbnail = Scalr.resize(srcImage, 150);

有更多的选项可供设置和使用(例如缩放的质量或速度),但开箱即用,所有内容都有智能默认值,以便为您创建一个漂亮的缩放图像,如果您不想担心更多问题,也可以不必担心。该库还会尽力处理和避免任何不绝对必要的对象分配,并立即处理不需要的BufferedImage实例——它旨在作为长时间运行的服务器应用程序的一部分进行编码,因此这是至关重要的。
我已经发布了几个版本的库,如果您愿意,只需提取“好东西”并自己处理。它全部在GitHub上,没有任何机密信息,只是为了让人们的生活变得更加轻松的尝试。
希望这可以帮到您。

这个库听起来非常有趣。我喜欢它的介绍和动机,我的早期示例也运行良好。我们还没有采用它(暂时),需要进一步分析。 - Michael Easter
@MichaelEaster 很高兴听到目前进展顺利;我期待任何额外的反馈! - Riyad Kalla

3

我用Thumbnailator获得了很好的结果。我不知道JAI.KEY_BORDER_EXTENDER应该做什么,但我猜测其他功能(抗锯齿、抖动等)都被支持了。 我用它来生成相当大的黑白图像的灰度缩略图。


1

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