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 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]
@ -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 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]
@ -31,7 +37,10 @@ fn filters_4_bits_filter_0(b: &mut Bencher) {
));
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]
@ -41,7 +50,10 @@ fn filters_2_bits_filter_0(b: &mut Bencher) {
));
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]
@ -51,7 +63,10 @@ fn filters_1_bits_filter_0(b: &mut Bencher) {
));
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]
@ -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 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]
@ -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 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]
@ -77,7 +98,10 @@ fn filters_4_bits_filter_1(b: &mut Bencher) {
));
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]
@ -87,7 +111,10 @@ fn filters_2_bits_filter_1(b: &mut Bencher) {
));
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]
@ -97,7 +124,10 @@ fn filters_1_bits_filter_1(b: &mut Bencher) {
));
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]
@ -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 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]
@ -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 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]
@ -123,7 +159,10 @@ fn filters_4_bits_filter_2(b: &mut Bencher) {
));
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]
@ -133,7 +172,10 @@ fn filters_2_bits_filter_2(b: &mut Bencher) {
));
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]
@ -143,7 +185,10 @@ fn filters_1_bits_filter_2(b: &mut Bencher) {
));
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]
@ -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 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]
@ -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 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]
@ -169,7 +220,10 @@ fn filters_4_bits_filter_3(b: &mut Bencher) {
));
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]
@ -179,7 +233,10 @@ fn filters_2_bits_filter_3(b: &mut Bencher) {
));
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]
@ -189,7 +246,10 @@ fn filters_1_bits_filter_3(b: &mut Bencher) {
));
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]
@ -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 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]
@ -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 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]
@ -215,7 +281,10 @@ fn filters_4_bits_filter_4(b: &mut Bencher) {
));
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]
@ -225,7 +294,10 @@ fn filters_2_bits_filter_4(b: &mut Bencher) {
));
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]
@ -235,7 +307,10 @@ fn filters_1_bits_filter_4(b: &mut Bencher) {
));
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]
@ -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 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]
@ -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 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]
@ -261,7 +336,7 @@ fn filters_4_bits_filter_5(b: &mut Bencher) {
));
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]
@ -271,7 +346,7 @@ fn filters_2_bits_filter_5(b: &mut Bencher) {
));
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]
@ -281,5 +356,5 @@ fn filters_1_bits_filter_5(b: &mut Bencher) {
));
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 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]
@ -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 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]
@ -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 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]
@ -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 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]
@ -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 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"))]
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 image: Arc<PngImage>,
pub data: Vec<u8>,
pub data_is_compressed: bool,
pub estimated_output_size: usize,
pub filter: RowFilter,
pub filter: FilterStrategy,
// For determining tie-breaker
nth: usize,
}
@ -44,7 +46,7 @@ impl Candidate {
/// Collect image versions and pick one that compresses best
pub(crate) struct Evaluator {
deadline: Arc<Deadline>,
filters: IndexSet<RowFilter>,
filters: IndexSet<FilterStrategy>,
deflater: Deflaters,
optimize_alpha: bool,
final_round: bool,
@ -62,7 +64,7 @@ pub(crate) struct Evaluator {
impl Evaluator {
pub fn new(
deadline: Arc<Deadline>,
filters: IndexSet<RowFilter>,
filters: IndexSet<FilterStrategy>,
deflater: Deflaters,
optimize_alpha: bool,
final_round: bool,

View file

@ -1,30 +1,67 @@
use std::{fmt, fmt::Display, mem::transmute};
use crate::error::PngError;
/// 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)]
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)]
pub enum RowFilter {
// Standard filter types
None,
Sub,
Up,
Average,
Paeth,
// Heuristic strategies
MinSum,
Entropy,
Bigrams,
BigEnt,
Brute,
}
impl TryFrom<u8> for RowFilter {
type Error = ();
fn try_from(value: u8) -> Result<Self, Self::Error> {
if value > Self::LAST {
if value > 4 {
return Err(());
}
unsafe { transmute(value as i8) }
@ -40,11 +77,6 @@ impl Display for RowFilter {
Self::Up => "Up",
Self::Average => "Average",
Self::Paeth => "Paeth",
Self::MinSum => "MinSum",
Self::Entropy => "Entropy",
Self::Bigrams => "Bigrams",
Self::BigEnt => "BigEnt",
Self::Brute => "Brute",
},
f,
)
@ -52,9 +84,7 @@ impl Display for RowFilter {
}
impl RowFilter {
pub const LAST: u8 = Self::Brute as u8;
pub(crate) const STANDARD: [Self; 5] =
[Self::None, Self::Sub, Self::Up, Self::Average, Self::Paeth];
pub(crate) const ALL: [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) fn filter_line(
@ -115,7 +145,6 @@ impl RowFilter {
});
}
}
_ => unreachable!(),
}
}
@ -140,6 +169,7 @@ impl RowFilter {
_ => i - 1,
};
match self {
Self::None => unreachable!(),
Self::Sub => {
for j in 0..color_bytes {
pixels[i][j] = pixels[prev][j];
@ -171,7 +201,6 @@ impl RowFilter {
};
}
}
_ => unreachable!(),
}
}
}
@ -183,7 +212,7 @@ impl RowFilter {
data: &[u8],
prev_line: &[u8],
buf: &mut Vec<u8>,
) -> Result<(), PngError> {
) {
buf.clear();
buf.reserve(data.len());
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},
deflate::Deflaters,
error::PngError,
filters::RowFilter,
filters::{FilterStrategy, RowFilter},
headers::StripChunks,
interlace::Interlacing,
options::{InFile, Options, OutFile},
@ -432,7 +432,7 @@ fn optimize_raw(
opts.filter.clone()
} else {
// 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
let eval = Evaluator::new(
@ -489,7 +489,7 @@ fn perform_trials(
deadline: Arc<Deadline>,
max_size: Option<usize>,
mut eval_result: Option<Candidate>,
eval_filters: IndexSet<RowFilter>,
eval_filters: IndexSet<FilterStrategy>,
eval_deflater: Deflaters,
) -> Option<Candidate> {
let mut filters = opts.filter.clone();
@ -548,10 +548,10 @@ fn perform_trials(
// Pick a filter automatically
if image.ihdr.bit_depth as u8 >= 8 {
// Bigrams is the best all-rounder when there's at least one byte per pixel
filters.insert(RowFilter::Bigrams);
filters.insert(FilterStrategy::Bigrams);
} else {
// 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,
opts: &Options,
deadline: Arc<Deadline>,
filter: RowFilter,
filter: FilterStrategy,
) -> PngResult<()> {
if !opts.idat_recoding || png.frames.is_empty() {
return Ok(());

View file

@ -26,7 +26,7 @@ use clap::ArgMatches;
mod cli;
use indexmap::IndexSet;
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 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
.mut_arg("filters", |arg| {
arg.value_parser(|x: &str| {
parse_numeric_range_opts(x, 0, RowFilter::LAST)
.map_err(|_| "Invalid option for filters")
parse_numeric_range_opts(x, 0, 9).map_err(|_| "Invalid option for filters")
})
})
.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 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].
/// You can use [`optimize_from_memory`](crate::optimize_from_memory) to avoid external I/O.
@ -94,10 +99,10 @@ pub struct Options {
///
/// Default: `false`
pub force: bool,
/// Which `RowFilters` to try on the file
/// Which `FilterStrategy` to try on the file
///
/// Default: `None,Sub,Entropy,Bigrams`
pub filter: IndexSet<RowFilter>,
pub filter: IndexSet<FilterStrategy>,
/// Whether to change the interlacing type of the file.
///
/// These are the interlacing types avaliable:
@ -207,10 +212,10 @@ impl Options {
fn apply_preset_3(mut self) -> Self {
self.fast_evaluation = false;
self.filter = indexset! {
RowFilter::None,
RowFilter::Bigrams,
RowFilter::BigEnt,
RowFilter::Brute
FilterStrategy::Basic(RowFilter::None),
FilterStrategy::Bigrams,
FilterStrategy::BigEnt,
FilterStrategy::Brute
};
self
}
@ -224,10 +229,10 @@ impl Options {
fn apply_preset_5(mut self) -> Self {
self.fast_evaluation = false;
self.filter.insert(RowFilter::Up);
self.filter.insert(RowFilter::MinSum);
self.filter.insert(RowFilter::BigEnt);
self.filter.insert(RowFilter::Brute);
self.filter.insert(FilterStrategy::Basic(RowFilter::Up));
self.filter.insert(FilterStrategy::MinSum);
self.filter.insert(FilterStrategy::BigEnt);
self.filter.insert(FilterStrategy::Brute);
if let Deflaters::Libdeflater { compression } = &mut self.deflate {
*compression = 12;
}
@ -235,8 +240,9 @@ impl Options {
}
fn apply_preset_6(mut self) -> Self {
self.filter.insert(RowFilter::Average);
self.filter.insert(RowFilter::Paeth);
self.filter
.insert(FilterStrategy::Basic(RowFilter::Average));
self.filter.insert(FilterStrategy::Basic(RowFilter::Paeth));
self.apply_preset_5()
}
}
@ -247,7 +253,12 @@ impl Default for Options {
Self {
fix_errors: 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),
optimize_alpha: false,
bit_depth_reduction: true,

View file

@ -376,7 +376,7 @@ impl PngImage {
}
last_line.resize(line.data.len(), 0);
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);
std::mem::swap(&mut last_line, &mut unfiltered_buf);
unfiltered_buf.clear();
@ -386,7 +386,7 @@ impl PngImage {
/// Apply the specified filter type to all rows in the image
#[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 bpp = self.bytes_per_channel() * self.channels_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
let mut line_data = line.data.to_vec();
if filter <= RowFilter::Paeth {
if let FilterStrategy::Basic(filter) = strategy {
// Standard filters
let filter = if prev_pass == line.pass || filter <= RowFilter::Sub {
filter
@ -431,12 +431,12 @@ impl PngImage {
let mut best_line_raw = Vec::new();
// Avoid vertical filtering on first line of each interlacing pass
let try_filters = if prev_pass == line.pass {
RowFilter::STANDARD.iter()
RowFilter::ALL.iter()
} else {
RowFilter::SINGLE_LINE.iter()
};
match filter {
RowFilter::MinSum => {
match strategy {
FilterStrategy::MinSum => {
// MSAD algorithm mentioned in libpng reference docs
// http://www.libpng.org/pub/png/book/chapter09.html
let mut best_size = usize::MAX;
@ -453,7 +453,7 @@ impl PngImage {
}
}
}
RowFilter::Entropy => {
FilterStrategy::Entropy => {
// Shannon entropy algorithm, from LodePNG
// https://github.com/lvandeve/lodepng
let mut best_size = i32::MIN;
@ -476,7 +476,7 @@ impl PngImage {
}
}
}
RowFilter::Bigrams => {
FilterStrategy::Bigrams => {
// Count distinct bigrams, from pngwolf
// https://bjoern.hoehrmann.de/pngwolf/
let mut best_size = usize::MAX;
@ -495,7 +495,7 @@ impl PngImage {
}
}
}
RowFilter::BigEnt => {
FilterStrategy::BigEnt => {
// Bigram entropy, combined from Entropy and Bigrams filters
let mut best_size = i32::MIN;
// 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
// Similar to that of LodePNG but includes some previous lines for context
let mut best_size = usize::MAX;

View file

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

View file

@ -16,7 +16,7 @@ fn get_opts(input: &Path) -> (OutFile, Options) {
let options = Options {
force: true,
fast_evaluation: false,
filter: indexset! {RowFilter::None},
filter: indexset! {FilterStrategy::Basic(RowFilter::None)},
..Default::default()
};
(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 (output, mut opts) = get_opts(&input);
opts.interlace = Some(Interlacing::Adam7);
opts.filter = indexset! {RowFilter::Paeth};
opts.filter = indexset! {FilterStrategy::Basic(RowFilter::Paeth)};
test_it_converts_callbacks(
input,

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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