Duncan Wither

Home Notes Github LinkedIn

Why your website shouldn’t use dithered images

Written: 10-Oct-2021

This is a technical discussion1 prompted by this article on dithering. If you’ve not heard of dithering I’d recommend you read the article.

Or just look at these images2 and that’ll give you a feel for it:

David = 64.3kB
Dithered David = 13.3kB. Left click and open in new tab to view it full scales (and without the artefacts that scaling creates).

Dithering is a subject that’s caught my eye on a number of occasions. There’s something quite attractive about the effect.

The Case for dithering

Firstly I’d like to give a brief run down of the arguments presented. The logic goes: 1. Lots of websites are larger (in terms of bytes) than they might need to be, and definitely large than they used to be. 2. Images, often not needed but nice to have, are a large3 contribute to this. 3. Smaller images are good for reducing bandwidth requirements. This is good for: 1. The website host: smaller sites mean lower processing demands. 2. The environment: transferring bites over networks costs energy. 3. The reader: quicker website loads and less network utilisation, which can be surprisingly expensive. 4. Dithering images is a way of achieving this by keeping most of the visual information, with a small digital footprint.

An real example of someone using this logic to great effect would be the low tech magazine, which is excellent by the way.

Although I’ve got no problems with most of the points - I’m not going to talk about web bloat here - it’s whether dithering is the best way to go about point 4.

And I will say dithering does work. If we take a random image, and create a dithered alternative you can use smaller images. Go look at figure 1 and 2 again for reference.

JPEG

JPEG was designed, by a group of experts, to maximize quality of an image whilst minimizing the digital footprint.

Although I can’t find Floyd–Steinberg’s paper on dithering and nor have I read anything much beyond the Wikipedia page, dithering doesn’t appear to be focused on compression. It’s primary practical use is for eking more performance out of limited hardware. I.e. used to improve audio quality in a limited DAC, or to imply colours that a screen cant display. The wiki page has a bunch of great examples. And although this is barking up the same tree as compression, or at least a tree in the same forest, it doesn’t directly translate into as ideal an image compression method.

Example

So lets look at a picture of pizza. It’s home-made, so not picture perfect, but it should be illustrative. There’ll be plenty pictures shown later on, so lets just talk about numbers for now. It’s taken on a phone and stored there as a .heic. Unfortunately though although efficient4 at storage it’s not very browser readable. So we convert to a .png or .jpeg.

 IMG  |Size (MB)
.heic |     1.4 ██▉
 .png |    12.0 █████████████████████████
.jpeg |     8.5 █████████████████▋

This yields terribly large images. Given the resolution of these is terrible its good practise to crop and scale (c+s) to appropriate sizes. In this case we go from 3024x4032 to a nice 400x400. Plenty for a little bit of web based eye candy. The results speak for themselves.

    IMG  |Size (MB)
    .png |      12 █████████████████████████
 c+s.png |    0.35 ▋
   .jpeg |     8.5 █████████████████▋
c+s.jpeg |    0.22 ▍

But thankfully website generators are pretty well adept at scaling (cropping aside) images to size.

Less Bits Please…

So all this format and scaling business is just the prelude to get to the point where we’d consider dithering. And if you take your image and dither it now, the results would disagree with the points I’m putting forward.

.jpeg of Pizza = 220kB
Dithered Pizza = 58.8kB

But there’s a trick that the .jpeg standard has up it’s sleeve: Variable Quality. By adjusting a value - q - you can reduce the file size at the cost of quality. Luckily for us, the results aren’t linear, so we can loose many bits, whilst still retaining a reasonable image of a pizza.

The table on the JPEG Wikipedia page does a better job than I could of explaining this parameter, but I’ve made a chart of some values along with a selection of dithered images.

Smallest of the Small

Here’s a selection, and you can make your own mind up.

The smallest picture: q = 10, size = 10.kB. Just recognisable as pizza.
The smallest dither, much less recognisable as pizza: black and white with a Bayer filter = 12.6kB

Note the patterns found with the Bayer filter. This reduces the file size, but detracts significantly from the final image.

I think these are pretty unusable, except as abstract art, so lets allow ourselves a little larger images.

One step up

Tatty looking, but unmistakably pizza (IMHO): q = 25, size = 19.9kB
Smallest error diffusion dither, I think it looks alien here, but the mushrooms (esp. bottom middle) are recognisable: black and white = 21.8kB
The smallest dithered image where I’d say its unmistakably pizza: red black and white = 35.1kB

This is the clearest indication of the benefits of using .jpg files. The image is unmistakably pizza, and its takes another ~13.3kB (66%) more data to give a similar (but still worse in my view) result. In the following bar chart you can see that dithered images fall all about the spectrum of q values, wiht varying results. I’d say that any usable dithered image take about as much space as a q of 50, and at that point the .jpg image is much clearer. To further solidify that I’d look at the hole in the burnt crust in the lower middle portion of the photos, and see if its even spot-able (let alone recognisable) in the dithered images for what it is. There is an argument to be made that the picture chosen isn’t the best to highlight dithering benefits5, but I’d say that’s good, because it shows where dithering breaks down and another - more robust - method doesn’t.

     IMG    |Size (kB)
