# Chafa: Terminal Image Rendering from Teletype to Kitty

> Chafa converts images and animated GIFs into terminal graphics or ANSI/Unicode character art through a C library with a command-line frontend. It is for people who want images to survive over SSH, in tmux, or on hardware that predates color.

**hpjansson/chafa** — 📺🗿 Terminal graphics for the 21st century.

- Repository: https://github.com/hpjansson/chafa
- Website: https://hpjansson.org/chafa/
- Stars: 5,285 · Forks: 118
- Language: C
- License: LGPL-3.0
- Published: 2026-09-23 · Updated: 2026-09-23 · Language: en
- Canonical page: https://hysenlabs.com/projects/hpjansson-chafa

## What Chafa Solves That a Terminal Image Protocol Does Not

Terminal graphics support is fragmented. Kitty, iTerm2, sixel and plain ANSI terminals each accept different escape sequences, and a tool that targets one usually produces garbage on the others. Chafa's stated aim is to convert image data, including animated GIFs, into graphics formats or ANSI/Unicode character art suitable for display in a terminal, and the README describes the range as going from historical teleprinters to modern terminal emulators. The practical consequence is that the same command works on a VT100 emulator and in a modern GPU-accelerated terminal, with the output quality degrading gracefully instead of failing.

The audience is narrower than the tagline suggests. This is for CLI users who view images over SSH, for people running tmux or screen where graphics passthrough is unreliable, and for anyone building a terminal application that needs to show a picture. It is also a library project: the core functionality is provided by a C library with a public, well-documented API, and the CLI is a frontend over that library. If you are writing a C program that displays images in a terminal, the library matters more than the binary.

## How Chafa Decides Between Graphics and Character Art

The repository layout tells you most of the architecture. The chafa/ directory holds the C library and the CLI, tools/ holds the frontend entry point, and the vendored libnsgif/ and lodepng/ directories handle GIF and PNG decoding without pulling in external decoders. Other formats come through optional dependencies: FreeType2 for fonts, libjpeg, librsvg, libtiff and libwebp. That split means a build without librsvg silently loses SVG input rather than failing at configure time in an obvious way, which is a real source of confusion when a file type is rejected.

At runtime the library inspects the terminal's capabilities and picks an output mode. On a terminal that supports a graphics protocol, it emits the corresponding escape sequences. Otherwise it falls back to rendering the image as a grid of Unicode characters, choosing symbols whose density approximates the brightness of the underlying pixels. The examples/ directory ships adaptive.c, example.c and ncurses.c, which is a fair summary of the intended integration paths: adaptive output selection, a minimal library call, and embedding inside an ncurses interface. The animation support is not a separate pipeline; animated GIFs are decoded frame by frame and redrawn, which is why the tool can display them in character art as well as in graphics mode.

## Installing Chafa and Rendering Your First Image

The README is direct about this: Chafa is most likely packaged for your distribution, so if you are not going to hack on it, use the official packages linked from the project's download page. Building from source is the path for people who want the latest code. You need GCC, make, Autoconf, Automake, Libtool and the GLib development package; building the CLI additionally needs FreeType2 and optionally libjpeg, librsvg, libtiff and libwebp. Documentation builds need gtk-doc.

Start by cloning the repository:

```bash
git clone https://github.com/hpjansson/chafa.git
```

Then change into the top-level directory and run the three commands the README gives:

```bash
./autogen.sh
make
sudo make install
```

After installation the chafa binary is on your PATH. The README does not print a usage example in its Installing section, so the first real use is simply pointing it at a file: run chafa on a PNG or JPEG and the terminal fills with either graphics escape sequences or a character-art rendition, depending on what your terminal advertises. If the output is character art when you expected graphics, the terminal is the variable, not the file.

If Python is your environment, the README points to separately maintained bindings by Erica Ferrua Edwardsdóttir at chafapy.mage.black, which come with a detailed tutorial. For JavaScript, Héctor Molinero Fernández maintains chafa-wasm, a WebAssembly port published to NPM for Node.js and browsers. Neither is part of this repository, so their release cycles are independent of Chafa's.

## Where Chafa Is the Wrong Tool

Character-art rendering is inherently lossy. When Chafa falls back to Unicode symbols, it is approximating pixel brightness with glyph density, and no amount of tuning recovers detail that the character grid cannot represent. If you need photographic fidelity, a terminal that speaks kitty or iTerm2 graphics is a prerequisite, not a nice-to-have. On a terminal without a graphics protocol, Chafa is a previewer, not a viewer.

The dependency story has the same shape. A build configured without libwebp, libtiff or librsvg will not open those formats, and the README lists them as optional without describing the failure mode. In practice you discover this when a file is rejected. There is also no documented rollback or uninstall procedure in the README; make install places files according to the Autotools defaults, so removing the tool means tracking those paths yourself or using your package manager's removal command if you installed a distribution package.

