|
| 1 | +use { |
| 2 | + image::{imageops::FilterType, DynamicImage, GenericImageView}, |
| 3 | + libc::{ioctl, winsize, STDOUT_FILENO, TIOCGWINSZ}, |
| 4 | + std::env, |
| 5 | +}; |
| 6 | + |
| 7 | +pub struct ITerm2Backend {} |
| 8 | + |
| 9 | +impl ITerm2Backend { |
| 10 | + pub fn new() -> Self { |
| 11 | + Self {} |
| 12 | + } |
| 13 | + |
| 14 | + pub fn supported() -> bool { |
| 15 | + let term_program = env::var("TERM_PROGRAM").unwrap_or("".to_string()); |
| 16 | + term_program == "iTerm.app" |
| 17 | + } |
| 18 | +} |
| 19 | + |
| 20 | +impl super::ImageBackend for ITerm2Backend { |
| 21 | + fn add_image(&self, lines: Vec<String>, image: &DynamicImage, _colors: usize) -> String { |
| 22 | + let tty_size = unsafe { |
| 23 | + let tty_size: winsize = std::mem::zeroed(); |
| 24 | + ioctl(STDOUT_FILENO, TIOCGWINSZ, &tty_size); |
| 25 | + tty_size |
| 26 | + }; |
| 27 | + let width_ratio = f64::from(tty_size.ws_col) / f64::from(tty_size.ws_xpixel); |
| 28 | + let height_ratio = f64::from(tty_size.ws_row) / f64::from(tty_size.ws_ypixel); |
| 29 | + |
| 30 | + // resize image to fit the text height with the Lanczos3 algorithm |
| 31 | + let image = image.resize( |
| 32 | + u32::max_value(), |
| 33 | + (lines.len() as f64 / height_ratio) as u32, |
| 34 | + FilterType::Lanczos3, |
| 35 | + ); |
| 36 | + let _image_columns = width_ratio * f64::from(image.width()); |
| 37 | + let image_rows = height_ratio * f64::from(image.height()); |
| 38 | + |
| 39 | + let mut bytes: Vec<u8> = Vec::new(); |
| 40 | + image |
| 41 | + .write_to(&mut bytes, image::ImageOutputFormat::Png) |
| 42 | + .unwrap(); |
| 43 | + let encoded_image = base64::encode(bytes); |
| 44 | + let mut image_data = Vec::<u8>::new(); |
| 45 | + |
| 46 | + image_data.extend(b"\x1B]1337;File=inline=1:"); |
| 47 | + image_data.extend(encoded_image.bytes()); |
| 48 | + image_data.extend(b"\x07"); |
| 49 | + |
| 50 | + image_data.extend(format!("\x1B[{}A", image_rows as u32 - 1).as_bytes()); // move cursor to start of image |
| 51 | + let mut i = 0; |
| 52 | + for line in &lines { |
| 53 | + image_data.extend(format!("\x1B[s{}\x1B[u\x1B[1B", line).as_bytes()); |
| 54 | + i += 1; |
| 55 | + } |
| 56 | + image_data |
| 57 | + .extend(format!("\n\x1B[{}B", lines.len().max(image_rows as usize) - i).as_bytes()); // move cursor to end of image |
| 58 | + |
| 59 | + String::from_utf8(image_data).unwrap() |
| 60 | + } |
| 61 | +} |
0 commit comments