DCS Sixel — Inline raster graphics (ESC P q … ESC \)
Embed pixel images in the terminal stream using the Sixel device-control payload.
Byte forms
Every common string-literal form so you can paste-and-search either direction.
\x1bPq <sixel data> \x1b\\\033Pq … \033\\\eP q … \e\\ESC P q DATA ESC \1b 50 71 ... 1b 5cDescription
Sixel is a DEC-era inline pixel graphics format (DEC VT240/VT340) revived by modern terminals. The frame begins with the Device Control String introducer \x1bP (DCS), an optional parameter run, the q final byte that selects Sixel mode, then a payload of ?..~ printable characters where each byte encodes a 6-pixel-tall vertical slice (hence 'sixel'). The frame ends with the String Terminator — either \x1b\\ (ST, spec-correct) or \x07 (BEL, widely accepted). libsixel, chafa, viu, timg, ranger-style image previews, kitten icat --transfer-mode=stream (Sixel fallback for Kitty's native protocol), and mpv --vo=sixel all emit this sequence. Terminal support varies: xterm needs +sb compile and -ti vt340, mintty + foot + wezterm + iTerm2 + Windows Terminal Canary + ghostty work out of the box, kitty + alacritty + macOS Terminal do not (Kitty has its own better protocol).
Spec citation: DEC VT340 Programmer Reference / xterm-ctlseqs (DCS Ps; Ps; Ps q)
Examples
# A 12x6 magenta block via the Sixel raw payload\nprintf '\033Pq#0;2;100;0;100#0~~\033\\'import sys; sys.stdout.write('\x1bPq#0;2;100;0;100#0~~\x1b\\')fmt.Print("\x1bPq#0;2;100;0;100#0~~\x1b\\")process.stdout.write('\x1bPq#0;2;100;0;100#0~~\x1b\\')printf("\x1bPq#0;2;100;0;100#0~~\x1b\\");Used in
Real-world tools that emit this sequence — anchors the bytes to commands you've already used.
- libsixel + `img2sixel` CLIlibsixel is the reference encoder — `img2sixel input.png | cat` produces a `\x1bPq…\x1b\\` DCS stream that any sixel-aware terminal (xterm `+T --tn xterm-direct`, mlterm, foot, WezTerm with `enable_kitty_graphics=false`) renders inline. libsixel also powers most other tools' sixel output paths via dynamic linking
- gnuplot `set terminal sixel`gnuplot 5.4+ supports `set terminal sixel size 800,600` for inline plot rendering in the terminal — useful in scientific pipelines where you want to glance at a generated plot during a long-running fit without opening an X11 window or saving to PNG
- ranger / mc image previewranger (with the `img2sixel` preview script) and Midnight Commander on sixel-capable terminals render image-file previews inline in the right pane. Preferred over kitty-graphics for portability — sixel runs on xterm / mlterm / foot / WezTerm / Windows Terminal ≥ 1.22 / Black Box, broader than kitty-graphics' kitty / WezTerm / Ghostty trio
- matplotlib `mpl_sixel` backendPython: `import matplotlib; matplotlib.use('module://mpl_sixel'); plt.plot([1,2,3]); plt.show()` renders the plot as sixel directly in the Jupyter-less terminal — popular in HPC contexts where Jupyter is unavailable but interactive numeric work still happens at the shell
- Black Box / Windows Terminal sixel previewBlack Box (GNOME terminal emulator built on VTE 0.73+) and Windows Terminal 1.22+ added native sixel rendering — `cat photo.six` displays inline. Both ship sixel-aware test patterns in their CI to catch regressions; integrators target these as the modern reference renderers
Frequently asked
Short answers to the questions developers actually search for this sequence.
- What's the maximum image size a Sixel terminal can render in one DCS sequence?
- There's no spec-mandated cap — Sixel images stream pixel-row groups inside one DCS envelope (
\x1bPq … \x1b\\) so the limit is the terminal's pixel-buffer allocation. Practical ceilings: xterm usesdecGraphicsMaxSize(default 1000×1000) and silently truncates beyond; mlterm / WezTerm / Konsole / foot accept multi-megapixel images bounded only by RAM; Windows Terminal added Sixel in v1.22 with a soft 10 MP cap. Performance — not the spec — is the real limiter: a 4K full-screen image is ~2 MB of base-6-encoded payload that the terminal decodes serially while blocking the input loop. - Why does my Sixel image render as gibberish in tmux even though the terminal supports it?
- tmux historically strips DCS payloads — Sixel arrives as
\x1bP…\x1b\\and tmux's parser eats both the introducer and the terminator, leaving the base-6 body to land as literal characters. Two fixes: (1)set -g allow-passthrough onplus wrapping each Sixel in\x1bPtmux;<escaped>\x1b\\(thetmux;passthrough envelope, with inner\x1bdoubled to\x1b\x1b); (2) since tmux 3.4, native Sixel support is opt-in viaset -g sixel on— no passthrough envelope needed. Use option 2 if you're on 3.4+; option 1 is the only path on older versions.
Terminal support
- xterm
- partial
- Linux console (fbcon)
- no
- macOS Terminal.app
- no
- iTerm2
- yes
- Windows Terminal
- partial
- cmd.exe / ConPTY
- no
- kitty
- no
- alacritty
- no
- WezTerm
- yes
- Ghostty
- yes
- GNOME Terminal
- partial
- Konsole
- yes
- tmux
- partial
- GNU screen
- no
| xterm | Linux console (fbcon) | macOS Terminal.app | iTerm2 | Windows Terminal | cmd.exe / ConPTY | kitty | alacritty | WezTerm | Ghostty | GNOME Terminal | Konsole | tmux | GNU screen |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| partial | no | no | yes | partial | no | no | no | yes | yes | partial | yes | partial | no |
Related sequences
In the family cookbook
DCS cookbook · 2. Pictures inside the stream — Sixel and Kitty graphics