图像调整质量(Java)

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1625137/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 17:57:04  来源:igfitidea点击:

Image resize quality (Java)

javaimageresizejpegphoto

提问by

I have an open-source app which uploads photos to Facebook. To save bandwidth, the photos are automatically resized before uploading (Facebook imposes a maximum size limit). A few people have complained about the photo quality, and in fact you can see the difference (see this issuefor some demo images).

我有一个开源应用程序,可以将照片上传到 Facebook。为了节省带宽,照片会在上传前自动调整大小(Facebook 设置了最大大小限制)。一些人抱怨照片质量,实际上您可以看到差异(请参阅此问题以获取一些演示图像)。

So my question is, what is the "best" way of scaling down images (i.e. photos) in Java without losing quality, or at least, with minimal quality loss / artifacts?

所以我的问题是,在 Java 中缩小图像(即照片)而不会降低质量,或者至少以最小的质量损失/伪影缩小图像(即照片)的“最佳”方法是什么?

You can see the current code I have here(resize code via this page).

您可以在此处查看我的当前代码(通过此页面调整代码大小)。

采纳答案by Alexander Torstling

I've tried it all - including the tricks here, and all I can say that you're better of using ImageMagick with whatever interface, Javas imaging libraries are just not up to snuff when it comes to this. You need to support so many formats and algorithms to get it right.

我已经尝试了所有 - 包括这里的技巧,而且我只能说您最好将 ImageMagick 与任何接口一起使用,Java 成像库在这方面并不能满足要求。您需要支持如此多的格式和算法才能使其正确。

回答by Kip

What rendering hint are you using? Usually bicubic resampling will be the best. In the photos you are linking to they are very jaggy, which makes me think you are using nearest neighbor as your hint.

你使用什么渲染提示?通常双三次重采样将是最好的。在您链接到的照片中,它们非常参差不齐,这让我觉得您正在使用最近的邻居作为提示。

In the PictureScalerclass that you link to, in the paintComponentmethod, it uses six different means of resizing the image. Have you tried all six to see which gives the best result?

在您链接到的PictureScaler类的paintComponent方法中,它使用六种不同的方法来调整图像大小。您是否尝试了所有六个,看看哪个给出了最好的结果?

回答by Tom

After a few frustrating experiments I found the following resize evaluation, and employed the multi-pass approach in my project.

经过几次令人沮丧的实验后,我发现了以下调整大小评估,并在我的项目中采用了多通道方法。

To do that I copied the getScaledInstance() method into my thumbnail generator class, changed my image read approach to use ImageIO (that one returns a BufferedImage) and am now very happy!

为此,我将 getScaledInstance() 方法复制到我的缩略图生成器类中,将我的图像读取方法更改为使用 ImageIO(该方法返回 BufferedImage),现在我很高兴

I compared the result with a resize done in Photoshop CS3 and the result is very much the same.

我将结果与在 Photoshop CS3 中完成的调整大小进行了比较,结果非常相似。

回答by Riyad Kalla

Phil, I don't know which solution you eventually went with, but scaling images in Java can look pretty good if you:

Phil,我不知道您最终采用了哪种解决方案,但是如果您:

  • Avoid BufferedImage types that aren't well supported by the JDK.
  • Use incremental scaling
  • Stick to bicubic when using incremental scaling
  • 避免使用 JDK 不太支持的 BufferedImage 类型。
  • 使用增量缩放
  • 使用增量缩放时坚持双三次

I've done a fair share of testing with these methods and the incremental scaling along with sticking to well supported image types is the key -- I see Alexander mentioned he still didn't get good luck with it which is a bummer.

我已经对这些方法进行了相当多的测试,增量缩放以及坚持支持良好的图像类型是关键——我看到亚历山大提到他仍然没有获得好运,这真是令人失望。

I released the imgscalr library(Apache 2) about 6 months ago to address the issue of "I want good-looking scaled copies of this image, DO IT NOW!" after reading something like 10 questions like this on SO.

我在大约 6 个月前发布了imgscalr 库(Apache 2)来解决“我想要这张图片的漂亮缩放副本,现在就做!”的问题。在阅读了诸如此类的 10 个问题之后。

Standard usage looks like:

标准用法如下所示:

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

The 2nd argument is the bounding width and height imgscalr will use to scale the image -- keeping its proportions correct even if you passed in invalid dimensions -- there are many more detailed methods, but that is the simplest usage.

第二个参数是 imgscalr 将用于缩放图像的边界宽度和高度 - 即使您传入无效尺寸也保持其比例正确 - 有许多更详细的方法,但这是最简单的用法。

The use-case you would want, for example if Facebook limited images to 800x600 pixels, would look like this:

您想要的用例,例如,如果 Facebook 将图像限制为 800x600 像素,则如下所示:

