DEV Community

Cover image for I compressed 7 images 77 different ways. Here's what actually shrank (and what got ugly)
Enlh NG
Enlh NG

Posted on Edited on

I compressed 7 images 77 different ways. Here's what actually shrank (and what got ugly)

Every "how to compress images" article tells you to "use WebP." I wanted to see how much that advice is worth, so I ran the same seven images through JPEG, WebP, AVIF and PNG at several quality settings, and measured two things: file size and how close the result is to the original.

Short version: the format matters less than which kind of image you have. Photos and graphics behave in opposite ways, and picking the wrong format for a graphic costs you more than any quality slider can save.

The setup

  • Images (7): five photos (a real fundus photo at 1411×1411, plus four standard sample photos at 512–640 px wide), one flat-colour bar chart (800×500) and one UI screenshot (1440×900).
  • Encoders: Pillow 12.3 (libjpeg, libwebp, libavif). JPEG at q95/85/75/60 (optimized + progressive), WebP at q85/75/60 (method=6), AVIF at q70/50, PNG lossless, and PNG reduced to 256 colours.
  • Quality metric: SSIM against the decoded original (1.0 = identical). It's a rough proxy for "looks the same", not a verdict from human eyes.
  • Units: 1 KB = 1,024 bytes throughout.
  • Baseline: every size below is shown as a percentage of the same image saved as JPEG q95, which is roughly what an export dialog gives you by default.

I tested the encoder libraries, not any website's pipeline. Online tools choose their own presets, so treat these numbers as "what the codecs can do", not "what tool X will give you".

from PIL import Image
im = Image.open("photo.png").convert("RGB")
im.save("out.jpg",  quality=75, optimize=True, progressive=True)
im.save("out.webp", quality=75, method=6)
im.save("out.avif", quality=70, speed=6)
Enter fullscreen mode Exit fullscreen mode

Result 1: for photos, WebP q75 was smaller than JPEG q75 every time

Photos: size and SSIM by format

(the SSIM axis starts at 0.88 to make differences visible)

Photo JPEG q75 WebP q75 WebP vs JPEG size SSIM JPEG / WebP
astronaut 512² 38.2 KB 24.0 KB −37% 0.9405 / 0.9395
china 640×427 56.4 KB 49.0 KB −13% 0.9414 / 0.9566
coffee 600×400 39.5 KB 28.7 KB −27% 0.9083 / 0.9144
flower 640×427 25.5 KB 15.3 KB −40% 0.9369 / 0.9368
fundus 1411² 104.3 KB 41.0 KB −61% 0.9751 / 0.9568

On two photos WebP matched JPEG's SSIM almost exactly while being 37–40% smaller; on two it scored higher and was smaller; on the large photo it was 61% smaller but visibly scored lower (0.957 vs 0.975). So "WebP is 30% smaller" is a fair rule of thumb, but at the same number on the quality slider you don't get the same quality. Compare at matched SSIM, or just look at the result.

AVIF at q70 was often the closest to the original (highest SSIM on four of five photos) at a size that varied from smaller than JPEG q75 to slightly larger. At q50 it got very small, for example 29.0 KB against 138.5 KB for JPEG q95 on the china photo, but SSIM dropped to 0.92. I would not claim AVIF is "always smallest": with these default Pillow settings, it was not.

Result 2: for graphics and screenshots, JPEG was the worst choice

Image PNG lossless JPEG q75 WebP q75 PNG 256 colours
Flat bar chart 9.7 KB 14.4 KB 4.1 KB 4.4 KB
UI screenshot 86.0 KB 52.1 KB 26.9 KB 24.9 KB

For the flat chart, a lossless PNG (9.7 KB) beat JPEG q75 (14.4 KB), and JPEG q95 was 28.8 KB, three times the PNG. JPEG is built for noisy, continuous-tone photos. On sharp edges and flat colour it adds ringing artifacts and gets bigger.

The 256-colour PNG was the surprise winner for the screenshot: 24.9 KB at SSIM 0.994, with sharp text, roughly 29% of the lossless PNG size. WebP q75 was about the same size.

Result 3: 256-colour PNG on a photo is a trap

Quantizing a photo to 256 colours gave files 95–116% the size of JPEG q95, with an SSIM of only 0.89–0.96, plus colour banding. Palette PNG is great for graphics and pointless for photos.

Result 4: resizing beat every codec setting

Same fundus photo, WebP q75:

Dimensions Size
1411×1411 41.0 KB
1000×1000 24.6 KB
700×700 15.0 KB

Dropping from 1411 to 1000 px saved more (−40%) than switching from JPEG q75 to WebP q75 did on three of the five photos (and the same as the best case). If your page displays an image at 700 px wide, shipping it at 3000 px is the real waste, and no quality slider fixes that.

What I'd actually do

  1. Resize first to the largest size the page will display (×2 if you care about high-DPI screens).
  2. Photos: WebP q75–80, or AVIF if your audience's browsers support it. Keep a JPEG fallback if you need one.
  3. Screenshots, charts, logos, UI: PNG with a reduced palette, or lossless WebP. Never JPEG.
  4. Look at the result at 100% zoom. A single metric (even SSIM) won't catch every artifact.

Tools, if you don't want to script this

  • Squoosh (Google Chrome Labs, Apache-2.0) is the one to reach for if you want to compare codecs side by side. Its README says it "does not send your image to a server."
  • TinyPNG is simple and fast; its page currently states "up to 20 images, max 5 MB each" (checked Nov 2026, so verify before relying on it), and I couldn't find a data-retention statement on the page.
  • ImageMagick/cwebp if you're comfortable on the command line: cwebp -q 75 -m 6 in.png -o out.webp.
  • I also run a free browser-based image compressor on ToolTiny with a live size preview, which is handy for one-off files.

Limits of this experiment

  • The photos are small by modern camera standards. Ratios usually hold on larger images, but I didn't test 12-megapixel files.
  • Seven images is a small sample. Results on your own images will vary, so run the script above on yours.
  • SSIM isn't perception. AVIF and WebP can blur fine texture in ways SSIM undervalues.
  • One encoder version (Pillow 12.3 / libwebp / libavif defaults). mozjpeg or a tuned avifenc would change the JPEG and AVIF rows.

If you try the script on your own images and get different numbers, I'd like to see them in the comments.

Top comments (0)