colorutils_rs/
image_to_linear.rs1use crate::gamma_curves::TransferFunction;
8use crate::image::ImageConfiguration;
9use crate::Rgb;
10#[cfg(feature = "rayon")]
11use rayon::iter::{IndexedParallelIterator, ParallelIterator};
12#[cfg(feature = "rayon")]
13use rayon::prelude::{ParallelSlice, ParallelSliceMut};
14use std::slice;
15
16#[allow(clippy::type_complexity)]
17fn channels_to_linear<const CHANNELS_CONFIGURATION: u8, const USE_ALPHA: bool>(
18 src: &[u8],
19 src_stride: u32,
20 dst: &mut [f32],
21 dst_stride: u32,
22 width: u32,
23 height: u32,
24 transfer_function: TransferFunction,
25) {
26 let image_configuration: ImageConfiguration = CHANNELS_CONFIGURATION.into();
27 if USE_ALPHA && !image_configuration.has_alpha() {
28 panic!("Alpha may be set only on images with alpha");
29 }
30
31 let channels = image_configuration.get_channels_count();
32
33 let mut lut_table = vec![0f32; 256];
34 for (i, lut) in lut_table.iter_mut().enumerate() {
35 *lut = transfer_function.linearize(i as f32 * (1. / 255.0));
36 }
37
38 let dst_slice_safe_align = unsafe {
39 slice::from_raw_parts_mut(
40 dst.as_mut_ptr() as *mut u8,
41 dst_stride as usize * height as usize,
42 )
43 };
44
45 let iter;
46
47 #[cfg(feature = "rayon")]
48 {
49 iter = dst_slice_safe_align
50 .par_chunks_exact_mut(dst_stride as usize)
51 .zip(src.par_chunks_exact(src_stride as usize));
52 }
53
54 #[cfg(not(feature = "rayon"))]
55 {
56 iter = dst_slice_safe_align
57 .chunks_exact_mut(dst_stride as usize)
58 .zip(src.chunks_exact(src_stride as usize));
59 }
60
61 iter.for_each(|(dst_row, src_row)| unsafe {
62 let mut _cx = 0usize;
63
64 let src_ptr = src_row.as_ptr();
65 let dst_ptr = dst_row.as_mut_ptr() as *mut f32;
66
67 for x in _cx..width as usize {
68 let px = x * channels;
69 let dst = dst_ptr.add(px);
70 let src = src_ptr.add(px);
71 let r = src
72 .add(image_configuration.get_r_channel_offset())
73 .read_unaligned();
74 let g = src
75 .add(image_configuration.get_g_channel_offset())
76 .read_unaligned();
77 let b = src
78 .add(image_configuration.get_b_channel_offset())
79 .read_unaligned();
80
81 let rgb = Rgb::<u8>::new(r, g, b);
82
83 dst.add(image_configuration.get_r_channel_offset())
84 .write_unaligned(*lut_table.get_unchecked(rgb.r as usize));
85 dst.add(image_configuration.get_g_channel_offset())
86 .write_unaligned(*lut_table.get_unchecked(rgb.g as usize));
87 dst.add(image_configuration.get_b_channel_offset())
88 .write_unaligned(*lut_table.get_unchecked(rgb.b as usize));
89
90 if USE_ALPHA && image_configuration.has_alpha() {
91 let a = src
92 .add(image_configuration.get_a_channel_offset())
93 .read_unaligned();
94 let a_lin = a as f32 * (1f32 / 255f32);
95 dst.add(image_configuration.get_a_channel_offset())
96 .write_unaligned(a_lin);
97 }
98 }
99 });
100}
101
102pub fn rgb_to_linear(
115 src: &[u8],
116 src_stride: u32,
117 dst: &mut [f32],
118 dst_stride: u32,
119 width: u32,
120 height: u32,
121 transfer_function: TransferFunction,
122) {
123 channels_to_linear::<{ ImageConfiguration::Rgb as u8 }, false>(
124 src,
125 src_stride,
126 dst,
127 dst_stride,
128 width,
129 height,
130 transfer_function,
131 );
132}
133
134pub fn rgba_to_linear(
147 src: &[u8],
148 src_stride: u32,
149 dst: &mut [f32],
150 dst_stride: u32,
151 width: u32,
152 height: u32,
153 transfer_function: TransferFunction,
154) {
155 channels_to_linear::<{ ImageConfiguration::Rgba as u8 }, true>(
156 src,
157 src_stride,
158 dst,
159 dst_stride,
160 width,
161 height,
162 transfer_function,
163 );
164}
165
166pub fn bgra_to_linear(
179 src: &[u8],
180 src_stride: u32,
181 dst: &mut [f32],
182 dst_stride: u32,
183 width: u32,
184 height: u32,
185 transfer_function: TransferFunction,
186) {
187 channels_to_linear::<{ ImageConfiguration::Bgra as u8 }, true>(
188 src,
189 src_stride,
190 dst,
191 dst_stride,
192 width,
193 height,
194 transfer_function,
195 );
196}
197
198pub fn bgr_to_linear(
211 src: &[u8],
212 src_stride: u32,
213 dst: &mut [f32],
214 dst_stride: u32,
215 width: u32,
216 height: u32,
217 transfer_function: TransferFunction,
218) {
219 channels_to_linear::<{ ImageConfiguration::Bgr as u8 }, false>(
220 src,
221 src_stride,
222 dst,
223 dst_stride,
224 width,
225 height,
226 transfer_function,
227 );
228}