Q=90        |    64.1 █████████████████████████
Di=rgbcmykw |    58.8 ██████████████████████▉
Q=85        |    56.1 █████████████████████▉
Di=rgbkw    |    53.2 ████████████████████▋
Q=80        |    51.0 ███████████████████▉
Di=rgbk     |    49.8 ███████████████████▍
Q=75        |    46.8 ██████████████████▎
Di=keew**   |    45.0 █████████████████▌
Q=70        |    42.4 ████████████████▌
Di=rykw     |    38.9 ███████████████▏
Di=cmykw    |    38.4 ██████████████▉
Di=cmyk     |    37.8 ██████████████▋
Q=65        |    35.6 █████████████▉
Di=rkw      |    35.1 █████████████▋
Q=60        |    33.9 █████████████▏
Q=55        |    32.4 ████████████▋
Q=50        |    31.2 ████████████▏
Di=rgbkw*   |    27.9 ██████████▉
Di=kw       |    21.8 ████████▌
Q=25        |    19.9 ███████▊
Di=kw*      |    12.6 ████▉
Q=10        |    10.7 ████▏

Where Q= is the size of .jpg images of said q values and Di= is dithered images with a given colour palette.r=red,g=green, b=blue, c=cyan, m=magenta, y=yellow, k=black, e=grey and w=white. Thecolour palette has a noticeable impact on size, and in my opinion understanding of the image.

Links to all the images are in the appendix

* These are done with Bayer filters, producing notably worse results. The rest are done with Floyd Steinberg Error diffusion. These are different ways of working out where to put the dots to produce the dithering effect. Play around with this online dithering tool to get a feel for it, but it’s beyond the scope of this post.

** This has two shades of grey, basically giving 4 greyscale options.

However, I’ll show some more dithered images for fun…

Other Notables

Greyscale adds alot of detail: black, grey (#555555), grey (#aaaaaa) and white = 45kB
Bayer dithering with colour doesn’t work well: red, green. blue, black and white = 27.9kB
The CMYK colour space works well here. It feels right given its use for printing. CMYK = 45kB
The RGBK colour space doesn’t work in size or visual fidelity = 49.8kB

Machine-ability

The beauty of the q value is it’s simplicity. It’s boiled down all the complexity into one number that you can change and a machine can interpret. For this website for instance, in my config file there’s a line I change, and all the auto-scaled imaged also have their quality shifted, which is great for file sizes.

There are shortcomings, like not converting .png files to .jpg for adjustment, but for some things - like small screenshots - I wouldn’t want that, so it’s an understandable design choice.

I’ve also looked into other methods, like minimising the colour palette of .pngs, which on an old version of this site saved me several MB on a single image from some fluid simulation. But all of this takes tuning for each image - like dithering does - for best results. An example would be the best dithered image - in terms of size and recognisability - would be the one with the red, yellow, black and white colour pallet which was found through trial, error and guesswork:

My best dithered pizza = 38.9kB

For this specific case the trade-off of using colour is so important because the shape is somewhat alien, and that’s the point. Individual tuning means more effort, and more effort means (most) people won’t do it. So that’s part of the beauty of the simplicity of the q value.

Conclusion

Dithering isn’t the best compression method for images, but I will admit there’s a charm to it, and an aesthetic that is - in my humble opinion - much more attractive than highly compressed jpeg images. There is a danger in how they get used: virtue signalling. The question is are you trying to save bandwidth, or do you want to look like you are? Because we’ve seen low quality JPEGs for years they aren’t interesting, and belay a old-but-not-vintage feel to a site, whereas a dithered image is something novel and stands out.

I’d argue that places like the low tech magazine use them genuinely and fits in well with their aesthetic, but for equivalent results in visual fidelity I’d say the low cost of of colour makes the JPEG superior in conveying information.

Alas, as mentioned at the start, images often aren’t required to convey information but act like a pause for readers, and a nice pattern can do the trick. Furthermore, dithered images can be basically the same size as low quality JPEGs, and both are much better than scaled PNGs on your website.

Unsurprisingly then the conclusion is more nuanced than the title conveys.

See / Read more

In exploring this topic I found some interesting sites, give them a gander if you’re interested: - Dither me this - an online dithering tool. - Didder - an excellent command line tool for dithering images locally. - HTTP Archive - page weight tracker. Just an interesting website to explore. - Low Tech Mag Github - Provides some more technical info on how the low tech magazine works.

Appendix


  1. I’d hesitate to call it a rebuttal.↩︎

  2. Michelangelo’s David appears to be the default dithering image.↩︎

  3. Citation Needed.↩︎

  4. .heic is a combination of the High Efficiency Image File Format and the High Efficiency Video Coding (source). So lots of high efficiency.↩︎

  5. I didn’t pick it for that reason.↩︎