// SPDX-FileCopyrightText: © 2026 Jeffrey C. Ollie // SPDX-License-Identifier: MIT //! Reading and writing DEC sixel graphics as [z2d](https://github.com/vancluever/z2d) //! surfaces. //! //! Sixel is the bitmap format of DEC's graphics terminals and printers: an //! image sent as printable characters inside a device control string, each //! character six pixels in a column. xterm, foot, WezTerm, Ghostty's //! siblings and a good many others still display it. //! //! ## Reading a stream //! //! `relay` copies a `std.Io.Reader` to a `std.Io.Writer` and takes the sixel //! images out as it goes, handing each to a handler of yours as a surface: //! //! ```zig //! const Handler = struct { //! gpa: std.mem.Allocator, //! pub fn image(self: *Handler, img: sixel.Image) !void { //! var owned = img; //! defer owned.deinit(self.gpa); //! // ... owned.surface is a z2d.Surface ... //! } //! }; //! var handler: Handler = .{ .gpa = gpa }; //! try sixel.relay(gpa, &reader.interface, &writer.interface, &handler, .{}); //! ``` //! //! Everything that is not an image passes through untouched, and as soon as //! it arrives: `relay` writes what it has read before it waits to read more. //! //! ## Reading a slice //! //! ```zig //! var img = try sixel.decode(gpa, bytes, .{}); //! defer img.deinit(gpa); //! ``` //! //! ## Writing //! //! ```zig //! try sixel.encode(gpa, writer, &surface, .{}); // to a std.Io.Writer //! const bytes = try sixel.encodeAlloc(gpa, &surface, .{}); // to memory you own //! const used = try sixel.encodeBuffer(gpa, &buf, &surface, .{}); // to your buffer //! ``` //! //! An image with more colors than registers is reduced to a palette by //! median cut and dithered; one with few enough is written exactly. See //! `quantize`. //! //! ## Sans-I/O //! //! Nothing here opens, reads or writes anything on its own, and nothing takes //! an `Io`. Bytes come in through a `std.Io.Reader` or a slice and go out //! through a `std.Io.Writer` or a slice, and where those lead is the calling //! program's business. Under both read paths is `Parser`, a state machine //! fed bytes in pieces of any size, for anything else that wants to drive a //! decoder. //! //! ## Untrusted input //! //! A sixel stream can claim any size and draw anywhere, so `Limits` bounds //! the canvas a decoder will allocate. What falls outside is dropped and the //! image is marked `clipped`, as a terminal drops what falls off its screen. //! Nothing a stream contains can make a decoder panic or allocate without //! bound. const std = @import("std"); pub const Canvas = @import("Canvas.zig"); pub const Image = @import("Image.zig"); pub const Parser = @import("Parser.zig"); pub const introducer = @import("introducer.zig"); pub const palette = @import("palette.zig"); pub const quantize = @import("quantize.zig"); pub const Limits = Canvas.Limits; pub const Aspect = introducer.Aspect; const decode_ = @import("decode.zig"); pub const decode = decode_.decode; pub const DecodeOptions = decode_.Options; pub const DecodeError = decode_.Error; const relay_ = @import("relay.zig"); pub const relay = relay_.relay; pub const RelayOptions = relay_.Options; pub const RelayError = relay_.Error; pub const min_buffer_len = relay_.min_buffer_len; const encode_ = @import("encode.zig"); pub const encode = encode_.encode; pub const encodeBuffer = encode_.encodeBuffer; pub const encodeAlloc = encode_.encodeAlloc; pub const EncodeOptions = encode_.Options; pub const EncodeError = encode_.Error; pub const Dither = encode_.Dither; test { std.testing.refAllDecls(@This()); _ = decode_; _ = relay_; _ = encode_; }