Back to Blog

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?

ToolWhere your image is processedPlatformGood forLimits worth knowing
SnapCompress (mine)In your browser, nothing uploadedAny modern browserOne photo or screenshot at a time, HEIC and DNG input, crop and resize in the same placeOne image at a time in /compress; output format follows the input (HEIC and DNG become JPEG); no AVIF output
SquooshIn your browser; its README says it "does not send your image to a server"Any modern browserSide-by-side visual comparison and fine codec settings for a single imageOne image at a time; collects usage data with Google Analytics, per its README
TinyPNGOn Tinify's servers; its FAQ says files are kept for up to 48 hoursAny browserQuick batches of up to 20 images, 5 MB each, on the free web tierUpload required; free conversion is capped at 3 images
ImageOptimOn your MacmacOS 11 or laterDragging whole folders; lossless by defaultMac only; lossy settings are opt-in
sharpOn your machine (Node.js)Any OS with Node.jsScripts and build steps: resize and encode JPEG, PNG, WebP, AVIFNeeds code or a small script
cwebpOn your machineCommand lineConverting to WebP with full control of libwebp settingsWebP output only
pngquantOn your machineCommand line, librariesShrinking PNGs with transparency by reducing the paletteLossy; 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:

  1. 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.
  2. 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-compression 2.0.2) and the /convert to WebP pipeline (@jsquash/webp 1.5.0).
  3. 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.
  4. 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 WebPPSNR
5038.2 KB35.01 dB20.3 KB34.89 dB
6047.5 KB35.35 dB30.1 KB35.05 dB
7074.6 KB35.67 dB40.8 KB35.21 dB
80 (default)91.5 KB36.25 dB82.8 KB35.64 dB
90225.1 KB37.40 dB192.0 KB37.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 50Quality 80Quality 90
JPEG, standard settings36.4 KB, 35.07 dB99.0 KB, 36.43 dB195.9 KB, 37.98 dB
JPEG, MozJPEG settings20.7 KB, 34.76 dB63.0 KB, 36.04 dB133.9 KB, 37.39 dB
WebP17.0 KB, 35.00 dB71.9 KB, 36.36 dB189.9 KB, 40.50 dB
AVIF20.4 KB, 35.65 dB179.3 KB, 40.89 dB293.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

InputOutputSizePSNR
screenshot.png (13.7 KB)SnapCompress /compress, quality 80 (PNG)7.5 KBidentical pixels
screenshot.pngSnapCompress /convert to WebP, quality 8032.4 KB41.39 dB
screenshot.pngsharp lossless WebP4.0 KBidentical pixels
screenshot.pngsharp JPEG, quality 8095.7 KB38.83 dB
graphic.png (12.9 KB)SnapCompress /compress, quality 80 (PNG)10.5 KB73.58 dB
graphic.pngsharp palette PNG (pngquant's libimagequant)9.8 KBidentical pixels
graphic.pngsharp lossless WebP5.5 KBidentical 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:
bash
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

Further reading