Switch main compressor to libdeflate
This commit is contained in:
parent
f688d20fe6
commit
3e8fcc1335
3 changed files with 46 additions and 94 deletions
52
src/lib.rs
52
src/lib.rs
|
|
@ -190,7 +190,7 @@ pub struct Options {
|
||||||
pub strip: Headers,
|
pub strip: Headers,
|
||||||
/// Which DEFLATE algorithm to use
|
/// Which DEFLATE algorithm to use
|
||||||
///
|
///
|
||||||
/// Default: `Zlib`
|
/// Default: `Libdeflater`
|
||||||
pub deflate: Deflaters,
|
pub deflate: Deflaters,
|
||||||
/// Whether to use heuristics to pick the best filter and compression
|
/// Whether to use heuristics to pick the best filter and compression
|
||||||
///
|
///
|
||||||
|
|
@ -212,10 +212,7 @@ impl Options {
|
||||||
1 => opts.apply_preset_1(),
|
1 => opts.apply_preset_1(),
|
||||||
2 => opts.apply_preset_2(),
|
2 => opts.apply_preset_2(),
|
||||||
3 => opts.apply_preset_3(),
|
3 => opts.apply_preset_3(),
|
||||||
4 => {
|
4 => opts.apply_preset_4(),
|
||||||
warn!("Level 4 is deprecated and is identical to level 3");
|
|
||||||
opts.apply_preset_4()
|
|
||||||
}
|
|
||||||
5 => opts.apply_preset_5(),
|
5 => opts.apply_preset_5(),
|
||||||
6 => opts.apply_preset_6(),
|
6 => opts.apply_preset_6(),
|
||||||
_ => {
|
_ => {
|
||||||
|
|
@ -233,17 +230,20 @@ impl Options {
|
||||||
// on an `Options` struct generated by the `default` method.
|
// on an `Options` struct generated by the `default` method.
|
||||||
fn apply_preset_0(mut self) -> Self {
|
fn apply_preset_0(mut self) -> Self {
|
||||||
self.idat_recoding = false;
|
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.clear();
|
||||||
compression.insert(3);
|
compression.insert(5);
|
||||||
}
|
}
|
||||||
self.apply_preset_1()
|
self.use_heuristics = true;
|
||||||
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply_preset_1(mut self) -> Self {
|
fn apply_preset_1(mut self) -> Self {
|
||||||
self.filter.clear();
|
self.filter.clear();
|
||||||
if let Deflaters::Zlib { strategies, .. } = &mut self.deflate {
|
if let Deflaters::Libdeflater { compression } = &mut self.deflate {
|
||||||
strategies.clear();
|
compression.clear();
|
||||||
|
compression.insert(10);
|
||||||
}
|
}
|
||||||
self.use_heuristics = true;
|
self.use_heuristics = true;
|
||||||
self
|
self
|
||||||
|
|
@ -254,34 +254,38 @@ impl Options {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply_preset_3(mut self) -> Self {
|
fn apply_preset_3(mut self) -> Self {
|
||||||
for i in 1..5 {
|
for i in 1..=4 {
|
||||||
self.filter.insert(i);
|
self.filter.insert(i);
|
||||||
}
|
}
|
||||||
self
|
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()
|
self.apply_preset_3()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply_preset_5(mut self) -> Self {
|
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();
|
compression.clear();
|
||||||
for i in 3..10 {
|
for i in 9..=12 {
|
||||||
compression.insert(i);
|
compression.insert(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.apply_preset_4()
|
self.apply_preset_3()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply_preset_6(mut self) -> Self {
|
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();
|
compression.clear();
|
||||||
for i in 1..10 {
|
for i in 1..=12 {
|
||||||
compression.insert(i);
|
compression.insert(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.apply_preset_4()
|
self.apply_preset_3()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -292,11 +296,7 @@ impl Default for Options {
|
||||||
filter.insert(0);
|
filter.insert(0);
|
||||||
filter.insert(5);
|
filter.insert(5);
|
||||||
let mut compression = IndexSet::new();
|
let mut compression = IndexSet::new();
|
||||||
compression.insert(9);
|
compression.insert(11);
|
||||||
let mut strategies = IndexSet::new();
|
|
||||||
for i in 0..4 {
|
|
||||||
strategies.insert(i);
|
|
||||||
}
|
|
||||||
// We always need NoOp to be present
|
// We always need NoOp to be present
|
||||||
let mut alphas = IndexSet::new();
|
let mut alphas = IndexSet::new();
|
||||||
alphas.insert(AlphaOptim::NoOp);
|
alphas.insert(AlphaOptim::NoOp);
|
||||||
|
|
@ -317,11 +317,7 @@ impl Default for Options {
|
||||||
grayscale_reduction: true,
|
grayscale_reduction: true,
|
||||||
idat_recoding: true,
|
idat_recoding: true,
|
||||||
strip: Headers::None,
|
strip: Headers::None,
|
||||||
deflate: Deflaters::Zlib {
|
deflate: Deflaters::Libdeflater { compression },
|
||||||
compression,
|
|
||||||
strategies,
|
|
||||||
window: 15,
|
|
||||||
},
|
|
||||||
use_heuristics: false,
|
use_heuristics: false,
|
||||||
timeout: None,
|
timeout: None,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
62
src/main.rs
62
src/main.rs
|
|
@ -143,7 +143,7 @@ fn main() {
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
.arg(Arg::new("compression")
|
.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")
|
.long("zc")
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
.value_name("levels")
|
.value_name("levels")
|
||||||
|
|
@ -153,7 +153,7 @@ fn main() {
|
||||||
Err(_) => Err("Invalid option for compression".to_owned()),
|
Err(_) => Err("Invalid option for compression".to_owned()),
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.conflicts_with("zopfli"))
|
.conflicts_with_all(&["zopfli", "libdeflater"]))
|
||||||
.arg(Arg::new("strategies")
|
.arg(Arg::new("strategies")
|
||||||
.help("zlib compression strategies (0-3) - Default: 0-3")
|
.help("zlib compression strategies (0-3) - Default: 0-3")
|
||||||
.long("zs")
|
.long("zs")
|
||||||
|
|
@ -164,6 +164,7 @@ fn main() {
|
||||||
Err(_) => Err("Invalid option for strategies".to_owned()),
|
Err(_) => Err("Invalid option for strategies".to_owned()),
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
.hide(true)
|
||||||
.conflicts_with_all(&["zopfli", "libdeflater"]))
|
.conflicts_with_all(&["zopfli", "libdeflater"]))
|
||||||
.arg(Arg::new("window")
|
.arg(Arg::new("window")
|
||||||
.help("zlib window size - Default: 32k")
|
.help("zlib window size - Default: 32k")
|
||||||
|
|
@ -178,6 +179,7 @@ fn main() {
|
||||||
.possible_value("8k")
|
.possible_value("8k")
|
||||||
.possible_value("16k")
|
.possible_value("16k")
|
||||||
.possible_value("32k")
|
.possible_value("32k")
|
||||||
|
.hide(true)
|
||||||
.conflicts_with_all(&["zopfli", "libdeflater"]))
|
.conflicts_with_all(&["zopfli", "libdeflater"]))
|
||||||
.arg(Arg::new("no-bit-reduction")
|
.arg(Arg::new("no-bit-reduction")
|
||||||
.help("No bit depth reduction")
|
.help("No bit depth reduction")
|
||||||
|
|
@ -204,7 +206,7 @@ fn main() {
|
||||||
.help("Write the output even if it is larger than the input")
|
.help("Write the output even if it is larger than the input")
|
||||||
.long("force"))
|
.long("force"))
|
||||||
.arg(Arg::new("zopfli")
|
.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')
|
.short('Z')
|
||||||
.long("zopfli")
|
.long("zopfli")
|
||||||
.conflicts_with("libdeflater"))
|
.conflicts_with("libdeflater"))
|
||||||
|
|
@ -212,6 +214,7 @@ fn main() {
|
||||||
.help("Use an alternative Libdeflater algorithm, overrides zlib-specific options")
|
.help("Use an alternative Libdeflater algorithm, overrides zlib-specific options")
|
||||||
.short('D')
|
.short('D')
|
||||||
.long("libdeflater")
|
.long("libdeflater")
|
||||||
|
.hide(true)
|
||||||
.conflicts_with("zopfli"))
|
.conflicts_with("zopfli"))
|
||||||
.arg(Arg::new("timeout")
|
.arg(Arg::new("timeout")
|
||||||
.help("Maximum amount of time, in seconds, to spend on optimizations")
|
.help("Maximum amount of time, in seconds, to spend on optimizations")
|
||||||
|
|
@ -237,16 +240,16 @@ fn main() {
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
.after_help("Optimization levels:
|
.after_help("Optimization levels:
|
||||||
-o 0 => --zc 3 --nz (0 or 1 trials)
|
-o 0 => --zc 6 --nz (0 or 1 trials)
|
||||||
-o 1 => --zc 9 (1 trial, determined heuristically)
|
-o 1 => --zc 10 (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 2 => --zc 11 -f 0,5 (2 trials)
|
||||||
-o 3 => --zc 9 --zs 0-3 -f 0-5 (24 trials with zlib or 6 trials with other compressors)
|
-o 3 => --zc 11 -f 0-5 (6 trials)
|
||||||
-o 4 => (deprecated; same as `-o 3`)
|
-o 4 => --zc 12 -f 0-5 (6 trials; same as `-o 3` for zopfli)
|
||||||
-o 5 => --zc 3-9 --zs 0-3 -f 0-5 (168 trials with zlib; same as `-o 3` for other compressors)
|
-o 5 => --zc 9-12 -f 0-5 (24 trials; same as `-o 3` for zopfli)
|
||||||
-o 6 => --zc 1-9 --zs 0-3 -f 0-5 (216 trials with zlib; same as `-o 3` for other compressors)
|
-o 6 => --zc 1-12 -f 0-5 (72 trials; same as `-o 3` for zopfli)
|
||||||
-o max => (stable alias for the max compression)
|
-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.")
|
regardless of the order you write the arguments.")
|
||||||
.get_matches_from(wild::args());
|
.get_matches_from(wild::args());
|
||||||
|
|
||||||
|
|
@ -501,46 +504,19 @@ fn parse_opts_into_struct(
|
||||||
};
|
};
|
||||||
} else if matches.is_present("libdeflater") {
|
} else if matches.is_present("libdeflater") {
|
||||||
opts.deflate = Deflaters::Libdeflater {
|
opts.deflate = Deflaters::Libdeflater {
|
||||||
compression: match matches.value_of("compression") {
|
compression: indexset! { 12 },
|
||||||
Some(x) => parse_numeric_range_opts(x, 1, 12).unwrap(),
|
|
||||||
_ => indexset! { 12 },
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
} else if let Deflaters::Zlib {
|
} else if let Deflaters::Libdeflater { compression } = &mut opts.deflate {
|
||||||
compression,
|
|
||||||
strategies,
|
|
||||||
window,
|
|
||||||
} = &mut opts.deflate
|
|
||||||
{
|
|
||||||
if let Some(x) = matches.value_of("compression") {
|
if let Some(x) = matches.value_of("compression") {
|
||||||
*compression = parse_numeric_range_opts(x, 1, 9)
|
*compression = parse_numeric_range_opts(x, 1, 12).unwrap();
|
||||||
.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
|
|
||||||
_ => (),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if explicit_level > Some(3) {
|
if explicit_level > Some(3) {
|
||||||
match opts.deflate {
|
match opts.deflate {
|
||||||
Deflaters::Zlib { .. } => {}
|
Deflaters::Libdeflater { .. } => {}
|
||||||
_ => {
|
_ => {
|
||||||
warn!(
|
warn!("Level 4 and above are equivalent to level 3 for zopfli");
|
||||||
"Level 4 and above are equivalent to level 3 for compressors other than zlib"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -170,10 +170,10 @@ fn verbose_mode() {
|
||||||
});
|
});
|
||||||
|
|
||||||
let mut logs: Vec<_> = receiver.into_iter().collect();
|
let mut logs: Vec<_> = receiver.into_iter().collect();
|
||||||
assert_eq!(logs.len(), 4);
|
assert_eq!(logs.len(), 1);
|
||||||
logs.sort();
|
logs.sort();
|
||||||
for (i, log) in logs.into_iter().enumerate() {
|
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!(
|
assert!(
|
||||||
log.starts_with(&expected_prefix),
|
log.starts_with(&expected_prefix),
|
||||||
"logs[{}] = {:?} doesn't start with {:?}",
|
"logs[{}] = {:?} doesn't start with {:?}",
|
||||||
|
|
@ -597,23 +597,3 @@ fn zopfli_mode() {
|
||||||
BitDepth::Eight,
|
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,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue