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. 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, and the flags that matter.
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.jpgThe most useful flags:
# ANSI color in the terminal (truecolor where supported, else 256-color)
jp2a --colors --width=100 photo.jpg
# Invert brightness for a light-on-dark terminal
jp2a --invert --width=80 photo.jpg
# Save the plain-text art to a file instead of printing it
jp2a --width=80 --output=art.txt photo.jpgA 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.pngWith no flags it auto-detects your terminal and picks the best output it can. If the terminal supports 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 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.pngThe --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. --colors full is the default truecolor mode; 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.
Choosing a width that fits your terminal
The single most common mistake is asking for art wider than the terminal, which wraps every line and turns the picture into noise. Match the width to your actual column count:
# How wide is the terminal, in columns?
tput cols
# Feed that straight into jp2a
jp2a --width=$(tput cols) photo.jpgchafa handles this for you by default (it sizes to the terminal automatically), which is another reason it is the friendlier default. Use --size only when you want a specific, smaller dimension, for example to keep the art small enough to paste somewhere.
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. - 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
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





