Convert images into colorized ASCII art. This project provides two main tools for creating high-quality ASCII art from images.
- Image to ASCII conversion - Convert PNG images directly to ASCII art using high-quality glyph matching
- ASCII colorization - Add colors to existing ASCII text by mapping image pixels to characters
- Flexible output formats - Generate ANSI, HTML, or braille output
- Multiple quality modes - Choose between fast, balanced, or best-quality character matching
Requires Python 3.10+.
pipx install ascii-magic-tools # from PyPI (CLI tools)
pip install "ascii-magic-tools[web]" # + web GUI
pip install "ascii-magic-tools[video]" # + video support
# from a checkout:
pip install -e ".[web,video]"The import package is asciimagic (the PyPI project ascii-magic is an unrelated package that owns the ascii_magic import name).
The ascii-magic command is the recommended entry point. It provides all tools under one command:
# Convert image to ASCII art
ascii-magic image input.png -o output.txt
# Render text as ASCII art
ascii-magic text "Hello, world" -s block -w 80
# Colorize ASCII art with an image
ascii-magic colorize image.png ascii.txt output.ans
# Install art as a login greeting / start the web GUI
ascii-magic greet install output.ans
ascii-magic web
# Show version
ascii-magic --versionThe individual commands (image-to-ascii, colorize-ascii, text-to-ascii) continue to work as before.
Generate a static completion script for bash or zsh — subcommands, flags, and enum values all complete, with filename fallback:
eval "$(ascii-magic completion bash)" # in ~/.bashrc
eval "$(ascii-magic completion zsh)" # in ~/.zshrc
# or install persistently:
ascii-magic completion bash > ~/.local/share/bash-completion/completions/ascii-magicThe standalone commands (image-to-ascii, colorize-ascii, text-to-ascii, ascii-magic-greet, ascii-magic-video, ascii-magic-web) are covered by the same script.
The repo pins its Python version in .python-version and locks exact dependency versions in uv.lock, so a fresh clone builds the same environment on any OS. With uv installed (a single binary — it downloads the right Python by itself):
uv sync --extra web # creates .venv/ with pinned Python, deps, and test tools
uv run pytest # run the test suite
uv run ascii-magic-web # start the web GUIWithout uv, stock tooling works too (pip 25.1+ for --group):
python3 -m venv .venv
.venv/bin/pip install -e ".[web]" --group dev
.venv/bin/pytestAlways create the virtualenv as .venv/ inside the repo — never at the repo root — so editors and tools auto-detect it and git ignores it.
Bump version in pyproject.toml and __version__ in src/asciimagic/__init__.py, merge, then tag: git tag v0.3.0 && git push origin v0.3.0. The publish workflow runs the tests, builds sdist+wheel, and uploads via PyPI trusted publishing (configure once on PyPI: project ascii-magic-tools → publisher = this repo, workflow publish.yml, environment pypi).
Convert an image directly to ASCII art (preferred: installed console script):
image-to-ascii input.png -o output.txt
# or, during development:
python -m asciimagic.image_to_ascii input.png -o output.txtOptions:
-c, --cols- Output width in characters (default: 120)--mode- Conversion mode:glyph(default) orbraille--quality- Matching quality:fast,balanced(default), orbest--cell-w, --cell-h- Cell dimensions for glyph rendering--ascii- Charset preset:dense(default) orprintable--unicode- Unicode support:off,blocks, orbig--font- Path to custom .ttf font--autocontrast- Auto-adjust image contrast--gamma- Apply gamma correction--invert- Invert image colors--rotate- Rotate clockwise (90/180/270) before conversion; EXIF orientation from phone photos is applied automatically--threshold- Braille mode dot threshold (0-1)--dither- Braille mode: Floyd-Steinberg dithering (keeps smooth gradients a hard threshold flattens)--color- Convert and colorize in one step (ANSI, or HTML when the output ends in.html) — no separatecolorizeinvocation needed--caption TEXT- Render TEXT as ASCII and stitch it onto the art (see Captions below)
Attach text above or below the art — rendered as ASCII letters sized to the art, or as a simple box/banner. Works on both the image and colorize commands, and composes with --color (the caption keeps its own color instead of being smeared by the image):
ascii-magic image cat.png --color --caption "Whiskers 2010-2024" -o cat.ans
ascii-magic image cat.png --caption "Whiskers" --caption-style box --caption-pos topOptions (prefix --caption-):
pos:bottom(default) ortopstyle:block(default),small,shadow,box,banner,figlet(classic terminal-banner lettering)scale F: caption width as a fraction of the art width for rendered styles (default 0.6) — the sizing knobgap N: blank lines between caption and art (default 1)color COLOR: caption color — theme name,#RRGGBB,image(colors from the strip of the picture nearest the caption), orimage-full(the whole picture stretched over the text); default: terminal foregroundalign:center(default),left,right
The web GUI has a matching Caption panel (text, position, style, size slider, alignment, color).
Add colors to existing ASCII art (preferred: installed console script):
colorize-ascii image.png ascii.txt output.ans
# or, during development:
python -m asciimagic.colorize_ascii image.png ascii.txt output.ansIf you omit the output file, the tool defaults to ANSI and prints to stdout (convenient for piping). To print HTML to stdout, pass --format html and redirect, for example:
python -m asciimagic.colorize_ascii image.png ascii.txt
python -m asciimagic.colorize_ascii image.png ascii.txt --format html > out.htmlOutput formats: .ans (ANSI), .html (HTML)
Options:
--format- Output format:ansiorhtml--max-rows, --max-cols- Maximum output dimensions--rows, --cols- Exact output dimensions--keep-top N- Preserve top N lines without colorization--color-top- Apply colors to kept header lines--html-font-size PX- HTML font size (default: 12)--html-line-height PX- HTML line height--html-fill-spaces- Colorize spaces in HTML output--log FILE— Write debug logs to a file
A special colorization mode that produces the classic "Matrix" effect: green glyphs drawn with emphasis on subject areas (edges and stretched luminance). Enable with --matrix and tune behavior with the flags below.
Options:
--matrix: Enable Matrix mode (green glyphs driven by image luminance/edges)--matrix-top: Apply Matrix mode to the header/header-lines preserved by--keep-top--matrix-seed N: Deterministic RNG seed (integer). Use to reproduce the same random glyph placement.--matrix-gamma F: Gamma applied to the subject score (default: 2.0). Higher values emphasize bright/edge regions.--matrix-fg-min N,--matrix-fg-max N: Foreground (glyph) green intensity range (0..255). Defaults:20..255.--matrix-bg-min N,--matrix-bg-max N: Background green intensity range (0..255). Defaults:0..60.--matrix-color COLOR: Rain color —green(classic, default),amber,cyan,crimson,violet,white, or any#RRGGBB.--matrix-chars STR: String of glyphs to choose from (default includes digits, letters, and symbols).--matrix-fill-spaces: Keep background color on space characters (fills spaces with background color instead of leaving them blank).--matrix-mask: Use the input ASCII glyphs as a mask to bias glyph placement toward inked characters.--matrix-mask-boost F: When--matrix-maskis enabled, how much to boost subject score on inked pixels (0..1, default ~0.30).--matrix-mask-density-floor F: Minimum glyph probability on masked/subject pixels (0..1, default ~0.35).--matrix-bg-dim F: Multiply subject score on background pixels (0..1, default ~0.80).--matrix-bg-density F: Multiply glyph probability on background pixels (0..1, default ~0.75).
Example (ANSI Matrix output):
colorize-ascii photo.png art.txt output.ans --matrix --matrix-seed 42 --matrix-gamma 2.2 --matrix-fill-spacesExample (HTML Matrix output with larger font):
colorize-ascii photo.png art.txt output.html --format html --html-font-size 16 --matrix --matrix-mask --matrix-mask-boost 0.4Matrix subject mask (uses your ASCII art as a subject hint)
If your ASCII text already captures the subject well (non-space characters), enabling --matrix-mask will bias Matrix glyph placement so the subject "pops" more than the background. Use --matrix-mask-boost and --matrix-mask-density-floor to tune how strongly inked characters influence glyph density and intensity.
Add --animate for looping matrix rain driven by the image's subject — bright heads, fading tails, glyphs that flicker, and columns timed so the loop is seamless:
colorize-ascii photo.png art.txt rain.gif --animate --matrix-seed 42 # animated GIF
colorize-ascii photo.png art.txt rain.html --animate # self-playing web page
colorize-ascii photo.png art.txt --animate --loops 3 # play in the terminalOptions:
--frames N: Frames per loop (default: 60)--fps F: Playback speed (default: 12)--tail F: Fade length in rows behind each drop head (default: 6)--loops N: Terminal playback repeats;0plays until Ctrl-C (default: 3)--reveal: The rain uncovers the colorized image, which persists beneath it — the loop ends (and holds) on the fully revealed picture
All --matrix-* knobs (seed, gamma, intensity ranges, mask biasing, --matrix-color themes) apply to the rain too. Drop positions loop seamlessly; glyph identities re-roll at the wrap point, which reads as the same flicker the rain has everywhere else. --caption* works in every animation sink — the caption stays static (matching the rain tint by default, or any --caption-color including image) while the rain falls. The web GUI exposes the same controls under Matrix mode → Animate, previews the animation live, and adds a .gif download. Programmatic use: asciimagic.pipeline.animate(ctx, ...) returns an object with frames_ansi(), play(), to_gif_bytes(), and to_html().
Render plain text into an image and convert it to ASCII art. This module provides a small CLI and programmatic API for producing several simple ASCII styles.
Usage (console script):
text-to-ascii "Hello, world" -s block -w 80 --font-size 24Or via the unified CLI:
ascii-magic text "Hello, world" --style block --width 80 --font-size 24Options:
--stdin: Read text from standard input (useful for piping)-o, --output: Write ASCII output to a file (default: stdout)-s, --style: Style to use (block,small,shadow,box,banner,figlet) —blockis the default-w, --width: Output width in characters (default: 80)--font-size: Font size used when rendering text (default: 24)--font: Path to a .ttf font file to use for rendering-c, --char: Character to use for thebannerstyle--log-level: CLI logging level (DEBUG,INFO,WARNING,ERROR,CRITICAL)
-
Convert image to ASCII (preferred: console script):
image-to-ascii photo.png -o art.txt # or during development: python -m asciimagic.image_to_ascii photo.png -o art.txt -
Colorize the output (preferred: console script):
colorize-ascii photo.png art.txt output.ans --max-rows 30 # or during development: python -m asciimagic.colorize_ascii photo.png art.txt output.ans --max-rows 30 -
View in terminal or browser
You can run image -> ASCII -> colorized output entirely in memory:
from PIL import Image
from asciimagic.pipeline import AsciiPipelineContext, image_to_ascii, colorize
from asciimagic.colorize_ascii import Options
img = Image.open("photo.png").convert("RGB")
ctx = AsciiPipelineContext(source_image=img)
ascii_text = image_to_ascii(ctx, mode="braille", cols=120)
ansi_output = colorize(ctx, opt=Options(out_format="ansi"))
html_output = colorize(ctx, opt=Options(out_format="html"))There are also lower-level in-memory helpers if you do not want the context object:
asciimagic.image_to_ascii.image_to_text_glyph_from_image(...)asciimagic.image_to_ascii.image_to_braille_from_image(...)asciimagic.colorize_ascii.colorize_ascii_text(...)
Convert a video into a colorized ASCII animation — every format ffmpeg reads (mp4, webm, mov, mkv, avi, gif, ...). Requires the [video] extra:
pip install -e ".[video]" # or: uv sync --extra video
ascii-magic video clip.mp4 out.gif -c 100 --fps 10 # animated GIF of ASCII frames
ascii-magic video clip.mp4 out.mp4 # real video WITH the original audio
ascii-magic video clip.mp4 out.frames # playable via greet/play
ascii-magic video clip.mp4 --loops 0 # play live in the terminalFrames are sampled at the target --fps, converted through the braille pipeline (dithered by default; --no-dither to disable), and colorized from each frame. --max-frames caps long clips (default 300). A .frames output can be installed as an animated login greeting with ascii-magic greet install.
.mp4 output re-encodes the ASCII frames as h264 and muxes the source's audio track back in (--no-audio to skip; silent sources fall back gracefully). --caption* stamps text onto every frame — --caption-color image samples the first frame.
Per-frame rendering is configurable: --mode glyph uses character matching instead of braille, and --matrix (with --matrix-color, --matrix-seed, --matrix-gamma, --matrix-mask) renders each frame as matrix glyphs driven by that frame — the subject moves through the rain. Seeds advance per frame, so seeded runs are reproducible.
Point the video command at a camera device and it streams to your terminal live until Ctrl-C — mirrored like a real mirror (--no-mirror to disable), with all the same mode/matrix/caption knobs:
ascii-magic video "<video0>" # live mirror
ascii-magic video "<video0>" --matrix --matrix-color green # you, in the Matrix
ascii-magic video "<video0>" selfie.gif --seconds 5 # record 5s to an ASCII GIFCamera recordings are silent (.mp4 output works but has no audio path).
The web GUI has a matching Video tab: pick a file, set width/fps/frame cap and frame mode, press Render (video renders take a few seconds — no live auto-render), preview the animated result, and download .gif or .frames. The Matrix panel applies to video too.
Install any output as a shell login greeting — the art (or matrix rain) appears whenever you open a terminal or SSH in:
# Static greeting
colorize-ascii cat.png art.txt cat.ans
ascii-magic-greet install cat.ans
# Animated greeting (matrix rain, plays once per login)
colorize-ascii cat.png art.txt cat.frames --animate --loops 1
ascii-magic-greet install cat.framesThe install copies the file to ~/.config/ascii-magic/ and appends a marker-guarded block to your ~/.bashrc (or ~/.zshrc) that only fires in interactive terminals. Reinstalling replaces the previous greeting; ascii-magic-greet remove cleans everything up.
Subcommands: install FILE, remove, show/preview, status, play FILE [--fps F] [--loops N]. Use --rc PATH to target a different rc file, and set ASCII_MAGIC_NO_GREETING=1 to suppress the greeting temporarily.
A browser interface over the same pipeline: upload an image (or type text), turn every knob the CLIs expose, preview live, and download .ans, .html, or .txt results. Nothing is stored server-side.
pip install -e ".[web]"
ascii-magic-web # http://127.0.0.1:8000Resize like GIMP: the rendered art gets drag handles — pull the right edge for width, the bottom edge to stretch/squish the height, or the corner for a free resize (hold Shift to keep aspect). A live cols × rows readout follows the drag; double-click the ring to reset the height to auto. Works on images, text, and video (video applies on the next Render).
The Profile switch in the header applies sensible defaults per target: Terminal (SSH greetings, .ans output) or Web page (larger canvas, filled spaces, .html output).
One image covers both the web GUI and one-shot CLI runs (it bundles DejaVu Sans Mono, so glyph matching works out of the box):
docker build -t ascii-magic .
# Web GUI (default command) — open http://localhost:8000
docker run --rm -p 8000:8000 ascii-magic
# One-shot CLI: mount your working directory at /data and pass any subcommand
docker run --rm -v "$(pwd):/data" ascii-magic image photo.png -o art.txt
docker run --rm -v "$(pwd):/data" ascii-magic colorize photo.png art.txt output.ans
docker run --rm -v "$(pwd):/data" ascii-magic text "Hello" -s block- Cartoon or anime-styled images work best for ASCII conversion
- For colorization, use
--keep-top Nto preserve text headers - Use
--mode braillefor high-detail output with Unicode braille characters; add--ditherfor photos and smooth gradients - Glyph matching is fully vectorized —
--quality bestis fast enough to use freely - HTML output is great for web display and preservation
Apache License 2.0
The unified ascii-magic command (recommended) wraps everything as subcommands:
ascii-magic image photo.png --mode braille --dither -o art.txt
ascii-magic colorize photo.png art.txt out.gif --animate
ascii-magic greet install out.frames
ascii-magic webThe standalone scripts remain and behave identically:
ascii-magic->asciimagic.unified_cli:main(subcommands: image, text, colorize, greet, web)image-to-ascii->asciimagic.image_to_ascii:maincolorize-ascii->asciimagic.colorize_ascii:maintext-to-ascii->asciimagic.text_to_ascii:mainascii-magic-greet->asciimagic.greet:mainascii-magic-web->asciimagic.webapp:main(requires the[web]extra)
Prefer calling ascii-magic or the individual console scripts after pip install -e .. You can also invoke modules directly with python -m asciimagic.<module> when developing.