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,3 +198,63 @@ pub fn display_kitty( | ||
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 | |