pub mod image_processor; pub mod vfx; pub mod depth; pub mod animation; pub mod postprocessing; use crate::error::Result; use std::path::{Path, PathBuf}; #[derive(Debug, Clone)] pub struct RenderContext { pub scene_id: usize, pub prompt: String, pub text_overlay: String, pub vfx_profile: VfxProfile, } #[derive(Debug, Clone, Copy, PartialEq)] pub enum VfxProfile { Grain, Blur, Glitch, Vignette, CinematicDark, None, } impl VfxProfile { pub fn from_env_string(s: &str) -> Self { match s.to_lowercase().as_str() { "blur" => Self::Blur, "glitch" => Self::Glitch, "vignette" => Self::Vignette, "cinematic_dark" => Self::CinematicDark, "none" => Self::None, _ => Self::Grain, } } pub fn as_str(&self) -> &'static str { match self { Self::Blur => "blur", Self::Glitch => "glitch", Self::Vignette => "vignette", Self::CinematicDark => "cinematic_dark", Self::None => "none", Self::Grain => "grain", } } } pub struct Renderer { pub base_dir: PathBuf, pub vfx_profile: VfxProfile, } impl Renderer { pub fn new(base_dir: PathBuf, vfx_profile: VfxProfile) -> Self { Self { base_dir, vfx_profile } } /// Rendre une image avec texte overlay et effets VFX pub async fn render_image( &self, input_image: &Path, output_image: &Path, text_overlay: &str, _scene_id: usize, ) -> Result<()> { // 1. Charger l'image let mut image = image_processor::load_image(input_image)?; // 2. Appliquer les VFX image = vfx::apply_vfx(image, self.vfx_profile)?; // 3. Ajouter le texte overlay if !text_overlay.is_empty() { image = image_processor::render_text_overlay(image, text_overlay)?; } // 4. Sauvegarder image_processor::save_image(&image, output_image)?; Ok(()) } /// Générer une depth map pour le zoom 3D pub async fn generate_depth_map(&self, image_path: &Path, depth_path: &Path) -> Result<()> { depth::generate_depth_anything(image_path, depth_path).await } /// Rendre une scène complète (image + depth + overlay) pub async fn render_scene( &self, source_image: &Path, scene_id: usize, text_overlay: &str, output_dir: &Path, ) -> Result<()> { let img_file = output_dir.join(format!("scene_{}.png", scene_id)); let depth_file = output_dir.join("..").join("depths").join(format!("scene_{}.png", scene_id)); // Rendre l'image avec texte et VFX self.render_image(source_image, &img_file, text_overlay, scene_id).await?; // Générer la depth map (optionnel, non-bloquant) if let Err(e) = self.generate_depth_map(&img_file, &depth_file).await { eprintln!(" ⚠️ Depth map non disponible: {}", e); } Ok(()) } } #[cfg(test)] mod tests { use super::*; #[test] fn test_vfx_profile_parsing() { assert_eq!(matches!(VfxProfile::from_env_string("grain"), VfxProfile::Grain), true); assert_eq!(matches!(VfxProfile::from_env_string("blur"), VfxProfile::Blur), true); assert_eq!(matches!(VfxProfile::from_env_string("glitch"), VfxProfile::Glitch), true); assert_eq!(matches!(VfxProfile::from_env_string("unknown"), VfxProfile::Grain), true); } }