Library / SDK
kornelski/pngquant avatar
kornelski/pngquant

pngquant: lossy 8-bit PNG compression from the command line

Lossy PNG compressor — pngquant command based on libimagequant library

5,755 stars504 forksCNOASSERTION

At a glance

What is it?
pngquant converts 24/32-bit PNGs to 8-bit palettes with alpha, often cutting file size by 60-80%. It is a C tool wrapped in a small Rust binary, dual-licensed GPL v3 or commercial, and it is the wrong tool when you need lossless output.
Who is it for?
Adopt pngquant when you control the build pipeline and can accept lossy 8-bit output, especially for web assets where you can inspect results with --quality and --skip-if-larger. Do not adopt it if your images must stay lossless, if you need more than 256 colors per image, or if your product cannot ship GPL v3 code and you have no commercial license.
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 101 days ago.
What is it written in?
Mainly C, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 29, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What pngquant solves for people shipping PNGs

A 24-bit or 32-bit PNG stores each pixel as three or four bytes. That is wasteful for logos, icons, screenshots and flat illustrations, which typically use far fewer distinct colors than the format allows. pngquant converts those images to an 8-bit indexed PNG with an alpha channel, so each pixel becomes an index into a palette of at most 256 colors. The README states the result is often 60-80% smaller than the original 24/32-bit file, and that the output stays standards-compliant and readable by browsers and operating systems.

The audience is narrow but real: front-end and build engineers who need smaller image payloads and are willing to trade exact pixel reproduction for size. It is not a general-purpose image optimizer. It is a quantizer. If your source is already an 8-bit palette PNG, or a photograph with smooth gradients, the trade is much less attractive, and the documentation does not pretend otherwise.

How the quantization and dithering actually work

The compression engine lives in libimagequant, a separate library that pngquant links against. The repository layout reflects this split: pngquant.c and pngquant_opts.c handle the command-line interface and file I/O, rwpng.c wraps PNG reading and writing, and the lib/ directory holds the quantizer. Cargo.toml shows the Rust binary at rust/bin.rs depending on imagequant-sys version 4.1.0, with libpng-sys for PNG I/O and an optional lcms2-sys for color profile handling. Default features are lcms2 and threads.

The pipeline is: read the source PNG, build a palette by clustering the image's colors, map each pixel to a palette entry, optionally apply dithering, then write an indexed PNG. The README describes the palette generation as supporting gamma correction and premultiplied alpha, and the dithering as a "unique dithering algorithm that does not add unnecessary noise to the image". The alpha handling matters: premultiplied alpha avoids the dark or light fringes you get when you quantize straight alpha naively.

Multicore support comes through OpenMP, and there are Intel SSE optimizations. The Cargo.toml threads feature forwards to imagequant-sys/threads, so a Rust build without that feature loses parallelism. The release profile sets lto = true, codegen-units = 1 and panic = "abort", which is a size-and-speed build rather than a debugging build.

Installing pngquant and running a first conversion

The project publishes prebuilt binaries and packages through pngquant.org, and the README points at that site as the home of the tool. Package managers are the usual route on macOS and Linux; the repository itself does not document a single canonical install command, so check the site or your distribution's package for the version you get.

Once the binary is on your PATH, the simplest invocation converts every PNG in the current directory:

bash
pngquant *.png

By default pngquant writes a new file next to each input using a suffix such as -fs8.png, leaving the original untouched. To control the quality floor and ceiling, use --quality with a min and max on a 0-100 scale:

bash
pngquant --quality=65-80 image.png

If the conversion cannot reach the min quality, the README states the image is not saved and pngquant exits with status code 99. When output goes to stdout, the 24-bit original is emitted instead. That exit code is the part to wire into a build script, because a naive shell pipeline will otherwise treat a skipped file as success.

For a single explicit output path, use -o. Only one input file is allowed with this option:

bash
pngquant --quality=65-80 -o out.png image.png

To avoid writing files that did not get smaller, add --skip-if-larger. To overwrite inputs in place, the README documents --ext=.png together with --force, and explicitly says to use it with caution.

Quality, speed and the settings that change the output

The --speed flag runs from 1 (slowest, highest quality, smallest files) to 11 (fastest, less consistent quality, lighter compression), with a default of 4. The README recommends keeping the default unless you generate images in real time, giving map tiles as the example. It also notes that higher speeds are fine with 256 colors but do not handle lower color counts well. That is a specific and useful warning: if you are targeting a small palette, do not reach for speed 11.

Dithering is controlled by --nofs, which disables Floyd-Steinberg dithering entirely, or by --floyd with a level from 0 to 1. The README notes that the = character is required, so --floyd 0.5 will not do what you want. For low-depth displays or ARGB444-style compressed textures, --posterize reduces palette precision by a number of bits.

--strip drops optional PNG chunks. The README adds that metadata is always removed on Mac when the Cocoa reader is used, which is a platform-specific behavior worth knowing before you assume metadata survives a build. The full option list is in the man page, pngquant.1, which ships in the repository.

Where pngquant is the wrong tool

