PNG 图片压缩

Pngquant

既然是缩减包大小,当然是有损压缩收益更高,而且,人眼对于图像之间的细微差异根本难以辩别,所以,我们选择有损压缩。

无论是从压缩效果和使用便利性来看,pngquant在新窗口打开 的表现都是相当令人惊艳,但是有一个很重要的问题,pngquant在新窗口打开 虽然是开源软件,但它是 GPL License在新窗口打开,而 Booster 是 Apache License在新窗口打开,如何既能避开法务风险,又能使用优秀的 GPL License在新窗口打开 软件呢?

Command SPI

为了解决开源协议的冲突问题,Booster 专门为此提供了 Command SPI在新窗口打开,将 API 与实现进行分离,API 采用 Apache License在新窗口打开,实现采用 GPL License在新窗口打开,通过 SPI (Service Provider Interface)在新窗口打开 完美的解决了这一问题。

Pngquant Provider

booster-pngquant-provider在新窗口打开 作为 pngquant 命令的提供者,采用 GPL License在新窗口打开 独立开源,目前内置了 Linux, macOS, Windows 三个平台的 pngquant 二进制可执行文件 64 位版本。

实现思路

根据 Android 的构建流程,我们选择在 mergeRes 和 processRes 任务之间插入 PNG 压缩任务,如下图所示:

自 AGP 3.0.0 开始,AAPT2 默认会被开启,由于 AAPT2 采用了 AAPT2 Container 格式在新窗口打开 (文件后缀为 .flat) 所以,需要在压缩之前需要明确,项目中是否开启 android.enableAapt2 的选项,因此 Booster 根据 AAPT2 选项分不同的 task 来处理:

注意

由于 AAPT 1.0 已经成为过去式,Booster 只支持启用 AAPT2 的情况。

如何使用

在使用 booster-task-compression-pngquant在新窗口打开 的时候,还需要引入 booster-pngquant-provider在新窗口打开,如下所示:

buildscript {
    ext {
        kotlin_version = "1.5.31"
        booster_version = "4.16.3"
    }
    repositories {
        mavenLocal()
        mavenCentral()
        google()
        jcenter()
        maven { url 'https://oss.sonatype.org/content/repositories/public/' }
        maven { url 'https://oss.sonatype.org/content/repositories/snapshots/' }
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:3.5.0'
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
        classpath "com.didiglobal.booster:booster-gradle-plugin:$booster_version"
        /* 👇👇👇👇 引用这两个模块 👇👇👇👇 */
        classpath "com.didiglobal.booster:booster-task-compression-pngquant:$booster_version"
        classpath "io.johnsonlee.booster:booster-pngquant-provider:2.3.0"
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

然后,执行 compress{Variant}ResourcesWithPngquant 任务来完成对图片资源的压缩,如下所示:

$ ./gradlew compressDebugResourcesWithPngquant --info
1

注意

Android Gradle Plugin 3.6 及以上版本,需要在 gradle.properties 中设置:

android.precompileDependenciesResources=false
1

注意

Android Gradle Plugin 7.0 及以上版本,需要在 gradle.properties 中设置:

android.enableSourceSetPathsMap=false
1

自定义压缩质量

booster-task-compression-pngquant在新窗口打开 支持自定义的参数如下表所示:

选项描述
booster.task.compression.pngquant.option.quality压缩质量 (默认 80)
booster.task.compression.pngquant.option.speed压缩速度 (默认 3)

通过 gradle.properties 配置

booster.task.compression.pngquant.option.quality=75
booster.task.compression.pngquant.option.speed=1
1
2

通过命令行配置

$ ./gradlew assembleDebug \
    -Pbooster.task.compression.pngquant.option.quality=75 \
    -Pbooster.task.compression.pngquant.option.speed=1
1
2
3

任务报告

当 compress${Variant}ResourcesWithPngquant 任务执行完成后会自动在以下路径中生成任务报告:

build/reports/booster-task-compression-pngquant/${variant}/report.txt
1

其内容如下所示:

50.37% intermediates/res/merged/debug/mipmap-xxxhdpi_ic_launcher_round.png.flat 7,622 15,132 ...
46.30% intermediates/res/merged/debug/mipmap-xxhdpi_ic_launcher_round.png.flat  4,821 10,413 ...
45.95% intermediates/res/merged/debug/mipmap-xxxhdpi_ic_launcher.png.flat       4,194  9,128 ...
42.31% intermediates/res/merged/debug/mipmap-xhdpi_ic_launcher_round.png.flat   2,917  6,895 ...
39.31% intermediates/res/merged/debug/mipmap-xxhdpi_ic_launcher.png.flat        2,511  6,387 ...
36.88% intermediates/res/merged/debug/mipmap-hdpi_ic_launcher_round.png.flat    1,809  4,905 ...
34.90% intermediates/res/merged/debug/mipmap-xhdpi_ic_launcher.png.flat         1,567  4,490 ...
20.72% intermediates/res/merged/debug/mipmap-hdpi_ic_launcher.png.flat            614  2,963 ...
18.51% intermediates/res/merged/debug/mipmap-mdpi_ic_launcher_round.png.flat      515  2,783 ...
 7.09% intermediates/res/merged/debug/mipmap-mdpi_ic_launcher.png.flat            146  2,060 ...
-------------------------------------------------------------------------------------
 TOTAL                                                                         26,716
1
2
3
4
5
6
7
8
9
10
11
12

其中,各列涵义如下所示:

  1. 压缩率 (压缩前的大小 - 压缩后的大小) / 压缩前的大小
  2. 合并后的资源文件路径
  3. 压缩后的大小
  4. 压缩前的大小
  5. 原始路径