From e68c4caa82c0c69ede4077144dacf7659ba93e2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kornel=20Lesi=C5=84ski?= Date: Thu, 10 Jan 2019 18:53:04 +0000 Subject: [PATCH] Immutable interlace reductions --- benches/interlacing.rs | 20 ++++++++++---------- src/interlace.rs | 32 ++++++++++++++++++++++++++------ src/lib.rs | 4 ++-- src/png/mod.rs | 18 ++++++++++-------- src/reduction/alpha.rs | 1 + src/reduction/bit_depth.rs | 1 + src/reduction/color.rs | 3 +++ src/reduction/mod.rs | 2 ++ 8 files changed, 55 insertions(+), 26 deletions(-) diff --git a/benches/interlacing.rs b/benches/interlacing.rs index 45a36cf0..26d93da7 100644 --- a/benches/interlacing.rs +++ b/benches/interlacing.rs @@ -14,7 +14,7 @@ fn interlacing_16_bits(b: &mut Bencher) { b.iter(|| { let mut safe_png = png.clone(); - safe_png.change_interlacing(1); + safe_png.change_interlacing(1) }); } @@ -25,7 +25,7 @@ fn interlacing_8_bits(b: &mut Bencher) { b.iter(|| { let mut safe_png = png.clone(); - safe_png.change_interlacing(1); + safe_png.change_interlacing(1) }); } @@ -38,7 +38,7 @@ fn interlacing_4_bits(b: &mut Bencher) { b.iter(|| { let mut safe_png = png.clone(); - safe_png.change_interlacing(1); + safe_png.change_interlacing(1) }); } @@ -51,7 +51,7 @@ fn interlacing_2_bits(b: &mut Bencher) { b.iter(|| { let mut safe_png = png.clone(); - safe_png.change_interlacing(1); + safe_png.change_interlacing(1) }); } @@ -64,7 +64,7 @@ fn interlacing_1_bits(b: &mut Bencher) { b.iter(|| { let mut safe_png = png.clone(); - safe_png.change_interlacing(1); + safe_png.change_interlacing(1) }); } @@ -77,7 +77,7 @@ fn deinterlacing_16_bits(b: &mut Bencher) { b.iter(|| { let mut safe_png = png.clone(); - safe_png.change_interlacing(0); + safe_png.change_interlacing(0) }); } @@ -90,7 +90,7 @@ fn deinterlacing_8_bits(b: &mut Bencher) { b.iter(|| { let mut safe_png = png.clone(); - safe_png.change_interlacing(0); + safe_png.change_interlacing(0) }); } @@ -103,7 +103,7 @@ fn deinterlacing_4_bits(b: &mut Bencher) { b.iter(|| { let mut safe_png = png.clone(); - safe_png.change_interlacing(0); + safe_png.change_interlacing(0) }); } @@ -116,7 +116,7 @@ fn deinterlacing_2_bits(b: &mut Bencher) { b.iter(|| { let mut safe_png = png.clone(); - safe_png.change_interlacing(0); + safe_png.change_interlacing(0) }); } @@ -129,6 +129,6 @@ fn deinterlacing_1_bits(b: &mut Bencher) { b.iter(|| { let mut safe_png = png.clone(); - safe_png.change_interlacing(0); + safe_png.change_interlacing(0) }); } diff --git a/src/interlace.rs b/src/interlace.rs index 6d720e90..c681dc4e 100644 --- a/src/interlace.rs +++ b/src/interlace.rs @@ -1,7 +1,9 @@ +use reduction::ReducedPng; use bit_vec::BitVec; use png::PngData; -pub fn interlace_image(png: &mut PngData) { +#[must_use] +pub fn interlace_image(png: &PngData) -> ReducedPng { let mut passes: Vec = vec![BitVec::new(); 7]; let bits_per_pixel = png.ihdr_data.bit_depth.as_u8() * png.channels_per_pixel(); for (index, line) in png.scan_lines().enumerate() { @@ -74,14 +76,24 @@ pub fn interlace_image(png: &mut PngData) { } } } - let mut output = Vec::new(); + + let mut output = Vec::with_capacity(png.raw_data.len()); for pass in &passes { output.extend(pass.to_bytes()); } - png.raw_data = output; + + ReducedPng { + raw_data: output, + interlaced: 1, + color_type: png.ihdr_data.color_type, + bit_depth: png.ihdr_data.bit_depth, + aux_headers: Default::default(), + palette: None, + transparency_pixel: None, + } } -pub fn deinterlace_image(png: &mut PngData) { +pub fn deinterlace_image(png: &PngData) -> ReducedPng { let bits_per_pixel = png.ihdr_data.bit_depth.as_u8() * png.channels_per_pixel(); let bits_per_line = 8 + bits_per_pixel as usize * png.ihdr_data.width as usize; // Initialize each output line with a starting filter byte of 0 @@ -126,14 +138,22 @@ pub fn deinterlace_image(png: &mut PngData) { current_y = pass_constants.y_shift as usize; } } - let mut output = Vec::new(); + let mut output = Vec::with_capacity(png.raw_data.len()); for line in &mut lines { while line.len() % 8 != 0 { line.push(false); } output.extend(line.to_bytes()); } - png.raw_data = output; + ReducedPng { + raw_data: output, + interlaced: 0, + color_type: png.ihdr_data.color_type, + bit_depth: png.ihdr_data.bit_depth, + aux_headers: Default::default(), + palette: None, + transparency_pixel: None, + } } #[derive(Clone, Copy)] diff --git a/src/lib.rs b/src/lib.rs index cb97ab6d..3f1e8ebd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -766,8 +766,8 @@ fn perform_reductions(png: &mut PngData, opts: &Options, deadline: &Deadline) -> } if let Some(interlacing) = opts.interlace { - if png.change_interlacing(interlacing) { - png.ihdr_data.interlaced = interlacing; + if let Some(reduced) = png.change_interlacing(interlacing) { + png.apply_reduction(reduced); reduction_occurred = true; } } diff --git a/src/png/mod.rs b/src/png/mod.rs index 980b1c59..25526cdc 100644 --- a/src/png/mod.rs +++ b/src/png/mod.rs @@ -365,6 +365,7 @@ impl PngData { Some(ReducedPng { color_type: self.ihdr_data.color_type, + interlaced: self.ihdr_data.interlaced, bit_depth: BitDepth::Eight, raw_data: reduced, palette: self.palette.clone(), @@ -419,9 +420,10 @@ impl PngData { changed } - pub(crate) fn apply_reduction(&mut self, ReducedPng {color_type, bit_depth, raw_data, palette, transparency_pixel, aux_headers}: ReducedPng) { + pub(crate) fn apply_reduction(&mut self, ReducedPng {color_type, bit_depth, raw_data, interlaced, palette, transparency_pixel, aux_headers}: ReducedPng) { self.ihdr_data.color_type = color_type; self.ihdr_data.bit_depth = bit_depth; + self.ihdr_data.interlaced = interlaced; self.raw_data = raw_data; if palette.is_some() { self.transparency_pixel = None; @@ -652,19 +654,19 @@ impl PngData { /// The `interlace` parameter specifies the *new* interlacing mode /// Assumes that the data has already been de-filtered #[inline] - pub fn change_interlacing(&mut self, interlace: u8) -> bool { + #[must_use] + pub fn change_interlacing(&mut self, interlace: u8) -> Option { if interlace == self.ihdr_data.interlaced { - return false; + return None; } - if interlace == 1 { + Some(if interlace == 1 { // Convert progressive to interlaced data - interlace_image(self); + interlace_image(self) } else { // Convert interlaced to progressive data - deinterlace_image(self); - } - true + deinterlace_image(self) + }) } } diff --git a/src/reduction/alpha.rs b/src/reduction/alpha.rs index caad1a48..04d59821 100644 --- a/src/reduction/alpha.rs +++ b/src/reduction/alpha.rs @@ -47,6 +47,7 @@ pub fn reduced_alpha_channel(png: &PngData) -> Option { Some(ReducedPng { raw_data, bit_depth: png.ihdr_data.bit_depth, + interlaced: png.ihdr_data.interlaced, color_type: target_color_type, aux_headers, transparency_pixel: None, diff --git a/src/reduction/bit_depth.rs b/src/reduction/bit_depth.rs index a6bab853..10afca51 100644 --- a/src/reduction/bit_depth.rs +++ b/src/reduction/bit_depth.rs @@ -82,6 +82,7 @@ pub fn reduce_bit_depth_8_or_less(png: &PngData) -> Option { Some(ReducedPng { color_type: png.ihdr_data.color_type, + interlaced: png.ihdr_data.interlaced, raw_data: reduced.to_bytes(), bit_depth: BitDepth::from_u8(allowed_bits as u8), aux_headers: Default::default(), diff --git a/src/reduction/color.rs b/src/reduction/color.rs index 2a2552ca..c773b933 100644 --- a/src/reduction/color.rs +++ b/src/reduction/color.rs @@ -61,6 +61,7 @@ pub fn reduce_rgba_to_grayscale_alpha(png: &PngData) -> Option { Some(ReducedPng { raw_data: reduced, bit_depth: png.ihdr_data.bit_depth, + interlaced: png.ihdr_data.interlaced, color_type: ColorType::GrayscaleAlpha, palette: None, transparency_pixel: None, @@ -178,6 +179,7 @@ pub fn reduced_color_to_palette(png: &PngData) -> Option { Some(ReducedPng { color_type: ColorType::Indexed, bit_depth: png.ihdr_data.bit_depth, + interlaced: png.ihdr_data.interlaced, aux_headers, raw_data, transparency_pixel: None, @@ -242,6 +244,7 @@ pub fn reduce_rgb_to_grayscale(png: &PngData) -> Option { raw_data: reduced, color_type: ColorType::Grayscale, bit_depth: png.ihdr_data.bit_depth, + interlaced: png.ihdr_data.interlaced, palette: None, transparency_pixel, aux_headers, diff --git a/src/reduction/mod.rs b/src/reduction/mod.rs index 2d326976..09d32d31 100644 --- a/src/reduction/mod.rs +++ b/src/reduction/mod.rs @@ -19,6 +19,7 @@ pub struct ReducedPng { pub transparency_pixel: Option>, /// replace if Some, delete if None pub aux_headers: HashMap<[u8; 4], Option>>, + pub interlaced: u8, } /// Attempt to reduce the number of colors in the palette @@ -109,6 +110,7 @@ fn do_palette_reduction(png: &PngData, palette_map: &[Option; 256]) -> Optio Some(ReducedPng { color_type: ColorType::Indexed, bit_depth: png.ihdr_data.bit_depth, + interlaced: png.ihdr_data.interlaced, raw_data, transparency_pixel: None, palette: Some(reordered_palette(png.palette.as_ref()?, palette_map)),