### Install textual-image (Basic) Source: https://github.com/lnqs/textual-image/blob/main/README.md Install the basic textual-image package using pip. ```sh pip install textual-image ``` -------------------------------- ### Example BackgroundColor Usage Source: https://github.com/lnqs/textual-image/blob/main/_autodocs/types.md Demonstrates creating BackgroundColor tuples for Sixel rendering. Examples include a black opaque background and a semi-transparent white background. ```python from textual_image._sixel import image_to_sixels, BackgroundColor # Black background (default) bg: BackgroundColor = (0, 0, 0, 1.0) # Semi-transparent white bg: BackgroundColor = (255, 255, 255, 0.5) ``` -------------------------------- ### Install Textual Image Source: https://github.com/lnqs/textual-image/blob/main/_autodocs/quick-reference.md Install the library with optional dependencies for Textual widget support or NumPy optimization. ```bash # Basic installation (Rich renderable only) pip install textual-image # With Textual widget support pip install textual-image[textual] # With NumPy optimization (Sixel encoding ~3x faster) pip install textual-image[numpy] ``` -------------------------------- ### Install uv pre-commit Hook Source: https://github.com/lnqs/textual-image/blob/main/README.md Install the pre-commit hook for commit message validation using uv. ```sh uv run pre-commit install --hook-type commit-msg ``` -------------------------------- ### Install Textual Image with NumPy Support Source: https://github.com/lnqs/textual-image/blob/main/_autodocs/api-reference/graphics-protocols.md Installs the `textual-image` library with NumPy support, which accelerates Sixel encoding through optimized palette compaction and band iteration. ```bash pip install textual-image[numpy] ``` -------------------------------- ### Basic Image Widget Usage Source: https://github.com/lnqs/textual-image/blob/main/_autodocs/api-reference/widget-image.md A simple example of how to create and run a Textual application displaying an Image widget with a specified file path. ```python from textual.app import App, ComposeResult from textual_image.widget import Image class ImageApp(App): def compose(self) -> ComposeResult: yield Image("path/to/image.png") if __name__ == "__main__": ImageApp().run() ``` -------------------------------- ### Install textual-image with Textual Widget Dependencies Source: https://github.com/lnqs/textual-image/blob/main/README.md Install textual-image along with its Textual Widget dependencies using pip. ```sh pip install textual-image[textual] ``` -------------------------------- ### Get Help for textual-image Module Source: https://github.com/lnqs/textual-image/blob/main/README.md Display the help message for the textual-image module, showing available arguments and options. ```sh python -m textual_image --help ``` -------------------------------- ### Example: ImageSize Calculation Source: https://github.com/lnqs/textual-image/blob/main/_autodocs/types.md Demonstrates calculating both cell and pixel dimensions for an ImageSize object using provided terminal dimensions and cell size. ```python from textual_image._geometry import ImageSize from textual_image._terminal import CellSize # Image: 1920x1080, target: 80% width, auto height size = ImageSize(1920, 1080, "80%", "auto") # Terminal: 120 cells wide, 40 cells tall, each cell is 10x20 pixels terminal = CellSize(width=10, height=20) # Calculate cell dimensions cell_width, cell_height = size.get_cell_size(120, 40, terminal) # Result: width=96 cells, height=54 cells (maintaining 16:9 ratio) # Calculate pixel dimensions px_width, px_height = size.get_pixel_size(120, 40, terminal) # Result: width=960 pixels, height=1080 pixels ``` -------------------------------- ### Basic Sixel Options Configuration Source: https://github.com/lnqs/textual-image/blob/main/_autodocs/types.md Create SixelOptions to reduce the number of colors for smaller output size. This example sets the color count to 128. ```python from textual_image.renderable.sixel import Image, SixelOptions # Reduce to 128 colors for smaller output options = SixelOptions(colors=128) image = Image("photo.png", sixel_options=options) ``` -------------------------------- ### Example Debug Log Output Source: https://github.com/lnqs/textual-image/blob/main/_autodocs/errors.md Illustrative log messages showing Sixel detection and successful terminal cell size query. ```text DEBUG:textual_image.renderable:Sixel support detected DEBUG:textual_image._terminal:Query succeeded: CellSize(width=10, height=20) ``` -------------------------------- ### Configure SixelOptions with Light Smoothing Source: https://github.com/lnqs/textual-image/blob/main/_autodocs/configuration.md Example of configuring SixelOptions with light smoothing (smooth=3) and a full color palette for slightly noisy photos. This balances detail preservation with minor noise reduction. ```python from textual_image.renderable.sixel import Image, SixelOptions # Light smoothing for slightly noisy photos options = SixelOptions(colors=256, smooth=3) image = Image("modern_photo.png", sixel_options=options) ``` -------------------------------- ### Example Usage of _LONG_RUN_RE Source: https://github.com/lnqs/textual-image/blob/main/_autodocs/constants-and-defaults.md Demonstrates how the _LONG_RUN_RE pattern can be used to find and compress sequences of four or more identical bytes. ```python # Input: b"AAAABBBBCCCC" # Matches: (b"AAAA", 4), (b"BBBB", 4), (b"CCCC", 4) ``` -------------------------------- ### Load Image Data from Stream Source: https://github.com/lnqs/textual-image/blob/main/_autodocs/api-reference/functions-and-utilities.md This example shows how to load image data, buffering non-seekable streams into a `BytesIO` object for compatibility with `PixelData`. ```python from textual_image._utils import is_non_seekable_stream from textual_image._pixeldata import PixelData import io def load_image_data(source): if is_non_seekable_stream(source): # Buffer non-seekable stream to seekable BytesIO buffered = io.BytesIO(source.read()) return PixelData(buffered) else: # Use directly return PixelData(source) ``` -------------------------------- ### Configure SixelOptions for Compact Output Source: https://github.com/lnqs/textual-image/blob/main/_autodocs/configuration.md Example of creating SixelOptions with a reduced color count for more compact output, suitable for photo galleries. This snippet demonstrates how to instantiate the Image class with custom Sixel options. ```python from textual_image.renderable.sixel import Image, SixelOptions # Compact output for photo gallery options = SixelOptions(colors=64) image = Image("photo.png", sixel_options=options) ``` -------------------------------- ### Configure SixelOptions with Fast Octree Quantization Source: https://github.com/lnqs/textual-image/blob/main/_autodocs/configuration.md Example of setting the quantize option to 'fastoctree', the recommended default for balanced quality and speed in color quantization. This is suitable for general-purpose image encoding. ```python options = SixelOptions(quantize="fastoctree") ``` -------------------------------- ### Configure SixelOptions with Max Coverage Quantization Source: https://github.com/lnqs/textual-image/blob/main/_autodocs/configuration.md Example of configuring SixelOptions with the 'maxcoverage' quantization algorithm and a full color palette. This method is best for large images where file size is critical and some quality loss is acceptable. ```python options = SixelOptions(colors=256, quantize="maxcoverage") ``` -------------------------------- ### Unicode Rendering Example Source: https://github.com/lnqs/textual-image/blob/main/_autodocs/api-reference/renderable-image.md Demonstrates how to render an image using the Image class with Unicode characters. This method is suitable for terminals that support Unicode. ```python from rich.console import Console from textual_image.renderable.unicode import Image console = Console() console.print(Image("photo.png")) ``` -------------------------------- ### Example Usage of _NONZERO_RUN_RE Source: https://github.com/lnqs/textual-image/blob/main/_autodocs/constants-and-defaults.md Illustrates the use of _NONZERO_RUN_RE to identify contiguous sequences of non-zero bytes, useful for detecting color spans. ```python # Input: b"A\x00B\x00\x00C" # Matches: b"A", b"B", b"C" ``` -------------------------------- ### Example of Setting Environment Variables for Cell Dimensions Source: https://github.com/lnqs/textual-image/blob/main/_autodocs/constants-and-defaults.md Demonstrates how to export environment variables to override terminal cell dimensions, useful for environments like textual-serve. ```bash export TEXTUAL_CELL_WIDTH=10 export TEXTUAL_CELL_HEIGHT=20 python myapp.py ``` -------------------------------- ### Query Terminal Support Before Rendering Source: https://github.com/lnqs/textual-image/blob/main/_autodocs/errors.md Check terminal support for TGP or Sixel rendering before initializing the image class. This should be done before the Textual app starts. ```python from textual_image.renderable.tgp import query_terminal_support, Image as TGPImage from textual_image.renderable.sixel import Image as SixelImage # Query before rendering (must do this before Textual app starts) try: supports_tgp = query_terminal_support() except Exception: supports_tgp = False if supports_tgp: image_class = TGPImage else: image_class = SixelImage ``` -------------------------------- ### Render Image with Rich Source: https://github.com/lnqs/textual-image/blob/main/_autodocs/INDEX.md Use this snippet to render an image using the Rich library. Ensure you have the 'rich' and 'textual-image' libraries installed. ```python from rich.console import Console from textual_image.renderable import Image console = Console() console.print(Image("photo.png")) ``` -------------------------------- ### Configure SixelOptions with Heavy Smoothing Source: https://github.com/lnqs/textual-image/blob/main/_autodocs/configuration.md Example of configuring SixelOptions with heavy smoothing (smooth=7) and a moderate color count for noisy photos. This aims to reduce noise and output size while maintaining acceptable quality. ```python from textual_image.renderable.sixel import Image, SixelOptions # Heavy smoothing for noisy photos options = SixelOptions(colors=128, smooth=7) image = Image("old_photo.png", sixel_options=options) ``` -------------------------------- ### Simplified Sixel Stream Example Source: https://github.com/lnqs/textual-image/blob/main/_autodocs/api-reference/graphics-protocols.md Illustrates the basic structure of a Sixel graphics stream, including the header, palette definitions, image data, and terminator sequence. ```text # Simplified structure \x1b[?80h # Enable sixel (sent by terminal) \x1b P q # Start sequence #0;2;0;0;0#1;2;255;0;0 # Define 2 colors (black, red) !!!!!!!!!- # Sixel data \x1b \ # End sequence ``` -------------------------------- ### Fallback Rendering Example Source: https://github.com/lnqs/textual-image/blob/main/_autodocs/api-reference/renderable-image.md Shows how to use the Image class with automatic fallback to Unicode rendering if the terminal is not a TTY. This ensures compatibility across different terminal environments. ```python from rich.console import Console from textual_image.renderable import Image as AutoImage # This will automatically fall back to Unicode if terminal is not TTY console = Console() console.print(AutoImage("photo.png")) ``` -------------------------------- ### Validate ImageSize Values Source: https://github.com/lnqs/textual-image/blob/main/_autodocs/errors.md Provides examples of valid and invalid values for ImageSize validation, showing how ValueError is raised for incorrect formats. ```python from textual_image._geometry import ImageSize # Valid ImageSize.validate_value(None) # ✓ ImageSize.validate_value(80) # ✓ ImageSize.validate_value("80%") # ✓ ImageSize.validate_value("auto") # ✓ # Invalid try: ImageSize.validate_value("80.5%") # ✗ ValueError ImageSize.validate_value("-50%") # ✗ ValueError ImageSize.validate_value("xyz") # ✗ ValueError except ValueError as e: print(f"Invalid: {e}") ``` -------------------------------- ### Create Image Widget in Textual Source: https://github.com/lnqs/textual-image/blob/main/_autodocs/INDEX.md This snippet demonstrates how to create an image widget within a Textual application. Make sure 'textual' and 'textual-image' are installed. ```python from textual.app import App, ComposeResult from textual_image.widget import Image class ImageApp(App): def compose(self) -> ComposeResult: yield Image("photo.png") ImageApp().run() ``` -------------------------------- ### Render PIL Image with TGP Source: https://github.com/lnqs/textual-image/blob/main/_autodocs/api-reference/renderable-image.md Illustrates how to render an image directly from a PIL (Pillow) Image object using the TGP Image class. Ensure Pillow is installed. ```python from PIL import Image as PILImage from rich.console import Console from textual_image.renderable.tgp import Image as TGPImage pil_image = PILImage.open("photo.png") console = Console() console.print(TGPImage(pil_image, width=50)) ``` -------------------------------- ### RGB Percentage Conversion Formula Source: https://github.com/lnqs/textual-image/blob/main/_autodocs/constants-and-defaults.md Provides the formula and rounding adjustment for converting RGB values to percentages. Examples illustrate the conversion for key values. ```python # Formula: (value * 100 + 127) // 255 # Rounding adjustment: +127 for banker's rounding # Examples: # 0 → 0% # 127 → 50% # 128 → 50% # 255 → 100% ``` -------------------------------- ### Rich Console Table with Images Source: https://github.com/lnqs/textual-image/blob/main/_autodocs/quick-reference.md Demonstrates how to embed images within a Rich console table. This example adds two rows, each with a description and an Image renderable. ```python from rich.console import Console from rich.table import Table from textual_image.renderable import Image console = Console() # Create table with image table = Table(title="Image Gallery") table.add_column("Description") table.add_column("Image") table.add_row( "Landscape", Image("landscape.png", width=40, height="auto") ) table.add_row( "Portrait", Image("portrait.png", width=30, height="auto") ) console.print(table) ``` -------------------------------- ### Debugging Terminal Cell Size and Protocol Support Source: https://github.com/lnqs/textual-image/blob/main/_autodocs/INDEX.md Provides command-line examples for debugging terminal issues, including checking cell size and querying support for Sixel and TGP protocols. ```APIDOC ## Debug Terminal Issues ### Description These command-line snippets can help diagnose terminal-related problems by querying essential information such as cell size and support for specific graphics protocols like Sixel and TGP. ### Commands - **Get Cell Size:** ```bash python -c "from textual_image._terminal import get_cell_size; print(get_cell_size())" ``` This command executes a Python snippet to retrieve the dimensions of a terminal cell. - **Query Sixel Support:** ```bash python -c "from textual_image.renderable.sixel import query_terminal_support; print('Sixel:', query_terminal_support())" ``` This command checks and prints whether the terminal supports the Sixel graphics protocol. - **Query TGP Support:** ```bash python -c "from textual_image.renderable.tgp import query_terminal_support; print('TGP:', query_terminal_support())" ``` This command checks and prints whether the terminal supports the TGP (Tektronix Graphics Protocol). ``` -------------------------------- ### TGP Image Cleanup Example Source: https://github.com/lnqs/textual-image/blob/main/_autodocs/api-reference/graphics-protocols.md Demonstrates how to explicitly free image data from terminal memory using the cleanup() method. This is useful for manual resource management, though it's also called automatically when a widget is destroyed. ```python from textual_image.renderable.tgp import Image from rich.console import Console image = Image("photo.png") console = Console() console.print(image) # Later, free the image from terminal image.cleanup() ``` -------------------------------- ### Best Practice for TGP Support Detection Source: https://github.com/lnqs/textual-image/blob/main/_autodocs/api-reference/graphics-protocols.md Recommends calling query_terminal_support() before starting a Textual application to determine TGP compatibility. It includes error handling for cases where the query might fail or the terminal doesn't support the query mechanism. ```python from textual_image.renderable.tgp import query_terminal_support # Call BEFORE Textual app starts try: supports_tgp = query_terminal_support() except Exception: supports_tgp = False # Then create app app = MyTextualApp() app.run() ``` -------------------------------- ### Sixel Options: Color Reduction Source: https://github.com/lnqs/textual-image/blob/main/_autodocs/api-reference/graphics-protocols.md Example of reducing the color palette size for Sixel output to decrease file size. This uses the `colors` parameter within `SixelOptions`. ```python SixelOptions(colors=64) # 64 colors instead of 256 ``` -------------------------------- ### Run Textual Widget Demonstration Source: https://github.com/lnqs/textual-image/blob/main/README.md Execute the Textual Widget demonstration for textual-image. ```sh python -m textual_image textual ``` -------------------------------- ### Get Terminal Cell Size Source: https://github.com/lnqs/textual-image/blob/main/_autodocs/api-reference/functions-and-utilities.md Queries the terminal for cell dimensions in pixels. Results are cached after the first call. This function should be called before a Textual app starts. ```python from textual_image._terminal import get_cell_size, CellSize cell_size = get_cell_size() # Returns: CellSize(width=10, height=20) ``` -------------------------------- ### Run Rich Renderable Demonstration Source: https://github.com/lnqs/textual-image/blob/main/README.md Execute the Rich renderable demonstration for textual-image. ```sh python -m textual_image rich ``` -------------------------------- ### Avoid Thread Safety Issues with TGP Query Source: https://github.com/lnqs/textual-image/blob/main/_autodocs/api-reference/graphics-protocols.md Demonstrates the incorrect way to call `query_terminal_support` within a running Textual app, which can lead to race conditions. The correct approach is to query support before the app starts. ```python # ❌ Do NOT do this in Textual from textual.app import App from textual_image.renderable.tgp import query_terminal_support app = App() # Textual has started thread for input/output supports = query_terminal_support() # Will fail or hang app.run() ``` ```python # ✓ Correct from textual_image.renderable.tgp import query_terminal_support from textual.app import App supports = query_terminal_support() # Before threads start app = App() app.run() ``` -------------------------------- ### Custom TGP Image Cleanup Source: https://github.com/lnqs/textual-image/blob/main/_autodocs/api-reference/graphics-protocols.md Provides an example of subclassing the TGP Image class to override the cleanup method for custom behavior, such as logging. It demonstrates calling the parent class's cleanup method to ensure proper resource deallocation. ```python from textual_image.renderable.tgp import Image from rich.console import Console, ConsoleOptions class CustomTGPImage(Image): def cleanup(self) -> None: print(f"Cleaning up TGP image {self.terminal_image_id}") super().cleanup() image = CustomTGPImage("photo.png", width=100, height="auto") console = Console() console.print(image) # Image stays in terminal until cleanup image.cleanup() # Now image is removed ``` -------------------------------- ### Build Distribution Packages with uv Source: https://github.com/lnqs/textual-image/blob/main/README.md Build the distribution packages for the project using uv. ```sh uv build ``` -------------------------------- ### Example Usage of TerminalError Source: https://github.com/lnqs/textual-image/blob/main/_autodocs/types.md Demonstrates how to catch and handle `TerminalError` exceptions that may occur during terminal operations. This example shows a try-except block to gracefully manage potential failures. ```python from textual_image._terminal import get_cell_size, TerminalError try: sizes = get_cell_size() except TerminalError as e: print(f"Terminal error: {e}") ``` -------------------------------- ### Run Textual Image Demos Source: https://github.com/lnqs/textual-image/blob/main/_autodocs/quick-reference.md Commands to run different demonstrations of the textual-image library. Includes options for built-in demos, Rich renderables, Textual widgets, and forcing specific protocols. ```bash # Run built-in demo python -m textual_image # Rich renderable demo python -m textual_image rich # Textual widget demo python -m textual_image textual # Force specific protocol python -m textual_image -p sixel rich python -m textual_image -p tgp textual python -m textual_image -p halfcell widget python -m textual_image -p unicode renderable ``` -------------------------------- ### TerminalError Wrapped as TimeoutError Source: https://github.com/lnqs/textual-image/blob/main/_autodocs/errors.md Example where a TerminalError, specifically a timeout on response, is wrapped and raised as a TimeoutError. ```python # Running on terminal with no protocol support from textual_image.renderable.sixel import query_terminal_support try: supports = query_terminal_support() except TimeoutError: # TerminalError wrapped as TimeoutError supports = False ``` -------------------------------- ### TerminalError on Non-interactive Shell Source: https://github.com/lnqs/textual-image/blob/main/_autodocs/errors.md Example showing TerminalError when running Python in a non-interactive shell where stdin is closed. ```bash echo 'from textual_image.renderable import Image' | python # TerminalError: stdin is closed ``` -------------------------------- ### TGP Message Formatting Constants Source: https://github.com/lnqs/textual-image/blob/main/_autodocs/constants-and-defaults.md Defines the start and end markers for TGP (Text Graphics Protocol) messages. ```python _TGP_MESSAGE_START = "\x1b_G" # ESC _ G - Start TGP message _TGP_MESSAGE_END = "\x1b\\" # ESC \ - String terminator ``` -------------------------------- ### Group Iterable into Pairs Source: https://github.com/lnqs/textual-image/blob/main/_autodocs/api-reference/functions-and-utilities.md Use the `grouped` utility to divide an iterable into chunks of a specified size. This example groups a list into pairs. ```python from textual_image._utils import grouped # Group list into pairs result = list(grouped([1, 2, 3, 4, 5, 6], 2)) # Result: [(1, 2), (3, 4), (5, 6)] ``` -------------------------------- ### Configure Sixel Options for Performance Source: https://github.com/lnqs/textual-image/blob/main/_autodocs/configuration.md Create SixelOptions optimized for performance, suitable for real-time updates or streaming. This involves reducing colors, disabling smoothing, and using the fastest quantization algorithm. ```python from textual_image.renderable.sixel import SixelOptions # Minimal encoding overhead fast_options = SixelOptions( colors=64, # Reduced palette smooth=None, # No smoothing quantize="fastoctree" # Fastest algorithm ) ``` -------------------------------- ### Configure Sixel Options for Size Source: https://github.com/lnqs/textual-image/blob/main/_autodocs/configuration.md Create SixelOptions optimized for minimal output size, useful in bandwidth-constrained environments. This reduces colors, applies smoothing to reduce scattered pixels, and uses an algorithm for best spatial coherence. ```python from textual_image.renderable.sixel import SixelOptions # Minimal output size compact_options = SixelOptions( colors=64, # Reduce colors smooth=5, # Smooth to reduce scattered pixels quantize="maxcoverage" # Best spatial coherence ) ``` -------------------------------- ### Get Terminal Cell Size Source: https://github.com/lnqs/textual-image/blob/main/_autodocs/types.md Retrieves the current terminal's cell dimensions in pixels. The result is a CellSize named tuple. ```python from textual_image._terminal import get_cell_size cell_size = get_cell_size() # Example: CellSize(width=10, height=20) # Each terminal cell is 10 pixels wide and 20 pixels tall ``` -------------------------------- ### Image Class Initialization with Various Path Types Source: https://github.com/lnqs/textual-image/blob/main/_autodocs/types.md Illustrates how to initialize an `Image` object using different accepted path types: string, bytes, `pathlib.Path` returning string, and `pathlib.Path` returning bytes. This demonstrates the flexibility of the `StrOrBytesPath` type. ```python from pathlib import Path from textual_image.renderable.tgp import Image # String path image1 = Image("photo.png") # bytes path image2 = Image(b"photo.png") # pathlib.Path image3 = Image(Path("photo.png")) # pathlib.Path with bytes image4 = Image(Path(b"photo.png")) ``` -------------------------------- ### Handle TerminalError When Getting Cell Size Source: https://github.com/lnqs/textual-image/blob/main/_autodocs/errors.md Demonstrates how to catch TerminalError when querying terminal dimensions fails due to unavailable output. ```python from textual_image._terminal import get_cell_size, TerminalError try: cell_size = get_cell_size() except TerminalError as e: print(f"Cannot determine cell size: {e}") ``` -------------------------------- ### Define Custom Image Widget Using __init_subclass__ Source: https://github.com/lnqs/textual-image/blob/main/_autodocs/api-reference/widget-image.md Demonstrates the recommended pattern for creating custom image widgets by specifying the renderable class using PEP 560's __init_subclass__. ```python from textual_image.widget._base import BaseImage # Assuming MyRenderableClass is defined elsewhere and matches the ImageRenderable protocol # class MyRenderableClass: # ... class MyImage(BaseImage, Renderable=MyRenderableClass): """Custom image widget using MyRenderableClass.""" pass ``` -------------------------------- ### Image Size Parameters Source: https://github.com/lnqs/textual-image/blob/main/_autodocs/INDEX.md Demonstrates various ways to specify image dimensions using width and height parameters. Supports original size, fixed dimensions, percentage-based sizing, and auto-scaling. ```python # Format variants Image(path, width=None, height=None) # Original size Image(path, width=100, height=50) # 100×50 cells Image(path, width="80%", height="auto") # 80% width, auto height Image(path, width="auto", height="auto") # Auto-scale both ``` -------------------------------- ### Basic Textual Widget Usage Source: https://github.com/lnqs/textual-image/blob/main/_autodocs/quick-reference.md Create a basic Textual app that displays an image. Ensure 'photo.png' is accessible. ```python from textual.app import App, ComposeResult from textual_image.widget import Image class ImageApp(App): def compose(self) -> ComposeResult: yield Image("photo.png") if __name__ == "__main__": ImageApp().run() ``` -------------------------------- ### Change Textual Image Dynamically Source: https://github.com/lnqs/textual-image/blob/main/_autodocs/quick-reference.md Update the image displayed in a Textual widget after the app has started. The widget will automatically re-render with the new image. ```python from textual.app import App, ComposeResult from textual_image.widget import Image class ImageApp(App): def compose(self) -> ComposeResult: yield Image("photo1.png", id="main") def on_mount(self) -> None: # Change image after app starts self.query_one(Image).image = "photo2.png" if __name__ == "__main__": ImageApp().run() ``` -------------------------------- ### Get Terminal Cell Size Source: https://github.com/lnqs/textual-image/blob/main/_autodocs/quick-reference.md Retrieve the current dimensions of a single terminal cell in pixels. This is useful for calculating pixel-based image sizes. ```python from textual_image._terminal import get_cell_size cell_size = get_cell_size() # CellSize(width=10, height=20) pixel_width = cell_size.width pixel_height = cell_size.height ``` -------------------------------- ### Run Tests, Type Checking, and Linting with uv Source: https://github.com/lnqs/textual-image/blob/main/README.md Execute tests with coverage, type checking, linting, and formatting checks using uv. ```sh uv run pytest --cov=textual_image --cov-report=term-missing ``` ```sh uv run mypy . ``` ```sh uv run ruff check . ``` ```sh uv run ruff format --check . ``` ```sh uv run typos . ``` -------------------------------- ### Clamp Value Within Range Source: https://github.com/lnqs/textual-image/blob/main/_autodocs/api-reference/functions-and-utilities.md Use the `clamp` utility to restrict a numerical value to a specified minimum and maximum. This example shows clamping an integer. ```python from textual_image._utils import clamp clamp(5, 0, 10) # Returns: 5 clamp(-5, 0, 10) # Returns: 0 clamp(15, 0, 10) # Returns: 10 ``` -------------------------------- ### Configure Sixel Options for Quality Source: https://github.com/lnqs/textual-image/blob/main/_autodocs/configuration.md Create SixelOptions optimized for maximum image quality, ideal for static images. This uses the full color palette, preserves details, and employs the best color allocation algorithm. ```python from textual_image.renderable.sixel import SixelOptions # Maximum quality quality_options = SixelOptions( colors=256, # Full palette smooth=None, # Preserve all details quantize="maxcoverage" # Best color allocation ) ``` -------------------------------- ### Sixel Options for Output Size Optimization Source: https://github.com/lnqs/textual-image/blob/main/_autodocs/types.md Configure SixelOptions to minimize output size by reducing the color count, applying a small smoothing filter, and using the maxcoverage quantization method. ```python from textual_image.renderable.sixel import SixelOptions # Minimize output size options = SixelOptions( colors=64, # Reduce to 64 colors smooth=3, # Apply 3x3 smoothing quantize="maxcoverage" ) ``` -------------------------------- ### Safely Get Terminal Cell Size Source: https://github.com/lnqs/textual-image/blob/main/_autodocs/errors.md Retrieve terminal cell size, falling back to default VT340 dimensions (10x20) if a TerminalError occurs. ```python from textual_image._terminal import get_cell_size, TerminalError, CellSize def get_terminal_cell_size_safe(): try: return get_cell_size() except TerminalError: # Use VT340 defaults if query fails return CellSize(10, 20) cell_size = get_terminal_cell_size_safe() ``` -------------------------------- ### TGP Image Class and Cleanup Source: https://github.com/lnqs/textual-image/blob/main/_autodocs/api-reference/graphics-protocols.md Demonstrates the initialization of a TGP Image object and how to explicitly free its resources from terminal memory using the `cleanup` method. ```APIDOC ## `textual_image.renderable.tgp.Image` Class ### Description Represents an image to be rendered using the Terminal Graphics Protocol (TGP). ### Methods #### `__init__( image: StrOrBytesPath | IO[bytes] | PILImage.Image, width: int | str | None = None, height: int | str | None = None, ) -> None` Initializes the TGP Image object with the provided image data, optionally specifying width and height. #### `cleanup() -> None` ### Description Frees image data from terminal memory. This method is called automatically when the widget is destroyed, but can also be called manually. It is safe to call multiple times and sends a delete command to the terminal. ### Method `cleanup` ### Endpoint N/A (SDK method) ### Parameters None ### Request Example ```python from textual_image.renderable.tgp import Image from rich.console import Console image = Image("photo.png") console = Console() console.print(image) # Later, free the image from terminal image.cleanup() ``` ### Response None (This is a method call, not an API endpoint response) ### Response Example None ``` -------------------------------- ### Image Rendering with Sixel Options Source: https://github.com/lnqs/textual-image/blob/main/_autodocs/INDEX.md Demonstrates how to configure Sixel encoding options for image rendering, allowing control over colors and smoothing. ```APIDOC ## Configure Sixel Encoding ### Description Use the `SixelOptions` class to customize Sixel encoding parameters such as the number of colors and smoothing. ### Method ```python from textual_image.renderable.sixel import Image, SixelOptions options = SixelOptions(colors=128, smooth=3) image = Image("photo.png", sixel_options=options) ``` ### Parameters #### `Image` Constructor - **filename** (str) - Required - Path to the image file. - **sixel_options** (SixelOptions) - Optional - Configuration for Sixel encoding. #### `SixelOptions` Constructor - **colors** (int) - Optional - Number of colors to use for Sixel encoding (default: 256). - **smooth** (int) - Optional - Smoothing factor for Sixel encoding (default: 0). ``` -------------------------------- ### Query Terminal Device Attributes Source: https://github.com/lnqs/textual-image/blob/main/_autodocs/api-reference/functions-and-utilities.md Queries the terminal for its device attributes using escape sequences. This example demonstrates error handling for timeouts or terminal errors during the query. ```python import sys from textual_image._terminal import capture_terminal_response # Query terminal device attributes try: with capture_terminal_response("\x1b[?", "c", timeout=0.1) as response: sys.__stdout__.write("\x1b[c") sys.__stdout__.flush() sequence = response.sequence[len("\x1b[?"):-len("c")] print(f"Device attributes: {sequence}") except (TimeoutError, TerminalError): print("Terminal query failed") ``` -------------------------------- ### Configure Sixel Options for Maximum Compatibility Source: https://github.com/lnqs/textual-image/blob/main/_autodocs/configuration.md Create SixelOptions that prioritize maximum compatibility across all Sixel-capable terminals. This configuration ensures the widest possible support. ```python from textual_image.renderable.sixel import SixelOptions ``` -------------------------------- ### Image Widget Size Configuration with CSS Source: https://github.com/lnqs/textual-image/blob/main/_autodocs/api-reference/widget-image.md Shows how to control the size of an Image widget using CSS. Supports absolute cell values, percentages, and auto scaling while maintaining aspect ratio. ```python from textual.app import App, ComposeResult from textual_image.widget import Image class MyApp(App): CSS = """ #main-image { width: 50%; height: auto; } """ def compose(self) -> ComposeResult: yield Image("photo.png", id="main-image") ``` -------------------------------- ### capture_terminal_response() Source: https://github.com/lnqs/textual-image/blob/main/_autodocs/api-reference/functions-and-utilities.md A context manager designed to capture terminal responses to escape sequences. It takes start and end markers to identify the relevant part of the response and an optional timeout. ```APIDOC ## capture_terminal_response(start_marker: str, end_marker: str, timeout: float | None) ### Description Context manager to capture terminal response to escape sequence. ### Method ```python with capture_terminal_response(start_marker, end_marker, timeout=None): # ... code to send escape sequence ... pass ``` ### Parameters #### Path Parameters * None #### Query Parameters * None #### Request Body * None #### Parameters - **start_marker** (`str`) - Required - Expected start of response (e.g., `"\x1b["`) - **end_marker** (`str`) - Required - Expected end of response (e.g., `"t"`) - **timeout** (`float | None`) - Optional - Timeout in seconds, `None` to disable (Default: `None`) ### Request Example ```python import sys from textual_image._terminal import capture_terminal_response with capture_terminal_response("\x1b[", "t", timeout=0.1) as response: # Send your escape sequence here sys.__stdout__.write("\x1b[16t") sys.__stdout__.flush() # Response is in response.sequence print(f"Terminal response: {response.sequence}") ``` ### Response #### Success Response Yields a `SimpleNamespace` object with a `sequence` attribute containing the captured response. #### Response Example ```python # Assuming response is the yielded SimpleNamespace object print(f"Captured sequence: {response.sequence}") ``` ### Error Handling - `TerminalError`: If stdin is unavailable. - `TimeoutError`: If the response is not received within the specified timeout. - `TerminalError`: If the response does not match the expected start and end markers. ### Notes - May consume the first stdin character if the terminal does not respond. - Will not work once a Textual app has started. - Can be flaky with concurrent keyboard input. ### Example ```python import sys from textual_image._terminal import capture_terminal_response from textual_image.errors import TerminalError # Query terminal device attributes try: with capture_terminal_response("\x1b[?", "c", timeout=0.1) as response: sys.__stdout__.write("\x1b[c") sys.__stdout__.flush() sequence = response.sequence[len("\x1b[?"):-len("c")] print(f"Device attributes: {sequence}") except (TimeoutError, TerminalError): print("Terminal query failed") ``` ``` -------------------------------- ### Image Widget Property Usage Source: https://github.com/lnqs/textual-image/blob/main/_autodocs/api-reference/widget-image.md Demonstrates how to initialize an Image widget with an initial image and later update it. Setting the 'image' property triggers a refresh of the widget. ```python from textual.app import App, ComposeResult from textual_image.widget import Image class MyApp(App): def compose(self) -> ComposeResult: image = Image("initial.png") yield image def on_mount(self) -> None: # Later, change the image self.query_one(Image).image = "different.png" ``` -------------------------------- ### Define PixelMeta for Image Dimensions Source: https://github.com/lnqs/textual-image/blob/main/_autodocs/types.md Use PixelMeta to access image dimensions without loading full pixel data. This is useful for quickly getting image size information. ```python class PixelMeta: width: int height: int ``` ```python from textual_image._pixeldata import PixelMeta meta = PixelMeta("photo.png") print(f"Image size: {meta.width}x{meta.height}") ``` -------------------------------- ### Sixel Options: High Quality Source: https://github.com/lnqs/textual-image/blob/main/_autodocs/quick-reference.md Configure Sixel options for high-quality output using the full color palette, no smoothing, and a fast octree quantization method. ```python from textual_image.renderable.sixel import Image, SixelOptions options = SixelOptions( colors=256, # Full palette smooth=None, # No smoothing quantize="fastoctree" # Fast, good quality ) image = Image("photo.png", sixel_options=options) ``` -------------------------------- ### Sixel Options: Lazy Palette Source: https://github.com/lnqs/textual-image/blob/main/_autodocs/api-reference/graphics-protocols.md Example of enabling a lazy color palette in Sixel encoding, which omits unused colors from the output to reduce size. This is controlled by the `lazy_color_palette` parameter in `SixelOptions`. ```python SixelOptions(lazy_color_palette=True) # Omit unused colors ``` -------------------------------- ### Sixel Options for Quality Optimization Source: https://github.com/lnqs/textual-image/blob/main/_autodocs/types.md Configure SixelOptions for optimal image quality by using a full color palette, a smoothing filter, and the maxcoverage quantization method. ```python from textual_image.renderable.sixel import SixelOptions # Smooth filter reduces scattered pixels options = SixelOptions( colors=256, # Full palette smooth=5, # 5x5 smoothing kernel quantize="maxcoverage" # Best color allocation ) ``` -------------------------------- ### Calculate Render Size with Cell Size Source: https://github.com/lnqs/textual-image/blob/main/_autodocs/api-reference/functions-and-utilities.md Calculates the render size in cells based on image dimensions and terminal cell size. This example demonstrates using the cached cell size for calculations. ```python from textual_image._terminal import get_cell_size from textual_image._geometry import ImageSize cell_size = get_cell_size() # Use for size calculations size = ImageSize(1920, 1080, "80%", "auto") cell_width, cell_height = size.get_cell_size(120, 40, cell_size) print(f"Render at {cell_width}×{cell_height} cells") ``` -------------------------------- ### Set Adaptive Quantization Source: https://github.com/lnqs/textual-image/blob/main/_autodocs/configuration.md Configure Sixel rendering to use the adaptive median-cut quantization method. This provides a balance between quality and compatibility. ```python options = SixelOptions(quantize="adaptive") ``` -------------------------------- ### Sixel Options: Quantization Method Source: https://github.com/lnqs/textual-image/blob/main/_autodocs/api-reference/graphics-protocols.md Shows how to specify the color quantization method for Sixel encoding, using the `quantize` parameter in `SixelOptions`. 'maxcoverage' is recommended for best spatial coherence. ```python SixelOptions(quantize="maxcoverage") # Best spatial coherence ``` -------------------------------- ### Check Terminal Support for TGP and Sixel Protocols Source: https://github.com/lnqs/textual-image/blob/main/_autodocs/quick-reference.md Query the terminal for support of TGP (Text Graphics Protocol) and Sixel graphics protocols. This check must be performed before starting a Textual application. ```python from textual_image.renderable.tgp import query_terminal_support as check_tgp from textual_image.renderable.sixel import query_terminal_support as check_sixel # Must be called before Textual app starts! supports_tgp = check_tgp() supports_sixel = check_sixel() if supports_tgp: from textual_image.renderable.tgp import Image elif supports_sixel: from textual_image.renderable.sixel import Image else: from textual_image.renderable.unicode import Image ``` -------------------------------- ### Sixel Options: Compact Output Source: https://github.com/lnqs/textual-image/blob/main/_autodocs/quick-reference.md Configure Sixel options for compact output by reducing colors, applying a smooth filter, and using a specific quantization method. ```python from textual_image.renderable.sixel import Image, SixelOptions options = SixelOptions( colors=64, # Reduce to 64 colors smooth=5, # Smooth filter for coherence quantize="maxcoverage" # Best color allocation ) image = Image("photo.png", sixel_options=options) ``` -------------------------------- ### Enable Sixel Support in xterm Source: https://github.com/lnqs/textual-image/blob/main/README.md Launch xterm with specific options to enable Sixel support. This can also be made permanent via .Xresources. ```sh xterm +lc -ti vt340 ``` ```sh echo 'XTerm*decTerminalID: vt340' >> ~/.Xresources xrdb -merge ~/.Xresources ``` -------------------------------- ### Sync Project Dependencies with uv Source: https://github.com/lnqs/textual-image/blob/main/README.md Synchronize project dependencies, including all optional extras and development dependencies, using the uv tool. ```sh uv sync --all-extras ``` -------------------------------- ### Auto-Detect Best Available Image Protocol Source: https://github.com/lnqs/textual-image/blob/main/_autodocs/quick-reference.md The recommended approach is to let the `Image` class automatically detect and use the best available terminal image rendering method. ```python from textual_image.renderable import Image # Automatically detects and uses best available method image = Image("photo.png") ``` -------------------------------- ### Image Class Initialization Source: https://github.com/lnqs/textual-image/blob/main/_autodocs/api-reference/renderable-image.md Initializes an Image renderable for use with Rich. Supports various image inputs and size specifications. ```APIDOC ## Image Class ### Description Initializes an Image renderable for use with Rich. Supports various image inputs and size specifications. ### Method Signature `Image(image: StrOrBytesPath | IO[bytes] | PILImage.Image, width: int | str | None = None, height: int | str | None = None)` ### Parameters #### Parameters - **image** (`StrOrBytesPath | IO[bytes] | PILImage.Image`) - Required - Path to image file, byte stream, or PIL Image instance - **width** (`int | str | None`) - Optional - Width specification (see ImageSize) - **height** (`int | str | None`) - Optional - Height specification (see ImageSize) ### Returns Instance of `Image` renderable for use with Rich. ``` -------------------------------- ### Gallery App with Textual Source: https://github.com/lnqs/textual-image/blob/main/_autodocs/quick-reference.md A Textual app to display a gallery of PNG images from a 'photos' directory. It includes navigation buttons for previous and next images and updates a counter. ```python from textual.app import App, ComposeResult from textual.containers import Container from textual.widgets import Button, Label from textual_image.widget import Image from pathlib import Path class GalleryApp(App): CSS = """ Screen { layout: vertical; } #image { width: 100%; height: 1fr; } #controls { height: 3; dock: bottom; } """ def compose(self) -> ComposeResult: self.images = list(Path("photos").glob("*.png")) self.current = 0 yield Image(str(self.images[0]), id="image") yield Container( Label(f"1 / {len(self.images)}", id="counter"), Button("◀ Previous", id="prev"), Button("Next ▶", id="next"), id="controls" ) def on_button_pressed(self, event: Button.Pressed) -> None: if event.button.id == "next": self.current = (self.current + 1) % len(self.images) else: self.current = (self.current - 1) % len(self.images) image = self.query_one(Image) image.image = str(self.images[self.current]) counter = self.query_one(Label) counter.update(f"{self.current + 1} / {len(self.images)}") ``` -------------------------------- ### Capture Terminal Response with Markers Source: https://github.com/lnqs/textual-image/blob/main/_autodocs/api-reference/functions-and-utilities.md A context manager to capture terminal responses to escape sequences. It requires specifying start and end markers and an optional timeout. The captured sequence is available in the `sequence` attribute of the response object. ```python import sys from textual_image._terminal import capture_terminal_response with capture_terminal_response("\x1b[", "t", timeout=0.1) as response: # Send your escape sequence here sys.__stdout__.write("\x1b[16t") sys.__stdout__.flush() # Response is in response.sequence print(f"Terminal response: {response.sequence}") ``` -------------------------------- ### Query Terminal Sixel Support Source: https://github.com/lnqs/textual-image/blob/main/_autodocs/api-reference/renderable-image.md Detects if the current terminal supports Sixel graphics. This function is useful for conditionally rendering Sixel images. Note that it may not work reliably once a Textual app has started or with concurrent keyboard input. ```python from textual_image.renderable.sixel import query_terminal_support if query_terminal_support(): print("Sixel is supported") ``` -------------------------------- ### Import Type Hints for Image Loading Source: https://github.com/lnqs/textual-image/blob/main/_autodocs/quick-reference.md Import various types used for image loading and rendering, including paths, options, geometry, and terminal size information. ```python from textual_image._utils import StrOrBytesPath from textual_image._sixel import SixelOptions, BackgroundColor from textual_image._geometry import ImageSize from textual_image._terminal import CellSize from pathlib import Path from typing import IO from PIL import Image as PILImage def load_image( image: StrOrBytesPath | IO[bytes] | PILImage.Image, width: int | str | None = None, height: int | str | None = None, sixel_options: SixelOptions | None = None, ) -> None: """Load and render image with specified options.""" pass ``` -------------------------------- ### get_cell_size() Source: https://github.com/lnqs/textual-image/blob/main/_autodocs/api-reference/functions-and-utilities.md Queries the terminal for its cell dimensions in pixels. This function caches the result after the first call to avoid repeated queries. It attempts to get the cell size using ioctl, then escape sequences, environment variables, or finally VT340 defaults. ```APIDOC ## get_cell_size() ### Description Query terminal for cell dimensions in pixels. Results are cached after first call. ### Method ```python get_cell_size() ``` ### Returns `CellSize` with width and height in pixels. `CellSize(width: int, height: int)` where width and height are in pixels per terminal cell. ### Caching Queries terminal only once per process. Subsequent calls return cached result. ### How It Works 1. Attempts ioctl query (fastest, most accurate) 2. Falls back to escape sequence query (slower) 3. Falls back to environment variables `TEXTUAL_CELL_WIDTH` / `TEXTUAL_CELL_HEIGHT` 4. Falls back to VT340 defaults (10×20 pixels) ### Raises `TerminalError` if stdout is unavailable. ### Note Must be called before Textual app starts. Textual runs input thread that will intercept terminal responses. ### Example ```python from textual_image._terminal import get_cell_size from textual_image._geometry import ImageSize cell_size = get_cell_size() # Returns: CellSize(width=10, height=20) # Use for size calculations size = ImageSize(1920, 1080, "80%", "auto") cell_width, cell_height = size.get_cell_size(120, 40, cell_size) print(f"Render at {cell_width}×{cell_height} cells") ``` ### Fallback Chain Example ```python from textual_image._terminal import get_cell_size # On machine without ioctl support: # 1. Tries ioctl → fails # 2. Tries escape sequence → succeeds → returns result # 3. Caches result # 4. Subsequent calls return cached value cell_size = get_cell_size() ``` ``` -------------------------------- ### Sixel RGB to Percentage Conversion Table Source: https://github.com/lnqs/textual-image/blob/main/_autodocs/constants-and-defaults.md A lookup table for converting 8-bit RGB values (0-255) to Sixel percentage values (0-100), rounded to the nearest percent. ```python _RGB_TO_PCT = tuple((v * 100 + 127) // 255 for v in range(256)) ``` -------------------------------- ### Render Image from Byte Stream with TGP Source: https://github.com/lnqs/textual-image/blob/main/_autodocs/api-reference/renderable-image.md Shows how to render an image from a byte stream (e.g., read from a file in binary mode) using the TGP Image class. This is useful for in-memory image data. ```python import io from rich.console import Console from textual_image.renderable.tgp import Image with open("photo.png", "rb") as f: data = io.BytesIO(f.read()) console = Console() console.print(Image(data)) ``` -------------------------------- ### Image Viewer with Textual Bindings Source: https://github.com/lnqs/textual-image/blob/main/_autodocs/quick-reference.md A Textual app for viewing PNG images in the current directory. It uses keyboard bindings (n, p, q) for navigation and quitting, and displays images using the Image widget. ```python from textual.app import App, ComposeResult from textual.widgets import Footer from textual.binding import Binding from textual_image.widget import Image from pathlib import Path class ViewerApp(App): BINDINGS = [ Binding("n", "next", "Next"), Binding("p", "previous", "Previous"), Binding("q", "quit", "Quit"), ] def compose(self) -> ComposeResult: self.images = sorted(Path(".").glob("*.png")) self.index = 0 yield Image(str(self.images[0]), id="image") yield Footer() def action_next(self) -> None: self.index = (self.index + 1) % len(self.images) self.query_one(Image).image = str(self.images[self.index]) def action_previous(self) -> None: self.index = (self.index - 1) % len(self.images) self.query_one(Image).image = str(self.images[self.index]) ``` -------------------------------- ### Override Sixel Image Default Options Source: https://github.com/lnqs/textual-image/blob/main/_autodocs/api-reference/graphics-protocols.md Demonstrates how to override the project-wide default Sixel options for specific `Image` instances or globally for an application. This allows customization of color depth and smoothing. ```python from textual_image.renderable.sixel import Image, SixelOptions # Set compact defaults for this app Image.DEFAULT_OPTIONS = SixelOptions(colors=64, smooth=3) # All instances now use these defaults img1 = Image("photo1.png") img2 = Image("photo2.png") # Can still override per-instance img3 = Image("photo3.png", sixel_options=SixelOptions(colors=256)) ```