The two tools that turn an image into terminal art are jp2a for the classic monospace ASCII look, and chafa for high-detail, truecolor output.
Every command on this page converts the same source image, so you can compare what each tool and flag actually does to the same picture. Here is the original:

The minimal versions:
# Classic ASCII characters, 80 columns wide
jp2a --width=80 photo.jpg
# Modern, full-color, far more detail
chafa photo.pngjp2a gives you the recognizable typewriter-grain ASCII portrait. chafa is the one to reach for when you want the image to actually look good in the terminal, because it uses Unicode block and braille characters and 24-bit color instead of a 70-odd character ramp. The rest of this page is when to pick which, the flags that matter, and the one setting that changes the result more than any other: how wide you make it for the wide terminals everyone actually runs in 2026.
jp2a: the classic ASCII look
jp2a maps each block of pixels to a single ASCII character chosen by brightness, which produces the familiar grayscale-text portrait. Despite the name, it reads both JPEG and PNG.
jp2a --width=80 photo.jpg
The most useful flags:
# ANSI color in the terminal (truecolor where supported, otherwise the terminal's ANSI palette)
jp2a --colors --width=200 photo.jpg
# Invert brightness for a light-on-dark terminal
jp2a --invert --width=120 photo.jpg
# Save the plain-text art to a file instead of printing it
jp2a --width=80 --output=art.txt photo.jpg

A few things worth knowing:
--colorsprints with ANSI escape codes so the characters carry the image's colors. It looks great in the terminal but is no longer plain text, so do not pipe it somewhere that expects clean ASCII (more on saving below).--invertflips the brightness-to-character mapping. The default ramp assumes a dark character on a light background (like ink on paper). On a normal dark terminal that comes out as a photo negative, so--invertis the flag you almost always want there.--output=art.txtwrites the result to a file. Without--colors, that file is portable plain text you can paste into a README or a code comment. jp2a can also emit HTML with--htmlif you want a colored version for the web.
If you only pass --width, jp2a works out the height from the image's aspect ratio, correcting for the fact that terminal cells are taller than they are wide. You rarely need to set both.
chafa: the modern, high-detail tool
chafa is the one I reach for when the output needs to look like the actual picture. Instead of a single ASCII character per cell it draws from Unicode block, quadrant, sextant, and braille glyphs, and it renders in 24-bit truecolor, so a single character cell can carry far more visual information than one ASCII glyph ever could.
chafa photo.png
With no flags chafa does two things automatically, and both matter. First, it sizes the art to your whole terminal, not some small default, so on a wide modern window it has hundreds of columns to work with (much more on that below). Second, it auto-detects the best format your terminal supports: if the terminal speaks a real graphics protocol (sixel, Kitty, or iTerm2) chafa sends an actual bitmap; otherwise it falls back to Unicode character art. That detection is the whole appeal: you get the best your terminal can show, at full size, without configuring anything.
Useful flags:
# Constrain to a width x height in character cells
chafa --size=100x40 photo.png
# Pure monochrome braille art (no color, dense detail)
chafa --colors none --symbols braille photo.png
# Force a color mode if auto-detect guesses wrong: none, 2, 8, 16, 240, 256, full
chafa --colors 256 photo.png
# Force plain ASCII-only symbols (closest to the jp2a look)
chafa --symbols ascii photo.png


The --symbols classes (block, braille, ascii, half, quad, and more) let you trade detail for portability: braille packs the most pixels per cell, ascii keeps it copy-paste friendly. They only apply when chafa is drawing character art, so on a terminal with a graphics protocol add -f symbols to force character output instead of a bitmap. --colors full is the truecolor mode; chafa already picks a sensible color depth from your environment by default, drop to 256 or 16 for terminals or recordings that mangle 24-bit color.
Animated GIFs
chafa also plays animated GIFs straight in the terminal, looping the frames in place:
chafa animation.gifThis is genuinely useful for previewing a GIF over SSH without a desktop. jp2a does not do this.
How wide should the art be?
Width is the single biggest lever on how good the output looks, and the right number depends entirely on what you are doing with it.
80 columns is the safe portable width. It is the convention that reads comfortably almost everywhere: a README code block (anything wider starts to need horizontal scrolling, and looks worst on a narrow or mobile view), a Git commit message, an email, or an SSH login banner that has to fit whatever window someone connects with. It is coarse, but it is universal, which is exactly why it is still the default. Use 80 whenever the art is going to be saved and read somewhere else, the --output=art.txt case.
But a terminal in 2026 is rarely 80 columns. It depends on your font size and display scaling, but a maximized terminal on a retina MacBook commonly lands somewhere around 200 to 260 columns (on my 16-inch I get 266). A 1440p or 4K monitor, or a smaller font, goes higher still. Check your own:
tput colsWhatever that prints is how much detail your terminal can actually show, commonly two to four times the old 80. The same jp2a command, just wider, climbs from "recognizable" to "you can read the scene" (compare these to the 80-column version higher up):


