use image::DynamicImage;
use minifb::{Key, Window, WindowOptions};
use crate::error::{InferenceError, Result};
pub struct Viewer {
window: Window,
pub width: usize,
pub height: usize,
buffer: Vec<u32>,
}
impl Viewer {
pub fn new(title: &str, width: usize, height: usize) -> Result<Self> {
let mut window = Window::new(
title,
width,
height,
WindowOptions {
resize: false,
..WindowOptions::default()
},
)
.map_err(|e| InferenceError::VisualizerError(format!("Failed to create window: {e}")))?;
window.set_target_fps(60);
Ok(Self {
window,
width,
height,
buffer: Vec::new(),
})
}
pub fn update(&mut self, image: &DynamicImage) -> Result<bool> {
if !self.window.is_open()
|| self.window.is_key_down(Key::Escape)
|| self.window.is_key_down(Key::Q)
{
return Ok(false);
}
let (img_width, img_height) = (image.width() as usize, image.height() as usize);
let num_pixels = img_width * img_height;
if self.buffer.len() != num_pixels {
self.buffer.resize(num_pixels, 0);
}
let rgb = image.to_rgb8();
for (i, pixel) in rgb.pixels().enumerate() {
let r = u32::from(pixel[0]);
let g = u32::from(pixel[1]);
let b = u32::from(pixel[2]);
self.buffer[i] = (r << 16) | (g << 8) | b;
}
if self.width != img_width || self.height != img_height {
self.width = img_width;
self.height = img_height;
}
self.window
.update_with_buffer(&self.buffer, self.width, self.height)
.map_err(|e| {
InferenceError::VisualizerError(format!("Failed to update window: {e}"))
})?;
Ok(true)
}
pub fn wait(&mut self, duration: std::time::Duration) -> Result<bool> {
if self.buffer.is_empty() {
return Ok(true);
}
let start = std::time::Instant::now();
while start.elapsed() < duration {
if !self.window.is_open()
|| self.window.is_key_down(Key::Escape)
|| self.window.is_key_down(Key::Q)
{
return Ok(false);
}
let _ = self
.window
.update_with_buffer(&self.buffer, self.width, self.height);
}
Ok(true)
}
}