Hokusai carved one block and pulled thousands of impressions from it, and every pull wore the block down a little further. A JPEG saved from a JPEG is the same idea with arithmetic instead of cherry wood.
Eighteen real files, measured. At matched fidelity the same pictures cost 983 KB as WebP and 1,812 KB as JPEG.
Every picture in the gallery on this site was measured for this article. Not estimated, not benchmarked against somebody else's test corpus. Eighteen files came off the server, went through a script, and came back with numbers, and the numbers say the JPEGs are carrying roughly three times the bytes per megapixel that the WebP files next to them are carrying, for a difference nobody looking at a phone screen can see.
That is not a general claim about codecs. It is a measurement of these specific files, and the method is at the bottom so anybody can repeat it on their own output.
Eighteen images, 2,966 KB in total. Fourteen of them are JPEGs at 1168 by 784. Three are WebP at 1024 by 1536. One is a JPEG at 720 by 1280 that behaves completely differently from the rest and is worth its own paragraph.
| Group | Files | Dimensions | Median size | KB per megapixel |
|---|---|---|---|---|
| Gallery JPEGs | 14 | 1168 x 784 | 185 KB | 193 |
| Gallery WebP | 3 | 1024 x 1536 | 99 KB | 63 |
| The odd one out | 1 | 720 x 1280 | 79 KB | 85 |
Bytes per megapixel is the only fair way to compare files at different resolutions, and it is the number most people never compute. A 250 KB file at 1168 by 784 is heavier, per pixel of picture, than a 115 KB file at 1024 by 1536. Sorting a folder by file size tells you almost nothing.
A JPEG carries its own quality setting inside it, in the quantization tables. You do not have to guess. The first four luma coefficients on all fourteen gallery JPEGs read 2, 1, 1, 2. Those are the divisors applied to the lowest frequency parts of each 8 by 8 block, and values that small mean almost nothing is being thrown away. That is a quality setting in the mid nineties or above.
The odd file out reads 8, 6, 5, 8. Same structure, four times the divisor. That file was saved at a much more aggressive setting, and it is the only one in the set that was. It also happens to be the smallest per megapixel of any JPEG here, which is the whole point: somebody made a different choice on that one file and it cost 55 percent fewer bytes per pixel of picture.
Image.open(path).quantization. Small numbers mean high quality. It is the closest thing to a receipt that the format offers.The fourteen gallery JPEGs total 2,589 KB. Every one of them was decoded and re encoded, first to WebP and then to JPEG again, across a range of quality settings, with the fidelity measured against the file that came off the server. Peak signal to noise ratio is the metric, in decibels, and higher is better. Anything above about 40 dB is a difference you will not see without flipping between two versions at full zoom.
| Encoding | Total size | Share of original | Median PSNR |
|---|---|---|---|
| Original JPEGs off the server | 2,589 KB | 100% | reference |
| JPEG quality 95 | 2,464 KB | 95.2% | 56.5 dB |
| JPEG quality 90 | 1,812 KB | 70.0% | 44.3 dB |
| JPEG quality 85 | 1,333 KB | 51.5% | 43.0 dB |
| WebP quality 95 | 1,615 KB | 62.4% | 46.1 dB |
| WebP quality 90 | 983 KB | 38.0% | 43.8 dB |
| WebP quality 85 | 724 KB | 28.0% | 42.1 dB |
| WebP quality 80 | 580 KB | 22.4% | 41.0 dB |
| WebP quality 75 | 477 KB | 18.4% | 39.6 dB |
Compare the two rows that land in the same fidelity band. JPEG at quality 90 gives 44.3 dB for 70 percent of the original bytes. WebP at quality 90 gives 43.8 dB for 38 percent. Half a decibel apart, and one of them is 1,812 KB while the other is 983 KB.
That is the entire finding. Not a codec war, not a claim that WebP is better at everything. On this specific corpus, at matched fidelity, the same pictures cost roughly half.
| File | On the server | WebP q90 | WebP q80 |
|---|---|---|---|
| nurse-new-01 | 174 KB | 64 KB | 38 KB |
| nurse-new-010 | 157 KB | 55 KB | 32 KB |
| nurse-new-02 | 185 KB | 70 KB | 42 KB |
| nurse-new-03 | 200 KB | 78 KB | 45 KB |
Averages hide things, so those are four real files rather than a mean. The pattern holds file by file, not just in aggregate.
The instinct when somebody says the word lossy is to reach for PNG. Those same fourteen images, saved as optimised PNG, come to 10,181 KB. That is 3.9 times what the JPEGs already cost, to preserve detail that was thrown away by the first JPEG encode and is not coming back.
PNG is the right format for the file that comes straight out of the generator, before anything touches it, and it is the right format if you want the embedded generation metadata to survive. It is the wrong format for a gallery page. Storing a lossless copy of a lossy source is paying full price for a photocopy.
Re encoding an existing JPEG at quality 95 produced files at 95.2 percent of the original size and 56.5 dB. Fifty six decibels is effectively invisible, which tells you the second encode at a high setting barely touched anything. The loss compounds, it just compounds slowly at high quality settings.
Where it stops being slow is the third and fourth pass at moderate settings, which is exactly what happens when a picture goes generator, then editor, then upload, then a platform's own recompression. Nobody in that chain is doing anything wrong individually. The stack is what does the damage.
Eighteen files pulled from the site's own images directory. Sizes read with os.path.getsize. Dimensions and quantization tables read with Pillow. Re encodes done with Pillow using method=6 for WebP and optimize=True, progressive=True for JPEG. PSNR computed in RGB against the decoded original, per file, and the median reported rather than the mean so one outlier cannot move it.
Anybody can run the same thing on their own folder. The only part that takes any thought is comparing against the file you actually have rather than against a hypothetical master you no longer possess.
PSNR is a weak proxy for what an eye notices. It punishes an evenly spread small error and forgives a concentrated one, and the errors that ruin an AI generated portrait are concentrated: banding in a gradient across a cheek, mush in an iris, a hard edge in hair going soft. A file can hold 43 dB and still look visibly worse in the one region anybody was looking at. Every number in this article should be treated as a size argument backed by a rough fidelity guardrail, not as proof that two files look identical.
Browser support is also not the issue it was. WebP has been supported everywhere that matters for years. AVIF would very likely beat every row in that table on size, and it was left out on purpose because encode time and tooling maturity are real costs and this test was meant to be one anybody could repeat in a minute.
And a gallery of eighteen images is a gallery of eighteen images. Two of the three WebP files here are of a different subject at a different aspect ratio than the fourteen JPEGs, so the 193 versus 63 comparison between those two groups is suggestive rather than controlled. The controlled comparison is the re encode table, where the same fourteen files are measured against themselves. That is the one to trust.