BufferedImage img = ImageIO.read(...); // load image
BufferedImage scaledImg = Scalr.resize(img, Method.QUALITY, 800, 600);

That will ensure the image stays in the best supported image type and scaled with the highest quality method that Java can muster.

这将确保图像保持最佳支持的图像类型,并使用 Java 可以收集的最高质量方法进行缩放。

In my own high-resolution testing I have not noticed any gaping discrepancies with scaled images using this library/these methods EXCEPT when your image gets put into a poorly supported image type by the ImageIO loader -- for example, this happens a lot with GIFs. If you leave them like that and don't get them out of those poorly supported types, it ends up looking really dithered and terrible.

在我自己的高分辨率测试中,我没有注意到使用这个库/这些方法的缩放图像有任何巨大的差异,除了当你的图像被 ImageIO 加载器放入支持不佳的图像类型时——例如,这种情况在 GIF 中经常发生. 如果你就这样离开它们并且不让它们摆脱那些支持不佳的类型,它最终看起来真的很烦躁和可怕。

The reason for this is that the Java2D team actually has different hardware accelerated pipelines for all the different types of BufferedImages that the JDK can process - a subset of those image types that are less common all fall back to using the same software rendering pipeline under the covers in Java2D, resulting in poor and sometimes totally incorrect looking images. This was such a PIA to explain and try and figure out that I just wrote that logic directly into the library.

这样做的原因是 Java2D 团队实际上对 JDK 可以处理的所有不同类型的 BufferedImages 有不同的硬件加速管道——那些不太常见的图像类型的子集都回退到使用相同的软件渲染管道下覆盖在 Java2D 中,导致图像质量不佳,有时甚至完全不正确。这是一个 PIA 来解释和尝试弄清楚我只是直接将该逻辑写入库中。

The two best supported types are BufferedImage.TYPE_INT_RGB and _ARGB if you are curious.

如果您好奇的话,两种最受支持的类型是 BufferedImage.TYPE_INT_RGB 和 _ARGB。

回答by SAN

To resize image with custom quality use thumbnailator.jar.

要使用自定义质量调整图像大小,请使用thumbnailator.jar。

Example Code http://code.google.com/p/thumbnailator/wiki/Examples

示例代码 http://code.google.com/p/thumbnailator/wiki/Examples

回答by Mladen Adamovic

I wanted highest quality resize with aspect ratio preserved. Tried few things and read several entries. Lost two days and in the end I got the best result with plain Java method (tried also ImageMagick and java-image-scaling libraries):

我想要保留纵横比的最高质量调整大小。尝试了几件事并阅读了几个条目。失去了两天,最后我用纯 Java 方法得到了最好的结果(也尝试了 ImageMagick 和 java-image-scaling 库):

public static boolean resizeUsingJavaAlgo(String source, File dest, int width, int height) throws IOException {
  BufferedImage sourceImage = ImageIO.read(new FileInputStream(source));
  double ratio = (double) sourceImage.getWidth()/sourceImage.getHeight();
  if (width < 1) {
    width = (int) (height * ratio + 0.4);
  } else if (height < 1) {
    height = (int) (width /ratio + 0.4);
  }

  Image scaled = sourceImage.getScaledInstance(width, height, Image.SCALE_AREA_AVERAGING);
  BufferedImage bufferedScaled = new BufferedImage(scaled.getWidth(null), scaled.getHeight(null), BufferedImage.TYPE_INT_RGB);
  Graphics2D g2d = bufferedScaled.createGraphics();
  g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
  g2d.drawImage(scaled, 0, 0, width, height, null);
  dest.createNewFile();
  writeJpeg(bufferedScaled, dest.getCanonicalPath(), 1.0f);
  return true;
}


/**
* Write a JPEG file setting the compression quality.
*
* @param image a BufferedImage to be saved
* @param destFile destination file (absolute or relative path)
* @param quality a float between 0 and 1, where 1 means uncompressed.
* @throws IOException in case of problems writing the file
*/
private static void writeJpeg(BufferedImage image, String destFile, float quality)
      throws IOException {
  ImageWriter writer = null;
  FileImageOutputStream output = null;
  try {
    writer = ImageIO.getImageWritersByFormatName("jpeg").next();
    ImageWriteParam param = writer.getDefaultWriteParam();
    param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
    param.setCompressionQuality(quality);
    output = new FileImageOutputStream(new File(destFile));
    writer.setOutput(output);
    IIOImage iioImage = new IIOImage(image, null, null);
    writer.write(null, iioImage, param);
  } catch (IOException ex) {
    throw ex;
  } finally {
    if (writer != null) {
      writer.dispose();
    }
    if (output != null) {
      output.close();
    }
  }
}

回答by Patrick Favre

The two most popular open source libs specializing in image resizing in java currently are:

目前在 Java 中专门用于图像大小调整的两个最流行的开源库是:

