use std::iter::repeat;
#[inline(always)]
pub(crate) fn expand_packed<F>(buf: &mut [u8], channels: usize, bit_depth: u8, mut func: F)
where
F: FnMut(u8, &mut [u8]),
{
let pixels = buf.len() / channels * bit_depth as usize;
let extra = pixels % 8;
let entries = pixels / 8
+ match extra {
0 => 0,
_ => 1,
};
let mask = ((1u16 << bit_depth) - 1) as u8;
let i = (0..entries)
.rev() .flat_map(|idx|
(0..8/bit_depth).map(|i| i*bit_depth).zip(repeat(idx)))
.skip(extra);
let buf_len = buf.len();
let j_inv = (channels..buf_len).step_by(channels);
for ((shift, i), j_inv) in i.zip(j_inv) {
let j = buf_len - j_inv;
let pixel = (buf[i] & (mask << shift)) >> shift;
func(pixel, &mut buf[j as usize..(j + channels) as usize])
}
}
#[allow(dead_code)]
pub(crate) fn expand_bits(bit_depth: u8, row_size: u32, buf: &[u8]) -> Vec<u8> {
let mask = (1u8 << bit_depth as usize) - 1;
let scaling_factor = 255 / ((1 << bit_depth as usize) - 1);
let bit_width = row_size * u32::from(bit_depth);
let skip = if bit_width % 8 == 0 {
0
} else {
(8 - bit_width % 8) / u32::from(bit_depth)
};
let row_len = row_size + skip;
let mut p = Vec::new();
let mut i = 0;
for v in buf {
for shift_inv in 1..=8 / bit_depth {
let shift = 8 - bit_depth * shift_inv;
if i % (row_len as usize) < (row_size as usize) {
let pixel = (v & mask << shift as usize) >> shift as usize;
p.push(pixel * scaling_factor);
}
i += 1;
}
}
p
}
#[allow(dead_code)]
pub(crate) fn check_dimension_overflow(width: u32, height: u32, bytes_per_pixel: u8) -> bool {
width as u64 * height as u64 > std::u64::MAX / bytes_per_pixel as u64
}
#[allow(dead_code)]
pub(crate) fn vec_copy_to_u8<T>(vec: &[T]) -> Vec<u8>
where
T: bytemuck::Pod,
{
bytemuck::cast_slice(vec).to_owned()
}
#[inline]
pub(crate) fn clamp<N>(a: N, min: N, max: N) -> N
where
N: PartialOrd,
{
if a < min {
min
} else if a > max {
max
} else {
a
}
}
#[cfg(test)]
mod test {
#[test]
fn gray_to_luma8_skip() {
let check = |bit_depth, w, from, to| {
assert_eq!(super::expand_bits(bit_depth, w, from), to);
};
check(
1,
10,
&[0b11110000, 0b11000000, 0b00001111, 0b11000000],
vec![
255, 255, 255, 255, 0, 0, 0, 0, 255, 255, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255,
],
);
check(
2,
5,
&[0b11110000, 0b11000000, 0b00001111, 0b11000000],
vec![255, 255, 0, 0, 255, 0, 0, 255, 255, 255],
);
check(
2,
4,
&[0b11110000, 0b00001111],
vec![255, 255, 0, 0, 0, 0, 255, 255],
);
check(4, 1, &[0b11110011, 0b00001100], vec![255, 0]);
}
}