PNG 图片压缩

Pngquant

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

无论是从压缩效果和使用便利性来看,pngquant在新窗口打开 的表现都是相当令人惊艳,但是有一个很重要的问题,pngquant在新窗口打开 虽然是开源软件,但它是 GPL License在新窗口打开,而 BoosterApache 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 的构建流程,我们选择在 mergeResprocessRes 任务之间插入 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. 原始路径