Chafa 1.6.0: Wider

Here's another one from the terminal graphics extravaganza dept: Chafa 1.6.0 brings fullwidth character support, so in addition to the usual block elements and ASCII art, you now get some mean CJK art too. Or grab as many fonts as you can and combine all of the Unicode into one big glorious mess. Chafa can efficiently distinguish between thousands of symbols, so it also runs fast enough for animations — up to a point.

Since some users want this in environments where it's not practical to build from source or even to have nice things like GLib, I've started adding statically linked builds. These are pretty bare-bones (fewer image loaders, no man page), so look to your steadfast distribution first.

Speaking of distributions, a big thank you to the packagers. Special thanks go to Florian Viehweger for getting in touch re. adding it to OpenBSD ports, and Mo Zhou (Debian), Michael Vetter (openSUSE), Herby Gillot (MacPorts), @chenrui and Carlo Cabrera (Homebrew) for getting 1.6 out there before I could even finish this post.

So what's it look like?

Obviously if you just want as faithful a reproduction as possible, stick with the default block elements or sixels. That said, fullwidth characters open up some new artistic possibilities.

Chafa rendering of Dog's Head

Above, a rendering of Dog's Head (1920) by Julie de Graag, digitally enhanced by Rawpixel. It was generated with the following command line:

chafa --glyph-file /usr/share/fonts/truetype/SourceHanSansCN-Normal.otf \
  --glyph-file /usr/share/fonts/truetype/SourceHanSansJP-Normal.otf \
  --glyph-file /usr/share/fonts/truetype/DroidSansThai.ttf \ 
  --glyph-file /usr/share/fonts/truetype/SourceCodePro-Regular.ttf \
  --symbols 0..fffff-block-border-stipple-dot-geometric \
  -c none -w 9 dog.png

Although I'd like to include a moderately large built-in selection of fullwidth symbols in a future release, for now you must load fonts with --glyph-file in order to achieve this effect. You also need to enable the Unicode ranges you want and curtail the use of block and border elements with --symbols. The latter is necessary because block elements produce more accurate results and will otherwise pretty much always come out on top during error minimization.

Chafa rendering of Shinjuku Skyscrapers

This is a rendering of Shinjuku Skyscrapers, CC-BY-SA Wilhelm Joys Andersen. I used the same set of options to produce it, but left out -c none, resulting in 24-bit color — the default under VTE.

A side effect of allowing lots of color variation is fewer wide characters. This makes sense considering that they force a pair of cells to have the same color, which is often less accurate than two narrow characters with different colors.

彡 (._.) ( l: ) (.-.) ( :l )

Like many subjects that look simple at first, terminal graphics makes for a surprisingly deep rabbit hole to be tumbling into. Chafa now spans the gamut from the most basic monochrome ASCII art to fullwidth Unicode, 24-bit color and sixels, and there's still a lot that can be done to improve it. I will be doing so… slowly.

If you want to help, feel free to send pull requests or file any issues you find. I think it's also at the point where you can achieve various surprising effects, so if you manage to get something particularly cool/sick/downright disgusting out of it, just lob it in my general direction and maybe I'll include it in a future gallery.


  1. Bit of a feedback on an issue I encountered playing around with Chafa recently.
    ~/hg/chafa$ LD_LIBRARY_PATH=./chafa/.libs /home/nemo/hg/chafa/tools/chafa/.libs/chafa ~/libera-color.svg > temp.ansi
    Segmentation fault

    Any redirection to a file crashed.

    $ hg bisect -g
    The first bad revision is:
    changeset: 673:89152f358a00
    user: Hans Petter Jansson
    date: Mon Jul 13 20:35:53 2020 +0200
    summary: ChafaCanvas: Split out symbol printing logic
    The git revision being:
    commit 58c3534cd9d2b59345e2e38a027d02a9d044fa87

    0x00007f656cae9442 in coverage_to_bitmap (rowstride=16, cov=0x557c09630f90 "") at chafa-symbols.c:22
    227I if (cov [y * rowstride + x])

  2. Hm… actually bisect might have found another crash?
    0x0000556aaff2ac06 in run_magickwand (quiet=, is_first_frame=1, is_first_file=1, filename=) at chafa.c:1471
    1471 fwrite (frame->gs->str, sizeof (gchar), frame->gs->len, stdout);

    lemme try skipping ahead a bit.

  3. Ok. New crash location.
    changeset: 773:e14883bb1031
    user: Hans Petter Jansson
    date: Tue Mar 02 22:01:47 2021 +0100
    summary: symbols: Add Japanese kana symbols
    git hash 44c93be7bcde7c346f6c22895f16d04219266c6f

    At least it's recent! Also. Confirmed same crash location this time.
    0x00007fc9f234e352 in coverage_to_bitmap (rowstride=16, cov=0x5579ed58df90 "") at chafa-symbols.c:221
    221 if (cov [y * rowstride + x])

  4. Eh… Feel free to delete useless comments above if you like. pippin figured out issue.
    $ tools/chafa/chafa ~/computer.png > temp.ansi
    Segmentation fault
    $ /usr/local/bin/chafa ~/computer.png > temp.ansi

    needed to be installed ☹

    1. … it turns out that working in local did not mean it was *really* working 😃 hpf suggested
      libtool –mode=execute valgrind tools/chafa/chafa and suuure enough…
      So. Yay. Didn't spam up the feedback for nothing.

    1. There are new built-in symbols in master/1.7.0 that may be interfering. I'm able to get mostly Chinese characters with –symbols space+wide or (more complete, but more unwieldy) –symbols 0..fffff-block-border-stipple-dot-geometric-sextant-wedge.

      You can also exclude the symbols you don't want to appear. Just copy/paste the symbol from the terminal into a Unicode search engine to look up its hex code, and subtract it from the symbol set. E.g. to use fullwidth symbols, but exclude the fullwidth macron, use –symbols wide-ffe3.

      If you're still getting poor results, feel free to report it as an issue on GitHub or directly to me by e-mail!

        1. I mostly use gnome-terminal and xfce4-terminal, which are both based on the VTE library. You're quite right: VTE is able to fall back to alternate fonts for each symbol, as long as the fonts are installed in the system path and findable by fontconfig.

    1. The command-line utility can read most image formats, but the library backend only takes raw raster data (8-bit RGBA in its various permutations) as input. You'll have to find an image library or code snippet to decode the sixels. Since it's not a huge amount of code, it's probably easier to do the latter.

      Take a look at how mintty integrated the parser based on libsixel's from_sixel.c here:

  5. Hans, the skyscrapers picture is the greatest terminal rendering of an image I have ever seen. Your software is amazing. Thanks.

Leave a Reply

Your email address will not be published. Required fields are marked *