Skip to main content

kitty_graphics_protocol/
image.rs

1//! High-level image display utilities
2
3use crate::command::Command;
4use crate::error::Result;
5use crate::types::{Action, ImageFormat};
6use std::io::Write;
7use std::path::Path;
8
9/// A high-level interface for displaying images in the terminal
10pub struct ImageDisplay {
11    quiet: u8,
12}
13
14impl Default for ImageDisplay {
15    fn default() -> Self {
16        Self::new()
17    }
18}
19
20impl ImageDisplay {
21    /// Create a new ImageDisplay instance
22    pub fn new() -> Self {
23        Self { quiet: 2 }
24    }
25
26    /// Set quiet mode (0 = all responses, 1 = suppress OK, 2 = suppress all)
27    pub fn quiet(mut self, mode: u8) -> Self {
28        self.quiet = mode;
29        self
30    }
31
32    /// Display a PNG image from file
33    pub fn display_png_file<P: AsRef<Path>>(&self, path: P) -> Result<()> {
34        let data = std::fs::read(path)?;
35        self.display_png(&data)
36    }
37
38    /// Display a PNG image from memory
39    pub fn display_png(&self, data: &[u8]) -> Result<()> {
40        let chunks = Command::transmit_png(data)?;
41        let mut stdout = std::io::stdout().lock();
42        for chunk in chunks {
43            stdout.write_all(chunk.as_bytes())?;
44        }
45        stdout.flush()?;
46        Ok(())
47    }
48
49    /// Display raw RGBA data
50    pub fn display_rgba(&self, data: &[u8], width: u32, height: u32) -> Result<()> {
51        let chunks = Command::transmit_rgba(data, width, height)?;
52        let mut stdout = std::io::stdout().lock();
53        for chunk in chunks {
54            stdout.write_all(chunk.as_bytes())?;
55        }
56        stdout.flush()?;
57        Ok(())
58    }
59
60    /// Display raw RGB data
61    pub fn display_rgb(&self, data: &[u8], width: u32, height: u32) -> Result<()> {
62        let chunks = Command::transmit_rgb(data, width, height)?;
63        let mut stdout = std::io::stdout().lock();
64        for chunk in chunks {
65            stdout.write_all(chunk.as_bytes())?;
66        }
67        stdout.flush()?;
68        Ok(())
69    }
70
71    /// Clear all visible images
72    pub fn clear_all(&self) -> Result<()> {
73        let cmd = Command::delete_all();
74        let seq = cmd.serialize(&[])?;
75        let mut stdout = std::io::stdout().lock();
76        stdout.write_all(seq.as_bytes())?;
77        stdout.flush()?;
78        Ok(())
79    }
80
81    /// Transmit an image without displaying it (returns image ID for later use)
82    pub fn transmit_png(&self, data: &[u8], image_id: u32) -> Result<()> {
83        let cmd = Command::builder()
84            .action(Action::Transmit)
85            .format(ImageFormat::Png)
86            .image_id(image_id)
87            .quiet(self.quiet)
88            .build();
89
90        let chunks: Vec<String> = cmd.serialize_chunked(data)?.collect();
91        let mut stdout = std::io::stdout().lock();
92        for chunk in chunks {
93            stdout.write_all(chunk.as_bytes())?;
94        }
95        stdout.flush()?;
96        Ok(())
97    }
98
99    /// Place a previously transmitted image
100    pub fn place_image(&self, image_id: u32, cols: u32, rows: u32) -> Result<()> {
101        let cmd = Command::place(image_id, cols, rows);
102        let seq = cmd.serialize(&[])?;
103        let mut stdout = std::io::stdout().lock();
104        stdout.write_all(seq.as_bytes())?;
105        stdout.flush()?;
106        Ok(())
107    }
108}
109
110/// Quick function to display a PNG file
111pub fn display_png<P: AsRef<Path>>(path: P) -> Result<()> {
112    ImageDisplay::new().display_png_file(path)
113}
114
115/// Quick function to display PNG data from memory
116pub fn display_png_data(data: &[u8]) -> Result<()> {
117    ImageDisplay::new().display_png(data)
118}
119
120/// Quick function to clear all visible images
121pub fn clear_all_images() -> Result<()> {
122    ImageDisplay::new().clear_all()
123}
124
125#[cfg(test)]
126mod tests {
127    use super::*;
128
129    #[test]
130    fn test_image_display_creation() {
131        let display = ImageDisplay::new().quiet(1);
132        assert_eq!(display.quiet, 1);
133    }
134}