Additonal there is the JDK way with Java's Graphics2D(see this question on how to do it) which is notorious to create bad results especially with downscaling. There is also a Java interface to ImageMagickwhich will be omitted here because it requires an external tool.

此外,还有 Java 的 JDK 方式Graphics2D请参阅有关如何操作的问题),这是众所周知的,尤其是在缩小规模时会产生不良结果。还有一个ImageMagickJava 接口,这里将省略,因为它需要一个外部工具。

Visual Quality

视觉质量

Here is a comparison of the results of resizing/downscaling a 580x852png to 145x213. As reference Photoshop CS5 "save for web" resizing is used. Note: the results are 1:1 what the libs created just copied together. The zoom does not use any filtering, just a simple nearest neighbor algorithm.Here you can find the original image.

这是将580x852png大小调整/缩小到145x213. 作为参考,使用 Photoshop CS5“另存为 Web”调整大小。注意:结果是 1:1 刚刚创建的库复制到一起。缩放不使用任何过滤,只是一个简单的最近邻算法。在这里你可以找到原始图像。

comparison

比较

  1. Thumbnailator 0.4.8 with default settings, no dimension adjustments
  2. Photoshop CS5 with bicubic algorithm
  3. imgscalr 4.2 with ULTRA_QUALITY setting, no dimension adjustments
  4. Graphics2D (Java 8) with render hints VALUE_INTERPOLATION_BICUBIC, VALUE_RENDER_QUALITY, VALUE_ANTIALIAS_ON
  1. 缩略图 0.4.8 默认设置,无尺寸调整
  2. Photoshop CS5 与双三次算法
  3. 带有 ULTRA_QUALITY 设置的 imgscalr 4.2,无尺寸调整
  4. Graphics2D (Java 8) 与渲染提示 VALUE_INTERPOLATION_BICUBIC、VALUE_RENDER_QUALITY、VALUE_ANTIALIAS_ON

I leave it to the reader to select the best result as this is subjective. Generally, all have good output except Graphics2D. Thumbnailator generates sharper images very similar to Photoshop output, whereas imgscalr's output is considerably softer. For icons/text etc. you want a sharper output, for pictures you may want softer output.

我留给读者选择最佳结果,因为这是主观的。一般来说,除了Graphics2D. Thumbnailator 生成与 Photoshop 输出非常相似的更清晰的图像,而 imgscalr 的输出要柔和得多。对于图标/文本等,您需要更清晰的输出,对于图片,您可能需要更柔和的输出。

Computational Time

计算时间

Here is non-scientific benchmark using this tooland 114 images with dimension from about 96x96up to 2560x1440treating it as 425% images creating: 100%, 150%, 200%, 300% and 400% scaled versions of it (so 114 * 5 scaling operations). All libs use the same settings as in the quality comparison (so highest quality possible). Times are only scaling not the whole process. Done on a i5-2520M with 8GB Ram and 5 runs.

这是使用此工具的非科学基准测试和 114 张尺寸从大约96x962560x1440将其视为 425% 图像创建的图像:100%、150%、200%、300% 和 400% 缩放版本(因此 114 * 5 缩放操作)。所有库都使用与质量比较中相同的设置(因此可能达到最高质量)。时间只是在缩放而不是整个过程。在具有 8GB 内存和 5 次运行的 i5-2520M 上完成。

  • Thumbnailator: 7003.0ms | 6581.3ms | 6019.1ms | 6375.3ms | 8700.3ms
  • imgscalr: 25218.5ms | 25786.6ms | 25095.7ms | 25790.4ms | 29296.3ms
  • Graphics2D: 7387.6ms | 7177.0ms | 7048.2ms | 7132.3ms | 7510.3ms
  • 缩略图:7003.0ms | 6581.3ms | 6019.1ms | 6375.3ms | 8700.3ms
  • imgscalr: 25218.5ms | 25786.6ms | 25095.7ms | 25790.4ms | 29296.3ms
  • Graphics2D:7387.6ms | 7177.0ms | 7048.2ms | 7132.3ms | 7510.3ms

Here is the code used in this benchmark.

这是此基准测试中使用的代码。

Interestingly Thumbnailator is also the fastest with an average time of 6.9 secfollowed by Java2D with 7.2 secleaving imgscalr behind with a poor 26.2 sec. This is probably not fair since imgscalr is set to ULTRA_QUALITYwhich seems to be extremely expensive; with the QUALITYsetting it averages at a more competitive 11.1 sec.

有趣的是,Thumbnailator 也是最快的,平均时间为 6.9 秒,其次是Java2D,为 7.2 秒,imgscalr 则为 26.2 秒。这可能是不公平的,因为 imgscalr 设置为ULTRA_QUALITY似乎非常昂贵;与QUALITY在一个更具有竞争力11.1秒设置它的平均值。