xnano.image
xnano.image
¶
xnano.image
xnano-image images that a
terminal can show. Needs the optional image extra: pip install "xnano[image]".
Classes:
-
TerminalGraphics–Terminal graphics capabilities: the protocol to draw with and the cell size.
-
TerminalImage–A decoded, immutable image or animation.
TerminalGraphics
¶
Terminal graphics capabilities: the protocol to draw with and the cell size.
Pass one as graphics= to
TerminalImage.to_cell_grid or
TerminalImage.to_cell_animation
to draw with the sixel, kitty or iterm2 protocol instead of
half-block characters. Instances are immutable and hashable; use
with_protocol to
get a copy with another protocol.
Maps to ratatui_image::picker::Picker.
Attributes:
-
protocol(Literal['half_blocks', 'sixel', 'kitty', 'iterm2']) –The graphics protocol images are drawn with.
-
cell_size_in_pixels(tuple[int, int]) –The size of one terminal cell in pixels,
(width, height). -
capabilities(list[str]) –The capabilities the terminal reported when it was detected.
Examples:
graphics = TerminalGraphics.detect() # before the full-screen session starts
grid = TerminalImage.open('photo.png').to_cell_grid(40, 20, graphics=graphics)
Methods:
-
half_blocks–Capabilities that draw with half-block characters, which work in every terminal.
-
detect–Ask the terminal which graphics protocol and cell size it supports.
-
from_capabilities–Capabilities you already know, without querying the terminal.
-
with_protocol–A copy of these capabilities that draws with
protocol.
protocol
property
¶
protocol: Literal['half_blocks', 'sixel', 'kitty', 'iterm2']
The graphics protocol images are drawn with.
cell_size_in_pixels
property
¶
The size of one terminal cell in pixels, (width, height).
capabilities
property
¶
The capabilities the terminal reported when it was detected.
Each is one of kitty, sixel, rectangular_operations,
kitty_compression, cell_size, text_sizing_protocol or
background_color. Empty unless built by
detect.
half_blocks
staticmethod
¶
half_blocks() -> TerminalGraphics
Capabilities that draw with half-block characters, which work in every terminal.
The cell size is assumed to be (10, 20) pixels.
detect
staticmethod
¶
detect() -> TerminalGraphics
Ask the terminal which graphics protocol and cell size it supports.
The query writes escape sequences to the terminal and reads its answer from standard input, waiting up to two seconds. Call it once, before starting a full-screen session and before reading terminal events. A terminal that does not answer is treated as supporting half-blocks only.
Returns:
-
TerminalGraphics–The detected capabilities.
Raises:
-
TerminalQueryError–If standard input or output is not a terminal, or the query cannot be written or read. Use
from_capabilitiesorhalf_blocksin that case.
Source code in packages/xnano-image/src/xnano_image/_xnano_image/__init__.pyi
from_capabilities
staticmethod
¶
from_capabilities(*, protocol: Literal['half_blocks', 'sixel', 'kitty', 'iterm2'], cell_size_in_pixels: tuple[int, int]) -> TerminalGraphics
Capabilities you already know, without querying the terminal.
Use it when the terminal was queried elsewhere (for example by
xnano.input.detect_terminal_capabilities()) or when a
protocol must be forced.
Parameters:
-
protocol(Literal['half_blocks', 'sixel', 'kitty', 'iterm2']) –The graphics protocol to draw with.
-
cell_size_in_pixels(tuple[int, int]) –The size of one terminal cell,
(width, height), each side between 1 and 1000 pixels.
Raises:
-
TerminalImageError–If
protocolis not one of the four protocols or a side ofcell_size_in_pixelsis out of range.
Source code in packages/xnano-image/src/xnano_image/_xnano_image/__init__.pyi
with_protocol
¶
with_protocol(protocol: Literal['half_blocks', 'sixel', 'kitty', 'iterm2']) -> TerminalGraphics
A copy of these capabilities that draws with protocol.
Raises:
-
TerminalImageError–If
protocolis not one of the four protocols.
Source code in packages/xnano-image/src/xnano_image/_xnano_image/__init__.pyi
TerminalImage
¶
A decoded, immutable image or animation.
Every operation returns a new image, so one instance can be shared and
reused freely, including across threads. Frames are stored as straight
RGBA. len(image) is the frame count.
Attributes:
-
width(int) –Width in pixels.
-
height(int) –Height in pixels.
-
frame_count(int) –Number of frames (1 for a still image).
-
duration_milliseconds(int) –Total playback time of every frame, in milliseconds.
-
is_animated(bool) –Whether there is more than one frame.
-
is_opaque(bool) –Whether no pixel is transparent.
Examples:
Methods:
-
open–Load an image from a file (PNG, JPEG, GIF, WebP or XNI1).
-
from_bytes–Decode PNG, JPEG, GIF, WebP or XNI1 bytes; the format is detected.
-
from_rgba–A single-frame image from
width * height * 4straight RGBA bytes. -
from_frames–An animation from images that all share one size.
-
from_xni–Decode the compact
XNI1container written by -
frame_durations–Each frame's display time in milliseconds, in playback order.
-
frame_index_at–Index of the frame showing
elapsed_millisecondsinto playback. -
to_rgba–Raw straight RGBA bytes of one frame, row-major.
-
resize–Resize to exactly
widthxheightpixels. -
scale–Scale both sides by
factor(2.0doubles them). -
crop–Cut out a rectangle of pixels.
-
fit_to_canvas–Place the image on a
widthxheightcanvas without resizing it. -
focal_crop–Scale by
scale, then keep an exact window, padding where needed. -
flatten–Composite onto a solid RGB color so no pixel is transparent.
-
quantize–Reduce every frame to an adaptive palette of at most
colorscolors. -
first_frames–Keep only the first
countframes. -
still_frame–Keep one frame as a still image.
-
with_frames_per_second–Give every frame an even cadence of
frames_per_second. -
with_speed–Play
factortimes faster (2.0is twice as fast). -
to_cell_grid–Convert one frame to a cell grid (
XCG1bytes). -
to_cell_grids–Convert every frame to its own cell grid (
XCG1bytes). -
to_cell_animation–Convert every frame, with its display time, to a cell animation (
XCA1bytes). -
to_ansi–One frame as half-block ANSI text, ready to
print. -
encode–Encode as
png(the first frame) orgif(every frame, looping). -
save–Write to
path; the extension (.pngor.gif) picks the format. -
to_xni–Encode as the compact
XNI1container, quantized tocolors.
duration_milliseconds
property
¶
duration_milliseconds: int
Total playback time of every frame, in milliseconds.
open
staticmethod
¶
open(path: str | PathLike[str]) -> TerminalImage
Load an image from a file (PNG, JPEG, GIF, WebP or XNI1).
Raises:
-
OSError–If the file cannot be read.
-
TerminalImageError–If the data cannot be decoded.
Source code in packages/xnano-image/src/xnano_image/_xnano_image/__init__.pyi
from_bytes
staticmethod
¶
from_bytes(data: bytes) -> TerminalImage
Decode PNG, JPEG, GIF, WebP or XNI1 bytes; the format is detected.
Animated GIF and WebP keep every frame, composited onto the full canvas, with their display times. A zero delay means 100 milliseconds and no frame is shorter than 10 milliseconds.
Raises:
-
TerminalImageError–If the format is unrecognized or the data is corrupt or too large (sides over 16384 pixels, over 1 GiB of pixels in total, an animated GIF or WebP canvas over 67 megapixels, or over 10000 frames).
Source code in packages/xnano-image/src/xnano_image/_xnano_image/__init__.pyi
from_rgba
staticmethod
¶
from_rgba(width: int, height: int, pixels: bytes, *, duration_milliseconds: int = 100) -> TerminalImage
A single-frame image from width * height * 4 straight RGBA bytes.
Parameters:
-
width(int) –Width in pixels, 1 to 16384.
-
height(int) –Height in pixels, 1 to 16384.
-
pixels(bytes) –Row-major RGBA bytes.
-
duration_milliseconds(int, default:100) –How long the frame is shown when it becomes part of an animation.
Raises:
-
TerminalImageError–If the size is out of range or
pixelshas the wrong length.
Source code in packages/xnano-image/src/xnano_image/_xnano_image/__init__.pyi
from_frames
staticmethod
¶
from_frames(frames: list[TerminalImage]) -> TerminalImage
An animation from images that all share one size.
Each image contributes all of its frames, in order, keeping its own
frame durations (use
with_frames_per_second
to even them out).
Raises:
-
TerminalImageError–If the list is empty, the sizes differ, or the result would hold more than 1 GiB of pixels.
Source code in packages/xnano-image/src/xnano_image/_xnano_image/__init__.pyi
from_xni
staticmethod
¶
from_xni(data: bytes) -> TerminalImage
Decode the compact XNI1 container written by
to_xni.
Raises:
-
TerminalImageError–If the data is truncated or corrupt.
Source code in packages/xnano-image/src/xnano_image/_xnano_image/__init__.pyi
frame_durations
¶
Each frame's display time in milliseconds, in playback order.
frame_index_at
¶
Index of the frame showing elapsed_milliseconds into playback.
Negative times show the first frame.
Parameters:
-
elapsed_milliseconds(float) –Time since playback started.
-
should_loop(bool, default:True) –Start over after the last frame; otherwise hold the last frame.
Raises:
-
TerminalImageError–If
elapsed_millisecondsis NaN or infinite.
Source code in packages/xnano-image/src/xnano_image/_xnano_image/__init__.pyi
to_rgba
¶
Raw straight RGBA bytes of one frame, row-major.
Raises:
-
TerminalImageError–If
frame_indexis out of range.
resize
¶
resize(width: int, height: int, *, resampling_filter: Literal['nearest', 'bilinear', 'catmull_rom', 'lanczos3'] = 'lanczos3') -> TerminalImage
Resize to exactly width x height pixels.
Uses SIMD resampling that keeps transparent edges free of dark halos.
Parameters:
-
width(int) –Width in pixels, 1 to 16384.
-
height(int) –Height in pixels, 1 to 16384.
-
resampling_filter(Literal['nearest', 'bilinear', 'catmull_rom', 'lanczos3'], default:'lanczos3') –nearestkeeps hard pixel edges;bilinear,catmull_romandlanczos3are progressively sharper and slower.
Raises:
-
TerminalImageError–If a side is out of range or the filter is unknown.
Source code in packages/xnano-image/src/xnano_image/_xnano_image/__init__.pyi
scale
¶
scale(factor: float, *, resampling_filter: Literal['nearest', 'bilinear', 'catmull_rom', 'lanczos3'] = 'lanczos3') -> TerminalImage
Scale both sides by factor (2.0 doubles them).
Raises:
-
TerminalImageError–If
factoris not a finite number greater than zero, or the result would exceed 16384 pixels per side.
Source code in packages/xnano-image/src/xnano_image/_xnano_image/__init__.pyi
crop
¶
crop(left: int, top: int, width: int, height: int) -> TerminalImage
Cut out a rectangle of pixels.
Raises:
-
TerminalImageError–If the rectangle is empty or does not fit inside the image.
Source code in packages/xnano-image/src/xnano_image/_xnano_image/__init__.pyi
fit_to_canvas
¶
fit_to_canvas(width: int, height: int, *, background: tuple[int, int, int] = (0, 0, 0), left: int | None = None, top: int | None = None) -> TerminalImage
Place the image on a width x height canvas without resizing it.
Smaller images are centered and padded with background; larger
ones are cropped around the center.
Parameters:
-
width(int) –Canvas width in pixels, 1 to 16384.
-
height(int) –Canvas height in pixels, 1 to 16384.
-
background(tuple[int, int, int], default:(0, 0, 0)) –RGB color of the padding.
-
left(int | None, default:None) –Left edge of the kept window within a wider image. Centered when
None. -
top(int | None, default:None) –Top edge of the kept window within a taller image. Centered when
None.
Source code in packages/xnano-image/src/xnano_image/_xnano_image/__init__.pyi
focal_crop
¶
focal_crop(width: int, height: int, *, scale: float = 1.0, left: int | None = None, top: int | None = None, background: tuple[int, int, int] = (0, 0, 0), resampling_filter: Literal['nearest', 'bilinear', 'catmull_rom', 'lanczos3'] = 'lanczos3') -> TerminalImage
Scale by scale, then keep an exact window, padding where needed.
Zooms in on the subject, then keeps a fixed-size rectangle at the scaled resolution.
Parameters:
-
width(int) –Width of the window in pixels.
-
height(int) –Height of the window in pixels.
-
scale(float, default:1.0) –Scale factor applied before cropping.
-
left(int | None, default:None) –Left edge of the window in the scaled image. Centered when
None. -
top(int | None, default:None) –Top edge of the window in the scaled image. Centered when
None. -
background(tuple[int, int, int], default:(0, 0, 0)) –RGB color used to flatten transparency and to pad when the window extends past the image.
-
resampling_filter(Literal['nearest', 'bilinear', 'catmull_rom', 'lanczos3'], default:'lanczos3') –Resampling filter, as in
resize.
Source code in packages/xnano-image/src/xnano_image/_xnano_image/__init__.pyi
quantize
¶
quantize(colors: int = 64, *, should_dither: bool = False) -> TerminalImage
Reduce every frame to an adaptive palette of at most colors colors.
Transparency is flattened onto black first.
Parameters:
-
colors(int, default:64) –2 to 256. Fewer colors compress better (see
to_xni) at the cost of fidelity. -
should_dither(bool, default:False) –Apply Floyd-Steinberg dithering.
Raises:
-
TerminalImageError–If
colorsis out of range.
Source code in packages/xnano-image/src/xnano_image/_xnano_image/__init__.pyi
first_frames
¶
first_frames(count: int) -> TerminalImage
still_frame
¶
still_frame(frame_index: int) -> TerminalImage
with_frames_per_second
¶
with_frames_per_second(frames_per_second: float) -> TerminalImage
Give every frame an even cadence of frames_per_second.
Raises:
-
TerminalImageError–If
frames_per_secondis not a finite number greater than zero.
Source code in packages/xnano-image/src/xnano_image/_xnano_image/__init__.pyi
with_speed
¶
with_speed(factor: float) -> TerminalImage
Play factor times faster (2.0 is twice as fast).
No frame becomes shorter than 10 milliseconds.
Raises:
-
TerminalImageError–If
factoris not a finite number greater than zero.
Source code in packages/xnano-image/src/xnano_image/_xnano_image/__init__.pyi
to_cell_grid
¶
to_cell_grid(columns: int | None = None, rows: int | None = None, *, fit: Literal['crop', 'contain', 'cover', 'stretch', 'smart'] = 'contain', horizontal_pixels_per_cell: int = 1, should_correct_aspect_ratio: bool = False, background: tuple[int, int, int] = (0, 0, 0), resampling_filter: Literal['nearest', 'bilinear', 'catmull_rom', 'lanczos3'] = 'lanczos3', frame_index: int = 0, graphics: TerminalGraphics | None = None) -> bytes
Convert one frame to a cell grid (XCG1 bytes).
With neither columns nor rows the image keeps its native pixel
size (two pixel rows per cell). Give one to derive the other from the
aspect ratio, or both to fit inside that box.
Parameters:
-
columns(int | None, default:None) –Width in terminal cells, 1 to 1000.
-
rows(int | None, default:None) –Height in terminal cells, 1 to 1000.
-
fit(Literal['crop', 'contain', 'cover', 'stretch', 'smart'], default:'contain') –How the image is placed in a
columnsxrowsbox.cropnever resizes (center, crop or pad),containfits entirely inside,coverfills and crops the overflow,stretchfills exactly, andsmartiscoverwhen the aspect ratios nearly match andcontainotherwise. -
horizontal_pixels_per_cell(int, default:1) –1 (lossless width) or 2 (sample two pixels across each cell).
-
should_correct_aspect_ratio(bool, default:False) –With 2 pixels per cell the pixels are half as wide as tall; this widens the picture so proportions stay true.
-
background(tuple[int, int, int], default:(0, 0, 0)) –RGB color behind transparency and padding.
-
resampling_filter(Literal['nearest', 'bilinear', 'catmull_rom', 'lanczos3'], default:'lanczos3') –Resampling filter, as in
resize. -
frame_index(int, default:0) –Which frame to convert.
-
graphics(TerminalGraphics | None, default:None) –Capabilities whose protocol is
sixel,kittyoriterm2draw with that protocol instead of half-blocks.
Raises:
-
TerminalImageError–If an option is invalid,
frame_indexis out of range, or the grid would hold more than 4000000 cells (an unsized conversion of a very large image; passcolumnsorrows).
Source code in packages/xnano-image/src/xnano_image/_xnano_image/__init__.pyi
to_cell_grids
¶
to_cell_grids(columns: int | None = None, rows: int | None = None, *, fit: Literal['crop', 'contain', 'cover', 'stretch', 'smart'] = 'contain', horizontal_pixels_per_cell: int = 1, should_correct_aspect_ratio: bool = False, background: tuple[int, int, int] = (0, 0, 0), resampling_filter: Literal['nearest', 'bilinear', 'catmull_rom', 'lanczos3'] = 'lanczos3', graphics: TerminalGraphics | None = None) -> list[bytes]
Convert every frame to its own cell grid (XCG1 bytes).
Takes the same arguments as
to_cell_grid, except
frame_index. Pair the result with
frame_durations, or use
to_cell_animation to
get frames and timing in one value.
Raises:
-
TerminalImageError–If an option is invalid or a grid would hold more than 4000000 cells.
Source code in packages/xnano-image/src/xnano_image/_xnano_image/__init__.pyi
to_cell_animation
¶
to_cell_animation(columns: int | None = None, rows: int | None = None, *, should_loop: bool = True, fit: Literal['crop', 'contain', 'cover', 'stretch', 'smart'] = 'contain', horizontal_pixels_per_cell: int = 1, should_correct_aspect_ratio: bool = False, background: tuple[int, int, int] = (0, 0, 0), resampling_filter: Literal['nearest', 'bilinear', 'catmull_rom', 'lanczos3'] = 'lanczos3', graphics: TerminalGraphics | None = None) -> bytes
Convert every frame, with its display time, to a cell animation (XCA1 bytes).
Takes the same arguments as
to_cell_grid, except
frame_index. A still image becomes a one-frame animation.
With the kitty protocol every frame reuses one image id, so the
terminal replaces the image in place instead of storing a new one per
frame; each frame still carries its full pixel data. sixel and
iterm2 frames carry their full image data every frame.
Parameters:
-
should_loop(bool, default:True) –Start over after the last frame; otherwise hold the last frame.
Raises:
-
TerminalImageError–If an option is invalid, or the animation would hold more than 100000 frames or 64000000 cells in total. Pass smaller
columnsorrows, or keep fewer frames withfirst_frames.
Source code in packages/xnano-image/src/xnano_image/_xnano_image/__init__.pyi
to_ansi
¶
to_ansi(columns: int | None = None, rows: int | None = None, *, fit: Literal['crop', 'contain', 'cover', 'stretch', 'smart'] = 'contain', horizontal_pixels_per_cell: int = 1, should_correct_aspect_ratio: bool = False, background: tuple[int, int, int] = (0, 0, 0), resampling_filter: Literal['nearest', 'bilinear', 'catmull_rom', 'lanczos3'] = 'lanczos3', frame_index: int = 0) -> str
One frame as half-block ANSI text, ready to print.
Takes the same arguments as
to_cell_grid, except
graphics. Every line ends with a style reset.
Source code in packages/xnano-image/src/xnano_image/_xnano_image/__init__.pyi
encode
¶
Encode as png (the first frame) or gif (every frame, looping).
Raises:
-
TerminalImageError–If
image_formatis notpngorgif.
Source code in packages/xnano-image/src/xnano_image/_xnano_image/__init__.pyi
save
¶
Write to path; the extension (.png or .gif) picks the format.
Raises:
-
TerminalImageError–If the extension is not
.pngor.gif. -
OSError–If the file cannot be written.
Source code in packages/xnano-image/src/xnano_image/_xnano_image/__init__.pyi
to_xni
¶
Encode as the compact XNI1 container, quantized to colors.
Raises:
-
TerminalImageError–If
colorsis not between 2 and 256, or there are more than 65535 frames.