我正在尝试使用Java和Scalr 3.2
创建此图像的高质量缩略图
这是相关的源代码,其中THUMB_WIDTH = 77
和THUMB_HEIGHT = 57
BufferedImage srcImg = ImageIO.read(new File(sourceFile));
BufferedImage dstImg = Scalr.resize(srcImg, Scalr.Method.QUALITY,
THUMB_WIDTH, THUMB_HEIGHT);
ImageIO.write(dstImg, format, new File(destFile));
如果我使用format = "png"
,结果如下:
如果我使用format = "jpg"
,结果如下:
使用imagemagick identify我发现JPEG的质量保存为75,完全不足以创建美观的缩略图。 PNG对我来说也不好看。
以下是原始文件的标识输出和两个缩略图:
$ identify 42486_1.jpg 42486_s1.jpg 42486_s1.png
42486_1.jpg JPEG 580x435 580x435+0+0 8-bit DirectClass 50.6KB 0.000u 0:00.000
42486_s1.jpg[1] JPEG 77x58 77x58+0+0 8-bit DirectClass 2.22KB 0.000u 0:00.000
42486_s1.png[2] PNG 77x58 77x58+0+0 8-bit DirectClass 12.2KB 0.000u 0:00.000
更新:通过网络搜索,我找到了一篇关于如何adjust JPEG image compression quality的文章。我编写了自己的方法来保存BufferedImage设置的质量:
/**
* 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 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();
}
}
以下是结果。 PNG:
JPEG质量75:
JPEG quality 90(stackoverflow上的gravatars保存为JPEG quality 90):
和filesize:
thumb90.jpg JPEG 77x58 77x58+0+0 8-bit DirectClass 6.89KB 0.000u 0:00.000
更新2 :测试将Scalr与java-image-scaling进行比较。
private void scaleAndSaveImageWithScalr(String sourceFile, String destFile, int width, int height)
throws IOException {
BufferedImage sourceImage = ImageIO.read(new File(sourceFile));
BufferedImage destImage = Scalr.resize(sourceImage, Scalr.Method.QUALITY, width, height);
writeJpeg(destImage, destFile, JPEG_QUALITY);
}
private void scaleAndSaveImageWithJImage(String sourceFile, String destFile, int width, int height)
throws IOException {
BufferedImage sourceImage = ImageIO.read(new File(sourceFile));
ResampleOp resampleOp = new ResampleOp(width, height);
resampleOp.setFilter(ResampleFilters.getLanczos3Filter());
resampleOp.setUnsharpenMask(AdvancedResizeOp.UnsharpenMask.Normal);
BufferedImage destImage = resampleOp.filter(sourceImage, null);
writeJpeg(destImage, destFile, JPEG_QUALITY);
}
使用Scalr生成的JPEG质量90:
使用java-image-scaling生成的JPEG quality 90:
我没有收到任何进一步的反馈,所以我的个人结论是java-image-scaling提供了卓越的质量,因此它是我选择的库。
答案 0 :(得分:1)
这不是您问题的完整答案,但是:
关于JPEG质量:
可以使用ImageWriteParam
作为described here来设置压缩质量。他们建议使用int
值0 | 1但我相信你应该实际指定一个介于0.0和1.0之间的浮点值。
关于缩放维度问题:
注意:如果提供的违反图像的宽度和高度 比例(例如,尝试将800×600图像的大小调整为150×150 方形)图书馆将首先查看图像的方向 (风景/广场或肖像)然后 选择主要维度 (横向或方形使用宽度,纵向使用高度)重新计算 正确的次要维度; 忽略用户传入的内容 这违反了比例。
在您的情况下,主要尺寸的宽度为77,因此您的高度限制为57将被忽略。
答案 1 :(得分:1)
@Stivlo,我很抱歉没有回复此事,我从未收到任何关于这个问题的通知。
java-image-scaling确实有一些很好的过滤器可以帮助你进行微调。也就是说,在imgscalr的v4.2中,我添加了新的ULTRA_QUALITY,可能会让你更接近你想要的。
我希望这会有所帮助,但不幸的是,事实发生这种情况已经差不多一年了。对不起。
答案 2 :(得分:0)
我已经运行了相同的测试,并且java-image-scaling明确地对于小于250px的缩略图有更好的结果。它还支持锐利过滤,使结果更好。
我保留了两个库,因为Scalr的语法通常更容易,只有一行。
答案 3 :(得分:0)
请注意,如果您的图片具有Alpha通道,则两个库都存在问题。我只是谈论缩小的图像,我还没有测试过放大它们。
java-image-scaling可能会根据图像在透明边缘周围创建一个丑陋的边框,这看起来非常糟糕。我发现没办法避免这种情况。
Scalr仅使用(超)质量模式存在问题。它可以很容易地以一种工作正常的方式使用:双三次插值会在透明图像中留下伪影,因此您可能希望避免它。因为它是(超)质量图像的默认值,并且scaleImageIncrementally()受到保护,你必须为此子类化,但是,如果你想要质量(高于2的分数看起来非常模糊,但是使用双线性过滤)。
答案 4 :(得分:0)
如果您想要高质量的结果,请使用[RapidDecoder] [1]库。它很简单如下:
import rapid.decoder.BitmapDecoder; ... 位图位图= BitmapDecoder.from(getResources(),R.drawable.image) .scale(宽度,高度) .useBuiltInDecoder(真) 。解码(); 如果你想缩小不到50%和HQ结果,不要忘记使用内置解码器。