use super::{IccProfile, RenderingIntent};
#[derive(Debug, Clone, Copy, Default)]
pub struct TransformFlags {
pub black_point_compensation: bool,
}
impl TransformFlags {
pub const fn press_default() -> Self {
Self {
black_point_compensation: true,
}
}
}
pub trait IccBackend {
type SrgbTransform;
type CmykRetarget;
type SrgbToCmykTransform;
fn build_srgb_transform(
profile: &IccProfile,
intent: RenderingIntent,
flags: TransformFlags,
) -> Option<Self::SrgbTransform>;
fn convert_cmyk_pixel(transform: &Self::SrgbTransform, cmyk: [u8; 4]) -> Option<[u8; 3]>;
fn convert_cmyk_buffer(transform: &Self::SrgbTransform, cmyk: &[u8]) -> Option<Vec<u8>>;
fn convert_rgb_buffer(transform: &Self::SrgbTransform, rgb: &[u8]) -> Option<Vec<u8>>;
fn convert_gray_buffer(transform: &Self::SrgbTransform, gray: &[u8]) -> Option<Vec<u8>>;
fn build_cmyk_retarget(
src_profile: &IccProfile,
dst_profile: &IccProfile,
intent: RenderingIntent,
flags: TransformFlags,
) -> Option<Self::CmykRetarget>;
fn retarget_cmyk_pixel(transform: &Self::CmykRetarget, cmyk: [f32; 4]) -> [f32; 4];
fn build_srgb_to_cmyk(
dst_profile: &IccProfile,
intent: RenderingIntent,
flags: TransformFlags,
) -> Option<Self::SrgbToCmykTransform>;
fn convert_srgb_to_cmyk_pixel(transform: &Self::SrgbToCmykTransform, rgb: [f32; 3]) -> [f32; 4];
}
pub struct QcmsBackend;
mod qcms_impl {
use super::*;
pub struct SrgbTransform {
pub(super) inner: qcms::Transform,
pub(super) source_components: u8,
}
pub struct CmykRetarget(pub(super) core::convert::Infallible);
pub struct SrgbToCmykTransform(pub(super) core::convert::Infallible);
fn qcms_intent(intent: RenderingIntent) -> qcms::Intent {
match intent {
RenderingIntent::Perceptual => qcms::Intent::Perceptual,
RenderingIntent::RelativeColorimetric => qcms::Intent::RelativeColorimetric,
RenderingIntent::Saturation => qcms::Intent::Saturation,
RenderingIntent::AbsoluteColorimetric => qcms::Intent::AbsoluteColorimetric,
}
}
impl IccBackend for QcmsBackend {
type SrgbTransform = SrgbTransform;
type CmykRetarget = CmykRetarget;
type SrgbToCmykTransform = SrgbToCmykTransform;
fn build_srgb_transform(
profile: &IccProfile,
intent: RenderingIntent,
_flags: TransformFlags,
) -> Option<Self::SrgbTransform> {
let src = qcms::Profile::new_from_slice(profile.bytes(), false)?;
let dst = qcms::Profile::new_sRGB();
let src_ty = match profile.n_components() {
1 => qcms::DataType::Gray8,
3 => qcms::DataType::RGB8,
4 => qcms::DataType::CMYK,
_ => return None,
};
qcms::Transform::new_to(&src, &dst, src_ty, qcms::DataType::RGB8, qcms_intent(intent)).map(|inner| {
SrgbTransform {
inner,
source_components: profile.n_components(),
}
})
}
fn convert_cmyk_pixel(transform: &Self::SrgbTransform, cmyk: [u8; 4]) -> Option<[u8; 3]> {
if transform.source_components != 4 {
return None;
}
let mut dst = [0u8; 3];
transform.inner.convert(&cmyk, &mut dst);
Some(dst)
}
fn convert_cmyk_buffer(transform: &Self::SrgbTransform, cmyk: &[u8]) -> Option<Vec<u8>> {
if transform.source_components != 4 {
return None;
}
let pixels = cmyk.len() / 4;
let mut out = vec![0u8; pixels * 3];
transform.inner.convert(cmyk, &mut out);
Some(out)
}
fn convert_rgb_buffer(transform: &Self::SrgbTransform, rgb: &[u8]) -> Option<Vec<u8>> {
if transform.source_components != 3 {
return None;
}
let mut out = vec![0u8; rgb.len()];
transform.inner.convert(rgb, &mut out);
Some(out)
}
fn convert_gray_buffer(transform: &Self::SrgbTransform, gray: &[u8]) -> Option<Vec<u8>> {
if transform.source_components != 1 {
return None;
}
let mut out = vec![0u8; gray.len() * 3];
transform.inner.convert(gray, &mut out);
Some(out)
}
fn build_cmyk_retarget(
_src_profile: &IccProfile,
_dst_profile: &IccProfile,
_intent: RenderingIntent,
_flags: TransformFlags,
) -> Option<Self::CmykRetarget> {
None
}
fn retarget_cmyk_pixel(transform: &Self::CmykRetarget, _cmyk: [f32; 4]) -> [f32; 4] {
match transform.0 {}
}
fn build_srgb_to_cmyk(
_dst_profile: &IccProfile,
_intent: RenderingIntent,
_flags: TransformFlags,
) -> Option<Self::SrgbToCmykTransform> {
None
}
fn convert_srgb_to_cmyk_pixel(transform: &Self::SrgbToCmykTransform, _rgb: [f32; 3]) -> [f32; 4] {
match transform.0 {}
}
}
}
pub use qcms_impl::{
CmykRetarget as QcmsCmykRetarget, SrgbToCmykTransform as QcmsSrgbToCmykTransform,
SrgbTransform as QcmsSrgbTransform,
};
pub type ActiveIccBackend = QcmsBackend;
pub const fn active_backend_name() -> &'static str {
"qcms"
}