PNG Compression

Pngquant

Since it is to reduce the packet size, of course the lossy compression gains higher, and the human eyes can hardly distinguish the subtle differences between the images, so we choose lossy compression.

Regardless of the compression effect and usability, the performance of pngquantopen in new window is quite amazing, but there is a big problem to use it. Although pngquantopen in new window is open source software, it is released under the GPL Licenseopen in new window, and Booster is released under the Apache Licenseopen in new window. How to avoid legal risks while using excellent GPL Licensed software?

Command SPI

To solve the open source license problem, Booster provide the Command SPIopen in new window to split the compression into two parts -- The API part which managed by Booster, and the implementation part which provided by others, the API is released under the Apache Licenseopen in new window, but for the implementation, it can be released under the GPL Licenseopen in new window, so, this prblem has been solved perfectly by using the SPI (Service Provider Interface)open in new window.

Pngquant Provider

As the provider of the pngquantopen in new window command line, booster-pngquant-provideropen in new window is released under the GPL Licenseopen in new window and open sourced separately, currently, it prebuilt both 32-bit and 64-bit executables for Linux, macOS, and Windows platforms.

How it Works?

According to the Android app build process, we decide to insert the PNG compression task between mergeRes and processRes tasks, as shown in the following diagram:

From AGP 3.0.0, the AAPT2 is enabled by default. Since the AAPT2 uses the AAPT2 Container formatopen in new window (the file suffix is .flat), it needs to determine whether the android.enableAapt2 option is enabled in the Android project before compressing, so, Booster divides it into different tasks by the AAPT2 options:

WARNING

Since the AAPT 1.0 has been deprecated, so, Booster only supports AAPT2.

Getting Started

When using booster-task-compression-pngquantopen in new window, the booster-pngquant-provideropen in new window is also required unless the pngquantopen in new window command-line tool has already been installed, otherwise, it won't work.

buildscript {
    ext {
        booster_version = "4.11.0"
    }
    repositories {
        mavenCentral()
        google()
    }
    dependencies {
        classpath "com.android.tools.build:gradle:$agp_version"
        classpath "com.didiglobal.booster:booster-gradle-plugin:$booster_version"

        /* 👇👇👇👇 Use the following 2 plugins 👇👇👇👇 */
        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
buildscript {
    val booster_version = "4.11.0"

    repositories {
        mavenCentral()
        google()
    }
    dependencies {
        classpath("com.android.tools.build:gradle:$agp_version")
        classpath("com.didiglobal.booster:booster-gradle-plugin:$booster_version")

        /* 👇👇👇👇 Use the following 2 plugins 👇👇👇👇 */
        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

Then, execute the compress{Variant}ResourcesWithPngquant task to start the image compression:

$ ./gradlew compressDebugResourcesWithPngquant --info
1

WARNING

The following properties is required on Android Gradle Plugin 3.6 and above:

android.precompileDependenciesResources=false
1

Customize Compression Quality

The options supported by booster-task-compression-pngquantopen in new window are listed as following:

OptionDescription
booster.task.compression.pngquant.option.qualityCompression quality (default: 80)
booster.task.compression.pngquant.option.speedCompression speed (default: 3)

Configuring by gradle.properties

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

Configuring by command line

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

Task Report

After the compress${Variant}ResourcesWithPngquant task executed successful, a report will be generated at the following location:

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

The content looks like as following:

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

The meaning of each column is as follows:

  1. Compression Rate (Size Before Compression - Size After Compression) / Size Before Compression
  2. The resource path after merged
  3. The file size after compression
  4. The file size before compression
  5. The source path