缩减图像下载大小

大多数下载流量都包含图片。因此,您的可下载图片调整得越小,您的应用为用户提供的网络体验就越好。本页面提供了有关如何缩小图片文件以使其更适合网络下载的指导。

关于图片格式

Android 应用使用的图片通常采用以下一种或多种文件格式:AVIF、PNG、JPG 和 WebP。对于每种格式,您都可以采取相应步骤来缩减图片大小。

AVIF

Android 12(API 级别 31)及更高版本支持使用 AV1 图片文件格式 (AVIF) 的图片。AVIF 是一种使用 AV1 编码的图片和图片序列的容器格式。AVIF 利用了视频压缩的帧内编码内容。与以前的图片格式(例如 JPEG)相比,这种格式可显著提升相同文件大小下的图片质量。如需深入了解此格式的优势,请参阅 Jake Archibald 的博文

PNG

缩小 PNG 文件的关键是减少构成图片的每行像素所使用的单色数量。通过减少颜色的使用,您可以提高流水线所有其他阶段的压缩潜力。

减少单色的数量会带来显著变化,因为 PNG 压缩效果的部分决定因素是水平相邻像素颜色的变化程度。因此,减少 PNG 图片各行中的单色数量有助于缩小文件。

在决定是否采用这种策略时,您应该记住,减少单色的数量实际上是对图片实施了一个有损编码阶段。然而,编码工具可能无法很好地判断看似很小的误差在人眼中的严重程度。因此,您应该手动执行这项工作,以确保在高效压缩和可接受的图片质量之间保持适当的平衡。

您可以采取两种特别实用的方法:力求采用索引格式和应用矢量量化。

力求采用索引格式

每当您想要减少颜色数量时,都应该先尝试对颜色进行优化,从而可以在将图片导出为 PNG 时使用索引格式。索引色模式的原理是选择最适合使用的 256 种颜色,并将所有像素值替换为该调色板的索引。这样一来,颜色数量将从潜在的 1600 万种减少到只有 256 种,每像素字节数相应地从 3 字节(无透明度)或 4 字节(有透明度)减少到 1 字节。 第一步的这一变化就大大缩小了文件。

图 1 显示的是图片及其索引变体。

图 1. 转换为索引格式前后的图片。

图 2 显示了图 1 中图片的调色板:

图 2.图 1 中图片的调色板。

将图片表示为调色板图片对显著扩大文件大小大有帮助,因此如果大部分图片都可以转换,则有必要研究一下。

当然,并不是每张图片都能只用 256 种颜色就准确地呈现出来。 例如,某些图片可能需要 257、310、512 或 912 种颜色才能正常显示。在这种情况下,也可以借助矢量量化。

矢量量化

将创建索引图片的过程描述为矢量量化 (VQ) 可能更恰当。VQ 就是多维数的一个舍入过程。在此过程中,图片中的所有颜色都会根据它们的相似性进行分组。对于特定的组,该组中的所有颜色都会替换为单个“中心点”,以最大限度地减少该单元格(如果使用 Voronoi 术语则为“site”)中的颜色误差。在图 3 中,绿点代表输入颜色,红点代表替换输入颜色的中心点。每个单元格都以蓝线作为边界。

图 3.将矢量量化应用到图片中的颜色。

对图片应用 VQ 的结果会减少单色的数量,将每组颜色替换为视觉质量“非常接近”的单一颜色。

您还可以使用该技术来定义图片中的最大单色数量。例如,图 4 显示的是一个 1670 万种颜色(每像素 24 位,或 24 bpp)的鹦鹉头,旁边是仅允许使用 16 种 (3 bpp) 单色的版本。

图 4. 应用矢量量化之前和之后的图片。

您很快就会发现画质有所受损;大部分渐变颜色已被替换,从而让图片呈现出条纹效果。此图片需要超过 16 种单色。

在流水线中设置 VQ 步骤有助于您更清楚地了解图片所用单色的真实数量,并帮助您显著降低这些数量。您可以使用许多现成的工具来帮助您采用该技术。

JPG

如果您使用的是 JPG 图片,通过进行一些细微的更改,您有可能大幅缩小文件。其中包括:

  • 通过不同的编码方法生成较小的文件(不影响质量)。
  • 稍微调整质量以获得更好的压缩效果。

采用这些策略通常可以将文件缩小高达 25%。

在选择工具时,请记住,照片导出工具可能会在图片中插入不必要的元数据,例如 GPS 信息。您至少应尝试借助现有工具从文件中删除这些信息。

WebP

WebP 是 Android 4.2.1(API 级别 17)支持的较新图片格式。这种格式可为网络上的图片提供出色的无损压缩和有损压缩效果。 使用 WebP,开发者可以创建更小、更丰富的图片。WebP 无损图片文件比 PNG 平均缩小了 26%。这些图片文件还支持透明度(也称为 Alpha 通道),只需增加 22% 的字节。

