📜  Android 中的图像压缩

📅  最后修改于: 2022-05-13 01:58:45.028000             🧑  作者: Mango

Android 中的图像压缩

在任何应用程序中,图像都起着至关重要的作用。它有助于更好地传达我们的信息。然而,它确实有很大的缺点。它扩展了 APK 的大小。您可能已经注意到处理照片的程序(无论是本地的还是从 Internet 下载的)的大小都较大,而且我们也知道应用程序的大小越小,它接收的下载量就越多。因此,如果我们减小程序中使用的照片的大小,APK 的大小也会随之减小。因此,在本文中,我们将学习图片压缩,以便将来如果您想在您的应用中使用图片,您只需参考此博客并选择最合适的图片格式来降低 APK 大小。

在本文中,我们将讨论以下主题:

  • 图像压缩的目的是什么?
  • WebP 图像、PNG 图像、矢量图像和 JPEG 图像

图像压缩的目的是什么?

将我们的信息传达给用户的最佳方式是通过图像。与文本相比,我们可以使用视觉更有效地表达信息。然而,照片的困难在于它们会迅速变得臃肿。过大或具有过多像素或分辨率的图像会降低应用程序的性能。例如,如果您的应用在 2G 网络上加载 5MB 的图像并且花费的时间太长,您可能会失去一位用户。下载图像不仅会消耗额外的带宽,还会耗尽电池。因此,确保应用程序中使用的图像经过压缩以提供更好的用户体验至关重要。

PNG

Portable Network Graphics 是当今 Android 中使用最广泛的图片格式。它们提供令人赏心悦目的高分辨率图像格式。但是,因此我们必须另外使用一些图片压缩技术。 PNG压缩是无损的,这意味着您可以从压缩版本中恢复原始图像,而不会丢失颜色。在 PNG 图像中,每一行像素都是单独获取和处理的。整个 PNG 压缩过程可以分为两个步骤。

  • 过滤:在这一步中,我们将跟踪每个像素的值,并计算该值与下一个或前一个像素的值之间的差异,或者向上或向下一个像素的值。因此,主要目标是实现尽可能小的差异。差异越小,色调越接近,压缩度越大。例如,如果图像仅包含红色,则压缩会更容易,因为那里只有一种颜色。所有像素的颜色都是相同的。
  • Deflate :过滤过程的输出使用 deflate 技术进行编码。在本例中,我们采用 LZ77 和 Huffman 编码器方法。

回顾这两个过程,如果图像的颜色可能性较少,则可能会进行更多的压缩,因为像素差将在 0 左右。但是,如果图像有大量的颜色选择,压缩就会出现问题。在 Android 上,我们可以使用 AAPT 工具对 PNG 图像进行上述操作。但是,使用它有一些缺点。那么让我们来看看 AAPT 为我们完成了什么:

  1. 它检查 PNG 文件以查看图像是否为灰度(只有白色和黑色)或具有多种颜色。
  2. 它确定图像是否具有透明通道或不透明。如果您的图像不透明,它将消除该通道并因此降低图像的大小。
  3. 确定图像中使用的颜色总数。如果小于或等于 256,则缩小图像尺寸。

在上图中可以看到三种颜色(绿色、白色)。但是,AAPT 正在尝试获取 256 种不同颜色的值,因此,图像的最终大小为 500KB。但是,减少颜色对图像质量没有影响,但会导致图像尺寸显着减小。例如,一张 125KB 的图像有 128 种颜色,一张 124B 的图像有 8 种颜色。

因此,首先优化您的 PNG(您可以使用 PNGQuant、TinyPNG、PNGOut 和其他工具来做到这一点),然后在您的应用程序中使用它。但是,您必须为您的应用程序禁用 AAPT 工具才能这样做,因为 AAPT 不知道您已经压缩了数据。

aaptOptions {
    cruncherEnabled = False
}

之后,您必须确保您使用的所有照片都已完全压缩,因为不再有用于图像压缩的 AAPT。

