Split RowFilter and FilterStrategy

This commit is contained in:
Andrew 2025-05-20 08:47:19 +12:00
parent ff9beb00fe
commit 682b5d9ad0
16 changed files with 297 additions and 203 deletions

View file

@ -13,7 +13,10 @@ fn filters_16_bits_filter_0(b: &mut Bencher) {
let input = test::black_box(PathBuf::from("tests/files/rgb_16_should_be_rgb_16.png")); let input = test::black_box(PathBuf::from("tests/files/rgb_16_should_be_rgb_16.png"));
let png = PngData::new(&input, &Options::default()).unwrap(); let png = PngData::new(&input, &Options::default()).unwrap();
b.iter(|| png.raw.filter_image(RowFilter::None, false)); b.iter(|| {
png.raw
.filter_image(FilterStrategy::Basic(RowFilter::None), false)
});
} }
#[bench] #[bench]
@ -21,7 +24,10 @@ fn filters_8_bits_filter_0(b: &mut Bencher) {
let input = test::black_box(PathBuf::from("tests/files/rgb_8_should_be_rgb_8.png")); let input = test::black_box(PathBuf::from("tests/files/rgb_8_should_be_rgb_8.png"));
let png = PngData::new(&input, &Options::default()).unwrap(); let png = PngData::new(&input, &Options::default()).unwrap();
b.iter(|| png.raw.filter_image(RowFilter::None, false)); b.iter(|| {
png.raw
.filter_image(FilterStrategy::Basic(RowFilter::None), false)
});
} }
#[bench] #[bench]
@ -31,7 +37,10 @@ fn filters_4_bits_filter_0(b: &mut Bencher) {
)); ));
let png = PngData::new(&input, &Options::default()).unwrap(); let png = PngData::new(&input, &Options::default()).unwrap();
b.iter(|| png.raw.filter_image(RowFilter::None, false)); b.iter(|| {
png.raw
.filter_image(FilterStrategy::Basic(RowFilter::None), false)
});
} }
#[bench] #[bench]
@ -41,7 +50,10 @@ fn filters_2_bits_filter_0(b: &mut Bencher) {
)); ));
let png = PngData::new(&input, &Options::default()).unwrap(); let png = PngData::new(&input, &Options::default()).unwrap();
b.iter(|| png.raw.filter_image(RowFilter::None, false)); b.iter(|| {
png.raw
.filter_image(FilterStrategy::Basic(RowFilter::None), false)
});
} }
#[bench] #[bench]
@ -51,7 +63,10 @@ fn filters_1_bits_filter_0(b: &mut Bencher) {
)); ));
let png = PngData::new(&input, &Options::default()).unwrap(); let png = PngData::new(&input, &Options::default()).unwrap();
b.iter(|| png.raw.filter_image(RowFilter::None, false)); b.iter(|| {
png.raw
.filter_image(FilterStrategy::Basic(RowFilter::None), false)
});
} }
#[bench] #[bench]
@ -59,7 +74,10 @@ fn filters_16_bits_filter_1(b: &mut Bencher) {
let input = test::black_box(PathBuf::from("tests/files/rgb_16_should_be_rgb_16.png")); let input = test::black_box(PathBuf::from("tests/files/rgb_16_should_be_rgb_16.png"));
let png = PngData::new(&input, &Options::default()).unwrap(); let png = PngData::new(&input, &Options::default()).unwrap();
b.iter(|| png.raw.filter_image(RowFilter::Sub, false)); b.iter(|| {
png.raw
.filter_image(FilterStrategy::Basic(RowFilter::Sub), false)
});
} }
#[bench] #[bench]
@ -67,7 +85,10 @@ fn filters_8_bits_filter_1(b: &mut Bencher) {
let input = test::black_box(PathBuf::from("tests/files/rgb_8_should_be_rgb_8.png")); let input = test::black_box(PathBuf::from("tests/files/rgb_8_should_be_rgb_8.png"));
let png = PngData::new(&input, &Options::default()).unwrap(); let png = PngData::new(&input, &Options::default()).unwrap();
b.iter(|| png.raw.filter_image(RowFilter::Sub, false)); b.iter(|| {
png.raw
.filter_image(FilterStrategy::Basic(RowFilter::Sub), false)
});
} }
#[bench] #[bench]
@ -77,7 +98,10 @@ fn filters_4_bits_filter_1(b: &mut Bencher) {
)); ));
let png = PngData::new(&input, &Options::default()).unwrap(); let png = PngData::new(&input, &Options::default()).unwrap();
b.iter(|| png.raw.filter_image(RowFilter::Sub, false)); b.iter(|| {
png.raw
.filter_image(FilterStrategy::Basic(RowFilter::Sub), false)
});
} }
#[bench] #[bench]
@ -87,7 +111,10 @@ fn filters_2_bits_filter_1(b: &mut Bencher) {
)); ));
let png = PngData::new(&input, &Options::default()).unwrap(); let png = PngData::new(&input, &Options::default()).unwrap();
b.iter(|| png.raw.filter_image(RowFilter::Sub, false)); b.iter(|| {
png.raw
.filter_image(FilterStrategy::Basic(RowFilter::Sub), false)
});
} }
#[bench] #[bench]
@ -97,7 +124,10 @@ fn filters_1_bits_filter_1(b: &mut Bencher) {
)); ));
let png = PngData::new(&input, &Options::default()).unwrap(); let png = PngData::new(&input, &Options::default()).unwrap();
b.iter(|| png.raw.filter_image(RowFilter::Sub, false)); b.iter(|| {
png.raw
.filter_image(FilterStrategy::Basic(RowFilter::Sub), false)
});
} }
#[bench] #[bench]
@ -105,7 +135,10 @@ fn filters_16_bits_filter_2(b: &mut Bencher) {
let input = test::black_box(PathBuf::from("tests/files/rgb_16_should_be_rgb_16.png")); let input = test::black_box(PathBuf::from("tests/files/rgb_16_should_be_rgb_16.png"));
let png = PngData::new(&input, &Options::default()).unwrap(); let png = PngData::new(&input, &Options::default()).unwrap();
b.iter(|| png.raw.filter_image(RowFilter::Up, false)); b.iter(|| {
png.raw
.filter_image(FilterStrategy::Basic(RowFilter::Up), false)
});
} }
#[bench] #[bench]
@ -113,7 +146,10 @@ fn filters_8_bits_filter_2(b: &mut Bencher) {
let input = test::black_box(PathBuf::from("tests/files/rgb_8_should_be_rgb_8.png")); let input = test::black_box(PathBuf::from("tests/files/rgb_8_should_be_rgb_8.png"));
let png = PngData::new(&input, &Options::default()).unwrap(); let png = PngData::new(&input, &Options::default()).unwrap();
b.iter(|| png.raw.filter_image(RowFilter::Up, false)); b.iter(|| {
png.raw
.filter_image(FilterStrategy::Basic(RowFilter::Up), false)
});
} }
#[bench] #[bench]
@ -123,7 +159,10 @@ fn filters_4_bits_filter_2(b: &mut Bencher) {
)); ));
let png = PngData::new(&input, &Options::default()).unwrap(); let png = PngData::new(&input, &Options::default()).unwrap();
b.iter(|| png.raw.filter_image(RowFilter::Up, false)); b.iter(|| {
png.raw
.filter_image(FilterStrategy::Basic(RowFilter::Up), false)
});
} }
#[bench] #[bench]
@ -133,7 +172,10 @@ fn filters_2_bits_filter_2(b: &mut Bencher) {
)); ));
let png = PngData::new(&input, &Options::default()).unwrap(); let png = PngData::new(&input, &Options::default()).unwrap();
b.iter(|| png.raw.filter_image(RowFilter::Up, false)); b.iter(|| {
png.raw
.filter_image(FilterStrategy::Basic(RowFilter::Up), false)
});
} }
#[bench] #[bench]
@ -143,7 +185,10 @@ fn filters_1_bits_filter_2(b: &mut Bencher) {
)); ));
let png = PngData::new(&input, &Options::default()).unwrap(); let png = PngData::new(&input, &Options::default()).unwrap();
b.iter(|| png.raw.filter_image(RowFilter::Up, false)); b.iter(|| {
png.raw
.filter_image(FilterStrategy::Basic(RowFilter::Up), false)
});
} }
#[bench] #[bench]
@ -151,7 +196,10 @@ fn filters_16_bits_filter_3(b: &mut Bencher) {
let input = test::black_box(PathBuf::from("tests/files/rgb_16_should_be_rgb_16.png")); let input = test::black_box(PathBuf::from("tests/files/rgb_16_should_be_rgb_16.png"));
let png = PngData::new(&input, &Options::default()).unwrap(); let png = PngData::new(&input, &Options::default()).unwrap();
b.iter(|| png.raw.filter_image(RowFilter::Average, false)); b.iter(|| {
png.raw
.filter_image(FilterStrategy::Basic(RowFilter::Average), false)
});
} }
#[bench] #[bench]
@ -159,7 +207,10 @@ fn filters_8_bits_filter_3(b: &mut Bencher) {
let input = test::black_box(PathBuf::from("tests/files/rgb_8_should_be_rgb_8.png")); let input = test::black_box(PathBuf::from("tests/files/rgb_8_should_be_rgb_8.png"));
let png = PngData::new(&input, &Options::default()).unwrap(); let png = PngData::new(&input, &Options::default()).unwrap();
b.iter(|| png.raw.filter_image(RowFilter::Average, false)); b.iter(|| {
png.raw
.filter_image(FilterStrategy::Basic(RowFilter::Average), false)
});
} }
#[bench] #[bench]
@ -169,7 +220,10 @@ fn filters_4_bits_filter_3(b: &mut Bencher) {
)); ));
let png = PngData::new(&input, &Options::default()).unwrap(); let png = PngData::new(&input, &Options::default()).unwrap();
b.iter(|| png.raw.filter_image(RowFilter::Average, false)); b.iter(|| {
png.raw
.filter_image(FilterStrategy::Basic(RowFilter::Average), false)
});
} }
#[bench] #[bench]
@ -179,7 +233,10 @@ fn filters_2_bits_filter_3(b: &mut Bencher) {
)); ));
let png = PngData::new(&input, &Options::default()).unwrap(); let png = PngData::new(&input, &Options::default()).unwrap();
b.iter(|| png.raw.filter_image(RowFilter::Average, false)); b.iter(|| {
png.raw
.filter_image(FilterStrategy::Basic(RowFilter::Average), false)
});
} }
#[bench] #[bench]
@ -189,7 +246,10 @@ fn filters_1_bits_filter_3(b: &mut Bencher) {
)); ));
let png = PngData::new(&input, &Options::default()).unwrap(); let png = PngData::new(&input, &Options::default()).unwrap();
b.iter(|| png.raw.filter_image(RowFilter::Average, false)); b.iter(|| {
png.raw
.filter_image(FilterStrategy::Basic(RowFilter::Average), false)
});
} }
#[bench] #[bench]
@ -197,7 +257,10 @@ fn filters_16_bits_filter_4(b: &mut Bencher) {
let input = test::black_box(PathBuf::from("tests/files/rgb_16_should_be_rgb_16.png")); let input = test::black_box(PathBuf::from("tests/files/rgb_16_should_be_rgb_16.png"));
let png = PngData::new(&input, &Options::default()).unwrap(); let png = PngData::new(&input, &Options::default()).unwrap();
b.iter(|| png.raw.filter_image(RowFilter::Paeth, false)); b.iter(|| {
png.raw
.filter_image(FilterStrategy::Basic(RowFilter::Paeth), false)
});
} }
#[bench] #[bench]
@ -205,7 +268,10 @@ fn filters_8_bits_filter_4(b: &mut Bencher) {
let input = test::black_box(PathBuf::from("tests/files/rgb_8_should_be_rgb_8.png")); let input = test::black_box(PathBuf::from("tests/files/rgb_8_should_be_rgb_8.png"));
let png = PngData::new(&input, &Options::default()).unwrap(); let png = PngData::new(&input, &Options::default()).unwrap();
b.iter(|| png.raw.filter_image(RowFilter::Paeth, false)); b.iter(|| {
png.raw
.filter_image(FilterStrategy::Basic(RowFilter::Paeth), false)
});
} }
#[bench] #[bench]
@ -215,7 +281,10 @@ fn filters_4_bits_filter_4(b: &mut Bencher) {
)); ));
let png = PngData::new(&input, &Options::default()).unwrap(); let png = PngData::new(&input, &Options::default()).unwrap();
b.iter(|| png.raw.filter_image(RowFilter::Paeth, false)); b.iter(|| {
png.raw
.filter_image(FilterStrategy::Basic(RowFilter::Paeth), false)
});
} }
#[bench] #[bench]
@ -225,7 +294,10 @@ fn filters_2_bits_filter_4(b: &mut Bencher) {
)); ));
let png = PngData::new(&input, &Options::default()).unwrap(); let png = PngData::new(&input, &Options::default()).unwrap();
b.iter(|| png.raw.filter_image(RowFilter::Paeth, false)); b.iter(|| {
png.raw
.filter_image(FilterStrategy::Basic(RowFilter::Paeth), false)
});
} }
#[bench] #[bench]
@ -235,7 +307,10 @@ fn filters_1_bits_filter_4(b: &mut Bencher) {
)); ));
let png = PngData::new(&input, &Options::default()).unwrap(); let png = PngData::new(&input, &Options::default()).unwrap();
b.iter(|| png.raw.filter_image(RowFilter::Paeth, false)); b.iter(|| {
png.raw
.filter_image(FilterStrategy::Basic(RowFilter::Paeth), false)
});
} }
#[bench] #[bench]
@ -243,7 +318,7 @@ fn filters_16_bits_filter_5(b: &mut Bencher) {
let input = test::black_box(PathBuf::from("tests/files/rgb_16_should_be_rgb_16.png")); let input = test::black_box(PathBuf::from("tests/files/rgb_16_should_be_rgb_16.png"));
let png = PngData::new(&input, &Options::default()).unwrap(); let png = PngData::new(&input, &Options::default()).unwrap();
b.iter(|| png.raw.filter_image(RowFilter::MinSum, false)); b.iter(|| png.raw.filter_image(FilterStrategy::MinSum, false));
} }
#[bench] #[bench]
@ -251,7 +326,7 @@ fn filters_8_bits_filter_5(b: &mut Bencher) {
let input = test::black_box(PathBuf::from("tests/files/rgb_8_should_be_rgb_8.png")); let input = test::black_box(PathBuf::from("tests/files/rgb_8_should_be_rgb_8.png"));
let png = PngData::new(&input, &Options::default()).unwrap(); let png = PngData::new(&input, &Options::default()).unwrap();
b.iter(|| png.raw.filter_image(RowFilter::MinSum, false)); b.iter(|| png.raw.filter_image(FilterStrategy::MinSum, false));
} }
#[bench] #[bench]
@ -261,7 +336,7 @@ fn filters_4_bits_filter_5(b: &mut Bencher) {
)); ));
let png = PngData::new(&input, &Options::default()).unwrap(); let png = PngData::new(&input, &Options::default()).unwrap();
b.iter(|| png.raw.filter_image(RowFilter::MinSum, false)); b.iter(|| png.raw.filter_image(FilterStrategy::MinSum, false));
} }
#[bench] #[bench]
@ -271,7 +346,7 @@ fn filters_2_bits_filter_5(b: &mut Bencher) {
)); ));
let png = PngData::new(&input, &Options::default()).unwrap(); let png = PngData::new(&input, &Options::default()).unwrap();
b.iter(|| png.raw.filter_image(RowFilter::MinSum, false)); b.iter(|| png.raw.filter_image(FilterStrategy::MinSum, false));
} }
#[bench] #[bench]
@ -281,5 +356,5 @@ fn filters_1_bits_filter_5(b: &mut Bencher) {
)); ));
let png = PngData::new(&input, &Options::default()).unwrap(); let png = PngData::new(&input, &Options::default()).unwrap();
b.iter(|| png.raw.filter_image(RowFilter::MinSum, false)); b.iter(|| png.raw.filter_image(FilterStrategy::MinSum, false));
} }

