From de61b7abf924780c60f9b5876da7f315789fe378 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kornel=20Lesin=CC=81ski?= Date: Thu, 17 Jan 2019 16:05:00 +0000 Subject: [PATCH] Faster bit depth check --- src/reduction/bit_depth.rs | 45 ++++++++++++++++++++++++-------------- 1 file changed, 28 insertions(+), 17 deletions(-) diff --git a/src/reduction/bit_depth.rs b/src/reduction/bit_depth.rs index ef1055ac..24493f0f 100644 --- a/src/reduction/bit_depth.rs +++ b/src/reduction/bit_depth.rs @@ -78,28 +78,39 @@ pub fn reduce_bit_depth(png: &PngImage) -> Option { pub fn reduce_bit_depth_8_or_less(png: &PngImage) -> Option { let mut reduced = BitVec::with_capacity(png.data.len() * 8); let bit_depth: usize = png.ihdr.bit_depth.as_u8() as usize; - let mut allowed_bits = 1; + let mut minimum_bits = 1; + if minimum_bits >= bit_depth { + return None; + } for line in png.scan_lines() { - let bit_vec = BitVec::from_bytes(&line.data); if png.ihdr.color_type == ColorType::Indexed { - for (i, bit) in bit_vec.iter().enumerate() { - let bit_index = bit_depth - (i % bit_depth); - if bit && bit_index > allowed_bits { - allowed_bits = bit_index.next_power_of_two(); - if allowed_bits == bit_depth { - // Not reducable - return None; - } + let line_max = line.data.iter().map(|&byte| match png.ihdr.bit_depth { + BitDepth::Two => (byte & 0x3).max((byte >> 2) & 0x3).max((byte >> 4) & 0x3).max(byte >> 6), + BitDepth::Four => (byte & 0xF).max(byte >> 4), + _ => byte, + }).max().unwrap_or(0); + let required_bits = match line_max { + x if x > 0x0F => 8, + x if x > 0x03 => 4, + x if x > 0x01 => 2, + _ => 1, + }; + if required_bits > minimum_bits { + minimum_bits = required_bits; + if minimum_bits >= bit_depth { + // Not reducable + return None; } } } else { + let bit_vec = BitVec::from_bytes(&line.data); for byte in bit_vec.to_bytes() { - while allowed_bits < bit_depth { - let permutations: &[u8] = if allowed_bits == 1 { + while minimum_bits < bit_depth { + let permutations: &[u8] = if minimum_bits == 1 { &ONE_BIT_PERMUTATIONS - } else if allowed_bits == 2 { + } else if minimum_bits == 2 { &TWO_BIT_PERMUTATIONS - } else if allowed_bits == 4 { + } else if minimum_bits == 4 { &FOUR_BIT_PERMUTATIONS } else { return None; @@ -107,7 +118,7 @@ pub fn reduce_bit_depth_8_or_less(png: &PngImage) -> Option { if permutations.iter().any(|perm| *perm == byte) { break; } else { - allowed_bits <<= 1; + minimum_bits <<= 1; } } } @@ -119,7 +130,7 @@ pub fn reduce_bit_depth_8_or_less(png: &PngImage) -> Option { let bit_vec = BitVec::from_bytes(&line.data); for (i, bit) in bit_vec.iter().enumerate() { let bit_index = bit_depth - (i % bit_depth); - if bit_index <= allowed_bits { + if bit_index <= minimum_bits { reduced.push(bit); } } @@ -132,7 +143,7 @@ pub fn reduce_bit_depth_8_or_less(png: &PngImage) -> Option { Some(PngImage { data: reduced.to_bytes(), ihdr: IhdrData { - bit_depth: BitDepth::from_u8(allowed_bits as u8), + bit_depth: BitDepth::from_u8(minimum_bits as u8), ..png.ihdr }, aux_headers: png.aux_headers.clone(),