The largest limitation is in the name: this is a lossy compressor. Converting to an 8-bit palette discards color information permanently, and for photographic content with wide gradients the result shows banding even with dithering enabled. If your requirement is bit-exact output, pngquant cannot meet it, and the README does not claim it can.

The 256-color ceiling is a hard boundary. Images with more distinct colors than that will lose detail, and the quality settings only control how the loss is managed, not whether it happens. Images that are already indexed PNGs gain little.

There is also an operational failure mode around quality. Because a too-low result exits with status 99 and writes nothing, a build system that ignores exit codes will silently keep the original file while reporting success. The README documents the exit code and the stdout fallback, but the integration work is on you. Finally, the GPL v3 side of the dual license is a real constraint for closed-source products, discussed below.

pngquant against lossless PNG optimizers

The README itself recommends oxipng, ImageOptim and zopflipng for further size reduction, which is the clearest signal about where the boundary sits. Those tools re-encode PNG losslessly: they try different filter and compression strategies and keep the pixels identical. pngquant changes the pixels. That is the whole difference in approach, and it explains why the tools compose rather than compete. Running pngquant first and a lossless optimizer afterward is a reasonable pipeline because the two operate on different axes.

Against a hosted service in the same space, the trade is control versus convenience. A command-line quantizer runs inside your build, needs no upload, and lets you script quality thresholds and exit-code handling. A hosted service handles the compute for you and hides the settings. If your build already runs in CI, the local tool is the one that fits; if you are optimizing a handful of images by hand, the hosted route removes setup work.

The relevant question is not which tool compresses best in the abstract, but whether you can accept lossy output at all. If you cannot, pngquant is out and the lossless tools are the whole answer.

Licensing, maintenance and upgrade cost

pngquant is dual-licensed. The README states it is available under GPL v3 or later, with an additional copyright notice that must be kept for older parts of the code, or under a commercial license for use in non-GPL software such as closed-source or App Store distribution. The commercial license is obtained through Super Source. Cargo.toml lists the package license as GPL-3.0-or-later, which matches the README. The repository metadata reports the license as NOASSERTION, so the package metadata is the clearer signal here. This is a description of the stated terms, not legal advice; if your product ships pngquant or links its code, get your own reading of the GPL obligations.

On maintenance: the last push to the default branch was on 2026-06-21. The repository is not archived. There is a CHANGELOG and a test directory, and CI runs through GitHub Actions. Cargo.toml pins rust-version 1.67 and edition 2021, so the Rust build side has a modest toolchain floor. Upgrade cost is mostly tied to the libimagequant dependency: imagequant-sys is versioned 4.1.0 in the manifest, and palette behavior can shift between engine versions, so re-check output sizes and visual quality after bumping it rather than assuming identical results.

Editorial conclusion

Adopt pngquant when you control the build pipeline and can accept lossy 8-bit output, especially for web assets where you can inspect results with --quality and --skip-if-larger. Do not adopt it if your images must stay lossless, if you need more than 256 colors per image, or if your product cannot ship GPL v3 code and you have no commercial license. Before rolling it out, verify three things on your own images: the exit status 99 path in your build script, the actual output size versus the input, and whether your distribution channel expects the GPL v3 terms or a commercial license from Super Source.

Frequently asked questions

How do I install pngquant on Windows?

The README points to pngquant.org as the project's home, and the repository does not document a single Windows install command. The repository does contain an msvc directory for Visual Studio builds, which the README mentions as the exception to the C99 codebase. Use the binaries published on the project site or a package manager rather than assuming a command from the README.

What is pngquant exe?

It is the pngquant command-line binary. Cargo.toml defines a single binary named pngquant at rust/bin.rs, and the README describes the tool as a PNG compressor that converts images to 8-bit PNG with alpha. On Windows that executable is what you invoke from a terminal or a build script.

Is pngquant safe to use?

The README describes the output as fully standards-compliant and supported by all web browsers and operating systems. The tool reads your PNGs and writes new files next to them by default, so the originals are not modified unless you pass --ext=.png with --force, which the README says to use with caution. Safety of the output format is a separate question from whether the lossy conversion suits your images.

How do I use pngquant?

Run pngquant followed by one or more PNG paths, for example pngquant *.png for batch conversion. Add --quality=65-80 to set a quality floor and ceiling, and note that pngquant exits with status code 99 and saves nothing when the result falls below the minimum. The README also documents stdin and stdout chaining with pngquant -.

How does pngquant compare with oxipng?

They work on different axes. pngquant converts images to an 8-bit palette, which is lossy, while the README recommends oxipng as an additional step for further size reduction. Because oxipng does not change the pixel data the way quantization does, the two can be run in sequence.

How does pngquant compare with optipng?

The README does not discuss optipng directly. It does list oxipng, ImageOptim and zopflipng as tools for further size reduction after pngquant, all of which are lossless re-encoders rather than quantizers. That places pngquant in a different category from a lossless optimizer.

Official sources

  1. Issues
  2. kornelski/pngquant on GitHub
  3. Project website
  4. README
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.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/kornelski-pngquant.svg)](https://hysenlabs.com/projects/kornelski-pngquant)