WebP 有损图片比采用等效 SSIM 质量指标的同等 JPG 图片缩小 25-34%。对于可以接受有损 RGB 压缩的情况,有损 WebP 也支持透明度,生成的文件大小通常比 PNG 小 3 倍。

如需详细了解 WebP,请访问 WebP 网站

您可以使用 Android Studio 将现有 BMP、JPG、PNG 或静态 GIF 图片转换为 WebP 格式。如需了解详情,请参阅使用 Android Studio 创建 WebP 图片

选择格式

不同的图片格式适用于不同类型的图片。JPG 和 PNG 的压缩过程截然不同,产生的结果也差异显著。

PNG 和 JPG 之间的选择往往取决于图片本身的复杂程度。图 5 显示的两张图片因开发者采用不同的压缩方案而出现了截然不同的结果。左侧的图片包含许多小细节,因此使用 JPG 进行压缩的效率更高。右侧的图片包含连续的相同颜色,使用 PNG 进行压缩的效率更高。

图 5. 适合采用 JPG 或 PNG 的情况比较

WebP 格式支持有损和无损两种模式,对 PNG 和 JPG 来说都是理想的替代选择。唯一需要注意的是,它仅在搭载 Android 4.2.1(API 级别 17)及更高版本的设备上受到原生支持。幸运的是,大多数的设备都满足该要求。

图 6 提供了一个简单的可视化图形来帮助您决定应使用的压缩方案。

图 6. 确定压缩方案

确定最佳质量值

您可以使用多种技术在压缩效果和图片质量之间取得适当的平衡。其中一种技术使用标量值,因此仅适用于 JPG 和 WebP。另一种技术则利用了 Butteraugli 库,适用于所有图片格式。

标量值(仅限 JPG 和 WebP)

JPG 和 WebP 的强大之处在于,您可以使用标量值来平衡图片质量和文件大小。关键在于找出适合图片的质量值。质量级别太低会生成小尺寸文件,但图像质量受损。质量级别太高会增加文件大小,却对用户没有明显的益处。

最简单的解决方案是选择最大值以外的某个值,并使用该值。不过请注意,质量值会对每张图片产生不同的影响。例如,75% 的画质对于大多数图片来说可能效果不错,但也可能有一些效果不那么好的情况。您应确保根据图片的代表性样本测试所选的最大值。此外,请确保针对原始图片而不是压缩版本执行所有测试。

对于每天上传和重新发送数百万张 JPG 图片的大型媒体应用,对每个资源进行手动微调是不切实际的。如需解决这个难题,您可以根据图片类别指定多个不同的质量等级。例如,您可以将缩略图的质量级别设置为 35%,因为较小的图片会隐藏更多压缩失真。

Butteraugli

Butteraugli 项目是一个库,用于测试图片的心理视觉误差阈值,即查看者开始注意到图片质量下降的点。换句话说,此项目试图量化您的压缩图片的失真程度。

您可以使用 Butteraugli 定义视觉质量目标,然后运行 PNG、JPG、WebP 有损和 WebP 无损压缩。然后,您可以选择在文件大小和 Butteraugli 级别之间达到最佳平衡的图片。图 7 中的示例演示了如何使用 Butteraugli 找出最小的 JPG 质量级别,若低于该级别,则视觉失真会高到足以让用户察觉到问题;该操作使文件缩小了约 65%。

图 7. 应用 Butteraugli 技术之前和之后的图片。

Butteraugli 允许您根据输出或输入进行操作。也就是说,您可以查找用户不会感知到生成的图片会出现明显失真的最低质量级别设置,您也可以反复设置图片失真级别,以了解其相关的质量级别。

传送尺寸

开发者倾向于在服务器上只保存一种分辨率的图片。当设备访问图片时,服务器以该分辨率传送图片,然后由设备来完成缩小图片的任务。

该解决方案对于开发者来说非常方便,但对于用户来说可能比较麻烦,因为该解决方案迫使用户下载远远超过他们需求的数据。 您应改为存储多种尺寸的图片,并传送最适合特定用例的尺寸。例如,对于缩略图,比起先传送全尺寸版本再进行缩小,传送实际的缩略图所消耗的网络带宽要少得多

这种方法可以加快下载速度,对于可能使用有限流量或按流量计费的流量套餐的用户来说,成本也更低。此类操作还可以减少图片在设备和主内存中占用的空间。对于大型图片,例如 4K 图片,此方法还可使设备无需在加载图片之前调整图片大小。

如需采用此方法,您需要通过某种后端图片服务为各种分辨率的图片提供适当缓存。您可以借助一些现有的服务来完成这项任务。例如,App Engine 已经安装了图片大小调整功能。