feat(image): implement sixel image backend
Swadhin Biswas committed 7 months ago
98b0928
1 parent 60a9dd7
commit 98b0928
1 file changed
+50 -0
Showing 1 changed file+50-0
▼src/image_backend/mod.rs
+50-0
| @@ -148,3 +148,53 @@ fn display_kitty_frame( | ||
148 | 148 | target_w, target_h, more, chunk |
149 | 149 | ) |
150 | 150 | .ok(); |
151 | + } else { | |
152 | + write!(out, "\x1b_Gm={};{}\x1b\\", more, chunk).ok(); | |
153 | + } | |
154 | + } | |
155 | + | |
156 | + let display_w = (target_w as f64 / cell_w).ceil() as usize; | |
157 | + let display_h = (target_h as f64 / cell_h).ceil() as usize; | |
158 | + | |
159 | + Ok((display_w, display_h)) | |
160 | +} | |
161 | + | |
162 | +/// Display an image using the kitty graphics protocol. | |
163 | +/// Returns the dimensions used. | |
164 | +pub fn display_kitty( | |
165 | + image_path: &str, | |
166 | + max_cols: usize, | |
167 | + max_rows: usize, | |
168 | +) -> Result<(usize, usize), String> { | |
169 | + let path = Path::new(image_path); | |
170 | + if !path.exists() { | |
171 | + return Err(format!("Image not found: {}", image_path)); | |
172 | + } | |
173 | + | |
174 | + // Check if it's an animated GIF | |
175 | + if let Ok(frames) = extract_gif_frames(image_path) { | |
176 | + if frames.len() > 1 { | |
177 | + // Display first frame for now (full animation support requires terminal refresh loop) | |
178 | + return display_kitty_frame(&frames[0], max_cols, max_rows); | |
179 | + } | |
180 | + } | |
181 | + | |
182 | + let img = image::open(path).map_err(|e| format!("Failed to open image: {}", e))?; | |
183 | + | |
184 | + // Calculate dimensions — fit within max_cols x max_rows | |
185 | + // Assume ~2:1 character aspect ratio (chars are taller than wide) | |
186 | + let (orig_w, orig_h) = (img.width() as f64, img.height() as f64); | |
187 | + let cell_w = 8.0_f64; // approximate pixel width of a terminal cell | |
188 | + let cell_h = 16.0_f64; // approximate pixel height of a terminal cell | |
189 | + | |
190 | + let max_px_w = max_cols as f64 * cell_w; | |
191 | + let max_px_h = max_rows as f64 * cell_h; | |
192 | + | |
193 | + let scale = (max_px_w / orig_w).min(max_px_h / orig_h).min(1.0); | |
194 | + let target_w = (orig_w * scale) as u32; | |
195 | + let target_h = (orig_h * scale) as u32; | |
196 | + | |
197 | + let resized = img.resize(target_w, target_h, image::imageops::FilterType::Lanczos3); | |
198 | + let rgba = resized.to_rgba8(); | |
199 | + let raw = rgba.as_raw(); | |
200 | + | |
151 | 201 | |