Skip to main content

Syxel

Early alpha release. Interfaces and output may still change, and some rough edges remain. Bug reports (and any other feedback) are very welcome: please open an issue at github.com/luispedro/syxel/issues.

Test Status License: MIT

SIXEL in Python: display images directly in your terminal.

syxel is a small, pure-Python package that converts images to the SIXEL escape-sequence protocol and writes them to standard output. If your terminal speaks SIXEL, the image appears inline, no image viewer required.

It ships a command line tool, imcat, and a matplotlib backend, so that plt.show() draws your plots in the terminal.

Installation

pip install syxel

Or, from a checkout, for development (the imcat script then tracks your working copy):

pip install -e .

Requires Python 3.11 or later.

The base install only depends on numpy, which is enough to convert arrays (or matplotlib figures) to SIXEL. Reading image files and the matplotlib backend each come as an extra:

pip install 'syxel[imcat]'         # the imcat command line tool
pip install 'syxel[matplotlib]'    # the matplotlib backend
pip install 'syxel[imcat,matplotlib]'

Dependencies

  • numpy
  • imread — optional (imcat extra), image loading for the command line tool
  • matplotlib — optional (matplotlib extra), only for the backend

Usage

imcat image.png

Several images can be given at once; each is written followed by a newline, so they stack vertically:

imcat one.png two.jpg three.tiff

Images larger than 800x1200 are subsampled (halved repeatedly) until they fit. Override the limits with:

imcat --max-height 400 --max-width 600 image.png

Full option list:

Option Meaning
--max-height N subsample until the image is at most N pixels high (default: 800)
--max-width N subsample until the image is at most N pixels wide (default: 1200)
--version print the version and exit
--help print usage and exit

Terminal support

You need a terminal emulator with SIXEL support, such as foot, WezTerm, mlterm, or xterm started with SIXEL enabled (xterm -ti vt340). In a terminal without SIXEL support you will just see a wall of escape-sequence bytes.

Since imcat writes to sys.stdout.buffer, you can also capture the raw byte stream instead of rendering it:

imcat image.png > image.six

matplotlib backend

syxel.backend_sixel is a matplotlib backend that draws figures into the terminal instead of opening a window. Select it from the environment:

MPLBACKEND=module://syxel.backend_sixel python plot.py

or from Python, before importing pyplot:

import matplotlib
matplotlib.use('module://syxel.backend_sixel')

import matplotlib.pyplot as plt
plt.plot([1, 4, 9])
plt.show()                  # the figure appears in the terminal

With matplotlib 3.9 or later the short name matplotlib.use('sixel') also works, via an entry point.

The figure is scaled to fill the terminal: its dpi is raised or lowered so that it fits the window, which redraws it at the right resolution rather than resampling it. Terminals that do not report their size in pixels (some multiplexers) fall back to 1200x800; set SYXEL_MAX_WIDTH and SYXEL_MAX_HEIGHT to override.

savefig gains a sixel format, which writes at the figure's own size:

fig.savefig('plot.sixel')                       # or
fig.savefig(sys.stdout.buffer, format='sixel')

Each plt.show() prints the figures drawn so far and then drops them, so a script with several show() calls does not reprint earlier figures.

Using it as a library

The conversion is available directly, independently of the command line tool:

import sys
from syxel.imcat import load_image
from syxel.sixel import rgb_to_palette, write_sixel

rgb = load_image('image.png')        # (M,N,3) uint8 array
active, data = rgb_to_palette(rgb)   # palette (P,3) and indexed image (M,N)
write_sixel(sys.stdout.buffer, data, active)

write_sixel accepts any object with a write method taking bytes, so an io.BytesIO works for testing or for building the sequence in memory.

The same is true of figures, without going through the backend machinery:

from syxel.backend_sixel import write_figure

write_figure(sys.stdout.buffer, fig)

How it works

The pipeline has three stages:

  1. Load (load_image) — read the file with imread, subsample by [::2,::2] until it fits the size limits, expand greyscale to three channels and drop any alpha channel. The result is an (M,N,3) uint8 array.

  2. Quantize (rgb_to_palette) — SIXEL supports at most 256 colour registers, so colours are counted and the 255 most frequent are kept. If those do not cover at least half of the image, a fixed 5x9x5 RGB cube is used instead. Every distinct source colour is then mapped to its nearest palette entry by squared Euclidean distance.

  3. Emit (write_sixel) — write the escape sequences. The image is processed in bands of six rows, with one pass per colour present in the band; each output byte encodes one column's six-pixel bitmask. A final band shorter than six rows only sets the bits of the rows that exist.

The matplotlib backend replaces the first stage: it renders the figure through Agg and hands the resulting pixels to the same last two stages.

Development

Tests use pytest and hypothesis, and are run through pixi:

pixi run -e test test

CI runs the suite on Python 3.11 through 3.14.

Releases are cut by pushing a v<version> tag matching syxel/syxel_version.py (for example git tag v0.1 && git push origin v0.1), which builds the sdist and wheel and uploads them to PyPI through trusted publishing.

License

MIT (see COPYING.MIT).

Copyright (c) 2024–2026 Luis Pedro Coelho

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

syxel-0.1.tar.gz (21.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

syxel-0.1-py3-none-any.whl (13.0 kB view details)

Uploaded Python 3

File details

Details for the file syxel-0.1.tar.gz.

File metadata

  • Download URL: syxel-0.1.tar.gz
  • Upload date:
  • Size: 21.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/5.1.0 CPython/3.11.9

File hashes

Hashes for syxel-0.1.tar.gz
Algorithm Hash digest
SHA256 b4b081ed0fdad4d4c3d615deb57c327ebc5554a788d49b4b0bb8224421b85bf2
MD5 7dc22c45711d8bec0652dfc377d6713a
BLAKE2b-256 aaf4e6eb3938d03203a896b6a08b50c43c0932a8e6cec9b6ffafcd576d0877c0

See more details on using hashes here.

File details

Details for the file syxel-0.1-py3-none-any.whl.

File metadata

  • Download URL: syxel-0.1-py3-none-any.whl
  • Upload date:
  • Size: 13.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/5.1.0 CPython/3.11.9

File hashes

Hashes for syxel-0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 606c047596e32a2ea196de03b6ab13d617f1e7e6b8fbbcd0b1c554a1e3871bb5
MD5 ea1a66b22ba98b12baa14842a1121137
BLAKE2b-256 77dc4feb1ca699b29ce19a7c5580702ea83d35b3d9cf6de4ac87a467a69334c0

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

0.1

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page