View file

@ -13,7 +13,7 @@ fn filters_minsum(b: &mut Bencher) {
let input = test::black_box(PathBuf::from("tests/files/rgb_8_should_be_rgb_8.png")); let input = test::black_box(PathBuf::from("tests/files/rgb_8_should_be_rgb_8.png"));
let png = PngData::new(&input, &Options::default()).unwrap(); let png = PngData::new(&input, &Options::default()).unwrap();
b.iter(|| png.raw.filter_image(RowFilter::MinSum, false)); b.iter(|| png.raw.filter_image(FilterStrategy::MinSum, false));
} }
#[bench] #[bench]
@ -21,7 +21,7 @@ fn filters_entropy(b: &mut Bencher) {
let input = test::black_box(PathBuf::from("tests/files/rgb_8_should_be_rgb_8.png")); let input = test::black_box(PathBuf::from("tests/files/rgb_8_should_be_rgb_8.png"));
let png = PngData::new(&input, &Options::default()).unwrap(); let png = PngData::new(&input, &Options::default()).unwrap();
b.iter(|| png.raw.filter_image(RowFilter::Entropy, false)); b.iter(|| png.raw.filter_image(FilterStrategy::Entropy, false));
} }
#[bench] #[bench]
@ -29,7 +29,7 @@ fn filters_bigrams(b: &mut Bencher) {
let input = test::black_box(PathBuf::from("tests/files/rgb_8_should_be_rgb_8.png")); let input = test::black_box(PathBuf::from("tests/files/rgb_8_should_be_rgb_8.png"));
let png = PngData::new(&input, &Options::default()).unwrap(); let png = PngData::new(&input, &Options::default()).unwrap();
b.iter(|| png.raw.filter_image(RowFilter::Bigrams, false)); b.iter(|| png.raw.filter_image(FilterStrategy::Bigrams, false));
} }
#[bench] #[bench]
@ -37,7 +37,7 @@ fn filters_bigent(b: &mut Bencher) {
let input = test::black_box(PathBuf::from("tests/files/rgb_8_should_be_rgb_8.png")); let input = test::black_box(PathBuf::from("tests/files/rgb_8_should_be_rgb_8.png"));
let png = PngData::new(&input, &Options::default()).unwrap(); let png = PngData::new(&input, &Options::default()).unwrap();
b.iter(|| png.raw.filter_image(RowFilter::BigEnt, false)); b.iter(|| png.raw.filter_image(FilterStrategy::BigEnt, false));
} }
#[bench] #[bench]
@ -45,5 +45,5 @@ fn filters_brute(b: &mut Bencher) {
let input = test::black_box(PathBuf::from("tests/files/rgb_8_should_be_rgb_8.png")); let input = test::black_box(PathBuf::from("tests/files/rgb_8_should_be_rgb_8.png"));
let png = PngData::new(&input, &Options::default()).unwrap(); let png = PngData::new(&input, &Options::default()).unwrap();
b.iter(|| png.raw.filter_image(RowFilter::Brute, false)); b.iter(|| png.raw.filter_image(FilterStrategy::Brute, false));
} }

View file

