# 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 来处理:

WARNING

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

# 如何使用

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

buildscript {
    ext {
        kotlin_version = '1.3.31'
        booster_version = '3.0.0'
    }
    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"
    }
}

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

$ ./gradlew compressDebugResourcesWithPngquant --info

WARNING

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

android.precompileDependenciesResources=false

# 自定义压缩质量

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

# 通过命令行配置

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

# 任务报告

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

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

其内容如下所示:

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. 原始路径