我有一个开放源代码的应用程序,它的照片上传到Facebook。 为了节省带宽,将照片上传(脸谱规定的最大大小限制)之前自动调整大小。 有几个人抱怨照片质量,而事实上,你可以看到其中的差别(参见本期一段试玩影像)。
所以我的问题是,什么是缩小在Java的图像(即照片)而不失品位的“最佳”的方式,或者至少,以最少的质量损失/文物?
你可以看到当前的代码,我在这里 (通过调整代码此页 )。
我有一个开放源代码的应用程序,它的照片上传到Facebook。 为了节省带宽,将照片上传(脸谱规定的最大大小限制)之前自动调整大小。 有几个人抱怨照片质量,而事实上,你可以看到其中的差别(参见本期一段试玩影像)。
所以我的问题是,什么是缩小在Java的图像(即照片)而不失品位的“最佳”的方式,或者至少,以最少的质量损失/文物?
你可以看到当前的代码,我在这里 (通过调整代码此页 )。
我已经尝试了一切-包括技巧在这里 ,和所有我能说你是使用ImageMagick与任何接口的更好,Java类成像图书馆只不涨,当谈到这个断气。 你需要支持这么多的格式和算法得到它的权利。
菲尔,我不知道哪个解决方案,你最终会去,但如果你在Java的图像缩放,可以看起来不错:
我已经做了这些方法和增量扩展一起坚持以及支持的图像类型的测试的公平份额的关键所在 - 我看到亚历山大提到他仍然没有得到它的好运气这是一个令人失望。
我发布了imgscalr库 (阿帕奇2)大约6个月前解决的问题“我要好看这一形象的缩放复印,现在就做!” 阅读像10分类似这样的问题上打完。
标准用法是这样的:
BufferedImage img = ImageIO.read(...); // load image
BufferedImage scaledImg = Scalr.resize(img, 640);
第二个参数是边界宽度和高度imgscalr将使用缩放图像-保持它的比例,即使你在尺寸无效传递正确的-还有很多更详细的方法 ,但是这是最简单的用法。
你想用例,例如如果Facebook局限于图像800x600像素,应该是这样的:
BufferedImage img = ImageIO.read(...); // load image
BufferedImage scaledImg = Scalr.resize(img, Method.QUALITY, 800, 600);
这将确保图像停留在最好的支持的图像类型和最高质量的方法,Java可以鼓起缩放。
在我自己的高分辨率测试我还没有发现使用这个库缩放的图像任何不符,张开/这些方法时,你的形象被倒入以ImageIO的加载器支持的不良图像类型EXCEPT - 例如,这种情况发生了很多与GIF格式。 如果你让他们这样的,没有得到他们脱离乏力的类型,它结束了仔细看还真抖动和可怕。
这样做的原因是,Java2D的团队实际上有各种不同类型的BufferedImages的不同硬件加速管道的JDK可以处理 - 这是不常见的图像类型的子集都回落到使用同一软件下的渲染管线涵盖的Java2D,导致较差,有时完全不正确的精美影像。 这是这样的PIA解释,并尝试弄清楚,我只是写了逻辑直接到库中。
最好的两个支持的类型有BufferedImage.TYPE_INT_RGB和_ARGB如果你是好奇。
两种最流行的开源库专业图像中的java调整目前主要有:
产生额外还有就是JDK的方式与Java的Graphics2D
( 见该怎么办呢这个问题 ),这是臭名昭著的创造坏的结果尤其是与缩小 。 还有一个Java接口到ImageMagick的 ,这将在这里,因为它需要一个外部工具被省略。
下面是调整大小/缩减一个的结果的比较580x852
PNG到145x213
。 作为参考的Photoshop CS5“另存为网页”是用来调整大小。 注:结果是1:1是什么创造了林达只是一起复制。 变焦没有使用任何过滤,只是一个简单的近邻算法。 在这里您可以找到原始图像。
- 使用默认设置,尺寸不调整Thumbnailator 0.4.8
- Photoshop CS5的与双三次算法
- imgscalr 4.2 ULTRA_QUALITY设置,没有尺寸调整
- 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缩放操作)。 所有库使用相同的设置,在质量上的比较(因此可能的最高品质)。 时间仅缩放不是整个过程。 完成与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
下面是在这个基准测试中使用的代码。
有趣的是Thumbnailator也最快,接着用的Java2D与7.2秒离去imgscalr后面与不良26.2秒 6.9秒的平均时间 。 因为imgscalr设置为这可能是不公平的ULTRA_QUALITY
这似乎是非常昂贵的; 与所述QUALITY
在一个更具有竞争力11.1秒设置它的平均值。
要使用自定义的使用质量thumbnailator.jar调整图像。
示例代码http://code.google.com/p/thumbnailator/wiki/Examples
什么呈现提示您使用的? 通常双三次重采样将是最好的。 在您链接到他们的照片都非常锯齿,这让我觉得你是使用最近的邻居作为你的暗示。
在PictureScaler你链接到,在类paintComponent
方法,它采用调整图像的六个不同的方式。 您是否尝试过所有六个看到提供了最好的结果呢?
一些令人沮丧的实验后,我发现下面的大小调整的评估 ,以及所采用的多通道方法在我的项目。
要做到这一点我复制了getScaledInstance()方法为我的缩略图生成器类,改变了我的图像读取方法使用的ImageIO(即一个返回一个BufferedImage),现在我很高兴 !
我比较了在Photoshop CS3进行大小调整的结果,其结果是大同小异。
我想最高质量保存宽高比调整。 试了几件事情,读几个条目。 失去了两天,最后我得到了最好的结果与普通的Java方法(也尝试ImageMagick的和Java的图像缩放库):
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();
}
}
}