(** OCaml implementation of the Kitty graphics protocol. This library provides a clean API for generating escape sequences to display images and animations in terminals that support the Kitty graphics protocol. The protocol uses APC (Application Program Command) escape sequences to transmit and display images with extensive control over placement, sizing, and composition. See {{: https://sw.kovidgoyal.net/kitty/graphics-protocol/} Kitty Graphics Protocol} for the complete specification. *) (** {1 Core Types} *) (** Image format for raw pixel data. *) type format = | RGB (** 24-bit RGB (3 bytes per pixel) *) | RGBA (** 32-bit RGBA (4 bytes per pixel) *) | PNG (** PNG format *) (** Compression method for image data. *) type compression = | No_compression | Zlib (** Transmission medium. *) type transmission = | Direct of { format : format; data : bytes; width : int; (** Width in pixels *) height : int; (** Height in pixels *) compression : compression; } | File of { path : string; } (** Image identifier (number or string up to 24 chars). *) type image_id = private string (** Placement identifier. *) type placement_id = private int (** {1 Image Identifiers} *) (** [image_id_of_int n] creates an image ID from an integer. @raise Invalid_argument if [n] is negative *) val image_id_of_int : int -> image_id (** [image_id_of_string s] creates an image ID from a string. @raise Invalid_argument if [s] is empty or longer than 24 characters *) val image_id_of_string : string -> image_id (** [placement_id_of_int n] creates a placement ID from an integer. @raise Invalid_argument if [n] is negative *) val placement_id_of_int : int -> placement_id (** {1 Placement Configuration} *) (** Placement configuration for displaying images. *) type placement (** [v ?image_id ?placement_id ?x ?y ?width ?height ?rows ?columns ?z_index ?cursor_movement transmission ()] creates a placement configuration. @param image_id Image identifier for reuse/deletion @param placement_id Placement identifier for this specific display @param x Left edge offset in pixels @param y Top edge offset in pixels @param width Width in pixels (scales image if different from source) @param height Height in pixels (scales image if different from source) @param rows Height in terminal cells @param columns Width in terminal cells @param z_index Z-order for layering (-2^31 to 2^31-1, default 0) @param cursor_movement If false, cursor doesn't move after display (default true) @param transmission The image data transmission method *) val v : ?image_id:image_id -> ?placement_id:placement_id -> ?x:int -> ?y:int -> ?width:int -> ?height:int -> ?rows:int -> ?columns:int -> ?z_index:int -> ?cursor_movement:bool -> transmission -> unit -> placement (** {1 Rendering} *) (** [render placement] generates the complete escape sequence(s) for the placement. For large images that require chunking, this returns a single string with all chunks. *) val render : placement -> string (** [render_chunked placement] generates escape sequences as a list of chunks. Useful for streaming large images or interleaving with other output. *) val render_chunked : placement -> string list (** {1 Deletion} *) (** Delete images or placements. *) module Delete : sig (** Deletion target. *) type target = | By_id of image_id | By_image_id of image_id | By_placement_id of placement_id | At_cursor | All (** [render target] generates the escape sequence to delete images. *) val render : target -> string end (** {1 Animation} *) (** Animation support for multi-frame images. *) module Animation : sig (** Frame composition mode. *) type composition = | Blend (** Alpha blend with previous frame *) | Overwrite (** Replace previous frame *) (** Animation frame configuration. *) type frame (** [frame ?composition ?gap transmission frame_number] creates a frame configuration. @param composition How to compose this frame with previous frames @param gap Gap before next frame in milliseconds (0-65535) @param transmission The frame image data @param frame_number Frame index (1-based) *) val frame : ?composition:composition -> ?gap:int -> transmission -> int -> frame (** Animation control. *) type control = | Set_gap of { frame_number : int; (** Which frame to modify *) gap : int; (** New gap in milliseconds *) } | Set_loop of int (** Number of loops (0 = infinite) *) | Stop (** Stop animation *) | Run (** Resume animation *) (** [render_frame image_id frame] generates escape sequence for transmitting an animation frame. @param image_id The animation's image identifier *) val render_frame : image_id -> frame -> string (** [render_control image_id control] generates escape sequence for animation control. *) val render_control : image_id -> control -> string end (** {1 Fmt-style Formatters} *) (** [pp placement] creates a Fmt formatter that displays an image. Example: {[ let img = Graphics.v (Graphics.File { path = "image.png" }) () in Fmt.pr "Here's an image: %a" Graphics.pp img ]} *) val pp : placement -> unit Fmt.t (** [pp_delete target] creates a Fmt formatter that deletes images. Example: {[ Fmt.pr "Clearing screen: %a" Graphics.pp_delete Graphics.Delete.All ]} *) val pp_delete : Delete.target -> unit Fmt.t (** [pp_animation_frame image_id frame] creates a Fmt formatter for animation frames. *) val pp_animation_frame : image_id -> Animation.frame -> unit Fmt.t (** [pp_animation_control image_id control] creates a Fmt formatter for animation control. *) val pp_animation_control : image_id -> Animation.control -> unit Fmt.t (** {1 Convenience Functions} *) (** [display_png_file ?x ?y ?width ?height ?rows ?columns path] displays a PNG file. @param path Path to PNG file @return Escape sequence string *) val display_png_file : ?x:int -> ?y:int -> ?width:int -> ?height:int -> ?rows:int -> ?columns:int -> string -> string (** [display_png_bytes ?x ?y ?width ?height ?rows ?columns ~width:w ~height:h data] displays PNG data from bytes. @param width Image width in pixels @param height Image height in pixels @param data PNG-encoded image data @return Escape sequence string *) val display_png_bytes : ?x:int -> ?y:int -> ?width:int -> ?height:int -> ?rows:int -> ?columns:int -> w:int -> h:int -> bytes -> string (** [delete_all ()] generates escape sequence to delete all images. *) val delete_all : unit -> string (** [delete_by_id id] generates escape sequence to delete image by ID. *) val delete_by_id : image_id -> string