Phil,我不知道你最终选择了哪种解决方案,但是如果您:
我已经做了大量测试,并且渐进式缩放以及坚持使用得到良好支持的图像类型是关键——我看到亚历山大提到他仍然没有运气,这真是太糟糕了。
大约6个月前,我发布了imgscalr库(Apache 2),以解决“我想要这张图片的好看缩放副本,现在就做!”这样的问题,因为我在Stack Overflow上读到了10多个这样的问题。
标准用法如下:
BufferedImage img = ImageIO.read(...); // load image
BufferedImage scaledImg = Scalr.resize(img, 640);
BufferedImage img = ImageIO.read(...); // load image
BufferedImage scaledImg = Scalr.resize(img, Method.QUALITY, 800, 600);
目前在Java中,最受欢迎的两个开源图像调整库是:
此外,还有使用Java的Graphics2D
(请参见如何操作)的JDK方法,但其创建的结果常常质量较差,特别是缩小图像时。还有一个Java接口到ImageMagick,此处不再赘述,因为它需要外部工具。
- 默认设置下的Thumbnailator 0.4.8,无尺寸调整
- Photoshop CS5采用双三次算法
- ULTRA_QUALITY模式下的imgscalr 4.2,无尺寸调整
- Graphics2D (Java 8)采用渲染提示VALUE_INTERPOLATION_BICUBIC、VALUE_RENDER_QUALITY和VALUE_ANTIALIAS_ON
我把选择最佳结果的工作留给读者,因为这是主观的。一般来说,除了Graphics2D
之外,所有输出都很好。Thumbnailator生成的图像更锐利,非常类似于Photoshop的输出,而imgscalr的输出则相对柔和。对于图标/文本等,您需要更锐利的输出,而对于图片,则可能需要更柔和的输出。
这是一个非科学的基准测试,使用了工具和114个尺寸从大约96x96
到2560x1440
的图像,将其视为425%的图像创建:100%、150%、200%、300%和400%的比例版本(因此进行了114 * 5次缩放操作)。所有库都使用与质量比较相同的设置(因此是最高质量)。时间仅涉及缩放而不是整个过程。在i5-2520M上完成,配备8GB RAM和5次运行。
- Thumbnailator: 7003.0毫秒 | 6581.3毫秒 | 6019.1毫秒 | 6375.3毫秒 | 8700.3毫秒
- imgscalr: 25218.5毫秒 | 25786.6毫秒 | 25095.7毫秒 | 25790.4毫秒 | 29296.3毫秒
- Graphics2D: 7387.6毫秒 | 7177.0毫秒 | 7048.2毫秒 | 7132.3毫秒 | 7510.3毫秒
有趣的是,Thumbnailator 平均时间最快,只需6.9秒,其次是 Java2D,需要7.2秒,而 imgscalr 则需要26.2秒,这可能不公平,因为 imgscalr 设置为 ULTRA_QUALITY
,这似乎非常昂贵;将其设置为 QUALITY
后,平均时间更具竞争力,为11.1秒。
使用thumbnailator.jar调整图片大小并自定义质量。
paintComponent
方法中,它使用了六种不同的方法来调整图像大小。你尝试过所有六种方法来确定哪一种效果最好吗?我想要保持纵横比的最高质量调整大小。
尝试了几种方法并阅读了几篇文章。花费了两天时间,最后用简单的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();
}
}
}
经过几次令人沮丧的实验,我找到了以下 缩放评估 ,并在我的项目中采用了多通道方法。
为了做到这一点,我将 getScaledInstance() 方法复制到了我的缩略图生成器类中,改变了我的图像读取方法以使用 ImageIO(它返回一个 BufferedImage),现在我非常满意!
我将结果与在 Photoshop CS3 中进行的调整进行了比较,结果非常相似。