The animation support deserves a caveat too. The README says Chafa converts animated GIFs, but it does not describe frame-rate control, buffering behaviour or what happens on a slow link. If you are piping output through SSH, redrawing frames competes with the rest of your session.

## Chafa Against libsixel and Terminal Graphics Protocols

The closest alternative in spirit is libsixel, which targets the sixel graphics protocol specifically. The difference in approach is the abstraction level. libsixel assumes the receiving terminal understands sixel and optimizes for that one target; Chafa treats the terminal's capabilities as a runtime variable and carries a character-art fallback for terminals that understand nothing beyond ANSI. If your fleet is uniformly sixel-capable, libsixel's narrower focus is not a disadvantage. If it is not, Chafa's fallback is the whole point.

A second comparison is the graphics protocols themselves. Kitty's protocol and iTerm2's inline image escape sequence are terminal features, not libraries, and applications that emit them directly get better fidelity than any character-art renderer. Chafa's value is that it can emit those sequences when available while still producing something readable when they are not. The trade-off is a layer of indirection: you get portability at the cost of not controlling the exact escape sequences, which matters if you are debugging a terminal's graphics implementation.

## Maintenance, Licence and Upgrade Cost

The repository is not archived and the last push was on 2026-09-22, so development activity is recent as of this writing. Releases have been steady: 1.18.0 on 2025-11-10, 1.18.1 on 2026-02-08 and 1.18.2 on 2026-04-29. The NEWS file at the top level is where release changes are recorded, and the TODO file is where pending work is listed; both are worth reading before you pin a version, because the project does not maintain a separate changelog page.

Licensing is the part that needs care. Both the library and the frontend tools are covered by the Lesser GPL, version 3 or later. The COPYING and COPYING.LESSER files sit at the repository root. LGPLv3+ means linking the library into a proprietary application is permitted under conditions the licence spells out, but those conditions are not optional and the dynamic-linking requirement is the usual sticking point. This is not legal advice; if you are shipping a closed-source product that links libchafa, have counsel read COPYING.LESSER rather than relying on a summary.

Upgrade cost is low if you stay on distribution packages, since the CLI has no configuration file to migrate. Building from Git is where the cost lives: the Autotools toolchain and the optional format libraries have to be present on every build machine, and the absence of any one of them changes the set of formats the resulting binary accepts.

## Conclusion

Adopt Chafa if you need images to render across terminal emulators, SSH sessions and constrained environments from one binary, and if you are comfortable with its symbol-based rendering rather than pixel-accurate output. Do not adopt it if you need exact color reproduction, if your only target is a browser, or if you cannot take the LGPLv3+ obligations onto a linked library. Before committing, verify three things: that your distribution ships a package new enough for your formats, which optional dependencies (librsvg for SVG, libwebp, libtiff, libjpeg) are compiled in, and whether your terminal speaks sixel, kitty or iTerm2 graphics, since that determines whether Chafa emits real graphics or character art.

## FAQ

### How do I install Chafa?

The README recommends the official packages linked from the project's download page, since Chafa is most likely packaged for your distribution. Building from source requires GCC, make, Autoconf, Automake, Libtool and the GLib development package, and then the sequence ./autogen.sh, make and sudo make install.

### How do I use Chafa?

Chafa is a command-line utility that converts image data, including animated GIFs, into graphics formats or ANSI/Unicode character art suitable for display in a terminal. After installing it, you run the chafa binary on an image file and the output adapts to what your terminal supports.

### Does Chafa have Python bindings?

Yes, but they are not part of this repository. The README points to Python bindings maintained by Erica Ferrua Edwardsdóttir at chafapy.mage.black, which come with a detailed tutorial. There are also JavaScript bindings, chafa-wasm, maintained by Héctor Molinero Fernández and published to NPM.

### What licence does Chafa use?

Both the library and the frontend tools are covered by the Lesser GPL, version 3 or later. The COPYING and COPYING.LESSER files are at the top level of the repository.

### Which image formats can Chafa read?

GIF and PNG decoding are vendored in the repository through libnsgif and lodepng. JPEG, SVG, TIFF and WebP support come from optional dependencies (libjpeg, librsvg, libtiff, libwebp), so a build without them will not open those formats.

## Sources

- [hpjansson/chafa on GitHub](https://github.com/hpjansson/chafa)
- [License: LGPL-3.0](https://github.com/hpjansson/chafa/blob/master/LICENSE)
- [Project website](https://hpjansson.org/chafa/)
- [README](https://github.com/hpjansson/chafa/blob/master/README.md)
- [Releases](https://github.com/hpjansson/chafa/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/hpjansson-chafa
