Immutable interlace reductions
This commit is contained in:
parent
e8beb76192
commit
e68c4caa82
8 changed files with 55 additions and 26 deletions
|
|
@ -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)
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)]
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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)),
|
||||
|
|
|
|||
Loading…
Reference in a new issue