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(|| {
|
b.iter(|| {
|
||||||
let mut safe_png = png.clone();
|
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(|| {
|
b.iter(|| {
|
||||||
let mut safe_png = png.clone();
|
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(|| {
|
b.iter(|| {
|
||||||
let mut safe_png = png.clone();
|
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(|| {
|
b.iter(|| {
|
||||||
let mut safe_png = png.clone();
|
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(|| {
|
b.iter(|| {
|
||||||
let mut safe_png = png.clone();
|
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(|| {
|
b.iter(|| {
|
||||||
let mut safe_png = png.clone();
|
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(|| {
|
b.iter(|| {
|
||||||
let mut safe_png = png.clone();
|
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(|| {
|
b.iter(|| {
|
||||||
let mut safe_png = png.clone();
|
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(|| {
|
b.iter(|| {
|
||||||
let mut safe_png = png.clone();
|
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(|| {
|
b.iter(|| {
|
||||||
let mut safe_png = png.clone();
|
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 bit_vec::BitVec;
|
||||||
use png::PngData;
|
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 mut passes: Vec<BitVec> = vec![BitVec::new(); 7];
|
||||||
let bits_per_pixel = png.ihdr_data.bit_depth.as_u8() * png.channels_per_pixel();
|
let bits_per_pixel = png.ihdr_data.bit_depth.as_u8() * png.channels_per_pixel();
|
||||||
for (index, line) in png.scan_lines().enumerate() {
|
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 {
|
for pass in &passes {
|
||||||
output.extend(pass.to_bytes());
|
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_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;
|
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
|
// 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;
|
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 {
|
for line in &mut lines {
|
||||||
while line.len() % 8 != 0 {
|
while line.len() % 8 != 0 {
|
||||||
line.push(false);
|
line.push(false);
|
||||||
}
|
}
|
||||||
output.extend(line.to_bytes());
|
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)]
|
#[derive(Clone, Copy)]
|
||||||
|
|
|
||||||
|
|
@ -766,8 +766,8 @@ fn perform_reductions(png: &mut PngData, opts: &Options, deadline: &Deadline) ->
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(interlacing) = opts.interlace {
|
if let Some(interlacing) = opts.interlace {
|
||||||
if png.change_interlacing(interlacing) {
|
if let Some(reduced) = png.change_interlacing(interlacing) {
|
||||||
png.ihdr_data.interlaced = interlacing;
|
png.apply_reduction(reduced);
|
||||||
reduction_occurred = true;
|
reduction_occurred = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -365,6 +365,7 @@ impl PngData {
|
||||||
|
|
||||||
Some(ReducedPng {
|
Some(ReducedPng {
|
||||||
color_type: self.ihdr_data.color_type,
|
color_type: self.ihdr_data.color_type,
|
||||||
|
interlaced: self.ihdr_data.interlaced,
|
||||||
bit_depth: BitDepth::Eight,
|
bit_depth: BitDepth::Eight,
|
||||||
raw_data: reduced,
|
raw_data: reduced,
|
||||||
palette: self.palette.clone(),
|
palette: self.palette.clone(),
|
||||||
|
|
@ -419,9 +420,10 @@ impl PngData {
|
||||||
changed
|
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.color_type = color_type;
|
||||||
self.ihdr_data.bit_depth = bit_depth;
|
self.ihdr_data.bit_depth = bit_depth;
|
||||||
|
self.ihdr_data.interlaced = interlaced;
|
||||||
self.raw_data = raw_data;
|
self.raw_data = raw_data;
|
||||||
if palette.is_some() {
|
if palette.is_some() {
|
||||||
self.transparency_pixel = None;
|
self.transparency_pixel = None;
|
||||||
|
|
@ -652,19 +654,19 @@ impl PngData {
|
||||||
/// The `interlace` parameter specifies the *new* interlacing mode
|
/// The `interlace` parameter specifies the *new* interlacing mode
|
||||||
/// Assumes that the data has already been de-filtered
|
/// Assumes that the data has already been de-filtered
|
||||||
#[inline]
|
#[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 {
|
if interlace == self.ihdr_data.interlaced {
|
||||||
return false;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
if interlace == 1 {
|
Some(if interlace == 1 {
|
||||||
// Convert progressive to interlaced data
|
// Convert progressive to interlaced data
|
||||||
interlace_image(self);
|
interlace_image(self)
|
||||||
} else {
|
} else {
|
||||||
// Convert interlaced to progressive data
|
// Convert interlaced to progressive data
|
||||||
deinterlace_image(self);
|
deinterlace_image(self)
|
||||||
}
|
})
|
||||||
true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,7 @@ pub fn reduced_alpha_channel(png: &PngData) -> Option<ReducedPng> {
|
||||||
Some(ReducedPng {
|
Some(ReducedPng {
|
||||||
raw_data,
|
raw_data,
|
||||||
bit_depth: png.ihdr_data.bit_depth,
|
bit_depth: png.ihdr_data.bit_depth,
|
||||||
|
interlaced: png.ihdr_data.interlaced,
|
||||||
color_type: target_color_type,
|
color_type: target_color_type,
|
||||||
aux_headers,
|
aux_headers,
|
||||||
transparency_pixel: None,
|
transparency_pixel: None,
|
||||||
|
|
|
||||||
|
|
@ -82,6 +82,7 @@ pub fn reduce_bit_depth_8_or_less(png: &PngData) -> Option<ReducedPng> {
|
||||||
|
|
||||||
Some(ReducedPng {
|
Some(ReducedPng {
|
||||||
color_type: png.ihdr_data.color_type,
|
color_type: png.ihdr_data.color_type,
|
||||||
|
interlaced: png.ihdr_data.interlaced,
|
||||||
raw_data: reduced.to_bytes(),
|
raw_data: reduced.to_bytes(),
|
||||||
bit_depth: BitDepth::from_u8(allowed_bits as u8),
|
bit_depth: BitDepth::from_u8(allowed_bits as u8),
|
||||||
aux_headers: Default::default(),
|
aux_headers: Default::default(),
|
||||||
|
|
|
||||||
|
|
@ -61,6 +61,7 @@ pub fn reduce_rgba_to_grayscale_alpha(png: &PngData) -> Option<ReducedPng> {
|
||||||
Some(ReducedPng {
|
Some(ReducedPng {
|
||||||
raw_data: reduced,
|
raw_data: reduced,
|
||||||
bit_depth: png.ihdr_data.bit_depth,
|
bit_depth: png.ihdr_data.bit_depth,
|
||||||
|
interlaced: png.ihdr_data.interlaced,
|
||||||
color_type: ColorType::GrayscaleAlpha,
|
color_type: ColorType::GrayscaleAlpha,
|
||||||
palette: None,
|
palette: None,
|
||||||
transparency_pixel: None,
|
transparency_pixel: None,
|
||||||
|
|
@ -178,6 +179,7 @@ pub fn reduced_color_to_palette(png: &PngData) -> Option<ReducedPng> {
|
||||||
Some(ReducedPng {
|
Some(ReducedPng {
|
||||||
color_type: ColorType::Indexed,
|
color_type: ColorType::Indexed,
|
||||||
bit_depth: png.ihdr_data.bit_depth,
|
bit_depth: png.ihdr_data.bit_depth,
|
||||||
|
interlaced: png.ihdr_data.interlaced,
|
||||||
aux_headers,
|
aux_headers,
|
||||||
raw_data,
|
raw_data,
|
||||||
transparency_pixel: None,
|
transparency_pixel: None,
|
||||||
|
|
@ -242,6 +244,7 @@ pub fn reduce_rgb_to_grayscale(png: &PngData) -> Option<ReducedPng> {
|
||||||
raw_data: reduced,
|
raw_data: reduced,
|
||||||
color_type: ColorType::Grayscale,
|
color_type: ColorType::Grayscale,
|
||||||
bit_depth: png.ihdr_data.bit_depth,
|
bit_depth: png.ihdr_data.bit_depth,
|
||||||
|
interlaced: png.ihdr_data.interlaced,
|
||||||
palette: None,
|
palette: None,
|
||||||
transparency_pixel,
|
transparency_pixel,
|
||||||
aux_headers,
|
aux_headers,
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ pub struct ReducedPng {
|
||||||
pub transparency_pixel: Option<Vec<u8>>,
|
pub transparency_pixel: Option<Vec<u8>>,
|
||||||
/// replace if Some, delete if None
|
/// replace if Some, delete if None
|
||||||
pub aux_headers: HashMap<[u8; 4], Option<Vec<u8>>>,
|
pub aux_headers: HashMap<[u8; 4], Option<Vec<u8>>>,
|
||||||
|
pub interlaced: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Attempt to reduce the number of colors in the palette
|
/// 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 {
|
Some(ReducedPng {
|
||||||
color_type: ColorType::Indexed,
|
color_type: ColorType::Indexed,
|
||||||
bit_depth: png.ihdr_data.bit_depth,
|
bit_depth: png.ihdr_data.bit_depth,
|
||||||
|
interlaced: png.ihdr_data.interlaced,
|
||||||
raw_data,
|
raw_data,
|
||||||
transparency_pixel: None,
|
transparency_pixel: None,
|
||||||
palette: Some(reordered_palette(png.palette.as_ref()?, palette_map)),
|
palette: Some(reordered_palette(png.palette.as_ref()?, palette_map)),
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue