diff --git a/benches/deflate.rs b/benches/deflate.rs index 29bfada9..d83e3230 100644 --- a/benches/deflate.rs +++ b/benches/deflate.rs @@ -7,7 +7,6 @@ use std::path::PathBuf; use test::Bencher; use oxipng::internal_tests::*; -use oxipng::Deadline; #[bench] fn deflate_16_bits_strategy_0(b: &mut Bencher) { @@ -16,7 +15,7 @@ fn deflate_16_bits_strategy_0(b: &mut Bencher) { b.iter(|| { let min = AtomicMin::new(None); - deflate(png.raw.data.as_ref(), 9, 0, 15, &min, &Deadline::new(None)) + deflate(png.raw.data.as_ref(), 12, &min) }); } @@ -27,7 +26,7 @@ fn deflate_8_bits_strategy_0(b: &mut Bencher) { b.iter(|| { let min = AtomicMin::new(None); - deflate(png.raw.data.as_ref(), 9, 0, 15, &min, &Deadline::new(None)) + deflate(png.raw.data.as_ref(), 12, &min) }); } @@ -40,7 +39,7 @@ fn deflate_4_bits_strategy_0(b: &mut Bencher) { b.iter(|| { let min = AtomicMin::new(None); - deflate(png.raw.data.as_ref(), 9, 0, 15, &min, &Deadline::new(None)) + deflate(png.raw.data.as_ref(), 12, &min) }); } @@ -53,7 +52,7 @@ fn deflate_2_bits_strategy_0(b: &mut Bencher) { b.iter(|| { let min = AtomicMin::new(None); - deflate(png.raw.data.as_ref(), 9, 0, 15, &min, &Deadline::new(None)) + deflate(png.raw.data.as_ref(), 12, &min) }); } @@ -66,7 +65,7 @@ fn deflate_1_bits_strategy_0(b: &mut Bencher) { b.iter(|| { let min = AtomicMin::new(None); - deflate(png.raw.data.as_ref(), 9, 0, 15, &min, &Deadline::new(None)) + deflate(png.raw.data.as_ref(), 12, &min) }); } @@ -77,7 +76,7 @@ fn deflate_16_bits_strategy_1(b: &mut Bencher) { b.iter(|| { let min = AtomicMin::new(None); - deflate(png.raw.data.as_ref(), 9, 1, 15, &min, &Deadline::new(None)) + deflate(png.raw.data.as_ref(), 12, &min) }); } @@ -88,7 +87,7 @@ fn deflate_8_bits_strategy_1(b: &mut Bencher) { b.iter(|| { let min = AtomicMin::new(None); - deflate(png.raw.data.as_ref(), 9, 1, 15, &min, &Deadline::new(None)) + deflate(png.raw.data.as_ref(), 12, &min) }); } @@ -101,7 +100,7 @@ fn deflate_4_bits_strategy_1(b: &mut Bencher) { b.iter(|| { let min = AtomicMin::new(None); - deflate(png.raw.data.as_ref(), 9, 1, 15, &min, &Deadline::new(None)) + deflate(png.raw.data.as_ref(), 12, &min) }); } @@ -114,7 +113,7 @@ fn deflate_2_bits_strategy_1(b: &mut Bencher) { b.iter(|| { let min = AtomicMin::new(None); - deflate(png.raw.data.as_ref(), 9, 1, 15, &min, &Deadline::new(None)) + deflate(png.raw.data.as_ref(), 12, &min) }); } @@ -127,7 +126,7 @@ fn deflate_1_bits_strategy_1(b: &mut Bencher) { b.iter(|| { let min = AtomicMin::new(None); - deflate(png.raw.data.as_ref(), 9, 1, 15, &min, &Deadline::new(None)) + deflate(png.raw.data.as_ref(), 12, &min) }); } @@ -138,7 +137,7 @@ fn deflate_16_bits_strategy_2(b: &mut Bencher) { b.iter(|| { let min = AtomicMin::new(None); - deflate(png.raw.data.as_ref(), 9, 2, 15, &min, &Deadline::new(None)) + deflate(png.raw.data.as_ref(), 12, &min) }); } @@ -149,7 +148,7 @@ fn deflate_8_bits_strategy_2(b: &mut Bencher) { b.iter(|| { let min = AtomicMin::new(None); - deflate(png.raw.data.as_ref(), 9, 2, 15, &min, &Deadline::new(None)) + deflate(png.raw.data.as_ref(), 12, &min) }); } @@ -162,7 +161,7 @@ fn deflate_4_bits_strategy_2(b: &mut Bencher) { b.iter(|| { let min = AtomicMin::new(None); - deflate(png.raw.data.as_ref(), 9, 2, 15, &min, &Deadline::new(None)) + deflate(png.raw.data.as_ref(), 12, &min) }); } @@ -175,7 +174,7 @@ fn deflate_2_bits_strategy_2(b: &mut Bencher) { b.iter(|| { let min = AtomicMin::new(None); - deflate(png.raw.data.as_ref(), 9, 2, 15, &min, &Deadline::new(None)) + deflate(png.raw.data.as_ref(), 12, &min) }); } @@ -188,7 +187,7 @@ fn deflate_1_bits_strategy_2(b: &mut Bencher) { b.iter(|| { let min = AtomicMin::new(None); - deflate(png.raw.data.as_ref(), 9, 2, 15, &min, &Deadline::new(None)) + deflate(png.raw.data.as_ref(), 12, &min) }); } @@ -199,7 +198,7 @@ fn deflate_16_bits_strategy_3(b: &mut Bencher) { b.iter(|| { let min = AtomicMin::new(None); - deflate(png.raw.data.as_ref(), 9, 3, 15, &min, &Deadline::new(None)) + deflate(png.raw.data.as_ref(), 12, &min) }); } @@ -210,7 +209,7 @@ fn deflate_8_bits_strategy_3(b: &mut Bencher) { b.iter(|| { let min = AtomicMin::new(None); - deflate(png.raw.data.as_ref(), 9, 3, 15, &min, &Deadline::new(None)) + deflate(png.raw.data.as_ref(), 12, &min) }); } @@ -223,7 +222,7 @@ fn deflate_4_bits_strategy_3(b: &mut Bencher) { b.iter(|| { let min = AtomicMin::new(None); - deflate(png.raw.data.as_ref(), 9, 3, 15, &min, &Deadline::new(None)) + deflate(png.raw.data.as_ref(), 12, &min) }); } @@ -236,7 +235,7 @@ fn deflate_2_bits_strategy_3(b: &mut Bencher) { b.iter(|| { let min = AtomicMin::new(None); - deflate(png.raw.data.as_ref(), 9, 3, 15, &min, &Deadline::new(None)) + deflate(png.raw.data.as_ref(), 12, &min) }); } @@ -249,7 +248,7 @@ fn deflate_1_bits_strategy_3(b: &mut Bencher) { b.iter(|| { let min = AtomicMin::new(None); - deflate(png.raw.data.as_ref(), 9, 3, 15, &min, &Deadline::new(None)) + deflate(png.raw.data.as_ref(), 12, &min) }); } @@ -258,5 +257,5 @@ fn inflate_generic(b: &mut Bencher) { let input = test::black_box(PathBuf::from("tests/files/rgb_16_should_be_rgb_16.png")); let png = PngData::new(&input, false).unwrap(); - b.iter(|| inflate(png.idat_data.as_ref())); + b.iter(|| inflate(png.idat_data.as_ref(), png.raw.ihdr.raw_data_size())); } diff --git a/benches/libdeflater.rs b/benches/libdeflater.rs deleted file mode 100644 index d7917a0c..00000000 --- a/benches/libdeflater.rs +++ /dev/null @@ -1,64 +0,0 @@ -#![feature(test)] - -extern crate oxipng; -extern crate test; - -use oxipng::internal_tests::*; -use std::path::PathBuf; -use test::Bencher; - -#[bench] -fn libdeflater_16_bits_strategy_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, false).unwrap(); - - b.iter(|| { - libdeflater_deflate(png.raw.data.as_ref(), 12, &AtomicMin::new(None)).ok(); - }); -} - -#[bench] -fn libdeflater_8_bits_strategy_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, false).unwrap(); - - b.iter(|| { - libdeflater_deflate(png.raw.data.as_ref(), 12, &AtomicMin::new(None)).ok(); - }); -} - -#[bench] -fn libdeflater_4_bits_strategy_0(b: &mut Bencher) { - let input = test::black_box(PathBuf::from( - "tests/files/palette_4_should_be_palette_4.png", - )); - let png = PngData::new(&input, false).unwrap(); - - b.iter(|| { - libdeflater_deflate(png.raw.data.as_ref(), 12, &AtomicMin::new(None)).ok(); - }); -} - -#[bench] -fn libdeflater_2_bits_strategy_0(b: &mut Bencher) { - let input = test::black_box(PathBuf::from( - "tests/files/palette_2_should_be_palette_2.png", - )); - let png = PngData::new(&input, false).unwrap(); - - b.iter(|| { - libdeflater_deflate(png.raw.data.as_ref(), 12, &AtomicMin::new(None)).ok(); - }); -} - -#[bench] -fn libdeflater_1_bits_strategy_0(b: &mut Bencher) { - let input = test::black_box(PathBuf::from( - "tests/files/palette_1_should_be_palette_1.png", - )); - let png = PngData::new(&input, false).unwrap(); - - b.iter(|| { - libdeflater_deflate(png.raw.data.as_ref(), 12, &AtomicMin::new(None)).ok(); - }); -} diff --git a/src/main.rs b/src/main.rs index 9fd1d3f2..d950dd1d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -33,202 +33,214 @@ fn main() { .author("Joshua Holmer ") .about("Losslessly improves compression of PNG files") .setting(AppSettings::DeriveDisplayOrder) - .arg(Arg::new("files") - .help("File(s) to compress (use \"-\" for stdin)") - .index(1) - .multiple_values(true) - .use_value_delimiter(false) - .required(true)) - .arg(Arg::new("optimization") - .help("Optimization level - Default: 2") - .short('o') - .long("opt") - .takes_value(true) - .value_name("level") - .possible_value("0") - .possible_value("1") - .possible_value("2") - .possible_value("3") - .possible_value("4") - .possible_value("5") - .possible_value("6") - .possible_value("max")) - .arg(Arg::new("backup") - .help("Back up modified files") - .short('b') - .long("backup")) - .arg(Arg::new("recursive") - .help("Recurse into subdirectories") - .short('r') - .long("recursive")) - .arg(Arg::new("output_dir") - .help("Write output file(s) to ") - .long("dir") - .takes_value(true) - .value_name("directory") - .conflicts_with("output_file") - .conflicts_with("stdout")) - .arg(Arg::new("output_file") - .help("Write output file to ") - .long("out") - .takes_value(true) - .value_name("file") - .conflicts_with("output_dir") - .conflicts_with("stdout")) - .arg(Arg::new("stdout") - .help("Write output to stdout") - .long("stdout") - .conflicts_with("output_dir") - .conflicts_with("output_file")) - .arg(Arg::new("preserve") - .help("Preserve file attributes if possible") - .short('p') - .long("preserve")) - .arg(Arg::new("check") - .help("Do not run any optimization passes") - .short('c') - .long("check")) - .arg(Arg::new("pretend") - .help("Do not write any files, only calculate compression gains") - .short('P') - .long("pretend")) - .arg(Arg::new("strip-safe") - .help("Strip safely-removable metadata objects") - .short('s') - .conflicts_with("strip")) - .arg(Arg::new("strip") - .help("Strip metadata objects ['safe', 'all', or comma-separated list]") - .long("strip") - .takes_value(true) - .value_name("mode") - .conflicts_with("strip-safe")) - .arg(Arg::new("keep") - .help("Strip all optional metadata except objects in the comma-separated list") - .long("keep") - .takes_value(true) - .value_name("list") - .conflicts_with("strip") - .conflicts_with("strip-safe")) - .arg(Arg::new("alpha") - .help("Perform additional alpha optimizations") - .short('a') - .long("alpha")) - .arg(Arg::new("interlace") - .help("PNG interlace type") - .short('i') - .long("interlace") - .takes_value(true) - .value_name("0/1") - .possible_value("0") - .possible_value("1")) - .arg(Arg::new("verbose") - .help("Run in verbose mode") - .short('v') - .long("verbose") - .conflicts_with("quiet")) - .arg(Arg::new("quiet") - .help("Run in quiet mode") - .short('q') - .long("quiet") - .conflicts_with("verbose")) - .arg(Arg::new("filters") - .help("PNG delta filters (0-5) - Default: 0,5") - .short('f') - .long("filters") - .takes_value(true) - .validator(|x| { - match parse_numeric_range_opts(x, 0, 5) { + .arg( + Arg::new("files") + .help("File(s) to compress (use \"-\" for stdin)") + .index(1) + .multiple_values(true) + .use_value_delimiter(false) + .required(true), + ) + .arg( + Arg::new("optimization") + .help("Optimization level - Default: 2") + .short('o') + .long("opt") + .takes_value(true) + .value_name("level") + .possible_value("0") + .possible_value("1") + .possible_value("2") + .possible_value("3") + .possible_value("4") + .possible_value("5") + .possible_value("6") + .possible_value("max"), + ) + .arg( + Arg::new("backup") + .help("Back up modified files") + .short('b') + .long("backup"), + ) + .arg( + Arg::new("recursive") + .help("Recurse into subdirectories") + .short('r') + .long("recursive"), + ) + .arg( + Arg::new("output_dir") + .help("Write output file(s) to ") + .long("dir") + .takes_value(true) + .value_name("directory") + .conflicts_with("output_file") + .conflicts_with("stdout"), + ) + .arg( + Arg::new("output_file") + .help("Write output file to ") + .long("out") + .takes_value(true) + .value_name("file") + .conflicts_with("output_dir") + .conflicts_with("stdout"), + ) + .arg( + Arg::new("stdout") + .help("Write output to stdout") + .long("stdout") + .conflicts_with("output_dir") + .conflicts_with("output_file"), + ) + .arg( + Arg::new("preserve") + .help("Preserve file attributes if possible") + .short('p') + .long("preserve"), + ) + .arg( + Arg::new("check") + .help("Do not run any optimization passes") + .short('c') + .long("check"), + ) + .arg( + Arg::new("pretend") + .help("Do not write any files, only calculate compression gains") + .short('P') + .long("pretend"), + ) + .arg( + Arg::new("strip-safe") + .help("Strip safely-removable metadata objects") + .short('s') + .conflicts_with("strip"), + ) + .arg( + Arg::new("strip") + .help("Strip metadata objects ['safe', 'all', or comma-separated list]") + .long("strip") + .takes_value(true) + .value_name("mode") + .conflicts_with("strip-safe"), + ) + .arg( + Arg::new("keep") + .help("Strip all optional metadata except objects in the comma-separated list") + .long("keep") + .takes_value(true) + .value_name("list") + .conflicts_with("strip") + .conflicts_with("strip-safe"), + ) + .arg( + Arg::new("alpha") + .help("Perform additional alpha optimizations") + .short('a') + .long("alpha"), + ) + .arg( + Arg::new("interlace") + .help("PNG interlace type") + .short('i') + .long("interlace") + .takes_value(true) + .value_name("0/1") + .possible_value("0") + .possible_value("1"), + ) + .arg( + Arg::new("verbose") + .help("Run in verbose mode") + .short('v') + .long("verbose") + .conflicts_with("quiet"), + ) + .arg( + Arg::new("quiet") + .help("Run in quiet mode") + .short('q') + .long("quiet") + .conflicts_with("verbose"), + ) + .arg( + Arg::new("filters") + .help("PNG delta filters (0-5) - Default: 0,5") + .short('f') + .long("filters") + .takes_value(true) + .validator(|x| match parse_numeric_range_opts(x, 0, 5) { Ok(_) => Ok(()), Err(_) => Err("Invalid option for filters".to_owned()), - } - })) - .arg(Arg::new("compression") - .help("zlib compression levels (1-12) - Default: 12") - .long("zc") - .takes_value(true) - .value_name("levels") - .validator(|x| { - match parse_numeric_range_opts(x, 1, 12) { + }), + ) + .arg( + Arg::new("compression") + .help("zlib compression levels (1-12) - Default: 12") + .long("zc") + .takes_value(true) + .value_name("levels") + .validator(|x| match parse_numeric_range_opts(x, 1, 12) { Ok(_) => Ok(()), Err(_) => Err("Invalid option for compression".to_owned()), - } - }) - .conflicts_with_all(&["zopfli", "libdeflater"])) - .arg(Arg::new("strategies") - .help("zlib compression strategies (0-3) - Default: 0-3") - .long("zs") - .takes_value(true) - .validator(|x| { - match parse_numeric_range_opts(x, 0, 3) { - Ok(_) => Ok(()), - 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") - .long("zw") - .takes_value(true) - .value_name("size") - .possible_value("256") - .possible_value("512") - .possible_value("1k") - .possible_value("2k") - .possible_value("4k") - .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") - .long("nb")) - .arg(Arg::new("no-color-reduction") - .help("No color type reduction") - .long("nc")) - .arg(Arg::new("no-palette-reduction") - .help("No palette reduction") - .long("np")) - .arg(Arg::new("no-grayscale-reduction") - .help("No grayscale reduction") - .long("ng")) - .arg(Arg::new("no-reductions") - .help("No reductions") - .long("nx")) - .arg(Arg::new("no-recoding") - .help("No IDAT recoding unless necessary") - .long("nz")) - .arg(Arg::new("fix") - .help("Enable error recovery") - .long("fix")) - .arg(Arg::new("force") - .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") - .short('Z') - .long("zopfli") - .conflicts_with("libdeflater")) - .arg(Arg::new("libdeflater") - .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") - .takes_value(true) - .value_name("secs") - .long("timeout")) - .arg(Arg::new("threads") - .help("Set number of threads to use - default 1.5x CPU cores") - .long("threads") - .short('t') - .takes_value(true) - .value_name("num") - .validator(|x| { - match x.parse::() { + }) + .conflicts_with("zopfli"), + ) + .arg( + Arg::new("no-bit-reduction") + .help("No bit depth reduction") + .long("nb"), + ) + .arg( + Arg::new("no-color-reduction") + .help("No color type reduction") + .long("nc"), + ) + .arg( + Arg::new("no-palette-reduction") + .help("No palette reduction") + .long("np"), + ) + .arg( + Arg::new("no-grayscale-reduction") + .help("No grayscale reduction") + .long("ng"), + ) + .arg(Arg::new("no-reductions").help("No reductions").long("nx")) + .arg( + Arg::new("no-recoding") + .help("No IDAT recoding unless necessary") + .long("nz"), + ) + .arg(Arg::new("fix").help("Enable error recovery").long("fix")) + .arg( + Arg::new("force") + .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") + .short('Z') + .long("zopfli"), + ) + .arg( + Arg::new("timeout") + .help("Maximum amount of time, in seconds, to spend on optimizations") + .takes_value(true) + .value_name("secs") + .long("timeout"), + ) + .arg( + Arg::new("threads") + .help("Set number of threads to use - default 1.5x CPU cores") + .long("threads") + .short('t') + .takes_value(true) + .value_name("num") + .validator(|x| match x.parse::() { Ok(val) => { if val > 0 { Ok(()) @@ -237,9 +249,10 @@ fn main() { } } Err(_) => Err("Thread count must be >= 1".to_owned()), - } - })) - .after_help("Optimization levels: + }), + ) + .after_help( + "Optimization levels: -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) @@ -250,7 +263,8 @@ fn main() { -o max => (stable alias for the max compression) 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()); let (out_file, out_dir, opts) = match parse_opts_into_struct(&matches) {