use crate::globals::{ACES_TABLE, DCI_P3_TABLE, REC2020_TABLE, SRGB_TABLE}; use crate::spectra::colorspace::CreateRGBColorSpace; use anyhow::{anyhow, Result}; use shared::core::geometry::Point2f; use shared::core::spectrum::{Spectrum, StandardSpectra}; use shared::spectra::cie::{CIE_D65, CIE_X, CIE_Y, CIE_Z}; use shared::spectra::{DenselySampledSpectrum, DeviceStandardColorSpaces, RGBColorSpace}; use shared::Ptr; use std::sync::{Arc, LazyLock, OnceLock}; pub mod colorspace; pub mod data; pub mod piecewise; pub static CIE_X_DATA: LazyLock = LazyLock::new(|| data::create_cie(&CIE_X)); pub static CIE_Y_DATA: LazyLock = LazyLock::new(|| data::create_cie(&CIE_Y)); pub static CIE_Z_DATA: LazyLock = LazyLock::new(|| data::create_cie(&CIE_Z)); pub static CIE_D65_DATA: LazyLock = LazyLock::new(|| data::create_cie(&CIE_D65)); pub fn cie_x() -> Spectrum { Spectrum::Dense(Ptr::from(&*CIE_X_DATA)) } pub fn cie_y() -> Spectrum { Spectrum::Dense(Ptr::from(&*CIE_Y_DATA)) } pub fn cie_z() -> Spectrum { Spectrum::Dense(Ptr::from(&*CIE_Z_DATA)) } pub fn cie_d65() -> Spectrum { Spectrum::Dense(Ptr::from(&*CIE_D65_DATA)) } pub fn get_spectra_context() -> StandardSpectra { StandardSpectra { x: Ptr::from(&*CIE_X_DATA), y: Ptr::from(&*CIE_Y_DATA), z: Ptr::from(&*CIE_Z_DATA), d65: Ptr::from(&*CIE_D65_DATA), } } static D65_ILLUMINANT: LazyLock = LazyLock::new(|| CIE_D65_DATA.clone()); pub static SRGB: LazyLock> = LazyLock::new(|| { let r = Point2f::new(0.64, 0.33); let g = Point2f::new(0.3, 0.6); let b = Point2f::new(0.15, 0.06); let table_ptr = Ptr::from(&*SRGB_TABLE); let illum_ptr = Ptr::from(&*D65_ILLUMINANT); Arc::new(RGBColorSpace::new(r, g, b, illum_ptr, table_ptr)) }); pub static DCI_P3: LazyLock> = LazyLock::new(|| { let r = Point2f::new(0.680, 0.320); let g = Point2f::new(0.265, 0.690); let b = Point2f::new(0.150, 0.060); let table_ptr = Ptr::from(&*DCI_P3_TABLE); let illum_ptr = Ptr::from(&*D65_ILLUMINANT); Arc::new(RGBColorSpace::new(r, g, b, illum_ptr, table_ptr)) }); pub static REC2020: LazyLock> = LazyLock::new(|| { let r = Point2f::new(0.708, 0.292); let g = Point2f::new(0.170, 0.797); let b = Point2f::new(0.131, 0.046); let table_ptr = Ptr::from(&*REC2020_TABLE); let illum_ptr = Ptr::from(&*D65_ILLUMINANT); Arc::new(RGBColorSpace::new(r, g, b, illum_ptr, table_ptr)) }); pub static ACES: LazyLock> = LazyLock::new(|| { let r = Point2f::new(0.7347, 0.2653); let g = Point2f::new(0.0000, 1.0000); let b = Point2f::new(0.0001, -0.0770); let table_ptr = Ptr::from(&*ACES_TABLE); let illum_ptr = Ptr::from(&*D65_ILLUMINANT); Arc::new(RGBColorSpace::new(r, g, b, illum_ptr, table_ptr)) }); #[derive(Debug, Clone)] pub struct StandardColorSpaces { pub srgb: Arc, pub dci_p3: Arc, pub rec2020: Arc, pub aces2065_1: Arc, } impl StandardColorSpaces { pub fn get_named(&self, name: &str) -> Result> { match name.to_lowercase().as_str() { "srgb" => Ok(self.srgb.clone()), "dci-p3" => Ok(self.dci_p3.clone()), "rec2020" => Ok(self.rec2020.clone()), "aces2065-1" => Ok(self.aces2065_1.clone()), _ => Err(anyhow!("No such spectrum")), } } } pub fn get_colorspace_context() -> StandardColorSpaces { StandardColorSpaces { srgb: SRGB.clone().into(), dci_p3: DCI_P3.clone().into(), rec2020: REC2020.clone().into(), aces2065_1: ACES.clone().into(), } } pub fn get_colorspace_device() -> DeviceStandardColorSpaces { DeviceStandardColorSpaces { srgb: Ptr::from(&**SRGB), dci_p3: Ptr::from(&**DCI_P3), rec2020: Ptr::from(&**REC2020), aces2065_1: Ptr::from(&**ACES), } } pub fn default_colorspace() -> RGBColorSpace { let stdcs = get_colorspace_device(); *stdcs.srgb } pub fn default_colorspace_arc() -> Arc { Arc::new(default_colorspace()) } pub fn default_colorspace_ref() -> &'static RGBColorSpace { static CS: OnceLock = OnceLock::new(); let stdcs = get_colorspace_device(); CS.get_or_init(|| *stdcs.srgb) } pub fn default_illuminant() -> Spectrum { Spectrum::Dense(default_colorspace().illuminant) }