首页 文章

在创建JPEG时,我可以更改Java的ImageWriter使用的压缩算法吗?

提问于
浏览
5

或者,是否有更好的库来处理压缩?

让我用我已经理解的内容作为序言:(1)JPEG是有损的 - 它看起来与输入文件不一样 . (2)我可以将压缩质量设置调整到0.0到1.0之间,正如我在下面的代码中所做的那样 .

我正在使用BufferedImage并将其转换为JPEG,并注意到Java的ImageWriter的.write()方法为JPEG图像生成了低于标准的结果(与Photoshop“Save for Web”相比,作为示例) .

我的代码现在看起来有点像这样:

// img is a BufferedImage, here
ImageWriter writer = ImageIO.getImageWritersByFormatName("jpeg").next();
ImageWriteParam iwp = writer.getDefaultWriteParam();
iwp.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
iwp.setCompressionQuality(.75f);

IIOImage image = new IIOImage(img, null, null);
ByteArrayOutputStream byteArrayOut = new ByteArrayOutputStream();
writer.setOutput(ImageIO.createImageOutputStream(byteArrayOut));
writer.write(null, image, iwp);
writer.dispose();

使用压缩质量设置会产生不同的质量输出,但即使设置为“1.0”,它们也不像创建JPEG时的其他工具那样好 .

自从我发布图片后here's a webpage that demos the differences . 希望我可以在某些时候永久地让他们进入这里,以便将来可能有类似问题的用户 .

显然,这个特定的图像不是JPEG压缩的最佳候选者(PNG更小,无损),但它可以更容易地看到压缩伪像 . 实际的图像本质上主要是摄影的 . 至少,这更多地质疑Java的JPEG压缩算法和质量,而不是那些产生更接近原始图像的图像 .

1 回答

  • 5

    “Java的ImageWriter的.write()方法为JPEG图像生成低于标准的结果(与Photoshop”Save for Web“相比,作为一个例子) . ”

    出现这种情况的原因不止一个,将Java imageio生成的图像质量与专业图像软件作为photoshop进行比较是不公平的 .

    无论如何,让我们看看图像中的工件最可能的原因是:通常对于将图像保存为JPEG的软件,它将允许用户指定参数作为压缩或质量,一个是另一个的反转 . 该参数用于缩放量化过程中使用的量化表,这是JPEG丢失的最重要因素 . 不同的编码器可以使用不同的量化表,其部分地考虑图像质量差异 .

    但是可能存在影响压缩和图像质量的其他因素,其中色度子采样(或下采样)实际上在量化过程之前发生 . 色度子采样是以比原始分辨率更低的分辨率对图像中的颜色信息进行采样的过程 . 有关更好的解释,请阅读 this 文章 .

    Calvin Hass提供了一种优秀的JPEG阻尼工具,名为JPEGSnoop,可以从http://www.impulseadventure.com下载 . 在您提供的ps75.jpg图像上使用此工具,我发现以下输出与色度子采样有关:

    Component[1]: ID=0x01, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y)
     Component[2]: ID=0x02, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x01 (Chrom: Cb)
     Component[3]: ID=0x03, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x01 (Chrom: Cr)
    

    这意味着没有对颜色组件进行子采样 . 另一方面,100.jpg和75.jpg的子排列部分是相同的:

    Component[1]: ID=0x01, Samp Fac=0x22 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y)
     Component[2]: ID=0x02, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cb)
     Component[3]: ID=0x03, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cr)
    

    这意味着通过取两个连续像素的平均值,在颜色分量的水平和垂直方向上进行了二次调整 .

    当原始图像由条带和/或正方形组成时,色度子采样对图像质量的影响将是最显着的,并且您已经注意到这里的工件更容易被看到 .

    因此,IMO,对于这种特殊情况,问题更多来自色度子采样而不是质量因子设置 . 也许我没有挖得足够深,但是我找不到设置imageio的采样因子或者它背后的ImageWriter(最有可能是com.sun.imageio.plugins.jpeg.JPEGImageWriter)的方法,尽管它似乎可以设置ImageWriter使用的量化和Huffman表 .

    因此,除非您为imageio编写自己的ImageWriter插件或作为独立插件,否则不太可能更改Java的ImageWriter使用的压缩算法 . 但考虑到JEPG压缩算法的复杂性,两者都是非平凡的 . 有一个相对容易遵循的James JpegEncoder实现由James R. Weeks编写,默认情况下不进行色度子采样 . 它曾经是免费的,但您可以通过搜索网络找到原始版本 .

    另一件有趣的事情是:从JPEGSnoop的输出中,photoshop保存的75%JPEG图像的实际品质因数实际上显示为92%左右 . 以及引用的文字来自Calvin Hass的网站将回答为什么photoshop在你的情况下不使用子采样的问题:

    另外,请注意Photoshop CS2使用不同的色度子采样级别,具体取决于“保存JPEG质量”设置:

    Photoshop Save As Quality 0-6 - 2x2 Chroma Subsampling
    Photoshop Save As Quality 7-12 - 1x1 No Chroma Subsampling
    Photoshop Save For Web Quality 0-50 - 2x2 Chroma Subsampling
    Photoshop Save For Web Quality 51-100 - 1x1 No Chroma Subsampling
    

    查看this Java图像库,它也可以编写JPEG图像 .

相关问题