Gratitude Day 23: Dithering (Floyd and Steinberg, take a bow!)

Wed 23 September 2026

Background / Basic Concepts

Another entry in the "Things that old folks care about but young folks don't know much about" department, let's talk about dithering!

Dithering was how you got your 8/16-bit computers to look like they had more colors (or shades of gray) onscreen than they could really produce. It was even used in chiptunes, to make a single-voice PC speaker sound like it actually had four or more voices by quickly switching between the different parts of the tune, sort of like PWM, if you're familiar with that.

On a high-level, "dithering" just means quickly jumping back and forth between discrete values, giving the impression of a values in-between the two. For example, if you wanted to produce a graphic sort of like this:

________░░░░░░░░▒▒▒▒▒▒▒▒▓▓▓▓▓▓▓▓████████

but the only values you have at your disposal are "_" and "█," then you could do something like this:

________█_______█___█___█_█_█_█_████████

Comparing the two, you can see the vague similarity:

________░░░░░░░░▒▒▒▒▒▒▒▒▓▓▓▓▓▓▓▓████████

________█_______█___█___█_█_█_█_████████

That's the basic idea.


Thresholding

The most conceptually simple dither isn't a dither at all, but a 50% threshold. In high-level pseudocode it looks something like this:

for pixel in image
do
    if pixel.to_grayscale() >= 128
    then
        newpixel=255
    else
        newpixel=0
    fi
    newimage.append(newpixel)

If you remember what Xeroxes (photocopies) of photos looked like before the advent of digital copiers, the end result will look familiar to you, and it's not great. 😄

Image of Michaelangelo's David in grayscale, sourced from Wikipedia right arrow Image of Michaelangelo's David in threshold mono, sourced from Wikipedia


Randomness dither

In my opinion, the next most conceptually simple method of dithering is the random or randomness dither. In pseudocode, it looks like this:

for pixel in image
do
    if pixel.to_grayscale() >= random(0,255)
    then
        newpixel=255
    else
        newpixel=0
    fi
    newimage.append(newpixel)

It yields an image that looks a little more like the original, but is kind of noisy:

Image of Michaelangelo's David in grayscale, sourced from Wikipedia right arrow Image of Michaelangelo's David in random dither mono, sourced from Wikipedia

However, the randomness dither does somewhat emulate the way that "the real world" (a.k.a. quantum physics?) accomplishes dithering, so if used in a quickly-moving animation, it almost looks plausible:

Image of Michaelangelo's David sourced from Wikipedia, converted to a random-dithered animation with 10 frames


Ordered / Bayer dither

This is probably the dithering algorithm that people are most familiar with, as it's still used in "retro" graphics and games today. It is a nice middle ground between algorithms, because it is most recognizable as a dither, but it also somewhat effective at representing the source image.

Now the matrix math involved in the Bayer algorithm quickly rises above my pay grade, but a very simple 2x2 bayer matrix algorithm would look something like this:

for x in ( 0 to image.size_x() / 2, step 2 )
do
    for y in ( 0 to image.size_y() / 2, step 2 )
    do
        if image.pixel(x,y).to_grayscale() >= 51
            then newimage.assign(x,y,255)
                else newimage.assign(x,y,0)
        fi  
        if image.pixel(x+1,y).to_grayscale() >= 102
            then newimage.assign(x+1,y,255)
                else newimage.assign(x+1,y,0)
        fi  
        if image.pixel(x,y+1).to_grayscale() >= 153
            then newimage.assign(x,y+1,255)
                else newimage.assign(x,y+1,0)
        fi  
        if image.pixel(x+1,y+1).to_grayscale() >= 204
            then newimage.assign(x+1,y+1,255)
                else newimage.assign(x+1,y+1,0)
        fi  
    done
done

Image of Michaelangelo's David in grayscale, sourced from Wikipedia right arrow Image of Michaelangelo's David in bayer/ordered dither mono, sourced from Wikipedia

