Free image compressors compared: what each one is good at, with measured numbers
Disclosure: I built SnapCompress, one of the tools in this article. It is a free hobby project with no paid plan, and I have no relationship with any of the other tools. Read the comparison with that in mind. To keep it checkable, I only publish numbers I can reproduce, and the method, inputs, and raw results are linked below.
The short answer: for a single photo or screenshot in the browser, use a tool that compresses on your device (SnapCompress or Squoosh). For many files on a Mac, ImageOptim. For build pipelines and scripts, sharp, cwebp, or pngquant on the command line. TinyPNG is convenient, but your files go to its servers.
Last updated:
By Óscar Gallego Ruiz.
What changed in this version
An earlier version of this page put SnapCompress at the top with a numeric score I gave it myself, and claimed a month of testing that was never published. Neither could be checked, so both are gone. This version describes each tool from its own documentation, without scores, and publishes measurements only for what a script can reproduce: SnapCompress's own pipelines and the open-source encoders listed below.
Which tool fits which job?
| Tool | Where your image is processed | Platform | Good for | Limits worth knowing |
|---|---|---|---|---|
| SnapCompress (mine) | In your browser, nothing uploaded | Any modern browser | One photo or screenshot at a time, HEIC and DNG input, crop and resize in the same place | One image at a time in /compress; output format follows the input (HEIC and DNG become JPEG); no AVIF output |
| Squoosh | In your browser; its README says it "does not send your image to a server" | Any modern browser | Side-by-side visual comparison and fine codec settings for a single image | One image at a time; collects usage data with Google Analytics, per its README |
| TinyPNG | On Tinify's servers; its FAQ says files are kept for up to 48 hours | Any browser | Quick batches of up to 20 images, 5 MB each, on the free web tier | Upload required; free conversion is capped at 3 images |
| ImageOptim | On your Mac | macOS 11 or later | Dragging whole folders; lossless by default | Mac only; lossy settings are opt-in |
| sharp | On your machine (Node.js) | Any OS with Node.js | Scripts and build steps: resize and encode JPEG, PNG, WebP, AVIF | Needs code or a small script |
| cwebp | On your machine | Command line | Converting to WebP with full control of libwebp settings | WebP output only |
| pngquant | On your machine | Command line, libraries | Shrinking PNGs with transparency by reducing the palette | Lossy; PNG only |
All facts in this table come from each project's own page, linked in Sources.
How I measured
The benchmark is a versioned script, scripts/benchmark-compressors/run.mjs, in the SnapCompress repository. It does the following:
- Generates three test images from fixed arithmetic, so they are identical on every machine and free to share: a 1200×800 photo-like landscape with grain (also saved as a quality-92 JPEG, the kind of file people upload), a 1200×800 app screenshot, and an 800×800 logo-like graphic with transparency.
- Runs SnapCompress's own code paths in headless Chromium 153: the /compress pipeline (decode, then one canvas encode at the chosen quality; PNG goes through
browser-image-compression2.0.2) and the /convert to WebP pipeline (@jsquash/webp1.5.0). - Runs reference encoders through sharp 0.35.5 (libvips 8.18.7): JPEG with standard and MozJPEG settings, WebP, AVIF, PNG, palette PNG, and lossless WebP.
- Records the size, SHA-256 hash, and PSNR of every output against the original pixels. PSNR is a simple fidelity number in decibels; higher is closer to the original. It is not a substitute for looking at the image.
Running it twice gives byte-identical results. You can download the results file (sizes, hashes, versions) and the inputs: photo.png, photo.jpg, screenshot.png, and graphic.png.
Results
Run on October 8, 2026, on macOS (Apple Silicon). Sizes in KB (1 KB = 1,024 bytes).
Photo: SnapCompress at each quality setting
Input: photo.jpg, 231.3 KB.
| Quality setting | /compress output (JPEG) | PSNR | /convert to WebP | PSNR |
|---|---|---|---|---|
| 50 | 38.2 KB | 35.01 dB | 20.3 KB | 34.89 dB |
| 60 | 47.5 KB | 35.35 dB | 30.1 KB | 35.05 dB |
| 70 | 74.6 KB | 35.67 dB | 40.8 KB | 35.21 dB |
| 80 (default) | 91.5 KB | 36.25 dB | 82.8 KB | 35.64 dB |
| 90 | 225.1 KB | 37.40 dB | 192.0 KB | 37.19 dB |
WebP output was 9% to 47% smaller than JPEG output at the same setting, with similar PSNR, and both formats now get steadily larger and closer to the original as the setting goes up.
That was not true in the first run of this benchmark. The /compress pipeline used to re-encode every image at quality 0.95 before compressing it, so the final file was a second-generation JPEG, and quality 80 came out larger (137.1 KB) and further from the original (33.25 dB) than quality 70. The benchmark caught it, the pipeline now decodes once and encodes once, and the table above is from the fixed version. Publishing the measurements is what made the bug visible.
Photo: reference encoders from the original pixels
These start from the lossless photo.png, so they are not directly comparable with the table above, which starts from a JPEG.
| Encoder (sharp) | Quality 50 | Quality 80 | Quality 90 |
|---|---|---|---|
| JPEG, standard settings | 36.4 KB, 35.07 dB | 99.0 KB, 36.43 dB | 195.9 KB, 37.98 dB |
| JPEG, MozJPEG settings | 20.7 KB, 34.76 dB | 63.0 KB, 36.04 dB | 133.9 KB, 37.39 dB |
| WebP | 17.0 KB, 35.00 dB | 71.9 KB, 36.36 dB | 189.9 KB, 40.50 dB |
| AVIF | 20.4 KB, 35.65 dB | 179.3 KB, 40.89 dB | 293.2 KB, 45.24 dB |
Quality numbers are not comparable across formats. In this test, AVIF at quality 50 (20.4 KB, 35.65 dB) scored a higher PSNR than standard JPEG at quality 60 (47.8 KB, 35.39 dB) at less than half the size. MozJPEG settings saved 32% to 45% over standard JPEG settings at the same quality.
Screenshot and transparent graphic
| Input | Output | Size | PSNR |
|---|---|---|---|
| screenshot.png (13.7 KB) | SnapCompress /compress, quality 80 (PNG) | 7.5 KB | identical pixels |
| screenshot.png | SnapCompress /convert to WebP, quality 80 | 32.4 KB | 41.39 dB |
| screenshot.png | sharp lossless WebP | 4.0 KB | identical pixels |
| screenshot.png | sharp JPEG, quality 80 | 95.7 KB | 38.83 dB |
| graphic.png (12.9 KB) | SnapCompress /compress, quality 80 (PNG) | 10.5 KB | 73.58 dB |
| graphic.png | sharp palette PNG (pngquant's libimagequant) | 9.8 KB | identical pixels |
| graphic.png | sharp lossless WebP | 5.5 KB | identical pixels |
For flat graphics, lossy formats work against you. The screenshot grew from 13.7 KB to 95.7 KB as a JPEG and to 32.4 KB as a lossy WebP. Keep screenshots and logos in PNG (and compress them in /compress), or use lossless WebP where it is supported.
The full table, with every quality step and hash, is in the results file.
Limitations
- Three synthetic images are not a photo library. Real photos will give different absolute numbers. The trends are what this set shows.
- SnapCompress encodes with your browser. These numbers are from Chromium; Safari and Firefox use different JPEG encoders and will give different sizes for the same setting.
- TinyPNG, Squoosh, and ImageOptim are not in the measurements. TinyPNG requires uploading files to its servers, and the other two are interactive apps that a script cannot drive reproducibly. They are described from their documentation only.
- There are no speed numbers, because speed depends on your device and cannot be reproduced.
Which one should you use?
- One photo, private, in the browser: SnapCompress or Squoosh. Squoosh gives more codec controls; SnapCompress also opens HEIC and DNG and has crop and resize next to it.
- iPhone HEIC photos to JPEG: /heic-to-jpg.
- A folder of images on a Mac: ImageOptim, lossless by default.
- A build step or script: sharp for resizing and encoding, cwebp for WebP, pngquant for PNGs with transparency. Example with cwebp, whose default quality is 75:
cwebp -q 75 photo.jpg -o photo.webp
cwebp -lossless screenshot.png -o screenshot.webp
pngquant --quality=65-80 logo.png
For the format decision itself, see JPEG vs PNG vs WebP vs AVIF. For the step-by-step process, see how to compress an image.
Sources
- TinyPNG home page and FAQ (limits, formats, 48-hour retention): tinypng.com, accessed 2026-10-08.
- Squoosh README (local processing, Google Analytics, Apache-2.0): github.com/GoogleChromeLabs/squoosh, accessed 2026-10-08.
- ImageOptim for Mac (macOS 11+, GPL, lossless by default, bundled tools): imageoptim.com/mac, accessed 2026-10-08.
- sharp documentation (libvips, output formats, Apache-2.0): sharp.pixelplumbing.com, accessed 2026-10-08.
- cwebp manual (default quality 75,
-lossless): developers.google.com/speed/webp/docs/cwebp, accessed 2026-10-08. - pngquant (lossy palette PNG with alpha, GPL or commercial): pngquant.org, accessed 2026-10-08.
- Benchmark results and inputs (sizes, SHA-256, toolchain versions): results.json, generated 2026-10-08.
Further reading
- Guides
How to Compress an Image Without Visible Quality Loss
Compress a photo or screenshot step by step: resize first, pick the right format, then lower quality until you see a difference. Free, in your browser.
Read - Guides
JPEG vs PNG vs WebP vs AVIF: Which Image Format Should You Use?
When to use JPEG, PNG, WebP, or AVIF: browser support from caniuse, a picture element fallback example, and a decision table for web and sharing.
Read - Guides
Image Optimization for Core Web Vitals: A Developer Checklist
Fix image-driven LCP and CLS: fetchpriority, preload, srcset and sizes, width and height, AVIF and WebP, and next/image changes in Next.js 16.
Read