feat(image): implement chafa image backend

Swadhin Biswas committed 7 months ago
982fffd
1 parent 98b0928
commit 982fffd
1 file changed
+60 -0
Showing 1 changed file+60-0
▼src/image_backend/mod.rs
+60-0
198
198
let rgba = resized.to_rgba8();
199
199
let raw = rgba.as_raw();
200
200
201
+ // Kitty graphics protocol: transmit in chunks
202
+ // Format: \x1b_Ga=T,f=32,s=<width>,v=<height>,m=1;<base64>\x1b\\
203
+ let encoded = base64::engine::general_purpose::STANDARD.encode(raw);
204
+
205
+ let stdout = io::stdout();
206
+ let mut out = stdout.lock();
207
+
208
+ let chunk_size = 4096;
209
+ let chunks: Vec<&str> = encoded
210
+ .as_bytes()
211
+ .chunks(chunk_size)
212
+ .map(|c| std::str::from_utf8(c).unwrap_or(""))
213
+ .collect();
214
+
215
+ for (i, chunk) in chunks.iter().enumerate() {
216
+ let more = if i < chunks.len() - 1 { 1 } else { 0 };
217
+ if i == 0 {
218
+ write!(
219
+ out,
220
+ "\x1b_Ga=T,f=32,s={},v={},m={};{}\x1b\\",
221
+ resized.width(),
222
+ resized.height(),
223
+ more,
224
+ chunk
225
+ )
226
+ .ok();
227
+ } else {
228
+ write!(out, "\x1b_Gm={};{}\x1b\\", more, chunk).ok();
229
+ }
230
+ }
231
+ out.flush().ok();
232
+
233
+ // Return how many terminal cells the image occupies
234
+ let cols_used = (resized.width() as f64 / cell_w).ceil() as usize;
235
+ let rows_used = (resized.height() as f64 / cell_h).ceil() as usize;
236
+
237
+ Ok((cols_used, rows_used))
238
+}
239
+
240
+/// Display an image using chafa (converts to text-based art).
241
+/// Returns the rendered lines.
242
+pub fn display_chafa(
243
+ image_path: &str,
244
+ max_cols: usize,
245
+ max_rows: usize,
246
+) -> Result<Vec<String>, String> {
247
+ let path = Path::new(image_path);
248
+ if !path.exists() {
249
+ return Err(format!("Image not found: {}", image_path));
250
+ }
251
+
252
+ let output = Command::new("chafa")
253
+ .args([
254
+ "--size",
255
+ &format!("{}x{}", max_cols, max_rows),
256
+ "--animate",
257
+ "off",
258
+ image_path,
259
+ ])
260
+ .output()
201
261