1use std::collections::TryReserveError;
4use std::iter::repeat;
5
6#[inline(always)]
7pub(crate) fn expand_packed<F>(buf: &mut [u8], channels: usize, bit_depth: u8, mut func: F)
8where
9 F: FnMut(u8, &mut [u8]),
10{
11 let pixels = buf.len() / channels * bit_depth as usize;
12 let extra = pixels % 8;
13 let entries = pixels / 8
14 + match extra {
15 0 => 0,
16 _ => 1,
17 };
18 let mask = ((1u16 << bit_depth) - 1) as u8;
19 let i = (0..entries)
20 .rev() .flat_map(|idx|
22 (0..8/bit_depth).map(|i| i*bit_depth).zip(repeat(idx)))
24 .skip(extra);
25 let buf_len = buf.len();
26 let j_inv = (channels..buf_len).step_by(channels);
27 for ((shift, i), j_inv) in i.zip(j_inv) {
28 let j = buf_len - j_inv;
29 let pixel = (buf[i] & (mask << shift)) >> shift;
30 func(pixel, &mut buf[j..(j + channels)]);
31 }
32}
33
34#[allow(dead_code)]
37pub(crate) fn expand_bits(bit_depth: u8, row_size: u32, buf: &[u8]) -> Vec<u8> {
39 let mask = (1u8 << bit_depth as usize) - 1;
41 let scaling_factor = 255 / ((1 << bit_depth as usize) - 1);
42 let bit_width = row_size * u32::from(bit_depth);
43 let skip = if bit_width.is_multiple_of(8) {
44 0
45 } else {
46 (8 - bit_width % 8) / u32::from(bit_depth)
47 };
48 let row_len = row_size + skip;
49 let mut p = Vec::new();
50 let mut i = 0;
51 for v in buf {
52 for shift_inv in 1..=8 / bit_depth {
53 let shift = 8 - bit_depth * shift_inv;
54 if i % (row_len as usize) < (row_size as usize) {
57 let pixel = (v & (mask << shift as usize)) >> shift as usize;
58 p.push(pixel * scaling_factor);
59 }
60 i += 1;
61 }
62 }
63 p
64}
65
66#[inline(always)]
67pub(crate) fn interleave_planes(out: &mut [u8], color: crate::ColorType, planes: &[&[u8]]) {
68 #[track_caller]
69 pub(crate) fn trampoline<const PLANES: usize, const N: usize>(
70 out: &mut [u8],
71 planes: &[&[u8]],
72 ) {
73 interleave_planes_inner::<PLANES, N>(
74 out.as_chunks_mut::<N>().0,
75 <[_; PLANES]>::try_from(planes)
76 .unwrap()
77 .map(|arr| arr.as_chunks::<N>().0),
78 )
79 }
80
81 assert_eq!(planes.len(), usize::from(color.channel_count()));
82
83 match color {
84 crate::ColorType::L8 => trampoline::<1, 1>(out, planes),
85 crate::ColorType::La8 => trampoline::<2, 1>(out, planes),
86 crate::ColorType::Rgb8 => trampoline::<3, 1>(out, planes),
87 crate::ColorType::Rgba8 => trampoline::<4, 1>(out, planes),
88 crate::ColorType::L16 => trampoline::<1, 2>(out, planes),
89 crate::ColorType::La16 => trampoline::<2, 2>(out, planes),
90 crate::ColorType::Rgb16 => trampoline::<3, 2>(out, planes),
91 crate::ColorType::Rgba16 => trampoline::<4, 2>(out, planes),
92 crate::ColorType::Rgb32F => trampoline::<3, 4>(out, planes),
93 crate::ColorType::Rgba32F => trampoline::<4, 4>(out, planes),
94 }
95}
96
97#[inline(always)]
98fn interleave_planes_inner<const PLANES: usize, const N: usize>(
99 out: &mut [[u8; N]],
100 planes: [&[[u8; N]]; PLANES],
101) {
102 let mut iters = planes.map(|plane| plane.iter().copied());
103 for out in out.as_chunks_mut::<PLANES>().0 {
104 let vals = iters.each_mut().map(Iterator::next);
105
106 for i in 0..PLANES {
108 out[i] = vals[i].unwrap_or(out[i]);
109 }
110 }
111}
112
113#[allow(dead_code)]
115pub(crate) fn check_dimension_overflow(width: u32, height: u32, bytes_per_pixel: u8) -> bool {
117 u64::from(width) * u64::from(height) > u64::MAX / u64::from(bytes_per_pixel)
118}
119
120#[allow(dead_code)]
121pub(crate) fn vec_copy_to_u8<T>(vec: &[T]) -> Vec<u8>
123where
124 T: bytemuck::Pod,
125{
126 bytemuck::cast_slice(vec).to_owned()
127}
128
129#[inline]
130pub(crate) fn clamp<N>(a: N, min: N, max: N) -> N
131where
132 N: PartialOrd,
133{
134 if a < min {
135 min
136 } else if a > max {
137 max
138 } else {
139 a
140 }
141}
142
143#[inline]
144pub(crate) fn vec_try_with_capacity<T>(capacity: usize) -> Result<Vec<T>, TryReserveError> {
145 let mut vec = Vec::new();
146 vec.try_reserve_exact(capacity)?;
147 Ok(vec)
148}
149
150#[cfg(test)]
151mod test {
152 #[test]
153 fn gray_to_luma8_skip() {
154 let check = |bit_depth, w, from, to| {
155 assert_eq!(super::expand_bits(bit_depth, w, from), to);
156 };
157 check(
159 1,
160 10,
161 &[0b11110000, 0b11000000, 0b00001111, 0b11000000],
162 vec![
163 255, 255, 255, 255, 0, 0, 0, 0, 255, 255, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255,
164 ],
165 );
166 check(
168 2,
169 5,
170 &[0b11110000, 0b11000000, 0b00001111, 0b11000000],
171 vec![255, 255, 0, 0, 255, 0, 0, 255, 255, 255],
172 );
173 check(
175 2,
176 4,
177 &[0b11110000, 0b00001111],
178 vec![255, 255, 0, 0, 0, 0, 255, 255],
179 );
180 check(4, 1, &[0b11110011, 0b00001100], vec![255, 0]);
182 }
183}