A size against SSIM curve for JPEG chroma subsampling modes 4:4:4, 4:2:2 and 4:2:0, measured on eight 1024 pixel PNG files from this gallery at quality 50 through 95

Left: mean encoded size in KB against mean luma SSIM, quality labelled at each point, further left and higher up is better. Right: mean size by quality for each subsampling mode. The three curves on the left sit almost on top of each other, which is the point of the article. Charts generated from the measurement run described below.

Chroma Subsampling Saved 20 Percent Of Every JPEG, And Luma SSIM Could Not See The Cost

Chroma subsampling is the biggest free saving in JPEG and the easiest one to measure dishonestly. Score it on luma and it looks like a rounding error. Score the colour channels and the number is 0.0164. Both of those are in this run.

Published September 6, 2026 · RealAIGirls · About a 6 minute read

Share on X Share on Facebook Share on Reddit

There is one JPEG setting that reliably takes a fifth off every file, costs nothing at decode time, and is not the quality slider. Almost nobody touches it, and the guides that mention it wave at it in a sentence.

It is chroma subsampling, and the reason it goes unexamined is more interesting than the setting itself. The standard way people measure image quality cannot see what it does.

What The Setting Actually Does

A JPEG does not store red, green and blue. It converts to luma, which is brightness, plus two colour difference channels, Cb and Cr. Human vision resolves brightness detail far better than colour detail, so the format lets you store the colour channels at lower resolution than the brightness channel.

4:4:4 keeps colour at full resolution. 4:2:2 halves it horizontally. 4:2:0 halves it in both directions, so each colour sample covers a two by two block of pixels. Luma is untouched in all three.

That last sentence is the whole trap, and we will come back to it.

The Setup

Eight 1024 pixel PNGs from this gallery. JPEG at quality 50, 60, 70, 75, 80, 85, 90 and 95, each at all three subsampling modes, with optimize on. That is 192 encodes. For every one: exact encoded byte count, wall clock encode time, wall clock decode time, and SSIM against the original PNG.

Every source is a PNG, so nothing carries a prior lossy pass that would contaminate the reference.

The Size Result

Mean encoded size across the eight files, in KB.

Quality4:4:44:2:24:2:04:2:0 saving
5089.1380.1374.3416.6%
60101.8891.3584.5117.1%
70121.59108.53100.1817.6%
75134.31119.46110.0318.1%
80154.63136.75125.5018.8%
85183.44160.97147.2219.7%
90231.17202.53185.2419.9%
95339.30294.75268.3020.9%

The saving is never smaller than 16.6 percent and it grows with quality, which is the opposite of most people's intuition. At quality 95 you are throwing away 71 KB a file.

The reason is straightforward once you see it. At high quality the encoder is spending real bytes on chroma detail, so there is more chroma to discard. At quality 50 the chroma has already been quantised into near nothing and there is less left to take.

4:2:2 lands almost exactly halfway, 10.1 to 13.1 percent. That is what you would expect from halving one axis instead of two.

The Part Where The Measurement Lies

Now score it. Here is mean SSIM computed the way essentially every image comparison on the internet computes it, on the luma channel.

Quality4:4:4 luma SSIM4:2:0 luma SSIMDifference
500.972600.97252-0.00008
700.981310.98126-0.00005
800.986190.98615-0.00004
900.991690.99166-0.00003
950.994950.99493-0.00002

Three hundred thousandths of a point, at worst. Read that table on its own and 4:2:0 is free money: a fifth of the bytes for a difference that rounds to zero.

It is not free, and the table cannot tell you that, because chroma subsampling does not touch the luma channel. Measuring it on luma is measuring the one channel the setting was designed not to change. The tiny non zero deltas that do appear come from second order interaction inside the encoder's quantisation, not from the subsampling itself.

This is not a subtle methodological quibble. It is the most common way image comparisons get published wrong, and it is why so many guides describe 4:2:0 as costing nothing.

Scoring The Channels That Actually Changed

Same encodes, SSIM computed separately on Y, Cb and Cr.

QualityModeYCbCr
754:4:40.982350.980820.98137
754:2:20.982330.973310.97400
754:2:00.982300.965960.96699
904:4:40.990010.987270.98755
904:2:20.989980.981650.98197
904:2:00.989970.975970.97644

At quality 75 the Cb channel drops 0.01486 going from 4:4:4 to 4:2:0. The luma reading for the same change was 0.00004. That is a factor of roughly 370.

At quality 90 the Cb drop is 0.01130 against a luma reading of 0.00003.

The luma column barely moves across all six rows, exactly as the format promises. The colour columns move a lot. Anybody publishing a subsampling comparison scored on luma has measured the control condition and called it a result.

So Is 4:2:0 Worth It

Yes, almost always, and now for a defensible reason rather than a measurement artefact.

A 0.015 SSIM drop on the chroma channels is a real loss and it is concentrated exactly where you would expect: hard saturated colour edges, red text on a dark ground, thin coloured lines. On photographic content, skin, hair, cloth, landscape, there is very little high frequency chroma to lose in the first place, which is why the format was designed this way in 1992 and why every camera on earth writes 4:2:0.

Where it genuinely hurts is screenshots, UI captures, charts with coloured one pixel gridlines, and anything with coloured text. Those are also the images that should not be JPEGs at all.

The honest recommendation is a short one.

Photographic content, 4:2:0. Take the 17 to 21 percent. The loss is in a channel your eye undersamples anyway.

Coloured text, charts or line art, 4:4:4, or do not use JPEG. The chroma penalty lands directly on the edges that carry the meaning.

4:2:2 is a compromise nobody needs. It gives up 11 to 13 percent of the saving to recover about half the chroma loss. If the content is safe for subsampling, go all the way; if it is not, do not subsample at all.

The Timing Column, Briefly

4:2:0 encoded faster in every row, because there is less chroma to transform. Mean encode time at quality 90 was 12.1 ms for 4:4:4 against 8.7 ms for 4:2:0. Decode time did not separate meaningfully at this resolution.

That is a small effect and it is not a reason to choose anything. It is only worth noting because it means the trade has no downside on the build side either.

Method

Eight files, eight qualities, three subsampling modes, 192 encodes scored. Pillow with the standard JPEG encoder, optimize enabled, subsampling passed explicitly as 0, 1 and 2 so no library default is in play. Every source is a PNG so there is no prior lossy pass to muddy the reference. SSIM computed with an 11 tap window and the standard stabilisers, once on the luma channel for the first two tables and once per channel on the YCbCr decomposition for the third. Encode and decode timings are wall clock around the save and load calls on one machine, indicative rather than a benchmark. Sizes are exact byte counts. Eight photographic images is a small sample and the direction of every result here is consistent across all eight files, but the magnitudes are specific to this content.