# PNG

Canonical URL: https://encode.wiki/codecs/images/png/
Content version: ca42e61ede0a24f789d7287a0001244ad22f4abf
Status: current
License: CC BY-SA 4.0
Checksum (SHA-256): 3a18275fa33a9592d585929b639f045fcf7a668c379f713240e355d5cdfe4ee5

PNG (1996) is the lossless format for screenshots, UI, diagrams, pixel art and anything that needs real transparency. It was created as a patent-free replacement for [GIF](/codecs/images/gif/), and the third edition of the spec (a W3C Recommendation since June 2025) adds animation (APNG), HDR colour signalling (`cICP`, `mDCV`, `cLLI`) and Exif.

| Property     | Value                                                          |
| ------------ | -------------------------------------------------------------- |
| Compression  | Lossless (per-row filters plus DEFLATE)                        |
| Bit depth    | 1, 2, 4, 8 or 16 bits per sample (palette up to 8 bits)        |
| Colour types | Grayscale, RGB, indexed palette, with or without alpha         |
| Alpha        | Full alpha channel, or per-entry alpha in palette images       |
| Animation    | APNG, supported by all current browsers                        |
| Progressive  | Adam7 interlacing (usually makes files larger)                 |
| Royalty-free | Yes                                                            |

## When to use it

- **Use PNG** for screenshots, graphics with flat colour or sharp edges, masters you will edit again, and anything that must come out pixel-exact.
- **Not for photos.** A photo as PNG is several times larger than a good JPEG, and usually larger than lossless [WebP](/codecs/images/webp/) or lossless [JPEG XL](/codecs/images/jxl/) too. Use [JPEG](/codecs/images/jpeg/), [AVIF](/codecs/images/avif/) or WebP for delivery.
- **For smaller PNGs**, you have two routes: lossless recompression (oxipng, ECT) which never changes pixels, or palette quantisation (pngquant) which does and often saves 60–80%.

## Shrink PNGs without changing pixels

### oxipng

