Skip to main content

Render images via Kitty's Terminal Graphics Protocol with Rich and Textual

Project description

textual-image

PyPI - Version PyPI - Python Version GitHub deployments PyPI - Downloads

Render images directly in your terminal using Textual and Rich.

Demo App

textual-image offers both Rich renderables and Textual Widgets that leverage the Terminal Graphics Protocol (TGP) and Sixel protocols to display images in your terminal. For terminals that don't support these protocols, fallback rendering using Unicode characters is available.

Supported Terminals

  • Terminal Graphics Protocol (TGP): Initially introduced by the Kitty terminal emulator. While support is partially available in other terminals, it doesn't seem to be really usable there.
  • Sixel Graphics: Supported by various terminal emulators including xterm and a lot of others.

Note: As implementation of these protocols differ a lot feedback on different terminal emulators is very welcome.

See the Support Matrix below on what was tested already.

Support Matrix [^1]

[^1]: Based on Are We Sixel Yet?

Terminal TGP support Sixel support Works with textual-image
Black Box
foot
GNOME Terminal
iTerm2
kitty
konsole
tmux
Visual Studio Code
Warp
wezterm
Windows Console
Windows Terminal
xterm

✅ = Supported; ❌ = Not Supported

BlackBox

Homepage: https://gitlab.gnome.org/raggesilver/blackbox
TGP support: No
Sixel support: Yes
Works: Yes

Notes:
Preferences -> Advanced -> Sixel Support has to be enabled.

Needs to be linked against a version of VTE with Sixel support enabled. This is the case for the Flatpak version of BlackBox, but not on most Linux distribution's native packages.

foot

Homepage: https://codeberg.org/dnkl/foot
TGP support: No
Sixel support: Yes
Works: Yes

Notes:
Works out of the box, no known issues.

GNOME Terminal

Homepage: https://gitlab.gnome.org/GNOME/gnome-terminal
TGP support: No
Sixel support: No
Works: No

