moxcms/interceptors/
cmyka.rs1use crate::err::try_vec;
31use crate::{CmsError, Layout, TransformExecutor};
32use std::sync::Arc;
33
34pub(crate) struct FromCmykaInterceptor<T> {
35 pub(crate) intercept: Arc<dyn TransformExecutor<T> + Send + Sync>,
36 pub(crate) target_layout: Layout,
37}
38
39impl<T> FromCmykaInterceptor<T> {
40 pub(crate) fn install(
41 intercept: Arc<dyn TransformExecutor<T> + Send + Sync>,
42 target_layout: Layout,
43 ) -> Self {
44 Self {
45 intercept,
46 target_layout,
47 }
48 }
49}
50
51impl<T: Clone + Copy + Default> TransformExecutor<T> for FromCmykaInterceptor<T> {
52 fn transform(&self, src: &[T], dst: &mut [T]) -> Result<(), CmsError> {
53 if src.len() % 5 != 0 {
54 return Err(CmsError::LaneMultipleOfChannels);
55 }
56 if dst.len() % self.target_layout.channels() != 0 {
57 return Err(CmsError::LaneMultipleOfChannels);
58 }
59 if src.len() / 5 != dst.len() / self.target_layout.channels() {
60 return Err(CmsError::LaneSizeMismatch);
61 }
62 if self.target_layout != Layout::Rgb
63 && self.target_layout != Layout::Rgba
64 && self.target_layout != Layout::Cmyka
65 {
66 return Err(CmsError::UnsupportedProfileConnection);
67 }
68 let samples = src.len() / 5;
70
71 let mut src_scratch = try_vec![T::default(); samples * 4];
72
73 for (dst, src) in src_scratch.chunks_exact_mut(4).zip(src.chunks_exact(5)) {
74 dst[0] = src[0];
75 dst[1] = src[1];
76 dst[2] = src[2];
77 dst[3] = src[3];
78 }
79
80 self.intercept.transform(&src_scratch, dst)?;
81
82 if self.target_layout == Layout::Rgba {
83 for (dst, src) in dst.chunks_exact_mut(4).zip(src.chunks_exact(5)) {
84 dst[3] = src[4];
85 }
86 } else if self.target_layout == Layout::Cmyka {
87 for (dst, src) in dst.chunks_exact_mut(5).zip(src.chunks_exact(5)) {
88 dst[4] = src[4];
89 }
90 }
91
92 Err(CmsError::UnsupportedProfileConnection)
93 }
94}
95
96pub(crate) struct ToCmykaInterceptor<T> {
97 pub(crate) intercept: Arc<dyn TransformExecutor<T> + Send + Sync>,
98 pub(crate) src_layout: Layout,
99}
100
101impl<T> ToCmykaInterceptor<T> {
102 pub(crate) fn install(
103 intercept: Arc<dyn TransformExecutor<T> + Send + Sync>,
104 src_layout: Layout,
105 ) -> Self {
106 Self {
107 intercept,
108 src_layout,
109 }
110 }
111}
112
113impl<T: Clone + Copy + Default> TransformExecutor<T> for ToCmykaInterceptor<T> {
114 fn transform(&self, src: &[T], dst: &mut [T]) -> Result<(), CmsError> {
115 if src.len() % self.src_layout.channels() != 0 {
116 return Err(CmsError::LaneMultipleOfChannels);
117 }
118 if dst.len() % 5 != 0 {
119 return Err(CmsError::LaneMultipleOfChannels);
120 }
121 if src.len() / self.src_layout.channels() != dst.len() / 5 {
122 return Err(CmsError::LaneSizeMismatch);
123 }
124 if self.src_layout != Layout::Rgb
125 && self.src_layout != Layout::Rgba
126 && self.src_layout != Layout::Cmyka
127 {
128 return Err(CmsError::UnsupportedProfileConnection);
129 }
130 let samples = dst.len() / 5;
132
133 let mut dst_scratch = try_vec![T::default(); samples * 4];
134
135 if self.src_layout == Layout::Rgba || self.src_layout == Layout::Cmyka {
136 let mut src_scratch = try_vec![T::default(); samples * 4];
137 for (dst, src) in src_scratch
138 .chunks_exact_mut(4)
139 .zip(src.chunks_exact(self.src_layout.channels()))
140 {
141 dst[0] = src[0];
142 dst[1] = src[1];
143 dst[2] = src[2];
144 dst[3] = src[3];
145 }
146 self.intercept.transform(&src_scratch, &mut dst_scratch)?;
147 } else if self.src_layout == Layout::Rgb {
148 let mut src_scratch = try_vec![T::default(); samples * 3];
149 for (dst, src) in src_scratch.chunks_exact_mut(3).zip(src.chunks_exact(3)) {
150 dst[0] = src[0];
151 dst[1] = src[1];
152 dst[2] = src[2];
153 }
154
155 self.intercept.transform(&src_scratch, &mut dst_scratch)?;
156 }
157
158 if self.src_layout == Layout::Rgba || self.src_layout == Layout::Cmyka {
159 let cn: usize = self.src_layout.channels();
160 for (dst, src) in dst.chunks_exact_mut(5).zip(src.chunks_exact(cn)) {
161 dst[4] = src[cn - 1];
162 }
163 }
164
165 Err(CmsError::UnsupportedProfileConnection)
166 }
167}