[oxipng](https://github.com/oxipng/oxipng) is the usual choice: multithreaded, fast, and able to do limited optimisation of APNG. It rewrites files **in place** unless you give `--out` or `--dir`.

```sh
oxipng -o 4 --strip safe image.png --out image.opt.png
oxipng -o max --strip safe *.png
```

| Option | What it does |
| --- | --- |
| `-o 0`…`-o 6`, `-o max` | Effort. Default is 2, which is fast and already good; higher levels have diminishing returns. `max` is level 6. |
| `--strip safe` (`-s`) | Removes non-critical chunks but keeps `cICP`, `iCCP`, `sRGB`, `pHYs` and the APNG chunks. Use `--strip all` only if you are sure no colour or animation data matters. |
| `--alpha` (`-a`) | Rewrites the colour of fully transparent pixels to compress better. Looks identical, but the hidden RGB values change. |
| `-z` | Uses Zopfli instead of libdeflate. Slower, small extra gain. |
| `--scale16` | Converts 16-bit to 8-bit. **Lossy**; oxipng otherwise keeps 16-bit data intact. |

Without `--strip` oxipng keeps every chunk that is still valid, including metadata.

### ECT

[Efficient Compression Tool](https://github.com/fhanau/Efficient-Compression-Tool) (`ect`) optimises PNG and JPEG (and gzip/zip) in place. Level `-9` is very slow; `-3` is the default.

```sh
ect -9 -strip image.png
```

`ect` also recompresses JPEGs losslessly (`-progressive` makes them progressive). [ZopfliPNG](https://github.com/google/zopfli) and [OptiPNG](https://optipng.sourceforge.net/) do the same job; OptiPNG is the older tool, ZopfliPNG strips all ancillary chunks (including colour profiles) unless told to keep them.

## Shrink PNGs by reducing colours (lossy)

[pngquant](https://pngquant.org/) converts RGB/RGBA to an 8-bit palette with per-colour alpha, using dithering to hide the loss. It suits icons, illustrations and screenshots; smooth gradients and photos can band or posterise.

```sh
pngquant --quality 65-90 --skip-if-larger --strip --output small.png input.png
```

- `--quality min-max` picks the fewest colours that reach `max`; if it cannot reach `min` it writes nothing and exits with status 99 (98 for `--skip-if-larger`).
- `--speed` runs 1 (slowest, best) to 11. The default is 4 and the author recommends leaving it unless you need real-time speed.
- `--nofs` turns off dithering (cleaner flat areas, more banding in gradients). `--floyd=0.5` reduces it.
- `--ext .png --force` overwrites input files in place. There is no backup.

Run oxipng on the result for a little more.

## Pitfalls

- **Metadata and colour**: PNG colour can come from `sRGB`, `iCCP`, `cICP`, or legacy `gAMA`/`cHRM`. oxipng's `--strip safe` drops `gAMA` and `cHRM`, and `--strip all` drops everything non-critical, so check images that depended on them. Missing profiles change how colour-managed viewers show the image.
- **Interlacing**: Adam7 costs compression and is rarely worth it. oxipng removes it by default; use `-i keep` or `-i on` if you need it.
- **Hidden RGB in transparent pixels**: `--alpha` and ZopfliPNG's `--lossy_transparent` change it. Harmless for display, wrong if the same file feeds a later edit or a texture pipeline.
- **16-bit images**: many tools silently convert to 8-bit. Keep an eye on `--scale16`, ImageMagick's `-depth 8` and any "web export" preset.
- **APNG**: only some tools keep every frame. `oxipng --strip all` and `optipng -snip` flatten animations. For animation that is not a looping sticker, an actual video or animated WebP/AVIF is far smaller.
- **Large flat-colour screenshots** may compress better as lossless WebP or JPEG XL if the destination supports them.

## Full option reference

Every option and default for oxipng 10.2.1, OptiPNG 7.9.1, pngquant 3.0.3 and ZopfliPNG. [Reading option tables](/reference/encoder-parameters/) explains the Default column.

## oxipng parameter reference

Use `--` before an input filename that begins with a hyphen. The hidden `-Z` is still accepted as an alias of `--zopfli`.

<details>
<summary>Complete oxipng 10.2.1 options and defaults</summary>

| Parameter and aliases  | Type / accepted values      | Default                                     | Meaning and limits                                                                               |
| ---------------------- | --------------------------- | ------------------------------------------- | ------------------------------------------------------------------------------------------------ |
| `--opt`, `-o`          | enum 0–6/max                | 2                                           | Preset from 0 (fastest) to 6 or max (smallest); explicit coding options override it.             |
| `--recursive`, `-r`    | switch                      | off                                         | Optimizes every .png and .apng file found in input directories.                                  |
| `--dir`                | directory                   | not specified                               | Writes outputs into this directory, creating it; recursion flattens the folder layout.           |
| `--out`                | path                        | not specified (input replaced if optimized) | Writes the result to this file instead of replacing the input.                                   |
| `--stdout`             | switch                      | off                                         | Writes the PNG to stdout; cannot combine with --dir, --out or --json.                            |
| `--preserve`, `-p`     | switch                      | off                                         | Keeps the original permissions and timestamps where possible.                                    |
| `--dry-run`, `-d`      | switch                      | off                                         | Reports the savings without writing any file.                                                    |
| `-s`                   | switch                      | off                                         | Same as --strip safe: removes non-essential chunks and keeps those that affect display.          |
| `--strip`              | mode/list                   | keep valid chunks, except caBX/iDOT         | safe, all or a comma-separated chunk list; all also turns APNG into a plain PNG.                 |
| `--keep`               | comma-separated chunk names | not specified                               | Strips everything except the listed chunks; display keeps the appearance-affecting set.          |
| `--alpha`, `-a`        | switch                      | off                                         | Rewrites colour values of fully transparent pixels to compress better; visually lossless.        |
| `--interlace`, `-i`    | enum                        | off; keep with --nx                         | off, on (Adam7) or keep; interlacing adds 25–50% to the size.                                    |
| `--scale16`            | switch                      | off                                         | Reduces 16-bit channels to 8-bit by scaling; lossy.                                              |
| `--verbose`, `-v`      | repeatable switch           | 0 occurrences                               | Shows per-file detail; repeat for more. Cannot combine with --quiet.                             |
| `--quiet`, `-q`        | switch                      | off                                         | Suppresses all output.                                                                           |
| `--json`, `-j`         | switch                      | off                                         | Prints results as JSON; cannot combine with --stdout.                                            |
| `--filters`, `-f`      | integer list/range 0–9      | 0,1,6,7 at level 2                          | Row filters to try: 0–4 fixed, 5 MinSum, 6 Entropy, 7 Bigrams, 8 BigEnt, 9 Brute.                |
| `--fast`               | switch                      | on at levels 0–4; off at 5–6                | Scores filters with a quick pass, then runs one full trial on the best.                          |
| `--zc`                 | integer 0–12                | 11 at level 2                               | libdeflate level 0–12 for main trials; cannot combine with --zopfli.                             |
| `--nb`                 | switch                      | off                                         | Keeps the original bit depth.                                                                    |
| `--nc`                 | switch                      | off                                         | Keeps the original colour type.                                                                  |
| `--np`                 | switch                      | off                                         | Does not convert to indexed colour or change an existing palette.                                |
| `--ng`                 | switch                      | off                                         | Does not convert to or from greyscale.                                                           |
| `--nx`                 | switch                      | off                                         | Disables every reduction and makes the default interlace mode keep.                              |
| `--nz`                 | switch                      | off                                         | Skips IDAT recompression unless a transformation needs it; with --nx, disables all optimization. |
| `--fix`                | switch                      | off                                         | Skips chunk checksum validation so damaged files can be processed; output checksums are valid.   |
| `--force`              | switch                      | off                                         | Writes the output even when it is larger than the input.                                         |
| `--zopfli`, `-z`, `-Z` | switch                      | off                                         | Uses Zopfli instead of libdeflate for main trials; much slower, a little smaller.                |
| `--zi`                 | positive u64                | 15                                          | Zopfli iteration count; fewer is faster. Requires --zopfli.                                      |
| `--ziwi`               | positive u64                | not specified                               | Stops Zopfli after this many iterations without improvement; pair with a high --zi.              |
| `--brute-level`        | integer 1–12                | 1; 5 at level 6                             | libdeflate level for the Brute filter; 1–5 is sensible.                                          |
| `--brute-lines`        | nonnegative integer         | 3; 4 at level 4; 8 at levels 5–6            | Rows compressed together by the Brute filter; 2–16 is sensible.                                  |
| `--timeout`            | u64 seconds                 | no limit                                    | Time budget in seconds, checked between trials; a running trial can overrun it.                  |
| `--max-raw-size`       | size with unit suffix       | no limit                                    | Skips images whose decompressed data exceeds this size; accepts suffixes like k or MB.           |
| `--threads`, `-t`      | nonnegative integer         | logical CPU count                           | Maximum worker threads; 0 lets Rayon choose.                                                     |
| `--sequential`         | switch                      | off (parallel file processing)              | Processes files one at a time, in order.                                                         |
| `--help`, `-h`         | action                      | not requested                               | Shows help.                                                                                      |
| `--version`, `-V`      | action                      | not requested                               | Prints the version.                                                                              |
| `--`                   | action                      | not requested                               | Ends option parsing so later arguments are input paths.                                          |

</details>

Presets: `-o 0` uses filters `0,5` with libdeflate level 5; `-o 1` uses `0,7` and level 10; `-o 2` (default) uses `0,1,6,7` and level 11 with fast evaluation; `-o 3` adds filters `8,9`; `-o 4` uses level 12; `-o 5` and `-o 6` disable fast evaluation, `-o 6` uses every filter. Explicit `--filters`, `--zc`, `--brute-*` and `--fast` options override the preset regardless of order.

`--strip safe` / `--keep display` keep `cICP`, `iCCP`, `sRGB`, `pHYs`, `acTL`, `fcTL` and `fdAT`, and drop other ancillary chunks such as `gAMA`, `cHRM`, `sBIT`, `mDCV` and `cLLI`. Without `--strip`, oxipng keeps every chunk that is still valid, but drops `caBX` and Apple `iDOT`.

## OptiPNG parameter reference

OptiPNG takes the same kind of optimisation switches but uses single-hyphen options, and documented prefixes are accepted as abbreviations. Prefer the full lowercase spelling. Attached forms such as `-o2`, `-f0,5` and `-zc9` are the same options.

<details>
<summary>Complete OptiPNG 7.9.1 options, aliases, and defaults</summary>

| Parameter and aliases                                                           | Type / accepted values | Default                                        | Meaning and limits                                                               |
| ------------------------------------------------------------------------------- | ---------------------- | ---------------------------------------------- | -------------------------------------------------------------------------------- |
| `-o`                                                                            | nonnegative integer    | 2                                              | Preset 0–7, higher is slower and smaller; larger values act as 7.                |
| `-out`, `-ou`                                                                   | path                   | not specified (input can be replaced)          | Output file for a single input; cannot combine with -dir.                        |
| `-dir`, `-d`, `-di`                                                             | directory              | not specified                                  | Output directory; cannot combine with -out.                                      |
| `-backup`, `-b`, `-ba`, `-bac`, `-back`, `-backu`, `-keep`, `-k`, `-ke`, `-kee` | switch                 | off                                            | Keeps a .bak copy when overwriting the input.                                    |
| `-clobber`, `-c`, `-cl`, `-clo`, `-clob`, `-clobb`, `-clobbe`                   | switch                 | off                                            | Allows replacing an existing output file.                                        |
| `-fix`, `-fi`                                                                   | switch                 | off                                            | Tries to recover malformed input; check the result.                              |
| `-force`, `-fo`, `-for`, `-forc`                                                | switch                 | off                                            | Writes an output file even when no improvement is found.                         |
| `-preserve`, `-p`, `-pr`, `-pre`, `-pres`, `-prese`, `-preser`, `-preserv`      | switch                 | off                                            | Keeps file attributes such as permissions and timestamps where possible.         |
| `-quiet`, `-q`, `-qu`, `-qui`, `-quie`, `-silent`, `-sil`, `-sile`, `-silen`    | switch                 | off                                            | Suppresses normal output.                                                        |
| `-simulate`, `-sim`, `-simu`, `-simul`, `-simula`, `-simulat`                   | switch                 | off                                            | Runs the optimization without writing files.                                     |
| `-f`                                                                            | set/ranges 0–5         | 0,5 at level 2                                 | Row filters to try: 0–4 fixed, 5 adaptive. Accepts lists and ranges such as 0,5. |
| `-i`                                                                            | integer 0–1            | retain input interlace                         | Output interlacing: 0 none, 1 Adam7.                                             |
| `-zc`                                                                           | set/ranges 1–9         | 9 at level 2                                   | zlib compression levels to try, 1–9.                                             |
| `-zm`                                                                           | set/ranges 1–9         | 8 at level 2                                   | zlib memory levels to try, 1–9.                                                  |
| `-zs`                                                                           | set/ranges 0–3         | 0–3 at level 2                                 | zlib strategies to try: 0 default, 1 filtered, 2 Huffman-only, 3 RLE.            |
| `-zw`                                                                           | power-of-two size      | libpng default 32 KiB; smaller for Huffman/RLE | zlib window size, 256 to 32768 bytes; accepts suffixes like 4k.                  |
| `-full`, `-fu`, `-ful`                                                          | switch                 | off                                            | Produces a full IDAT report, which can slow the search.                          |
| `-nb`                                                                           | switch                 | off                                            | Disables bit-depth reduction.                                                    |
| `-nc`                                                                           | switch                 | off                                            | Disables colour-type reduction.                                                  |
| `-np`                                                                           | switch                 | off                                            | Disables palette reduction.                                                      |
| `-nx`                                                                           | switch                 | off                                            | Disables all three reductions.                                                   |
| `-nz`                                                                           | switch                 | off                                            | Skips IDAT recompression unless a reduction needs it.                            |
| `-snip`, `-sn`, `-sni`                                                          | switch                 | off                                            | Extracts one image from an animated or multi-image file and drops the rest.      |
| `-strip`, `-st`, `-str`, `-stri`                                                | object                 | not enabled                                    | Only all is accepted; individual chunks cannot be named.                         |
| `-v`                                                                            | switch                 | off                                            | Verbose output; with no input files, prints the version and copyright.           |
| `-verbose`, `-verb`, `-verbo`, `-verbos`                                        | switch                 | off                                            | Verbose output only.                                                             |
| `-version`, `-vers`, `-versi`, `-versio`                                        | action                 | not requested                                  | Prints the version when no input files are given.                                |
| `-debug`                                                                        | switch                 | off                                            | Enables internal debug features; cannot be abbreviated.                          |
| `-log`, `-lo`                                                                   | removed option         | not supported                                  | Removed; the parser rejects it. Redirect output with the shell instead.          |
| `-help`, `-?`, `-h`, `-he`, `-hel`                                              | action                 | not requested                                  | Shows extended help.                                                             |
| `--`                                                                            | action                 | not requested                                  | Ends option parsing so later arguments are input paths.                          |

</details>

The default `-o2` searches `-zc9 -zm8 -zs0-3 -f0,5`. Higher levels search more combinations but never add visual loss. Repeated `-f` and `-z*` sets are unioned. `-strip` accepts only `all`. `-snip` extracts a single image from an animated or multi-image input and discards the animation. See the [versioned manual](https://optipng.sourceforge.net/optipng-7.9.1.man1.html).

## pngquant parameter reference

This is the Rust frontend (3.0.3). The optional positional `ncolors` is the same as the hidden `--colors`.

<details>
<summary>Complete pngquant 3.0.3 Rust options and defaults</summary>

| Parameter and aliases | Type / accepted values | Default                              | Meaning and limits                                                                                      |
| --------------------- | ---------------------- | ------------------------------------ | ------------------------------------------------------------------------------------------------------- |
| `--colors`            | integer 2–256          | 256 maximum                          | Maximum palette size, 2–256; the positional ncolors argument sets the same limit.                       |
| `--quality`, `-Q`     | min-max in 0–100       | no minimum; target 100               | Quality range min-max, 0–100. Below min the image is refused (exit 99). A single N means 90% of N to N. |
| `--speed`, `-s`       | integer 1–11           | 4                                    | 1 (slowest, best) to 11 (fastest); 10 compresses the PNG faster, 11 also disables dithering.            |
| `--floyd`             | optional float         | 1                                    | Floyd–Steinberg dithering strength 0–1; write --floyd=0.5.                                              |
| `--nofs`, `--ordered` | switch                 | off                                  | Disables dithering; --ordered is an alias.                                                              |
| `--posterize`         | integer 0–4            | 0                                    | Drops this many low bits of colour precision, 0–4; lossy but smaller.                                   |
| `--strip`             | switch                 | off                                  | Removes optional metadata chunks.                                                                       |
| `--map`               | PNG path               | not specified                        | Uses the colours of this PNG as a fixed palette.                                                        |
| `--ext`               | suffix                 | -fs8.png; -or8.png without dithering | Output filename suffix for batch runs; cannot combine with --output.                                    |
| `--output`, `-o`      | path                   | derived suffix; stdout for stdin     | Single output file; - writes to stdout.                                                                 |
| `--force`, `-f`       | switch                 | off                                  | Overwrites existing output files without a backup.                                                      |
| `--no-force`          | switch                 | off                                  | Never overwrites existing files, even when --force is also given.                                       |
| `--skip-if-larger`    | switch                 | off                                  | Writes nothing when the result is not smaller than the input (exit 98).                                 |
| `--transbug`          | switch                 | off                                  | Puts a transparent entry last in the palette for old, buggy viewers.                                    |
| `--iebug`             | ignored switch         | off                                  | Accepted but ignored in 3.0.3.                                                                          |
| `--verbose`, `-v`     | switch                 | off                                  | Prints status and quantization details.                                                                 |
| `--quiet`, `-q`       | switch                 | off                                  | Accepted but has no effect; output is already quiet unless --verbose is given.                          |
| `--help`, `-h`        | action                 | not requested                        | Shows help.                                                                                             |
| `--version`, `-V`     | action                 | not requested                        | Prints the version.                                                                                     |
| `--`                  | action                 | not requested                        | Ends option parsing so later arguments are the color count and input paths.                             |

</details>

`--quality 65-85` tries a palette that meets 85 and refuses images that cannot reach 65, with exit code **99**; **98** is the `--skip-if-larger` refusal. When reading from stdin the original may be passed through unchanged, so check what the pipeline actually produced. `--iebug` is registered but ignored in this version. The old C-only spellings (`-nofs`, `-fs`) are not accepted. `--nofs` and `--ordered` both mean no error diffusion.

## ZopfliPNG parameter reference

Pinned to Google's source commit `df1517dd8518` (30 September 2026); there is no versioned release. Long-option values are attached with `=`.

<details>
<summary>Complete pinned Google ZopfliPNG options and defaults</summary>

| Parameter and aliases | Type / accepted values                  | Default                                | Meaning and limits                                                                                                        |
| --------------------- | --------------------------------------- | -------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- |
| `-m`                  | repeatable switch                       | off (15/5 iterations)                  | Multiplies the iteration counts by 4; repeat for more.                                                                    |
| `-y`                  | switch                                  | off                                    | Overwrites existing output without asking; a smaller earlier output is still kept.                                        |
| `-d`                  | switch                                  | off                                    | Dry run: prints sizes without saving.                                                                                     |
| `-q`                  | switch                                  | off                                    | Fast compression without Zopfli; for quickly trying filters and colour types.                                             |
| `--prefix`            | optional text attached with =           | not enabled; `zopfli_` when bare       | Batch mode: writes prefixed copies of each input, optionally into a directory. Use --prefix=name.                         |
| `--always_zopflify`   | switch                                  | off                                    | Writes the Zopfli output even when larger than the input; for benchmarking.                                               |
| `--verbose`           | switch                                  | off                                    | Prints a detailed coding report.                                                                                          |
| `--lossy_transparent` | switch                                  | off                                    | Discards RGB values behind fully transparent pixels.                                                                      |
| `--lossy_8bit`        | switch                                  | off                                    | Converts 16-bit channels to 8-bit; lossy.                                                                                 |
| `--iterations`        | integer attached with =                 | 15 below 200000 raw bytes; 5 otherwise | Zopfli iterations for any file size; more is slower and slightly smaller. Minimum 1.                                      |
| `--splitting`         | ignored compatibility argument          | ignored                                | Ignored; kept for backward compatibility.                                                                                 |
| `--filters`           | characters attached with =              | automatic fast selection               | Strategies to try: 0–4 fixed, m MinSum, e entropy, p input filters, b brute force. 0me is a good set.                     |
| `--keepchunks`        | comma-separated four-letter chunk names | none (IHDR,PLTE,tRNS,IDAT,IEND only)   | Extra chunks to keep, as exact four-letter names separated by commas (iCCP,gAMA). bKGD or sBIT also pins the colour type. |
| `--keepcolortype`     | switch                                  | off                                    | Keeps the input colour type and bit depth, at some cost in compression.                                                   |
| `--help`, `-h`        | action                                  | not requested                          | Shows help.                                                                                                               |

</details>

The default iteration split depends on the raw DEFLATE input size (15 below 200,000 bytes, otherwise 5). An existing output file is treated as a previous candidate and kept if smaller. ZopfliPNG returns success on some failure paths, so confirm the output exists and decodes. By default it keeps only `IHDR`, `PLTE`, `tRNS`, `IDAT` and `IEND`, which removes colour profiles; list the ones the image needs, such as `--keepchunks=iCCP,sRGB,gAMA,cHRM,cICP`; names are exact four-letter, case-sensitive and comma-separated with no spaces. It is not an APNG optimiser.
