use super::*;
use crate::context::Context;
use std::os::raw::c_void;
use std::marker::PhantomData;
pub struct Transform<InputPixelFormat, OutputPixelFormat, Context = GlobalContext, Flags = AllowCache> {
pub(crate) handle: ffi::HTRANSFORM,
_from: PhantomData<InputPixelFormat>,
_to: PhantomData<OutputPixelFormat>,
_context_ref: PhantomData<Context>,
_flags_ref: PhantomData<Flags>,
}
unsafe impl<'a, F, T, C: Send, Z> Send for Transform<F, T, C, Z> {}
unsafe impl<'a, F, T, C: Send> Sync for Transform<F, T, C, DisallowCache> {}
impl<InputPixelFormat: Copy + Clone, OutputPixelFormat: Copy + Clone> Transform<InputPixelFormat, OutputPixelFormat, GlobalContext, AllowCache> {
#[inline]
pub fn new(input: &Profile,
in_format: PixelFormat,
output: &Profile,
out_format: PixelFormat,
intent: Intent) -> LCMSResult<Self> {
Self::new_flags(input, in_format, output, out_format, intent, Flags::default())
}
#[inline]
pub fn new_flags<Fl: CacheFlag>(input: &Profile,
in_format: PixelFormat,
output: &Profile,
out_format: PixelFormat,
intent: Intent,
flags: Flags<Fl>)
-> LCMSResult<Self> {
Self::new_flags_context(GlobalContext::new(), input, in_format, output, out_format, intent, flags.allow_cache())
}
#[inline]
pub fn new_proofing(input: &Profile, in_format: PixelFormat,
output: &Profile, out_format: PixelFormat,
proofing: &Profile, intent: Intent, proofng_intent: Intent,
flags: Flags)
-> LCMSResult<Self> {
Self::new_proofing_context(GlobalContext::new(), input, in_format, output, out_format, proofing, intent, proofng_intent, flags)
}
#[inline]
pub fn new_multiprofile(profiles: &[&Profile], in_format: PixelFormat, out_format: PixelFormat, intent: Intent, flags: Flags) -> LCMSResult<Self> {
Self::new_multiprofile_context(GlobalContext::new(), profiles, in_format, out_format, intent, flags)
}
}
impl<PixelFormat: Copy + Clone, Ctx: Context, C> Transform<PixelFormat, PixelFormat, Ctx, C> {
#[inline]
pub fn transform_in_place(&self, srcdst: &mut [PixelFormat]) {
let size = srcdst.len();
assert!(size < std::u32::MAX as usize);
unsafe {
ffi::cmsDoTransform(self.handle,
srcdst.as_ptr() as *const c_void,
srcdst.as_ptr() as *mut c_void,
size as u32);
}
}
}
impl<InputPixelFormat: Copy + Clone, OutputPixelFormat: Copy + Clone, Ctx: Context> Transform<InputPixelFormat, OutputPixelFormat, Ctx, AllowCache> {
#[inline]
pub fn new_context(context: impl AsRef<Ctx>, input: &Profile<Ctx>, in_format: PixelFormat,
output: &Profile<Ctx>, out_format: PixelFormat, intent: Intent) -> LCMSResult<Self> {
Self::new_flags_context(context, input, in_format, output, out_format, intent, Flags::default())
}
}
impl<InputPixelFormat: Copy + Clone, OutputPixelFormat: Copy + Clone, Ctx: Context, Fl: CacheFlag> Transform<InputPixelFormat, OutputPixelFormat, Ctx, Fl> {
#[inline]
fn new_handle(handle: ffi::HTRANSFORM, in_format: PixelFormat, out_format: PixelFormat) -> LCMSResult<Self> {
if handle.is_null() {
Err(Error::ObjectCreationError)
} else {
Ok(Transform {
handle,
_from: Self::check_format::<InputPixelFormat>(in_format, true),
_to: Self::check_format::<OutputPixelFormat>(out_format, false),
_context_ref: PhantomData,
_flags_ref: PhantomData,
})
}
}
#[inline]
fn check_format<Z>(format: PixelFormat, input: bool) -> PhantomData<Z> {
assert!(!format.planar(), "Planar not supported");
assert_eq!(format.bytes_per_pixel(),
std::mem::size_of::<Z>(),
"PixelFormat {:?} has {} bytes per pixel, but the {} format has {}",
format,
format.bytes_per_pixel(),
if input {"input"} else {"output"},
std::mem::size_of::<Z>());
PhantomData
}
pub fn transform_pixels(&self, src: &[InputPixelFormat], dst: &mut [OutputPixelFormat]) {
let size = src.len();
assert_eq!(size, dst.len());
assert!(size < std::u32::MAX as usize);
unsafe {
ffi::cmsDoTransform(self.handle,
src.as_ptr() as *const c_void,
dst.as_ptr() as *mut c_void,
size as u32);
}
}
#[inline]
pub fn input_format(&self) -> PixelFormat {
unsafe { ffi::cmsGetTransformInputFormat(self.handle) as PixelFormat }
}
#[inline]
pub fn output_format(&self) -> PixelFormat {
unsafe { ffi::cmsGetTransformOutputFormat(self.handle) as PixelFormat }
}
#[inline]
pub fn new_flags_context(context: impl AsRef<Ctx>, input: &Profile<Ctx>, in_format: PixelFormat,
output: &Profile<Ctx>, out_format: PixelFormat,
intent: Intent, flags: Flags<Fl>)
-> LCMSResult<Self> {
Self::new_handle(unsafe {
ffi::cmsCreateTransformTHR(context.as_ref().as_ptr(),
input.handle, in_format,
output.handle, out_format,
intent, flags.bits())
},
in_format, out_format)
}
#[inline]
pub fn new_proofing_context(context: impl AsRef<Ctx>, input: &Profile<Ctx>, in_format: PixelFormat,
output: &Profile<Ctx>, out_format: PixelFormat,
proofing: &Profile<Ctx>, intent: Intent, proofng_intent: Intent,
flags: Flags<Fl>)
-> LCMSResult<Self> {
Self::new_handle(unsafe {
ffi::cmsCreateProofingTransformTHR(context.as_ref().as_ptr(), input.handle, in_format,
output.handle, out_format,
proofing.handle, intent, proofng_intent, flags.bits())
},
in_format, out_format)
}
#[inline]
fn new_multiprofile_context(context: impl AsRef<Ctx>, profiles: &[&Profile],
in_format: PixelFormat, out_format: PixelFormat, intent: Intent, flags: Flags<Fl>) -> LCMSResult<Self> {
let mut handles: Vec<_> = profiles.iter().map(|p| p.handle).collect();
unsafe {
Self::new_handle(
ffi::cmsCreateMultiprofileTransformTHR(context.as_ref().as_ptr(), handles.as_mut_ptr(), handles.len() as u32, in_format, out_format, intent, flags.bits()),
in_format,
out_format,
)
}
}
}
impl<InputPixelFormat: Copy + Clone, OutputPixelFormat: Copy + Clone, C> Transform<InputPixelFormat, OutputPixelFormat, GlobalContext, C> {
#[inline]
pub fn global_adaptation_state() -> f64 {
unsafe { ffi::cmsSetAdaptationState(-1.) }
}
#[deprecated(note = "Use `ThreadContext::set_adaptation_state()`")]
pub fn set_global_adaptation_state(value: f64) {
unsafe {
ffi::cmsSetAdaptationState(value);
}
}
#[deprecated(note = "Use `ThreadContext::set_alarm_codes()`")]
pub fn set_global_alarm_codes(codes: [u16; ffi::MAXCHANNELS]) {
unsafe { ffi::cmsSetAlarmCodes(codes.as_ptr()) }
}
pub fn global_alarm_codes() -> [u16; ffi::MAXCHANNELS] {
let mut tmp = [0u16; ffi::MAXCHANNELS];
unsafe {
ffi::cmsGetAlarmCodes(tmp.as_mut_ptr());
}
tmp
}
}
impl<F, T, C, L> Drop for Transform<F, T, C, L> {
fn drop(&mut self) {
unsafe {
ffi::cmsDeleteTransform(self.handle);
}
}
}