feat(image): add kitty chunked image transmission

Swadhin Biswas committed 7 months ago
60a9dd7
1 parent bdb703e
commit 60a9dd7
1 file changed
+50 -0
Showing 1 changed file+50-0
▼src/image_backend/mod.rs
+50-0
98
98
99
99
match image::open(path) {
100
100
Ok(img) => {
101
+ // For now, return single frame (first frame of GIF)
102
+ // Full animation support would require the 'gif' crate
103
+ Ok(vec![img])
104
+ }
105
+ Err(e) => Err(format!("Failed to open GIF: {}", e)),
106
+ }
107
+}
108
+
109
+/// Display a single image frame using kitty graphics protocol
110
+fn display_kitty_frame(
111
+ img: &image::DynamicImage,
112
+ max_cols: usize,
113
+ max_rows: usize,
114
+) -> Result<(usize, usize), String> {
115
+ // Calculate dimensions — fit within max_cols x max_rows
116
+ let (orig_w, orig_h) = (img.width() as f64, img.height() as f64);
117
+ let cell_w = 8.0_f64;
118
+ let cell_h = 16.0_f64;
119
+
120
+ let max_px_w = max_cols as f64 * cell_w;
121
+ let max_px_h = max_rows as f64 * cell_h;
122
+
123
+ let scale = (max_px_w / orig_w).min(max_px_h / orig_h).min(1.0);
124
+ let target_w = (orig_w * scale) as u32;
125
+ let target_h = (orig_h * scale) as u32;
126
+
127
+ let resized = img.resize(target_w, target_h, image::imageops::FilterType::Lanczos3);
128
+ let rgba = resized.to_rgba8();
129
+ let raw = rgba.as_raw();
130
+
131
+ let encoded = base64::engine::general_purpose::STANDARD.encode(raw);
132
+ let stdout = io::stdout();
133
+ let mut out = stdout.lock();
134
+
135
+ let chunk_size = 4096;
136
+ let chunks: Vec<&str> = encoded
137
+ .as_bytes()
138
+ .chunks(chunk_size)
139
+ .map(|c| std::str::from_utf8(c).unwrap_or(""))
140
+ .collect();
141
+
142
+ for (i, chunk) in chunks.iter().enumerate() {
143
+ let more = if i < chunks.len() - 1 { 1 } else { 0 };
144
+ if i == 0 {
145
+ write!(
146
+ out,
147
+ "\x1b_Ga=T,f=32,s={},v={},m={};{}\x1b\\",
148
+ target_w, target_h, more, chunk
149
+ )
150
+ .ok();
101
151