stipple

By Steph10
Scroll to open

stipple

A single-file C library for 1-bit dithering. Five algorithms, no dependencies, no allocation you did not ask for, about 600 lines. Four of those five algorithms were written by somebody other than the author. This page is about them, because in a library this small you are not depending on a project. You are depending on five people.

Gallery image 1
The source. Generated greyscale: a ramp, a sphere and a hard bar, each stressing a different part of a kernel.
Gallery image 2
Threshold. Twelve lines. Included so the others have something to be better than.
Gallery image 3
Bayer 4x4. Ordered and tileable, which is why it is the only one that survives being applied per-tile.
Gallery image 4
Floyd-Steinberg. Error pushed to four neighbours. The default, and the one most people mean.
Gallery image 5
Atkinson. Only three quarters of the error is distributed, which is why the highlights blow out like that.

Those Are Real Outputs

Every image above came out of the library, run on the generated source in the first tile. Nothing was retouched and nothing was chosen for flattery. The Atkinson sample loses detail in the bright half and that is left in, because the whole reason to ship five algorithms is that they fail differently and you need to see how before you pick one.

Ren Okabe, who wrote the file that became this one

Started it as a 40 line threshold function inside a Game Boy emulator in 2017, pulled it out when a second project needed it, and has since written almost none of the algorithms in it. Owns the API, the single-header build, and the decision that the library never allocates. Reviews everything. Describes the role as mostly saying no.

Dilnoza Rakhimova

Wrote the Floyd-Steinberg implementation and then rewrote it twice. The second rewrite removed the serpentine option after demonstrating in a 900 word issue comment that it was producing worse results than the plain scan for every input anyone could produce.

Marcus Feld

Contributed Atkinson in 2019 and the ordered Bayer matrices in 2020. Also wrote the only documentation anyone reads: a comment block above each kernel explaining what the algorithm is for rather than what it does.

Sofia Almeida

Found and fixed the off-by-one that misaligned every ordered dither by one pixel on images whose width was not a multiple of four. It had been there for three years and was visible in every tiled output, which is how it was finally spotted.

Tobi Adeyemi

Ported the whole library to fixed-point arithmetic so it runs on hardware without an FPU, and did it without changing a single output byte on the floating-point path. That constraint was self-imposed and it took nine months.

People who wrote an algorithm here

5

Lines of C

617

Heap allocations

0

Algorithms

5

Years the ordered-dither off-by-one was live

3

"

I wrote the first forty lines and the word no about four hundred times. Everything anyone actually uses this library for was written by somebody else.

"

Ren Okabe

Why Naming People Matters Here

Six hundred lines is small enough that every algorithm has exactly one author and everyone knows who it is. When the fixed-point path misbehaves on some embedded target, the useful information is not that stipple has a bug. It is that Tobi wrote that path, deliberately, under a constraint, and the issue should say so. Credit and accountability are the same list read in two directions.

Getting it into your build

0%

Copy stipple.h into your source tree. That is the install

Define STIPPLE_IMPLEMENTATION in exactly one translation unit before including it

C99 or newer. No build system, no package manager, nothing to configure

Define STIPPLE_FIXED_POINT if your target has no FPU

Pick an algorithm by looking at the samples above rather than by name