diff options
Diffstat (limited to 'vendor/png/src/utils.rs')
-rw-r--r-- | vendor/png/src/utils.rs | 463 |
1 files changed, 0 insertions, 463 deletions
diff --git a/vendor/png/src/utils.rs b/vendor/png/src/utils.rs deleted file mode 100644 index d43753b..0000000 --- a/vendor/png/src/utils.rs +++ /dev/null @@ -1,463 +0,0 @@ -//! Utility functions -use std::iter::{repeat, StepBy}; -use std::ops::Range; - -#[inline(always)] -pub fn unpack_bits<F>(buf: &mut [u8], channels: usize, bit_depth: u8, func: F) -where - F: Fn(u8, &mut [u8]), -{ - // Return early if empty. This enables to subtract `channels` later without overflow. - if buf.len() < channels { - return; - } - - let bits = buf.len() / channels * bit_depth as usize; - let extra_bits = bits % 8; - let entries = bits / 8 - + match extra_bits { - 0 => 0, - _ => 1, - }; - let skip = match extra_bits { - 0 => 0, - n => (8 - n) / bit_depth as usize, - }; - let mask = ((1u16 << bit_depth) - 1) as u8; - let i = (0..entries) - .rev() // reverse iterator - .flat_map(|idx| - // this has to be reversed too - (0..8).step_by(bit_depth.into()) - .zip(repeat(idx))) - .skip(skip); - let j = (0..=buf.len() - channels).rev().step_by(channels); - for ((shift, i), j) in i.zip(j) { - let pixel = (buf[i] & (mask << shift)) >> shift; - func(pixel, &mut buf[j..(j + channels)]) - } -} - -pub fn expand_trns_line(input: &[u8], output: &mut [u8], trns: Option<&[u8]>, channels: usize) { - for (input, output) in input - .chunks_exact(channels) - .zip(output.chunks_exact_mut(channels + 1)) - { - output[..channels].copy_from_slice(input); - output[channels] = if Some(input) == trns { 0 } else { 0xFF }; - } -} - -pub fn expand_trns_line16(input: &[u8], output: &mut [u8], trns: Option<&[u8]>, channels: usize) { - for (input, output) in input - .chunks_exact(channels * 2) - .zip(output.chunks_exact_mut(channels * 2 + 2)) - { - output[..channels * 2].copy_from_slice(input); - if Some(input) == trns { - output[channels * 2] = 0; - output[channels * 2 + 1] = 0 - } else { - output[channels * 2] = 0xFF; - output[channels * 2 + 1] = 0xFF - }; - } -} - -pub fn expand_trns_and_strip_line16( - input: &[u8], - output: &mut [u8], - trns: Option<&[u8]>, - channels: usize, -) { - for (input, output) in input - .chunks_exact(channels * 2) - .zip(output.chunks_exact_mut(channels + 1)) - { - for i in 0..channels { - output[i] = input[i * 2]; - } - output[channels] = if Some(input) == trns { 0 } else { 0xFF }; - } -} - -/// This iterator iterates over the different passes of an image Adam7 encoded -/// PNG image -/// The pattern is: -/// 16462646 -/// 77777777 -/// 56565656 -/// 77777777 -/// 36463646 -/// 77777777 -/// 56565656 -/// 77777777 -/// -#[derive(Clone)] -pub(crate) struct Adam7Iterator { - line: u32, - lines: u32, - line_width: u32, - current_pass: u8, - width: u32, - height: u32, -} - -impl Adam7Iterator { - pub fn new(width: u32, height: u32) -> Adam7Iterator { - let mut this = Adam7Iterator { - line: 0, - lines: 0, - line_width: 0, - current_pass: 1, - width, - height, - }; - this.init_pass(); - this - } - - /// Calculates the bounds of the current pass - fn init_pass(&mut self) { - let w = f64::from(self.width); - let h = f64::from(self.height); - let (line_width, lines) = match self.current_pass { - 1 => (w / 8.0, h / 8.0), - 2 => ((w - 4.0) / 8.0, h / 8.0), - 3 => (w / 4.0, (h - 4.0) / 8.0), - 4 => ((w - 2.0) / 4.0, h / 4.0), - 5 => (w / 2.0, (h - 2.0) / 4.0), - 6 => ((w - 1.0) / 2.0, h / 2.0), - 7 => (w, (h - 1.0) / 2.0), - _ => unreachable!(), - }; - self.line_width = line_width.ceil() as u32; - self.lines = lines.ceil() as u32; - self.line = 0; - } - - /// The current pass#. - pub fn current_pass(&self) -> u8 { - self.current_pass - } -} - -/// Iterates over the (passes, lines, widths) -impl Iterator for Adam7Iterator { - type Item = (u8, u32, u32); - fn next(&mut self) -> Option<Self::Item> { - if self.line < self.lines && self.line_width > 0 { - let this_line = self.line; - self.line += 1; - Some((self.current_pass, this_line, self.line_width)) - } else if self.current_pass < 7 { - self.current_pass += 1; - self.init_pass(); - self.next() - } else { - None - } - } -} - -fn subbyte_pixels(scanline: &[u8], bits_pp: usize) -> impl Iterator<Item = u8> + '_ { - (0..scanline.len() * 8) - .step_by(bits_pp) - .map(move |bit_idx| { - let byte_idx = bit_idx / 8; - - // sub-byte samples start in the high-order bits - let rem = 8 - bit_idx % 8 - bits_pp; - - match bits_pp { - // evenly divides bytes - 1 => (scanline[byte_idx] >> rem) & 1, - 2 => (scanline[byte_idx] >> rem) & 3, - 4 => (scanline[byte_idx] >> rem) & 15, - _ => unreachable!(), - } - }) -} - -/// Given pass, image width, and line number, produce an iterator of bit positions of pixels to copy -/// from the input scanline to the image buffer. -fn expand_adam7_bits( - pass: u8, - width: usize, - line_no: usize, - bits_pp: usize, -) -> StepBy<Range<usize>> { - let (line_mul, line_off, samp_mul, samp_off) = match pass { - 1 => (8, 0, 8, 0), - 2 => (8, 0, 8, 4), - 3 => (8, 4, 4, 0), - 4 => (4, 0, 4, 2), - 5 => (4, 2, 2, 0), - 6 => (2, 0, 2, 1), - 7 => (2, 1, 1, 0), - _ => panic!("Adam7 pass out of range: {}", pass), - }; - - // the equivalent line number in progressive scan - let prog_line = line_mul * line_no + line_off; - // line width is rounded up to the next byte - let line_width = (width * bits_pp + 7) & !7; - let line_start = prog_line * line_width; - let start = line_start + (samp_off * bits_pp); - let stop = line_start + (width * bits_pp); - - (start..stop).step_by(bits_pp * samp_mul) -} - -/// Expands an Adam 7 pass -pub fn expand_pass( - img: &mut [u8], - width: u32, - scanline: &[u8], - pass: u8, - line_no: u32, - bits_pp: u8, -) { - let width = width as usize; - let line_no = line_no as usize; - let bits_pp = bits_pp as usize; - - // pass is out of range but don't blow up - if pass == 0 || pass > 7 { - return; - } - - let bit_indices = expand_adam7_bits(pass, width, line_no, bits_pp); - - if bits_pp < 8 { - for (pos, px) in bit_indices.zip(subbyte_pixels(scanline, bits_pp)) { - let rem = 8 - pos % 8 - bits_pp; - img[pos / 8] |= px << rem as u8; - } - } else { - let bytes_pp = bits_pp / 8; - - for (bitpos, px) in bit_indices.zip(scanline.chunks(bytes_pp)) { - for (offset, val) in px.iter().enumerate() { - img[bitpos / 8 + offset] = *val; - } - } - } -} - -#[test] -fn test_adam7() { - /* - 1646 - 7777 - 5656 - 7777 - */ - let it = Adam7Iterator::new(4, 4); - let passes: Vec<_> = it.collect(); - assert_eq!( - &*passes, - &[ - (1, 0, 1), - (4, 0, 1), - (5, 0, 2), - (6, 0, 2), - (6, 1, 2), - (7, 0, 4), - (7, 1, 4) - ] - ); -} - -#[test] -fn test_subbyte_pixels() { - let scanline = &[0b10101010, 0b10101010]; - - let pixels = subbyte_pixels(scanline, 1).collect::<Vec<_>>(); - assert_eq!(pixels.len(), 16); - assert_eq!(pixels, [1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0]); -} - -#[test] -fn test_expand_adam7_bits() { - let width = 32; - let bits_pp = 1; - - let expected = |offset: usize, step: usize, count: usize| { - (0..count) - .map(move |i| step * i + offset) - .collect::<Vec<_>>() - }; - - for line_no in 0..8 { - let start = 8 * line_no * width; - - assert_eq!( - expand_adam7_bits(1, width, line_no, bits_pp).collect::<Vec<_>>(), - expected(start, 8, 4) - ); - - let start = start + 4; - - assert_eq!( - expand_adam7_bits(2, width, line_no, bits_pp).collect::<Vec<_>>(), - expected(start, 8, 4) - ); - - let start = (8 * line_no + 4) as usize * width as usize; - - assert_eq!( - expand_adam7_bits(3, width, line_no, bits_pp).collect::<Vec<_>>(), - expected(start, 4, 8) - ); - } - - for line_no in 0..16 { - let start = 4 * line_no * width + 2; - - assert_eq!( - expand_adam7_bits(4, width, line_no, bits_pp).collect::<Vec<_>>(), - expected(start, 4, 8) - ); - - let start = (4 * line_no + 2) * width; - - assert_eq!( - expand_adam7_bits(5, width, line_no, bits_pp).collect::<Vec<_>>(), - expected(start, 2, 16) - ) - } - - for line_no in 0..32 { - let start = 2 * line_no * width + 1; - - assert_eq!( - expand_adam7_bits(6, width, line_no, bits_pp).collect::<Vec<_>>(), - expected(start, 2, 16), - "line_no: {}", - line_no - ); - - let start = (2 * line_no + 1) * width; - - assert_eq!( - expand_adam7_bits(7, width, line_no, bits_pp).collect::<Vec<_>>(), - expected(start, 1, 32) - ); - } -} - -#[test] -fn test_expand_pass_subbyte() { - let mut img = [0u8; 8]; - let width = 8; - let bits_pp = 1; - - expand_pass(&mut img, width, &[0b10000000], 1, 0, bits_pp); - assert_eq!(img, [0b10000000u8, 0, 0, 0, 0, 0, 0, 0]); - - expand_pass(&mut img, width, &[0b10000000], 2, 0, bits_pp); - assert_eq!(img, [0b10001000u8, 0, 0, 0, 0, 0, 0, 0]); - - expand_pass(&mut img, width, &[0b11000000], 3, 0, bits_pp); - assert_eq!(img, [0b10001000u8, 0, 0, 0, 0b10001000, 0, 0, 0]); - - expand_pass(&mut img, width, &[0b11000000], 4, 0, bits_pp); - assert_eq!(img, [0b10101010u8, 0, 0, 0, 0b10001000, 0, 0, 0]); - - expand_pass(&mut img, width, &[0b11000000], 4, 1, bits_pp); - assert_eq!(img, [0b10101010u8, 0, 0, 0, 0b10101010, 0, 0, 0]); - - expand_pass(&mut img, width, &[0b11110000], 5, 0, bits_pp); - assert_eq!(img, [0b10101010u8, 0, 0b10101010, 0, 0b10101010, 0, 0, 0]); - - expand_pass(&mut img, width, &[0b11110000], 5, 1, bits_pp); - assert_eq!( - img, - [0b10101010u8, 0, 0b10101010, 0, 0b10101010, 0, 0b10101010, 0] - ); - - expand_pass(&mut img, width, &[0b11110000], 6, 0, bits_pp); - assert_eq!( - img, - [0b11111111u8, 0, 0b10101010, 0, 0b10101010, 0, 0b10101010, 0] - ); - - expand_pass(&mut img, width, &[0b11110000], 6, 1, bits_pp); - assert_eq!( - img, - [0b11111111u8, 0, 0b11111111, 0, 0b10101010, 0, 0b10101010, 0] - ); - - expand_pass(&mut img, width, &[0b11110000], 6, 2, bits_pp); - assert_eq!( - img, - [0b11111111u8, 0, 0b11111111, 0, 0b11111111, 0, 0b10101010, 0] - ); - - expand_pass(&mut img, width, &[0b11110000], 6, 3, bits_pp); - assert_eq!( - [0b11111111u8, 0, 0b11111111, 0, 0b11111111, 0, 0b11111111, 0], - img - ); - - expand_pass(&mut img, width, &[0b11111111], 7, 0, bits_pp); - assert_eq!( - [ - 0b11111111u8, - 0b11111111, - 0b11111111, - 0, - 0b11111111, - 0, - 0b11111111, - 0 - ], - img - ); - - expand_pass(&mut img, width, &[0b11111111], 7, 1, bits_pp); - assert_eq!( - [ - 0b11111111u8, - 0b11111111, - 0b11111111, - 0b11111111, - 0b11111111, - 0, - 0b11111111, - 0 - ], - img - ); - - expand_pass(&mut img, width, &[0b11111111], 7, 2, bits_pp); - assert_eq!( - [ - 0b11111111u8, - 0b11111111, - 0b11111111, - 0b11111111, - 0b11111111, - 0b11111111, - 0b11111111, - 0 - ], - img - ); - - expand_pass(&mut img, width, &[0b11111111], 7, 3, bits_pp); - assert_eq!( - [ - 0b11111111u8, - 0b11111111, - 0b11111111, - 0b11111111, - 0b11111111, - 0b11111111, - 0b11111111, - 0b11111111 - ], - img - ); -} |