The path through the browser

  1. The main thread accepts a PNG or JPEG from drop, file picker, or clipboard paste.
  2. A module Web Worker receives the file bytes, MIME type, filename, resize percentage, and WebP choice.
  3. createImageBitmap decodes the source; OffscreenCanvas produces RGBA pixel data.
  4. The worker selects the PNG, JPEG, or WebP encoder path.
  5. The main thread receives a local output buffer, renders the result, and prepares downloads.

The worker boundary keeps codec work away from the interface thread. Adding files, toggling options, and reading progress remain responsive while an encoder is busy.

PNG: palette reduction, then lossless optimisation

PNG follows a two-stage path. Libimagequant first reduces the colour palette with a minimum quality of 65, target quality of 80, and speed setting 4. The resulting PNG then passes through oxipng at optimisation level 2 with alpha optimisation enabled.

If libimagequant cannot satisfy the quality floor, Squeezr skips palette reduction. The source PNG receives the lossless oxipng pass instead. When resizing is enabled, the resized pixels are encoded to PNG before that fallback because the original bytes have the wrong dimensions.

JPEG: MozJPEG at a fixed quality

JPEG and JPG input uses the MozJPEG encoder at quality 80. There is no automatic per-file quality search and no visible quality slider. That fixed contract keeps the workflow predictable: add a photograph, encode it once, inspect it, and keep the source if the delivery copy is not suitable.

WebP: an explicit format change

When WebP is enabled, either PNG or JPEG pixel data goes to the libwebp encoder at quality 80. The output extension changes to .webp. This is the only standard path that changes the image format, and the interface makes that choice visible before compression begins.

Resize happens before encoding

Resize scales both dimensions by the selected percentage, preserves aspect ratio, and never upscales. The worker uses high-quality canvas smoothing before the encoder sees the pixels. A resize is treated as an explicit output request, so the resized file is returned even if its byte count happens to exceed the source.

The keep-original safeguard

With resize off, the worker compares encoded and original byte lengths. If the new output is not smaller, it returns the original bytes and filename. This avoids offering a larger file as a successful compression result.

Memory and batch limits

The main thread sends one file at a time and waits for the worker’s result before advancing the queue. That sequential design limits peak codec memory. Source images above 40 megapixels are rejected, and a batch can contain up to 20 supported files.

Codec modules are imported on first use and then reused. Thumbnails are separately bounded to a maximum 400-pixel side so the result list does not keep full-size decoded images for every item.

Verified project results

Flat UI PNG, 900×600
35 KB → 3.0 KB
91% smaller
Gradient-and-noise PNG, 700×500
753 KB → 173 KB
77% smaller
Photographic JPEG
178 KB → 58 KB
68% smaller
Gradient PNG to WebP
Quality 80
99% smaller

These values come from the project’s browser fixtures. They describe those inputs, not every image. Compression ratio depends on dimensions, palette, noise, existing optimisation, transparency, and the source encoder.

What the pipeline does not promise

  • Animated GIF, animated PNG, HEIC, SVG, AVIF, and RAW formats are not accepted.
  • Unusual colour profiles and exotic metadata are not an archival target.
  • Visual equivalence is subjective; the preview is part of the workflow.
  • The tool is experimental and should not replace the only copy of an important file.

Ready to try a specific path? Open the PNG compressor, JPEG compressor, or WebP converter.