libimagequant: RGBA to 8-bit palette quantization in Rust
Palette quantization library that powers pngquant and other PNG optimizers
At a glance
- What is it?
- libimagequant is the palette quantization engine behind pngquant, rewritten in Rust while keeping the old C interface, and it is licensed GPL v3 or later for open source use with a commercial licence available otherwise. It does not encode or decode images, and it dropped configure and make along with OpenMP along the way.
- Who is it for?
- Adopt libimagequant when you are writing Rust or C code that needs a high quality palette with alpha, you already handle PNG encoding elsewhere, and your licence situation allows GPL v3 or later or a purchased commercial licence. Do not adopt it as a standalone tool, since the README points CLI users to pngquant, and do not adopt it as a drop-in C library without accepting that v4 is Rust based and needs a Cargo build.
- Can I use it commercially?
- Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
- Is it still maintained?
- Yes. The repository last received commits 124 days ago.
- What is it written in?
- Mainly Rust, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 21, 2026, and from our analysis. They are not legal advice.
Editorial analysis
Quantization only, with encoding left to you
libimagequant does one job: it converts RGBA images into palette based 8-bit indexed images, and it keeps the alpha channel in the process. That is the whole scope. The README states plainly that image encoding and decoding is not handled by the library itself and that you should bring your own encoder, and it points anyone who wants a command line tool to pngquant instead.
That boundary is the first thing to check against your own need. If you want to shrink PNGs and nothing else, pngquant is the tool. If you are embedding a quantizer inside an application, a build pipeline, or a service that already owns the PNG writer, then a library that stops at the palette is exactly the shape you want, because the output is a palette plus an index array that your encoder can write as a PNG with a PLTE chunk or a GIF with a colour table.
The palette it produces is what makes the output small. A 24 or 32-bit RGBA source can carry far more colour information than a file format with an indexed palette can hold, so quantization is the lossy step where the reduction happens. The library is described as ideal for generating tiny PNG images and good looking GIFs.
Adding it to a Rust project
For Rust consumers the entry point is the `imagequant` crate on crates.io, and the installation step is short.
rustup update
cargo add imagequantThe API documentation is on docs.rs, and the repository keeps an examples directory with a basic.rs file, which is the fastest way to see how the pieces fit together in practice.
The Cargo.toml carries useful detail about what you are pulling in. The package is named `imagequant` at version 4.5.0, the edition is 2021 and the declared rust-version is 1.65, while the README asks for Rust 1.70 or newer to build the C interface, which is the stricter of the two requirements. Dependencies are small and deliberate: arrayvec, rgb with the bytemuck feature, and optionally rayon and thread_local for threading plus hashbrown for the no_std path.
Two feature flags shape the build. The default feature set is threads and std. The large_palettes feature supports up to 2048 colours for palettes, but the comment in the manifest is explicit that this does not apply to remapping. The no_std feature needs std and threads disabled as well as no_std enabled, and it swaps in hashbrown.
Building the static library for C and C++ callers
C and C++ programs use the imagequant-sys subdirectory, which is a Rust crate with C bindings. The build instructions changed with version 4, because the library used to be C and is now Rust under the hood.
rustup update
cd imagequant-sys
cargo build --releaseThat produces `target/release/libimagequant_sys.a`. The documentation is careful about what has and has not changed: the API, the ABI and the header files remain the same, so everything else should work the same way it did.
The files for C and C++ have moved out of the repository root and into the imagequant-sys subdirectory, and there is no configure and make any more. If you are building for macOS or iOS, there is an included xcode project that can be added as a subproject. For Android the documented route is to add the target with rustup and then build for it.
rustup target add aarch64-linux-android; cargo build --release --target aarch64-linux-androidThat yields `target/aarch64-linux-android/release/libimagequant_sys.a`, and the same pattern applies when cross compiling to other platforms. The imagequant-sys readme has instructions for producing smaller builds.
Dynamic libraries and the cargo-c requirement
Application developers are steered towards static linking, and the reasoning given is practical rather than technical preference: static linking is much easier and gives smaller executables. Package maintainers who need a system wide shared library have a harder path, and the project says so plainly.
The route the project recommends is the cargo-c tool, which knows how to build and link a shared library properly and generates an accurate pkg-config file. It is described as the de-facto requirement for a correct system wide install of a dynamic library.
rustup update
cd imagequant-sys
cargo install cargo-c
cargo cinstall --prefix=/usr/local --destdir=.That makes Rust 1.70 and cargo-c a build time dependency, with no runtime dependencies apart from Cargo internal ones.
There is a rougher alternative for people who do not care about soname and rpath being wrong: add "cdylib" to the existing crate-type property in imagequant-sys/Cargo.toml and run cargo build --release, which produces target/release/libimagequant.{so,dylib,dll}. The author is blunt about the old make based build being gone, explains that wrapping the static library did not work, and says he would welcome pull requests about a more standard and lightweight solution than cargo-c if you are good at wrangling linker flags and symbol visibility.
Migrating from v2 C to v4 Rust without changing your C code
The version jump is the one migration that genuinely costs time, and the documentation treats it in two tracks.
For C static library users, the change is in the build system rather than the code. You need Rust installed through rustup, the build commands change, and the output path moves. The API, ABI and headers stay the same, so the C source itself should not need edits. If you prefer not to migrate at all, the 2.x branch of the repository still holds the old C version, and the sover is unchanged, which means it can serve as a drop-in replacement for the previous release.
For Rust users, the advice is to move off the imagequant-sys crate to the higher level imagequant crate. The v4 Rust API is described as almost entirely backwards compatible, with small changes that the compiler will point out, such as a changed use of c_int to u32. Two specific changes are worth knowing in advance. The openmp Cargo feature has been renamed to threads. And new_image() can now take ownership of its argument to avoid copying, which means code passing a reference to a vector of RGBA will report that From<&Vec<RGBA>> is not implemented; the documented fixes are to pass by value, to call .as_slice() to copy the pixels, or to use the new_image_borrowed() method.
The deprecation note matters too: deprecated functions will be removed, so fix the warnings rather than leaving them in place.
Threading on by default, and awkward in WASM
The library uses multi-threading when the threads Cargo feature is enabled, and that feature is on by default. The number of threads is controlled through the RAYON_NUM_THREADS environment variable, so you can cap it without recompiling.
Disabling it is a supported configuration, and the manifest comment is blunt about the cost: the library makes good use of multi-threading, so disabling threads has a significant performance penalty. To turn it off in a dependency you disable default features.
[dependencies]
imagequant = { version = "4.0", default-features = false }Note that turning off default features also disables std, so if you need std you have to enable it explicitly alongside whatever else you want.
WASM is the awkward case. Threads in WASM are experimental and require special handling, and the guidance is direct: if you are targeting WASM you will most likely want to disable threads. Given the stated performance penalty of turning threading off, a browser build of an image pipeline is the case where you should measure rather than assume the tradeoff is worth it.
Dual licensing, the PNG quantizer relationship and the project state
Licensing is the first thing to resolve, and the library is dual licensed. For free and libre open source software it is available under GPL v3 or later, with additional copyright notices for historical reasons that live in the COPYRIGHT file. For closed source software, App Store distribution and other non-GPL uses, a commercial licence can be obtained, and the README invites requests to the maintainer's address for custom licensing terms. The Cargo.toml records the SPDX identifier as GPL-3.0-or-later.
This is not legal advice, but it is a decision you should make before writing code, not after. A GPL dependency linked into a closed source application is a different situation from a library you purchase, and the routes are clearly separated.
The relationship with pngquant is also worth understanding. pngquant v2 can use this library as a dynamic library, but pngquant v4 does not support unbundling. It uses the library as a Cargo dependency through its Rust-native interface. The shared libimagequant library exports only a stable ABI for C programs, and that interface is not useful for Rust programs, which is why Rust users should take the `imagequant` crate instead.
On project state: the repository is not archived, and the last push was on 2026-06-21. It publishes no GitHub releases, so the version history lives in the CHANGELOG file at the repository root, and the manifest currently reads 4.5.0.
Editorial conclusion
Adopt libimagequant when you are writing Rust or C code that needs a high quality palette with alpha, you already handle PNG encoding elsewhere, and your licence situation allows GPL v3 or later or a purchased commercial licence. Do not adopt it as a standalone tool, since the README points CLI users to pngquant, and do not adopt it as a drop-in C library without accepting that v4 is Rust based and needs a Cargo build. Verify first that the licence fits your distribution model, since the Cargo.toml records GPL-3.0-or-later while the project also offers a commercial route, then confirm your Rust toolchain meets the stated 1.70 requirement for building the C interface and decide early whether you need the threads feature, which is on by default and has a stated performance penalty when disabled.
Frequently asked questions
How do I use libimagequant from Rust?
Run cargo add imagequant and use the imagequant crate, whose API documentation is on docs.rs. The Cargo.toml declares rust-version 1.65, while the README asks for Rust 1.70 or newer when building the C interface.
Can libimagequant encode or decode PNG files?
No. The README states that image encoding and decoding is not handled by the library itself and that you should bring your own encoder. For a command line tool, the README points to pngquant.
Is libimagequant GPL licensed?
It is dual licensed. The README states GPL v3 or later with additional copyright notices for free and libre open source software, and a commercial licence for closed source software, App Store distribution and other non-GPL uses. The Cargo.toml records the licence as GPL-3.0-or-later.
How do I build libimagequant for a C program?
The C and C++ files now live in the imagequant-sys subdirectory and configure and make no longer exist. Install Rust through rustup, then run rustup update, cd imagequant-sys and cargo build --release, which produces target/release/libimagequant_sys.a with the same API, ABI and header files.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/imageoptim-libimagequant)Was this useful?