diff options
Diffstat (limited to 'src/image.zig')
| -rw-r--r-- | src/image.zig | 53 |
1 files changed, 53 insertions, 0 deletions
diff --git a/src/image.zig b/src/image.zig new file mode 100644 index 00000000..a3415019 --- /dev/null +++ b/src/image.zig @@ -0,0 +1,53 @@ +//! Image panes. Decoding is zstbi (C stb_image) to RGBA, downscaled; the kept +//! pixels render as PETSCII glyph art directly into the Surface — or, when the +//! host has kitty graphics (and Petscii isn't toggled), ride the Surface as a +//! pixel attachment the shell transmits/places (tty: vaxis kitty; SDL: blit). +const std = @import("std"); +const zstbi = @import("zstbi"); +const ghostty_vt = @import("ghostty-vt"); +pub const petscii = @import("petscii.zig"); + +/// the terminal's own 16 ANSI colors — what the `terminal` palette mode +/// scores against; cells then paint as indexed colors so the real terminal +/// resolves the RGB +pub fn ansiPalette() [16][3]u8 { + var p: [16][3]u8 = undefined; + for (0..16) |i| { + const c = ghostty_vt.color.default[i]; + p[i] = .{ c.r, c.g, c.b }; + } + return p; +} + +/// cap the longest side before keeping/transmitting: a pane is at most a +/// screenful of cells, multi-thousand-pixel photos waste decode/transmit time +const MAX_DIM: u32 = 1280; + +pub const PaletteMode = enum { commodore, terminal }; + +/// call once at startup / exit (stb_image's allocator shim) +pub fn start(io: std.Io, gpa: std.mem.Allocator) void { + zstbi.init(io, gpa); +} +pub fn stop() void { + zstbi.deinit(); +} + +/// decode + downscale to RGBA, gpa-owned. Returns null on any failure — the +/// pane then simply shows a blank body. +pub fn decode(gpa: std.mem.Allocator, bytes: []const u8) ?struct { rgba: []u8, w: usize, h: usize } { + if (bytes.len == 0) return null; + var img = zstbi.Image.loadFromMemory(bytes, 4) catch return null; // 4 = RGBA + defer img.deinit(); + var scaled: ?zstbi.Image = null; + defer if (scaled) |*s| s.deinit(); + const longest = @max(img.width, img.height); + const src: *const zstbi.Image = if (longest > MAX_DIM) blk: { + const nw = @max(1, img.width * MAX_DIM / longest); + const nh = @max(1, img.height * MAX_DIM / longest); + scaled = img.resize(nw, nh); + break :blk &scaled.?; + } else &img; + const rgba = gpa.dupe(u8, src.data) catch return null; + return .{ .rgba = rgba, .w = src.width, .h = src.height }; +} |