chafa behaves the same way, and by default it sizes the art to your detected terminal, which is why its no-flag output (the large one above) looks so good. Starve it of columns and the detail collapses just like jp2a does:


So feed your real column count straight in:
# jp2a has to be told the width; chafa uses the detected terminal size
jp2a --width=$(tput cols) photo.jpg
chafa photo.pngThe rule for art you are viewing live: do not ask for more columns than the terminal has. Art wider than the window wraps every line and turns the picture into noise, so tput cols is the ceiling for direct viewing. (Saving to a file, or viewing with wrap turned off, is the exception, there you can go as wide as you like.) Below that ceiling, wider is better for looking at; 80 is better for saving and sharing.
Plain text vs colored output: which to save
This distinction trips people up, so it is worth being explicit:
- Plain ASCII text (no color flag) is portable.
jp2a --width=80 --output=art.txt photo.jpggives you a.txtyou can drop into a README, a Git commit, or an email, and it renders anywhere a monospace font does, as long as the destination keeps the whitespace and has room for the width. - Colored ANSI output (
jp2a --colors, or chafa's default) embeds terminal escape codes. Redirect it to a file and the file contains those raw codes; it only displays correctly whencat-ed back into an ANSI-capable terminal, not in a plain text viewer.
# Portable plain text
jp2a --width=80 --output=banner.txt photo.jpg
# Colored, terminal-only (escape codes baked in)
jp2a --colors --width=80 photo.jpg > color-art.ansi
cat color-art.ansi # replays the colorsSo: if the destination is a document or anywhere outside a terminal, keep it plain. If it is going to live in a terminal (a login banner, a cat-able file, an SSH session), color is fine.
Other tools worth knowing
jp2a and chafa cover almost every case, but two more come up in roundups and are worth a sentence each:
img2txtships with the libcaca text-mode graphics library (thecaca-utilspackage). It reads PNG, JPEG, GIF, and BMP, and its real strength is the output formats: besides colored ANSI it can emit HTML, SVG, IRC color codes, and PostScript. If you need ASCII art as SVG or HTML rather than terminal escape codes, it is the tool that does it directly. The character output itself is coarser than chafa's Unicode rendering.ascii-image-converteris a single cross-platform Go binary (Linux, macOS, Windows) that does colored ASCII and braille art, reads JPEG, PNG, BMP, WEBP, TIFF, and GIF, and saves straight to a PNG or text file. It is the easiest to install on Windows wherejp2aandchafaare fiddlier.
For most of what I do, the split is still: chafa for fidelity, jp2a for the classic plain-text look. The other two are situational.
FAQ
It depends on the destination. Use 80 columns for anything you save and share (a README, a commit message, an email), because 80 is the one width that renders un-wrapped everywhere. For art you are just looking at in your own terminal, use your full width: run tput cols to see it (a maximized terminal on a modern retina display is often 200 to 266 columns, far more than 80), then jp2a --width=$(tput cols) photo.jpg. chafa already fills the terminal by default. Wider always means more detail, up to your column count; going past it just wraps the lines into noise.
Use chafa when you want the output to look like the actual image: it uses truecolor and Unicode block and braille characters for far more detail, and it auto-sizes to your terminal. Use jp2a when you specifically want the classic monospace ASCII-character look, or portable plain text you can paste into a README.
Both are in the usual package managers. On Debian or Ubuntu, sudo apt install jp2a chafa. On macOS with Homebrew, brew install jp2a chafa. On Arch, sudo pacman -S jp2a chafa.
Current jp2a reads both JPEG and PNG, despite the name (the "j2" is historical). If you have an older build that only handles JPEG, convert first with ImageMagick: magick in.png in.jpg, then run jp2a on the JPEG.
jp2a's default brightness ramp assumes a dark character on a light background. On a dark terminal that inverts the apparent brightness. Add --invert and it will read correctly on a light-on-dark terminal.
For portable plain text, use jp2a without a color flag: jp2a --width=80 --output=art.txt photo.jpg. Avoid --colors for that purpose, because it bakes in ANSI escape codes that only render inside a terminal, not in a document or a code comment.
See also
- The ffmpeg command cheat sheet: the hub for converting, cropping, trimming, and compressing video and media from the CLI.
- Convert an image to grayscale from the command line: true grayscale vs black-and-white vs sepia with ImageMagick, a useful pre-step before generating ASCII art.
- Convert an image to WebP from the command line: when you want a small, modern raster image rather than terminal art.
Sources
Authoritative references this article was fact-checked against.
- jp2a manual page (official, JPEG and PNG to ASCII)manpages.ubuntu.com
- chafa manual page (official)hpjansson.org
- chafa source and documentation (official)github.com
- img2txt manual page (caca-utils / libcaca, official)manpages.debian.org
- ascii-image-converter source and documentation (official)github.com





