PNG Optimization in 2025 — Palettization and Lossless Squeeze

Published: Sep 19, 2025 · Reading time: 3 min · By Unified Image Tools Editorial

PNG optimization that preserves transparency and crisp edges

PNG still shines for UI, logos, and icons. This guide summarizes a reliable workflow to cut size without quality regressions: palettization when applicable, remove redundant chunks, then squeeze with lossless tools.

Decide first

  • Need transparency? → PNG or WebP lossless (for UI)
  • Few colors? → Palettize (≤8-bit) for major savings
  • Fine edges/text? → Prefer lossless; avoid over-aggressive pre-processing

Practical workflow

  1. Normalize to sRGB (details: Correct Color Management & ICC Profile Strategy 2025 — A Practical Guide for Stable Web Image Color)
  2. Palettize to reduce colors
  3. Remove redundant chunks (EXIF, text timestamps, etc.)
  4. Apply lossless compression

For one-off jobs use PNG Lossless Optimizer; for batches consider Batch Optimizer Plus.

Pitfalls to watch

  • Text edge smearing: avoid pre-blur; keep source sharp
  • Color breakage: adjust palette size stepwise; review with Compare Slider

How far to reduce colors (thresholds)

  • Logos/icons: often fine at 8–32 colors; watch anti-aliased edges
  • UI screenshots: 64–128 colors commonly reach visual parity
  • Photo-like illustrations: avoid PNG; consider WebP lossless/lossy or AVIF

For alpha edges on dark backgrounds, add a 0.5–1px drawing halo in the same color to prevent fringing.

CLI recipes (lossless)

# oxipng: good balance of speed and compression
oxipng -o 4 --strip all input.png -o output.png

# zopflipng: stronger but slower
zopflipng -m --iterations=50 --filters=0me input.png output.png

# pngquant: lossy (palettization) but high quality; set target with --quality
pngquant --quality=70-95 --speed 1 --strip --force --output output.png input.png

Hints:

  • Start with pngquant to reduce colors, then run oxipng/zopflipng for a tight result.
  • Use --strip all to remove timestamps/text chunks that don’t affect rendering.

Filter strategy and zlib parameters

PNG chooses a per-scanline filter (None/Sub/Up/Average/Paeth) then zlib-compresses. The best combination of filter sequence and zlib parameters can change size by single to double-digit percent.

  • Filter auto-search: try multiple patterns like zopflipng -m --iterations=50 --filters=0me
  • zlib level: 9 is strongest but slow; in practice start at 5–7 and iterate
  • Continuous-tone areas often like Paeth/Average; flat UI areas sometimes do better with None/Sub

Dithering (perceived granularity)

Palettization’s “dither” hides banding but can look noisy on sharp edges and text.

  • Floyd–Steinberg: general-purpose; good for natural images
  • Ordered: regular pattern; can stand out on UI
  • None: best for text/logos; flat areas stay clean

With pngquant, control with --floyd (0..1) and --ordered. For icon sets, prefer no dither; for subtle gradients, a weak Floyd often works.

Alpha and premultiplied edges (dark halo fixes)

Transparent PNGs can show dark halos when composited on dark backgrounds. Match the expected background and consider premultiplied-alpha handling or a 0.5–1px outer stroke in the same color.

// Conceptual example with sharp
import sharp from 'sharp'

await sharp('input.png')
  .removeAlpha()       // flatten when background is predetermined
  .png({ compressionLevel: 9 })
  .toFile('flat.png')

await sharp('input.png')
  .ensureAlpha()       // keep transparency
  .png({ compressionLevel: 9 })
  .toFile('alpha.png')

CI/CD integration (example)

# .github/workflows/png-optimize.yml (excerpt)
name: Optimize PNG
on: [pull_request]
jobs:
  png-opt:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: sudo apt-get update && sudo apt-get install -y pngquant
      - run: |
          find assets -name "*.png" -print0 | xargs -0 -n1 -I{} pngquant --skip-if-larger --quality=70-95 --strip --force --output {} {}

Related Articles