The worst ANSI renderer, except for all the others

By Hans Petter Jansson

Chafa (github) started out as a small piece of supporting code for an obscure personal project I may announce at some indefinite point in the future. Then I decided to release it as a tongue-in-cheek thing for the VT100 anniversary last year, and, well… it gathered a bit of steam.

Chafa 1.0

Since I’m not one to leave well enough alone, I packaged it up over the holidays for the 1.0 release. It brings a pile of improvements, e.g. new symbol ranges like ASCII and Braille, better image preprocessing and a new --fill option for halftone/dithering. It’s also, like, real fast now, and the build is much less brittle.

Big thanks to everyone who contributed to this release: Adam Borowski, Felix Yan, Lajos Papp, Mo Zhou, Ricardo Arguello, Robert-André Mauchin, @dcb314 and @medusacle.

You’ll find packages out there for Arch, Debian, Fedora, Gentoo and Ubuntu now; check your repositories. Extra big thanks to the package maintainers.

As the post title implies, I think Chafa is now the least bad tool in this tiny but tradition-rich niche. So what’s so not-quite-terrible about it?

Only the best for your aixterm

If you’ve been around text terminals for a while, you’ll know what this means:

Up until fairly recently, the most colorful terminal applications would operate within the confines of some variant of the above palette, and many still do. It’s a nice and distinct (not to mention cheerful) set of colors, but it’s not a great match for most image material you’ll come across, which makes legible Chafa output a challenge. And that is precisely why I had to try (here with a nice woodblock print):

The top left image is the best reproduction you can get with Chafa using a modern 24-bit color terminal emulator (in this case, GNOME Terminal) at 60 characters wide. At top right is the 16-color mapping you get without applying any tricks; this is pretty close to the mark given the muted moonlight colors of the input image, but it doesn’t make good use of our palette, nor does it convey the essence of the scene very well. Blue sky, rolling hills, green grass. A shady waterfront pavilion. Given our limitations, the output will look nothing like the original anyway, so we’re better off trying to capture the gist of it.

We do this simply by cranking up the contrast and saturation to levels where our cheerful old palette can do a decent job (bottom left). Chafa no longer relies on ImageMagick for this, so it’s available in the library API, and integer-only math makes it performant enough to run in real time on animations and video (more on this in a later post, perhaps).

It gets even better if you do color assignment in DIN99d space (bottom right), but that’s way slow, so you have to explicitly enable it.

No ANSI? No problem

You can generate varied output without any color codes at all. The above examples also demonstrate use of the --fg option, which, along with --bg, exists to tell Chafa what your terminal’s default colors look like so it can target those, but is equally useful for tweaking monochrome output thresholds.

So if for some reason your terminal can’t handle ANSI or you still have one of those warm & fuzzy monochrome tubes sitting around, we’ve got you covered. Or break out your civil rights-era dot-matrix printer and make some precision banners to hang in your lab!