darkmedia-x-api / engine /src /renderer /postprocessing.rs
cybermedia's picture
Upload folder using huggingface_hub
343eed9 verified
use crate::error::Result;
use image::DynamicImage;
#[derive(Debug, Clone, Copy)]
pub enum ColorGrade {
CinematicDark,
CoolTones,
WarmTones,
Desaturated,
HighContrast,
None,
}
pub struct PostProcessor {
pub color_grade: ColorGrade,
pub contrast: f32,
pub brightness: f32,
pub saturation: f32,
}
impl Default for PostProcessor {
fn default() -> Self {
Self {
color_grade: ColorGrade::CinematicDark,
contrast: 1.1,
brightness: 0.95,
saturation: 1.1,
}
}
}
impl PostProcessor {
pub fn new(color_grade: ColorGrade) -> Self {
Self {
color_grade,
..Default::default()
}
}
/// Appliquer tous les traitements de post-processing
pub fn process(&self, img: DynamicImage) -> Result<DynamicImage> {
let mut result = img;
// 1. Appliquer le grade de couleur
result = self.apply_color_grade(result)?;
// 2. Ajuster contraste/luminosité
result = self.adjust_contrast_brightness(result)?;
// 3. Ajuster saturation
result = self.adjust_saturation(result)?;
Ok(result)
}
fn apply_color_grade(&self, img: DynamicImage) -> Result<DynamicImage> {
match self.color_grade {
ColorGrade::CinematicDark => self.apply_cinematic_dark(img),
ColorGrade::CoolTones => self.apply_cool_tones(img),
ColorGrade::WarmTones => self.apply_warm_tones(img),
ColorGrade::Desaturated => self.apply_desaturated(img),
ColorGrade::HighContrast => self.apply_high_contrast(img),
ColorGrade::None => Ok(img),
}
}
fn apply_cinematic_dark(&self, img: DynamicImage) -> Result<DynamicImage> {
let rgba = img.to_rgba8();
let mut output = rgba.clone();
for pixel in output.pixels_mut() {
let [r, g, b, a] = pixel.0;
// Ajouter une teinte bleuée et assombrir
pixel.0 = [
(r as f32 * 0.95) as u8,
(g as f32 * 0.98) as u8,
(b as f32 * 1.05).min(255.0) as u8,
a,
];
}
Ok(DynamicImage::ImageRgba8(output))
}
fn apply_cool_tones(&self, img: DynamicImage) -> Result<DynamicImage> {
let rgba = img.to_rgba8();
let mut output = rgba.clone();
for pixel in output.pixels_mut() {
let [r, g, b, a] = pixel.0;
pixel.0 = [
(r as f32 * 0.9) as u8,
(g as f32 * 0.98) as u8,
(b as f32 * 1.1).min(255.0) as u8,
a,
];
}
Ok(DynamicImage::ImageRgba8(output))
}
fn apply_warm_tones(&self, img: DynamicImage) -> Result<DynamicImage> {
let rgba = img.to_rgba8();
let mut output = rgba.clone();
for pixel in output.pixels_mut() {
let [r, g, b, a] = pixel.0;
pixel.0 = [
(r as f32 * 1.1).min(255.0) as u8,
(g as f32 * 1.05).min(255.0) as u8,
(b as f32 * 0.9) as u8,
a,
];
}
Ok(DynamicImage::ImageRgba8(output))
}
fn apply_desaturated(&self, img: DynamicImage) -> Result<DynamicImage> {
let rgba = img.to_rgba8();
let mut output = rgba.clone();
for pixel in output.pixels_mut() {
let [r, g, b, a] = pixel.0;
let gray = ((r as f32 + g as f32 + b as f32) / 3.0) as u8;
// 70% saturé = 30% gris
let sat = 0.7;
pixel.0 = [
((r as f32 * sat + gray as f32 * (1.0 - sat)) as u8),
((g as f32 * sat + gray as f32 * (1.0 - sat)) as u8),
((b as f32 * sat + gray as f32 * (1.0 - sat)) as u8),
a,
];
}
Ok(DynamicImage::ImageRgba8(output))
}
fn apply_high_contrast(&self, img: DynamicImage) -> Result<DynamicImage> {
let rgba = img.to_rgba8();
let mut output = rgba.clone();
for pixel in output.pixels_mut() {
let [r, g, b, a] = pixel.0;
// Formule: (val - 128) * 1.5 + 128
let contrast = 1.5;
let offset = 128.0;
pixel.0 = [
((r as f32 - offset) * contrast + offset).clamp(0.0, 255.0) as u8,
((g as f32 - offset) * contrast + offset).clamp(0.0, 255.0) as u8,
((b as f32 - offset) * contrast + offset).clamp(0.0, 255.0) as u8,
a,
];
}
Ok(DynamicImage::ImageRgba8(output))
}
fn adjust_contrast_brightness(&self, img: DynamicImage) -> Result<DynamicImage> {
let rgba = img.to_rgba8();
let mut output = rgba.clone();
for pixel in output.pixels_mut() {
let [r, g, b, a] = pixel.0;
pixel.0 = [
((r as f32 - 128.0) * self.contrast + 128.0 + self.brightness * 255.0)
.clamp(0.0, 255.0) as u8,
((g as f32 - 128.0) * self.contrast + 128.0 + self.brightness * 255.0)
.clamp(0.0, 255.0) as u8,
((b as f32 - 128.0) * self.contrast + 128.0 + self.brightness * 255.0)
.clamp(0.0, 255.0) as u8,
a,
];
}
Ok(DynamicImage::ImageRgba8(output))
}
fn adjust_saturation(&self, img: DynamicImage) -> Result<DynamicImage> {
let rgba = img.to_rgba8();
let mut output = rgba.clone();
for pixel in output.pixels_mut() {
let [r, g, b, a] = pixel.0;
let gray = (r as f32 + g as f32 + b as f32) / 3.0;
pixel.0 = [
(r as f32 + (gray - r as f32) * (1.0 - self.saturation)).clamp(0.0, 255.0) as u8,
(g as f32 + (gray - g as f32) * (1.0 - self.saturation)).clamp(0.0, 255.0) as u8,
(b as f32 + (gray - b as f32) * (1.0 - self.saturation)).clamp(0.0, 255.0) as u8,
a,
];
}
Ok(DynamicImage::ImageRgba8(output))
}
}