image · 8 min read

How to compress an image without wrecking it

The quality slider is not a percentage of anything. Knowing what it actually does turns a guess into a decision.

Everyone has moved that slider and hoped. Eighty feels safe, ninety feels careful, a hundred feels responsible. None of those numbers mean what they look like they mean, and the difference between the good ones and the bad ones is larger than most people expect.

What JPEG is doing

A JPEG encoder does not store your pixels. It cuts the image into 8×8 blocks and rewrites each one as a set of frequencies — how much flat tone it has, how much gentle variation, how much fine detail. That transform is lossless so far; nothing has gone.

The loss happens next. Each frequency is divided by a number from a quantisation table and rounded, and the numbers for fine detail are much larger than the ones for flat tone. Divide by a big number and round, and small values become zero. The detail is not compressed — it is deleted, and zeros compress to almost nothing.

The quality setting scales that table. It is not a percentage of anything; it picks how aggressive the rounding is. So the setting decides how much of the finest detail survives, and that detail is the most expensive part of the file and the part your eye is worst at noticing.

One more thing happens quietly. Human vision resolves brightness far better than colour, so most encoders keep full brightness detail and half the colour detail. This is chroma subsampling, it is invisible on a photograph, and it is why fine red text on a blue background comes out looking chewed.

What the setting costs

The interesting question is not what quality looks like but what it costs. Here is the same bitmap encoded eleven times:

one bitmap, encoded eleven timesmeasured by scripts/measure-jpeg.mjs — the shape is JPEG's, the bytes are this image'sq 1001100 KB — none of it visibleq 95568 KBq 90444 KBq 85371 KBq 80320 KB — where most photos belongq 75279 KBq 70251 KBq 60202 KBq 50165 KBq 40132 KBq 3098 KB
One step down from 100 halves the file. That single step saves more than every step from 85 to 30 put together, and no one can see it — quality 100 spends its bytes recording the difference between grain and slightly different grain. The same bitmap as a lossless PNG is 2,299 KB, twice the largest JPEG here, which is why photographs are not PNGs.

One step down from 100 halves the file. That step alone saves more than every step from 85 down to 30 put together, and there is nothing in it a person can see — at quality 100 the encoder is faithfully recording the difference between grain and slightly different grain.

Below about 75 the curve flattens: each step costs visible quality and returns progressively fewer bytes. That is the whole shape of the decision. Between 75 and 85 is where nearly every photograph belongs.

Why re-saving makes it worse

Open a JPEG, crop it, save it. The encoder starts from what it was given — an image that has already had its fine detail rounded away — and rounds again against a grid that no longer lines up with the first one. Errors from the first pass become input to the second. This is generation loss, and it accumulates without ever showing you a moment where it went wrong.

The practical rule: keep the original. Edit from it every time, and export a JPEG as the last step rather than as a working format. If you are handed a JPEG and must edit it, accept that you have one generation to spend and spend it once.

The step that beats every setting

A phone photograph is around 4,000 pixels wide. A blog post displays it at 800. Uploading the original means sending twenty-five times the pixels anyone will see, and no quality setting recovers that — you are compressing detail that is going to be thrown away by the browser anyway.

Resize first, then compress. Halving both dimensions quarters the pixel count before the encoder has done anything. It is the largest saving available and it is the one people skip, because the slider is visible and the dimensions are not.

When JPEG is the wrong answer

JPEG assumes photographs: smooth tone, no hard edges, nothing needing to be exact. Give it anything else and it fails in a specific, recognisable way — grey smudges around lettering, halos along flat borders.

  • Screenshots, text, line art, logos — PNG. Few colours and hard edges are what it is for, and it is lossless, so nothing smears.
  • Anything transparent — PNG or WebP. JPEG has no transparency; save one and the transparent parts turn black or white.
  • Photographs — JPEG or WebP. Never PNG. The bitmap in the figure above is 2,299 KB as a lossless PNG, twice the size of the largest JPEG in the chart, and it looks the same.

WebP and AVIF

WebP is roughly 25–35% smaller than JPEG at matching quality, supports transparency, and works in every browser people actually use. It is the sensible default now.

AVIF goes further, sometimes dramatically, and is slower to encode and less universally supported. It is worth it for a site's own images where you control the pipeline and can serve a fallback. It is not worth it for a photo you are about to email to someone.

The short version

Resize to the size it will actually be seen at. Export at quality 80 — or 85 if it is going to be printed or examined closely. Use WebP where you can, PNG for anything with text or transparency, and never PNG for a photograph. Keep the original, and never edit a JPEG twice.

Every one of those steps can be done here, in this browser, on a file that never leaves your device — which also means you can try quality 95 and quality 80 on the same photo and compare the two files before deciding, without uploading anything to find out.

Tools from this guide