Notes:
Relies on VTE Sixel implementation (https://gitlab.gnome.org/GNOME/vte/-/issues/253). While that one is available in an experimental state, I didn't find any resources if it's somehow possible to enable Sixel support on the terminal.

iTerm2

Homepage: https://iterm2.com/
TGP support: No
Sixel support: Yes
Works: Yes

Notes:
Works out of the box.

Kitty

Homepage: https://sw.kovidgoyal.net/kitty/
TGP support: Yes
Sixel support: No
Works: Yes

Notes:
Works out of the box.

Konsole

Homepage: https://konsole.kde.org/
TGP support: Partially
Sixel support: Yes
Works: Yes

Notes:
TGP support is not in a usable state. However, Sixel is working out of the box with a few minor graphical glitches in Textual.

tmux

Homepage: https://github.com/tmux/tmux/wiki
TGP support: No
Sixel support: Yes
Works: Partially

Notes:
tmux doesn't support TGP, even on a TGP enabled terminal nothing will render. Sixel generally works, but heavily depends on the underlying terminal. In some terminals it works great, in others major bugs occur, even if the terminal without tmux works.

Visual Studio Code

Homepage: https://code.visualstudio.com/
TGP support: No
Sixel support: Yes
Works: Yes

Notes:
The terminal.integrated.enableImages setting has to be enabled.

Warp

Homepage: https://www.warp.dev/
TGP support: No
Sixel support: No
Works: No

Notes:
Warp partially supports TGP and reports so when queried for it. But as it does not support TGP's unicode placeholders which are used by textual-image the actual rendering fails.

WezTerm

Homepage: https://wezfurlong.org/wezterm/index.html
TGP support: No
Sixel support: Yes
Works: Yes

Notes:
Works out of the box.

Windows Console

TGP support: No
Sixel support: No
Works: No

Notes:
Windows Console and Windows Terminal are two different pieces of software. The latter one is supported.

Windows Terminal

Homepage: https://github.com/microsoft/terminal
TGP support: No
Sixel support: Yes
Works: Yes

Notes:
Sixel support was added in version 1.22, please make sure you're on that version.

xterm

Homepage: https://invisible-island.net/xterm/
TGP support: No
Sixel support: Yes
Works: Yes

Notes:
Sixel on xterm is disabled by default. To enable it, add +lc and -ti vt340 options when launching xterm:

xterm +lc -ti vt340

Alternatively, you can add these options to your xterm configuration file (~/.Xresources or ~/.Xdefaults) to make the change permanent:

echo 'XTerm*decTerminalID: vt340' >> ~/.Xresources
xrdb -merge ~/.Xresources

Installation

Install textual-image using pip with the following commands:

For the basic installation:

pip install textual-image

To include the Textual Widget's dependencies:

pip install textual-image[textual]

Demonstration

Once installed, run the demo application to see the module in action.

For a demonstration of the Rich renderable, use:

python -m textual_image rich

For a demonstration of the Textual Widget, use:

python -m textual_image textual

The module will automatically select the best available rendering option. If you wish to specify a particular rendering method, use the -p argument with one of the following values: tgp, sixel, halfcell, or unicode.

For more information, use:

python -m textual_image --help

Usage

Rich Integration

To use the Rich renderable, simply pass an instance of textual_image.renderable.Image to a Rich function that renders data:

from rich.console import Console
from textual_image.renderable import Image

console = Console()
console.print(Image("path/to/image.png"))

The Image constructor accepts either a string, a pathlib.Path representing the file path of an image readable by Pillow, or a Pillow Image instance directly.

By default, the image is rendered in its original dimensions. You can modify this behavior by specifying the width and/or height parameters. These can be defined as an integer (number of cells), a percentage string (e.g., 50%), or the literal auto to automatically scale while maintaining the aspect ratio.

textual_image.renderable.Image defaults to the best available rendering method. To specify an explicit rendering method, use one of the following classes: textual_image.renderable.tgp.Image, textual_image.renderable.sixel.Image, textual_image.renderable.halfcell.Image, or textual_image.renderable.unicode.Image.

Textual Integration

For integration with Textual, textual-image offers a Textual Widget to render images:

from textual.app import App, ComposeResult
from textual_image.widget import Image

class ImageApp(App[None]):
    def compose(self) -> ComposeResult:
        yield Image("path/to/image.png")

ImageApp().run()

The Image constructor accepts either a string or a pathlib.Path with the file path of an image readable by Pillow, or a Pillow Image instance directly.

You can also set the image using the image property of an Image instance:

from textual.app import App, ComposeResult
from textual_image.widget import Image

class ImageApp(App[None]):
    def compose(self) -> ComposeResult:
        image = Image()
        image.image = "path/to/image.png"
        yield image

ImageApp().run()

If a different image is set, the Widget will update to display the new image.

By default, the best available rendering option is used. To override this, you can instantiate textual_image.widget.TGPImage, textual_image.widget.SixelImage, textual_image.widget.HalfcellImage, or textual_image.widget.UnicodeImage directly.

Note: The process of determining the best available rendering option involves querying the terminal, which means sending and receiving data. Since Textual starts threads to handle input and output, this query will not work once the Textual app has started. Therefore, make sure that textual_image.renderable is imported before running the Textual app (which is typically the case in most use cases).

Limitations

  • High Sixel images in Rich: As terminal emulators don't implement the Sixel protocol exactly consistent, a workaround to get the cursor position in Rich right had to be implemented. This breaks as soon as the image is higher that the terminal window itself. Rendering will still happen, but the image may be displaced and borders around it may be broken.
  • Sixel Support in Textual: Sixel support in Textual is not particularly performant due to the way Textual handles rendering. The Sixel graphics are injected into the rendering process in a somewhat hacky manner, which affects performance. Scrolling and changing styles of images can lead to a lot of flickering. But for mostly static images it should work fine. If not, please file an issue on GitHub.
  • textual-serve: textual-serve is not supported. Due to the different nature of image rendering in terminals and browsers it would be a completely different implementation. It may be added one day but not in the near future.

Contribution

If you find this module useful, please consider starring the repository on GitHub.

This project began by moving some TGP functionality from a private project to a public GitHub repository and PyPI package, with some additional code added along the way to support Sixel graphics. If you encounter any issues, please file an issue on GitHub.

Contributions via pull requests are welcome and encouraged.

Project details


Download files

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

Source Distribution

textual_image-0.8.5.tar.gz (109.0 kB view details)

Uploaded Source

Built Distribution

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

textual_image-0.8.5-py3-none-any.whl (109.6 kB view details)

Uploaded Python 3

File details

Details for the file textual_image-0.8.5.tar.gz.

File metadata

  • Download URL: textual_image-0.8.5.tar.gz
  • Upload date:
  • Size: 109.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for textual_image-0.8.5.tar.gz
Algorithm Hash digest
SHA256 43d4c0026a4f21fa255f41eac7b0fc1f7410a4c7bc9bf95b908bec901b0a8c3a
MD5 ec000906253167dbd354906945a2a5e0
BLAKE2b-256 1a64e5e49b639794f0ae426f6c19ca541af55b24a30e96df3b03e086688b8ec1

See more details on using hashes here.

Provenance

The following attestation bundles were made for textual_image-0.8.5.tar.gz:

Publisher: publish.yml on lnqs/textual-image

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file textual_image-0.8.5-py3-none-any.whl.

File metadata

  • Download URL: textual_image-0.8.5-py3-none-any.whl
  • Upload date:
  • Size: 109.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for textual_image-0.8.5-py3-none-any.whl
Algorithm Hash digest
SHA256 dffc85458ca8744bce3f17bddbf582b1e086eb52d111f1063753e8dd316fa45d
MD5 f7bf19b1f4376ac881f01cab095c8b74
BLAKE2b-256 b00dca8367c100c09850379f83645abd60f47c051e6b1e7b64adb953bce96be9

See more details on using hashes here.

Provenance

The following attestation bundles were made for textual_image-0.8.5-py3-none-any.whl:

Publisher: publish.yml on lnqs/textual-image

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

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