| Documentation | Build Status |
|---|---|
A dithering / digital halftoning package inspired by Lucas Pope's Obra Dinn and Surma's blogpost of the same name. Check out the gallery for an overview of all currently implemented algorithms.
To install this package and its dependencies, open the Julia REPL and run
julia> ]add DitherPunkusing DitherPunk
using Images
using TestImages
img = testimage("fabio_gray_256")
d = dither(img) # apply default algorithm: FloydSteinberg()
d = dither(img, Bayer()) # apply algorithm of choice
dither!(img) # or in-place modify image
dither!(img, Bayer()) # with the algorithm of your choiceIf no color palette is provided, DitherPunk will apply binary dithering to each color channel of the input:
| Error diffusion | Ordered dithering | Digital halftoning |
|---|---|---|
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
Any of the 29 implemented algorithms can be used.
All error diffusion, ordered dithering and halftoning methods support custom color palettes. Define your own palette or use those from ColorSchemes.jl:
using ColorSchemes
cs = ColorSchemes.flag_us
dither(img, cs) flag_us |
PuOr_6 |
websafe |
|---|---|---|
![]() |
![]() |
![]() |
DitherPunk also lets you generate optimized color palettes for each input image:
ncolors = 8
dither(img, ncolors)| 2 colors | 8 colors | 32 colors |
|---|---|---|
![]() |
![]() |
![]() |
Dithering in custom colors is supported by all error diffusion, ordered dithering and halftoning methods:
dither(img, Atkinson(), cs)
dither(img, Atkinson(), ncolors)Images can also be printed using Unicode Braille Patterns
braille(img, Bayer())
braille(img, Bayer(); invert=true)⠕⠅⠅⠅⠕⠅⠕⠅⠅⠅⠅⠅⠅⠅⠅⠅⠅⠅⠕⠅⠕⠅⠕⢅⠕⠅⠕⢅⠕⠅⠕⠅⠅⠅⠅⠅⠅⠅⠕⠅⠁⠅⠁⠅⠁⠅⠁⠅⠁⠅⠁⠅⣪⣺⣺⣺⣪⣺⣪⣺⣺⣺⣺⣺⣺⣺⣺⣺⣺⣺⣪⣺⣪⣺⣪⡺⣪⣺⣪⡺⣪⣺⣪⣺⣺⣺⣺⣺⣺⣺⣪⣺⣾⣺⣾⣺⣾⣺⣾⣺⣾⣺⣾⡂
⠕⢅⠅⠅⠕⠅⠕⠅⠅⠅⠁⠅⠁⠅⠁⠅⠁⠅⠕⠅⠕⢅⢕⢕⢕⠅⠕⠅⢕⢅⠕⢅⠅⠅⠅⠅⠅⠅⠅⠅⠅⠅⠁⠄⠁⠄⠁⠄⠁⠄⠁⠄⣪⡺⣺⣺⣪⣺⣪⣺⣺⣺⣾⣺⣾⣺⣾⣺⣾⣺⣪⣺⣪⡺⡪⡪⡪⣺⣪⣺⡪⡺⣪⡺⣺⣺⣺⣺⣺⣺⣺⣺⣺⣺⣾⣻⣾⣻⣾⣻⣾⣻⣾⡃
⠕⢅⠅⠅⠕⠅⠕⠅⠅⠅⠁⠅⠁⠅⠁⠅⠅⠅⠅⢅⢕⢅⢕⢥⠕⢕⢕⢅⢕⢅⠕⠅⠅⠅⠅⠅⠁⠅⠁⠅⠁⠅⠁⠄⠁⠄⠁⠄⠁⠄⠁⠄⣪⡺⣺⣺⣪⣺⣪⣺⣺⣺⣾⣺⣾⣺⣾⣺⣺⣺⣺⡺⡪⡺⡪⡚⣪⡪⡪⡺⡪⡺⣪⣺⣺⣺⣺⣺⣾⣺⣾⣺⣾⣺⣾⣻⣾⣻⣾⣻⣾⣻⣾⡃
⠕⠅⠅⠅⠕⠅⠕⠅⠅⠅⠅⠅⠅⠅⠁⠅⠅⢵⢝⢵⢽⢽⢝⢵⢽⢽⢝⢕⠕⢕⠕⠕⠕⢅⠑⠄⠁⠅⠁⠅⠁⠅⠁⠄⠁⠄⠁⠄⠁⠄⠁⠄⣪⣺⣺⣺⣪⣺⣪⣺⣺⣺⣺⣺⣺⣺⣾⣺⣺⡊⡢⡊⡂⡂⡢⡊⡂⡂⡢⡪⣪⡪⣪⣪⣪⡺⣮⣻⣾⣺⣾⣺⣾⣺⣾⣻⣾⣻⣾⣻⣾⣻⣾⡃
⠕⠅⠅⠅⠕⠅⠕⠅⠅⠅⠅⠅⠅⠅⠅⢕⢝⢵⢝⢝⢕⢅⢅⢅⠕⠅⠅⠕⢕⢅⠅⠅⠅⢅⠕⠅⠅⠕⠁⠅⠁⠅⠁⠄⠁⠄⠁⠄⠁⠄⠁⠄⣪⣺⣺⣺⣪⣺⣪⣺⣺⣺⣺⣺⣺⣺⣺⡪⡢⡊⡢⡢⡪⡺⡺⡺⣪⣺⣺⣪⡪⡺⣺⣺⣺⡺⣪⣺⣺⣪⣾⣺⣾⣺⣾⣻⣾⣻⣾⣻⣾⣻⣾⡃
⠕⢅⠅⠅⠁⠅⠁⠅⠁⠅⠅⠅⠅⢅⢕⢕⠝⠅⠕⠅⠅⠅⠅⢕⠅⢕⠅⠄⠁⠕⠁⠅⠁⠅⠁⠅⠁⠅⢕⢅⠅⠅⠁⠅⠁⠄⠁⠄⠁⠄⠁⠄⣪⡺⣺⣺⣾⣺⣾⣺⣾⣺⣺⣺⣺⡺⡪⡪⣢⣺⣪⣺⣺⣺⣺⡪⣺⡪⣺⣻⣾⣪⣾⣺⣾⣺⣾⣺⣾⣺⡪⡺⣺⣺⣾⣺⣾⣻⣾⣻⣾⣻⣾⡃
⠕⢅⠅⠅⠁⠅⠕⠅⠅⠅⠅⠅⠅⢕⠕⢅⠕⠅⠁⠅⠅⠅⠁⠅⠅⠅⠁⠅⠅⠅⠁⠅⠁⠄⠅⢅⠅⠅⠁⠅⠑⠅⠁⠅⠁⠄⠁⠄⠁⠄⠁⠄⣪⡺⣺⣺⣾⣺⣪⣺⣺⣺⣺⣺⣺⡪⣪⡺⣪⣺⣾⣺⣺⣺⣾⣺⣺⣺⣾⣺⣺⣺⣾⣺⣾⣻⣺⡺⣺⣺⣾⣺⣮⣺⣾⣺⣾⣻⣾⣻⣾⣻⣾⡃
⠕⢅⠅⠅⠁⠅⠕⠅⠅⠅⠅⠅⢕⢅⠅⢅⠅⠅⠁⢕⢽⣵⢵⢵⢵⢵⢕⢵⢕⢅⢅⢅⢵⢵⢕⢕⢕⢕⠕⠄⠁⠅⠅⠅⠁⠄⠁⠄⠁⠄⠁⠄⣪⡺⣺⣺⣾⣺⣪⣺⣺⣺⣺⣺⡪⡺⣺⡺⣺⣺⣾⡪⡂⠊⡊⡊⡊⡊⡪⡊⡪⡺⡺⡺⡊⡊⡪⡪⡪⡪⣪⣻⣾⣺⣺⣺⣾⣻⣾⣻⣾⣻⣾⡃
⠕⢅⠕⠅⠁⠅⠕⠅⠅⠅⠕⢵⢕⠅⠅⠅⠅⠄⠕⢕⢽⢽⢿⣽⢿⢽⢿⣽⢿⢽⢿⢽⢿⢽⢝⢵⢕⢕⠕⠅⠅⠅⠁⠅⠅⠅⠁⠅⠁⠅⠁⠄⣪⡺⣪⣺⣾⣺⣪⣺⣺⣺⣪⡊⡪⣺⣺⣺⣺⣻⣪⡪⡂⡂⡀⠂⡀⡂⡀⠂⡀⡂⡀⡂⡀⡂⡢⡊⡪⡪⣪⣺⣺⣺⣾⣺⣺⣺⣾⣺⣾⣺⣾⡃
⠕⠅⠕⠅⠁⠅⠕⢅⠅⢅⢕⢕⠕⢅⠅⠅⠅⠅⠅⠅⢝⢽⢿⢽⢿⢽⢿⢽⢿⢽⢿⣽⢿⢽⢝⢵⢝⢕⠅⠄⠁⠅⠕⢅⢅⠅⠅⠅⠁⠅⠁⠄⣪⣺⣪⣺⣾⣺⣪⡺⣺⡺⡪⡪⣪⡺⣺⣺⣺⣺⣺⣺⡢⡂⡀⡂⡀⡂⡀⡂⡀⡂⡀⠂⡀⡂⡢⡊⡢⡪⣺⣻⣾⣺⣪⡺⡺⣺⣺⣺⣾⣺⣾⡃
⠕⠅⠕⠅⠁⢅⢕⢕⢝⢽⢝⢅⢕⢅⠅⠄⠕⠅⠁⢵⢝⢽⢽⢽⢿⣽⢿⢽⢿⣽⢿⣽⢿⢽⢝⢵⢝⢕⠕⠅⠁⠅⠕⢕⠕⠅⠅⠅⠁⠄⠁⠄⣪⣺⣪⣺⣾⡺⡪⡪⡢⡂⡢⡺⡪⡺⣺⣻⣪⣺⣾⡊⡢⡂⡂⡂⡀⠂⡀⡂⡀⠂⡀⠂⡀⡂⡢⡊⡢⡪⣪⣺⣾⣺⣪⡪⣪⣺⣺⣺⣾⣻⣾⡃
⠕⠅⠕⠅⠑⢅⠕⢅⢝⢵⢕⢵⢕⠅⠁⠅⠁⠄⠁⢵⢝⢝⠝⠝⠝⠝⠟⠝⢿⢽⢽⢽⠝⠝⠝⠅⠁⢅⢕⠅⠁⠄⠁⠅⠑⠅⠁⠅⠅⠄⠁⠄⣪⣺⣪⣺⣮⡺⣪⡺⡢⡊⡪⡊⡪⣺⣾⣺⣾⣻⣾⡊⡢⡢⣢⣢⣢⣢⣠⣢⡀⡂⡂⡂⣢⣢⣢⣺⣾⡺⡪⣺⣾⣻⣾⣺⣮⣺⣾⣺⣺⣻⣾⡃
⠕⠅⠕⠅⠕⢅⢝⢵⢝⢵⢽⢕⢝⠅⠅⠄⠁⠄⢑⢽⢽⢵⢕⢵⢕⢵⢕⢵⢝⢽⢿⢕⢕⢕⢕⢕⢕⢕⢕⢕⢕⠅⠁⠅⠁⠅⠅⠅⠅⠅⠁⠄⣪⣺⣪⣺⣪⡺⡢⡊⡢⡊⡂⡪⡢⣺⣺⣻⣾⣻⡮⡂⡂⡊⡪⡊⡪⡊⡪⡊⡢⡂⡀⡪⡪⡪⡪⡪⡪⡪⡪⡪⡪⣺⣾⣺⣾⣺⣺⣺⣺⣺⣾⡃
⠕⠅⠕⠅⠕⢕⢽⢕⢝⢽⢝⢕⢕⢅⠅⠄⠅⠄⠑⢽⢽⢽⢿⣿⢿⣽⢿⢽⢝⢽⢝⢕⢝⢽⢝⢽⢽⢽⢝⢅⢝⠕⠁⠄⠑⢅⠕⢅⠁⠅⠁⠄⣪⣺⣪⣺⣪⡪⡂⡪⡢⡂⡢⡪⡪⡺⣺⣻⣺⣻⣮⡂⡂⡂⡀⠀⡀⠂⡀⡂⡢⡂⡢⡪⡢⡂⡢⡂⡂⡂⡢⡺⡢⣪⣾⣻⣮⡺⣪⡺⣾⣺⣾⡃
⠕⠅⠕⠅⠕⢅⢝⢵⢽⢵⢝⢝⢝⢅⠕⢅⠕⠅⠁⢕⢝⢽⢿⣽⢿⣽⢿⢽⢝⢽⢟⢕⢕⢽⢝⢽⢝⢕⢕⢅⠝⠅⠁⠄⠑⢕⢕⠅⠕⠅⠁⠄⣪⣺⣪⣺⣪⡺⡢⡊⡂⡊⡢⡢⡢⡺⣪⡺⣪⣺⣾⡪⡢⡂⡀⠂⡀⠂⡀⡂⡢⡂⡠⡪⡪⡂⡢⡂⡢⡪⡪⡺⣢⣺⣾⣻⣮⡪⡪⣺⣪⣺⣾⡃
⠕⠅⠕⠕⠕⢅⢽⢵⢝⢽⠝⢕⢕⢕⢕⢅⠁⠀⠁⢕⢝⢽⢝⢽⢽⢽⢿⢽⢝⢽⢝⢕⢝⢵⢝⢕⢝⢕⠕⢅⠁⠀⠁⠄⠁⠕⠕⠅⠅⠅⠁⠄⣪⣺⣪⣪⣪⡺⡂⡊⡢⡂⣢⡪⡪⡪⡪⡺⣾⣿⣾⡪⡢⡂⡢⡂⡂⡂⡀⡂⡢⡂⡢⡪⡢⡊⡢⡪⡢⡪⣪⡺⣾⣿⣾⣻⣾⣪⣪⣺⣺⣺⣾⡃
⠕⠅⠅⠅⠕⢵⢟⢵⢽⢝⢕⢕⢕⢕⠕⠅⠁⠀⠁⢅⢕⢕⢝⢽⢿⢽⢽⢵⢝⢝⠝⢕⢝⢕⢝⢕⠝⢕⢕⢅⠁⠀⠁⠄⠁⠅⠕⠅⠅⠄⠁⠄⣪⣺⣺⣺⣪⡊⡠⡊⡂⡢⡪⡪⡪⡪⣪⣺⣾⣿⣾⡺⡪⡪⡢⡂⡀⡂⡂⡊⡢⡢⣢⡪⡢⡪⡢⡪⣢⡪⡪⡺⣾⣿⣾⣻⣾⣺⣪⣺⣺⣻⣾⡃
⠕⢅⠕⢕⢕⢝⢟⢽⢝⢵⢕⢵⢕⠕⠅⠅⠁⠀⠁⢅⢝⢕⢝⢽⢝⢽⢝⢽⢝⢕⢕⢕⢝⢕⢕⢕⠕⢕⠕⠅⠁⠀⠁⠀⠁⠅⠅⠅⠁⠅⠁⠄⣪⡺⣪⡪⡪⡢⡠⡂⡢⡊⡪⡊⡪⣪⣺⣺⣾⣿⣾⡺⡢⡪⡢⡂⡢⡂⡢⡂⡢⡪⡪⡪⡢⡪⡪⡪⣪⡪⣪⣺⣾⣿⣾⣿⣾⣺⣺⣺⣾⣺⣾⡃
⠕⢅⢕⢕⢝⢝⢝⢽⢽⢵⢝⢕⠅⠅⠅⠅⠁⠄⠁⠀⠝⢵⢝⢽⢝⢵⢵⢵⢵⢭⢝⢵⢕⢕⢕⢕⠕⢕⠕⢕⠅⠄⠁⠀⠁⠅⠅⠅⠅⠅⠕⠅⣪⡺⡪⡪⡢⡢⡢⡂⡂⡊⡢⡪⣺⣺⣺⣺⣾⣻⣾⣿⣢⡊⡢⡂⡢⡊⡊⡊⡊⡒⡢⡊⡪⡪⡪⡪⣪⡪⣪⡪⣺⣻⣾⣿⣾⣺⣺⣺⣺⣺⣪⡂
⠕⢝⢕⢕⢕⢽⢽⢽⢽⢽⢝⢕⢕⠅⠅⠅⠁⠀⠁⠀⠁⠑⠝⢕⢝⢽⢝⢵⢝⢕⢕⢕⢕⢕⢕⢕⠕⢅⢕⢅⠕⢕⢕⢄⠅⠀⠁⠅⠁⠅⠁⠅⣪⡢⡪⡪⡪⡂⡂⡂⡂⡂⡢⡪⡪⣺⣺⣺⣾⣿⣾⣿⣾⣮⣢⡪⡢⡂⡢⡊⡢⡪⡪⡪⡪⡪⡪⡪⣪⡺⡪⡺⣪⡪⡪⡻⣺⣿⣾⣺⣾⣺⣾⡂
⠕⢵⢕⢵⢝⢽⢽⣽⢝⢕⢕⢕⠝⠅⠅⠅⠁⠄⠁⠀⠁⠀⠑⢅⠝⢽⢝⢽⢿⢽⢿⢽⢝⢕⠕⢅⢕⢕⢕⢕⢕⢕⢝⢕⢕⢕⠅⠄⠁⠀⠁⠄⣪⡊⡪⡊⡢⡂⡂⠂⡢⡪⡪⡪⣢⣺⣺⣺⣾⣻⣾⣿⣾⣿⣮⡺⣢⡂⡢⡂⡀⡂⡀⡂⡢⡪⣪⡺⡪⡪⡪⡪⡪⡪⡢⡪⡪⡪⣺⣻⣾⣿⣾⡃
⢕⢵⢽⣽⢿⢽⢝⢝⢵⢕⠝⠕⠅⢅⠅⠅⠁⠅⠁⠄⠁⠀⠁⠅⢕⢕⠝⢕⠝⠝⠝⠕⠝⢅⢕⢕⢕⢕⢝⢕⢝⢕⢝⢕⢝⢕⢝⢅⠁⠄⠁⠄⡪⡊⡂⠂⡀⡂⡢⡢⡊⡪⣢⣪⣺⡺⣺⣺⣾⣺⣾⣻⣾⣿⣾⣺⡪⡪⣢⡪⣢⣢⣢⣪⣢⡺⡪⡪⡪⡪⡢⡪⡢⡪⡢⡪⡢⡪⡢⡺⣾⣻⣾⡃
⢽⢽⢟⢝⢝⢵⢽⢝⢕⠅⠕⠅⠁⠅⠁⠄⠁⠄⠁⠄⠁⠄⠁⢄⠕⢕⢕⢵⢕⢵⢕⢵⢕⢵⢝⢵⢝⢵⢝⢵⢝⢕⢝⢕⢝⢕⢕⢕⢕⠄⠁⠄⡂⡂⡠⡢⡢⡊⡂⡢⡪⣺⣪⣺⣾⣺⣾⣻⣾⣻⣾⣻⣾⣻⣾⡻⣪⡪⡪⡊⡪⡊⡪⡊⡪⡊⡢⡊⡢⡊⡢⡊⡢⡪⡢⡪⡢⡪⡪⡪⡪⣻⣾⡃
⢝⢽⢝⢽⢟⢽⢝⢵⢕⠅⠁⠄⠅⠄⠁⠄⠁⠄⠁⠄⠁⠀⠁⠅⠕⢕⢝⢕⢝⢽⢝⢵⢝⢵⢽⢽⢽⢽⢝⢵⢝⢵⢝⢵⢝⢵⢝⢕⢝⢕⠅⠄⡢⡂⡢⡂⡠⡂⡢⡊⡪⣺⣾⣻⣺⣻⣾⣻⣾⣻⣾⣻⣾⣿⣾⣺⣪⡪⡢⡪⡢⡂⡢⡊⡢⡊⡂⡂⡂⡂⡢⡊⡢⡊⡢⡊⡢⡊⡢⡪⡢⡪⣺⡃
⠝⢽⢝⢽⢝⢽⠝⠕⠅⠅⠅⠅⠁⠄⠁⠄⠁⠅⠁⠄⠁⠀⠁⠄⢕⢵⢝⢵⢝⢽⢝⢽⢽⢽⢽⢽⢽⢵⢕⢽⢝⢽⢝⢵⢝⢵⢝⢵⢝⢕⢕⠅⣢⡂⡢⡂⡢⡂⣢⣪⣺⣺⣺⣺⣾⣻⣾⣻⣾⣺⣾⣻⣾⣿⣾⣻⡪⡊⡢⡊⡢⡂⡢⡂⡂⡂⡂⡂⡂⡊⡪⡂⡢⡂⡢⡊⡢⡊⡢⡊⡢⡪⡪⡂
⠝⠽⠝⠵⠝⠕⠕⠅⠕⠅⠁⠄⠁⠄⠁⠄⠁⠄⠁⠄⠁⠄⠁⠅⠕⠽⠝⠽⠝⠵⠝⠽⠽⠽⠿⠽⠽⠵⠝⠵⠝⠵⠝⠵⠝⠵⠝⠵⠝⠵⠝⠅⠢⠂⠢⠊⠢⠪⠪⠺⠪⠺⠾⠻⠾⠻⠾⠻⠾⠻⠾⠻⠾⠻⠾⠺⠪⠂⠢⠂⠢⠊⠢⠂⠂⠂⠀⠂⠂⠊⠢⠊⠢⠊⠢⠊⠢⠊⠢⠊⠢⠊⠢⠂
For a more in-depth introduction, take a look at the docs.
Check out our talk at JuliaCon 2022 for a demonstration of the package:
- Error diffusion:
FloydSteinberg(default)JarvisJudiceAtkinsonStuckiBurkesSierraTwoRowSierraSierraLiteFan93ShiauFanShiauFan2SimpleErrorDiffusion
- Ordered dithering:
Bayer
- Halftoning:
ClusteredDotsCentralWhitePointBalancedCenteredPointRhombus- Threshold maps from ImageMagick:
IM_checksIM_h4x4aIM_h6x6aIM_h8x8aIM_h4x4oIM_h6x6oIM_h8x8oIM_c5x5IM_c6x6IM_c7x7
- Other:
ClosestColorConstantThresholdWhiteNoiseThreshold
Share your creations in the discussions tab and leave a GitHub Issue if you know of any cool algorithms you'd like to see implemented! 🔬🔧