@ -17,14 +17,16 @@ use rayon::prelude::*;
#[cfg(not(feature = "parallel"))] #[cfg(not(feature = "parallel"))]
use crate::rayon; use crate::rayon;
use crate::{Deadline, PngError, atomicmin::AtomicMin, deflate, filters::RowFilter, png::PngImage}; use crate::{
Deadline, PngError, atomicmin::AtomicMin, deflate, filters::FilterStrategy, png::PngImage,
};
pub(crate) struct Candidate { pub(crate) struct Candidate {
pub image: Arc<PngImage>, pub image: Arc<PngImage>,
pub data: Vec<u8>, pub data: Vec<u8>,
pub data_is_compressed: bool, pub data_is_compressed: bool,
pub estimated_output_size: usize, pub estimated_output_size: usize,
pub filter: RowFilter, pub filter: FilterStrategy,
// For determining tie-breaker // For determining tie-breaker
nth: usize, nth: usize,
} }
@ -44,7 +46,7 @@ impl Candidate {
/// Collect image versions and pick one that compresses best /// Collect image versions and pick one that compresses best
pub(crate) struct Evaluator { pub(crate) struct Evaluator {
deadline: Arc<Deadline>, deadline: Arc<Deadline>,
filters: IndexSet<RowFilter>, filters: IndexSet<FilterStrategy>,
deflater: Deflaters, deflater: Deflaters,
optimize_alpha: bool, optimize_alpha: bool,
final_round: bool, final_round: bool,
@ -62,7 +64,7 @@ pub(crate) struct Evaluator {
impl Evaluator { impl Evaluator {
pub fn new( pub fn new(
deadline: Arc<Deadline>, deadline: Arc<Deadline>,
filters: IndexSet<RowFilter>, filters: IndexSet<FilterStrategy>,
deflater: Deflaters, deflater: Deflaters,
optimize_alpha: bool, optimize_alpha: bool,
final_round: bool, final_round: bool,

View file

@ -1,30 +1,67 @@
use std::{fmt, fmt::Display, mem::transmute}; use std::{fmt, fmt::Display, mem::transmute};
use crate::error::PngError;
/// Filtering strategy for use in [`Options`][crate::Options] /// Filtering strategy for use in [`Options`][crate::Options]
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)]
pub enum FilterStrategy {
/// Same filter for all rows
Basic(RowFilter),
/// Minimum sum of absolute differences
MinSum,
/// Shannon entropy
Entropy,
/// Count of distinct bigrams
Bigrams,
/// Shannon entropy of bigrams
BigEnt,
/// Deflate compression
Brute,
}
impl Display for FilterStrategy {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Basic(filter) => filter.fmt(f),
Self::MinSum => "MinSum".fmt(f),
Self::Entropy => "Entropy".fmt(f),
Self::Bigrams => "Bigrams".fmt(f),
Self::BigEnt => "BigEnt".fmt(f),
Self::Brute => "Brute".fmt(f),
}
}
}
impl TryFrom<u8> for FilterStrategy {
type Error = ();
fn try_from(value: u8) -> Result<Self, Self::Error> {
match value {
0..=4 => Ok(Self::Basic(value.try_into()?)),
5 => Ok(Self::MinSum),
6 => Ok(Self::Entropy),
7 => Ok(Self::Bigrams),
8 => Ok(Self::BigEnt),
9 => Ok(Self::Brute),
_ => Err(()),
}
}
}
/// PNG delta filters
#[repr(u8)] #[repr(u8)]
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)] #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)]
pub enum RowFilter { pub enum RowFilter {
// Standard filter types
None, None,
Sub, Sub,
Up, Up,
Average, Average,
Paeth, Paeth,
// Heuristic strategies
MinSum,
Entropy,
Bigrams,
BigEnt,
Brute,
} }
impl TryFrom<u8> for RowFilter { impl TryFrom<u8> for RowFilter {
type Error = (); type Error = ();
fn try_from(value: u8) -> Result<Self, Self::Error> { fn try_from(value: u8) -> Result<Self, Self::Error> {
if value > Self::LAST { if value > 4 {
return Err(()); return Err(());
} }
unsafe { transmute(value as i8) } unsafe { transmute(value as i8) }
@ -40,11 +77,6 @@ impl Display for RowFilter {
Self::Up => "Up", Self::Up => "Up",
Self::Average => "Average", Self::Average => "Average",
Self::Paeth => "Paeth", Self::Paeth => "Paeth",
Self::MinSum => "MinSum",
Self::Entropy => "Entropy",
Self::Bigrams => "Bigrams",
Self::BigEnt => "BigEnt",
Self::Brute => "Brute",
}, },
f, f,
) )
@ -52,9 +84,7 @@ impl Display for RowFilter {
} }
impl RowFilter { impl RowFilter {
pub const LAST: u8 = Self::Brute as u8; pub(crate) const ALL: [Self; 5] = [Self::None, Self::Sub, Self::Up, Self::Average, Self::Paeth];
pub(crate) const STANDARD: [Self; 5] =
[Self::None, Self::Sub, Self::Up, Self::Average, Self::Paeth];
pub(crate) const SINGLE_LINE: [Self; 2] = [Self::None, Self::Sub]; pub(crate) const SINGLE_LINE: [Self; 2] = [Self::None, Self::Sub];
pub(crate) fn filter_line( pub(crate) fn filter_line(
@ -115,7 +145,6 @@ impl RowFilter {
}); });
} }
} }
_ => unreachable!(),
} }
} }
@ -140,6 +169,7 @@ impl RowFilter {
_ => i - 1, _ => i - 1,
}; };
match self { match self {
Self::None => unreachable!(),
Self::Sub => { Self::Sub => {
for j in 0..color_bytes { for j in 0..color_bytes {
pixels[i][j] = pixels[prev][j]; pixels[i][j] = pixels[prev][j];
@ -171,7 +201,6 @@ impl RowFilter {
}; };
} }
} }
_ => unreachable!(),
} }
} }
} }
@ -183,7 +212,7 @@ impl RowFilter {
data: &[u8], data: &[u8],
prev_line: &[u8], prev_line: &[u8],
buf: &mut Vec<u8>, buf: &mut Vec<u8>,
) -> Result<(), PngError> { ) {
buf.clear(); buf.clear();
buf.reserve(data.len()); buf.reserve(data.len());
assert!(data.len() >= bpp); assert!(data.len() >= bpp);
@ -232,9 +261,7 @@ impl RowFilter {
); );
} }
} }
_ => return Err(PngError::InvalidData),
} }
Ok(())
} }
} }

View file