(Note that the example image is using an 4x4 bayer dither, not the simple 2x2 algorithm I described in the pseudocode)


Floyd-Steinberg

Floyd-Steinberg and its derivatives is the one I remember seeing the most in the early 90s, because it really does an amazing job of preserving both detail and faking shades of gray (or colors) that your system wasn't able to display. I don't see it too much anymore because it's honestly a little too good for most purposes people use dithering for today (an aesthetic retro vibe).

I won't try to explain the algorithm, because I honestly don't remember it well, but I do recall going through Wikipedia's pseudocode for it some years back and producing my own FS dithering program in Processing, so it can't be that hard. 😄

Image of Michaelangelo's David in grayscale, sourced from Wikipedia right arrow Image of Michaelangelo's David in Floyd-Steinberg dither mono, sourced from Wikipedia

(Attribution: the above images were sourced from the Wikipedia articles on Dithering and Floyd-Steinberg linked in the body of this post, with the exception of the random dither animation, which was generated from the Wikipedia grayscale original using didder and ffmpeg)

Back to index

 

Category: Tech
Tags: Computing   Gaming   Monthly themes   Non-religious post   Retrocomputing  


Gratitude Day 21: Fediverse, my Beloved

Mon 21 September 2026

What can I say about the amazing place I've called my Internet-home for the past four and a half years?

The Fediverse is an amazing place. It consistently amazes me that there are just so many cool, kind, and amazing people on there. It's what social media should have always …

Category: Humor
Tags: Beauty   Bible   Ethics   Federated Services   Humor   Life   Monthly themes   Music   Non-technical post   Personal favorites   Philosophy   Politics   Prose   Social Media  

Read More

Gratitude Day 19: UNIX Shell

Sat 19 September 2026

Disclaimer: This post was indirectly inspired by a similar (and very enjoyable) post by the amazing Stefano, but it was germinating in my brain long before I realized the thematic similarities.

I've been programming in UNIX shell (mainly ksh, then bash, and now a bit more POSIX shell) for about …

Category: Tech
Tags: BSD   Computing   FOSS (Free and Open Source Software)   FreeBSD   Hobbies   Linux   Monthly themes   Non-religious post   Productivity   UNIX   Unix Tips  

Read More

Gratitude Day 17: Permacomputing

Thu 17 September 2026

Since I spoke on Retrocomputing yesterday, I wanted to talk about its sister discipline/concept: Permacomputing.

Now, I can't talk about it at length as anything remotely approaching a subject matter expert, but it is something I've been fairly interested in for several years, ever since I learned about uxn …

Category: Tech
Tags: ADHD   Computing   Ethics   Federated Services   FOSS (Free and Open Source Software)   Hobbies   Humor   Monthly themes   Non-religious post   Philosophy   Polemic   Productivity   Retrocomputing  

Read More

Gratitude Day 15: Mental Health Awareness

Tue 15 September 2026

One thing I struggle with is seeing how much worse things are today than 30 years ago. Our capitalism is unhinged, rapacious, and vulgar. Our leaders are utterly clueless sociopaths. Our technology is manipulative and vapid. Injustice is reaching biblical levels.

But dang if mental health awareness isn't on fire …

Category: Life
Tags: ADHD   Beauty   Bible   Computing   Life   Loss   Monthly themes   Non-religious post   Non-technical post   Philosophy   Politics   The Good Place  

Read More

Gratitude Day 14: Apple Video Codec

Mon 14 September 2026

I'm continuing to explore lossy compression algorithms in my "Unsung Heroes, Human and Algorithmic" sub-theme of my September Gratitude series.

The Apple Video codec from 1991 is one of my favorite codecs: not because it's particularly efficient/effective (it's horrible), nor because it's popular (you'd be insane to use it …

Category: Tech
Tags: Computing   Entertainment   Monthly themes   Non-religious post   Retrocomputing  

Read More
Page 1 of 20

Next »