Switch main compressor to libdeflate

This commit is contained in:
Andrew 2022-10-22 22:56:58 +13:00
parent f688d20fe6
commit 3e8fcc1335
3 changed files with 46 additions and 94 deletions

View file

@ -190,7 +190,7 @@ pub struct Options {
pub strip: Headers,
/// Which DEFLATE algorithm to use
///
/// Default: `Zlib`
/// Default: `Libdeflater`
pub deflate: Deflaters,
/// Whether to use heuristics to pick the best filter and compression
///
@ -212,10 +212,7 @@ impl Options {
1 => opts.apply_preset_1(),
2 => opts.apply_preset_2(),
3 => opts.apply_preset_3(),
4 => {
warn!("Level 4 is deprecated and is identical to level 3");
opts.apply_preset_4()
}
4 => opts.apply_preset_4(),
5 => opts.apply_preset_5(),
6 => opts.apply_preset_6(),
_ => {
@ -233,17 +230,20 @@ impl Options {
// on an `Options` struct generated by the `default` method.
fn apply_preset_0(mut self) -> Self {
self.idat_recoding = false;
if let Deflaters::Zlib { compression, .. } = &mut self.deflate {
self.filter.clear();
if let Deflaters::Libdeflater { compression } = &mut self.deflate {
compression.clear();
compression.insert(3);
compression.insert(5);
}
self.apply_preset_1()
self.use_heuristics = true;
self
}
fn apply_preset_1(mut self) -> Self {
self.filter.clear();
if let Deflaters::Zlib { strategies, .. } = &mut self.deflate {
strategies.clear();
if let Deflaters::Libdeflater { compression } = &mut self.deflate {
compression.clear();
compression.insert(10);
}
self.use_heuristics = true;
self
@ -254,34 +254,38 @@ impl Options {
}
fn apply_preset_3(mut self) -> Self {
for i in 1..5 {
for i in 1..=4 {
self.filter.insert(i);
}
self
}
fn apply_preset_4(self) -> Self {
fn apply_preset_4(mut self) -> Self {
if let Deflaters::Libdeflater { compression } = &mut self.deflate {
compression.clear();
compression.insert(12);
}
self.apply_preset_3()
}
fn apply_preset_5(mut self) -> Self {
if let Deflaters::Zlib { compression, .. } = &mut self.deflate {
if let Deflaters::Libdeflater { compression } = &mut self.deflate {
compression.clear();
for i in 3..10 {
for i in 9..=12 {
compression.insert(i);
}
}
self.apply_preset_4()
self.apply_preset_3()
}
fn apply_preset_6(mut self) -> Self {
if let Deflaters::Zlib { compression, .. } = &mut self.deflate {
if let Deflaters::Libdeflater { compression } = &mut self.deflate {
compression.clear();
for i in 1..10 {
for i in 1..=12 {
compression.insert(i);
}
}
self.apply_preset_4()
self.apply_preset_3()
}
}
@ -292,11 +296,7 @@ impl Default for Options {
filter.insert(0);
filter.insert(5);
let mut compression = IndexSet::new();
compression.insert(9);
let mut strategies = IndexSet::new();
for i in 0..4 {
strategies.insert(i);
}
compression.insert(11);
// We always need NoOp to be present
let mut alphas = IndexSet::new();
alphas.insert(AlphaOptim::NoOp);
@ -317,11 +317,7 @@ impl Default for Options {
grayscale_reduction: true,
idat_recoding: true,
strip: Headers::None,
deflate: Deflaters::Zlib {
compression,
strategies,
window: 15,
},
deflate: Deflaters::Libdeflater { compression },
use_heuristics: false,
timeout: None,
}

View file

@ -143,7 +143,7 @@ fn main() {
}
}))
.arg(Arg::new("compression")
.help("compression levels (zlib: 1-9, libdeflater: 1-12) - Default: 9 or 12")
.help("zlib compression levels (1-12) - Default: 12")
.long("zc")
.takes_value(true)
.value_name("levels")
@ -153,7 +153,7 @@ fn main() {
Err(_) => Err("Invalid option for compression".to_owned()),
}
})
.conflicts_with("zopfli"))
.conflicts_with_all(&["zopfli", "libdeflater"]))
.arg(Arg::new("strategies")
.help("zlib compression strategies (0-3) - Default: 0-3")
.long("zs")
@ -164,6 +164,7 @@ fn main() {
Err(_) => Err("Invalid option for strategies".to_owned()),
}
})
.hide(true)
.conflicts_with_all(&["zopfli", "libdeflater"]))
.arg(Arg::new("window")
.help("zlib window size - Default: 32k")
@ -178,6 +179,7 @@ fn main() {
.possible_value("8k")
.possible_value("16k")
.possible_value("32k")
.hide(true)
.conflicts_with_all(&["zopfli", "libdeflater"]))
.arg(Arg::new("no-bit-reduction")
.help("No bit depth reduction")
@ -204,7 +206,7 @@ fn main() {
.help("Write the output even if it is larger than the input")
.long("force"))
.arg(Arg::new("zopfli")
.help("Use the slower but better compressing Zopfli algorithm, overrides zlib-specific options")
.help("Use the slower but better compressing Zopfli algorithm")
.short('Z')
.long("zopfli")
.conflicts_with("libdeflater"))
@ -212,6 +214,7 @@ fn main() {
.help("Use an alternative Libdeflater algorithm, overrides zlib-specific options")
.short('D')
.long("libdeflater")
.hide(true)
.conflicts_with("zopfli"))
.arg(Arg::new("timeout")
.help("Maximum amount of time, in seconds, to spend on optimizations")
@ -237,16 +240,16 @@ fn main() {
}
}))
.after_help("Optimization levels:
-o 0 => --zc 3 --nz (0 or 1 trials)
-o 1 => --zc 9 (1 trial, determined heuristically)
-o 2 => --zc 9 --zs 0-3 -f 0,5 (8 trials with zlib or 2 trials with other compressors)
-o 3 => --zc 9 --zs 0-3 -f 0-5 (24 trials with zlib or 6 trials with other compressors)
-o 4 => (deprecated; same as `-o 3`)
-o 5 => --zc 3-9 --zs 0-3 -f 0-5 (168 trials with zlib; same as `-o 3` for other compressors)
-o 6 => --zc 1-9 --zs 0-3 -f 0-5 (216 trials with zlib; same as `-o 3` for other compressors)
-o max => (stable alias for the max compression)
-o 0 => --zc 6 --nz (0 or 1 trials)
-o 1 => --zc 10 (1 trial, determined heuristically)
-o 2 => --zc 11 -f 0,5 (2 trials)
-o 3 => --zc 11 -f 0-5 (6 trials)
-o 4 => --zc 12 -f 0-5 (6 trials; same as `-o 3` for zopfli)
-o 5 => --zc 9-12 -f 0-5 (24 trials; same as `-o 3` for zopfli)
-o 6 => --zc 1-12 -f 0-5 (72 trials; same as `-o 3` for zopfli)
-o max => (stable alias for the max compression)
Manually specifying a compression option (zc, zs, etc.) will override the optimization preset,
Manually specifying a compression option (zc, f, etc.) will override the optimization preset,
regardless of the order you write the arguments.")
.get_matches_from(wild::args());
@ -501,46 +504,19 @@ fn parse_opts_into_struct(
};
} else if matches.is_present("libdeflater") {
opts.deflate = Deflaters::Libdeflater {
compression: match matches.value_of("compression") {
Some(x) => parse_numeric_range_opts(x, 1, 12).unwrap(),
_ => indexset! { 12 },
},
compression: indexset! { 12 },
};
} else if let Deflaters::Zlib {
compression,
strategies,
window,
} = &mut opts.deflate
{
} else if let Deflaters::Libdeflater { compression } = &mut opts.deflate {
if let Some(x) = matches.value_of("compression") {
*compression = parse_numeric_range_opts(x, 1, 9)
.map_err(|_| "Compression levels 10-12 are only valid for libdeflater".to_owned())?
}
if let Some(x) = matches.value_of("strategies") {
*strategies = parse_numeric_range_opts(x, 0, 3).unwrap();
}
match matches.value_of("window") {
Some("256") => *window = 8,
Some("512") => *window = 9,
Some("1k") => *window = 10,
Some("2k") => *window = 11,
Some("4k") => *window = 12,
Some("8k") => *window = 13,
Some("16k") => *window = 14,
// 32k is default
_ => (),
*compression = parse_numeric_range_opts(x, 1, 12).unwrap();
}
}
if explicit_level > Some(3) {
match opts.deflate {
Deflaters::Zlib { .. } => {}
Deflaters::Libdeflater { .. } => {}
_ => {
warn!(
"Level 4 and above are equivalent to level 3 for compressors other than zlib"
);
warn!("Level 4 and above are equivalent to level 3 for zopfli");
}
}
}

View file

@ -170,10 +170,10 @@ fn verbose_mode() {
});
let mut logs: Vec<_> = receiver.into_iter().collect();
assert_eq!(logs.len(), 4);
assert_eq!(logs.len(), 1);
logs.sort();
for (i, log) in logs.into_iter().enumerate() {
let expected_prefix = format!(" zc = 9 zs = {} f = 0 ", i);
let expected_prefix = format!(" zc = 11 zs = 0 f = 0 ");
assert!(
log.starts_with(&expected_prefix),
"logs[{}] = {:?} doesn't start with {:?}",
@ -597,23 +597,3 @@ fn zopfli_mode() {
BitDepth::Eight,
);
}
#[test]
#[cfg(feature = "libdeflater")]
fn libdeflater_mode() {
let input = PathBuf::from("tests/files/zopfli_mode.png");
let (output, mut opts) = get_opts(&input);
let mut compression = IndexSet::new();
compression.insert(0);
opts.deflate = Deflaters::Libdeflater { compression };
test_it_converts(
input,
&output,
&opts,
ColorType::RGB,
BitDepth::Eight,
ColorType::RGB,
BitDepth::Eight,
);
}