可绘制矢量

众所周知,PNG 文件本质上是光栅文件。因此,如果您要为多种设备尺寸构建应用程序,则必须为不同设备使用不同分辨率尺寸的照片(我们需要为 mdpi、hdpi、xhdpi 等提供单独的图像),这将增加你的应用程序。

结果,我们有很多相同图像的重复,这并不理想。如果一个图像可以在所有设备上使用,而不管分辨率如何?是的,在 Vector Drawables 的帮助下,我们可以做到这一点。用代码绘制图形的概念被称为 Vector Drawable。

这样做的好处是我们可以为具有不同分辨率的设备使用相同的可绘制图像,从而最大限度地减少 APK 大小,因为我们只需为所有设备使用一张图像。我们这里要做的是编写图片代码,在CPU内存中执行或光栅化为位图,然后上传到GPU,最终将图像渲染到设备的屏幕上。通过这种方式,您将获得更小的图像文件,但光栅化过程将花费更长的时间。您可以编写整个代码或使用名为 POTrace 的程序将您的 PNG 图像转换为矢量可绘制对象。但是,由于 POTrace 只是一种自动化技术,因此在使用由它生成的照片时要小心。因此,您不会总是收到理想的图像。但是,如果可能,对矢量图进行编码,您将始终获得所需的结果。

JPG

到目前为止,我们已经看到了 PNG 和 Vector Drawable,现在是时候转向 JPEG 或大图像了。因此,每当我们希望使用高质量的图像时,我们倾向于使用 JPEG,这就是我们关注 JPEG 压缩的原因。我们将源 RGB 图像更改为不同的色彩空间以进行 JPG 压缩。我们创建了一个独特的色彩空间,因为人眼注意到 RGB 的变化比 YCbCr 色彩空间中的变化更大。然后我们使用离散余弦变换来最小化 CB 和 CR 通道的大小。结果,任何信号都被转换或表示为余弦之和。此余弦变换的结果通过量化阶段发送,该阶段将输出转换为整数,然后是统计编码,可以是 Huffman、算术或任何其他编码,最后是 JPG 文件。唷,这是很多步骤:(

我们将源 RGB 图像更改为不同的色彩空间以进行 JPG 压缩。我们创建了一个独特的色彩空间,因为人眼注意到 RGB 的变化比 YCbCr 色彩空间中的变化更大。然后我们使用离散余弦变换来最小化 CB 和 CR 通道的大小。它只是一种压缩源图像的方法,以测试人眼如何感知各种图像质量之间的差异。因此,如果您想在压缩图像的同时确定可以压缩多少图像而人眼不会注意到差异,则可以使用 Butteraugli。您有想要使用的高分辨率图像吗?很酷,现在使用 Butteraugli 计算可以将图像压缩到多少百分比,然后进行压缩。这就是它的全部。同时,如果图像质量对您来说不是问题,您可以进一步压缩图像以获得更小的图像文件。

WebP

我们可以用无损和有损两种方式压缩 WebP 格式的图像。 WebP 图像在无损时比 PNG 图像小 26%。有损照片比 JPEG 文件小 25% 到 34%。为了对图像进行编码,WebP 采用了预测编码。因此,WebP 利用相邻块中的值来预测像素中的值,然后只对差异进行编码。另一方面,无损 WebP 压缩使用已经看到的图像片段重建新像素。如果没有识别出匹配,则使用本地调色板。

Android 中的图像压缩

结论

到目前为止,我们已经看到了我们每天看到的每种类型的图片压缩。如果您要在应用程序中使用图像,Vector drawable 应该是您的首选。如果您手头有可绘制的矢量,请利用它。如果您没有矢量可绘制对象和 WebP 支持,那么 WebP 就是要走的路。如果您无法访问 WebP 并且需要透明度,请使用 PNG。如果您不需要透明度,请确定图像是基本的还是复杂的。如果图片比较简单,选择PNG;如果图像更复杂,请使用 JPG。