Raising Quality on an Already-Bad JPEG Makes It Worse
On 320 photos, re-encoding a quality-45 file at 90 made every one score slightly worse and almost doubled its size, while staying 20 points short of a clean encode.
Someone sends you a photo that looks mushy. You open it in an editor, drag the quality slider from wherever it was up to 90, save. The file is now bigger and the picture is... still mushy. You assume it at least did not hurt.
It hurt. Slightly, on every image we tested.
The three paths
The question has a clean form, so we set it up as three paths from the same original:
- A, clean: original → JPEG at quality 90
- C, damaged: original → JPEG at quality 45
- B, rescued: original → quality 45 → decode → quality 90
B and A end in the same format, the same quality, the same encoder. B just went through one low-quality pass first. If raising the slider recovers detail, B should land near A. If it does nothing, B should land near C.
The numbers
320 JPEGs, scaled to 768 px on the long edge, scored with SSIMULACRA2 against the decoded original.
- A clean: mean score 87.84, 261.0 KB
- C damaged at q45: mean score 67.75, 96.3 KB
- B re-encoded at q90: mean score 67.32, 183.7 KB
The q45 pass cost 20.09 points. Re-encoding at 90 recovered minus 0.43 of them.
Not "zero". Minus. All 320 images came out slightly worse than the file they started from, and the average was 2.1% of the loss in the wrong direction.
The size went the other way: 183.7 KB against 96.3 KB, an increase of 90.9%, for a file that still sits 20.5 points below a clean encode.
Why it gets worse rather than just not helping
A q45 image is full of compression artifacts. They are not detail, but they are structure, and an encoder has to spend bits on them. At quality 90 it tries hard to represent every one of them faithfully, which is a lot of work for something you would rather it ignored. Then that effort introduces its own quantization and throws away a little more.
So the second pass does not restore anything. It spends roughly twice the bytes describing the damage more precisely, and loses a fraction of a point doing it.
Our earlier piece on why compressing an image can make it bigger is the same mechanism from a different angle: the encoder has no way to know that some of the signal it is being asked to preserve is not signal at all.
What to do instead
If you still have the original, re-encode from the original. That is the only path that recovers anything, because it is the only one that has the detail.
If the q45 file is all you have, leave it alone. More precisely:
- Do not re-encode it to a higher quality. The test above covers that.
- Lossless optimisation is fine. Stripping metadata or rewriting the entropy coding does not touch pixels and costs nothing in quality.
- If it must be smaller, go down, not up. Re-encoding at quality 60 will at least save bytes. It will look worse, but it will look worse by an amount you chose.
- If it must be bigger (because a form wants "high quality"), you have a file that meets the letter of the requirement and none of the intent. There is no tool that fixes this.
Caveats
Pillow's libjpeg, not this site's encoders. The absolute numbers would shift with a different encoder, but "re-encoding a damaged file at high quality does not recover it" is a property of lossy compression rather than of one implementation. 768 px sources, mostly already-compressed JPEGs.
Quality 45 and 90 were the only two settings tested. A different pair would change the magnitude. The direction of the result seems unlikely to reverse, though: once detail is gone, later encoders cannot see what was there.
And SSIMULACRA2 is a metric. That said, this is the one result where you can verify it by eye in ten seconds: open C and B at 100% and try to find a difference that favours B.
Reproducing it
The script is tools/measure-quality-recovery.py. It needs Pillow and ssimulacra2 on the path, and takes about six minutes for 320 images.
If your own images behave differently, tell us. The about page has the address, and all six of our measurements are collected on one summary page.