ferrite_image/
manager.rs

1use eframe::egui::{self, Context};
2use ferrite_cache::{CacheHandle, CacheResult};
3use ferrite_logging::metrics::PerformanceMetrics;
4use image::{DynamicImage, GenericImageView};
5use std::{path::PathBuf, sync::Arc};
6use tracing::{info, info_span, instrument, warn};
7
8use crate::error::{ImageError, Result};
9
10pub struct ImageManager {
11    pub current_image: Option<Arc<DynamicImage>>,
12    pub texture:       Option<egui::TextureHandle>,
13    pub current_path:  Option<PathBuf>,
14    pub cache_manager: Arc<CacheHandle>,
15}
16
17impl ImageManager {
18    #[instrument(skip_all)]
19    pub fn new(cache_manager: Arc<CacheHandle>) -> Self {
20        info!("Initializing ImageManager with cache");
21        Self {
22            current_image: None,
23            texture: None,
24            current_path: None,
25            cache_manager,
26        }
27    }
28
29    pub fn set_path(&mut self, path: PathBuf) {
30        info!("Setting new image path: {}", path.display());
31        self.current_path = Some(path);
32    }
33
34    #[instrument(skip(self, path), fields(path = ?path))]
35    pub fn load_image(&mut self, path: PathBuf) -> Result<()> {
36        let metrics = PerformanceMetrics::new("image_loading", true);
37
38        let result = info_span!("image_loading_process").in_scope(|| {
39            let get_image: CacheResult<Arc<DynamicImage>> =
40                self.cache_manager.get_image(path.clone());
41
42            if let Ok(image_data) = get_image {
43                let dimensions = image_data.dimensions();
44                info!("Setting new image and clearing texture");
45
46                self.texture = None;
47
48                self.current_image = Some(image_data);
49                self.current_path = Some(path);
50
51                info!(
52                    "Successfully loaded image from cache: dimensions={}x{}",
53                    dimensions.0, dimensions.1
54                );
55                Ok(())
56            } else {
57                Err(ImageError::CacheError(get_image.unwrap_err()))
58            }
59        });
60
61        let duration = metrics.finish();
62        info!("Image loading completed in {} µs", duration.as_micros());
63
64        result
65    }
66
67    pub fn preload_image(&self, path: PathBuf) {
68        if let Err(e) = self.cache_manager.cache_image(path) {
69            warn!("Failed to preload image: {}", e);
70        }
71    }
72
73    pub fn get_current_dimensions(&self) -> Option<(u32, u32)> {
74        self.current_image
75            .as_ref()
76            .map(|img| img.dimensions())
77    }
78
79    #[instrument(skip(self, ctx))]
80    pub fn show_performance_window(&self, ctx: &Context) {
81        egui::Window::new("Performance Metrics").show(ctx, |ui| {
82            ui.heading("Image Information");
83
84            if let Some(ref img) = self.current_image {
85                let dims = img.dimensions();
86                ui.label(format!(
87                    "Current image dimensions: {}x{}",
88                    dims.0, dims.1
89                ));
90            }
91
92            if let Some(path) = &self.current_path {
93                ui.label(format!(
94                    "Current image: {:?}",
95                    path.file_name().unwrap_or_default()
96                ));
97            }
98        });
99    }
100}