summaryrefslogtreecommitdiff
path: root/src/image.zig
diff options
context:
space:
mode:
authorGabriel Schneider <[email protected]>2026-10-01 00:45:14 -0300
committerGabriel Schneider <[email protected]>2026-10-01 00:53:56 -0300
commit0bb65902ebec104dac954b59f28500812419e1af (patch)
tree1c2d756ce89fcf6059bacf62928804da5585d36b /src/image.zig
parent28c74918cde4092d964daa847c026ed3de282683 (diff)
downloadpardes-0bb65902ebec104dac954b59f28500812419e1af.tar.gz
pardes-0bb65902ebec104dac954b59f28500812419e1af.zip
A terminal's kitty graphics draw as glyph art where pixels cannot, and by choice: Petscii on the pane, TermImages for new ones
Under an outer terminal without kitty graphics a tty pardes cannot pass a terminal pane's images on, so it draws them itself as an image pane's Petscii does: each row of an image is matched to C64-palette glyph art over the cells it covers (GlyphArt.renderRect, the exact-grid half of GlyphArt.render), cached while it is on screen. yazi is still told the kitty protocol works, so it keeps sending its previews. The same art is a choice anywhere: the Petscii builtin now takes a terminal pane too (PaneKind.picture), flipping its images between pixels and glyphs, and a terminal holding images, or drawing them as glyphs by choice, says petscii:on|off in its tag as an image pane does. TermImages real|petscii (default real) is what a new terminal starts with; it is in DumpConfig, /ctl and the reference. Co-Authored-By: Claude Opus 5.5 <[email protected]>
Diffstat (limited to 'src/image.zig')
-rw-r--r--src/image.zig21
1 files changed, 16 insertions, 5 deletions
diff --git a/src/image.zig b/src/image.zig
index 936fe19a..3a3f1932 100644
--- a/src/image.zig
+++ b/src/image.zig
@@ -305,7 +305,6 @@ pub const GlyphArt = struct {
pub fn render(gpa: std.mem.Allocator, rgba: []const u8, iw: usize, ih: usize, max_cols: usize, max_rows: usize, pal: Palette, ascii: bool) !Grid {
if (iw == 0 or ih == 0 or max_cols == 0 or max_rows == 0) return .{ .cells = try gpa.alloc(Cell, 0), .cols = 0, .rows = 0 };
- const gset: []const Glyph = if (ascii) &glyphs_ascii else &glyphs;
// contain-fit; cells are ~twice as tall as wide, so a row spans 2 width-units.
var cols = max_cols;
var rows = (max_cols * ih) / (2 * iw);
@@ -315,16 +314,28 @@ pub const GlyphArt = struct {
}
cols = std.math.clamp(cols, 1, max_cols);
rows = std.math.clamp(rows, 1, max_rows);
+ return renderRect(gpa, rgba, iw, ih, .{ .w = @intCast(iw), .h = @intCast(ih) }, cols, rows, pal, ascii);
+ }
+ /// The pixels of `src` (a rectangle of the `iw` x `ih` image) laid
+ /// over exactly `cols` x `rows` cells, whatever their shape: a
+ /// terminal's image fragment is already the size its cells are.
+ pub fn renderRect(gpa: std.mem.Allocator, rgba: []const u8, iw: usize, ih: usize, src: PixelRect, cols: usize, rows: usize, pal: Palette, ascii: bool) !Grid {
+ const x0: usize = @min(src.x, iw);
+ const y0: usize = @min(src.y, ih);
+ const sw: usize = @min(src.w, iw - x0);
+ const sh: usize = @min(src.h, ih - y0);
+ if (sw == 0 or sh == 0 or cols == 0 or rows == 0) return .{ .cells = try gpa.alloc(Cell, 0), .cols = 0, .rows = 0 };
+ const gset: []const Glyph = if (ascii) &glyphs_ascii else &glyphs;
const cells = try gpa.alloc(Cell, cols * rows);
var cy: usize = 0;
while (cy < rows) : (cy += 1) {
- const ry0 = cy * ih / rows;
- const ry1 = @max(ry0 + 1, (cy + 1) * ih / rows);
+ const ry0 = y0 + cy * sh / rows;
+ const ry1 = @max(ry0 + 1, y0 + (cy + 1) * sh / rows);
var cx: usize = 0;
while (cx < cols) : (cx += 1) {
- const rx0 = cx * iw / cols;
- const rx1 = @max(rx0 + 1, (cx + 1) * iw / cols);
+ const rx0 = x0 + cx * sw / cols;
+ const rx1 = @max(rx0 + 1, x0 + (cx + 1) * sw / cols);
var cell: [64][3]u8 = undefined;
var sy: usize = 0;
while (sy < 8) : (sy += 1) {