Spaces:
Sleeping
Sleeping
| 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}; | |
| pub struct RenderContext { | |
| pub scene_id: usize, | |
| pub prompt: String, | |
| pub text_overlay: String, | |
| pub vfx_profile: VfxProfile, | |
| } | |
| 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(()) | |
| } | |
| } | |
| mod tests { | |
| use super::*; | |
| 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); | |
| } | |
| } | |