diff --git a/benches/filters.rs b/benches/filters.rs index 27a330b8..687f9709 100644 --- a/benches/filters.rs +++ b/benches/filters.rs @@ -3,7 +3,7 @@ extern crate oxipng; extern crate test; -use oxipng::internal_tests::*; +use oxipng::{internal_tests::*, RowFilter}; use std::path::PathBuf; use test::Bencher; @@ -13,7 +13,7 @@ fn filters_16_bits_filter_0(b: &mut Bencher) { let png = PngData::new(&input, false).unwrap(); b.iter(|| { - png.raw.filter_image(0); + png.raw.filter_image(RowFilter::None); }); } @@ -23,7 +23,7 @@ fn filters_8_bits_filter_0(b: &mut Bencher) { let png = PngData::new(&input, false).unwrap(); b.iter(|| { - png.raw.filter_image(0); + png.raw.filter_image(RowFilter::None); }); } @@ -35,7 +35,7 @@ fn filters_4_bits_filter_0(b: &mut Bencher) { let png = PngData::new(&input, false).unwrap(); b.iter(|| { - png.raw.filter_image(0); + png.raw.filter_image(RowFilter::None); }); } @@ -47,7 +47,7 @@ fn filters_2_bits_filter_0(b: &mut Bencher) { let png = PngData::new(&input, false).unwrap(); b.iter(|| { - png.raw.filter_image(0); + png.raw.filter_image(RowFilter::None); }); } @@ -59,7 +59,7 @@ fn filters_1_bits_filter_0(b: &mut Bencher) { let png = PngData::new(&input, false).unwrap(); b.iter(|| { - png.raw.filter_image(0); + png.raw.filter_image(RowFilter::None); }); } @@ -69,7 +69,7 @@ fn filters_16_bits_filter_1(b: &mut Bencher) { let png = PngData::new(&input, false).unwrap(); b.iter(|| { - png.raw.filter_image(1); + png.raw.filter_image(RowFilter::Sub); }); } @@ -79,7 +79,7 @@ fn filters_8_bits_filter_1(b: &mut Bencher) { let png = PngData::new(&input, false).unwrap(); b.iter(|| { - png.raw.filter_image(1); + png.raw.filter_image(RowFilter::Sub); }); } @@ -91,7 +91,7 @@ fn filters_4_bits_filter_1(b: &mut Bencher) { let png = PngData::new(&input, false).unwrap(); b.iter(|| { - png.raw.filter_image(1); + png.raw.filter_image(RowFilter::Sub); }); } @@ -103,7 +103,7 @@ fn filters_2_bits_filter_1(b: &mut Bencher) { let png = PngData::new(&input, false).unwrap(); b.iter(|| { - png.raw.filter_image(1); + png.raw.filter_image(RowFilter::Sub); }); } @@ -115,7 +115,7 @@ fn filters_1_bits_filter_1(b: &mut Bencher) { let png = PngData::new(&input, false).unwrap(); b.iter(|| { - png.raw.filter_image(1); + png.raw.filter_image(RowFilter::Sub); }); } @@ -125,7 +125,7 @@ fn filters_16_bits_filter_2(b: &mut Bencher) { let png = PngData::new(&input, false).unwrap(); b.iter(|| { - png.raw.filter_image(2); + png.raw.filter_image(RowFilter::Up); }); } @@ -135,7 +135,7 @@ fn filters_8_bits_filter_2(b: &mut Bencher) { let png = PngData::new(&input, false).unwrap(); b.iter(|| { - png.raw.filter_image(2); + png.raw.filter_image(RowFilter::Up); }); } @@ -147,7 +147,7 @@ fn filters_4_bits_filter_2(b: &mut Bencher) { let png = PngData::new(&input, false).unwrap(); b.iter(|| { - png.raw.filter_image(2); + png.raw.filter_image(RowFilter::Up); }); } @@ -159,7 +159,7 @@ fn filters_2_bits_filter_2(b: &mut Bencher) { let png = PngData::new(&input, false).unwrap(); b.iter(|| { - png.raw.filter_image(2); + png.raw.filter_image(RowFilter::Up); }); } @@ -171,7 +171,7 @@ fn filters_1_bits_filter_2(b: &mut Bencher) { let png = PngData::new(&input, false).unwrap(); b.iter(|| { - png.raw.filter_image(2); + png.raw.filter_image(RowFilter::Up); }); } @@ -181,7 +181,7 @@ fn filters_16_bits_filter_3(b: &mut Bencher) { let png = PngData::new(&input, false).unwrap(); b.iter(|| { - png.raw.filter_image(3); + png.raw.filter_image(RowFilter::Average); }); } @@ -191,7 +191,7 @@ fn filters_8_bits_filter_3(b: &mut Bencher) { let png = PngData::new(&input, false).unwrap(); b.iter(|| { - png.raw.filter_image(3); + png.raw.filter_image(RowFilter::Average); }); } @@ -203,7 +203,7 @@ fn filters_4_bits_filter_3(b: &mut Bencher) { let png = PngData::new(&input, false).unwrap(); b.iter(|| { - png.raw.filter_image(3); + png.raw.filter_image(RowFilter::Average); }); } @@ -215,7 +215,7 @@ fn filters_2_bits_filter_3(b: &mut Bencher) { let png = PngData::new(&input, false).unwrap(); b.iter(|| { - png.raw.filter_image(3); + png.raw.filter_image(RowFilter::Average); }); } @@ -227,7 +227,7 @@ fn filters_1_bits_filter_3(b: &mut Bencher) { let png = PngData::new(&input, false).unwrap(); b.iter(|| { - png.raw.filter_image(3); + png.raw.filter_image(RowFilter::Average); }); } @@ -237,7 +237,7 @@ fn filters_16_bits_filter_4(b: &mut Bencher) { let png = PngData::new(&input, false).unwrap(); b.iter(|| { - png.raw.filter_image(4); + png.raw.filter_image(RowFilter::Paeth); }); } @@ -247,7 +247,7 @@ fn filters_8_bits_filter_4(b: &mut Bencher) { let png = PngData::new(&input, false).unwrap(); b.iter(|| { - png.raw.filter_image(4); + png.raw.filter_image(RowFilter::Paeth); }); } @@ -259,7 +259,7 @@ fn filters_4_bits_filter_4(b: &mut Bencher) { let png = PngData::new(&input, false).unwrap(); b.iter(|| { - png.raw.filter_image(4); + png.raw.filter_image(RowFilter::Paeth); }); } @@ -271,7 +271,7 @@ fn filters_2_bits_filter_4(b: &mut Bencher) { let png = PngData::new(&input, false).unwrap(); b.iter(|| { - png.raw.filter_image(4); + png.raw.filter_image(RowFilter::Paeth); }); } @@ -283,7 +283,7 @@ fn filters_1_bits_filter_4(b: &mut Bencher) { let png = PngData::new(&input, false).unwrap(); b.iter(|| { - png.raw.filter_image(4); + png.raw.filter_image(RowFilter::Paeth); }); } @@ -293,7 +293,7 @@ fn filters_16_bits_filter_5(b: &mut Bencher) { let png = PngData::new(&input, false).unwrap(); b.iter(|| { - png.raw.filter_image(5); + png.raw.filter_image(RowFilter::MinSum); }); } @@ -303,7 +303,7 @@ fn filters_8_bits_filter_5(b: &mut Bencher) { let png = PngData::new(&input, false).unwrap(); b.iter(|| { - png.raw.filter_image(5); + png.raw.filter_image(RowFilter::MinSum); }); } @@ -315,7 +315,7 @@ fn filters_4_bits_filter_5(b: &mut Bencher) { let png = PngData::new(&input, false).unwrap(); b.iter(|| { - png.raw.filter_image(5); + png.raw.filter_image(RowFilter::MinSum); }); } @@ -327,7 +327,7 @@ fn filters_2_bits_filter_5(b: &mut Bencher) { let png = PngData::new(&input, false).unwrap(); b.iter(|| { - png.raw.filter_image(5); + png.raw.filter_image(RowFilter::MinSum); }); } @@ -339,6 +339,6 @@ fn filters_1_bits_filter_5(b: &mut Bencher) { let png = PngData::new(&input, false).unwrap(); b.iter(|| { - png.raw.filter_image(5); + png.raw.filter_image(RowFilter::MinSum); }); } diff --git a/src/evaluate.rs b/src/evaluate.rs index 96bca0fb..b4d31919 100644 --- a/src/evaluate.rs +++ b/src/evaluate.rs @@ -3,10 +3,9 @@ use crate::atomicmin::AtomicMin; use crate::deflate; +use crate::filters::RowFilter; use crate::png::PngData; use crate::png::PngImage; -use crate::png::STD_COMPRESSION; -use crate::png::STD_FILTERS; #[cfg(not(feature = "parallel"))] use crate::rayon; use crate::Deadline; @@ -19,9 +18,13 @@ use std::sync::atomic::AtomicUsize; use std::sync::atomic::Ordering::SeqCst; use std::sync::Arc; +/// Must use normal (lazy) compression, as faster ones (greedy) are not representative +const STD_COMPRESSION: u8 = 5; +const STD_FILTERS: [RowFilter; 2] = [RowFilter::None, RowFilter::MinSum]; + struct Candidate { image: PngData, - filter: u8, + filter: RowFilter, // first wins tie-breaker nth: usize, } diff --git a/src/filters.rs b/src/filters.rs index c0c10b10..a9d5630e 100644 --- a/src/filters.rs +++ b/src/filters.rs @@ -1,130 +1,180 @@ +use std::{fmt::Display, mem::transmute}; + use crate::error::PngError; -pub fn filter_line(filter: u8, bpp: usize, data: &[u8], last_line: &[u8], buf: &mut Vec) { - assert!(data.len() >= bpp); - assert!(last_line.is_empty() || data.len() == last_line.len()); - buf.reserve(data.len()); - match filter { - 0 => { - buf.extend_from_slice(data); +#[repr(u8)] +#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)] +pub enum RowFilter { + // Standard filter types + None, + Sub, + Up, + Average, + Paeth, + // Heuristic strategies + MinSum, +} + +impl TryFrom for RowFilter { + type Error = (); + + fn try_from(value: u8) -> Result { + if value > Self::LAST { + return Err(()); } - 1 => { - buf.extend_from_slice(&data[0..bpp]); - buf.extend( - data.iter() - .skip(bpp) - .zip(data.iter()) - .map(|(cur, last)| cur.wrapping_sub(*last)), - ); - } - 2 => { - if last_line.is_empty() { - buf.extend_from_slice(data); - } else { - assert_eq!(data.len(), last_line.len()); - buf.extend( - data.iter() - .zip(last_line.iter()) - .map(|(cur, last)| cur.wrapping_sub(*last)), - ); - }; - } - 3 => { - for (i, byte) in data.iter().enumerate() { - if last_line.is_empty() { - buf.push(match i.checked_sub(bpp) { - Some(x) => byte.wrapping_sub(data[x] >> 1), - None => *byte, - }); - } else { - buf.push(match i.checked_sub(bpp) { - Some(x) => byte.wrapping_sub( - ((u16::from(data[x]) + u16::from(last_line[i])) >> 1) as u8, - ), - None => byte.wrapping_sub(last_line[i] >> 1), - }); - }; - } - } - 4 => { - for (i, byte) in data.iter().enumerate() { - if last_line.is_empty() { - buf.push(match i.checked_sub(bpp) { - Some(x) => byte.wrapping_sub(data[x]), - None => *byte, - }); - } else { - buf.push(match i.checked_sub(bpp) { - Some(x) => { - byte.wrapping_sub(paeth_predictor(data[x], last_line[i], last_line[x])) - } - None => byte.wrapping_sub(last_line[i]), - }); - }; - } - } - _ => unreachable!(), + unsafe { transmute(value as i8) } } } -pub fn unfilter_line( - filter: u8, - bpp: usize, - data: &[u8], - last_line: &[u8], - buf: &mut Vec, -) -> Result<(), PngError> { - buf.clear(); - buf.reserve(data.len()); - assert!(data.len() >= bpp); - assert_eq!(data.len(), last_line.len()); - match filter { - 0 => { - buf.extend_from_slice(data); - } - 1 => { - for (i, &cur) in data.iter().enumerate() { - let prev_byte = i.checked_sub(bpp).and_then(|x| buf.get(x).copied()); - buf.push(match prev_byte { - Some(b) => cur.wrapping_add(b), - None => cur, - }); +impl Display for RowFilter { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "{:8}", + match *self { + Self::None => "None", + Self::Sub => "Sub", + Self::Up => "Up", + Self::Average => "Average", + Self::Paeth => "Paeth", + Self::MinSum => "MinSum", } - } - 2 => { - buf.extend( - data.iter() - .zip(last_line) - .map(|(&cur, &last)| cur.wrapping_add(last)), - ); - } - 3 => { - for (i, (&cur, &last)) in data.iter().zip(last_line).enumerate() { - let prev_byte = i.checked_sub(bpp).and_then(|x| buf.get(x).copied()); - buf.push(match prev_byte { - Some(b) => cur.wrapping_add(((u16::from(b) + u16::from(last)) >> 1) as u8), - None => cur.wrapping_add(last >> 1), - }); + ) + } +} + +impl RowFilter { + pub const LAST: u8 = Self::MinSum as u8; + pub const STANDARD: [Self; 5] = [Self::None, Self::Sub, Self::Up, Self::Average, Self::Paeth]; + + pub fn filter_line(self, bpp: usize, data: &[u8], last_line: &[u8], buf: &mut Vec) { + assert!(data.len() >= bpp); + assert!(last_line.is_empty() || data.len() == last_line.len()); + buf.reserve(data.len()); + match self { + Self::None => { + buf.extend_from_slice(data); } - } - 4 => { - for (i, (&cur, &up)) in data.iter().zip(last_line).enumerate() { - buf.push( - match i - .checked_sub(bpp) - .map(|x| (buf.get(x).copied(), last_line.get(x).copied())) - { - Some((Some(left), Some(left_up))) => { - cur.wrapping_add(paeth_predictor(left, up, left_up)) - } - _ => cur.wrapping_add(up), - }, + Self::Sub => { + buf.extend_from_slice(&data[0..bpp]); + buf.extend( + data.iter() + .skip(bpp) + .zip(data.iter()) + .map(|(cur, last)| cur.wrapping_sub(*last)), ); } + Self::Up => { + if last_line.is_empty() { + buf.extend_from_slice(data); + } else { + assert_eq!(data.len(), last_line.len()); + buf.extend( + data.iter() + .zip(last_line.iter()) + .map(|(cur, last)| cur.wrapping_sub(*last)), + ); + }; + } + Self::Average => { + for (i, byte) in data.iter().enumerate() { + if last_line.is_empty() { + buf.push(match i.checked_sub(bpp) { + Some(x) => byte.wrapping_sub(data[x] >> 1), + None => *byte, + }); + } else { + buf.push(match i.checked_sub(bpp) { + Some(x) => byte.wrapping_sub( + ((u16::from(data[x]) + u16::from(last_line[i])) >> 1) as u8, + ), + None => byte.wrapping_sub(last_line[i] >> 1), + }); + }; + } + } + Self::Paeth => { + for (i, byte) in data.iter().enumerate() { + if last_line.is_empty() { + buf.push(match i.checked_sub(bpp) { + Some(x) => byte.wrapping_sub(data[x]), + None => *byte, + }); + } else { + buf.push(match i.checked_sub(bpp) { + Some(x) => byte.wrapping_sub(paeth_predictor( + data[x], + last_line[i], + last_line[x], + )), + None => byte.wrapping_sub(last_line[i]), + }); + }; + } + } + _ => unreachable!(), } - _ => return Err(PngError::InvalidData), } - Ok(()) + + pub fn unfilter_line( + self, + bpp: usize, + data: &[u8], + last_line: &[u8], + buf: &mut Vec, + ) -> Result<(), PngError> { + buf.clear(); + buf.reserve(data.len()); + assert!(data.len() >= bpp); + assert_eq!(data.len(), last_line.len()); + match self { + Self::None => { + buf.extend_from_slice(data); + } + Self::Sub => { + for (i, &cur) in data.iter().enumerate() { + let prev_byte = i.checked_sub(bpp).and_then(|x| buf.get(x).copied()); + buf.push(match prev_byte { + Some(b) => cur.wrapping_add(b), + None => cur, + }); + } + } + Self::Up => { + buf.extend( + data.iter() + .zip(last_line) + .map(|(&cur, &last)| cur.wrapping_add(last)), + ); + } + Self::Average => { + for (i, (&cur, &last)) in data.iter().zip(last_line).enumerate() { + let prev_byte = i.checked_sub(bpp).and_then(|x| buf.get(x).copied()); + buf.push(match prev_byte { + Some(b) => cur.wrapping_add(((u16::from(b) + u16::from(last)) >> 1) as u8), + None => cur.wrapping_add(last >> 1), + }); + } + } + Self::Paeth => { + for (i, (&cur, &up)) in data.iter().zip(last_line).enumerate() { + buf.push( + match i + .checked_sub(bpp) + .map(|x| (buf.get(x).copied(), last_line.get(x).copied())) + { + Some((Some(left), Some(left_up))) => { + cur.wrapping_add(paeth_predictor(left, up, left_up)) + } + _ => cur.wrapping_add(up), + }, + ); + } + } + _ => return Err(PngError::InvalidData), + } + Ok(()) + } } fn paeth_predictor(a: u8, b: u8, c: u8) -> u8 { diff --git a/src/lib.rs b/src/lib.rs index fc57e16f..899640da 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -45,6 +45,7 @@ use std::time::{Duration, Instant}; pub use crate::colors::AlphaOptim; pub use crate::deflate::Deflaters; pub use crate::error::PngError; +pub use crate::filters::RowFilter; pub use crate::headers::Headers; pub use indexmap::{IndexMap, IndexSet}; @@ -149,7 +150,7 @@ pub struct Options { /// Which filters to try on the file (0-5) /// /// Default: `0,5` - pub filter: IndexSet, + pub filter: IndexSet, /// Whether to change the interlacing type of the file. /// /// `None` will not change the current interlacing type. @@ -253,9 +254,10 @@ impl Options { } fn apply_preset_3(mut self) -> Self { - for i in 1..=4 { - self.filter.insert(i); - } + self.filter.insert(RowFilter::Sub); + self.filter.insert(RowFilter::Up); + self.filter.insert(RowFilter::Average); + self.filter.insert(RowFilter::Paeth); self } @@ -292,8 +294,8 @@ impl Default for Options { fn default() -> Options { // Default settings based on -o 2 from the CLI interface let mut filter = IndexSet::new(); - filter.insert(0); - filter.insert(5); + filter.insert(RowFilter::None); + filter.insert(RowFilter::MinSum); let mut compression = IndexSet::new(); compression.insert(11); // We always need NoOp to be present @@ -465,7 +467,7 @@ pub fn optimize_from_memory(data: &[u8], opts: &Options) -> PngResult> { #[derive(Debug, PartialEq, PartialOrd, Clone, Copy)] /// Defines options to be used for a single compression trial struct TrialOptions { - pub filter: u8, + pub filter: RowFilter, pub compression: u8, } @@ -511,9 +513,9 @@ fn optimize_png( let use_filter = if png.raw.ihdr.bit_depth.as_u8() >= 8 && png.raw.ihdr.color_type != colors::ColorType::Indexed { - 5 + RowFilter::MinSum } else { - 0 + RowFilter::None }; if filter.is_empty() { filter.insert(use_filter); @@ -570,7 +572,7 @@ fn optimize_png( info!("Trying: {} combinations", results.len()); - let filters: IndexMap> = filter + let filters: IndexMap> = filter .par_iter() .with_max_len(1) .map(|f| { @@ -601,7 +603,7 @@ fn optimize_png( Ok(n) => n, Err(PngError::DeflatedDataTooLong(max)) => { debug!( - " zc = {} f = {} >{} bytes", + " zc = {} f = {} >{} bytes", trial.compression, trial.filter, max, ); return None; @@ -614,7 +616,7 @@ fn optimize_png( best_size.set_min(new_size); debug!( - " zc = {} f = {} {} bytes", + " zc = {} f = {} {} bytes", trial.compression, trial.filter, new_idat.len() @@ -638,7 +640,7 @@ fn optimize_png( png.idat_data = idat_data; info!("Found better combination:"); info!( - " zc = {} f = {} {} bytes", + " zc = {} f = {} {} bytes", opts.compression, opts.filter, png.idat_data.len() diff --git a/src/main.rs b/src/main.rs index 1ac6f70f..ddbcc118 100644 --- a/src/main.rs +++ b/src/main.rs @@ -20,6 +20,7 @@ use oxipng::AlphaOptim; use oxipng::Deflaters; use oxipng::Headers; use oxipng::Options; +use oxipng::RowFilter; use oxipng::{InFile, OutFile}; use std::fs::DirBuilder; #[cfg(feature = "zopfli")] @@ -168,11 +169,15 @@ fn main() { ) .arg( Arg::new("filters") - .help("PNG delta filters (0-5) - Default: 0,5") + .help(&*format!( + "PNG delta filters (0-{}) - Default: 0,{}", + RowFilter::LAST, + RowFilter::MinSum as u8 + )) .short('f') .long("filters") .takes_value(true) - .validator(|x| match parse_numeric_range_opts(x, 0, 5) { + .validator(|x| match parse_numeric_range_opts(x, 0, RowFilter::LAST) { Ok(_) => Ok(()), Err(_) => Err("Invalid option for filters".to_owned()), }), @@ -381,7 +386,10 @@ fn parse_opts_into_struct( } if let Some(x) = matches.value_of("filters") { - opts.filter = parse_numeric_range_opts(x, 0, 5).unwrap(); + opts.filter.clear(); + for f in parse_numeric_range_opts(x, 0, RowFilter::LAST).unwrap() { + opts.filter.insert(RowFilter::try_from(f).unwrap()); + } } if let Some(x) = matches.value_of("timeout") { diff --git a/src/png/mod.rs b/src/png/mod.rs index 2d1adace..d6697298 100644 --- a/src/png/mod.rs +++ b/src/png/mod.rs @@ -13,10 +13,6 @@ use std::iter::Iterator; use std::path::Path; use std::sync::Arc; -/// Must use normal (lazy) compression, as faster ones (greedy) are not representative -pub(crate) const STD_COMPRESSION: u8 = 5; -pub(crate) const STD_FILTERS: [u8; 2] = [0, 5]; - pub(crate) mod scan_lines; use self::scan_lines::{ScanLines, ScanLinesMut}; @@ -292,7 +288,8 @@ impl PngImage { last_pass = line.pass; } last_line.resize(line.data.len(), 0); - unfilter_line(line.filter, bpp, line.data, &last_line, &mut unfiltered_buf)?; + let filter = RowFilter::try_from(line.filter).map_err(|_| PngError::InvalidData)?; + filter.unfilter_line(bpp, line.data, &last_line, &mut unfiltered_buf)?; unfiltered.push(0); unfiltered.extend_from_slice(&unfiltered_buf); std::mem::swap(&mut last_line, &mut unfiltered_buf); @@ -302,13 +299,7 @@ impl PngImage { } /// Apply the specified filter type to all rows in the image - /// 0: None - /// 1: Sub - /// 2: Up - /// 3: Average - /// 4: Paeth - /// 5: All (heuristically pick the best filter for each line) - pub fn filter_image(&self, filter: u8) -> Vec { + pub fn filter_image(&self, filter: RowFilter) -> Vec { let mut filtered = Vec::with_capacity(self.data.len()); let bpp = ((self.ihdr.bit_depth.as_u8() * self.channels_per_pixel() + 7) / 8) as usize; let mut last_line: &[u8] = &[]; @@ -320,42 +311,44 @@ impl PngImage { last_line = &[]; } match filter { - 0 | 1 | 2 | 3 | 4 => { - let filter = if last_pass == line.pass || filter <= 1 { - filter - } else { - 0 - }; - filtered.push(filter); - filter_line(filter, bpp, line.data, last_line, &mut f_buf); - filtered.extend_from_slice(&f_buf); - } - 5 => { + RowFilter::MinSum => { // Heuristically guess best filter per line // Uses MSAD algorithm mentioned in libpng reference docs // http://www.libpng.org/pub/png/book/chapter09.html - let mut best_filter = 0; + let mut best_filter = RowFilter::None; let mut best_line = Vec::new(); let mut best_size = u64::MAX; - // Avoid vertical filtering on first line of each interlacing pass - for filter in if last_pass == line.pass { 0..5 } else { 0..2 } { - filter_line(filter, bpp, line.data, last_line, &mut f_buf); + for try_filter in RowFilter::STANDARD { + // Avoid vertical filtering on first line of each interlacing pass + if last_pass != line.pass && try_filter > RowFilter::Sub { + continue; + } + try_filter.filter_line(bpp, line.data, last_line, &mut f_buf); let size = f_buf.iter().fold(0_u64, |acc, &x| { let signed = x as i8; acc + i16::from(signed).unsigned_abs() as u64 }); if size < best_size { best_size = size; - best_filter = filter; + best_filter = try_filter; std::mem::swap(&mut best_line, &mut f_buf); } f_buf.clear() //discard buffer, and start again } - filtered.push(best_filter); + filtered.push(best_filter as u8); filtered.extend_from_slice(&best_line); } - _ => unreachable!(), + _ => { + let filter = if last_pass == line.pass || filter <= RowFilter::Sub { + filter + } else { + RowFilter::None + }; + filtered.push(filter as u8); + filter.filter_line(bpp, line.data, last_line, &mut f_buf); + filtered.extend_from_slice(&f_buf); + } } last_line = line.data; last_pass = line.pass; diff --git a/tests/filters.rs b/tests/filters.rs index 4da00a8c..e1dbad40 100644 --- a/tests/filters.rs +++ b/tests/filters.rs @@ -1,5 +1,5 @@ use indexmap::IndexSet; -use oxipng::internal_tests::*; +use oxipng::{internal_tests::*, RowFilter}; use oxipng::{InFile, OutFile}; use std::fs::remove_file; use std::path::Path; @@ -11,7 +11,7 @@ fn get_opts(input: &Path) -> (OutFile, oxipng::Options) { ..Default::default() }; let mut filter = IndexSet::new(); - filter.insert(0); + filter.insert(RowFilter::None); options.filter = filter; ( @@ -22,7 +22,7 @@ fn get_opts(input: &Path) -> (OutFile, oxipng::Options) { fn test_it_converts( input: &str, - filter: u8, + filter: RowFilter, color_type_in: ColorType, bit_depth_in: BitDepth, color_type_out: ColorType, @@ -67,7 +67,7 @@ fn test_it_converts( fn filter_0_for_rgba_16() { test_it_converts( "tests/files/filter_0_for_rgba_16.png", - 0, + RowFilter::None, ColorType::RGBA, BitDepth::Sixteen, ColorType::RGBA, @@ -79,7 +79,7 @@ fn filter_0_for_rgba_16() { fn filter_1_for_rgba_16() { test_it_converts( "tests/files/filter_1_for_rgba_16.png", - 1, + RowFilter::Sub, ColorType::RGBA, BitDepth::Sixteen, ColorType::RGBA, @@ -91,7 +91,7 @@ fn filter_1_for_rgba_16() { fn filter_2_for_rgba_16() { test_it_converts( "tests/files/filter_2_for_rgba_16.png", - 2, + RowFilter::Up, ColorType::RGBA, BitDepth::Sixteen, ColorType::RGBA, @@ -103,7 +103,7 @@ fn filter_2_for_rgba_16() { fn filter_3_for_rgba_16() { test_it_converts( "tests/files/filter_3_for_rgba_16.png", - 3, + RowFilter::Average, ColorType::RGBA, BitDepth::Sixteen, ColorType::RGBA, @@ -115,7 +115,7 @@ fn filter_3_for_rgba_16() { fn filter_4_for_rgba_16() { test_it_converts( "tests/files/filter_4_for_rgba_16.png", - 4, + RowFilter::Paeth, ColorType::RGBA, BitDepth::Sixteen, ColorType::RGBA, @@ -127,7 +127,7 @@ fn filter_4_for_rgba_16() { fn filter_5_for_rgba_16() { test_it_converts( "tests/files/filter_5_for_rgba_16.png", - 5, + RowFilter::MinSum, ColorType::RGBA, BitDepth::Sixteen, ColorType::RGBA, @@ -139,7 +139,7 @@ fn filter_5_for_rgba_16() { fn filter_0_for_rgba_8() { test_it_converts( "tests/files/filter_0_for_rgba_8.png", - 0, + RowFilter::None, ColorType::RGBA, BitDepth::Eight, ColorType::RGBA, @@ -151,7 +151,7 @@ fn filter_0_for_rgba_8() { fn filter_1_for_rgba_8() { test_it_converts( "tests/files/filter_1_for_rgba_8.png", - 1, + RowFilter::Sub, ColorType::RGBA, BitDepth::Eight, ColorType::RGBA, @@ -163,7 +163,7 @@ fn filter_1_for_rgba_8() { fn filter_2_for_rgba_8() { test_it_converts( "tests/files/filter_2_for_rgba_8.png", - 2, + RowFilter::Up, ColorType::RGBA, BitDepth::Eight, ColorType::RGBA, @@ -175,7 +175,7 @@ fn filter_2_for_rgba_8() { fn filter_3_for_rgba_8() { test_it_converts( "tests/files/filter_3_for_rgba_8.png", - 3, + RowFilter::Average, ColorType::RGBA, BitDepth::Eight, ColorType::RGBA, @@ -187,7 +187,7 @@ fn filter_3_for_rgba_8() { fn filter_4_for_rgba_8() { test_it_converts( "tests/files/filter_4_for_rgba_8.png", - 4, + RowFilter::Paeth, ColorType::RGBA, BitDepth::Eight, ColorType::RGBA, @@ -199,7 +199,7 @@ fn filter_4_for_rgba_8() { fn filter_5_for_rgba_8() { test_it_converts( "tests/files/filter_5_for_rgba_8.png", - 5, + RowFilter::MinSum, ColorType::RGBA, BitDepth::Eight, ColorType::RGBA, @@ -211,7 +211,7 @@ fn filter_5_for_rgba_8() { fn filter_0_for_rgb_16() { test_it_converts( "tests/files/filter_0_for_rgb_16.png", - 0, + RowFilter::None, ColorType::RGB, BitDepth::Sixteen, ColorType::RGB, @@ -223,7 +223,7 @@ fn filter_0_for_rgb_16() { fn filter_1_for_rgb_16() { test_it_converts( "tests/files/filter_1_for_rgb_16.png", - 1, + RowFilter::Sub, ColorType::RGB, BitDepth::Sixteen, ColorType::RGB, @@ -235,7 +235,7 @@ fn filter_1_for_rgb_16() { fn filter_2_for_rgb_16() { test_it_converts( "tests/files/filter_2_for_rgb_16.png", - 2, + RowFilter::Up, ColorType::RGB, BitDepth::Sixteen, ColorType::RGB, @@ -247,7 +247,7 @@ fn filter_2_for_rgb_16() { fn filter_3_for_rgb_16() { test_it_converts( "tests/files/filter_3_for_rgb_16.png", - 3, + RowFilter::Average, ColorType::RGB, BitDepth::Sixteen, ColorType::RGB, @@ -259,7 +259,7 @@ fn filter_3_for_rgb_16() { fn filter_4_for_rgb_16() { test_it_converts( "tests/files/filter_4_for_rgb_16.png", - 4, + RowFilter::Paeth, ColorType::RGB, BitDepth::Sixteen, ColorType::RGB, @@ -271,7 +271,7 @@ fn filter_4_for_rgb_16() { fn filter_5_for_rgb_16() { test_it_converts( "tests/files/filter_5_for_rgb_16.png", - 5, + RowFilter::MinSum, ColorType::RGB, BitDepth::Sixteen, ColorType::RGB, @@ -283,7 +283,7 @@ fn filter_5_for_rgb_16() { fn filter_0_for_rgb_8() { test_it_converts( "tests/files/filter_0_for_rgb_8.png", - 0, + RowFilter::None, ColorType::RGB, BitDepth::Eight, ColorType::RGB, @@ -295,7 +295,7 @@ fn filter_0_for_rgb_8() { fn filter_1_for_rgb_8() { test_it_converts( "tests/files/filter_1_for_rgb_8.png", - 1, + RowFilter::Sub, ColorType::RGB, BitDepth::Eight, ColorType::RGB, @@ -307,7 +307,7 @@ fn filter_1_for_rgb_8() { fn filter_2_for_rgb_8() { test_it_converts( "tests/files/filter_2_for_rgb_8.png", - 2, + RowFilter::Up, ColorType::RGB, BitDepth::Eight, ColorType::RGB, @@ -319,7 +319,7 @@ fn filter_2_for_rgb_8() { fn filter_3_for_rgb_8() { test_it_converts( "tests/files/filter_3_for_rgb_8.png", - 3, + RowFilter::Average, ColorType::RGB, BitDepth::Eight, ColorType::RGB, @@ -331,7 +331,7 @@ fn filter_3_for_rgb_8() { fn filter_4_for_rgb_8() { test_it_converts( "tests/files/filter_4_for_rgb_8.png", - 4, + RowFilter::Paeth, ColorType::RGB, BitDepth::Eight, ColorType::RGB, @@ -343,7 +343,7 @@ fn filter_4_for_rgb_8() { fn filter_5_for_rgb_8() { test_it_converts( "tests/files/filter_5_for_rgb_8.png", - 5, + RowFilter::MinSum, ColorType::RGB, BitDepth::Eight, ColorType::RGB, @@ -355,7 +355,7 @@ fn filter_5_for_rgb_8() { fn filter_0_for_grayscale_alpha_16() { test_it_converts( "tests/files/filter_0_for_grayscale_alpha_16.png", - 0, + RowFilter::None, ColorType::GrayscaleAlpha, BitDepth::Sixteen, ColorType::GrayscaleAlpha, @@ -367,7 +367,7 @@ fn filter_0_for_grayscale_alpha_16() { fn filter_1_for_grayscale_alpha_16() { test_it_converts( "tests/files/filter_1_for_grayscale_alpha_16.png", - 1, + RowFilter::Sub, ColorType::GrayscaleAlpha, BitDepth::Sixteen, ColorType::GrayscaleAlpha, @@ -379,7 +379,7 @@ fn filter_1_for_grayscale_alpha_16() { fn filter_2_for_grayscale_alpha_16() { test_it_converts( "tests/files/filter_2_for_grayscale_alpha_16.png", - 2, + RowFilter::Up, ColorType::GrayscaleAlpha, BitDepth::Sixteen, ColorType::GrayscaleAlpha, @@ -391,7 +391,7 @@ fn filter_2_for_grayscale_alpha_16() { fn filter_3_for_grayscale_alpha_16() { test_it_converts( "tests/files/filter_3_for_grayscale_alpha_16.png", - 3, + RowFilter::Average, ColorType::GrayscaleAlpha, BitDepth::Sixteen, ColorType::GrayscaleAlpha, @@ -403,7 +403,7 @@ fn filter_3_for_grayscale_alpha_16() { fn filter_4_for_grayscale_alpha_16() { test_it_converts( "tests/files/filter_4_for_grayscale_alpha_16.png", - 4, + RowFilter::Paeth, ColorType::GrayscaleAlpha, BitDepth::Sixteen, ColorType::GrayscaleAlpha, @@ -415,7 +415,7 @@ fn filter_4_for_grayscale_alpha_16() { fn filter_5_for_grayscale_alpha_16() { test_it_converts( "tests/files/filter_5_for_grayscale_alpha_16.png", - 5, + RowFilter::MinSum, ColorType::GrayscaleAlpha, BitDepth::Sixteen, ColorType::GrayscaleAlpha, @@ -427,7 +427,7 @@ fn filter_5_for_grayscale_alpha_16() { fn filter_0_for_grayscale_alpha_8() { test_it_converts( "tests/files/filter_0_for_grayscale_alpha_8.png", - 0, + RowFilter::None, ColorType::GrayscaleAlpha, BitDepth::Eight, ColorType::GrayscaleAlpha, @@ -439,7 +439,7 @@ fn filter_0_for_grayscale_alpha_8() { fn filter_1_for_grayscale_alpha_8() { test_it_converts( "tests/files/filter_1_for_grayscale_alpha_8.png", - 1, + RowFilter::Sub, ColorType::GrayscaleAlpha, BitDepth::Eight, ColorType::GrayscaleAlpha, @@ -451,7 +451,7 @@ fn filter_1_for_grayscale_alpha_8() { fn filter_2_for_grayscale_alpha_8() { test_it_converts( "tests/files/filter_2_for_grayscale_alpha_8.png", - 2, + RowFilter::Up, ColorType::GrayscaleAlpha, BitDepth::Eight, ColorType::GrayscaleAlpha, @@ -463,7 +463,7 @@ fn filter_2_for_grayscale_alpha_8() { fn filter_3_for_grayscale_alpha_8() { test_it_converts( "tests/files/filter_3_for_grayscale_alpha_8.png", - 3, + RowFilter::Average, ColorType::GrayscaleAlpha, BitDepth::Eight, ColorType::GrayscaleAlpha, @@ -475,7 +475,7 @@ fn filter_3_for_grayscale_alpha_8() { fn filter_4_for_grayscale_alpha_8() { test_it_converts( "tests/files/filter_4_for_grayscale_alpha_8.png", - 4, + RowFilter::Paeth, ColorType::GrayscaleAlpha, BitDepth::Eight, ColorType::GrayscaleAlpha, @@ -487,7 +487,7 @@ fn filter_4_for_grayscale_alpha_8() { fn filter_5_for_grayscale_alpha_8() { test_it_converts( "tests/files/filter_5_for_grayscale_alpha_8.png", - 5, + RowFilter::MinSum, ColorType::GrayscaleAlpha, BitDepth::Eight, ColorType::GrayscaleAlpha, @@ -499,7 +499,7 @@ fn filter_5_for_grayscale_alpha_8() { fn filter_0_for_grayscale_16() { test_it_converts( "tests/files/filter_0_for_grayscale_16.png", - 0, + RowFilter::None, ColorType::Grayscale, BitDepth::Sixteen, ColorType::Grayscale, @@ -511,7 +511,7 @@ fn filter_0_for_grayscale_16() { fn filter_1_for_grayscale_16() { test_it_converts( "tests/files/filter_1_for_grayscale_16.png", - 1, + RowFilter::Sub, ColorType::Grayscale, BitDepth::Sixteen, ColorType::Grayscale, @@ -523,7 +523,7 @@ fn filter_1_for_grayscale_16() { fn filter_2_for_grayscale_16() { test_it_converts( "tests/files/filter_2_for_grayscale_16.png", - 2, + RowFilter::Up, ColorType::Grayscale, BitDepth::Sixteen, ColorType::Grayscale, @@ -535,7 +535,7 @@ fn filter_2_for_grayscale_16() { fn filter_3_for_grayscale_16() { test_it_converts( "tests/files/filter_3_for_grayscale_16.png", - 3, + RowFilter::Average, ColorType::Grayscale, BitDepth::Sixteen, ColorType::Grayscale, @@ -547,7 +547,7 @@ fn filter_3_for_grayscale_16() { fn filter_4_for_grayscale_16() { test_it_converts( "tests/files/filter_4_for_grayscale_16.png", - 4, + RowFilter::Paeth, ColorType::Grayscale, BitDepth::Sixteen, ColorType::Grayscale, @@ -559,7 +559,7 @@ fn filter_4_for_grayscale_16() { fn filter_5_for_grayscale_16() { test_it_converts( "tests/files/filter_5_for_grayscale_16.png", - 5, + RowFilter::MinSum, ColorType::Grayscale, BitDepth::Sixteen, ColorType::Grayscale, @@ -571,7 +571,7 @@ fn filter_5_for_grayscale_16() { fn filter_0_for_grayscale_8() { test_it_converts( "tests/files/filter_0_for_grayscale_8.png", - 0, + RowFilter::None, ColorType::Grayscale, BitDepth::Eight, ColorType::Grayscale, @@ -583,7 +583,7 @@ fn filter_0_for_grayscale_8() { fn filter_1_for_grayscale_8() { test_it_converts( "tests/files/filter_1_for_grayscale_8.png", - 1, + RowFilter::Sub, ColorType::Grayscale, BitDepth::Eight, ColorType::Grayscale, @@ -595,7 +595,7 @@ fn filter_1_for_grayscale_8() { fn filter_2_for_grayscale_8() { test_it_converts( "tests/files/filter_2_for_grayscale_8.png", - 2, + RowFilter::Up, ColorType::Grayscale, BitDepth::Eight, ColorType::Grayscale, @@ -607,7 +607,7 @@ fn filter_2_for_grayscale_8() { fn filter_3_for_grayscale_8() { test_it_converts( "tests/files/filter_3_for_grayscale_8.png", - 3, + RowFilter::Average, ColorType::Grayscale, BitDepth::Eight, ColorType::Grayscale, @@ -619,7 +619,7 @@ fn filter_3_for_grayscale_8() { fn filter_4_for_grayscale_8() { test_it_converts( "tests/files/filter_4_for_grayscale_8.png", - 4, + RowFilter::Paeth, ColorType::Grayscale, BitDepth::Eight, ColorType::Grayscale, @@ -631,7 +631,7 @@ fn filter_4_for_grayscale_8() { fn filter_5_for_grayscale_8() { test_it_converts( "tests/files/filter_5_for_grayscale_8.png", - 5, + RowFilter::MinSum, ColorType::Grayscale, BitDepth::Eight, ColorType::Grayscale, @@ -643,7 +643,7 @@ fn filter_5_for_grayscale_8() { fn filter_0_for_palette_4() { test_it_converts( "tests/files/filter_0_for_palette_4.png", - 0, + RowFilter::None, ColorType::Indexed, BitDepth::Four, ColorType::Indexed, @@ -655,7 +655,7 @@ fn filter_0_for_palette_4() { fn filter_1_for_palette_4() { test_it_converts( "tests/files/filter_1_for_palette_4.png", - 1, + RowFilter::Sub, ColorType::Indexed, BitDepth::Four, ColorType::Indexed, @@ -667,7 +667,7 @@ fn filter_1_for_palette_4() { fn filter_2_for_palette_4() { test_it_converts( "tests/files/filter_2_for_palette_4.png", - 2, + RowFilter::Up, ColorType::Indexed, BitDepth::Four, ColorType::Indexed, @@ -679,7 +679,7 @@ fn filter_2_for_palette_4() { fn filter_3_for_palette_4() { test_it_converts( "tests/files/filter_3_for_palette_4.png", - 3, + RowFilter::Average, ColorType::Indexed, BitDepth::Four, ColorType::Indexed, @@ -691,7 +691,7 @@ fn filter_3_for_palette_4() { fn filter_4_for_palette_4() { test_it_converts( "tests/files/filter_4_for_palette_4.png", - 4, + RowFilter::Paeth, ColorType::Indexed, BitDepth::Four, ColorType::Indexed, @@ -703,7 +703,7 @@ fn filter_4_for_palette_4() { fn filter_5_for_palette_4() { test_it_converts( "tests/files/filter_5_for_palette_4.png", - 5, + RowFilter::MinSum, ColorType::Indexed, BitDepth::Four, ColorType::Indexed, @@ -715,7 +715,7 @@ fn filter_5_for_palette_4() { fn filter_0_for_palette_2() { test_it_converts( "tests/files/filter_0_for_palette_2.png", - 0, + RowFilter::None, ColorType::Indexed, BitDepth::Two, ColorType::Indexed, @@ -727,7 +727,7 @@ fn filter_0_for_palette_2() { fn filter_1_for_palette_2() { test_it_converts( "tests/files/filter_1_for_palette_2.png", - 1, + RowFilter::Sub, ColorType::Indexed, BitDepth::Two, ColorType::Indexed, @@ -739,7 +739,7 @@ fn filter_1_for_palette_2() { fn filter_2_for_palette_2() { test_it_converts( "tests/files/filter_2_for_palette_2.png", - 2, + RowFilter::Up, ColorType::Indexed, BitDepth::Two, ColorType::Indexed, @@ -751,7 +751,7 @@ fn filter_2_for_palette_2() { fn filter_3_for_palette_2() { test_it_converts( "tests/files/filter_3_for_palette_2.png", - 3, + RowFilter::Average, ColorType::Indexed, BitDepth::Two, ColorType::Indexed, @@ -763,7 +763,7 @@ fn filter_3_for_palette_2() { fn filter_4_for_palette_2() { test_it_converts( "tests/files/filter_4_for_palette_2.png", - 4, + RowFilter::Paeth, ColorType::Indexed, BitDepth::Two, ColorType::Indexed, @@ -775,7 +775,7 @@ fn filter_4_for_palette_2() { fn filter_5_for_palette_2() { test_it_converts( "tests/files/filter_5_for_palette_2.png", - 5, + RowFilter::MinSum, ColorType::Indexed, BitDepth::Two, ColorType::Indexed, @@ -787,7 +787,7 @@ fn filter_5_for_palette_2() { fn filter_0_for_palette_1() { test_it_converts( "tests/files/filter_0_for_palette_1.png", - 0, + RowFilter::None, ColorType::Indexed, BitDepth::One, ColorType::Indexed, @@ -799,7 +799,7 @@ fn filter_0_for_palette_1() { fn filter_1_for_palette_1() { test_it_converts( "tests/files/filter_1_for_palette_1.png", - 1, + RowFilter::Sub, ColorType::Indexed, BitDepth::One, ColorType::Indexed, @@ -811,7 +811,7 @@ fn filter_1_for_palette_1() { fn filter_2_for_palette_1() { test_it_converts( "tests/files/filter_2_for_palette_1.png", - 2, + RowFilter::Up, ColorType::Indexed, BitDepth::One, ColorType::Indexed, @@ -823,7 +823,7 @@ fn filter_2_for_palette_1() { fn filter_3_for_palette_1() { test_it_converts( "tests/files/filter_3_for_palette_1.png", - 3, + RowFilter::Average, ColorType::Indexed, BitDepth::One, ColorType::Indexed, @@ -835,7 +835,7 @@ fn filter_3_for_palette_1() { fn filter_4_for_palette_1() { test_it_converts( "tests/files/filter_4_for_palette_1.png", - 4, + RowFilter::Paeth, ColorType::Indexed, BitDepth::One, ColorType::Indexed, @@ -847,7 +847,7 @@ fn filter_4_for_palette_1() { fn filter_5_for_palette_1() { test_it_converts( "tests/files/filter_5_for_palette_1.png", - 5, + RowFilter::MinSum, ColorType::Indexed, BitDepth::One, ColorType::Indexed, diff --git a/tests/flags.rs b/tests/flags.rs index 9bacf8e0..f24f7227 100644 --- a/tests/flags.rs +++ b/tests/flags.rs @@ -1,5 +1,5 @@ use indexmap::IndexSet; -use oxipng::internal_tests::*; +use oxipng::{internal_tests::*, RowFilter}; use oxipng::{InFile, OutFile}; #[cfg(feature = "filetime")] use std::cell::RefCell; @@ -16,7 +16,7 @@ fn get_opts(input: &Path) -> (OutFile, oxipng::Options) { ..Default::default() }; let mut filter = IndexSet::new(); - filter.insert(0); + filter.insert(RowFilter::None); options.filter = filter; ( @@ -173,7 +173,7 @@ fn verbose_mode() { assert_eq!(logs.len(), 1); logs.sort(); for (i, log) in logs.into_iter().enumerate() { - let expected_prefix = format!(" zc = 11 f = 0 "); + let expected_prefix = format!(" zc = 11 f = None "); assert!( log.starts_with(&expected_prefix), "logs[{}] = {:?} doesn't start with {:?}", @@ -454,7 +454,7 @@ fn interlaced_0_to_1_other_filter_mode() { let (output, mut opts) = get_opts(&input); opts.interlace = Some(1); let mut filter = IndexSet::new(); - filter.insert(4); + filter.insert(RowFilter::Paeth); opts.filter = filter; let png = PngData::new(&input, opts.fix_errors).unwrap(); diff --git a/tests/interlaced.rs b/tests/interlaced.rs index 80610c94..d6b3deb5 100644 --- a/tests/interlaced.rs +++ b/tests/interlaced.rs @@ -1,5 +1,5 @@ use indexmap::IndexSet; -use oxipng::internal_tests::*; +use oxipng::{internal_tests::*, RowFilter}; use oxipng::{InFile, OutFile}; use std::fs::remove_file; use std::path::Path; @@ -11,7 +11,7 @@ fn get_opts(input: &Path) -> (OutFile, oxipng::Options) { ..Default::default() }; let mut filter = IndexSet::new(); - filter.insert(0); + filter.insert(RowFilter::None); options.filter = filter; ( diff --git a/tests/reduction.rs b/tests/reduction.rs index 0951c628..2d084ad9 100644 --- a/tests/reduction.rs +++ b/tests/reduction.rs @@ -1,5 +1,5 @@ use indexmap::IndexSet; -use oxipng::internal_tests::*; +use oxipng::{internal_tests::*, RowFilter}; use oxipng::{InFile, OutFile}; use std::fs::remove_file; use std::path::Path; @@ -11,7 +11,7 @@ fn get_opts(input: &Path) -> (OutFile, oxipng::Options) { ..Default::default() }; let mut filter = IndexSet::new(); - filter.insert(0); + filter.insert(RowFilter::None); options.filter = filter; ( diff --git a/tests/regression.rs b/tests/regression.rs index 539ec88f..de63039f 100644 --- a/tests/regression.rs +++ b/tests/regression.rs @@ -1,5 +1,5 @@ use indexmap::IndexSet; -use oxipng::internal_tests::*; +use oxipng::{internal_tests::*, RowFilter}; use oxipng::{InFile, OutFile}; use std::fs::remove_file; use std::path::Path; @@ -11,7 +11,7 @@ fn get_opts(input: &Path) -> (OutFile, oxipng::Options) { ..Default::default() }; let mut filter = IndexSet::new(); - filter.insert(0); + filter.insert(RowFilter::None); options.filter = filter; ( @@ -288,7 +288,7 @@ fn issue_92_filter_0() { fn issue_92_filter_5() { let input = "tests/files/issue-92.png"; let (_, mut opts) = get_opts(Path::new(input)); - opts.filter = [5].iter().cloned().collect(); + opts.filter = [RowFilter::MinSum].iter().cloned().collect(); let output = OutFile::Path(Some(Path::new(input).with_extension("-f5-out.png"))); test_it_converts(