@ -45,7 +45,7 @@ pub use crate::{
colors::{BitDepth, ColorType}, colors::{BitDepth, ColorType},
deflate::Deflaters, deflate::Deflaters,
error::PngError, error::PngError,
filters::RowFilter, filters::{FilterStrategy, RowFilter},
headers::StripChunks, headers::StripChunks,
interlace::Interlacing, interlace::Interlacing,
options::{InFile, Options, OutFile}, options::{InFile, Options, OutFile},
@ -432,7 +432,7 @@ fn optimize_raw(
opts.filter.clone() opts.filter.clone()
} else { } else {
// None and Bigrams work well together, especially for alpha reductions // None and Bigrams work well together, especially for alpha reductions
indexset! {RowFilter::None, RowFilter::Bigrams} indexset! {FilterStrategy::Basic(RowFilter::None), FilterStrategy::Bigrams}
}; };
// This will collect all versions of images and pick one that compresses best // This will collect all versions of images and pick one that compresses best
let eval = Evaluator::new( let eval = Evaluator::new(
@ -489,7 +489,7 @@ fn perform_trials(
deadline: Arc<Deadline>, deadline: Arc<Deadline>,
max_size: Option<usize>, max_size: Option<usize>,
mut eval_result: Option<Candidate>, mut eval_result: Option<Candidate>,
eval_filters: IndexSet<RowFilter>, eval_filters: IndexSet<FilterStrategy>,
eval_deflater: Deflaters, eval_deflater: Deflaters,
) -> Option<Candidate> { ) -> Option<Candidate> {
let mut filters = opts.filter.clone(); let mut filters = opts.filter.clone();
@ -548,10 +548,10 @@ fn perform_trials(
// Pick a filter automatically // Pick a filter automatically
if image.ihdr.bit_depth as u8 >= 8 { if image.ihdr.bit_depth as u8 >= 8 {
// Bigrams is the best all-rounder when there's at least one byte per pixel // Bigrams is the best all-rounder when there's at least one byte per pixel
filters.insert(RowFilter::Bigrams); filters.insert(FilterStrategy::Bigrams);
} else { } else {
// Otherwise delta filters generally don't work well, so just stick with None // Otherwise delta filters generally don't work well, so just stick with None
filters.insert(RowFilter::None); filters.insert(FilterStrategy::Basic(RowFilter::None));
} }
} }
@ -627,7 +627,7 @@ fn recompress_frames(
png: &mut PngData, png: &mut PngData,
opts: &Options, opts: &Options,
deadline: Arc<Deadline>, deadline: Arc<Deadline>,
filter: RowFilter, filter: FilterStrategy,
) -> PngResult<()> { ) -> PngResult<()> {
if !opts.idat_recoding || png.frames.is_empty() { if !opts.idat_recoding || png.frames.is_empty() {
return Ok(()); return Ok(());

View file

@ -26,7 +26,7 @@ use clap::ArgMatches;
mod cli; mod cli;
use indexmap::IndexSet; use indexmap::IndexSet;
use log::{Level, LevelFilter, error, warn}; use log::{Level, LevelFilter, error, warn};
use oxipng::{Deflaters, InFile, Options, OutFile, PngError, RowFilter, StripChunks}; use oxipng::{Deflaters, InFile, Options, OutFile, PngError, StripChunks};
use rayon::prelude::*; use rayon::prelude::*;
use crate::cli::DISPLAY_CHUNKS; use crate::cli::DISPLAY_CHUNKS;
@ -36,8 +36,7 @@ fn main() -> ExitCode {
// Set the value parser for filters which isn't appropriate to do in the build_command function // Set the value parser for filters which isn't appropriate to do in the build_command function
.mut_arg("filters", |arg| { .mut_arg("filters", |arg| {
arg.value_parser(|x: &str| { arg.value_parser(|x: &str| {
parse_numeric_range_opts(x, 0, RowFilter::LAST) parse_numeric_range_opts(x, 0, 9).map_err(|_| "Invalid option for filters")
.map_err(|_| "Invalid option for filters")
}) })
}) })
.after_help("Run `oxipng --help` to see full details of all options") .after_help("Run `oxipng --help` to see full details of all options")

View file

@ -7,7 +7,12 @@ use std::{
use indexmap::{IndexSet, indexset}; use indexmap::{IndexSet, indexset};
use log::warn; use log::warn;
use crate::{deflate::Deflaters, filters::RowFilter, headers::StripChunks, interlace::Interlacing}; use crate::{
deflate::Deflaters,
filters::{FilterStrategy, RowFilter},
headers::StripChunks,
interlace::Interlacing,
};
/// Write destination for [`optimize`][crate::optimize]. /// Write destination for [`optimize`][crate::optimize].
/// You can use [`optimize_from_memory`](crate::optimize_from_memory) to avoid external I/O. /// You can use [`optimize_from_memory`](crate::optimize_from_memory) to avoid external I/O.
@ -94,10 +99,10 @@ pub struct Options {
/// ///
/// Default: `false` /// Default: `false`
pub force: bool, pub force: bool,
/// Which `RowFilters` to try on the file /// Which `FilterStrategy` to try on the file
/// ///
/// Default: `None,Sub,Entropy,Bigrams` /// Default: `None,Sub,Entropy,Bigrams`
pub filter: IndexSet<RowFilter>, pub filter: IndexSet<FilterStrategy>,
/// Whether to change the interlacing type of the file. /// Whether to change the interlacing type of the file.
/// ///
/// These are the interlacing types avaliable: /// These are the interlacing types avaliable:
@ -207,10 +212,10 @@ impl Options {
fn apply_preset_3(mut self) -> Self { fn apply_preset_3(mut self) -> Self {
self.fast_evaluation = false; self.fast_evaluation = false;
self.filter = indexset! { self.filter = indexset! {
RowFilter::None, FilterStrategy::Basic(RowFilter::None),
RowFilter::Bigrams, FilterStrategy::Bigrams,
RowFilter::BigEnt, FilterStrategy::BigEnt,
RowFilter::Brute FilterStrategy::Brute
}; };
self self
} }
@ -224,10 +229,10 @@ impl Options {
fn apply_preset_5(mut self) -> Self { fn apply_preset_5(mut self) -> Self {
self.fast_evaluation = false; self.fast_evaluation = false;
self.filter.insert(RowFilter::Up); self.filter.insert(FilterStrategy::Basic(RowFilter::Up));
self.filter.insert(RowFilter::MinSum); self.filter.insert(FilterStrategy::MinSum);
self.filter.insert(RowFilter::BigEnt); self.filter.insert(FilterStrategy::BigEnt);
self.filter.insert(RowFilter::Brute); self.filter.insert(FilterStrategy::Brute);
if let Deflaters::Libdeflater { compression } = &mut self.deflate { if let Deflaters::Libdeflater { compression } = &mut self.deflate {
*compression = 12; *compression = 12;
} }
@ -235,8 +240,9 @@ impl Options {
} }
fn apply_preset_6(mut self) -> Self { fn apply_preset_6(mut self) -> Self {
self.filter.insert(RowFilter::Average); self.filter
self.filter.insert(RowFilter::Paeth); .insert(FilterStrategy::Basic(RowFilter::Average));
self.filter.insert(FilterStrategy::Basic(RowFilter::Paeth));
self.apply_preset_5() self.apply_preset_5()
} }
} }
@ -247,7 +253,12 @@ impl Default for Options {
Self { Self {
fix_errors: false, fix_errors: false,
force: false, force: false,
filter: indexset! {RowFilter::None, RowFilter::Sub, RowFilter::Entropy, RowFilter::Bigrams}, filter: indexset! {
FilterStrategy::Basic(RowFilter::None),
FilterStrategy::Basic(RowFilter::Sub),
FilterStrategy::Entropy,
FilterStrategy::Bigrams
},
interlace: Some(Interlacing::None), interlace: Some(Interlacing::None),
optimize_alpha: false, optimize_alpha: false,
bit_depth_reduction: true, bit_depth_reduction: true,

View file

@ -376,7 +376,7 @@ impl PngImage {
} }
last_line.resize(line.data.len(), 0); last_line.resize(line.data.len(), 0);
let filter = RowFilter::try_from(line.filter).map_err(|_| PngError::InvalidData)?; let filter = RowFilter::try_from(line.filter).map_err(|_| PngError::InvalidData)?;
filter.unfilter_line(bpp, line.data, &last_line, &mut unfiltered_buf)?; filter.unfilter_line(bpp, line.data, &last_line, &mut unfiltered_buf);
unfiltered.extend_from_slice(&unfiltered_buf); unfiltered.extend_from_slice(&unfiltered_buf);
std::mem::swap(&mut last_line, &mut unfiltered_buf); std::mem::swap(&mut last_line, &mut unfiltered_buf);
unfiltered_buf.clear(); unfiltered_buf.clear();
@ -386,7 +386,7 @@ impl PngImage {
/// Apply the specified filter type to all rows in the image /// Apply the specified filter type to all rows in the image
#[must_use] #[must_use]
pub fn filter_image(&self, filter: RowFilter, optimize_alpha: bool) -> Vec<u8> { pub fn filter_image(&self, strategy: FilterStrategy, optimize_alpha: bool) -> Vec<u8> {
let mut filtered = Vec::with_capacity(self.data.len()); let mut filtered = Vec::with_capacity(self.data.len());
let bpp = self.bytes_per_channel() * self.channels_per_pixel(); let bpp = self.bytes_per_channel() * self.channels_per_pixel();
// If alpha optimization is enabled, determine how many bytes of alpha there are per pixel // If alpha optimization is enabled, determine how many bytes of alpha there are per pixel
@ -406,7 +406,7 @@ impl PngImage {
// Alpha optimisation may alter the line data, so we need a mutable copy of it // Alpha optimisation may alter the line data, so we need a mutable copy of it
let mut line_data = line.data.to_vec(); let mut line_data = line.data.to_vec();
if filter <= RowFilter::Paeth { if let FilterStrategy::Basic(filter) = strategy {
// Standard filters // Standard filters
let filter = if prev_pass == line.pass || filter <= RowFilter::Sub { let filter = if prev_pass == line.pass || filter <= RowFilter::Sub {
filter filter
@ -431,12 +431,12 @@ impl PngImage {
let mut best_line_raw = Vec::new(); let mut best_line_raw = Vec::new();
// Avoid vertical filtering on first line of each interlacing pass // Avoid vertical filtering on first line of each interlacing pass
let try_filters = if prev_pass == line.pass { let try_filters = if prev_pass == line.pass {
RowFilter::STANDARD.iter() RowFilter::ALL.iter()
} else { } else {
RowFilter::SINGLE_LINE.iter() RowFilter::SINGLE_LINE.iter()
}; };
match filter { match strategy {
RowFilter::MinSum => { FilterStrategy::MinSum => {
// MSAD algorithm mentioned in libpng reference docs // MSAD algorithm mentioned in libpng reference docs
// http://www.libpng.org/pub/png/book/chapter09.html // http://www.libpng.org/pub/png/book/chapter09.html
let mut best_size = usize::MAX; let mut best_size = usize::MAX;
@ -453,7 +453,7 @@ impl PngImage {
} }
} }
} }
RowFilter::Entropy => { FilterStrategy::Entropy => {
// Shannon entropy algorithm, from LodePNG // Shannon entropy algorithm, from LodePNG
// https://github.com/lvandeve/lodepng // https://github.com/lvandeve/lodepng
let mut best_size = i32::MIN; let mut best_size = i32::MIN;
@ -476,7 +476,7 @@ impl PngImage {
} }
} }
} }
RowFilter::Bigrams => { FilterStrategy::Bigrams => {
// Count distinct bigrams, from pngwolf // Count distinct bigrams, from pngwolf
// https://bjoern.hoehrmann.de/pngwolf/ // https://bjoern.hoehrmann.de/pngwolf/
let mut best_size = usize::MAX; let mut best_size = usize::MAX;
@ -495,7 +495,7 @@ impl PngImage {
} }
} }
} }
RowFilter::BigEnt => { FilterStrategy::BigEnt => {
// Bigram entropy, combined from Entropy and Bigrams filters // Bigram entropy, combined from Entropy and Bigrams filters
let mut best_size = i32::MIN; let mut best_size = i32::MIN;
// FxHasher is the fastest rust hasher currently available for this purpose // FxHasher is the fastest rust hasher currently available for this purpose
@ -515,7 +515,7 @@ impl PngImage {
} }
} }
} }
RowFilter::Brute => { FilterStrategy::Brute => {
// Brute force by compressing each filter attempt // Brute force by compressing each filter attempt
// Similar to that of LodePNG but includes some previous lines for context // Similar to that of LodePNG but includes some previous lines for context
let mut best_size = usize::MAX; let mut best_size = usize::MAX;

View file

@ -12,20 +12,17 @@ const GRAYSCALE_ALPHA: u8 = 4;
const RGBA: u8 = 6; const RGBA: u8 = 6;
fn get_opts(input: &Path) -> (OutFile, oxipng::Options) { fn get_opts(input: &Path) -> (OutFile, oxipng::Options) {
let mut options = oxipng::Options { let options = oxipng::Options {
force: true, force: true,
filter: indexset! {FilterStrategy::Basic(RowFilter::None)},
..Default::default() ..Default::default()
}; };
let mut filter = IndexSet::new();
filter.insert(RowFilter::None);
options.filter = filter;
(OutFile::from_path(input.with_extension("out.png")), options) (OutFile::from_path(input.with_extension("out.png")), options)
} }
fn test_it_converts( fn test_it_converts(
input: &str, input: &str,
filter: RowFilter, filter: FilterStrategy,
color_type_in: u8, color_type_in: u8,
bit_depth_in: BitDepth, bit_depth_in: BitDepth,
color_type_out: u8, color_type_out: u8,
@ -68,7 +65,7 @@ fn test_it_converts(
fn filter_0_for_rgba_16() { fn filter_0_for_rgba_16() {
test_it_converts( test_it_converts(
"tests/files/filter_0_for_rgba_16.png", "tests/files/filter_0_for_rgba_16.png",
RowFilter::None, FilterStrategy::Basic(RowFilter::None),
RGBA, RGBA,
BitDepth::Sixteen, BitDepth::Sixteen,
RGBA, RGBA,
@ -80,7 +77,7 @@ fn filter_0_for_rgba_16() {
fn filter_1_for_rgba_16() { fn filter_1_for_rgba_16() {
test_it_converts( test_it_converts(
"tests/files/filter_1_for_rgba_16.png", "tests/files/filter_1_for_rgba_16.png",
RowFilter::Sub, FilterStrategy::Basic(RowFilter::Sub),
RGBA, RGBA,
BitDepth::Sixteen, BitDepth::Sixteen,
RGBA, RGBA,
@ -92,7 +89,7 @@ fn filter_1_for_rgba_16() {
fn filter_2_for_rgba_16() { fn filter_2_for_rgba_16() {
test_it_converts( test_it_converts(
"tests/files/filter_2_for_rgba_16.png", "tests/files/filter_2_for_rgba_16.png",
RowFilter::Up, FilterStrategy::Basic(RowFilter::Up),
RGBA, RGBA,
BitDepth::Sixteen, BitDepth::Sixteen,
RGBA, RGBA,
@ -104,7 +101,7 @@ fn filter_2_for_rgba_16() {
fn filter_3_for_rgba_16() { fn filter_3_for_rgba_16() {
test_it_converts( test_it_converts(
"tests/files/filter_3_for_rgba_16.png", "tests/files/filter_3_for_rgba_16.png",
RowFilter::Average, FilterStrategy::Basic(RowFilter::Average),
RGBA, RGBA,
BitDepth::Sixteen, BitDepth::Sixteen,
RGBA, RGBA,
@ -116,7 +113,7 @@ fn filter_3_for_rgba_16() {
fn filter_4_for_rgba_16() { fn filter_4_for_rgba_16() {
test_it_converts( test_it_converts(
"tests/files/filter_4_for_rgba_16.png", "tests/files/filter_4_for_rgba_16.png",
RowFilter::Paeth, FilterStrategy::Basic(RowFilter::Paeth),
RGBA, RGBA,
BitDepth::Sixteen, BitDepth::Sixteen,
RGBA, RGBA,
@ -128,7 +125,7 @@ fn filter_4_for_rgba_16() {
fn filter_5_for_rgba_16() { fn filter_5_for_rgba_16() {
test_it_converts( test_it_converts(
"tests/files/filter_5_for_rgba_16.png", "tests/files/filter_5_for_rgba_16.png",
RowFilter::MinSum, FilterStrategy::MinSum,
RGBA, RGBA,
BitDepth::Sixteen, BitDepth::Sixteen,
RGBA, RGBA,
@ -140,7 +137,7 @@ fn filter_5_for_rgba_16() {
fn filter_0_for_rgba_8() { fn filter_0_for_rgba_8() {
test_it_converts( test_it_converts(
"tests/files/filter_0_for_rgba_8.png", "tests/files/filter_0_for_rgba_8.png",
RowFilter::None, FilterStrategy::Basic(RowFilter::None),
RGBA, RGBA,
BitDepth::Eight, BitDepth::Eight,
RGBA, RGBA,
@ -152,7 +149,7 @@ fn filter_0_for_rgba_8() {
fn filter_1_for_rgba_8() { fn filter_1_for_rgba_8() {
test_it_converts( test_it_converts(
"tests/files/filter_1_for_rgba_8.png", "tests/files/filter_1_for_rgba_8.png",
RowFilter::Sub, FilterStrategy::Basic(RowFilter::Sub),
RGBA, RGBA,
BitDepth::Eight, BitDepth::Eight,
RGBA, RGBA,
@ -164,7 +161,7 @@ fn filter_1_for_rgba_8() {
fn filter_2_for_rgba_8() { fn filter_2_for_rgba_8() {
test_it_converts( test_it_converts(
"tests/files/filter_2_for_rgba_8.png", "tests/files/filter_2_for_rgba_8.png",
RowFilter::Up, FilterStrategy::Basic(RowFilter::Up),
RGBA, RGBA,
BitDepth::Eight, BitDepth::Eight,
RGBA, RGBA,
@ -176,7 +173,7 @@ fn filter_2_for_rgba_8() {
fn filter_3_for_rgba_8() { fn filter_3_for_rgba_8() {
test_it_converts( test_it_converts(
"tests/files/filter_3_for_rgba_8.png", "tests/files/filter_3_for_rgba_8.png",
RowFilter::Average, FilterStrategy::Basic(RowFilter::Average),
RGBA, RGBA,
BitDepth::Eight, BitDepth::Eight,
RGBA, RGBA,
@ -188,7 +185,7 @@ fn filter_3_for_rgba_8() {
fn filter_4_for_rgba_8() { fn filter_4_for_rgba_8() {
test_it_converts( test_it_converts(
"tests/files/filter_4_for_rgba_8.png", "tests/files/filter_4_for_rgba_8.png",
RowFilter::Paeth, FilterStrategy::Basic(RowFilter::Paeth),
RGBA, RGBA,
BitDepth::Eight, BitDepth::Eight,
RGBA, RGBA,
@ -200,7 +197,7 @@ fn filter_4_for_rgba_8() {
fn filter_5_for_rgba_8() { fn filter_5_for_rgba_8() {
test_it_converts( test_it_converts(
"tests/files/filter_5_for_rgba_8.png", "tests/files/filter_5_for_rgba_8.png",
RowFilter::MinSum, FilterStrategy::MinSum,
RGBA, RGBA,
BitDepth::Eight, BitDepth::Eight,
RGBA, RGBA,
@ -212,7 +209,7 @@ fn filter_5_for_rgba_8() {
fn filter_0_for_rgb_16() { fn filter_0_for_rgb_16() {
test_it_converts( test_it_converts(
"tests/files/filter_0_for_rgb_16.png", "tests/files/filter_0_for_rgb_16.png",
RowFilter::None, FilterStrategy::Basic(RowFilter::None),
RGB, RGB,
BitDepth::Sixteen, BitDepth::Sixteen,
RGB, RGB,
@ -224,7 +221,7 @@ fn filter_0_for_rgb_16() {
fn filter_1_for_rgb_16() { fn filter_1_for_rgb_16() {
test_it_converts( test_it_converts(
"tests/files/filter_1_for_rgb_16.png", "tests/files/filter_1_for_rgb_16.png",
RowFilter::Sub, FilterStrategy::Basic(RowFilter::Sub),
RGB, RGB,
BitDepth::Sixteen, BitDepth::Sixteen,
RGB, RGB,
@ -236,7 +233,7 @@ fn filter_1_for_rgb_16() {
fn filter_2_for_rgb_16() { fn filter_2_for_rgb_16() {
test_it_converts( test_it_converts(
"tests/files/filter_2_for_rgb_16.png", "tests/files/filter_2_for_rgb_16.png",
RowFilter::Up, FilterStrategy::Basic(RowFilter::Up),
RGB, RGB,
BitDepth::Sixteen, BitDepth::Sixteen,
RGB, RGB,
@ -248,7 +245,7 @@ fn filter_2_for_rgb_16() {
fn filter_3_for_rgb_16() { fn filter_3_for_rgb_16() {
test_it_converts( test_it_converts(
"tests/files/filter_3_for_rgb_16.png", "tests/files/filter_3_for_rgb_16.png",
RowFilter::Average, FilterStrategy::Basic(RowFilter::Average),
RGB, RGB,
BitDepth::Sixteen, BitDepth::Sixteen,
RGB, RGB,
@ -260,7 +257,7 @@ fn filter_3_for_rgb_16() {
fn filter_4_for_rgb_16() { fn filter_4_for_rgb_16() {
test_it_converts( test_it_converts(
"tests/files/filter_4_for_rgb_16.png", "tests/files/filter_4_for_rgb_16.png",
RowFilter::Paeth, FilterStrategy::Basic(RowFilter::Paeth),
RGB, RGB,
BitDepth::Sixteen, BitDepth::Sixteen,
RGB, RGB,
@ -272,7 +269,7 @@ fn filter_4_for_rgb_16() {
fn filter_5_for_rgb_16() { fn filter_5_for_rgb_16() {
test_it_converts( test_it_converts(
"tests/files/filter_5_for_rgb_16.png", "tests/files/filter_5_for_rgb_16.png",
RowFilter::MinSum, FilterStrategy::MinSum,
RGB, RGB,
BitDepth::Sixteen, BitDepth::Sixteen,
RGB, RGB,
@ -284,7 +281,7 @@ fn filter_5_for_rgb_16() {
fn filter_0_for_rgb_8() { fn filter_0_for_rgb_8() {
test_it_converts( test_it_converts(
"tests/files/filter_0_for_rgb_8.png", "tests/files/filter_0_for_rgb_8.png",
RowFilter::None, FilterStrategy::Basic(RowFilter::None),
RGB, RGB,
BitDepth::Eight, BitDepth::Eight,
RGB, RGB,
@ -296,7 +293,7 @@ fn filter_0_for_rgb_8() {
fn filter_1_for_rgb_8() { fn filter_1_for_rgb_8() {
test_it_converts( test_it_converts(
"tests/files/filter_1_for_rgb_8.png", "tests/files/filter_1_for_rgb_8.png",
RowFilter::Sub, FilterStrategy::Basic(RowFilter::Sub),
RGB, RGB,
BitDepth::Eight, BitDepth::Eight,
RGB, RGB,
@ -308,7 +305,7 @@ fn filter_1_for_rgb_8() {
fn filter_2_for_rgb_8() { fn filter_2_for_rgb_8() {
test_it_converts( test_it_converts(
"tests/files/filter_2_for_rgb_8.png", "tests/files/filter_2_for_rgb_8.png",
RowFilter::Up, FilterStrategy::Basic(RowFilter::Up),
RGB, RGB,
BitDepth::Eight, BitDepth::Eight,
RGB, RGB,
@ -320,7 +317,7 @@ fn filter_2_for_rgb_8() {
fn filter_3_for_rgb_8() { fn filter_3_for_rgb_8() {
test_it_converts( test_it_converts(
"tests/files/filter_3_for_rgb_8.png", "tests/files/filter_3_for_rgb_8.png",
RowFilter::Average, FilterStrategy::Basic(RowFilter::Average),
RGB, RGB,
BitDepth::Eight, BitDepth::Eight,
RGB, RGB,
@ -332,7 +329,7 @@ fn filter_3_for_rgb_8() {
fn filter_4_for_rgb_8() { fn filter_4_for_rgb_8() {
test_it_converts( test_it_converts(
"tests/files/filter_4_for_rgb_8.png", "tests/files/filter_4_for_rgb_8.png",
RowFilter::Paeth, FilterStrategy::Basic(RowFilter::Paeth),
RGB, RGB,
BitDepth::Eight, BitDepth::Eight,
RGB, RGB,
@ -344,7 +341,7 @@ fn filter_4_for_rgb_8() {
fn filter_5_for_rgb_8() { fn filter_5_for_rgb_8() {
test_it_converts( test_it_converts(
"tests/files/filter_5_for_rgb_8.png", "tests/files/filter_5_for_rgb_8.png",
RowFilter::MinSum, FilterStrategy::MinSum,
RGB, RGB,
BitDepth::Eight, BitDepth::Eight,
RGB, RGB,
@ -356,7 +353,7 @@ fn filter_5_for_rgb_8() {
fn filter_0_for_grayscale_alpha_16() { fn filter_0_for_grayscale_alpha_16() {
test_it_converts( test_it_converts(
"tests/files/filter_0_for_grayscale_alpha_16.png", "tests/files/filter_0_for_grayscale_alpha_16.png",
RowFilter::None, FilterStrategy::Basic(RowFilter::None),
GRAYSCALE_ALPHA, GRAYSCALE_ALPHA,
BitDepth::Sixteen, BitDepth::Sixteen,
GRAYSCALE_ALPHA, GRAYSCALE_ALPHA,
@ -368,7 +365,7 @@ fn filter_0_for_grayscale_alpha_16() {
fn filter_1_for_grayscale_alpha_16() { fn filter_1_for_grayscale_alpha_16() {
test_it_converts( test_it_converts(
"tests/files/filter_1_for_grayscale_alpha_16.png", "tests/files/filter_1_for_grayscale_alpha_16.png",
RowFilter::Sub, FilterStrategy::Basic(RowFilter::Sub),
GRAYSCALE_ALPHA, GRAYSCALE_ALPHA,
BitDepth::Sixteen, BitDepth::Sixteen,
GRAYSCALE_ALPHA, GRAYSCALE_ALPHA,
@ -380,7 +377,7 @@ fn filter_1_for_grayscale_alpha_16() {
fn filter_2_for_grayscale_alpha_16() { fn filter_2_for_grayscale_alpha_16() {
test_it_converts( test_it_converts(
"tests/files/filter_2_for_grayscale_alpha_16.png", "tests/files/filter_2_for_grayscale_alpha_16.png",
RowFilter::Up, FilterStrategy::Basic(RowFilter::Up),
GRAYSCALE_ALPHA, GRAYSCALE_ALPHA,
BitDepth::Sixteen, BitDepth::Sixteen,
GRAYSCALE_ALPHA, GRAYSCALE_ALPHA,
@ -392,7 +389,7 @@ fn filter_2_for_grayscale_alpha_16() {
fn filter_3_for_grayscale_alpha_16() { fn filter_3_for_grayscale_alpha_16() {
test_it_converts( test_it_converts(
"tests/files/filter_3_for_grayscale_alpha_16.png", "tests/files/filter_3_for_grayscale_alpha_16.png",
RowFilter::Average, FilterStrategy::Basic(RowFilter::Average),
GRAYSCALE_ALPHA, GRAYSCALE_ALPHA,
BitDepth::Sixteen, BitDepth::Sixteen,
GRAYSCALE_ALPHA, GRAYSCALE_ALPHA,
@ -404,7 +401,7 @@ fn filter_3_for_grayscale_alpha_16() {
fn filter_4_for_grayscale_alpha_16() { fn filter_4_for_grayscale_alpha_16() {
test_it_converts( test_it_converts(
"tests/files/filter_4_for_grayscale_alpha_16.png", "tests/files/filter_4_for_grayscale_alpha_16.png",
RowFilter::Paeth, FilterStrategy::Basic(RowFilter::Paeth),
GRAYSCALE_ALPHA, GRAYSCALE_ALPHA,
BitDepth::Sixteen, BitDepth::Sixteen,
GRAYSCALE_ALPHA, GRAYSCALE_ALPHA,
@ -416,7 +413,7 @@ fn filter_4_for_grayscale_alpha_16() {
fn filter_5_for_grayscale_alpha_16() { fn filter_5_for_grayscale_alpha_16() {
test_it_converts( test_it_converts(
"tests/files/filter_5_for_grayscale_alpha_16.png", "tests/files/filter_5_for_grayscale_alpha_16.png",
RowFilter::MinSum, FilterStrategy::MinSum,
GRAYSCALE_ALPHA, GRAYSCALE_ALPHA,
BitDepth::Sixteen, BitDepth::Sixteen,
GRAYSCALE_ALPHA, GRAYSCALE_ALPHA,
@ -428,7 +425,7 @@ fn filter_5_for_grayscale_alpha_16() {
fn filter_0_for_grayscale_alpha_8() { fn filter_0_for_grayscale_alpha_8() {
test_it_converts( test_it_converts(
"tests/files/filter_0_for_grayscale_alpha_8.png", "tests/files/filter_0_for_grayscale_alpha_8.png",
RowFilter::None, FilterStrategy::Basic(RowFilter::None),
GRAYSCALE_ALPHA, GRAYSCALE_ALPHA,
BitDepth::Eight, BitDepth::Eight,
GRAYSCALE_ALPHA, GRAYSCALE_ALPHA,
@ -440,7 +437,7 @@ fn filter_0_for_grayscale_alpha_8() {
fn filter_1_for_grayscale_alpha_8() { fn filter_1_for_grayscale_alpha_8() {
test_it_converts( test_it_converts(
"tests/files/filter_1_for_grayscale_alpha_8.png", "tests/files/filter_1_for_grayscale_alpha_8.png",
RowFilter::Sub, FilterStrategy::Basic(RowFilter::Sub),
GRAYSCALE_ALPHA, GRAYSCALE_ALPHA,
BitDepth::Eight, BitDepth::Eight,
GRAYSCALE_ALPHA, GRAYSCALE_ALPHA,
@ -452,7 +449,7 @@ fn filter_1_for_grayscale_alpha_8() {
fn filter_2_for_grayscale_alpha_8() { fn filter_2_for_grayscale_alpha_8() {
test_it_converts( test_it_converts(
"tests/files/filter_2_for_grayscale_alpha_8.png", "tests/files/filter_2_for_grayscale_alpha_8.png",
RowFilter::Up, FilterStrategy::Basic(RowFilter::Up),
GRAYSCALE_ALPHA, GRAYSCALE_ALPHA,
BitDepth::Eight, BitDepth::Eight,
GRAYSCALE_ALPHA, GRAYSCALE_ALPHA,
@ -464,7 +461,7 @@ fn filter_2_for_grayscale_alpha_8() {
fn filter_3_for_grayscale_alpha_8() { fn filter_3_for_grayscale_alpha_8() {
test_it_converts( test_it_converts(
"tests/files/filter_3_for_grayscale_alpha_8.png", "tests/files/filter_3_for_grayscale_alpha_8.png",
RowFilter::Average, FilterStrategy::Basic(RowFilter::Average),
GRAYSCALE_ALPHA, GRAYSCALE_ALPHA,
BitDepth::Eight, BitDepth::Eight,
GRAYSCALE_ALPHA, GRAYSCALE_ALPHA,
@ -476,7 +473,7 @@ fn filter_3_for_grayscale_alpha_8() {
fn filter_4_for_grayscale_alpha_8() { fn filter_4_for_grayscale_alpha_8() {
test_it_converts( test_it_converts(
"tests/files/filter_4_for_grayscale_alpha_8.png", "tests/files/filter_4_for_grayscale_alpha_8.png",
RowFilter::Paeth, FilterStrategy::Basic(RowFilter::Paeth),
GRAYSCALE_ALPHA, GRAYSCALE_ALPHA,
BitDepth::Eight, BitDepth::Eight,
GRAYSCALE_ALPHA, GRAYSCALE_ALPHA,
@ -488,7 +485,7 @@ fn filter_4_for_grayscale_alpha_8() {
fn filter_5_for_grayscale_alpha_8() { fn filter_5_for_grayscale_alpha_8() {
test_it_converts( test_it_converts(
"tests/files/filter_5_for_grayscale_alpha_8.png", "tests/files/filter_5_for_grayscale_alpha_8.png",
RowFilter::MinSum, FilterStrategy::MinSum,
GRAYSCALE_ALPHA, GRAYSCALE_ALPHA,
BitDepth::Eight, BitDepth::Eight,
GRAYSCALE_ALPHA, GRAYSCALE_ALPHA,
@ -500,7 +497,7 @@ fn filter_5_for_grayscale_alpha_8() {
fn filter_0_for_grayscale_16() { fn filter_0_for_grayscale_16() {
test_it_converts( test_it_converts(
"tests/files/filter_0_for_grayscale_16.png", "tests/files/filter_0_for_grayscale_16.png",
RowFilter::None, FilterStrategy::Basic(RowFilter::None),
GRAYSCALE, GRAYSCALE,
BitDepth::Sixteen, BitDepth::Sixteen,
GRAYSCALE, GRAYSCALE,
@ -512,7 +509,7 @@ fn filter_0_for_grayscale_16() {
fn filter_1_for_grayscale_16() { fn filter_1_for_grayscale_16() {
test_it_converts( test_it_converts(
"tests/files/filter_1_for_grayscale_16.png", "tests/files/filter_1_for_grayscale_16.png",
RowFilter::Sub, FilterStrategy::Basic(RowFilter::Sub),
GRAYSCALE, GRAYSCALE,
BitDepth::Sixteen, BitDepth::Sixteen,
GRAYSCALE, GRAYSCALE,
@ -524,7 +521,7 @@ fn filter_1_for_grayscale_16() {
fn filter_2_for_grayscale_16() { fn filter_2_for_grayscale_16() {
test_it_converts( test_it_converts(
"tests/files/filter_2_for_grayscale_16.png", "tests/files/filter_2_for_grayscale_16.png",
RowFilter::Up, FilterStrategy::Basic(RowFilter::Up),
GRAYSCALE, GRAYSCALE,
BitDepth::Sixteen, BitDepth::Sixteen,
GRAYSCALE, GRAYSCALE,
@ -536,7 +533,7 @@ fn filter_2_for_grayscale_16() {
fn filter_3_for_grayscale_16() { fn filter_3_for_grayscale_16() {
test_it_converts( test_it_converts(
"tests/files/filter_3_for_grayscale_16.png", "tests/files/filter_3_for_grayscale_16.png",
RowFilter::Average, FilterStrategy::Basic(RowFilter::Average),
GRAYSCALE, GRAYSCALE,
BitDepth::Sixteen, BitDepth::Sixteen,
GRAYSCALE, GRAYSCALE,
@ -548,7 +545,7 @@ fn filter_3_for_grayscale_16() {
fn filter_4_for_grayscale_16() { fn filter_4_for_grayscale_16() {
test_it_converts( test_it_converts(
"tests/files/filter_4_for_grayscale_16.png", "tests/files/filter_4_for_grayscale_16.png",
RowFilter::Paeth, FilterStrategy::Basic(RowFilter::Paeth),
GRAYSCALE, GRAYSCALE,
BitDepth::Sixteen, BitDepth::Sixteen,
GRAYSCALE, GRAYSCALE,
@ -560,7 +557,7 @@ fn filter_4_for_grayscale_16() {
fn filter_5_for_grayscale_16() { fn filter_5_for_grayscale_16() {
test_it_converts( test_it_converts(
"tests/files/filter_5_for_grayscale_16.png", "tests/files/filter_5_for_grayscale_16.png",
RowFilter::MinSum, FilterStrategy::MinSum,
GRAYSCALE, GRAYSCALE,
BitDepth::Sixteen, BitDepth::Sixteen,
GRAYSCALE, GRAYSCALE,
@ -572,7 +569,7 @@ fn filter_5_for_grayscale_16() {
fn filter_0_for_grayscale_8() { fn filter_0_for_grayscale_8() {
test_it_converts( test_it_converts(
"tests/files/filter_0_for_grayscale_8.png", "tests/files/filter_0_for_grayscale_8.png",
RowFilter::None, FilterStrategy::Basic(RowFilter::None),
GRAYSCALE, GRAYSCALE,
BitDepth::Eight, BitDepth::Eight,
GRAYSCALE, GRAYSCALE,
@ -584,7 +581,7 @@ fn filter_0_for_grayscale_8() {
fn filter_1_for_grayscale_8() { fn filter_1_for_grayscale_8() {
test_it_converts( test_it_converts(
"tests/files/filter_1_for_grayscale_8.png", "tests/files/filter_1_for_grayscale_8.png",
RowFilter::Sub, FilterStrategy::Basic(RowFilter::Sub),
GRAYSCALE, GRAYSCALE,
BitDepth::Eight, BitDepth::Eight,
GRAYSCALE, GRAYSCALE,
@ -596,7 +593,7 @@ fn filter_1_for_grayscale_8() {
fn filter_2_for_grayscale_8() { fn filter_2_for_grayscale_8() {
test_it_converts( test_it_converts(
"tests/files/filter_2_for_grayscale_8.png", "tests/files/filter_2_for_grayscale_8.png",
RowFilter::Up, FilterStrategy::Basic(RowFilter::Up),
GRAYSCALE, GRAYSCALE,
BitDepth::Eight, BitDepth::Eight,
GRAYSCALE, GRAYSCALE,
@ -608,7 +605,7 @@ fn filter_2_for_grayscale_8() {
fn filter_3_for_grayscale_8() { fn filter_3_for_grayscale_8() {
test_it_converts( test_it_converts(
"tests/files/filter_3_for_grayscale_8.png", "tests/files/filter_3_for_grayscale_8.png",
RowFilter::Average, FilterStrategy::Basic(RowFilter::Average),
GRAYSCALE, GRAYSCALE,
BitDepth::Eight, BitDepth::Eight,
GRAYSCALE, GRAYSCALE,
@ -620,7 +617,7 @@ fn filter_3_for_grayscale_8() {
fn filter_4_for_grayscale_8() { fn filter_4_for_grayscale_8() {
test_it_converts( test_it_converts(
"tests/files/filter_4_for_grayscale_8.png", "tests/files/filter_4_for_grayscale_8.png",
RowFilter::Paeth, FilterStrategy::Basic(RowFilter::Paeth),
GRAYSCALE, GRAYSCALE,
BitDepth::Eight, BitDepth::Eight,
GRAYSCALE, GRAYSCALE,
@ -632,7 +629,7 @@ fn filter_4_for_grayscale_8() {
fn filter_5_for_grayscale_8() { fn filter_5_for_grayscale_8() {
test_it_converts( test_it_converts(
"tests/files/filter_5_for_grayscale_8.png", "tests/files/filter_5_for_grayscale_8.png",
RowFilter::MinSum, FilterStrategy::MinSum,
GRAYSCALE, GRAYSCALE,
BitDepth::Eight, BitDepth::Eight,
GRAYSCALE, GRAYSCALE,
@ -644,7 +641,7 @@ fn filter_5_for_grayscale_8() {
fn filter_0_for_palette_4() { fn filter_0_for_palette_4() {
test_it_converts( test_it_converts(
"tests/files/filter_0_for_palette_4.png", "tests/files/filter_0_for_palette_4.png",
RowFilter::None, FilterStrategy::Basic(RowFilter::None),
INDEXED, INDEXED,
BitDepth::Four, BitDepth::Four,
INDEXED, INDEXED,
@ -656,7 +653,7 @@ fn filter_0_for_palette_4() {
fn filter_1_for_palette_4() { fn filter_1_for_palette_4() {
test_it_converts( test_it_converts(
"tests/files/filter_1_for_palette_4.png", "tests/files/filter_1_for_palette_4.png",
RowFilter::Sub, FilterStrategy::Basic(RowFilter::Sub),
INDEXED, INDEXED,
BitDepth::Four, BitDepth::Four,
INDEXED, INDEXED,
@ -668,7 +665,7 @@ fn filter_1_for_palette_4() {
fn filter_2_for_palette_4() { fn filter_2_for_palette_4() {
test_it_converts( test_it_converts(
"tests/files/filter_2_for_palette_4.png", "tests/files/filter_2_for_palette_4.png",
RowFilter::Up, FilterStrategy::Basic(RowFilter::Up),
INDEXED, INDEXED,
BitDepth::Four, BitDepth::Four,
INDEXED, INDEXED,
@ -680,7 +677,7 @@ fn filter_2_for_palette_4() {
fn filter_3_for_palette_4() { fn filter_3_for_palette_4() {
test_it_converts( test_it_converts(
"tests/files/filter_3_for_palette_4.png", "tests/files/filter_3_for_palette_4.png",
RowFilter::Average, FilterStrategy::Basic(RowFilter::Average),
INDEXED, INDEXED,
BitDepth::Four, BitDepth::Four,
INDEXED, INDEXED,
@ -692,7 +689,7 @@ fn filter_3_for_palette_4() {
fn filter_4_for_palette_4() { fn filter_4_for_palette_4() {
test_it_converts( test_it_converts(
"tests/files/filter_4_for_palette_4.png", "tests/files/filter_4_for_palette_4.png",
RowFilter::Paeth, FilterStrategy::Basic(RowFilter::Paeth),
INDEXED, INDEXED,
BitDepth::Four, BitDepth::Four,
INDEXED, INDEXED,
@ -704,7 +701,7 @@ fn filter_4_for_palette_4() {
fn filter_5_for_palette_4() { fn filter_5_for_palette_4() {
test_it_converts( test_it_converts(
"tests/files/filter_5_for_palette_4.png", "tests/files/filter_5_for_palette_4.png",
RowFilter::MinSum, FilterStrategy::MinSum,
INDEXED, INDEXED,
BitDepth::Four, BitDepth::Four,
INDEXED, INDEXED,
@ -716,7 +713,7 @@ fn filter_5_for_palette_4() {
fn filter_0_for_palette_2() { fn filter_0_for_palette_2() {
test_it_converts( test_it_converts(
"tests/files/filter_0_for_palette_2.png", "tests/files/filter_0_for_palette_2.png",
RowFilter::None, FilterStrategy::Basic(RowFilter::None),
INDEXED, INDEXED,
BitDepth::Two, BitDepth::Two,
INDEXED, INDEXED,
@ -728,7 +725,7 @@ fn filter_0_for_palette_2() {
fn filter_1_for_palette_2() { fn filter_1_for_palette_2() {
test_it_converts( test_it_converts(
"tests/files/filter_1_for_palette_2.png", "tests/files/filter_1_for_palette_2.png",
RowFilter::Sub, FilterStrategy::Basic(RowFilter::Sub),
INDEXED, INDEXED,
BitDepth::Two, BitDepth::Two,
INDEXED, INDEXED,
@ -740,7 +737,7 @@ fn filter_1_for_palette_2() {
fn filter_2_for_palette_2() { fn filter_2_for_palette_2() {
test_it_converts( test_it_converts(
"tests/files/filter_2_for_palette_2.png", "tests/files/filter_2_for_palette_2.png",
RowFilter::Up, FilterStrategy::Basic(RowFilter::Up),
INDEXED, INDEXED,
BitDepth::Two, BitDepth::Two,
INDEXED, INDEXED,
@ -752,7 +749,7 @@ fn filter_2_for_palette_2() {
fn filter_3_for_palette_2() { fn filter_3_for_palette_2() {
test_it_converts( test_it_converts(
"tests/files/filter_3_for_palette_2.png", "tests/files/filter_3_for_palette_2.png",
RowFilter::Average, FilterStrategy::Basic(RowFilter::Average),
INDEXED, INDEXED,
BitDepth::Two, BitDepth::Two,
INDEXED, INDEXED,
@ -764,7 +761,7 @@ fn filter_3_for_palette_2() {
fn filter_4_for_palette_2() { fn filter_4_for_palette_2() {
test_it_converts( test_it_converts(
"tests/files/filter_4_for_palette_2.png", "tests/files/filter_4_for_palette_2.png",
RowFilter::Paeth, FilterStrategy::Basic(RowFilter::Paeth),
INDEXED, INDEXED,
BitDepth::Two, BitDepth::Two,
INDEXED, INDEXED,
@ -776,7 +773,7 @@ fn filter_4_for_palette_2() {
fn filter_5_for_palette_2() { fn filter_5_for_palette_2() {
test_it_converts( test_it_converts(
"tests/files/filter_5_for_palette_2.png", "tests/files/filter_5_for_palette_2.png",
RowFilter::MinSum, FilterStrategy::MinSum,
INDEXED, INDEXED,
BitDepth::Two, BitDepth::Two,
INDEXED, INDEXED,
@ -788,7 +785,7 @@ fn filter_5_for_palette_2() {
fn filter_0_for_palette_1() { fn filter_0_for_palette_1() {
test_it_converts( test_it_converts(
"tests/files/filter_0_for_palette_1.png", "tests/files/filter_0_for_palette_1.png",
RowFilter::None, FilterStrategy::Basic(RowFilter::None),
INDEXED, INDEXED,
BitDepth::One, BitDepth::One,
INDEXED, INDEXED,
@ -800,7 +797,7 @@ fn filter_0_for_palette_1() {
fn filter_1_for_palette_1() { fn filter_1_for_palette_1() {
test_it_converts( test_it_converts(
"tests/files/filter_1_for_palette_1.png", "tests/files/filter_1_for_palette_1.png",
RowFilter::Sub, FilterStrategy::Basic(RowFilter::Sub),
INDEXED, INDEXED,
BitDepth::One, BitDepth::One,
INDEXED, INDEXED,
@ -812,7 +809,7 @@ fn filter_1_for_palette_1() {
fn filter_2_for_palette_1() { fn filter_2_for_palette_1() {
test_it_converts( test_it_converts(
"tests/files/filter_2_for_palette_1.png", "tests/files/filter_2_for_palette_1.png",
RowFilter::Up, FilterStrategy::Basic(RowFilter::Up),
INDEXED, INDEXED,
BitDepth::One, BitDepth::One,
INDEXED, INDEXED,
@ -824,7 +821,7 @@ fn filter_2_for_palette_1() {
fn filter_3_for_palette_1() { fn filter_3_for_palette_1() {
test_it_converts( test_it_converts(
"tests/files/filter_3_for_palette_1.png", "tests/files/filter_3_for_palette_1.png",
RowFilter::Average, FilterStrategy::Basic(RowFilter::Average),
INDEXED, INDEXED,
BitDepth::One, BitDepth::One,
INDEXED, INDEXED,
@ -836,7 +833,7 @@ fn filter_3_for_palette_1() {
fn filter_4_for_palette_1() { fn filter_4_for_palette_1() {
test_it_converts( test_it_converts(
"tests/files/filter_4_for_palette_1.png", "tests/files/filter_4_for_palette_1.png",
RowFilter::Paeth, FilterStrategy::Basic(RowFilter::Paeth),
INDEXED, INDEXED,
BitDepth::One, BitDepth::One,
INDEXED, INDEXED,
@ -848,7 +845,7 @@ fn filter_4_for_palette_1() {
fn filter_5_for_palette_1() { fn filter_5_for_palette_1() {
test_it_converts( test_it_converts(
"tests/files/filter_5_for_palette_1.png", "tests/files/filter_5_for_palette_1.png",
RowFilter::MinSum, FilterStrategy::MinSum,
INDEXED, INDEXED,
BitDepth::One, BitDepth::One,
INDEXED, INDEXED,

View file

@ -16,7 +16,7 @@ fn get_opts(input: &Path) -> (OutFile, Options) {
let options = Options { let options = Options {
force: true, force: true,
fast_evaluation: false, fast_evaluation: false,
filter: indexset! {RowFilter::None}, filter: indexset! {FilterStrategy::Basic(RowFilter::None)},
..Default::default() ..Default::default()
}; };
(OutFile::from_path(input.with_extension("out.png")), options) (OutFile::from_path(input.with_extension("out.png")), options)
@ -409,7 +409,7 @@ fn interlaced_0_to_1_other_filter_mode() {
let input = PathBuf::from("tests/files/interlaced_0_to_1_other_filter_mode.png"); let input = PathBuf::from("tests/files/interlaced_0_to_1_other_filter_mode.png");
let (output, mut opts) = get_opts(&input); let (output, mut opts) = get_opts(&input);
opts.interlace = Some(Interlacing::Adam7); opts.interlace = Some(Interlacing::Adam7);
opts.filter = indexset! {RowFilter::Paeth}; opts.filter = indexset! {FilterStrategy::Basic(RowFilter::Paeth)};
test_it_converts_callbacks( test_it_converts_callbacks(
input, input,

View file

@ -12,16 +12,13 @@ const GRAYSCALE_ALPHA: u8 = 4;
const RGBA: u8 = 6; const RGBA: u8 = 6;
fn get_opts(input: &Path) -> (OutFile, oxipng::Options) { fn get_opts(input: &Path) -> (OutFile, oxipng::Options) {
let mut options = oxipng::Options { let options = oxipng::Options {
force: true, force: true,
fast_evaluation: false, fast_evaluation: false,
filter: indexset! {FilterStrategy::Basic(RowFilter::None)},
interlace: None, interlace: None,
..Default::default() ..Default::default()
}; };
let mut filter = IndexSet::new();
filter.insert(RowFilter::None);
options.filter = filter;
(OutFile::from_path(input.with_extension("out.png")), options) (OutFile::from_path(input.with_extension("out.png")), options)
} }

View file

@ -9,14 +9,11 @@ const RGB: u8 = 2;
const INDEXED: u8 = 3; const INDEXED: u8 = 3;
fn get_opts(input: &Path) -> (OutFile, oxipng::Options) { fn get_opts(input: &Path) -> (OutFile, oxipng::Options) {
let mut options = oxipng::Options { let options = oxipng::Options {
force: true, force: true,
filter: indexset! {FilterStrategy::Basic(RowFilter::None)},
..Default::default() ..Default::default()
}; };
let mut filter = IndexSet::new();
filter.insert(RowFilter::None);
options.filter = filter;
(OutFile::from_path(input.with_extension("out.png")), options) (OutFile::from_path(input.with_extension("out.png")), options)
} }

View file

@ -5,7 +5,7 @@ use oxipng::{internal_tests::*, *};
fn get_opts() -> Options { fn get_opts() -> Options {
Options { Options {
force: true, force: true,
filter: indexset! { RowFilter::None }, filter: indexset! {FilterStrategy::Basic(RowFilter::None)},
..Default::default() ..Default::default()
} }
} }

View file

@ -12,15 +12,12 @@ const GRAYSCALE_ALPHA: u8 = 4;
const RGBA: u8 = 6; const RGBA: u8 = 6;
fn get_opts(input: &Path) -> (OutFile, oxipng::Options) { fn get_opts(input: &Path) -> (OutFile, oxipng::Options) {
let mut options = oxipng::Options { let options = oxipng::Options {
force: true, force: true,
fast_evaluation: false, fast_evaluation: false,
filter: indexset! {FilterStrategy::Basic(RowFilter::None)},
..Default::default() ..Default::default()
}; };
let mut filter = IndexSet::new();
filter.insert(RowFilter::None);
options.filter = filter;
(OutFile::from_path(input.with_extension("out.png")), options) (OutFile::from_path(input.with_extension("out.png")), options)
} }

View file

@ -12,14 +12,11 @@ const GRAYSCALE_ALPHA: u8 = 4;
const RGBA: u8 = 6; const RGBA: u8 = 6;
fn get_opts(input: &Path) -> (OutFile, oxipng::Options) { fn get_opts(input: &Path) -> (OutFile, oxipng::Options) {
let mut options = oxipng::Options { let options = oxipng::Options {
force: true, force: true,
filter: indexset! {FilterStrategy::Basic(RowFilter::None)},
..Default::default() ..Default::default()
}; };
let mut filter = IndexSet::new();
filter.insert(RowFilter::None);
options.filter = filter;
(OutFile::from_path(input.with_extension("out.png")), options) (OutFile::from_path(input.with_extension("out.png")), options)
} }

View file

@ -11,20 +11,16 @@ const INDEXED: u8 = 3;
const RGBA: u8 = 6; const RGBA: u8 = 6;
fn get_opts(input: &Path) -> (OutFile, oxipng::Options) { fn get_opts(input: &Path) -> (OutFile, oxipng::Options) {
let mut options = oxipng::Options { let options = oxipng::Options {
force: true, force: true,
..Default::default() ..Default::default()
}; };
let mut filter = IndexSet::new();
filter.insert(RowFilter::None);
options.filter = filter;
(OutFile::from_path(input.with_extension("out.png")), options) (OutFile::from_path(input.with_extension("out.png")), options)
} }
fn test_it_converts( fn test_it_converts(
input: &str, input: &str,
filter: RowFilter, filter: FilterStrategy,
color_type_in: u8, color_type_in: u8,
bit_depth_in: BitDepth, bit_depth_in: BitDepth,
color_type_out: u8, color_type_out: u8,
@ -34,8 +30,7 @@ fn test_it_converts(
let (output, mut opts) = get_opts(&input); let (output, mut opts) = get_opts(&input);
let png = PngData::new(&input, &opts).unwrap(); let png = PngData::new(&input, &opts).unwrap();
opts.filter = IndexSet::new(); opts.filter = indexset! {filter};
opts.filter.insert(filter);
assert_eq!(png.raw.ihdr.color_type.png_header_code(), color_type_in); assert_eq!(png.raw.ihdr.color_type.png_header_code(), color_type_in);
assert_eq!(png.raw.ihdr.bit_depth, bit_depth_in); assert_eq!(png.raw.ihdr.bit_depth, bit_depth_in);
@ -67,7 +62,7 @@ fn test_it_converts(
fn filter_minsum() { fn filter_minsum() {
test_it_converts( test_it_converts(
"tests/files/rgb_16_should_be_rgb_16.png", "tests/files/rgb_16_should_be_rgb_16.png",
RowFilter::MinSum, FilterStrategy::MinSum,
RGB, RGB,
BitDepth::Sixteen, BitDepth::Sixteen,
RGB, RGB,
@ -79,7 +74,7 @@ fn filter_minsum() {
fn filter_entropy() { fn filter_entropy() {
test_it_converts( test_it_converts(
"tests/files/rgb_8_should_be_rgb_8.png", "tests/files/rgb_8_should_be_rgb_8.png",
RowFilter::Entropy, FilterStrategy::Entropy,
RGB, RGB,
BitDepth::Eight, BitDepth::Eight,
RGB, RGB,
@ -91,7 +86,7 @@ fn filter_entropy() {
fn filter_bigrams() { fn filter_bigrams() {
test_it_converts( test_it_converts(
"tests/files/rgba_8_should_be_rgba_8.png", "tests/files/rgba_8_should_be_rgba_8.png",
RowFilter::Bigrams, FilterStrategy::Bigrams,
RGBA, RGBA,
BitDepth::Eight, BitDepth::Eight,
RGBA, RGBA,
@ -103,7 +98,7 @@ fn filter_bigrams() {
fn filter_bigent() { fn filter_bigent() {
test_it_converts( test_it_converts(
"tests/files/grayscale_8_should_be_grayscale_8.png", "tests/files/grayscale_8_should_be_grayscale_8.png",
RowFilter::BigEnt, FilterStrategy::BigEnt,
GRAYSCALE, GRAYSCALE,
BitDepth::Eight, BitDepth::Eight,
GRAYSCALE, GRAYSCALE,
@ -115,7 +110,7 @@ fn filter_bigent() {
fn filter_brute() { fn filter_brute() {
test_it_converts( test_it_converts(
"tests/files/palette_8_should_be_palette_8.png", "tests/files/palette_8_should_be_palette_8.png",
RowFilter::Brute, FilterStrategy::Brute,
INDEXED, INDEXED,
BitDepth::Eight, BitDepth::Eight,
INDEXED, INDEXED,