Mobile Development 14 min read

Optimizing Image Assets in QQ Music Android APK with pngquant and TinyPNG

To shrink the QQ Music Android APK, the team replaced manual image compression with a multithreaded pngquant workflow that compresses PNGs at 90 % quality, integrates into the RDM build, cuts the res directory by 1.97 MB and the overall package by 2.22 MB, delivering faster, maintainable builds.

Tencent Music Tech Team
Tencent Music Tech Team
Tencent Music Tech Team
Optimizing Image Assets in QQ Music Android APK with pngquant and TinyPNG

Background: After several version iterations, the QQ Music Android APK grew beyond 25 MB, with the res directory alone occupying over 5.5 MB. PNG images constitute the majority of assets, making image compression a critical step for package slimming.

Previous workflow: Images were manually compressed locally, committed to SVN, and then packaged. This manual batch process using online tools suffered from repeated compression (causing distortion), lack of customizable parameters, and low efficiency.

Compression tools and principles:

TinyPNG – Uses quantization to convert 24‑bit PNGs to 8‑bit, removes metadata, and can achieve >50% reduction. It offers an online API (Ruby, PHP, Node.js, Python, Java) but requires an API key and is limited to 500 free calls, which is unsuitable for the internal development network.

pngquant – An open‑source lossy PNG compressor that converts 24/32‑bit RGBA PNGs to 8‑bit while preserving transparency. Typical size reduction is ~70%. It employs vector quantization, an adaptive dithering algorithm, and provides both command‑line and library interfaces, including a fast batch mode.

Other tools mentioned include ImageAlpha, ImageOptim, pngcrush, optipng, pngout, pngnq, advpng, each with varying lossless or lossy characteristics.

Compression comparison:

1. Single‑image test – TinyPNG achieved roughly 10 % higher compression than pngquant (default quality). Occasionally pngquant produced larger files, requiring a size check to discard such results.

2. Batch compression – TinyPNG’s batch service is limited to the web interface, while pngquant can be scripted locally, avoiding upload failures. Although TinyPNG’s overall compression is ~12 % better, its lossy nature demands visual verification.

3. Local script on drawable directories – Using a multithreaded pngquant script on eight drawable folders took 17.94 s. With a quality setting of 90, the process reduced the APK size by 1.97 MB.

Conclusion: The project adopted pngquant for batch PNG compression because it allows custom quality settings, is open‑source, and integrates smoothly into the build pipeline, despite a slightly lower compression ratio compared to TinyPNG.

pngquant compression workflow:

import com.tencent.qqmusic.ImageCompressionTask

task compressImages(type: ImageCompressionTask) {
    multiThread = true
    verbose = false
    backupRoot = new File('res-backup')
    sourceRoot = rootDir
    quality = 90
    compress = true
    folders = [
        "res/drawable",
        "res/drawable-hdpi",
        "res/drawable-ldpi",
        "res/drawable-mdpi",
        "res/drawable-xhdpi",
        "res/drawable-xhdpi-v21",
        "res/drawable-xxhdpi",
        "res/drawable-xxxhdpi"
    ]
}

To integrate the task into the RDM automated build, the following dependency is added:

copyNativeLibs.dependsOn compressImages

The default Android Asset Packaging Tool (AAPT) compression is disabled:

aaptOptions {
    cruncherEnabled = false
}

On Linux, pngquant requires several shared libraries. The build script sets LD_LIBRARY_PATH and creates symbolic links:

# Add dynamic loading dependencies for pngquant
export LD_LIBRARY_PATH=$(cd `dirname $0`; pwd)/scripts/Tools/pngquanti/linux/lib
ln -s $(cd `dirname $0`; pwd)/scripts/Tools/pngquanti/linux/lib/liblcms2.so.2.0.8 $(cd `dirname $0`; pwd)/scripts/Tools/pngquanti/linux/lib/liblcms2.so.2
ln -s $(cd `dirname $0`; pwd)/scripts/Tools/pngquanti/linux/lib/ld-2.23.so $(cd `dirname $0`; pwd)/scripts/Tools/pngquanti/linux/lib/ld-linux-x86-64.so.2
ln -s $(cd `dirname $0`; pwd)/scripts/Tools/pngquanti/linux/lib/libpng15.so.15.27.0 $(cd `dirname $0`; pwd)/scripts/Tools/pngquanti/linux/lib/libpng15.so.15

The automation flow ensures multithreaded execution, avoids re‑compressing already processed images by recording compression metadata, and discards any output larger than the original.

Advantages of using pngquant:

Achieves maximum compression (quality 90) without noticeable visual loss.

Groovy script enables batch processing, custom parameters, and metadata tracking to prevent duplicate work.

Integration into RDM automates the task, reducing developer effort and simplifying maintenance.

JPG compression: The internal "优图" tool provides lossless compression with >20 % reduction, while TinyJPG is lossy and less maintainable. The project prefers the internal tool, achieving a 0.23 MB reduction across 49 JPGs.

Third‑party JAR assets: PNGs from TVK_MediaPlayer, videoad‑sdk, and weiboSDKCore jars were manually compressed, saving ~41 KB.

Overall results:

PNG size reduced by 1.97 MB (res directory).

JPG size reduced by ~200 KB.

Third‑party PNG assets reduced by ~40 KB.

Total package size decreased by 2.22 MB .

Automation improves efficiency and maintainability.

References: (list of URLs omitted for brevity).

build automationAndroidResource optimizationGradleimage compressionpngquantTinyPNG
Tencent Music Tech Team
Written by

Tencent Music Tech Team

Public account of Tencent Music's development team, focusing on technology sharing and communication.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.