Immutable interlace reductions

This commit is contained in:
Kornel Lesiński 2019-01-10 18:53:04 +00:00
parent e8beb76192
commit e68c4caa82
8 changed files with 55 additions and 26 deletions

View file

@ -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)
});
}

View file

@ -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<BitVec> = 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)]

View file

@ -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;
}
}

View file

@ -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<ReducedPng> {
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)
})
}
}

View file

@ -47,6 +47,7 @@ pub fn reduced_alpha_channel(png: &PngData) -> Option<ReducedPng> {
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,

View file

@ -82,6 +82,7 @@ pub fn reduce_bit_depth_8_or_less(png: &PngData) -> Option<ReducedPng> {
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(),

View file

@ -61,6 +61,7 @@ pub fn reduce_rgba_to_grayscale_alpha(png: &PngData) -> Option<ReducedPng> {
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<ReducedPng> {
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<ReducedPng> {
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,

View file

@ -19,6 +19,7 @@ pub struct ReducedPng {
pub transparency_pixel: Option<Vec<u8>>,
/// replace if Some, delete if None
pub aux_headers: HashMap<[u8; 4], Option<Vec<u8>>>,
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<u8>; 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)),