【问题标题】:How to get a good quality thumbnail如何获得高质量的缩略图
【发布时间】:2011-10-12 15:02:32
【问题描述】:

我正在尝试使用 Java 和 Scalr 3.2

创建此图像的高质量缩略图

这是相关的源码,其中THUMB_WIDTH = 77THUMB_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

问题

  • 如何提高生成缩略图的质量?
  • 如何保存更高质量的 JPEG?我想尝试更高的质量并比较结果。我在 ImageIO.write 的 JavaDoc 中找不到任何内容。
  • 为什么我告诉 Scalr 我的最大尺寸是 77x57,它输出的图像是 77x58?我认为这是保持比例,但那些是我的最大宽度和最大高度。宽度或高度可以更小,但不能更大。

更新:通过网络搜索,我发现了一篇关于如何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();
    }
}

这是结果。巴布亚新几内亚:

JPEG 质量 75:

JPEG 质量 90(stackoverflow 上的头像保存为 JPEG 质量 90):

和文件大小:

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 质量 90:

我没有收到任何进一步的反馈,所以我个人的结论是 java-image-scaling 提供了卓越的质量,所以它是我选择的库。

【问题讨论】:

  • 嗨@Riyad,感谢分享Scalr。我正在尝试,遇到了一些困难,你能看一下给我提示吗?
  • writeJpeg() 需要在 finally 块中调用 writer.dispose()output.close() 来释放这些资源!
  • @user113215,谢谢,我已经按照建议更新了示例代码。
  • 感谢分享 writeJpeg() 方法!这是 Scalr.resize 缺少的拼图。

标签: java java-2d image-resizing scalr


【解决方案1】:

@Stivlo,我很抱歉没有回复这个问题,我从来没有收到任何关于这个问题的通知。

java-image-scaling 确实有一些不错的过滤器可以帮助您在需要时进行微调。也就是说,在 imgscalr 的 v4.2 中,我添加了新的 ULTRA_QUALITY,它可能会让您更接近您想要的。

我希望这会有所帮助,但不幸的是,这是在事实发生近一年后才回复的。对此感到抱歉。

【讨论】:

    【解决方案2】:

    这不是您问题的完整答案,但是:

    关于 JPEG 质量:

    可以使用ImageWriteParam 将压缩质量设置为described here。他们建议使用 0|1 的 int 值,但我认为您实际上应该指定一个介于 0.0 和 1.0 之间的浮点值。

    关于缩放维度问题:

    来自Scalr homepage

    注意:如果提供的宽度和高度违反了图像的 比例(例如,尝试将 800×600 的图像调整为 150×150 square) 库将首先查看图像的方向 (横向/正方形或纵向),然后 选择主要维度 (横向或正方形使用宽度,纵向使用高度)重新计算 正确的二级尺寸; 忽略用户传入的内容 这违反了比例。

    在您的情况下,主要尺寸将是 77 的宽度,因此您的 57 高度限制将被忽略。

    【讨论】:

    • 谢谢teabot +1,我会添加我的包装然后缩小其中一个尺寸,这样我就可以适应我的空间了。
    • 嗨@teabot,我也试过java-image-scaling,如果你有时间可以看看我问题底部的两个拇指吗?如果你看一下前后轮、油箱、座椅和发动机下方等细节,最后一张图片在我看来不那么像素化和自然,你同意吗?
    【解决方案3】:

    我已经运行了相同的测试,java-image-scaling 对于小于 250 像素的缩略图肯定有更好的结果。它还支持锐利过滤,使结果更好。

    我保留了这两个库,因为 Scalr 的语法通常更简单,只有一行。

    【讨论】:

      【解决方案4】:

      请注意,如果您的图像具有 Alpha 通道,则这两个库都有问题。我只是在谈论缩小图像,我没有测试过放大它们。

      java-image-scaling 可能会根据图像在透明边缘周围创建丑陋的边框,这看起来很糟糕。我没有办法避免这种情况。

      Scalr 只有在使用(超)质量模式时才有问题。但是,它可以很容易地以一种可以正常工作的方式使用:双三次插值会在透明图像中留下伪影,因此您可能希望避免它。由于它是(超)质量图像的默认值,并且 scaleImageIncrementally() 受到保护,但是如果您想要质量,则必须为此对其进行子类化(但是,对于双线性过滤,高于 2 的分数看起来非常模糊)。

      【讨论】:

      • “我没有办法避免这种情况。”摆脱 Alpha 通道? Afaict,这将是擦除内存缓冲区中所有第 4 个字节的问题。
      • 如果我有透明图像,我通常不想去掉 alpha 通道。我说的是避免在生成的缩略图中出现不需要的伪影。
      • 对不起,你当然是对的。但是,如果您正在生成 JPG,那么摆脱 alpha 通道通常很好:)
      【解决方案5】:

      如果您想要高质量的结果,请使用 [RapidDecoder][1] 库。很简单,如下:

      导入 rapid.decoder.BitmapDecoder; ... 位图位图 = BitmapDecoder.from(getResources(), R.drawable.image) .scale(宽度,高度) .useBuiltInDecoder(true) 。解码(); 如果您想缩小不到 50% 并获得 HQ 结果,请不要忘记使用内置解码器。

      【讨论】:

        猜你喜欢
        • 2014-04-07
        • 1970-01-01
        • 2011-10-11
        • 2011-10-11
        • 1970-01-01
        • 1970-01-01
        • 2011-06-07
        • 2011-08-05
        • 2021-01-26
        相关资源
        最近更新 更多