【问题标题】:Compress JPEG image to specific quality level without using Bitmap#compress() method不使用 Bitmap#compress() 方法将 JPEG 图像压缩到特定质量级别
【发布时间】:2019-10-11 01:24:21
【问题描述】:

我想将位图(JPEG 图像)压缩到质量64,结果存储在字节数组中。以前我可以通过Bitmap#compress() 方法实现这一点:

public static byte[] compressJPEG(Bitmap bmp, int quality) {
    if (quality <= 0)
        return new byte[0];

    byte[] array = new byte[0];
    try {
        ByteArrayOutputStream bmpStream = new ByteArrayOutputStream();
        bmp.compress(Bitmap.CompressFormat.JPEG, quality, bmpStream);
        array = bmpStream.toByteArray();
        bmpStream.close();
    } catch (Exception e) {
        e.printStackTrace();
    }
    return array;
}

但是当我在不同的设备上运行它时,结果字节数组(具有相同的输入图像文件)是不同的。 (可能是因为它内部使用了nativeCompress()

检查后,我发现不同之处在于 Huffman 表、SOS 和图像数据部分,请参见: Diff check between 2 image photos

那么如何在不使用Bitmap#compress() 方法的情况下将JPEG 图像压缩到特定的质量级别?因为我真的希望结果字节数组在结构上相似。

【问题讨论】:

  • 你必须自己写压缩算法或者使用跨平台库
  • @emandt 谢谢你回答我的问题,所以如果我想创建一个结构相似的压缩 JPEG 图像,我有两个选择:编写我自己的压缩算法,或者将整个图像传输到服务器处理并发送回 Android/iOS?
  • 简而言之:是的。使用的算法可能会在每个操作系统次要/主要版本或实现中发生变化(即在索尼和三星设备之间),因此如果您期望“固定数据”,则不能使用它们。
  • 正如您在另一个问题中提到的,我相信如果您使用固定表(量化表和霍夫曼表),您的方法将有效。您甚至不需要 SOS(但您需要图像尺寸来重新创建它)或 EOI,尝试捆绑 libjpeg 本机代码,并使用固定表进行编码。您可以在 "Abbreviated datastreams and multiple images" 中了解如何操作。

标签: java android image image-processing jpeg


【解决方案1】:

JPEG 中没有“质量级别”的概念。它是一些编码器用来选择量化表的简写。 JPEG 压缩中有许多变量,包括扫描的类型和分解、样本、霍夫曼表选择和量化表选择。如果您使用的编码器中的任何一个不同,您将获得不同的输出。这是野兽的本性。

【讨论】:

  • 我想要的只是:将 img 大小减小 40-50% 左右,并且输出的 img 结构相似。所以我可以去掉App0DQTDHT作为固定头,只发送SoS和img数据(这样他们会发送得更快)。然后receiver可以合并固定header的数据来构建img。
  • 您可能需要一些 APPn 标记来定义文件类型,具体取决于您使用的解码器。您将需要实际引用的 DQT 和 DHT 标记。
猜你喜欢
  • 1970-01-01
  • 2013-01-04
  • 2021-07-03
  • 2018-10-15
  • 2010-12-12
  • 2013-02-22
  • 2014-03-22
  • 2012-05-16
相关资源
最近更新 更多