diff --git a/.travis.yml b/.travis.yml index fe8b3a82..a5250b83 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,7 +11,7 @@ matrix: env: TARGET=x86_64-apple-darwin cache: cargo - os: linux - rust: 1.17.0 + rust: 1.19.0 env: TARGET=x86_64-unknown-linux-gnu cache: cargo - os: linux diff --git a/CHANGELOG.md b/CHANGELOG.md index 30a98116..0c8e73cb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,129 +1,139 @@ -**Version 0.16.3** +### Version 0.17.0 (unreleased) + - [SEMVER_MAJOR] Bump minimum required rustc version to 1.19.0 + - [SEMVER_MINOR] Oxipng will now, by default, attempt to change all transparent pixels to `rgba(0, 0, 0, 0)` to improve compression. + It does fast trials with filters 0 and 5 to see if this is an improvement over + the existing alpha channel. + - [SEMVER_MINOR] Add a `-a` option to the command line (`alphas` in the struct) which enables 6 different + trials for optimizing the alpha channel, using the previously mentioned fast heuristic. + This option will make optimization of images with transparency somewhat slower, + but may improve compression. + +### Version 0.16.3 - Fix command-line help text ([#70](https://github.com/shssoichiro/oxipng/issues/70)) -**Version 0.16.2** +### Version 0.16.2 - Publicly export `error` module -**Version 0.16.1** +### Version 0.16.1 - Fix rayon's breaking changes that they made in a point release -**Version 0.16.0** +### Version 0.16.0 - [SEMVER_MAJOR] Bump minimum rustc version to 1.17.0 - Bump `image` to 0.14 - Bump `rayon` to 0.8 -**Version 0.15.2** +### Version 0.15.2 - Bump `image` to 0.13 ([#65](https://github.com/shssoichiro/oxipng/pull/65)) - Bump `rayon` to 0.7 - Bump `itertools` to 0.6 -**Version 0.15.1** +### Version 0.15.1 - Ignore color reductions that would increase file size ([#61](https://github.com/shssoichiro/oxipng/issues/61)) -**Version 0.15.0** +### Version 0.15.0 - [SEMVER_MINOR] Check images for correctness before writing result ([#60](https://github.com/shssoichiro/oxipng/issues/60)) - Fix invalid output when reducing image to a different color type but file size does not improve ([#60](https://github.com/shssoichiro/oxipng/issues/60)) - Don't write new file if moving from interlaced to non-interlaced if new file would be larger -**Version 0.14.4** +### Version 0.14.4 - Fix bug when reducing RGBA to Indexed if image has 256 colors plus a background color -**Version 0.14.3** +### Version 0.14.3 - Fix multiple bugs when reducing transparency palettes -**Version 0.14.2** +### Version 0.14.2 - Fix a bug when reducing palette in images with bit depth less than 8 - Fix a bug when reducing palette in images with transparency -**Version 0.14.1** +### Version 0.14.1 - Remove zlib dependency and switch entirely to miniz, since zlib 1.2.11 was not working with oxipng. This costs some performance, but is better than having a broken application. -**Version 0.14.0** +### Version 0.14.0 - Performance optimizations - [SEMVER_MAJOR] Bump minimum rustc version to 1.13.0 - Add categories on crates.io -**Version 0.13.1** +### Version 0.13.1 - Bump regex dependency to 0.2 - Bump byteorder dependency to 1.0 - Bump rayon dependency to 0.6 -**Version 0.13.0** +### Version 0.13.0 - Fix bug in certain PNG headers when reducing color type ([#52](https://github.com/shssoichiro/oxipng/issues/52)) - [SEMVER_MAJOR] Reduction functions now take `&mut PngData` and return a `bool` indicating whether the image was reduced - [SMEVER_MAJOR] Bump minimum required rustc version to 1.12.0 -**Version 0.12.0** +### Version 0.12.0 - Performance optimizations - Fix processing filenames that contain commas (@aliceatlas [#50](https://github.com/shssoichiro/oxipng/pull/50)) - [SEMVER_MINOR] Add zopfli option (-Z), disabled by default. Gives about 10% better compression, but is currently 50-100x slower. -**Version 0.11.0** +### Version 0.11.0 - [SEMVER_MAJOR] Bump minimum rustc version to 1.9.0, required by dependencies - [SEMVER_MINOR] Allow calling optimization presets via crate using `Options::from_preset` - [SEMVER_MAJOR] Return proper `PngError` type which implements `std::error::Error` from `Result`s - [SEMVER_MAJOR] Rename module `deflate::deflate` to `deflate` - Performance optimizations -**Version 0.10.0** +### Version 0.10.0 - [SEMVER_MINOR] Make clap and regex dependencies optional - Enabled by default, needed for executable build; can be disabled for use in crates - Remove reduction from palette to grayscale, which was not working and provided minimal benefit -**Version 0.9.0** +### Version 0.9.0 - [SEMVER_MAJOR] Significant refactoring of modules - Use `itertools` to cleanup areas of code - Use multiple threads for filtering trials -**Version 0.8.2** +### Version 0.8.2 - Fix issue where images smaller than 4px width would crash on interlacing ([#42](https://github.com/shssoichiro/oxipng/issues/42)) -**Version 0.8.1** +### Version 0.8.1 - Minor optimizations - Fix issue where interlaced images with certain widths would fail to optimize -**Version 0.8.0** +### Version 0.8.0 - [SEMVER_MINOR] Add support for optimizing PNGs already loaded into memory via library function -**Version 0.7.0** +### Version 0.7.0 - Minor compression improvement on interlaced images - Performance optimizations - [SEMVER_MINOR] Move default Options into a Default impl - [SEMVER_MINOR] Add option for setting number of threads ([#39](https://github.com/shssoichiro/oxipng/issues/39)) -**Version 0.6.0** +### Version 0.6.0 - Fix issue where output directory would not be created if it did not exist - Use miniz for compression strategies where it outperforms zlib - [SEMVER_MINOR] Partially implement -p / --preserve, as far as stable Rust will allow for now - [SEMVER_MINOR] Implement --fix to ignore CRC errors and recalculate correct CRC in output -**Version 0.5.0** +### Version 0.5.0 - [SEMVER_MINOR] Palette entries can now reduced, on by default ([#11](https://github.com/shssoichiro/oxipng/issues/11)) - Don't report that we are in pretend mode if verbosity is set to none - Add cargo bench suite ([#7](https://github.com/shssoichiro/oxipng/issues/7)) -**Version 0.4.0** +### Version 0.4.0 - Performance optimizations - [SEMVER_MAJOR] `-s` automatically infers `--strip safe` ([#31](https://github.com/shssoichiro/oxipng/issues/31)) - Update byteorder and clap crates - Fix issue where interlaced images incorrectly applied filters on the first line of a pass -**Version 0.3.0** +### Version 0.3.0 - Properly decode interlaced images - [SEMVER_MINOR] Allow converting between progressive and interlaced images ([#3](https://github.com/shssoichiro/oxipng/issues/3)) - Fix a bug that would cause oxipng to crash on very small images -**Version 0.2.2** +### Version 0.2.2 - Limit number of threads to 1.5x number of cores - Significantly improve memory usage, especially with high optimization levels. ([#32](https://github.com/shssoichiro/oxipng/issues/32)) - Refactor output code ([#19](https://github.com/shssoichiro/oxipng/issues/19)) -**Version 0.2.1** +### Version 0.2.1 - Add rustdoc for public methods and structs - Improve filter mode 5 heuristic ([#16](https://github.com/shssoichiro/oxipng/issues/16)) - Add tests for edge-case images with subtitles ([#29](https://github.com/shssoichiro/oxipng/issues/29)) -**Version 0.2.0** +### Version 0.2.0 - Fix program version that is displayed when running `oxipng -V` - Ensure `--quiet` mode is actually quiet (@SethDusek [#20](https://github.com/shssoichiro/oxipng/pull/20)) - Write status/debug information to stderr instead of stdout @@ -131,10 +141,10 @@ - [SEMVER_MAJOR] Allow 'safe', 'all', or comma-separated list as options for `--strip` - [SEMVER_MINOR] Add `-s` alias for `--strip` -**Version 0.1.1** +### Version 0.1.1 - Fix `oxipng *` writing all input files to one output file ([#15](https://github.com/shssoichiro/oxipng/issues/15)) -**Version 0.1.0** +### Version 0.1.0 - Initial beta release - Reduce color type and bit depth - Recompress with zlib diff --git a/README.md b/README.md index 57bdb6e1..a5a0361c 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ cargo build --release cp target/release/oxipng /usr/local/bin ``` -The current minimum supported Rust version is **1.17.0**. Oxipng may compile on earlier versions of Rust, +The current minimum supported Rust version is **1.19.0**. Oxipng may compile on earlier versions of Rust, but there is no guarantee. Oxipng follows Semantic Versioning. diff --git a/benches/deflate.rs b/benches/deflate.rs index ddb5d8eb..7a0727b9 100644 --- a/benches/deflate.rs +++ b/benches/deflate.rs @@ -13,7 +13,9 @@ fn deflate_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 = png::PngData::new(&input, false).unwrap(); - b.iter(|| { deflate::deflate(png.raw_data.as_ref(), 9, 9, 0, 15).ok(); }); + b.iter(|| { + deflate::deflate(png.raw_data.as_ref(), 9, 9, 0, 15).ok(); + }); } #[bench] @@ -21,31 +23,45 @@ fn deflate_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 = png::PngData::new(&input, false).unwrap(); - b.iter(|| { deflate::deflate(png.raw_data.as_ref(), 9, 9, 0, 15).ok(); }); + b.iter(|| { + deflate::deflate(png.raw_data.as_ref(), 9, 9, 0, 15).ok(); + }); } #[bench] fn deflate_4_bits_strategy_0(b: &mut Bencher) { - let input = test::black_box(PathBuf::from("tests/files/palette_4_should_be_palette_4.png")); + let input = test::black_box(PathBuf::from( + "tests/files/palette_4_should_be_palette_4.png", + )); let png = png::PngData::new(&input, false).unwrap(); - b.iter(|| { deflate::deflate(png.raw_data.as_ref(), 9, 9, 0, 15).ok(); }); + b.iter(|| { + deflate::deflate(png.raw_data.as_ref(), 9, 9, 0, 15).ok(); + }); } #[bench] fn deflate_2_bits_strategy_0(b: &mut Bencher) { - let input = test::black_box(PathBuf::from("tests/files/palette_2_should_be_palette_2.png")); + let input = test::black_box(PathBuf::from( + "tests/files/palette_2_should_be_palette_2.png", + )); let png = png::PngData::new(&input, false).unwrap(); - b.iter(|| { deflate::deflate(png.raw_data.as_ref(), 9, 9, 0, 15).ok(); }); + b.iter(|| { + deflate::deflate(png.raw_data.as_ref(), 9, 9, 0, 15).ok(); + }); } #[bench] fn deflate_1_bits_strategy_0(b: &mut Bencher) { - let input = test::black_box(PathBuf::from("tests/files/palette_1_should_be_palette_1.png")); + let input = test::black_box(PathBuf::from( + "tests/files/palette_1_should_be_palette_1.png", + )); let png = png::PngData::new(&input, false).unwrap(); - b.iter(|| { deflate::deflate(png.raw_data.as_ref(), 9, 9, 0, 15).ok(); }); + b.iter(|| { + deflate::deflate(png.raw_data.as_ref(), 9, 9, 0, 15).ok(); + }); } #[bench] @@ -53,7 +69,9 @@ fn deflate_16_bits_strategy_1(b: &mut Bencher) { let input = test::black_box(PathBuf::from("tests/files/rgb_16_should_be_rgb_16.png")); let png = png::PngData::new(&input, false).unwrap(); - b.iter(|| { deflate::deflate(png.raw_data.as_ref(), 9, 9, 1, 15).ok(); }); + b.iter(|| { + deflate::deflate(png.raw_data.as_ref(), 9, 9, 1, 15).ok(); + }); } #[bench] @@ -61,31 +79,45 @@ fn deflate_8_bits_strategy_1(b: &mut Bencher) { let input = test::black_box(PathBuf::from("tests/files/rgb_8_should_be_rgb_8.png")); let png = png::PngData::new(&input, false).unwrap(); - b.iter(|| { deflate::deflate(png.raw_data.as_ref(), 9, 9, 1, 15).ok(); }); + b.iter(|| { + deflate::deflate(png.raw_data.as_ref(), 9, 9, 1, 15).ok(); + }); } #[bench] fn deflate_4_bits_strategy_1(b: &mut Bencher) { - let input = test::black_box(PathBuf::from("tests/files/palette_4_should_be_palette_4.png")); + let input = test::black_box(PathBuf::from( + "tests/files/palette_4_should_be_palette_4.png", + )); let png = png::PngData::new(&input, false).unwrap(); - b.iter(|| { deflate::deflate(png.raw_data.as_ref(), 9, 9, 1, 15).ok(); }); + b.iter(|| { + deflate::deflate(png.raw_data.as_ref(), 9, 9, 1, 15).ok(); + }); } #[bench] fn deflate_2_bits_strategy_1(b: &mut Bencher) { - let input = test::black_box(PathBuf::from("tests/files/palette_2_should_be_palette_2.png")); + let input = test::black_box(PathBuf::from( + "tests/files/palette_2_should_be_palette_2.png", + )); let png = png::PngData::new(&input, false).unwrap(); - b.iter(|| { deflate::deflate(png.raw_data.as_ref(), 9, 9, 1, 15).ok(); }); + b.iter(|| { + deflate::deflate(png.raw_data.as_ref(), 9, 9, 1, 15).ok(); + }); } #[bench] fn deflate_1_bits_strategy_1(b: &mut Bencher) { - let input = test::black_box(PathBuf::from("tests/files/palette_1_should_be_palette_1.png")); + let input = test::black_box(PathBuf::from( + "tests/files/palette_1_should_be_palette_1.png", + )); let png = png::PngData::new(&input, false).unwrap(); - b.iter(|| { deflate::deflate(png.raw_data.as_ref(), 9, 9, 1, 15).ok(); }); + b.iter(|| { + deflate::deflate(png.raw_data.as_ref(), 9, 9, 1, 15).ok(); + }); } #[bench] @@ -93,7 +125,9 @@ fn deflate_16_bits_strategy_2(b: &mut Bencher) { let input = test::black_box(PathBuf::from("tests/files/rgb_16_should_be_rgb_16.png")); let png = png::PngData::new(&input, false).unwrap(); - b.iter(|| { deflate::deflate(png.raw_data.as_ref(), 9, 9, 2, 15).ok(); }); + b.iter(|| { + deflate::deflate(png.raw_data.as_ref(), 9, 9, 2, 15).ok(); + }); } #[bench] @@ -101,31 +135,45 @@ fn deflate_8_bits_strategy_2(b: &mut Bencher) { let input = test::black_box(PathBuf::from("tests/files/rgb_8_should_be_rgb_8.png")); let png = png::PngData::new(&input, false).unwrap(); - b.iter(|| { deflate::deflate(png.raw_data.as_ref(), 9, 9, 2, 15).ok(); }); + b.iter(|| { + deflate::deflate(png.raw_data.as_ref(), 9, 9, 2, 15).ok(); + }); } #[bench] fn deflate_4_bits_strategy_2(b: &mut Bencher) { - let input = test::black_box(PathBuf::from("tests/files/palette_4_should_be_palette_4.png")); + let input = test::black_box(PathBuf::from( + "tests/files/palette_4_should_be_palette_4.png", + )); let png = png::PngData::new(&input, false).unwrap(); - b.iter(|| { deflate::deflate(png.raw_data.as_ref(), 9, 9, 2, 15).ok(); }); + b.iter(|| { + deflate::deflate(png.raw_data.as_ref(), 9, 9, 2, 15).ok(); + }); } #[bench] fn deflate_2_bits_strategy_2(b: &mut Bencher) { - let input = test::black_box(PathBuf::from("tests/files/palette_2_should_be_palette_2.png")); + let input = test::black_box(PathBuf::from( + "tests/files/palette_2_should_be_palette_2.png", + )); let png = png::PngData::new(&input, false).unwrap(); - b.iter(|| { deflate::deflate(png.raw_data.as_ref(), 9, 9, 2, 15).ok(); }); + b.iter(|| { + deflate::deflate(png.raw_data.as_ref(), 9, 9, 2, 15).ok(); + }); } #[bench] fn deflate_1_bits_strategy_2(b: &mut Bencher) { - let input = test::black_box(PathBuf::from("tests/files/palette_1_should_be_palette_1.png")); + let input = test::black_box(PathBuf::from( + "tests/files/palette_1_should_be_palette_1.png", + )); let png = png::PngData::new(&input, false).unwrap(); - b.iter(|| { deflate::deflate(png.raw_data.as_ref(), 9, 9, 2, 15).ok(); }); + b.iter(|| { + deflate::deflate(png.raw_data.as_ref(), 9, 9, 2, 15).ok(); + }); } #[bench] @@ -133,7 +181,9 @@ fn deflate_16_bits_strategy_3(b: &mut Bencher) { let input = test::black_box(PathBuf::from("tests/files/rgb_16_should_be_rgb_16.png")); let png = png::PngData::new(&input, false).unwrap(); - b.iter(|| { deflate::deflate(png.raw_data.as_ref(), 9, 9, 3, 15).ok(); }); + b.iter(|| { + deflate::deflate(png.raw_data.as_ref(), 9, 9, 3, 15).ok(); + }); } #[bench] @@ -141,31 +191,45 @@ fn deflate_8_bits_strategy_3(b: &mut Bencher) { let input = test::black_box(PathBuf::from("tests/files/rgb_8_should_be_rgb_8.png")); let png = png::PngData::new(&input, false).unwrap(); - b.iter(|| { deflate::deflate(png.raw_data.as_ref(), 9, 9, 3, 15).ok(); }); + b.iter(|| { + deflate::deflate(png.raw_data.as_ref(), 9, 9, 3, 15).ok(); + }); } #[bench] fn deflate_4_bits_strategy_3(b: &mut Bencher) { - let input = test::black_box(PathBuf::from("tests/files/palette_4_should_be_palette_4.png")); + let input = test::black_box(PathBuf::from( + "tests/files/palette_4_should_be_palette_4.png", + )); let png = png::PngData::new(&input, false).unwrap(); - b.iter(|| { deflate::deflate(png.raw_data.as_ref(), 9, 9, 3, 15).ok(); }); + b.iter(|| { + deflate::deflate(png.raw_data.as_ref(), 9, 9, 3, 15).ok(); + }); } #[bench] fn deflate_2_bits_strategy_3(b: &mut Bencher) { - let input = test::black_box(PathBuf::from("tests/files/palette_2_should_be_palette_2.png")); + let input = test::black_box(PathBuf::from( + "tests/files/palette_2_should_be_palette_2.png", + )); let png = png::PngData::new(&input, false).unwrap(); - b.iter(|| { deflate::deflate(png.raw_data.as_ref(), 9, 9, 3, 15).ok(); }); + b.iter(|| { + deflate::deflate(png.raw_data.as_ref(), 9, 9, 3, 15).ok(); + }); } #[bench] fn deflate_1_bits_strategy_3(b: &mut Bencher) { - let input = test::black_box(PathBuf::from("tests/files/palette_1_should_be_palette_1.png")); + let input = test::black_box(PathBuf::from( + "tests/files/palette_1_should_be_palette_1.png", + )); let png = png::PngData::new(&input, false).unwrap(); - b.iter(|| { deflate::deflate(png.raw_data.as_ref(), 9, 9, 3, 15).ok(); }); + b.iter(|| { + deflate::deflate(png.raw_data.as_ref(), 9, 9, 3, 15).ok(); + }); } #[bench] diff --git a/benches/filters.rs b/benches/filters.rs index 68ea6153..602ca391 100644 --- a/benches/filters.rs +++ b/benches/filters.rs @@ -25,7 +25,9 @@ fn filters_8_bits_filter_0(b: &mut Bencher) { #[bench] fn filters_4_bits_filter_0(b: &mut Bencher) { - let input = test::black_box(PathBuf::from("tests/files/palette_4_should_be_palette_4.png")); + let input = test::black_box(PathBuf::from( + "tests/files/palette_4_should_be_palette_4.png", + )); let png = png::PngData::new(&input, false).unwrap(); b.iter(|| { png.filter_image(0); }); @@ -33,7 +35,9 @@ fn filters_4_bits_filter_0(b: &mut Bencher) { #[bench] fn filters_2_bits_filter_0(b: &mut Bencher) { - let input = test::black_box(PathBuf::from("tests/files/palette_2_should_be_palette_2.png")); + let input = test::black_box(PathBuf::from( + "tests/files/palette_2_should_be_palette_2.png", + )); let png = png::PngData::new(&input, false).unwrap(); b.iter(|| { png.filter_image(0); }); @@ -41,7 +45,9 @@ fn filters_2_bits_filter_0(b: &mut Bencher) { #[bench] fn filters_1_bits_filter_0(b: &mut Bencher) { - let input = test::black_box(PathBuf::from("tests/files/palette_1_should_be_palette_1.png")); + let input = test::black_box(PathBuf::from( + "tests/files/palette_1_should_be_palette_1.png", + )); let png = png::PngData::new(&input, false).unwrap(); b.iter(|| { png.filter_image(0); }); @@ -65,7 +71,9 @@ fn filters_8_bits_filter_1(b: &mut Bencher) { #[bench] fn filters_4_bits_filter_1(b: &mut Bencher) { - let input = test::black_box(PathBuf::from("tests/files/palette_4_should_be_palette_4.png")); + let input = test::black_box(PathBuf::from( + "tests/files/palette_4_should_be_palette_4.png", + )); let png = png::PngData::new(&input, false).unwrap(); b.iter(|| { png.filter_image(1); }); @@ -73,7 +81,9 @@ fn filters_4_bits_filter_1(b: &mut Bencher) { #[bench] fn filters_2_bits_filter_1(b: &mut Bencher) { - let input = test::black_box(PathBuf::from("tests/files/palette_2_should_be_palette_2.png")); + let input = test::black_box(PathBuf::from( + "tests/files/palette_2_should_be_palette_2.png", + )); let png = png::PngData::new(&input, false).unwrap(); b.iter(|| { png.filter_image(1); }); @@ -81,7 +91,9 @@ fn filters_2_bits_filter_1(b: &mut Bencher) { #[bench] fn filters_1_bits_filter_1(b: &mut Bencher) { - let input = test::black_box(PathBuf::from("tests/files/palette_1_should_be_palette_1.png")); + let input = test::black_box(PathBuf::from( + "tests/files/palette_1_should_be_palette_1.png", + )); let png = png::PngData::new(&input, false).unwrap(); b.iter(|| { png.filter_image(1); }); @@ -105,7 +117,9 @@ fn filters_8_bits_filter_2(b: &mut Bencher) { #[bench] fn filters_4_bits_filter_2(b: &mut Bencher) { - let input = test::black_box(PathBuf::from("tests/files/palette_4_should_be_palette_4.png")); + let input = test::black_box(PathBuf::from( + "tests/files/palette_4_should_be_palette_4.png", + )); let png = png::PngData::new(&input, false).unwrap(); b.iter(|| { png.filter_image(2); }); @@ -113,7 +127,9 @@ fn filters_4_bits_filter_2(b: &mut Bencher) { #[bench] fn filters_2_bits_filter_2(b: &mut Bencher) { - let input = test::black_box(PathBuf::from("tests/files/palette_2_should_be_palette_2.png")); + let input = test::black_box(PathBuf::from( + "tests/files/palette_2_should_be_palette_2.png", + )); let png = png::PngData::new(&input, false).unwrap(); b.iter(|| { png.filter_image(2); }); @@ -121,7 +137,9 @@ fn filters_2_bits_filter_2(b: &mut Bencher) { #[bench] fn filters_1_bits_filter_2(b: &mut Bencher) { - let input = test::black_box(PathBuf::from("tests/files/palette_1_should_be_palette_1.png")); + let input = test::black_box(PathBuf::from( + "tests/files/palette_1_should_be_palette_1.png", + )); let png = png::PngData::new(&input, false).unwrap(); b.iter(|| { png.filter_image(2); }); @@ -145,7 +163,9 @@ fn filters_8_bits_filter_3(b: &mut Bencher) { #[bench] fn filters_4_bits_filter_3(b: &mut Bencher) { - let input = test::black_box(PathBuf::from("tests/files/palette_4_should_be_palette_4.png")); + let input = test::black_box(PathBuf::from( + "tests/files/palette_4_should_be_palette_4.png", + )); let png = png::PngData::new(&input, false).unwrap(); b.iter(|| { png.filter_image(3); }); @@ -153,7 +173,9 @@ fn filters_4_bits_filter_3(b: &mut Bencher) { #[bench] fn filters_2_bits_filter_3(b: &mut Bencher) { - let input = test::black_box(PathBuf::from("tests/files/palette_2_should_be_palette_2.png")); + let input = test::black_box(PathBuf::from( + "tests/files/palette_2_should_be_palette_2.png", + )); let png = png::PngData::new(&input, false).unwrap(); b.iter(|| { png.filter_image(3); }); @@ -161,7 +183,9 @@ fn filters_2_bits_filter_3(b: &mut Bencher) { #[bench] fn filters_1_bits_filter_3(b: &mut Bencher) { - let input = test::black_box(PathBuf::from("tests/files/palette_1_should_be_palette_1.png")); + let input = test::black_box(PathBuf::from( + "tests/files/palette_1_should_be_palette_1.png", + )); let png = png::PngData::new(&input, false).unwrap(); b.iter(|| { png.filter_image(3); }); @@ -185,7 +209,9 @@ fn filters_8_bits_filter_4(b: &mut Bencher) { #[bench] fn filters_4_bits_filter_4(b: &mut Bencher) { - let input = test::black_box(PathBuf::from("tests/files/palette_4_should_be_palette_4.png")); + let input = test::black_box(PathBuf::from( + "tests/files/palette_4_should_be_palette_4.png", + )); let png = png::PngData::new(&input, false).unwrap(); b.iter(|| { png.filter_image(4); }); @@ -193,7 +219,9 @@ fn filters_4_bits_filter_4(b: &mut Bencher) { #[bench] fn filters_2_bits_filter_4(b: &mut Bencher) { - let input = test::black_box(PathBuf::from("tests/files/palette_2_should_be_palette_2.png")); + let input = test::black_box(PathBuf::from( + "tests/files/palette_2_should_be_palette_2.png", + )); let png = png::PngData::new(&input, false).unwrap(); b.iter(|| { png.filter_image(4); }); @@ -201,7 +229,9 @@ fn filters_2_bits_filter_4(b: &mut Bencher) { #[bench] fn filters_1_bits_filter_4(b: &mut Bencher) { - let input = test::black_box(PathBuf::from("tests/files/palette_1_should_be_palette_1.png")); + let input = test::black_box(PathBuf::from( + "tests/files/palette_1_should_be_palette_1.png", + )); let png = png::PngData::new(&input, false).unwrap(); b.iter(|| { png.filter_image(4); }); @@ -225,7 +255,9 @@ fn filters_8_bits_filter_5(b: &mut Bencher) { #[bench] fn filters_4_bits_filter_5(b: &mut Bencher) { - let input = test::black_box(PathBuf::from("tests/files/palette_4_should_be_palette_4.png")); + let input = test::black_box(PathBuf::from( + "tests/files/palette_4_should_be_palette_4.png", + )); let png = png::PngData::new(&input, false).unwrap(); b.iter(|| { png.filter_image(5); }); @@ -233,7 +265,9 @@ fn filters_4_bits_filter_5(b: &mut Bencher) { #[bench] fn filters_2_bits_filter_5(b: &mut Bencher) { - let input = test::black_box(PathBuf::from("tests/files/palette_2_should_be_palette_2.png")); + let input = test::black_box(PathBuf::from( + "tests/files/palette_2_should_be_palette_2.png", + )); let png = png::PngData::new(&input, false).unwrap(); b.iter(|| { png.filter_image(5); }); @@ -241,7 +275,9 @@ fn filters_2_bits_filter_5(b: &mut Bencher) { #[bench] fn filters_1_bits_filter_5(b: &mut Bencher) { - let input = test::black_box(PathBuf::from("tests/files/palette_1_should_be_palette_1.png")); + let input = test::black_box(PathBuf::from( + "tests/files/palette_1_should_be_palette_1.png", + )); let png = png::PngData::new(&input, false).unwrap(); b.iter(|| { png.filter_image(5); }); diff --git a/benches/interlacing.rs b/benches/interlacing.rs index 4dae7753..478aff2a 100644 --- a/benches/interlacing.rs +++ b/benches/interlacing.rs @@ -13,9 +13,9 @@ fn interlacing_16_bits(b: &mut Bencher) { let png = png::PngData::new(&input, false).unwrap(); b.iter(|| { - let mut safe_png = png.clone(); - safe_png.change_interlacing(1); - }); + let mut safe_png = png.clone(); + safe_png.change_interlacing(1); + }); } #[bench] @@ -24,95 +24,111 @@ fn interlacing_8_bits(b: &mut Bencher) { let png = png::PngData::new(&input, false).unwrap(); b.iter(|| { - let mut safe_png = png.clone(); - safe_png.change_interlacing(1); - }); + let mut safe_png = png.clone(); + safe_png.change_interlacing(1); + }); } #[bench] fn interlacing_4_bits(b: &mut Bencher) { - let input = test::black_box(PathBuf::from("tests/files/palette_4_should_be_palette_4.png")); + let input = test::black_box(PathBuf::from( + "tests/files/palette_4_should_be_palette_4.png", + )); let png = png::PngData::new(&input, false).unwrap(); b.iter(|| { - let mut safe_png = png.clone(); - safe_png.change_interlacing(1); - }); + let mut safe_png = png.clone(); + safe_png.change_interlacing(1); + }); } #[bench] fn interlacing_2_bits(b: &mut Bencher) { - let input = test::black_box(PathBuf::from("tests/files/palette_2_should_be_palette_2.png")); + let input = test::black_box(PathBuf::from( + "tests/files/palette_2_should_be_palette_2.png", + )); let png = png::PngData::new(&input, false).unwrap(); b.iter(|| { - let mut safe_png = png.clone(); - safe_png.change_interlacing(1); - }); + let mut safe_png = png.clone(); + safe_png.change_interlacing(1); + }); } #[bench] fn interlacing_1_bits(b: &mut Bencher) { - let input = test::black_box(PathBuf::from("tests/files/palette_1_should_be_palette_1.png")); + let input = test::black_box(PathBuf::from( + "tests/files/palette_1_should_be_palette_1.png", + )); let png = png::PngData::new(&input, false).unwrap(); b.iter(|| { - let mut safe_png = png.clone(); - safe_png.change_interlacing(1); - }); + let mut safe_png = png.clone(); + safe_png.change_interlacing(1); + }); } #[bench] fn deinterlacing_16_bits(b: &mut Bencher) { - let input = test::black_box(PathBuf::from("tests/files/interlaced_rgb_16_should_be_rgb_16.png")); + let input = test::black_box(PathBuf::from( + "tests/files/interlaced_rgb_16_should_be_rgb_16.png", + )); let png = png::PngData::new(&input, false).unwrap(); b.iter(|| { - let mut safe_png = png.clone(); - safe_png.change_interlacing(0); - }); + let mut safe_png = png.clone(); + safe_png.change_interlacing(0); + }); } #[bench] fn deinterlacing_8_bits(b: &mut Bencher) { - let input = test::black_box(PathBuf::from("tests/files/interlaced_rgb_8_should_be_rgb_8.png")); + let input = test::black_box(PathBuf::from( + "tests/files/interlaced_rgb_8_should_be_rgb_8.png", + )); let png = png::PngData::new(&input, false).unwrap(); b.iter(|| { - let mut safe_png = png.clone(); - safe_png.change_interlacing(0); - }); + let mut safe_png = png.clone(); + safe_png.change_interlacing(0); + }); } #[bench] fn deinterlacing_4_bits(b: &mut Bencher) { - let input = test::black_box(PathBuf::from("tests/files/interlaced_palette_4_should_be_palette_4.png")); + let input = test::black_box(PathBuf::from( + "tests/files/interlaced_palette_4_should_be_palette_4.png", + )); let png = png::PngData::new(&input, false).unwrap(); b.iter(|| { - let mut safe_png = png.clone(); - safe_png.change_interlacing(0); - }); + let mut safe_png = png.clone(); + safe_png.change_interlacing(0); + }); } #[bench] fn deinterlacing_2_bits(b: &mut Bencher) { - let input = test::black_box(PathBuf::from("tests/files/interlaced_palette_2_should_be_palette_2.png")); + let input = test::black_box(PathBuf::from( + "tests/files/interlaced_palette_2_should_be_palette_2.png", + )); let png = png::PngData::new(&input, false).unwrap(); b.iter(|| { - let mut safe_png = png.clone(); - safe_png.change_interlacing(0); - }); + let mut safe_png = png.clone(); + safe_png.change_interlacing(0); + }); } #[bench] fn deinterlacing_1_bits(b: &mut Bencher) { - let input = test::black_box(PathBuf::from("tests/files/interlaced_palette_1_should_be_palette_1.png")); + let input = test::black_box(PathBuf::from( + "tests/files/interlaced_palette_1_should_be_palette_1.png", + )); let png = png::PngData::new(&input, false).unwrap(); b.iter(|| { - let mut safe_png = png.clone(); - safe_png.change_interlacing(0); - }); + let mut safe_png = png.clone(); + safe_png.change_interlacing(0); + }); } diff --git a/benches/reductions.rs b/benches/reductions.rs index 90e709b8..602b963d 100644 --- a/benches/reductions.rs +++ b/benches/reductions.rs @@ -4,6 +4,7 @@ extern crate test; extern crate oxipng; use oxipng::png; +use oxipng::colors::AlphaOptim; use test::Bencher; use std::path::PathBuf; @@ -13,75 +14,87 @@ fn reductions_16_to_8_bits(b: &mut Bencher) { let png = png::PngData::new(&input, false).unwrap(); b.iter(|| { - let mut safe_png = png.clone(); - safe_png.reduce_bit_depth(); - }); + let mut safe_png = png.clone(); + safe_png.reduce_bit_depth(); + }); } #[bench] fn reductions_8_to_4_bits(b: &mut Bencher) { - let input = test::black_box(PathBuf::from("tests/files/palette_8_should_be_palette_4.png")); + let input = test::black_box(PathBuf::from( + "tests/files/palette_8_should_be_palette_4.png", + )); let png = png::PngData::new(&input, false).unwrap(); b.iter(|| { - let mut safe_png = png.clone(); - safe_png.reduce_bit_depth(); - }); + let mut safe_png = png.clone(); + safe_png.reduce_bit_depth(); + }); } #[bench] fn reductions_8_to_2_bits(b: &mut Bencher) { - let input = test::black_box(PathBuf::from("tests/files/palette_8_should_be_palette_2.png")); + let input = test::black_box(PathBuf::from( + "tests/files/palette_8_should_be_palette_2.png", + )); let png = png::PngData::new(&input, false).unwrap(); b.iter(|| { - let mut safe_png = png.clone(); - safe_png.reduce_bit_depth(); - }); + let mut safe_png = png.clone(); + safe_png.reduce_bit_depth(); + }); } #[bench] fn reductions_8_to_1_bits(b: &mut Bencher) { - let input = test::black_box(PathBuf::from("tests/files/palette_8_should_be_palette_1.png")); + let input = test::black_box(PathBuf::from( + "tests/files/palette_8_should_be_palette_1.png", + )); let png = png::PngData::new(&input, false).unwrap(); b.iter(|| { - let mut safe_png = png.clone(); - safe_png.reduce_bit_depth(); - }); + let mut safe_png = png.clone(); + safe_png.reduce_bit_depth(); + }); } #[bench] fn reductions_4_to_2_bits(b: &mut Bencher) { - let input = test::black_box(PathBuf::from("tests/files/palette_4_should_be_palette_2.png")); + let input = test::black_box(PathBuf::from( + "tests/files/palette_4_should_be_palette_2.png", + )); let png = png::PngData::new(&input, false).unwrap(); b.iter(|| { - let mut safe_png = png.clone(); - safe_png.reduce_bit_depth(); - }); + let mut safe_png = png.clone(); + safe_png.reduce_bit_depth(); + }); } #[bench] fn reductions_4_to_1_bits(b: &mut Bencher) { - let input = test::black_box(PathBuf::from("tests/files/palette_4_should_be_palette_1.png")); + let input = test::black_box(PathBuf::from( + "tests/files/palette_4_should_be_palette_1.png", + )); let png = png::PngData::new(&input, false).unwrap(); b.iter(|| { - let mut safe_png = png.clone(); - safe_png.reduce_bit_depth(); - }); + let mut safe_png = png.clone(); + safe_png.reduce_bit_depth(); + }); } #[bench] fn reductions_2_to_1_bits(b: &mut Bencher) { - let input = test::black_box(PathBuf::from("tests/files/palette_2_should_be_palette_1.png")); + let input = test::black_box(PathBuf::from( + "tests/files/palette_2_should_be_palette_1.png", + )); let png = png::PngData::new(&input, false).unwrap(); b.iter(|| { - let mut safe_png = png.clone(); - safe_png.reduce_bit_depth(); - }); + let mut safe_png = png.clone(); + safe_png.reduce_bit_depth(); + }); } #[bench] @@ -90,9 +103,9 @@ fn reductions_rgba_to_rgb_16(b: &mut Bencher) { let png = png::PngData::new(&input, false).unwrap(); b.iter(|| { - let mut safe_png = png.clone(); - safe_png.reduce_color_type(); - }); + let mut safe_png = png.clone(); + safe_png.reduce_color_type(); + }); } #[bench] @@ -101,64 +114,74 @@ fn reductions_rgba_to_rgb_8(b: &mut Bencher) { let png = png::PngData::new(&input, false).unwrap(); b.iter(|| { - let mut safe_png = png.clone(); - safe_png.reduce_color_type(); - }); + let mut safe_png = png.clone(); + safe_png.reduce_color_type(); + }); } #[bench] fn reductions_rgba_to_grayscale_alpha_16(b: &mut Bencher) { - let input = test::black_box(PathBuf::from("tests/files/rgba_16_should_be_grayscale_alpha_16.png")); + let input = test::black_box(PathBuf::from( + "tests/files/rgba_16_should_be_grayscale_alpha_16.png", + )); let png = png::PngData::new(&input, false).unwrap(); b.iter(|| { - let mut safe_png = png.clone(); - safe_png.reduce_color_type(); - }); + let mut safe_png = png.clone(); + safe_png.reduce_color_type(); + }); } #[bench] fn reductions_rgba_to_grayscale_alpha_8(b: &mut Bencher) { - let input = test::black_box(PathBuf::from("tests/files/rgba_8_should_be_grayscale_alpha_8.png")); + let input = test::black_box(PathBuf::from( + "tests/files/rgba_8_should_be_grayscale_alpha_8.png", + )); let png = png::PngData::new(&input, false).unwrap(); b.iter(|| { - let mut safe_png = png.clone(); - safe_png.reduce_color_type(); - }); + let mut safe_png = png.clone(); + safe_png.reduce_color_type(); + }); } #[bench] fn reductions_rgba_to_grayscale_16(b: &mut Bencher) { - let input = test::black_box(PathBuf::from("tests/files/rgba_16_should_be_grayscale_16.png")); + let input = test::black_box(PathBuf::from( + "tests/files/rgba_16_should_be_grayscale_16.png", + )); let png = png::PngData::new(&input, false).unwrap(); b.iter(|| { - let mut safe_png = png.clone(); - safe_png.reduce_color_type(); - }); + let mut safe_png = png.clone(); + safe_png.reduce_color_type(); + }); } #[bench] fn reductions_rgba_to_grayscale_8(b: &mut Bencher) { - let input = test::black_box(PathBuf::from("tests/files/rgba_8_should_be_grayscale_8.png")); + let input = test::black_box(PathBuf::from( + "tests/files/rgba_8_should_be_grayscale_8.png", + )); let png = png::PngData::new(&input, false).unwrap(); b.iter(|| { - let mut safe_png = png.clone(); - safe_png.reduce_color_type(); - }); + let mut safe_png = png.clone(); + safe_png.reduce_color_type(); + }); } #[bench] fn reductions_rgb_to_grayscale_16(b: &mut Bencher) { - let input = test::black_box(PathBuf::from("tests/files/rgb_16_should_be_grayscale_16.png")); + let input = test::black_box(PathBuf::from( + "tests/files/rgb_16_should_be_grayscale_16.png", + )); let png = png::PngData::new(&input, false).unwrap(); b.iter(|| { - let mut safe_png = png.clone(); - safe_png.reduce_color_type(); - }); + let mut safe_png = png.clone(); + safe_png.reduce_color_type(); + }); } #[bench] @@ -167,9 +190,9 @@ fn reductions_rgb_to_grayscale_8(b: &mut Bencher) { let png = png::PngData::new(&input, false).unwrap(); b.iter(|| { - let mut safe_png = png.clone(); - safe_png.reduce_color_type(); - }); + let mut safe_png = png.clone(); + safe_png.reduce_color_type(); + }); } #[bench] @@ -178,9 +201,9 @@ fn reductions_rgba_to_palette_8(b: &mut Bencher) { let png = png::PngData::new(&input, false).unwrap(); b.iter(|| { - let mut safe_png = png.clone(); - safe_png.reduce_color_type(); - }); + let mut safe_png = png.clone(); + safe_png.reduce_color_type(); + }); } #[bench] @@ -189,40 +212,124 @@ fn reductions_rgb_to_palette_8(b: &mut Bencher) { let png = png::PngData::new(&input, false).unwrap(); b.iter(|| { - let mut safe_png = png.clone(); - safe_png.reduce_color_type(); - }); + let mut safe_png = png.clone(); + safe_png.reduce_color_type(); + }); } #[bench] fn reductions_palette_duplicate_reduction(b: &mut Bencher) { - let input = test::black_box(PathBuf::from("tests/files/palette_should_be_reduced_with_dupes.png")); + let input = test::black_box(PathBuf::from( + "tests/files/palette_should_be_reduced_with_dupes.png", + )); let png = png::PngData::new(&input, false).unwrap(); b.iter(|| { - let mut safe_png = png.clone(); - safe_png.reduce_palette(); - }); + let mut safe_png = png.clone(); + safe_png.reduce_palette(); + }); } #[bench] fn reductions_palette_unused_reduction(b: &mut Bencher) { - let input = test::black_box(PathBuf::from("tests/files/palette_should_be_reduced_with_unused.png")); + let input = test::black_box(PathBuf::from( + "tests/files/palette_should_be_reduced_with_unused.png", + )); let png = png::PngData::new(&input, false).unwrap(); b.iter(|| { - let mut safe_png = png.clone(); - safe_png.reduce_palette(); - }); + let mut safe_png = png.clone(); + safe_png.reduce_palette(); + }); } #[bench] fn reductions_palette_full_reduction(b: &mut Bencher) { - let input = test::black_box(PathBuf::from("tests/files/palette_should_be_reduced_with_both.png")); + let input = test::black_box(PathBuf::from( + "tests/files/palette_should_be_reduced_with_both.png", + )); let png = png::PngData::new(&input, false).unwrap(); b.iter(|| { - let mut safe_png = png.clone(); - safe_png.reduce_palette(); - }); + let mut safe_png = png.clone(); + safe_png.reduce_palette(); + }); +} + +#[bench] +fn reductions_alpha_black(b: &mut Bencher) { + let input = test::black_box(PathBuf::from( + "tests/files/rgba_8_reduce_alpha_black.png", + )); + let png = png::PngData::new(&input, false).unwrap(); + + b.iter(|| { + let mut safe_png = png.clone(); + safe_png.reduce_alpha_channel(AlphaOptim::Black); + }); +} + +#[bench] +fn reductions_alpha_white(b: &mut Bencher) { + let input = test::black_box(PathBuf::from( + "tests/files/rgba_8_reduce_alpha_white.png", + )); + let png = png::PngData::new(&input, false).unwrap(); + + b.iter(|| { + let mut safe_png = png.clone(); + safe_png.reduce_alpha_channel(AlphaOptim::White); + }); +} + +#[bench] +fn reductions_alpha_left(b: &mut Bencher) { + let input = test::black_box(PathBuf::from( + "tests/files/rgba_8_reduce_alpha_left.png", + )); + let png = png::PngData::new(&input, false).unwrap(); + + b.iter(|| { + let mut safe_png = png.clone(); + safe_png.reduce_alpha_channel(AlphaOptim::Left); + }); +} + +#[bench] +fn reductions_alpha_right(b: &mut Bencher) { + let input = test::black_box(PathBuf::from( + "tests/files/rgba_8_reduce_alpha_right.png", + )); + let png = png::PngData::new(&input, false).unwrap(); + + b.iter(|| { + let mut safe_png = png.clone(); + safe_png.reduce_alpha_channel(AlphaOptim::Right); + }); +} + +#[bench] +fn reductions_alpha_up(b: &mut Bencher) { + let input = test::black_box(PathBuf::from( + "tests/files/rgba_8_reduce_alpha_up.png", + )); + let png = png::PngData::new(&input, false).unwrap(); + + b.iter(|| { + let mut safe_png = png.clone(); + safe_png.reduce_alpha_channel(AlphaOptim::Up); + }); +} + +#[bench] +fn reductions_alpha_down(b: &mut Bencher) { + let input = test::black_box(PathBuf::from( + "tests/files/rgba_8_reduce_alpha_down.png", + )); + let png = png::PngData::new(&input, false).unwrap(); + + b.iter(|| { + let mut safe_png = png.clone(); + safe_png.reduce_alpha_channel(AlphaOptim::Down); + }); } diff --git a/benches/zopfli.rs b/benches/zopfli.rs index 4629c698..16269c70 100644 --- a/benches/zopfli.rs +++ b/benches/zopfli.rs @@ -26,7 +26,9 @@ fn zopfli_8_bits_strategy_0(b: &mut Bencher) { #[bench] fn zopfli_4_bits_strategy_0(b: &mut Bencher) { - let input = test::black_box(PathBuf::from("tests/files/palette_4_should_be_palette_4.png")); + let input = test::black_box(PathBuf::from( + "tests/files/palette_4_should_be_palette_4.png", + )); let png = png::PngData::new(&input, false).unwrap(); b.iter(|| { deflate::zopfli_deflate(png.raw_data.as_ref()).ok(); }); @@ -34,7 +36,9 @@ fn zopfli_4_bits_strategy_0(b: &mut Bencher) { #[bench] fn zopfli_2_bits_strategy_0(b: &mut Bencher) { - let input = test::black_box(PathBuf::from("tests/files/palette_2_should_be_palette_2.png")); + let input = test::black_box(PathBuf::from( + "tests/files/palette_2_should_be_palette_2.png", + )); let png = png::PngData::new(&input, false).unwrap(); b.iter(|| { deflate::zopfli_deflate(png.raw_data.as_ref()).ok(); }); @@ -42,7 +46,9 @@ fn zopfli_2_bits_strategy_0(b: &mut Bencher) { #[bench] fn zopfli_1_bits_strategy_0(b: &mut Bencher) { - let input = test::black_box(PathBuf::from("tests/files/palette_1_should_be_palette_1.png")); + let input = test::black_box(PathBuf::from( + "tests/files/palette_1_should_be_palette_1.png", + )); let png = png::PngData::new(&input, false).unwrap(); b.iter(|| { deflate::zopfli_deflate(png.raw_data.as_ref()).ok(); }); diff --git a/src/colors.rs b/src/colors.rs index 4da402cc..dd6e7866 100644 --- a/src/colors.rs +++ b/src/colors.rs @@ -18,13 +18,17 @@ pub enum ColorType { impl fmt::Display for ColorType { #[inline] fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", match *self { - ColorType::Grayscale => "Grayscale", - ColorType::RGB => "RGB", - ColorType::Indexed => "Indexed", - ColorType::GrayscaleAlpha => "Grayscale + Alpha", - ColorType::RGBA => "RGB + Alpha", - }) + write!( + f, + "{}", + match *self { + ColorType::Grayscale => "Grayscale", + ColorType::RGB => "RGB", + ColorType::Indexed => "Indexed", + ColorType::GrayscaleAlpha => "Grayscale + Alpha", + ColorType::RGBA => "RGB + Alpha", + } + ) } } @@ -60,13 +64,17 @@ pub enum BitDepth { impl fmt::Display for BitDepth { #[inline] fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", match *self { - BitDepth::One => "1", - BitDepth::Two => "2", - BitDepth::Four => "4", - BitDepth::Eight => "8", - BitDepth::Sixteen => "16", - }) + write!( + f, + "{}", + match *self { + BitDepth::One => "1", + BitDepth::Two => "2", + BitDepth::Four => "4", + BitDepth::Eight => "8", + BitDepth::Sixteen => "16", + } + ) } } @@ -95,3 +103,33 @@ impl BitDepth { } } } + +#[derive(Debug, PartialEq, Clone, Copy, Eq, Hash)] +/// Potential optimization methods for alpha channel +pub enum AlphaOptim { + NoOp, + Black, + White, + Up, + Right, + Down, + Left, +} + +impl fmt::Display for AlphaOptim { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!( + f, + "{}", + match *self { + AlphaOptim::NoOp => "_", + AlphaOptim::Black => "B", + AlphaOptim::White => "W", + AlphaOptim::Up => "U", + AlphaOptim::Right => "R", + AlphaOptim::Down => "D", + AlphaOptim::Left => "L", + } + ) + } +} diff --git a/src/deflate/miniz_stream.rs b/src/deflate/miniz_stream.rs index 5df4bbdc..7b86f3ca 100644 --- a/src/deflate/miniz_stream.rs +++ b/src/deflate/miniz_stream.rs @@ -22,19 +22,22 @@ pub trait Direction { } impl Stream { - pub fn new_compress(lvl: c_int, - window_bits: c_int, - mem_size: c_int, - strategy: c_int) - -> Stream { + pub fn new_compress( + lvl: c_int, + window_bits: c_int, + mem_size: c_int, + strategy: c_int, + ) -> Stream { unsafe { let mut state: miniz_sys::mz_stream = mem::zeroed(); - let ret = miniz_sys::mz_deflateInit2(&mut state, - lvl, - miniz_sys::MZ_DEFLATED, - window_bits, - mem_size, - strategy); + let ret = miniz_sys::mz_deflateInit2( + &mut state, + lvl, + miniz_sys::MZ_DEFLATED, + window_bits, + mem_size, + strategy, + ); debug_assert_eq!(ret, 0); Stream { raw: state, @@ -91,12 +94,14 @@ impl Stream { unsafe { self.raw.next_in = input.as_mut_ptr().offset(self.total_in() as isize); self.raw.next_out = output.as_mut_ptr().offset(self.total_out() as isize); - let rc = miniz_sys::mz_deflate(&mut self.raw, - if self.raw.avail_in > 0 { - miniz_sys::MZ_NO_FLUSH - } else { - miniz_sys::MZ_FINISH - }); + let rc = miniz_sys::mz_deflate( + &mut self.raw, + if self.raw.avail_in > 0 { + miniz_sys::MZ_NO_FLUSH + } else { + miniz_sys::MZ_FINISH + }, + ); output.set_len(self.total_out() as usize); rc } diff --git a/src/filters.rs b/src/filters.rs index 47141c11..3f227260 100644 --- a/src/filters.rs +++ b/src/filters.rs @@ -6,37 +6,33 @@ pub fn filter_line(filter: u8, bpp: usize, data: &[u8], last_line: &[u8]) -> Vec } 1 => { filtered.extend_from_slice(&data[0..bpp]); - filtered.extend(data.iter() - .skip(bpp) - .zip(data.iter()) - .map(|(cur, last)| cur.wrapping_sub(*last))); + filtered.extend(data.iter().skip(bpp).zip(data.iter()).map(|(cur, last)| { + cur.wrapping_sub(*last) + })); } 2 => { if last_line.is_empty() { filtered.extend_from_slice(data); } else { - filtered.extend(data.iter() - .zip(last_line.iter()) - .map(|(cur, last)| cur.wrapping_sub(*last))); + filtered.extend(data.iter().zip(last_line.iter()).map(|(cur, last)| { + cur.wrapping_sub(*last) + })); }; } 3 => { for (i, byte) in data.iter().enumerate() { if last_line.is_empty() { filtered.push(match i.checked_sub(bpp) { - Some(x) => byte.wrapping_sub(data[x] >> 1), - None => *byte, - }); + Some(x) => byte.wrapping_sub(data[x] >> 1), + None => *byte, + }); } else { filtered.push(match i.checked_sub(bpp) { - Some(x) => { - byte.wrapping_sub(((data[x] as u16 + - last_line[i] as u16) >> - 1) as - u8) - } - None => byte.wrapping_sub(last_line[i] >> 1), - }); + Some(x) => { + byte.wrapping_sub(((data[x] as u16 + last_line[i] as u16) >> 1) as u8) + } + None => byte.wrapping_sub(last_line[i] >> 1), + }); }; } } @@ -44,18 +40,16 @@ pub fn filter_line(filter: u8, bpp: usize, data: &[u8], last_line: &[u8]) -> Vec for (i, byte) in data.iter().enumerate() { if last_line.is_empty() { filtered.push(match i.checked_sub(bpp) { - Some(x) => byte.wrapping_sub(data[x]), - None => *byte, - }); + Some(x) => byte.wrapping_sub(data[x]), + None => *byte, + }); } else { filtered.push(match i.checked_sub(bpp) { - Some(x) => { - byte.wrapping_sub(paeth_predictor(data[x], - last_line[i], - last_line[x])) - } - None => byte.wrapping_sub(last_line[i]), - }); + Some(x) => { + byte.wrapping_sub(paeth_predictor(data[x], last_line[i], last_line[x])) + } + None => byte.wrapping_sub(last_line[i]), + }); }; } } @@ -87,9 +81,9 @@ pub fn unfilter_line(filter: u8, bpp: usize, data: &[u8], last_line: &[u8]) -> V if last_line.is_empty() { unfiltered.extend_from_slice(data); } else { - unfiltered.extend(data.iter() - .zip(last_line.iter()) - .map(|(cur, last)| cur.wrapping_add(*last))); + unfiltered.extend(data.iter().zip(last_line.iter()).map(|(cur, last)| { + cur.wrapping_add(*last) + })); }; } 3 => { @@ -108,9 +102,9 @@ pub fn unfilter_line(filter: u8, bpp: usize, data: &[u8], last_line: &[u8]) -> V match i.checked_sub(bpp) { Some(x) => { let b = unfiltered[x]; - unfiltered - .push(byte.wrapping_add(((b as u16 + last_line[i] as u16) >> 1) as - u8)); + unfiltered.push(byte.wrapping_add( + ((b as u16 + last_line[i] as u16) >> 1) as u8, + )); } None => { unfiltered.push(byte.wrapping_add(last_line[i] >> 1)); @@ -135,9 +129,9 @@ pub fn unfilter_line(filter: u8, bpp: usize, data: &[u8], last_line: &[u8]) -> V match i.checked_sub(bpp) { Some(x) => { let b = unfiltered[x]; - unfiltered.push(byte.wrapping_add(paeth_predictor(b, - last_line[i], - last_line[x]))); + unfiltered.push(byte.wrapping_add( + paeth_predictor(b, last_line[i], last_line[x]), + )); } None => { unfiltered.push(byte.wrapping_add(last_line[i])); diff --git a/src/headers.rs b/src/headers.rs index 9fac8b41..fff2847d 100644 --- a/src/headers.rs +++ b/src/headers.rs @@ -43,16 +43,19 @@ pub fn file_header_is_valid(bytes: &[u8]) -> bool { *bytes == expected_header } -pub fn parse_next_header(byte_data: &[u8], - byte_offset: &mut usize, - fix_errors: bool) - -> Result)>, PngError> { - let mut rdr = Cursor::new(byte_data - .iter() - .skip(*byte_offset) - .take(4) - .cloned() - .collect::>()); +pub fn parse_next_header( + byte_data: &[u8], + byte_offset: &mut usize, + fix_errors: bool, +) -> Result)>, PngError> { + let mut rdr = Cursor::new( + byte_data + .iter() + .skip(*byte_offset) + .take(4) + .cloned() + .collect::>(), + ); let length: u32 = match rdr.read_u32::() { Ok(x) => x, Err(_) => return Err(PngError::new("Invalid data found; unable to read PNG file")), @@ -82,12 +85,14 @@ pub fn parse_next_header(byte_data: &[u8], .cloned() .collect(); *byte_offset += length as usize; - let mut rdr = Cursor::new(byte_data - .iter() - .skip(*byte_offset) - .take(4) - .cloned() - .collect::>()); + let mut rdr = Cursor::new( + byte_data + .iter() + .skip(*byte_offset) + .take(4) + .cloned() + .collect::>(), + ); let crc: u32 = match rdr.read_u32::() { Ok(x) => x, Err(_) => return Err(PngError::new("Invalid data found; unable to read PNG file")), @@ -95,8 +100,10 @@ pub fn parse_next_header(byte_data: &[u8], *byte_offset += 4; header_bytes.extend_from_slice(&data); if !fix_errors && crc32::checksum_ieee(header_bytes.as_ref()) != crc { - return Err(PngError::new(&format!("CRC Mismatch in {} header; May be recoverable by using --fix", - header))); + return Err(PngError::new(&format!( + "CRC Mismatch in {} header; May be recoverable by using --fix", + header + ))); } Ok(Some((header, data))) @@ -105,26 +112,26 @@ pub fn parse_next_header(byte_data: &[u8], pub fn parse_ihdr_header(byte_data: &[u8]) -> Result { let mut rdr = Cursor::new(&byte_data[0..8]); Ok(IhdrData { - color_type: match byte_data[9] { - 0 => ColorType::Grayscale, - 2 => ColorType::RGB, - 3 => ColorType::Indexed, - 4 => ColorType::GrayscaleAlpha, - 6 => ColorType::RGBA, - _ => return Err(PngError::new("Unexpected color type in header")), - }, - bit_depth: match byte_data[8] { - 1 => BitDepth::One, - 2 => BitDepth::Two, - 4 => BitDepth::Four, - 8 => BitDepth::Eight, - 16 => BitDepth::Sixteen, - _ => return Err(PngError::new("Unexpected bit depth in header")), - }, - width: rdr.read_u32::().unwrap(), - height: rdr.read_u32::().unwrap(), - compression: byte_data[10], - filter: byte_data[11], - interlaced: byte_data[12], - }) + color_type: match byte_data[9] { + 0 => ColorType::Grayscale, + 2 => ColorType::RGB, + 3 => ColorType::Indexed, + 4 => ColorType::GrayscaleAlpha, + 6 => ColorType::RGBA, + _ => return Err(PngError::new("Unexpected color type in header")), + }, + bit_depth: match byte_data[8] { + 1 => BitDepth::One, + 2 => BitDepth::Two, + 4 => BitDepth::Four, + 8 => BitDepth::Eight, + 16 => BitDepth::Sixteen, + _ => return Err(PngError::new("Unexpected bit depth in header")), + }, + width: rdr.read_u32::().unwrap(), + height: rdr.read_u32::().unwrap(), + compression: byte_data[10], + filter: byte_data[11], + interlaced: byte_data[12], + }) } diff --git a/src/interlace.rs b/src/interlace.rs index 56b7220a..99384af7 100644 --- a/src/interlace.rs +++ b/src/interlace.rs @@ -92,15 +92,15 @@ pub fn deinterlace_image(png: &mut PngData) { let bits_per_line = 8 + bits_per_pixel as usize * png.ihdr_data.width as usize; // Initialize each output line with a starting filter byte of 0 // as well as some blank data - let mut lines: Vec = vec![BitVec::from_elem(bits_per_line, false); - png.ihdr_data.height as usize]; + let mut lines: Vec = + vec![BitVec::from_elem(bits_per_line, false); png.ihdr_data.height as usize]; let mut current_pass = 1; let mut pass_constants = interlaced_constants(current_pass); let mut current_y: usize = pass_constants.y_shift as usize; for line in png.scan_lines() { let bit_vec = BitVec::from_bytes(&line.data); let bits_in_line = ((png.ihdr_data.width - pass_constants.x_shift as u32) as f32 / - pass_constants.x_step as f32) + pass_constants.x_step as f32) .ceil() as usize * bits_per_pixel as usize; for (i, bit) in bit_vec.iter().enumerate() { // Avoid moving padded 0's into new image @@ -108,7 +108,7 @@ pub fn deinterlace_image(png: &mut PngData) { break; } let current_x: usize = pass_constants.x_shift as usize + - (i / bits_per_pixel as usize) * pass_constants.x_step as usize; + (i / bits_per_pixel as usize) * pass_constants.x_step as usize; // Copy this bit into the output line, offset by 8 because of filter byte let index = 8 + (i % bits_per_pixel as usize) + current_x * bits_per_pixel as usize; lines[current_y].set(index, bit); diff --git a/src/lib.rs b/src/lib.rs index be68879d..8d58a3ad 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,7 +20,7 @@ use png::PngData; use rayon::prelude::*; use std::collections::{HashMap, HashSet}; use std::fs::{File, copy}; -use std::io::{BufWriter, Write, stderr, stdout}; +use std::io::{BufWriter, Write, stdout}; use std::path::{Path, PathBuf}; pub mod colors; @@ -90,6 +90,8 @@ pub struct Options { /// 8-15 are valid values /// Default: `15` pub window: u8, + /// Alpha filtering strategies to use + pub alphas: HashSet, /// Whether to attempt bit depth reduction /// Default: `true` pub bit_depth_reduction: bool, @@ -241,6 +243,9 @@ impl Default for Options { for i in 0..4 { strategies.insert(i); } + let mut alphas = HashSet::new(); + alphas.insert(colors::AlphaOptim::NoOp); + alphas.insert(colors::AlphaOptim::Black); // Default to 1 thread on single-core, otherwise use threads = 1.5x CPU cores let num_cpus = num_cpus::get(); @@ -265,6 +270,7 @@ impl Default for Options { memory: memory, strategies: strategies, window: 15, + alphas, bit_depth_reduction: true, color_type_reduction: true, palette_reduction: true, @@ -281,11 +287,11 @@ impl Default for Options { pub fn optimize(filepath: &Path, opts: &Options) -> Result<(), PngError> { // Initialize the thread pool with correct number of threads let thread_count = opts.threads; - rayon::initialize(rayon::Configuration::new().num_threads(thread_count)).ok(); + let _ = rayon::initialize(rayon::Configuration::new().num_threads(thread_count)); // Read in the file and try to decode as PNG. if opts.verbosity.is_some() { - writeln!(&mut stderr(), "Processing: {}", filepath.to_str().unwrap()).ok(); + eprintln!("Processing: {}", filepath.to_str().unwrap()); } let in_file = Path::new(filepath); @@ -296,27 +302,29 @@ pub fn optimize(filepath: &Path, opts: &Options) -> Result<(), PngError> { let optimized_output = optimize_png(&mut png, &in_data, opts)?; if is_fully_optimized(in_data.len(), optimized_output.len(), opts) { - writeln!(&mut stderr(), "File already optimized").ok(); + eprintln!("File already optimized"); return Ok(()); } if opts.pretend { if opts.verbosity.is_some() { - writeln!(&mut stderr(), "Running in pretend mode, no output").ok(); + eprintln!("Running in pretend mode, no output"); } } else { if opts.backup { - match copy(in_file, - in_file.with_extension(format!("bak.{}", - in_file - .extension() - .unwrap() - .to_str() - .unwrap()))) { + match copy( + in_file, + in_file.with_extension(format!( + "bak.{}", + in_file.extension().unwrap().to_str().unwrap() + )), + ) { Ok(x) => x, Err(_) => { - return Err(PngError::new(&format!("Unable to write to backup file at {}", - opts.out_file.display()))) + return Err(PngError::new(&format!( + "Unable to write to backup file at {}", + opts.out_file.display() + ))) } }; } @@ -331,8 +339,10 @@ pub fn optimize(filepath: &Path, opts: &Options) -> Result<(), PngError> { let out_file = match File::create(&opts.out_file) { Ok(x) => x, Err(_) => { - return Err(PngError::new(&format!("Unable to write to file {}", - opts.out_file.display()))) + return Err(PngError::new(&format!( + "Unable to write to file {}", + opts.out_file.display() + ))) } }; @@ -352,9 +362,9 @@ pub fn optimize(filepath: &Path, opts: &Options) -> Result<(), PngError> { } Err(_) => { if opts.verbosity.is_some() { - writeln!(&mut stderr(), - "Failed to set permissions on output file") - .ok(); + eprintln!( + "Failed to set permissions on output file" + ); } } } @@ -362,17 +372,14 @@ pub fn optimize(filepath: &Path, opts: &Options) -> Result<(), PngError> { } Err(_) => { if opts.verbosity.is_some() { - writeln!(&mut stderr(), - "Failed to read permissions on input file") - .ok(); + eprintln!("Failed to read permissions on input file"); } } } } Err(_) => { if opts.verbosity.is_some() { - writeln!(&mut stderr(), "Failed to read permissions on input file") - .ok(); + eprintln!("Failed to read permissions on input file"); } } }; @@ -382,12 +389,14 @@ pub fn optimize(filepath: &Path, opts: &Options) -> Result<(), PngError> { match buffer.write_all(&optimized_output) { Ok(_) => { if opts.verbosity.is_some() { - writeln!(&mut stderr(), "Output: {}", opts.out_file.display()).ok(); + eprintln!("Output: {}", opts.out_file.display()); } } Err(_) => { - return Err(PngError::new(&format!("Unable to write to file {}", - opts.out_file.display()))) + return Err(PngError::new(&format!( + "Unable to write to file {}", + opts.out_file.display() + ))) } } } @@ -400,11 +409,11 @@ pub fn optimize(filepath: &Path, opts: &Options) -> Result<(), PngError> { pub fn optimize_from_memory(data: &[u8], opts: &Options) -> Result, PngError> { // Initialize the thread pool with correct number of threads let thread_count = opts.threads; - rayon::initialize(rayon::Configuration::new().num_threads(thread_count)).ok(); + let _ = rayon::initialize(rayon::Configuration::new().num_threads(thread_count)); // Read in the file and try to decode as PNG. if opts.verbosity.is_some() { - writeln!(&mut stderr(), "Processing from memory").ok(); + eprintln!("Processing from memory"); } let original_size = data.len() as usize; let mut png = PngData::from_slice(data, opts.fix_errors)?; @@ -413,7 +422,7 @@ pub fn optimize_from_memory(data: &[u8], opts: &Options) -> Result, PngE let optimized_output = optimize_png(&mut png, data, opts)?; if is_fully_optimized(original_size, optimized_output.len(), opts) { - writeln!(&mut stderr(), "Image already optimized").ok(); + eprintln!("Image already optimized"); Ok(data.to_vec()) } else { Ok(optimized_output) @@ -421,11 +430,12 @@ pub fn optimize_from_memory(data: &[u8], opts: &Options) -> Result, PngE } /// Perform optimization on the input PNG object using the options provided -fn optimize_png(png: &mut PngData, - original_data: &[u8], - opts: &Options) - -> Result, PngError> { - type TrialWithData = (u8, u8, u8, u8, Vec); +fn optimize_png( + png: &mut PngData, + original_data: &[u8], + opts: &Options, +) -> Result, PngError> { + type TrialWithData = (TrialOptions, Vec); let original_png = png.clone(); @@ -433,33 +443,27 @@ fn optimize_png(png: &mut PngData, let file_original_size = original_data.len(); let idat_original_size = png.idat_data.len(); if opts.verbosity.is_some() { - writeln!(&mut stderr(), - " {}x{} pixels, PNG format", - png.ihdr_data.width, - png.ihdr_data.height) - .ok(); + eprintln!( + " {}x{} pixels, PNG format", + png.ihdr_data.width, + png.ihdr_data.height + ); if let Some(ref palette) = png.palette { - writeln!(&mut stderr(), - " {} bits/pixel, {} colors in palette", - png.ihdr_data.bit_depth, - palette.len() / 3) - .ok(); + eprintln!( + " {} bits/pixel, {} colors in palette", + png.ihdr_data.bit_depth, + palette.len() / 3 + ); } else { - writeln!(&mut stderr(), - " {}x{} bits/pixel, {:?}", - png.channels_per_pixel(), - png.ihdr_data.bit_depth, - png.ihdr_data.color_type) - .ok(); + eprintln!( + " {}x{} bits/pixel, {:?}", + png.channels_per_pixel(), + png.ihdr_data.bit_depth, + png.ihdr_data.color_type + ); } - writeln!(&mut stderr(), - " IDAT size = {} bytes", - idat_original_size) - .ok(); - writeln!(&mut stderr(), - " File size = {} bytes", - file_original_size) - .ok(); + eprintln!(" IDAT size = {} bytes", idat_original_size); + eprintln!(" File size = {} bytes", file_original_size); } let mut filter = opts.filter.iter().cloned().collect::>(); @@ -470,7 +474,8 @@ fn optimize_png(png: &mut PngData, if opts.use_heuristics { // Heuristically determine which set of options to use if png.ihdr_data.bit_depth.as_u8() >= 8 && - png.ihdr_data.color_type != colors::ColorType::Indexed { + png.ihdr_data.color_type != colors::ColorType::Indexed + { if filter.is_empty() { filter.push(5); } @@ -496,9 +501,9 @@ fn optimize_png(png: &mut PngData, } else { filter.len() }; - let mut results: Vec<(u8, u8, u8, u8)> = Vec::with_capacity(combinations); + let mut results: Vec = Vec::with_capacity(combinations); if opts.verbosity.is_some() { - writeln!(&mut stderr(), "Trying: {} combinations", combinations).ok(); + eprintln!("Trying: {} combinations", combinations); } for f in &filter { @@ -506,24 +511,34 @@ fn optimize_png(png: &mut PngData, for zc in compression { for zm in memory { for zs in &strategies { - results.push((*f, *zc, *zm, *zs)); + results.push(TrialOptions { + filter: *f, + compression: *zc, + memory: *zm, + strategy: *zs, + }); } } } } else { // Zopfli compression has no additional options - results.push((*f, 0, 0, 0)); + results.push(TrialOptions { + filter: *f, + compression: 0, + memory: 0, + strategy: 0, + }); } } - let mut filters_tmp: Vec<(u8, Vec)> = Vec::with_capacity(filter.len()); - filter + let filters: HashMap> = filter .par_iter() .with_max_len(1) - .map(|f| (*f, png.filter_image(*f))) - .collect_into(&mut filters_tmp); - - let filters: HashMap> = filters_tmp.into_iter().collect(); + .map(|f| { + let png = png.clone(); + (*f, png.filter_image(*f)) + }) + .collect(); let original_len = original_png.idat_data.len(); let added_interlacing = opts.interlace == Some(1) && original_png.ihdr_data.interlaced == 0; @@ -533,47 +548,54 @@ fn optimize_png(png: &mut PngData, .into_par_iter() .with_max_len(1) .filter_map(|trial| { - let filtered = &filters[&trial.0]; + let filtered = &filters[&trial.filter]; let new_idat = if opts.deflate == Deflaters::Zlib { - deflate::deflate(filtered, trial.1, trial.2, trial.3, opts.window) + deflate::deflate( + filtered, + trial.compression, + trial.memory, + trial.strategy, + opts.window, + ) } else { deflate::zopfli_deflate(filtered) }.unwrap(); if opts.verbosity == Some(1) { - writeln!(&mut stderr(), - " zc = {} zm = {} zs = {} f = {} {} bytes", - trial.1, - trial.2, - trial.3, - trial.0, - new_idat.len()) - .ok(); + eprintln!( + " zc = {} zm = {} zs = {} f = {} {} bytes", + trial.compression, + trial.memory, + trial.strategy, + trial.filter, + new_idat.len() + ); } if new_idat.len() < original_len || added_interlacing || opts.force { - Some((trial.0, trial.1, trial.2, trial.3, new_idat)) + Some((trial, new_idat)) } else { None } }) - .reduce_with(|i, j| if i.4.len() <= j.4.len() { i } else { j }); + .reduce_with(|i, j| if i.1.len() <= j.1.len() { i } else { j }); if let Some(better) = best { - png.idat_data = better.4; + png.idat_data = better.1; if opts.verbosity.is_some() { - writeln!(&mut stderr(), "Found better combination:").ok(); - writeln!(&mut stderr(), - " zc = {} zm = {} zs = {} f = {} {} bytes", - better.1, - better.2, - better.3, - better.0, - png.idat_data.len()) - .ok(); + let opts = better.0; + eprintln!("Found better combination:"); + eprintln!( + " zc = {} zm = {} zs = {} f = {} {} bytes", + opts.compression, + opts.memory, + opts.strategy, + opts.filter, + png.idat_data.len() + ); } } else if reduction_occurred { - png.reset_from_original(original_png); + png.reset_from_original(&original_png); } } @@ -583,34 +605,32 @@ fn optimize_png(png: &mut PngData, if opts.verbosity.is_some() { if idat_original_size >= png.idat_data.len() { - writeln!(&mut stderr(), - " IDAT size = {} bytes ({} bytes decrease)", - png.idat_data.len(), - idat_original_size - png.idat_data.len()) - .ok(); + eprintln!( + " IDAT size = {} bytes ({} bytes decrease)", + png.idat_data.len(), + idat_original_size - png.idat_data.len() + ); } else { - writeln!(&mut stderr(), - " IDAT size = {} bytes ({} bytes increase)", - png.idat_data.len(), - png.idat_data.len() - idat_original_size) - .ok(); + eprintln!( + " IDAT size = {} bytes ({} bytes increase)", + png.idat_data.len(), + png.idat_data.len() - idat_original_size + ); } if file_original_size >= output.len() { - writeln!(&mut stderr(), - " file size = {} bytes ({} bytes = {:.2}% decrease)", - output.len(), - file_original_size - output.len(), - (file_original_size - output.len()) as f64 / file_original_size as f64 * - 100f64) - .ok(); + eprintln!( + " file size = {} bytes ({} bytes = {:.2}% decrease)", + output.len(), + file_original_size - output.len(), + (file_original_size - output.len()) as f64 / file_original_size as f64 * 100f64 + ); } else { - writeln!(&mut stderr(), - " file size = {} bytes ({} bytes = {:.2}% increase)", - output.len(), - output.len() - file_original_size, - (output.len() - file_original_size) as f64 / file_original_size as f64 * - 100f64) - .ok(); + eprintln!( + " file size = {} bytes ({} bytes = {:.2}% increase)", + output.len(), + output.len() - file_original_size, + (output.len() - file_original_size) as f64 / file_original_size as f64 * 100f64 + ); } } @@ -620,13 +640,16 @@ fn optimize_png(png: &mut PngData, if let Ok(new_png) = new_png { if let Ok(old_png) = old_png { if old_png - .pixels() - .map(|x| x.2.channels().to_owned()) - .collect::>>() == - new_png - .pixels() - .map(|x| x.2.channels().to_owned()) - .collect::>>() { + .pixels() + .map(|x| x.2.channels().to_owned()) + .filter(|p| !(p.len() == 4 && p[3] == 0)) + .collect::>>() == + new_png + .pixels() + .map(|x| x.2.channels().to_owned()) + .filter(|p| !(p.len() == 4 && p[3] == 0)) + .collect::>>() + { return Ok(output); } } else { @@ -637,7 +660,9 @@ fn optimize_png(png: &mut PngData, } } - writeln!(&mut stderr(), "The resulting image is corrupted and will not be outputted.\nThis is a bug! Please report it at https://github.com/shssoichiro/oxipng/issues").ok(); + eprintln!( + "The resulting image is corrupted and will not be outputted.\nThis is a bug! Please report it at https://github.com/shssoichiro/oxipng/issues" + ); Err(PngError::new("The resulting image is corrupted")) } @@ -678,6 +703,8 @@ fn perform_reductions(png: &mut png::PngData, opts: &Options) -> bool { } } + png.try_alpha_reduction(&opts.alphas); + reduction_occurred } @@ -685,18 +712,18 @@ fn perform_reductions(png: &mut png::PngData, opts: &Options) -> bool { #[inline] fn report_reduction(png: &png::PngData) { if let Some(ref palette) = png.palette { - writeln!(&mut stderr(), - "Reducing image to {} bits/pixel, {} colors in palette", - png.ihdr_data.bit_depth, - palette.len() / 3) - .ok(); + eprintln!( + "Reducing image to {} bits/pixel, {} colors in palette", + png.ihdr_data.bit_depth, + palette.len() / 3 + ); } else { - writeln!(&mut stderr(), - "Reducing image to {}x{} bits/pixel, {}", - png.channels_per_pixel(), - png.ihdr_data.bit_depth, - png.ihdr_data.color_type) - .ok(); + eprintln!( + "Reducing image to {}x{} bits/pixel, {}", + png.channels_per_pixel(), + png.ihdr_data.bit_depth, + png.ihdr_data.color_type + ); } } @@ -711,8 +738,17 @@ fn perform_strip(png: &mut png::PngData, opts: &Options) { } } Headers::Safe => { - const PRESERVED_HEADERS: [&'static str; 9] = ["cHRM", "gAMA", "iCCP", "sBIT", "sRGB", - "bKGD", "hIST", "pHYs", "sPLT"]; + const PRESERVED_HEADERS: [&'static str; 9] = [ + "cHRM", + "gAMA", + "iCCP", + "sBIT", + "sRGB", + "bKGD", + "hIST", + "pHYs", + "sPLT", + ]; let hdrs = png.aux_headers.keys().cloned().collect::>(); for hdr in hdrs { if !PRESERVED_HEADERS.contains(&hdr.as_ref()) { @@ -731,3 +767,12 @@ fn perform_strip(png: &mut png::PngData, opts: &Options) { fn is_fully_optimized(original_size: usize, optimized_size: usize, opts: &Options) -> bool { original_size <= optimized_size && !opts.force && opts.interlace.is_none() } + +#[derive(Debug, PartialEq, Clone, Copy)] +/// Defines options to be used for a single compression trial +struct TrialOptions { + pub filter: u8, + pub compression: u8, + pub memory: u8, + pub strategy: u8, +} diff --git a/src/main.rs b/src/main.rs index 57558ae9..ba19ac96 100644 --- a/src/main.rs +++ b/src/main.rs @@ -12,13 +12,13 @@ extern crate clap; extern crate regex; use clap::{App, Arg, ArgMatches}; +use oxipng::colors::AlphaOptim; use oxipng::deflate::Deflaters; use oxipng::headers::Headers; use oxipng::Options; use regex::Regex; use std::collections::HashSet; use std::fs::DirBuilder; -use std::io::{Write, stderr}; use std::path::PathBuf; fn main() { @@ -157,6 +157,10 @@ fn main() { .possible_value("8k") .possible_value("16k") .possible_value("32k")) + .arg(Arg::with_name("alpha") + .help("Perform additional alpha optimizations") + .short("a") + .long("alpha")) .arg(Arg::with_name("no-bit-reduction") .help("No bit depth reduction") .long("nb")) @@ -222,17 +226,19 @@ fn main() { let opts = match parse_opts_into_struct(&matches) { Ok(x) => x, Err(x) => { - writeln!(&mut stderr(), "{}", x).ok(); + eprintln!("{}", x); return (); } }; - handle_optimization(matches - .values_of("files") - .unwrap() - .map(PathBuf::from) - .collect(), - &opts); + handle_optimization( + matches + .values_of("files") + .unwrap() + .map(PathBuf::from) + .collect(), + &opts, + ); } fn handle_optimization(inputs: Vec, opts: &Options) { @@ -240,17 +246,16 @@ fn handle_optimization(inputs: Vec, opts: &Options) { let mut current_opts = opts.clone(); if input.is_dir() { if current_opts.recursive { - handle_optimization(input - .read_dir() - .unwrap() - .map(|x| x.unwrap().path()) - .collect(), - ¤t_opts) + handle_optimization( + input + .read_dir() + .unwrap() + .map(|x| x.unwrap().path()) + .collect(), + ¤t_opts, + ) } else { - writeln!(&mut stderr(), - "{} is a directory, skipping", - input.display()) - .ok(); + eprintln!("{} is a directory, skipping", input.display()); } continue; } @@ -262,7 +267,7 @@ fn handle_optimization(inputs: Vec, opts: &Options) { match oxipng::optimize(&input, ¤t_opts) { Ok(_) => (), Err(x) => { - writeln!(&mut stderr(), "{}", x).ok(); + eprintln!("{}", x); } }; } @@ -320,8 +325,10 @@ fn parse_opts_into_struct(matches: &ArgMatches) -> Result { Err(x) => return Err(format!("Could not create output directory {}", x)), }; } else if !path.is_dir() { - return Err(format!("{} is an existing file (not a directory), cannot create directory", - x)); + return Err(format!( + "{} is an existing file (not a directory), cannot create directory", + x + )); } opts.out_dir = Some(path); } @@ -334,6 +341,14 @@ fn parse_opts_into_struct(matches: &ArgMatches) -> Result { opts.stdout = true; } + if matches.is_present("alpha") { + opts.alphas.insert(AlphaOptim::White); + opts.alphas.insert(AlphaOptim::Up); + opts.alphas.insert(AlphaOptim::Down); + opts.alphas.insert(AlphaOptim::Left); + opts.alphas.insert(AlphaOptim::Right); + } + if matches.is_present("backup") { opts.backup = true; } @@ -398,8 +413,10 @@ fn parse_opts_into_struct(matches: &ArgMatches) -> Result { .collect::>(); if hdrs.contains(&"safe".to_owned()) || hdrs.contains(&"all".to_owned()) { if hdrs.len() > 1 { - return Err("'safe' or 'all' presets for --strip should be used by themselves" - .to_owned()); + return Err( + "'safe' or 'all' presets for --strip should be used by themselves" + .to_owned(), + ); } if hdrs[0] == "safe" { opts.strip = Headers::Safe; @@ -432,18 +449,21 @@ fn parse_opts_into_struct(matches: &ArgMatches) -> Result { Ok(opts) } -fn parse_numeric_range_opts(input: &str, - min_value: u8, - max_value: u8) - -> Result, String> { +fn parse_numeric_range_opts( + input: &str, + min_value: u8, + max_value: u8, +) -> Result, String> { let one_item = Regex::new(format!(r"^[{}-{}]$", min_value, max_value).as_ref()).unwrap(); - let multiple_items = Regex::new(format!(r"^([{}-{}])(,|-)([{}-{}])$", - min_value, - max_value, - min_value, - max_value) - .as_ref()) - .unwrap(); + let multiple_items = Regex::new( + format!( + r"^([{}-{}])(,|-)([{}-{}])$", + min_value, + max_value, + min_value, + max_value + ).as_ref(), + ).unwrap(); let mut items = HashSet::new(); if one_item.is_match(input) { diff --git a/src/png.rs b/src/png.rs index b7b19ac7..884dc4a3 100644 --- a/src/png.rs +++ b/src/png.rs @@ -1,6 +1,6 @@ use bit_vec::BitVec; use byteorder::{BigEndian, WriteBytesExt}; -use colors::{BitDepth, ColorType}; +use colors::{BitDepth, ColorType, AlphaOptim}; use crc::crc32; use deflate; use error::PngError; @@ -15,6 +15,12 @@ use std::io::Read; use std::iter::Iterator; use std::path::Path; +const STD_COMPRESSION: u8 = 8; +const STD_MEMORY: u8 = 9; +const STD_STRATEGY: u8 = 2; // Huffman only +const STD_WINDOW: u8 = 15; +const STD_FILTERS: [u8; 2] = [0, 5]; + #[derive(Debug, Clone)] /// An iterator over the scan lines of a PNG image pub struct ScanLines<'a> { @@ -51,7 +57,7 @@ impl<'a> Iterator for ScanLines<'a> { } } let bits_per_pixel = self.png.ihdr_data.bit_depth.as_u8() as u32 * - self.png.channels_per_pixel() as u32; + self.png.channels_per_pixel() as u32; let y_steps; let pixels_factor; match self.pass { @@ -129,23 +135,23 @@ impl<'a> Iterator for ScanLines<'a> { } } Some(ScanLine { - filter: self.png.raw_data[self.start], - data: self.png.raw_data[(self.start + 1)..self.end].to_owned(), - pass: current_pass, - }) + filter: self.png.raw_data[self.start], + data: self.png.raw_data[(self.start + 1)..self.end].to_owned(), + pass: current_pass, + }) } else { // Standard, non-interlaced PNG scanlines let bits_per_line = self.png.ihdr_data.width as usize * - self.png.ihdr_data.bit_depth.as_u8() as usize * - self.png.channels_per_pixel() as usize; + self.png.ihdr_data.bit_depth.as_u8() as usize * + self.png.channels_per_pixel() as usize; let bytes_per_line = (bits_per_line as f32 / 8f32).ceil() as usize; self.start = self.end; self.end = self.start + bytes_per_line + 1; Some(ScanLine { - filter: self.png.raw_data[self.start], - data: self.png.raw_data[(self.start + 1)..self.end].to_owned(), - pass: None, - }) + filter: self.png.raw_data[self.start], + data: self.png.raw_data[(self.start + 1)..self.end].to_owned(), + pass: None, + }) } } } @@ -280,14 +286,14 @@ impl PngData { } #[doc(hidden)] - pub fn reset_from_original(&mut self, original: PngData) { - self.idat_data = original.idat_data; + pub fn reset_from_original(&mut self, original: &PngData) { + self.idat_data = original.idat_data.clone(); self.ihdr_data = original.ihdr_data; - self.raw_data = original.raw_data; - self.palette = original.palette; - self.transparency_pixel = original.transparency_pixel; - self.transparency_palette = original.transparency_palette; - self.aux_headers = original.aux_headers; + self.raw_data = original.raw_data.clone(); + self.palette = original.palette.clone(); + self.transparency_pixel = original.transparency_pixel.clone(); + self.transparency_palette = original.transparency_palette.clone(); + self.aux_headers = original.aux_headers.clone(); } /// Return the number of channels in the image, based on color type @@ -307,21 +313,19 @@ impl PngData { let mut output = vec![0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A]; // IHDR let mut ihdr_data = Vec::with_capacity(13); - ihdr_data.write_u32::(self.ihdr_data.width).ok(); - ihdr_data.write_u32::(self.ihdr_data.height).ok(); - ihdr_data.write_u8(self.ihdr_data.bit_depth.as_u8()).ok(); - ihdr_data - .write_u8(self.ihdr_data.color_type.png_header_code()) - .ok(); - ihdr_data.write_u8(0).ok(); // Compression -- deflate - ihdr_data.write_u8(0).ok(); // Filter method -- 5-way adaptive filtering - ihdr_data.write_u8(self.ihdr_data.interlaced).ok(); + let _ = ihdr_data.write_u32::(self.ihdr_data.width); + let _ = ihdr_data.write_u32::(self.ihdr_data.height); + let _ = ihdr_data.write_u8(self.ihdr_data.bit_depth.as_u8()); + let _ = ihdr_data.write_u8(self.ihdr_data.color_type.png_header_code()); + let _ = ihdr_data.write_u8(0); // Compression -- deflate + let _ = ihdr_data.write_u8(0); // Filter method -- 5-way adaptive filtering + let _ = ihdr_data.write_u8(self.ihdr_data.interlaced); write_png_block(b"IHDR", &ihdr_data, &mut output); // Ancillary headers - for (key, header) in - self.aux_headers - .iter() - .filter(|&(key, _)| !(*key == "bKGD" || *key == "hIST" || *key == "tRNS")) { + for (key, header) in self.aux_headers.iter().filter(|&(key, _)| { + !(*key == "bKGD" || *key == "hIST" || *key == "tRNS") + }) + { write_png_block(key.as_bytes(), header, &mut output); } // Palette @@ -336,10 +340,10 @@ impl PngData { write_png_block(b"tRNS", transparency_pixel, &mut output); } // Special ancillary headers that need to come after PLTE but before IDAT - for (key, header) in - self.aux_headers - .iter() - .filter(|&(key, _)| *key == "bKGD" || *key == "hIST" || *key == "tRNS") { + for (key, header) in self.aux_headers.iter().filter(|&(key, _)| { + *key == "bKGD" || *key == "hIST" || *key == "tRNS" + }) + { write_png_block(key.as_bytes(), header, &mut output); } // IDAT data @@ -365,7 +369,7 @@ impl PngData { pub fn unfilter_image(&self) -> Vec { let mut unfiltered = Vec::with_capacity(self.raw_data.len()); let bpp = (((self.ihdr_data.bit_depth.as_u8() * self.channels_per_pixel()) as f32) / - 8f32) + 8f32) .ceil() as usize; let mut last_line: Vec = Vec::new(); for line in self.scan_lines() { @@ -387,7 +391,7 @@ impl PngData { pub fn filter_image(&self, filter: u8) -> Vec { let mut filtered = Vec::with_capacity(self.raw_data.len()); let bpp = (((self.ihdr_data.bit_depth.as_u8() * self.channels_per_pixel()) as f32) / - 8f32) + 8f32) .ceil() as usize; let mut last_line: Vec = Vec::new(); let mut last_pass: Option = None; @@ -396,8 +400,9 @@ impl PngData { 0 | 1 | 2 | 3 | 4 => { if last_pass == line.pass || filter <= 1 { filtered.push(filter); - filtered - .extend_from_slice(&filter_line(filter, bpp, &line.data, &last_line)); + filtered.extend_from_slice( + &filter_line(filter, bpp, &line.data, &last_line), + ); } else { // Avoid vertical filtering on first line of each interlacing pass filtered.push(0); @@ -438,17 +443,18 @@ impl PngData { pub fn reduce_bit_depth(&mut self) -> bool { if self.ihdr_data.bit_depth != BitDepth::Sixteen { if self.ihdr_data.color_type == ColorType::Indexed || - self.ihdr_data.color_type == ColorType::Grayscale { + self.ihdr_data.color_type == ColorType::Grayscale + { return reduce_bit_depth_8_or_less(self); } return false; } // Reduce from 16 to 8 bits per channel per pixel - let mut reduced = Vec::with_capacity((self.ihdr_data.width * self.ihdr_data.height * - self.channels_per_pixel() as u32 + - self.ihdr_data.height) as - usize); + let mut reduced = Vec::with_capacity( + (self.ihdr_data.width * self.ihdr_data.height * self.channels_per_pixel() as u32 + + self.ihdr_data.height) as usize, + ); let mut high_byte = 0; for line in self.scan_lines() { @@ -494,20 +500,20 @@ impl PngData { .chunks(3) .zip(trns.iter().chain([255].iter().cycle())) .flat_map(|(pixel, trns)| { - let mut pixel = pixel.to_owned(); - pixel.push(*trns); - pixel - }) + let mut pixel = pixel.to_owned(); + pixel.push(*trns); + pixel + }) .collect() } else { self.palette.clone().unwrap() }; let mut indexed_palette: Vec<&[u8]> = palette .chunks(if self.transparency_palette.is_some() { - 4 - } else { - 3 - }) + 4 + } else { + 3 + }) .collect(); // A map of old indexes to new ones, for any moved let mut index_map: HashMap = HashMap::new(); @@ -591,10 +597,12 @@ impl PngData { true } - fn do_palette_reduction(&mut self, - indices: &[u8], - index_map: &mut HashMap, - indexed_palette: &mut Vec<&[u8]>) { + fn do_palette_reduction( + &mut self, + indices: &[u8], + index_map: &mut HashMap, + indexed_palette: &mut Vec<&[u8]>, + ) { let mut new_data = Vec::with_capacity(self.raw_data.len()); let original_len = indexed_palette.len(); for idx in indices.iter().sorted_by(|a, b| b.cmp(a)) { @@ -687,7 +695,9 @@ impl PngData { .cloned() .flatten() .enumerate() - .filter(|&(i, _)| !(self.transparency_palette.is_some() && i % 4 == 3)) + .filter(|&(i, _)| { + !(self.transparency_palette.is_some() && i % 4 == 3) + }) .map(|(_, x)| *x) .collect::>(); self.palette = Some(new_palette); @@ -711,13 +721,15 @@ impl PngData { } if self.ihdr_data.color_type == ColorType::GrayscaleAlpha && - reduce_grayscale_alpha_to_grayscale(self) { + reduce_grayscale_alpha_to_grayscale(self) + { changed = true; should_reduce_bit_depth = true; } if self.ihdr_data.color_type == ColorType::RGB && - (reduce_rgb_to_grayscale(self) || reduce_rgb_to_palette(self)) { + (reduce_rgb_to_grayscale(self) || reduce_rgb_to_palette(self)) + { changed = true; should_reduce_bit_depth = true; } @@ -731,6 +743,174 @@ impl PngData { changed } + pub fn try_alpha_reduction(&mut self, alphas: &HashSet) { + assert!(!alphas.is_empty()); + let best = alphas + .iter() + .map(|alpha| { + let mut image = self.clone(); + image.reduce_alpha_channel(*alpha); + let size = STD_FILTERS + .iter() + .map(|f| { + deflate::deflate( + &image.filter_image(*f), + STD_COMPRESSION, + STD_MEMORY, + STD_STRATEGY, + STD_WINDOW, + ).unwrap() + .len() + }) + .min() + .unwrap(); + (size, image) + }) + .min_by_key(|&(size, _)| size) + .unwrap(); + + self.raw_data = best.1.raw_data; + } + + pub fn reduce_alpha_channel(&mut self, optim: AlphaOptim) -> bool { + let (bpc, bpp) = match self.ihdr_data.color_type { + ColorType::RGBA => { + match self.ihdr_data.bit_depth { + BitDepth::Sixteen => (2, 8), + BitDepth::Eight => (1, 4), + _ => unreachable!(), + } + } + ColorType::GrayscaleAlpha => { + match self.ihdr_data.bit_depth { + BitDepth::Sixteen => (2, 4), + BitDepth::Eight => (1, 2), + _ => unreachable!(), + } + } + _ => { + return false; + } + }; + let mut reduced = Vec::with_capacity(self.raw_data.len()); + + match optim { + AlphaOptim::NoOp => { + return false; + } + AlphaOptim::Black => { + for line in self.scan_lines() { + reduced.push(line.filter); + for pixel in line.data.chunks(bpp) { + if pixel.iter().skip(bpp - bpc).fold(0, |sum, i| sum | i) == 0 { + for _ in 0..bpp { + reduced.push(0); + } + } else { + reduced.extend_from_slice(pixel); + } + } + } + } + AlphaOptim::White => { + for line in self.scan_lines() { + reduced.push(line.filter); + for pixel in line.data.chunks(bpp) { + if pixel.iter().skip(bpp - bpc).fold(0, |sum, i| sum | i) == 0 { + for _ in 0..(bpp - bpc) { + reduced.push(255); + } + for _ in 0..bpc { + reduced.push(0); + } + } else { + reduced.extend_from_slice(pixel); + } + } + } + } + AlphaOptim::Up => { + let mut lines = Vec::new(); + let scan_lines = self.scan_lines().collect::>(); + let mut last_line = vec![0; scan_lines[0].data.len()]; + let mut current_line = Vec::with_capacity(last_line.len()); + for line in scan_lines.into_iter().rev() { + current_line.push(line.filter); + for (pixel, last_pixel) in line.data.chunks(bpp).zip(last_line.chunks(bpp)) { + if pixel.iter().skip(bpp - bpc).fold(0, |sum, i| sum | i) == 0 { + current_line.extend_from_slice(&last_pixel[0..(bpp - bpc)]); + for _ in 0..bpc { + current_line.push(0); + } + } else { + current_line.extend_from_slice(pixel); + } + } + last_line = current_line.clone(); + lines.push(current_line.clone()); + current_line.clear(); + } + reduced.extend(lines.into_iter().rev().flatten()); + } + AlphaOptim::Down => { + let mut last_line = vec![0; self.scan_lines().next().unwrap().data.len()]; + for line in self.scan_lines() { + reduced.push(line.filter); + for (pixel, last_pixel) in line.data.chunks(bpp).zip(last_line.chunks(bpp)) { + if pixel.iter().skip(bpp - bpc).fold(0, |sum, i| sum | i) == 0 { + reduced.extend_from_slice(&last_pixel[0..(bpp - bpc)]); + for _ in 0..bpc { + reduced.push(0); + } + } else { + reduced.extend_from_slice(pixel); + } + } + last_line = reduced.clone(); + } + } + AlphaOptim::Left => { + for line in self.scan_lines() { + let mut line_bytes = Vec::with_capacity(line.data.len()); + let mut last_pixel = vec![0; bpp]; + for pixel in line.data.chunks(bpp).rev() { + if pixel.iter().skip(bpp - bpc).fold(0, |sum, i| sum | i) == 0 { + line_bytes.extend_from_slice(&last_pixel[0..(bpp - bpc)]); + for _ in 0..bpc { + line_bytes.push(0); + } + } else { + line_bytes.extend_from_slice(pixel); + } + last_pixel = pixel.to_owned(); + } + reduced.push(line.filter); + reduced.extend(line_bytes.chunks(bpp).rev().flatten()); + } + } + AlphaOptim::Right => { + for line in self.scan_lines() { + reduced.push(line.filter); + let mut last_pixel = vec![0; bpp]; + for pixel in line.data.chunks(bpp) { + if pixel.iter().skip(bpp - bpc).fold(0, |sum, i| sum | i) == 0 { + reduced.extend_from_slice(&last_pixel[0..(bpp - bpc)]); + for _ in 0..bpc { + reduced.push(0); + } + } else { + reduced.extend_from_slice(pixel); + } + last_pixel = pixel.to_owned(); + } + } + } + } + + self.raw_data = reduced; + true + } + /// Convert the image to the specified interlacing type /// Returns true if the interlacing was changed, false otherwise /// The `interlace` parameter specifies the *new* interlacing mode @@ -758,10 +938,8 @@ fn write_png_block(key: &[u8], header: &[u8], output: &mut Vec) { header_data.extend_from_slice(key); header_data.extend_from_slice(header); output.reserve(header_data.len() + 8); - output - .write_u32::(header_data.len() as u32 - 4) - .ok(); + let _ = output.write_u32::(header_data.len() as u32 - 4); let crc = crc32::checksum_ieee(&header_data); output.append(&mut header_data); - output.write_u32::(crc).ok(); + let _ = output.write_u32::(crc); } diff --git a/src/reduction.rs b/src/reduction.rs index 8ac3b80c..fdd59c3f 100644 --- a/src/reduction.rs +++ b/src/reduction.rs @@ -134,13 +134,14 @@ pub fn reduce_rgba_to_palette(png: &mut PngData) -> bool { } } - let mut color_palette = Vec::with_capacity(palette.len() * 3 + - if png.aux_headers - .contains_key(&"bKGD".to_string()) { - 6 - } else { - 0 - }); + let mut color_palette = Vec::with_capacity( + palette.len() * 3 + + if png.aux_headers.contains_key(&"bKGD".to_string()) { + 6 + } else { + 0 + }, + ); let mut trans_palette = Vec::with_capacity(palette.len()); for color in &palette { for (i, byte) in color.iter().enumerate() { @@ -166,9 +167,10 @@ pub fn reduce_rgba_to_palette(png: &mut PngData) -> bool { .step(2) .cloned() .collect::>(); - if let Some(entry) = color_palette - .chunks(3) - .position(|x| x == header_pixels.as_slice()) { + if let Some(entry) = color_palette.chunks(3).position( + |x| x == header_pixels.as_slice(), + ) + { *bkgd_header = vec![entry as u8]; } else if color_palette.len() / 3 == 256 { return false; @@ -244,9 +246,10 @@ pub fn reduce_rgb_to_palette(png: &mut PngData) -> bool { .step(2) .cloned() .collect::>(); - if let Some(entry) = color_palette - .chunks(3) - .position(|x| x == header_pixels.as_slice()) { + if let Some(entry) = color_palette.chunks(3).position( + |x| x == header_pixels.as_slice(), + ) + { *bkgd_header = vec![entry as u8]; } else if color_palette.len() == 255 { return false; diff --git a/tests/files/grayscale_alpha_16_reduce_alpha_black.png b/tests/files/grayscale_alpha_16_reduce_alpha_black.png new file mode 100644 index 00000000..78b72778 Binary files /dev/null and b/tests/files/grayscale_alpha_16_reduce_alpha_black.png differ diff --git a/tests/files/grayscale_alpha_16_reduce_alpha_down.png b/tests/files/grayscale_alpha_16_reduce_alpha_down.png new file mode 100644 index 00000000..78b72778 Binary files /dev/null and b/tests/files/grayscale_alpha_16_reduce_alpha_down.png differ diff --git a/tests/files/grayscale_alpha_16_reduce_alpha_left.png b/tests/files/grayscale_alpha_16_reduce_alpha_left.png new file mode 100644 index 00000000..78b72778 Binary files /dev/null and b/tests/files/grayscale_alpha_16_reduce_alpha_left.png differ diff --git a/tests/files/grayscale_alpha_16_reduce_alpha_right.png b/tests/files/grayscale_alpha_16_reduce_alpha_right.png new file mode 100644 index 00000000..78b72778 Binary files /dev/null and b/tests/files/grayscale_alpha_16_reduce_alpha_right.png differ diff --git a/tests/files/grayscale_alpha_16_reduce_alpha_up.png b/tests/files/grayscale_alpha_16_reduce_alpha_up.png new file mode 100644 index 00000000..78b72778 Binary files /dev/null and b/tests/files/grayscale_alpha_16_reduce_alpha_up.png differ diff --git a/tests/files/grayscale_alpha_16_reduce_alpha_white.png b/tests/files/grayscale_alpha_16_reduce_alpha_white.png new file mode 100644 index 00000000..78b72778 Binary files /dev/null and b/tests/files/grayscale_alpha_16_reduce_alpha_white.png differ diff --git a/tests/files/grayscale_alpha_8_reduce_alpha_black.png b/tests/files/grayscale_alpha_8_reduce_alpha_black.png new file mode 100644 index 00000000..c2e1d1ce Binary files /dev/null and b/tests/files/grayscale_alpha_8_reduce_alpha_black.png differ diff --git a/tests/files/grayscale_alpha_8_reduce_alpha_down.png b/tests/files/grayscale_alpha_8_reduce_alpha_down.png new file mode 100644 index 00000000..c2e1d1ce Binary files /dev/null and b/tests/files/grayscale_alpha_8_reduce_alpha_down.png differ diff --git a/tests/files/grayscale_alpha_8_reduce_alpha_left.png b/tests/files/grayscale_alpha_8_reduce_alpha_left.png new file mode 100644 index 00000000..c2e1d1ce Binary files /dev/null and b/tests/files/grayscale_alpha_8_reduce_alpha_left.png differ diff --git a/tests/files/grayscale_alpha_8_reduce_alpha_right.png b/tests/files/grayscale_alpha_8_reduce_alpha_right.png new file mode 100644 index 00000000..c2e1d1ce Binary files /dev/null and b/tests/files/grayscale_alpha_8_reduce_alpha_right.png differ diff --git a/tests/files/grayscale_alpha_8_reduce_alpha_up.png b/tests/files/grayscale_alpha_8_reduce_alpha_up.png new file mode 100644 index 00000000..c2e1d1ce Binary files /dev/null and b/tests/files/grayscale_alpha_8_reduce_alpha_up.png differ diff --git a/tests/files/grayscale_alpha_8_reduce_alpha_white.png b/tests/files/grayscale_alpha_8_reduce_alpha_white.png new file mode 100644 index 00000000..c2e1d1ce Binary files /dev/null and b/tests/files/grayscale_alpha_8_reduce_alpha_white.png differ diff --git a/tests/files/rgba_16_reduce_alpha_black.png b/tests/files/rgba_16_reduce_alpha_black.png new file mode 100644 index 00000000..4792bf00 Binary files /dev/null and b/tests/files/rgba_16_reduce_alpha_black.png differ diff --git a/tests/files/rgba_16_reduce_alpha_down.png b/tests/files/rgba_16_reduce_alpha_down.png new file mode 100644 index 00000000..4792bf00 Binary files /dev/null and b/tests/files/rgba_16_reduce_alpha_down.png differ diff --git a/tests/files/rgba_16_reduce_alpha_left.png b/tests/files/rgba_16_reduce_alpha_left.png new file mode 100644 index 00000000..4792bf00 Binary files /dev/null and b/tests/files/rgba_16_reduce_alpha_left.png differ diff --git a/tests/files/rgba_16_reduce_alpha_right.png b/tests/files/rgba_16_reduce_alpha_right.png new file mode 100644 index 00000000..4792bf00 Binary files /dev/null and b/tests/files/rgba_16_reduce_alpha_right.png differ diff --git a/tests/files/rgba_16_reduce_alpha_up.png b/tests/files/rgba_16_reduce_alpha_up.png new file mode 100644 index 00000000..4792bf00 Binary files /dev/null and b/tests/files/rgba_16_reduce_alpha_up.png differ diff --git a/tests/files/rgba_16_reduce_alpha_white.png b/tests/files/rgba_16_reduce_alpha_white.png new file mode 100644 index 00000000..4792bf00 Binary files /dev/null and b/tests/files/rgba_16_reduce_alpha_white.png differ diff --git a/tests/files/rgba_8_reduce_alpha_black.png b/tests/files/rgba_8_reduce_alpha_black.png new file mode 100644 index 00000000..22a5a059 Binary files /dev/null and b/tests/files/rgba_8_reduce_alpha_black.png differ diff --git a/tests/files/rgba_8_reduce_alpha_down.png b/tests/files/rgba_8_reduce_alpha_down.png new file mode 100644 index 00000000..22a5a059 Binary files /dev/null and b/tests/files/rgba_8_reduce_alpha_down.png differ diff --git a/tests/files/rgba_8_reduce_alpha_left.png b/tests/files/rgba_8_reduce_alpha_left.png new file mode 100644 index 00000000..22a5a059 Binary files /dev/null and b/tests/files/rgba_8_reduce_alpha_left.png differ diff --git a/tests/files/rgba_8_reduce_alpha_right.png b/tests/files/rgba_8_reduce_alpha_right.png new file mode 100644 index 00000000..22a5a059 Binary files /dev/null and b/tests/files/rgba_8_reduce_alpha_right.png differ diff --git a/tests/files/rgba_8_reduce_alpha_up.png b/tests/files/rgba_8_reduce_alpha_up.png new file mode 100644 index 00000000..22a5a059 Binary files /dev/null and b/tests/files/rgba_8_reduce_alpha_up.png differ diff --git a/tests/files/rgba_8_reduce_alpha_white.png b/tests/files/rgba_8_reduce_alpha_white.png new file mode 100644 index 00000000..22a5a059 Binary files /dev/null and b/tests/files/rgba_8_reduce_alpha_white.png differ diff --git a/tests/filters.rs b/tests/filters.rs index dba811d0..d1c46505 100644 --- a/tests/filters.rs +++ b/tests/filters.rs @@ -20,13 +20,15 @@ fn get_opts(input: &Path) -> oxipng::Options { options } -fn test_it_converts(input: &Path, - output: &Path, - opts: &oxipng::Options, - color_type_in: ColorType, - bit_depth_in: BitDepth, - color_type_out: ColorType, - bit_depth_out: BitDepth) { +fn test_it_converts( + input: &Path, + output: &Path, + opts: &oxipng::Options, + color_type_in: ColorType, + bit_depth_in: BitDepth, + color_type_out: ColorType, + bit_depth_out: BitDepth, +) { let png = png::PngData::new(input, opts.fix_errors).unwrap(); assert_eq!(png.ihdr_data.color_type, color_type_in); @@ -60,13 +62,15 @@ fn filter_0_for_rgba_16() { opts.filter.insert(0); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGBA, - BitDepth::Sixteen, - ColorType::RGBA, - BitDepth::Sixteen); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGBA, + BitDepth::Sixteen, + ColorType::RGBA, + BitDepth::Sixteen, + ); } #[test] @@ -77,13 +81,15 @@ fn filter_1_for_rgba_16() { opts.filter.insert(1); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGBA, - BitDepth::Sixteen, - ColorType::RGBA, - BitDepth::Sixteen); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGBA, + BitDepth::Sixteen, + ColorType::RGBA, + BitDepth::Sixteen, + ); } #[test] @@ -94,13 +100,15 @@ fn filter_2_for_rgba_16() { opts.filter.insert(2); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGBA, - BitDepth::Sixteen, - ColorType::RGBA, - BitDepth::Sixteen); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGBA, + BitDepth::Sixteen, + ColorType::RGBA, + BitDepth::Sixteen, + ); } #[test] @@ -111,13 +119,15 @@ fn filter_3_for_rgba_16() { opts.filter.insert(3); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGBA, - BitDepth::Sixteen, - ColorType::RGBA, - BitDepth::Sixteen); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGBA, + BitDepth::Sixteen, + ColorType::RGBA, + BitDepth::Sixteen, + ); } #[test] @@ -128,13 +138,15 @@ fn filter_4_for_rgba_16() { opts.filter.insert(4); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGBA, - BitDepth::Sixteen, - ColorType::RGBA, - BitDepth::Sixteen); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGBA, + BitDepth::Sixteen, + ColorType::RGBA, + BitDepth::Sixteen, + ); } #[test] @@ -145,13 +157,15 @@ fn filter_5_for_rgba_16() { opts.filter.insert(5); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGBA, - BitDepth::Sixteen, - ColorType::RGBA, - BitDepth::Sixteen); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGBA, + BitDepth::Sixteen, + ColorType::RGBA, + BitDepth::Sixteen, + ); } #[test] @@ -162,13 +176,15 @@ fn filter_0_for_rgba_8() { opts.filter.insert(0); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGBA, - BitDepth::Eight, - ColorType::RGBA, - BitDepth::Eight); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGBA, + BitDepth::Eight, + ColorType::RGBA, + BitDepth::Eight, + ); } #[test] @@ -179,13 +195,15 @@ fn filter_1_for_rgba_8() { opts.filter.insert(1); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGBA, - BitDepth::Eight, - ColorType::RGBA, - BitDepth::Eight); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGBA, + BitDepth::Eight, + ColorType::RGBA, + BitDepth::Eight, + ); } #[test] @@ -196,13 +214,15 @@ fn filter_2_for_rgba_8() { opts.filter.insert(2); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGBA, - BitDepth::Eight, - ColorType::RGBA, - BitDepth::Eight); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGBA, + BitDepth::Eight, + ColorType::RGBA, + BitDepth::Eight, + ); } #[test] @@ -213,13 +233,15 @@ fn filter_3_for_rgba_8() { opts.filter.insert(3); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGBA, - BitDepth::Eight, - ColorType::RGBA, - BitDepth::Eight); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGBA, + BitDepth::Eight, + ColorType::RGBA, + BitDepth::Eight, + ); } #[test] @@ -230,13 +252,15 @@ fn filter_4_for_rgba_8() { opts.filter.insert(4); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGBA, - BitDepth::Eight, - ColorType::RGBA, - BitDepth::Eight); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGBA, + BitDepth::Eight, + ColorType::RGBA, + BitDepth::Eight, + ); } #[test] @@ -247,13 +271,15 @@ fn filter_5_for_rgba_8() { opts.filter.insert(5); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGBA, - BitDepth::Eight, - ColorType::RGBA, - BitDepth::Eight); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGBA, + BitDepth::Eight, + ColorType::RGBA, + BitDepth::Eight, + ); } #[test] @@ -264,13 +290,15 @@ fn filter_0_for_rgb_16() { opts.filter.insert(0); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGB, - BitDepth::Sixteen, - ColorType::RGB, - BitDepth::Sixteen); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGB, + BitDepth::Sixteen, + ColorType::RGB, + BitDepth::Sixteen, + ); } #[test] @@ -281,13 +309,15 @@ fn filter_1_for_rgb_16() { opts.filter.insert(1); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGB, - BitDepth::Sixteen, - ColorType::RGB, - BitDepth::Sixteen); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGB, + BitDepth::Sixteen, + ColorType::RGB, + BitDepth::Sixteen, + ); } #[test] @@ -298,13 +328,15 @@ fn filter_2_for_rgb_16() { opts.filter.insert(2); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGB, - BitDepth::Sixteen, - ColorType::RGB, - BitDepth::Sixteen); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGB, + BitDepth::Sixteen, + ColorType::RGB, + BitDepth::Sixteen, + ); } #[test] @@ -315,13 +347,15 @@ fn filter_3_for_rgb_16() { opts.filter.insert(3); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGB, - BitDepth::Sixteen, - ColorType::RGB, - BitDepth::Sixteen); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGB, + BitDepth::Sixteen, + ColorType::RGB, + BitDepth::Sixteen, + ); } #[test] @@ -332,13 +366,15 @@ fn filter_4_for_rgb_16() { opts.filter.insert(4); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGB, - BitDepth::Sixteen, - ColorType::RGB, - BitDepth::Sixteen); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGB, + BitDepth::Sixteen, + ColorType::RGB, + BitDepth::Sixteen, + ); } #[test] @@ -349,13 +385,15 @@ fn filter_5_for_rgb_16() { opts.filter.insert(5); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGB, - BitDepth::Sixteen, - ColorType::RGB, - BitDepth::Sixteen); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGB, + BitDepth::Sixteen, + ColorType::RGB, + BitDepth::Sixteen, + ); } #[test] @@ -366,13 +404,15 @@ fn filter_0_for_rgb_8() { opts.filter.insert(0); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGB, - BitDepth::Eight, - ColorType::RGB, - BitDepth::Eight); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGB, + BitDepth::Eight, + ColorType::RGB, + BitDepth::Eight, + ); } #[test] @@ -383,13 +423,15 @@ fn filter_1_for_rgb_8() { opts.filter.insert(1); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGB, - BitDepth::Eight, - ColorType::RGB, - BitDepth::Eight); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGB, + BitDepth::Eight, + ColorType::RGB, + BitDepth::Eight, + ); } #[test] @@ -400,13 +442,15 @@ fn filter_2_for_rgb_8() { opts.filter.insert(2); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGB, - BitDepth::Eight, - ColorType::RGB, - BitDepth::Eight); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGB, + BitDepth::Eight, + ColorType::RGB, + BitDepth::Eight, + ); } #[test] @@ -417,13 +461,15 @@ fn filter_3_for_rgb_8() { opts.filter.insert(3); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGB, - BitDepth::Eight, - ColorType::RGB, - BitDepth::Eight); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGB, + BitDepth::Eight, + ColorType::RGB, + BitDepth::Eight, + ); } #[test] @@ -434,13 +480,15 @@ fn filter_4_for_rgb_8() { opts.filter.insert(4); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGB, - BitDepth::Eight, - ColorType::RGB, - BitDepth::Eight); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGB, + BitDepth::Eight, + ColorType::RGB, + BitDepth::Eight, + ); } #[test] @@ -451,13 +499,15 @@ fn filter_5_for_rgb_8() { opts.filter.insert(5); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGB, - BitDepth::Eight, - ColorType::RGB, - BitDepth::Eight); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGB, + BitDepth::Eight, + ColorType::RGB, + BitDepth::Eight, + ); } #[test] @@ -468,13 +518,15 @@ fn filter_0_for_grayscale_alpha_16() { opts.filter.insert(0); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::GrayscaleAlpha, - BitDepth::Sixteen, - ColorType::GrayscaleAlpha, - BitDepth::Sixteen); + test_it_converts( + &input, + &output, + &opts, + ColorType::GrayscaleAlpha, + BitDepth::Sixteen, + ColorType::GrayscaleAlpha, + BitDepth::Sixteen, + ); } #[test] @@ -485,13 +537,15 @@ fn filter_1_for_grayscale_alpha_16() { opts.filter.insert(1); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::GrayscaleAlpha, - BitDepth::Sixteen, - ColorType::GrayscaleAlpha, - BitDepth::Sixteen); + test_it_converts( + &input, + &output, + &opts, + ColorType::GrayscaleAlpha, + BitDepth::Sixteen, + ColorType::GrayscaleAlpha, + BitDepth::Sixteen, + ); } #[test] @@ -502,13 +556,15 @@ fn filter_2_for_grayscale_alpha_16() { opts.filter.insert(2); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::GrayscaleAlpha, - BitDepth::Sixteen, - ColorType::GrayscaleAlpha, - BitDepth::Sixteen); + test_it_converts( + &input, + &output, + &opts, + ColorType::GrayscaleAlpha, + BitDepth::Sixteen, + ColorType::GrayscaleAlpha, + BitDepth::Sixteen, + ); } #[test] @@ -519,13 +575,15 @@ fn filter_3_for_grayscale_alpha_16() { opts.filter.insert(3); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::GrayscaleAlpha, - BitDepth::Sixteen, - ColorType::GrayscaleAlpha, - BitDepth::Sixteen); + test_it_converts( + &input, + &output, + &opts, + ColorType::GrayscaleAlpha, + BitDepth::Sixteen, + ColorType::GrayscaleAlpha, + BitDepth::Sixteen, + ); } #[test] @@ -536,13 +594,15 @@ fn filter_4_for_grayscale_alpha_16() { opts.filter.insert(4); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::GrayscaleAlpha, - BitDepth::Sixteen, - ColorType::GrayscaleAlpha, - BitDepth::Sixteen); + test_it_converts( + &input, + &output, + &opts, + ColorType::GrayscaleAlpha, + BitDepth::Sixteen, + ColorType::GrayscaleAlpha, + BitDepth::Sixteen, + ); } #[test] @@ -553,13 +613,15 @@ fn filter_5_for_grayscale_alpha_16() { opts.filter.insert(5); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::GrayscaleAlpha, - BitDepth::Sixteen, - ColorType::GrayscaleAlpha, - BitDepth::Sixteen); + test_it_converts( + &input, + &output, + &opts, + ColorType::GrayscaleAlpha, + BitDepth::Sixteen, + ColorType::GrayscaleAlpha, + BitDepth::Sixteen, + ); } #[test] @@ -570,13 +632,15 @@ fn filter_0_for_grayscale_alpha_8() { opts.filter.insert(0); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::GrayscaleAlpha, - BitDepth::Eight, - ColorType::GrayscaleAlpha, - BitDepth::Eight); + test_it_converts( + &input, + &output, + &opts, + ColorType::GrayscaleAlpha, + BitDepth::Eight, + ColorType::GrayscaleAlpha, + BitDepth::Eight, + ); } #[test] @@ -587,13 +651,15 @@ fn filter_1_for_grayscale_alpha_8() { opts.filter.insert(1); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::GrayscaleAlpha, - BitDepth::Eight, - ColorType::GrayscaleAlpha, - BitDepth::Eight); + test_it_converts( + &input, + &output, + &opts, + ColorType::GrayscaleAlpha, + BitDepth::Eight, + ColorType::GrayscaleAlpha, + BitDepth::Eight, + ); } #[test] @@ -604,13 +670,15 @@ fn filter_2_for_grayscale_alpha_8() { opts.filter.insert(2); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::GrayscaleAlpha, - BitDepth::Eight, - ColorType::GrayscaleAlpha, - BitDepth::Eight); + test_it_converts( + &input, + &output, + &opts, + ColorType::GrayscaleAlpha, + BitDepth::Eight, + ColorType::GrayscaleAlpha, + BitDepth::Eight, + ); } #[test] @@ -621,13 +689,15 @@ fn filter_3_for_grayscale_alpha_8() { opts.filter.insert(3); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::GrayscaleAlpha, - BitDepth::Eight, - ColorType::GrayscaleAlpha, - BitDepth::Eight); + test_it_converts( + &input, + &output, + &opts, + ColorType::GrayscaleAlpha, + BitDepth::Eight, + ColorType::GrayscaleAlpha, + BitDepth::Eight, + ); } #[test] @@ -638,13 +708,15 @@ fn filter_4_for_grayscale_alpha_8() { opts.filter.insert(4); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::GrayscaleAlpha, - BitDepth::Eight, - ColorType::GrayscaleAlpha, - BitDepth::Eight); + test_it_converts( + &input, + &output, + &opts, + ColorType::GrayscaleAlpha, + BitDepth::Eight, + ColorType::GrayscaleAlpha, + BitDepth::Eight, + ); } #[test] @@ -655,13 +727,15 @@ fn filter_5_for_grayscale_alpha_8() { opts.filter.insert(5); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::GrayscaleAlpha, - BitDepth::Eight, - ColorType::GrayscaleAlpha, - BitDepth::Eight); + test_it_converts( + &input, + &output, + &opts, + ColorType::GrayscaleAlpha, + BitDepth::Eight, + ColorType::GrayscaleAlpha, + BitDepth::Eight, + ); } #[test] @@ -672,13 +746,15 @@ fn filter_0_for_grayscale_16() { opts.filter.insert(0); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::Grayscale, - BitDepth::Sixteen, - ColorType::Grayscale, - BitDepth::Sixteen); + test_it_converts( + &input, + &output, + &opts, + ColorType::Grayscale, + BitDepth::Sixteen, + ColorType::Grayscale, + BitDepth::Sixteen, + ); } #[test] @@ -689,13 +765,15 @@ fn filter_1_for_grayscale_16() { opts.filter.insert(1); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::Grayscale, - BitDepth::Sixteen, - ColorType::Grayscale, - BitDepth::Sixteen); + test_it_converts( + &input, + &output, + &opts, + ColorType::Grayscale, + BitDepth::Sixteen, + ColorType::Grayscale, + BitDepth::Sixteen, + ); } #[test] @@ -706,13 +784,15 @@ fn filter_2_for_grayscale_16() { opts.filter.insert(2); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::Grayscale, - BitDepth::Sixteen, - ColorType::Grayscale, - BitDepth::Sixteen); + test_it_converts( + &input, + &output, + &opts, + ColorType::Grayscale, + BitDepth::Sixteen, + ColorType::Grayscale, + BitDepth::Sixteen, + ); } #[test] @@ -723,13 +803,15 @@ fn filter_3_for_grayscale_16() { opts.filter.insert(3); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::Grayscale, - BitDepth::Sixteen, - ColorType::Grayscale, - BitDepth::Sixteen); + test_it_converts( + &input, + &output, + &opts, + ColorType::Grayscale, + BitDepth::Sixteen, + ColorType::Grayscale, + BitDepth::Sixteen, + ); } #[test] @@ -740,13 +822,15 @@ fn filter_4_for_grayscale_16() { opts.filter.insert(4); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::Grayscale, - BitDepth::Sixteen, - ColorType::Grayscale, - BitDepth::Sixteen); + test_it_converts( + &input, + &output, + &opts, + ColorType::Grayscale, + BitDepth::Sixteen, + ColorType::Grayscale, + BitDepth::Sixteen, + ); } #[test] @@ -757,13 +841,15 @@ fn filter_5_for_grayscale_16() { opts.filter.insert(5); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::Grayscale, - BitDepth::Sixteen, - ColorType::Grayscale, - BitDepth::Sixteen); + test_it_converts( + &input, + &output, + &opts, + ColorType::Grayscale, + BitDepth::Sixteen, + ColorType::Grayscale, + BitDepth::Sixteen, + ); } #[test] @@ -774,13 +860,15 @@ fn filter_0_for_grayscale_8() { opts.filter.insert(0); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::Grayscale, - BitDepth::Eight, - ColorType::Grayscale, - BitDepth::Eight); + test_it_converts( + &input, + &output, + &opts, + ColorType::Grayscale, + BitDepth::Eight, + ColorType::Grayscale, + BitDepth::Eight, + ); } #[test] @@ -791,13 +879,15 @@ fn filter_1_for_grayscale_8() { opts.filter.insert(1); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::Grayscale, - BitDepth::Eight, - ColorType::Grayscale, - BitDepth::Eight); + test_it_converts( + &input, + &output, + &opts, + ColorType::Grayscale, + BitDepth::Eight, + ColorType::Grayscale, + BitDepth::Eight, + ); } #[test] @@ -808,13 +898,15 @@ fn filter_2_for_grayscale_8() { opts.filter.insert(2); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::Grayscale, - BitDepth::Eight, - ColorType::Grayscale, - BitDepth::Eight); + test_it_converts( + &input, + &output, + &opts, + ColorType::Grayscale, + BitDepth::Eight, + ColorType::Grayscale, + BitDepth::Eight, + ); } #[test] @@ -825,13 +917,15 @@ fn filter_3_for_grayscale_8() { opts.filter.insert(3); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::Grayscale, - BitDepth::Eight, - ColorType::Grayscale, - BitDepth::Eight); + test_it_converts( + &input, + &output, + &opts, + ColorType::Grayscale, + BitDepth::Eight, + ColorType::Grayscale, + BitDepth::Eight, + ); } #[test] @@ -842,13 +936,15 @@ fn filter_4_for_grayscale_8() { opts.filter.insert(4); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::Grayscale, - BitDepth::Eight, - ColorType::Grayscale, - BitDepth::Eight); + test_it_converts( + &input, + &output, + &opts, + ColorType::Grayscale, + BitDepth::Eight, + ColorType::Grayscale, + BitDepth::Eight, + ); } #[test] @@ -859,13 +955,15 @@ fn filter_5_for_grayscale_8() { opts.filter.insert(5); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::Grayscale, - BitDepth::Eight, - ColorType::Grayscale, - BitDepth::Eight); + test_it_converts( + &input, + &output, + &opts, + ColorType::Grayscale, + BitDepth::Eight, + ColorType::Grayscale, + BitDepth::Eight, + ); } #[test] @@ -876,13 +974,15 @@ fn filter_0_for_palette_4() { opts.filter.insert(0); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::Indexed, - BitDepth::Four, - ColorType::Indexed, - BitDepth::Four); + test_it_converts( + &input, + &output, + &opts, + ColorType::Indexed, + BitDepth::Four, + ColorType::Indexed, + BitDepth::Four, + ); } #[test] @@ -893,13 +993,15 @@ fn filter_1_for_palette_4() { opts.filter.insert(1); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::Indexed, - BitDepth::Four, - ColorType::Indexed, - BitDepth::Four); + test_it_converts( + &input, + &output, + &opts, + ColorType::Indexed, + BitDepth::Four, + ColorType::Indexed, + BitDepth::Four, + ); } #[test] @@ -910,13 +1012,15 @@ fn filter_2_for_palette_4() { opts.filter.insert(2); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::Indexed, - BitDepth::Four, - ColorType::Indexed, - BitDepth::Four); + test_it_converts( + &input, + &output, + &opts, + ColorType::Indexed, + BitDepth::Four, + ColorType::Indexed, + BitDepth::Four, + ); } #[test] @@ -927,13 +1031,15 @@ fn filter_3_for_palette_4() { opts.filter.insert(3); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::Indexed, - BitDepth::Four, - ColorType::Indexed, - BitDepth::Four); + test_it_converts( + &input, + &output, + &opts, + ColorType::Indexed, + BitDepth::Four, + ColorType::Indexed, + BitDepth::Four, + ); } #[test] @@ -944,13 +1050,15 @@ fn filter_4_for_palette_4() { opts.filter.insert(4); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::Indexed, - BitDepth::Four, - ColorType::Indexed, - BitDepth::Four); + test_it_converts( + &input, + &output, + &opts, + ColorType::Indexed, + BitDepth::Four, + ColorType::Indexed, + BitDepth::Four, + ); } #[test] @@ -961,13 +1069,15 @@ fn filter_5_for_palette_4() { opts.filter.insert(5); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::Indexed, - BitDepth::Four, - ColorType::Indexed, - BitDepth::Four); + test_it_converts( + &input, + &output, + &opts, + ColorType::Indexed, + BitDepth::Four, + ColorType::Indexed, + BitDepth::Four, + ); } #[test] @@ -978,13 +1088,15 @@ fn filter_0_for_palette_2() { opts.filter.insert(0); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::Indexed, - BitDepth::Two, - ColorType::Indexed, - BitDepth::Two); + test_it_converts( + &input, + &output, + &opts, + ColorType::Indexed, + BitDepth::Two, + ColorType::Indexed, + BitDepth::Two, + ); } #[test] @@ -995,13 +1107,15 @@ fn filter_1_for_palette_2() { opts.filter.insert(1); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::Indexed, - BitDepth::Two, - ColorType::Indexed, - BitDepth::Two); + test_it_converts( + &input, + &output, + &opts, + ColorType::Indexed, + BitDepth::Two, + ColorType::Indexed, + BitDepth::Two, + ); } #[test] @@ -1012,13 +1126,15 @@ fn filter_2_for_palette_2() { opts.filter.insert(2); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::Indexed, - BitDepth::Two, - ColorType::Indexed, - BitDepth::Two); + test_it_converts( + &input, + &output, + &opts, + ColorType::Indexed, + BitDepth::Two, + ColorType::Indexed, + BitDepth::Two, + ); } #[test] @@ -1029,13 +1145,15 @@ fn filter_3_for_palette_2() { opts.filter.insert(3); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::Indexed, - BitDepth::Two, - ColorType::Indexed, - BitDepth::Two); + test_it_converts( + &input, + &output, + &opts, + ColorType::Indexed, + BitDepth::Two, + ColorType::Indexed, + BitDepth::Two, + ); } #[test] @@ -1046,13 +1164,15 @@ fn filter_4_for_palette_2() { opts.filter.insert(4); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::Indexed, - BitDepth::Two, - ColorType::Indexed, - BitDepth::Two); + test_it_converts( + &input, + &output, + &opts, + ColorType::Indexed, + BitDepth::Two, + ColorType::Indexed, + BitDepth::Two, + ); } #[test] @@ -1063,13 +1183,15 @@ fn filter_5_for_palette_2() { opts.filter.insert(5); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::Indexed, - BitDepth::Two, - ColorType::Indexed, - BitDepth::Two); + test_it_converts( + &input, + &output, + &opts, + ColorType::Indexed, + BitDepth::Two, + ColorType::Indexed, + BitDepth::Two, + ); } #[test] @@ -1080,13 +1202,15 @@ fn filter_0_for_palette_1() { opts.filter.insert(0); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::Indexed, - BitDepth::One, - ColorType::Indexed, - BitDepth::One); + test_it_converts( + &input, + &output, + &opts, + ColorType::Indexed, + BitDepth::One, + ColorType::Indexed, + BitDepth::One, + ); } #[test] @@ -1097,13 +1221,15 @@ fn filter_1_for_palette_1() { opts.filter.insert(1); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::Indexed, - BitDepth::One, - ColorType::Indexed, - BitDepth::One); + test_it_converts( + &input, + &output, + &opts, + ColorType::Indexed, + BitDepth::One, + ColorType::Indexed, + BitDepth::One, + ); } #[test] @@ -1114,13 +1240,15 @@ fn filter_2_for_palette_1() { opts.filter.insert(2); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::Indexed, - BitDepth::One, - ColorType::Indexed, - BitDepth::One); + test_it_converts( + &input, + &output, + &opts, + ColorType::Indexed, + BitDepth::One, + ColorType::Indexed, + BitDepth::One, + ); } #[test] @@ -1131,13 +1259,15 @@ fn filter_3_for_palette_1() { opts.filter.insert(3); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::Indexed, - BitDepth::One, - ColorType::Indexed, - BitDepth::One); + test_it_converts( + &input, + &output, + &opts, + ColorType::Indexed, + BitDepth::One, + ColorType::Indexed, + BitDepth::One, + ); } #[test] @@ -1148,13 +1278,15 @@ fn filter_4_for_palette_1() { opts.filter.insert(4); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::Indexed, - BitDepth::One, - ColorType::Indexed, - BitDepth::One); + test_it_converts( + &input, + &output, + &opts, + ColorType::Indexed, + BitDepth::One, + ColorType::Indexed, + BitDepth::One, + ); } #[test] @@ -1165,11 +1297,13 @@ fn filter_5_for_palette_1() { opts.filter.insert(5); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::Indexed, - BitDepth::One, - ColorType::Indexed, - BitDepth::One); + test_it_converts( + &input, + &output, + &opts, + ColorType::Indexed, + BitDepth::One, + ColorType::Indexed, + BitDepth::One, + ); } diff --git a/tests/flags.rs b/tests/flags.rs index 61a82299..eb6d2e60 100644 --- a/tests/flags.rs +++ b/tests/flags.rs @@ -22,13 +22,15 @@ fn get_opts(input: &Path) -> oxipng::Options { options } -fn test_it_converts(input: &Path, - output: &Path, - opts: &oxipng::Options, - color_type_in: ColorType, - bit_depth_in: BitDepth, - color_type_out: ColorType, - bit_depth_out: BitDepth) { +fn test_it_converts( + input: &Path, + output: &Path, + opts: &oxipng::Options, + color_type_in: ColorType, + bit_depth_in: BitDepth, + color_type_out: ColorType, + bit_depth_out: BitDepth, +) { let png = png::PngData::new(input, opts.fix_errors).unwrap(); assert_eq!(png.ihdr_data.color_type, color_type_in); @@ -61,13 +63,15 @@ fn verbose_mode() { opts.verbosity = Some(1); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGB, - BitDepth::Eight, - ColorType::RGB, - BitDepth::Eight); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGB, + BitDepth::Eight, + ColorType::RGB, + BitDepth::Eight, + ); } #[test] @@ -374,13 +378,15 @@ fn preserve_attrs() { opts.preserve_attrs = true; let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGB, - BitDepth::Eight, - ColorType::RGB, - BitDepth::Eight); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGB, + BitDepth::Eight, + ColorType::RGB, + BitDepth::Eight, + ); // TODO: Actually check permissions } @@ -425,11 +431,13 @@ fn zopfli_mode() { opts.deflate = Deflaters::Zopfli; let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGB, - BitDepth::Eight, - ColorType::RGB, - BitDepth::Eight); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGB, + BitDepth::Eight, + ColorType::RGB, + BitDepth::Eight, + ); } diff --git a/tests/interlaced.rs b/tests/interlaced.rs index 3ff6744a..a63814c0 100644 --- a/tests/interlaced.rs +++ b/tests/interlaced.rs @@ -20,13 +20,15 @@ fn get_opts(input: &Path) -> oxipng::Options { options } -fn test_it_converts(input: &Path, - output: &Path, - opts: &oxipng::Options, - color_type_in: ColorType, - bit_depth_in: BitDepth, - color_type_out: ColorType, - bit_depth_out: BitDepth) { +fn test_it_converts( + input: &Path, + output: &Path, + opts: &oxipng::Options, + color_type_in: ColorType, + bit_depth_in: BitDepth, + color_type_out: ColorType, + bit_depth_out: BitDepth, +) { let png = png::PngData::new(input, opts.fix_errors).unwrap(); assert_eq!(png.ihdr_data.color_type, color_type_in); @@ -60,13 +62,15 @@ fn interlaced_rgba_16_should_be_rgba_16() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGBA, - BitDepth::Sixteen, - ColorType::RGBA, - BitDepth::Sixteen); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGBA, + BitDepth::Sixteen, + ColorType::RGBA, + BitDepth::Sixteen, + ); } #[test] @@ -75,13 +79,15 @@ fn interlaced_rgba_16_should_be_rgba_8() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGBA, - BitDepth::Sixteen, - ColorType::RGBA, - BitDepth::Eight); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGBA, + BitDepth::Sixteen, + ColorType::RGBA, + BitDepth::Eight, + ); } #[test] @@ -90,13 +96,15 @@ fn interlaced_rgba_8_should_be_rgba_8() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGBA, - BitDepth::Eight, - ColorType::RGBA, - BitDepth::Eight); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGBA, + BitDepth::Eight, + ColorType::RGBA, + BitDepth::Eight, + ); } #[test] @@ -105,13 +113,15 @@ fn interlaced_rgba_16_should_be_rgb_16() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGBA, - BitDepth::Sixteen, - ColorType::RGB, - BitDepth::Sixteen); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGBA, + BitDepth::Sixteen, + ColorType::RGB, + BitDepth::Sixteen, + ); } #[test] @@ -120,13 +130,15 @@ fn interlaced_rgba_16_should_be_rgb_8() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGBA, - BitDepth::Sixteen, - ColorType::RGB, - BitDepth::Eight); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGBA, + BitDepth::Sixteen, + ColorType::RGB, + BitDepth::Eight, + ); } #[test] @@ -135,13 +147,15 @@ fn interlaced_rgba_8_should_be_rgb_8() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGBA, - BitDepth::Eight, - ColorType::RGB, - BitDepth::Eight); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGBA, + BitDepth::Eight, + ColorType::RGB, + BitDepth::Eight, + ); } #[test] @@ -150,13 +164,15 @@ fn interlaced_rgba_16_should_be_palette_8() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGBA, - BitDepth::Sixteen, - ColorType::Indexed, - BitDepth::Eight); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGBA, + BitDepth::Sixteen, + ColorType::Indexed, + BitDepth::Eight, + ); } #[test] @@ -165,13 +181,15 @@ fn interlaced_rgba_8_should_be_palette_8() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGBA, - BitDepth::Eight, - ColorType::Indexed, - BitDepth::Eight); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGBA, + BitDepth::Eight, + ColorType::Indexed, + BitDepth::Eight, + ); } #[test] @@ -180,13 +198,15 @@ fn interlaced_rgba_16_should_be_palette_4() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGBA, - BitDepth::Sixteen, - ColorType::Indexed, - BitDepth::Four); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGBA, + BitDepth::Sixteen, + ColorType::Indexed, + BitDepth::Four, + ); } #[test] @@ -195,13 +215,15 @@ fn interlaced_rgba_8_should_be_palette_4() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGBA, - BitDepth::Eight, - ColorType::Indexed, - BitDepth::Four); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGBA, + BitDepth::Eight, + ColorType::Indexed, + BitDepth::Four, + ); } #[test] @@ -210,13 +232,15 @@ fn interlaced_rgba_16_should_be_palette_2() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGBA, - BitDepth::Sixteen, - ColorType::Indexed, - BitDepth::Two); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGBA, + BitDepth::Sixteen, + ColorType::Indexed, + BitDepth::Two, + ); } #[test] @@ -225,13 +249,15 @@ fn interlaced_rgba_8_should_be_palette_2() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGBA, - BitDepth::Eight, - ColorType::Indexed, - BitDepth::Two); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGBA, + BitDepth::Eight, + ColorType::Indexed, + BitDepth::Two, + ); } #[test] @@ -240,13 +266,15 @@ fn interlaced_rgba_16_should_be_palette_1() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGBA, - BitDepth::Sixteen, - ColorType::Indexed, - BitDepth::One); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGBA, + BitDepth::Sixteen, + ColorType::Indexed, + BitDepth::One, + ); } #[test] @@ -255,58 +283,72 @@ fn interlaced_rgba_8_should_be_palette_1() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGBA, - BitDepth::Eight, - ColorType::Indexed, - BitDepth::One); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGBA, + BitDepth::Eight, + ColorType::Indexed, + BitDepth::One, + ); } #[test] fn interlaced_rgba_16_should_be_grayscale_alpha_16() { - let input = PathBuf::from("tests/files/interlaced_rgba_16_should_be_grayscale_alpha_16.png"); + let input = PathBuf::from( + "tests/files/interlaced_rgba_16_should_be_grayscale_alpha_16.png", + ); let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGBA, - BitDepth::Sixteen, - ColorType::GrayscaleAlpha, - BitDepth::Sixteen); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGBA, + BitDepth::Sixteen, + ColorType::GrayscaleAlpha, + BitDepth::Sixteen, + ); } #[test] fn interlaced_rgba_16_should_be_grayscale_alpha_8() { - let input = PathBuf::from("tests/files/interlaced_rgba_16_should_be_grayscale_alpha_8.png"); + let input = PathBuf::from( + "tests/files/interlaced_rgba_16_should_be_grayscale_alpha_8.png", + ); let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGBA, - BitDepth::Sixteen, - ColorType::GrayscaleAlpha, - BitDepth::Eight); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGBA, + BitDepth::Sixteen, + ColorType::GrayscaleAlpha, + BitDepth::Eight, + ); } #[test] fn interlaced_rgba_8_should_be_grayscale_alpha_8() { - let input = PathBuf::from("tests/files/interlaced_rgba_8_should_be_grayscale_alpha_8.png"); + let input = PathBuf::from( + "tests/files/interlaced_rgba_8_should_be_grayscale_alpha_8.png", + ); let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGBA, - BitDepth::Eight, - ColorType::GrayscaleAlpha, - BitDepth::Eight); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGBA, + BitDepth::Eight, + ColorType::GrayscaleAlpha, + BitDepth::Eight, + ); } #[test] @@ -315,13 +357,15 @@ fn interlaced_rgba_16_should_be_grayscale_16() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGBA, - BitDepth::Sixteen, - ColorType::Grayscale, - BitDepth::Sixteen); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGBA, + BitDepth::Sixteen, + ColorType::Grayscale, + BitDepth::Sixteen, + ); } #[test] @@ -330,13 +374,15 @@ fn interlaced_rgba_16_should_be_grayscale_8() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGBA, - BitDepth::Sixteen, - ColorType::Grayscale, - BitDepth::Eight); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGBA, + BitDepth::Sixteen, + ColorType::Grayscale, + BitDepth::Eight, + ); } #[test] @@ -345,13 +391,15 @@ fn interlaced_rgba_8_should_be_grayscale_8() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGBA, - BitDepth::Eight, - ColorType::Grayscale, - BitDepth::Eight); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGBA, + BitDepth::Eight, + ColorType::Grayscale, + BitDepth::Eight, + ); } #[test] @@ -360,13 +408,15 @@ fn interlaced_rgb_16_should_be_rgb_16() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGB, - BitDepth::Sixteen, - ColorType::RGB, - BitDepth::Sixteen); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGB, + BitDepth::Sixteen, + ColorType::RGB, + BitDepth::Sixteen, + ); } #[test] @@ -375,13 +425,15 @@ fn interlaced_rgb_16_should_be_rgb_8() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGB, - BitDepth::Sixteen, - ColorType::RGB, - BitDepth::Eight); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGB, + BitDepth::Sixteen, + ColorType::RGB, + BitDepth::Eight, + ); } #[test] @@ -390,13 +442,15 @@ fn interlaced_rgb_8_should_be_rgb_8() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGB, - BitDepth::Eight, - ColorType::RGB, - BitDepth::Eight); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGB, + BitDepth::Eight, + ColorType::RGB, + BitDepth::Eight, + ); } #[test] @@ -405,13 +459,15 @@ fn interlaced_rgb_16_should_be_palette_8() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGB, - BitDepth::Sixteen, - ColorType::Indexed, - BitDepth::Eight); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGB, + BitDepth::Sixteen, + ColorType::Indexed, + BitDepth::Eight, + ); } #[test] @@ -420,13 +476,15 @@ fn interlaced_rgb_8_should_be_palette_8() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGB, - BitDepth::Eight, - ColorType::Indexed, - BitDepth::Eight); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGB, + BitDepth::Eight, + ColorType::Indexed, + BitDepth::Eight, + ); } #[test] @@ -435,13 +493,15 @@ fn interlaced_rgb_16_should_be_palette_4() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGB, - BitDepth::Sixteen, - ColorType::Indexed, - BitDepth::Four); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGB, + BitDepth::Sixteen, + ColorType::Indexed, + BitDepth::Four, + ); } #[test] @@ -450,13 +510,15 @@ fn interlaced_rgb_8_should_be_palette_4() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGB, - BitDepth::Eight, - ColorType::Indexed, - BitDepth::Four); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGB, + BitDepth::Eight, + ColorType::Indexed, + BitDepth::Four, + ); } #[test] @@ -465,13 +527,15 @@ fn interlaced_rgb_16_should_be_palette_2() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGB, - BitDepth::Sixteen, - ColorType::Indexed, - BitDepth::Two); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGB, + BitDepth::Sixteen, + ColorType::Indexed, + BitDepth::Two, + ); } #[test] @@ -480,13 +544,15 @@ fn interlaced_rgb_8_should_be_palette_2() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGB, - BitDepth::Eight, - ColorType::Indexed, - BitDepth::Two); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGB, + BitDepth::Eight, + ColorType::Indexed, + BitDepth::Two, + ); } #[test] @@ -495,13 +561,15 @@ fn interlaced_rgb_16_should_be_palette_1() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGB, - BitDepth::Sixteen, - ColorType::Indexed, - BitDepth::One); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGB, + BitDepth::Sixteen, + ColorType::Indexed, + BitDepth::One, + ); } #[test] @@ -510,13 +578,15 @@ fn interlaced_rgb_8_should_be_palette_1() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGB, - BitDepth::Eight, - ColorType::Indexed, - BitDepth::One); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGB, + BitDepth::Eight, + ColorType::Indexed, + BitDepth::One, + ); } #[test] @@ -525,13 +595,15 @@ fn interlaced_rgb_16_should_be_grayscale_16() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGB, - BitDepth::Sixteen, - ColorType::Grayscale, - BitDepth::Sixteen); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGB, + BitDepth::Sixteen, + ColorType::Grayscale, + BitDepth::Sixteen, + ); } #[test] @@ -540,13 +612,15 @@ fn interlaced_rgb_16_should_be_grayscale_8() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGB, - BitDepth::Sixteen, - ColorType::Grayscale, - BitDepth::Eight); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGB, + BitDepth::Sixteen, + ColorType::Grayscale, + BitDepth::Eight, + ); } #[test] @@ -555,13 +629,15 @@ fn interlaced_rgb_8_should_be_grayscale_8() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGB, - BitDepth::Eight, - ColorType::Grayscale, - BitDepth::Eight); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGB, + BitDepth::Eight, + ColorType::Grayscale, + BitDepth::Eight, + ); } #[test] @@ -570,13 +646,15 @@ fn interlaced_palette_8_should_be_palette_8() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::Indexed, - BitDepth::Eight, - ColorType::Indexed, - BitDepth::Eight); + test_it_converts( + &input, + &output, + &opts, + ColorType::Indexed, + BitDepth::Eight, + ColorType::Indexed, + BitDepth::Eight, + ); } #[test] @@ -585,13 +663,15 @@ fn interlaced_palette_8_should_be_palette_4() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::Indexed, - BitDepth::Eight, - ColorType::Indexed, - BitDepth::Four); + test_it_converts( + &input, + &output, + &opts, + ColorType::Indexed, + BitDepth::Eight, + ColorType::Indexed, + BitDepth::Four, + ); } #[test] @@ -600,13 +680,15 @@ fn interlaced_palette_4_should_be_palette_4() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::Indexed, - BitDepth::Four, - ColorType::Indexed, - BitDepth::Four); + test_it_converts( + &input, + &output, + &opts, + ColorType::Indexed, + BitDepth::Four, + ColorType::Indexed, + BitDepth::Four, + ); } #[test] @@ -615,13 +697,15 @@ fn interlaced_palette_8_should_be_palette_2() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::Indexed, - BitDepth::Eight, - ColorType::Indexed, - BitDepth::Two); + test_it_converts( + &input, + &output, + &opts, + ColorType::Indexed, + BitDepth::Eight, + ColorType::Indexed, + BitDepth::Two, + ); } #[test] @@ -630,13 +714,15 @@ fn interlaced_palette_4_should_be_palette_2() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::Indexed, - BitDepth::Four, - ColorType::Indexed, - BitDepth::Two); + test_it_converts( + &input, + &output, + &opts, + ColorType::Indexed, + BitDepth::Four, + ColorType::Indexed, + BitDepth::Two, + ); } #[test] @@ -645,13 +731,15 @@ fn interlaced_palette_2_should_be_palette_2() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::Indexed, - BitDepth::Two, - ColorType::Indexed, - BitDepth::Two); + test_it_converts( + &input, + &output, + &opts, + ColorType::Indexed, + BitDepth::Two, + ColorType::Indexed, + BitDepth::Two, + ); } #[test] @@ -660,13 +748,15 @@ fn interlaced_palette_8_should_be_palette_1() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::Indexed, - BitDepth::Eight, - ColorType::Indexed, - BitDepth::One); + test_it_converts( + &input, + &output, + &opts, + ColorType::Indexed, + BitDepth::Eight, + ColorType::Indexed, + BitDepth::One, + ); } #[test] @@ -675,13 +765,15 @@ fn interlaced_palette_4_should_be_palette_1() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::Indexed, - BitDepth::Four, - ColorType::Indexed, - BitDepth::One); + test_it_converts( + &input, + &output, + &opts, + ColorType::Indexed, + BitDepth::Four, + ColorType::Indexed, + BitDepth::One, + ); } #[test] @@ -690,13 +782,15 @@ fn interlaced_palette_2_should_be_palette_1() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::Indexed, - BitDepth::Two, - ColorType::Indexed, - BitDepth::One); + test_it_converts( + &input, + &output, + &opts, + ColorType::Indexed, + BitDepth::Two, + ColorType::Indexed, + BitDepth::One, + ); } #[test] @@ -705,148 +799,186 @@ fn interlaced_palette_1_should_be_palette_1() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::Indexed, - BitDepth::One, - ColorType::Indexed, - BitDepth::One); + test_it_converts( + &input, + &output, + &opts, + ColorType::Indexed, + BitDepth::One, + ColorType::Indexed, + BitDepth::One, + ); } #[test] fn interlaced_grayscale_alpha_16_should_be_grayscale_alpha_16() { - let input = PathBuf::from("tests/files/interlaced_grayscale_alpha_16_should_be_grayscale_alpha_16.png"); + let input = PathBuf::from( + "tests/files/interlaced_grayscale_alpha_16_should_be_grayscale_alpha_16.png", + ); let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::GrayscaleAlpha, - BitDepth::Sixteen, - ColorType::GrayscaleAlpha, - BitDepth::Sixteen); + test_it_converts( + &input, + &output, + &opts, + ColorType::GrayscaleAlpha, + BitDepth::Sixteen, + ColorType::GrayscaleAlpha, + BitDepth::Sixteen, + ); } #[test] fn interlaced_grayscale_alpha_16_should_be_grayscale_alpha_8() { - let input = PathBuf::from("tests/files/interlaced_grayscale_alpha_16_should_be_grayscale_alpha_8.png"); + let input = PathBuf::from( + "tests/files/interlaced_grayscale_alpha_16_should_be_grayscale_alpha_8.png", + ); let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::GrayscaleAlpha, - BitDepth::Sixteen, - ColorType::GrayscaleAlpha, - BitDepth::Eight); + test_it_converts( + &input, + &output, + &opts, + ColorType::GrayscaleAlpha, + BitDepth::Sixteen, + ColorType::GrayscaleAlpha, + BitDepth::Eight, + ); } #[test] fn interlaced_grayscale_alpha_8_should_be_grayscale_alpha_8() { - let input = PathBuf::from("tests/files/interlaced_grayscale_alpha_8_should_be_grayscale_alpha_8.png"); + let input = PathBuf::from( + "tests/files/interlaced_grayscale_alpha_8_should_be_grayscale_alpha_8.png", + ); let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::GrayscaleAlpha, - BitDepth::Eight, - ColorType::GrayscaleAlpha, - BitDepth::Eight); + test_it_converts( + &input, + &output, + &opts, + ColorType::GrayscaleAlpha, + BitDepth::Eight, + ColorType::GrayscaleAlpha, + BitDepth::Eight, + ); } #[test] fn interlaced_grayscale_alpha_16_should_be_grayscale_16() { - let input = PathBuf::from("tests/files/interlaced_grayscale_alpha_16_should_be_grayscale_16.png"); + let input = PathBuf::from( + "tests/files/interlaced_grayscale_alpha_16_should_be_grayscale_16.png", + ); let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::GrayscaleAlpha, - BitDepth::Sixteen, - ColorType::Grayscale, - BitDepth::Sixteen); + test_it_converts( + &input, + &output, + &opts, + ColorType::GrayscaleAlpha, + BitDepth::Sixteen, + ColorType::Grayscale, + BitDepth::Sixteen, + ); } #[test] fn interlaced_grayscale_alpha_16_should_be_grayscale_8() { - let input = PathBuf::from("tests/files/interlaced_grayscale_alpha_16_should_be_grayscale_8.png"); + let input = PathBuf::from( + "tests/files/interlaced_grayscale_alpha_16_should_be_grayscale_8.png", + ); let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::GrayscaleAlpha, - BitDepth::Sixteen, - ColorType::Grayscale, - BitDepth::Eight); + test_it_converts( + &input, + &output, + &opts, + ColorType::GrayscaleAlpha, + BitDepth::Sixteen, + ColorType::Grayscale, + BitDepth::Eight, + ); } #[test] fn interlaced_grayscale_alpha_8_should_be_grayscale_8() { - let input = PathBuf::from("tests/files/interlaced_grayscale_alpha_8_should_be_grayscale_8.png"); + let input = PathBuf::from( + "tests/files/interlaced_grayscale_alpha_8_should_be_grayscale_8.png", + ); let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::GrayscaleAlpha, - BitDepth::Eight, - ColorType::Grayscale, - BitDepth::Eight); + test_it_converts( + &input, + &output, + &opts, + ColorType::GrayscaleAlpha, + BitDepth::Eight, + ColorType::Grayscale, + BitDepth::Eight, + ); } #[test] fn interlaced_grayscale_16_should_be_grayscale_16() { - let input = PathBuf::from("tests/files/interlaced_grayscale_16_should_be_grayscale_16.png"); + let input = PathBuf::from( + "tests/files/interlaced_grayscale_16_should_be_grayscale_16.png", + ); let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::Grayscale, - BitDepth::Sixteen, - ColorType::Grayscale, - BitDepth::Sixteen); + test_it_converts( + &input, + &output, + &opts, + ColorType::Grayscale, + BitDepth::Sixteen, + ColorType::Grayscale, + BitDepth::Sixteen, + ); } #[test] fn interlaced_grayscale_16_should_be_grayscale_8() { - let input = PathBuf::from("tests/files/interlaced_grayscale_16_should_be_grayscale_8.png"); + let input = PathBuf::from( + "tests/files/interlaced_grayscale_16_should_be_grayscale_8.png", + ); let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::Grayscale, - BitDepth::Sixteen, - ColorType::Grayscale, - BitDepth::Eight); + test_it_converts( + &input, + &output, + &opts, + ColorType::Grayscale, + BitDepth::Sixteen, + ColorType::Grayscale, + BitDepth::Eight, + ); } #[test] fn interlaced_grayscale_8_should_be_grayscale_8() { - let input = PathBuf::from("tests/files/interlaced_grayscale_8_should_be_grayscale_8.png"); + let input = PathBuf::from( + "tests/files/interlaced_grayscale_8_should_be_grayscale_8.png", + ); let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::Grayscale, - BitDepth::Eight, - ColorType::Grayscale, - BitDepth::Eight); + test_it_converts( + &input, + &output, + &opts, + ColorType::Grayscale, + BitDepth::Eight, + ColorType::Grayscale, + BitDepth::Eight, + ); } #[test] @@ -855,13 +987,15 @@ fn interlaced_small_files() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::Indexed, - BitDepth::Eight, - ColorType::Indexed, - BitDepth::One); + test_it_converts( + &input, + &output, + &opts, + ColorType::Indexed, + BitDepth::Eight, + ColorType::Indexed, + BitDepth::One, + ); } #[test] @@ -870,11 +1004,13 @@ fn interlaced_odd_width() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGB, - BitDepth::Eight, - ColorType::RGB, - BitDepth::Eight); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGB, + BitDepth::Eight, + ColorType::RGB, + BitDepth::Eight, + ); } diff --git a/tests/reduction.rs b/tests/reduction.rs index 4e85411c..1cab344b 100644 --- a/tests/reduction.rs +++ b/tests/reduction.rs @@ -1,6 +1,6 @@ extern crate oxipng; -use oxipng::colors::{BitDepth, ColorType}; +use oxipng::colors::{BitDepth, ColorType, AlphaOptim}; use oxipng::png; use std::collections::HashSet; use std::error::Error; @@ -20,13 +20,15 @@ fn get_opts(input: &Path) -> oxipng::Options { options } -fn test_it_converts(input: &Path, - output: &Path, - opts: &oxipng::Options, - color_type_in: ColorType, - bit_depth_in: BitDepth, - color_type_out: ColorType, - bit_depth_out: BitDepth) { +fn test_it_converts( + input: &Path, + output: &Path, + opts: &oxipng::Options, + color_type_in: ColorType, + bit_depth_in: BitDepth, + color_type_out: ColorType, + bit_depth_out: BitDepth, +) { let png = png::PngData::new(input, opts.fix_errors).unwrap(); assert_eq!(png.ihdr_data.color_type, color_type_in); @@ -60,13 +62,15 @@ fn rgba_16_should_be_rgba_16() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGBA, - BitDepth::Sixteen, - ColorType::RGBA, - BitDepth::Sixteen); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGBA, + BitDepth::Sixteen, + ColorType::RGBA, + BitDepth::Sixteen, + ); } #[test] @@ -75,13 +79,15 @@ fn rgba_16_should_be_rgba_8() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGBA, - BitDepth::Sixteen, - ColorType::RGBA, - BitDepth::Eight); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGBA, + BitDepth::Sixteen, + ColorType::RGBA, + BitDepth::Eight, + ); } #[test] @@ -90,13 +96,15 @@ fn rgba_8_should_be_rgba_8() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGBA, - BitDepth::Eight, - ColorType::RGBA, - BitDepth::Eight); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGBA, + BitDepth::Eight, + ColorType::RGBA, + BitDepth::Eight, + ); } #[test] @@ -105,13 +113,15 @@ fn rgba_16_should_be_rgb_16() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGBA, - BitDepth::Sixteen, - ColorType::RGB, - BitDepth::Sixteen); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGBA, + BitDepth::Sixteen, + ColorType::RGB, + BitDepth::Sixteen, + ); } #[test] @@ -120,13 +130,15 @@ fn rgba_16_should_be_rgb_8() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGBA, - BitDepth::Sixteen, - ColorType::RGB, - BitDepth::Eight); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGBA, + BitDepth::Sixteen, + ColorType::RGB, + BitDepth::Eight, + ); } #[test] @@ -135,13 +147,15 @@ fn rgba_8_should_be_rgb_8() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGBA, - BitDepth::Eight, - ColorType::RGB, - BitDepth::Eight); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGBA, + BitDepth::Eight, + ColorType::RGB, + BitDepth::Eight, + ); } #[test] @@ -150,13 +164,15 @@ fn rgba_16_should_be_palette_8() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGBA, - BitDepth::Sixteen, - ColorType::Indexed, - BitDepth::Eight); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGBA, + BitDepth::Sixteen, + ColorType::Indexed, + BitDepth::Eight, + ); } #[test] @@ -165,13 +181,15 @@ fn rgba_8_should_be_palette_8() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGBA, - BitDepth::Eight, - ColorType::Indexed, - BitDepth::Eight); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGBA, + BitDepth::Eight, + ColorType::Indexed, + BitDepth::Eight, + ); } #[test] @@ -180,13 +198,15 @@ fn rgba_16_should_be_palette_4() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGBA, - BitDepth::Sixteen, - ColorType::Indexed, - BitDepth::Four); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGBA, + BitDepth::Sixteen, + ColorType::Indexed, + BitDepth::Four, + ); } #[test] @@ -195,13 +215,15 @@ fn rgba_8_should_be_palette_4() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGBA, - BitDepth::Eight, - ColorType::Indexed, - BitDepth::Four); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGBA, + BitDepth::Eight, + ColorType::Indexed, + BitDepth::Four, + ); } #[test] @@ -210,13 +232,15 @@ fn rgba_16_should_be_palette_2() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGBA, - BitDepth::Sixteen, - ColorType::Indexed, - BitDepth::Two); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGBA, + BitDepth::Sixteen, + ColorType::Indexed, + BitDepth::Two, + ); } #[test] @@ -225,13 +249,15 @@ fn rgba_8_should_be_palette_2() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGBA, - BitDepth::Eight, - ColorType::Indexed, - BitDepth::Two); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGBA, + BitDepth::Eight, + ColorType::Indexed, + BitDepth::Two, + ); } #[test] @@ -240,13 +266,15 @@ fn rgba_16_should_be_palette_1() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGBA, - BitDepth::Sixteen, - ColorType::Indexed, - BitDepth::One); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGBA, + BitDepth::Sixteen, + ColorType::Indexed, + BitDepth::One, + ); } #[test] @@ -255,13 +283,15 @@ fn rgba_8_should_be_palette_1() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGBA, - BitDepth::Eight, - ColorType::Indexed, - BitDepth::One); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGBA, + BitDepth::Eight, + ColorType::Indexed, + BitDepth::One, + ); } #[test] @@ -270,13 +300,15 @@ fn rgba_16_should_be_grayscale_alpha_16() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGBA, - BitDepth::Sixteen, - ColorType::GrayscaleAlpha, - BitDepth::Sixteen); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGBA, + BitDepth::Sixteen, + ColorType::GrayscaleAlpha, + BitDepth::Sixteen, + ); } #[test] @@ -285,13 +317,15 @@ fn rgba_16_should_be_grayscale_alpha_8() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGBA, - BitDepth::Sixteen, - ColorType::GrayscaleAlpha, - BitDepth::Eight); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGBA, + BitDepth::Sixteen, + ColorType::GrayscaleAlpha, + BitDepth::Eight, + ); } #[test] @@ -300,13 +334,15 @@ fn rgba_8_should_be_grayscale_alpha_8() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGBA, - BitDepth::Eight, - ColorType::GrayscaleAlpha, - BitDepth::Eight); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGBA, + BitDepth::Eight, + ColorType::GrayscaleAlpha, + BitDepth::Eight, + ); } #[test] @@ -315,13 +351,15 @@ fn rgba_16_should_be_grayscale_16() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGBA, - BitDepth::Sixteen, - ColorType::Grayscale, - BitDepth::Sixteen); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGBA, + BitDepth::Sixteen, + ColorType::Grayscale, + BitDepth::Sixteen, + ); } #[test] @@ -330,13 +368,15 @@ fn rgba_16_should_be_grayscale_8() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGBA, - BitDepth::Sixteen, - ColorType::Grayscale, - BitDepth::Eight); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGBA, + BitDepth::Sixteen, + ColorType::Grayscale, + BitDepth::Eight, + ); } #[test] @@ -345,13 +385,15 @@ fn rgba_8_should_be_grayscale_8() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGBA, - BitDepth::Eight, - ColorType::Grayscale, - BitDepth::Eight); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGBA, + BitDepth::Eight, + ColorType::Grayscale, + BitDepth::Eight, + ); } #[test] @@ -360,13 +402,15 @@ fn rgb_16_should_be_rgb_16() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGB, - BitDepth::Sixteen, - ColorType::RGB, - BitDepth::Sixteen); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGB, + BitDepth::Sixteen, + ColorType::RGB, + BitDepth::Sixteen, + ); } #[test] @@ -375,13 +419,15 @@ fn rgb_16_should_be_rgb_8() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGB, - BitDepth::Sixteen, - ColorType::RGB, - BitDepth::Eight); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGB, + BitDepth::Sixteen, + ColorType::RGB, + BitDepth::Eight, + ); } #[test] @@ -390,13 +436,15 @@ fn rgb_8_should_be_rgb_8() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGB, - BitDepth::Eight, - ColorType::RGB, - BitDepth::Eight); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGB, + BitDepth::Eight, + ColorType::RGB, + BitDepth::Eight, + ); } #[test] @@ -405,13 +453,15 @@ fn rgb_16_should_be_palette_8() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGB, - BitDepth::Sixteen, - ColorType::Indexed, - BitDepth::Eight); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGB, + BitDepth::Sixteen, + ColorType::Indexed, + BitDepth::Eight, + ); } #[test] @@ -420,13 +470,15 @@ fn rgb_8_should_be_palette_8() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGB, - BitDepth::Eight, - ColorType::Indexed, - BitDepth::Eight); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGB, + BitDepth::Eight, + ColorType::Indexed, + BitDepth::Eight, + ); } #[test] @@ -435,13 +487,15 @@ fn rgb_16_should_be_palette_4() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGB, - BitDepth::Sixteen, - ColorType::Indexed, - BitDepth::Four); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGB, + BitDepth::Sixteen, + ColorType::Indexed, + BitDepth::Four, + ); } #[test] @@ -450,13 +504,15 @@ fn rgb_8_should_be_palette_4() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGB, - BitDepth::Eight, - ColorType::Indexed, - BitDepth::Four); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGB, + BitDepth::Eight, + ColorType::Indexed, + BitDepth::Four, + ); } #[test] @@ -465,13 +521,15 @@ fn rgb_16_should_be_palette_2() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGB, - BitDepth::Sixteen, - ColorType::Indexed, - BitDepth::Two); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGB, + BitDepth::Sixteen, + ColorType::Indexed, + BitDepth::Two, + ); } #[test] @@ -480,13 +538,15 @@ fn rgb_8_should_be_palette_2() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGB, - BitDepth::Eight, - ColorType::Indexed, - BitDepth::Two); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGB, + BitDepth::Eight, + ColorType::Indexed, + BitDepth::Two, + ); } #[test] @@ -495,13 +555,15 @@ fn rgb_16_should_be_palette_1() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGB, - BitDepth::Sixteen, - ColorType::Indexed, - BitDepth::One); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGB, + BitDepth::Sixteen, + ColorType::Indexed, + BitDepth::One, + ); } #[test] @@ -510,13 +572,15 @@ fn rgb_8_should_be_palette_1() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGB, - BitDepth::Eight, - ColorType::Indexed, - BitDepth::One); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGB, + BitDepth::Eight, + ColorType::Indexed, + BitDepth::One, + ); } #[test] @@ -525,13 +589,15 @@ fn rgb_16_should_be_grayscale_16() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGB, - BitDepth::Sixteen, - ColorType::Grayscale, - BitDepth::Sixteen); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGB, + BitDepth::Sixteen, + ColorType::Grayscale, + BitDepth::Sixteen, + ); } #[test] @@ -540,13 +606,15 @@ fn rgb_16_should_be_grayscale_8() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGB, - BitDepth::Sixteen, - ColorType::Grayscale, - BitDepth::Eight); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGB, + BitDepth::Sixteen, + ColorType::Grayscale, + BitDepth::Eight, + ); } #[test] @@ -555,13 +623,15 @@ fn rgb_8_should_be_grayscale_8() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGB, - BitDepth::Eight, - ColorType::Grayscale, - BitDepth::Eight); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGB, + BitDepth::Eight, + ColorType::Grayscale, + BitDepth::Eight, + ); } #[test] @@ -570,13 +640,15 @@ fn palette_8_should_be_palette_8() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::Indexed, - BitDepth::Eight, - ColorType::Indexed, - BitDepth::Eight); + test_it_converts( + &input, + &output, + &opts, + ColorType::Indexed, + BitDepth::Eight, + ColorType::Indexed, + BitDepth::Eight, + ); } #[test] @@ -585,13 +657,15 @@ fn palette_8_should_be_palette_4() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::Indexed, - BitDepth::Eight, - ColorType::Indexed, - BitDepth::Four); + test_it_converts( + &input, + &output, + &opts, + ColorType::Indexed, + BitDepth::Eight, + ColorType::Indexed, + BitDepth::Four, + ); } #[test] @@ -600,13 +674,15 @@ fn palette_4_should_be_palette_4() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::Indexed, - BitDepth::Four, - ColorType::Indexed, - BitDepth::Four); + test_it_converts( + &input, + &output, + &opts, + ColorType::Indexed, + BitDepth::Four, + ColorType::Indexed, + BitDepth::Four, + ); } #[test] @@ -615,13 +691,15 @@ fn palette_8_should_be_palette_2() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::Indexed, - BitDepth::Eight, - ColorType::Indexed, - BitDepth::Two); + test_it_converts( + &input, + &output, + &opts, + ColorType::Indexed, + BitDepth::Eight, + ColorType::Indexed, + BitDepth::Two, + ); } #[test] @@ -630,13 +708,15 @@ fn palette_4_should_be_palette_2() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::Indexed, - BitDepth::Four, - ColorType::Indexed, - BitDepth::Two); + test_it_converts( + &input, + &output, + &opts, + ColorType::Indexed, + BitDepth::Four, + ColorType::Indexed, + BitDepth::Two, + ); } #[test] @@ -645,13 +725,15 @@ fn palette_2_should_be_palette_2() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::Indexed, - BitDepth::Two, - ColorType::Indexed, - BitDepth::Two); + test_it_converts( + &input, + &output, + &opts, + ColorType::Indexed, + BitDepth::Two, + ColorType::Indexed, + BitDepth::Two, + ); } #[test] @@ -660,13 +742,15 @@ fn palette_8_should_be_palette_1() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::Indexed, - BitDepth::Eight, - ColorType::Indexed, - BitDepth::One); + test_it_converts( + &input, + &output, + &opts, + ColorType::Indexed, + BitDepth::Eight, + ColorType::Indexed, + BitDepth::One, + ); } #[test] @@ -675,13 +759,15 @@ fn palette_4_should_be_palette_1() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::Indexed, - BitDepth::Four, - ColorType::Indexed, - BitDepth::One); + test_it_converts( + &input, + &output, + &opts, + ColorType::Indexed, + BitDepth::Four, + ColorType::Indexed, + BitDepth::One, + ); } #[test] @@ -690,13 +776,15 @@ fn palette_2_should_be_palette_1() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::Indexed, - BitDepth::Two, - ColorType::Indexed, - BitDepth::One); + test_it_converts( + &input, + &output, + &opts, + ColorType::Indexed, + BitDepth::Two, + ColorType::Indexed, + BitDepth::One, + ); } #[test] @@ -705,58 +793,72 @@ fn palette_1_should_be_palette_1() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::Indexed, - BitDepth::One, - ColorType::Indexed, - BitDepth::One); + test_it_converts( + &input, + &output, + &opts, + ColorType::Indexed, + BitDepth::One, + ColorType::Indexed, + BitDepth::One, + ); } #[test] fn grayscale_alpha_16_should_be_grayscale_alpha_16() { - let input = PathBuf::from("tests/files/grayscale_alpha_16_should_be_grayscale_alpha_16.png"); + let input = PathBuf::from( + "tests/files/grayscale_alpha_16_should_be_grayscale_alpha_16.png", + ); let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::GrayscaleAlpha, - BitDepth::Sixteen, - ColorType::GrayscaleAlpha, - BitDepth::Sixteen); + test_it_converts( + &input, + &output, + &opts, + ColorType::GrayscaleAlpha, + BitDepth::Sixteen, + ColorType::GrayscaleAlpha, + BitDepth::Sixteen, + ); } #[test] fn grayscale_alpha_16_should_be_grayscale_alpha_8() { - let input = PathBuf::from("tests/files/grayscale_alpha_16_should_be_grayscale_alpha_8.png"); + let input = PathBuf::from( + "tests/files/grayscale_alpha_16_should_be_grayscale_alpha_8.png", + ); let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::GrayscaleAlpha, - BitDepth::Sixteen, - ColorType::GrayscaleAlpha, - BitDepth::Eight); + test_it_converts( + &input, + &output, + &opts, + ColorType::GrayscaleAlpha, + BitDepth::Sixteen, + ColorType::GrayscaleAlpha, + BitDepth::Eight, + ); } #[test] fn grayscale_alpha_8_should_be_grayscale_alpha_8() { - let input = PathBuf::from("tests/files/grayscale_alpha_8_should_be_grayscale_alpha_8.png"); + let input = PathBuf::from( + "tests/files/grayscale_alpha_8_should_be_grayscale_alpha_8.png", + ); let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::GrayscaleAlpha, - BitDepth::Eight, - ColorType::GrayscaleAlpha, - BitDepth::Eight); + test_it_converts( + &input, + &output, + &opts, + ColorType::GrayscaleAlpha, + BitDepth::Eight, + ColorType::GrayscaleAlpha, + BitDepth::Eight, + ); } #[test] @@ -765,13 +867,15 @@ fn grayscale_alpha_16_should_be_grayscale_16() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::GrayscaleAlpha, - BitDepth::Sixteen, - ColorType::Grayscale, - BitDepth::Sixteen); + test_it_converts( + &input, + &output, + &opts, + ColorType::GrayscaleAlpha, + BitDepth::Sixteen, + ColorType::Grayscale, + BitDepth::Sixteen, + ); } #[test] @@ -780,13 +884,15 @@ fn grayscale_alpha_16_should_be_grayscale_8() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::GrayscaleAlpha, - BitDepth::Sixteen, - ColorType::Grayscale, - BitDepth::Eight); + test_it_converts( + &input, + &output, + &opts, + ColorType::GrayscaleAlpha, + BitDepth::Sixteen, + ColorType::Grayscale, + BitDepth::Eight, + ); } #[test] @@ -795,13 +901,15 @@ fn grayscale_alpha_8_should_be_grayscale_8() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::GrayscaleAlpha, - BitDepth::Eight, - ColorType::Grayscale, - BitDepth::Eight); + test_it_converts( + &input, + &output, + &opts, + ColorType::GrayscaleAlpha, + BitDepth::Eight, + ColorType::Grayscale, + BitDepth::Eight, + ); } #[test] @@ -810,13 +918,15 @@ fn grayscale_16_should_be_grayscale_16() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::Grayscale, - BitDepth::Sixteen, - ColorType::Grayscale, - BitDepth::Sixteen); + test_it_converts( + &input, + &output, + &opts, + ColorType::Grayscale, + BitDepth::Sixteen, + ColorType::Grayscale, + BitDepth::Sixteen, + ); } #[test] @@ -825,13 +935,15 @@ fn grayscale_16_should_be_grayscale_8() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::Grayscale, - BitDepth::Sixteen, - ColorType::Grayscale, - BitDepth::Eight); + test_it_converts( + &input, + &output, + &opts, + ColorType::Grayscale, + BitDepth::Sixteen, + ColorType::Grayscale, + BitDepth::Eight, + ); } #[test] @@ -840,13 +952,15 @@ fn grayscale_8_should_be_grayscale_8() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::Grayscale, - BitDepth::Eight, - ColorType::Grayscale, - BitDepth::Eight); + test_it_converts( + &input, + &output, + &opts, + ColorType::Grayscale, + BitDepth::Eight, + ColorType::Grayscale, + BitDepth::Eight, + ); } #[test] @@ -855,13 +969,15 @@ fn small_files() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::Indexed, - BitDepth::Eight, - ColorType::Indexed, - BitDepth::One); + test_it_converts( + &input, + &output, + &opts, + ColorType::Indexed, + BitDepth::Eight, + ColorType::Indexed, + BitDepth::One, + ); } #[test] @@ -962,3 +1078,451 @@ fn palette_should_be_reduced_with_both() { remove_file(output).ok(); } + +#[test] +fn rgba_16_reduce_alpha_black() { + let input = PathBuf::from("tests/files/rgba_16_reduce_alpha_black.png"); + let opts = get_opts(&input); + let output = opts.out_file.clone(); + + test_it_converts( + &input, + &output, + &opts, + ColorType::RGBA, + BitDepth::Sixteen, + ColorType::RGBA, + BitDepth::Eight, + ); +} + +#[test] +fn rgba_8_reduce_alpha_black() { + let input = PathBuf::from("tests/files/rgba_8_reduce_alpha_black.png"); + let opts = get_opts(&input); + let output = opts.out_file.clone(); + + test_it_converts( + &input, + &output, + &opts, + ColorType::RGBA, + BitDepth::Eight, + ColorType::RGBA, + BitDepth::Eight, + ); +} + +#[test] +fn grayscale_alpha_16_reduce_alpha_black() { + let input = PathBuf::from("tests/files/grayscale_alpha_16_reduce_alpha_black.png"); + let opts = get_opts(&input); + let output = opts.out_file.clone(); + + test_it_converts( + &input, + &output, + &opts, + ColorType::GrayscaleAlpha, + BitDepth::Sixteen, + ColorType::GrayscaleAlpha, + BitDepth::Eight, + ); +} + +#[test] +fn grayscale_alpha_8_reduce_alpha_black() { + let input = PathBuf::from("tests/files/grayscale_alpha_8_reduce_alpha_black.png"); + let opts = get_opts(&input); + let output = opts.out_file.clone(); + + test_it_converts( + &input, + &output, + &opts, + ColorType::GrayscaleAlpha, + BitDepth::Eight, + ColorType::GrayscaleAlpha, + BitDepth::Eight, + ); +} + +#[test] +fn rgba_16_reduce_alpha_white() { + let input = PathBuf::from("tests/files/rgba_16_reduce_alpha_white.png"); + let mut opts = get_opts(&input); + opts.alphas = HashSet::with_capacity(1); + opts.alphas.insert(AlphaOptim::White); + let output = opts.out_file.clone(); + + test_it_converts( + &input, + &output, + &opts, + ColorType::RGBA, + BitDepth::Sixteen, + ColorType::RGBA, + BitDepth::Eight, + ); +} + +#[test] +fn rgba_8_reduce_alpha_white() { + let input = PathBuf::from("tests/files/rgba_8_reduce_alpha_white.png"); + let mut opts = get_opts(&input); + opts.alphas = HashSet::with_capacity(1); + opts.alphas.insert(AlphaOptim::White); + let output = opts.out_file.clone(); + + test_it_converts( + &input, + &output, + &opts, + ColorType::RGBA, + BitDepth::Eight, + ColorType::RGBA, + BitDepth::Eight, + ); +} + +#[test] +fn grayscale_alpha_16_reduce_alpha_white() { + let input = PathBuf::from("tests/files/grayscale_alpha_16_reduce_alpha_white.png"); + let mut opts = get_opts(&input); + opts.alphas = HashSet::with_capacity(1); + opts.alphas.insert(AlphaOptim::White); + let output = opts.out_file.clone(); + + test_it_converts( + &input, + &output, + &opts, + ColorType::GrayscaleAlpha, + BitDepth::Sixteen, + ColorType::GrayscaleAlpha, + BitDepth::Eight, + ); +} + +#[test] +fn grayscale_alpha_8_reduce_alpha_white() { + let input = PathBuf::from("tests/files/grayscale_alpha_8_reduce_alpha_white.png"); + let mut opts = get_opts(&input); + opts.alphas = HashSet::with_capacity(1); + opts.alphas.insert(AlphaOptim::White); + let output = opts.out_file.clone(); + + test_it_converts( + &input, + &output, + &opts, + ColorType::GrayscaleAlpha, + BitDepth::Eight, + ColorType::GrayscaleAlpha, + BitDepth::Eight, + ); +} + +#[test] +fn rgba_16_reduce_alpha_down() { + let input = PathBuf::from("tests/files/rgba_16_reduce_alpha_down.png"); + let mut opts = get_opts(&input); + opts.alphas = HashSet::with_capacity(1); + opts.alphas.insert(AlphaOptim::Down); + let output = opts.out_file.clone(); + + test_it_converts( + &input, + &output, + &opts, + ColorType::RGBA, + BitDepth::Sixteen, + ColorType::RGBA, + BitDepth::Eight, + ); +} + +#[test] +fn rgba_8_reduce_alpha_down() { + let input = PathBuf::from("tests/files/rgba_8_reduce_alpha_down.png"); + let mut opts = get_opts(&input); + opts.alphas = HashSet::with_capacity(1); + opts.alphas.insert(AlphaOptim::Down); + let output = opts.out_file.clone(); + + test_it_converts( + &input, + &output, + &opts, + ColorType::RGBA, + BitDepth::Eight, + ColorType::RGBA, + BitDepth::Eight, + ); +} + +#[test] +fn grayscale_alpha_16_reduce_alpha_down() { + let input = PathBuf::from("tests/files/grayscale_alpha_16_reduce_alpha_down.png"); + let mut opts = get_opts(&input); + opts.alphas = HashSet::with_capacity(1); + opts.alphas.insert(AlphaOptim::Down); + let output = opts.out_file.clone(); + + test_it_converts( + &input, + &output, + &opts, + ColorType::GrayscaleAlpha, + BitDepth::Sixteen, + ColorType::GrayscaleAlpha, + BitDepth::Eight, + ); +} + +#[test] +fn grayscale_alpha_8_reduce_alpha_down() { + let input = PathBuf::from("tests/files/grayscale_alpha_8_reduce_alpha_down.png"); + let mut opts = get_opts(&input); + opts.alphas = HashSet::with_capacity(1); + opts.alphas.insert(AlphaOptim::Down); + let output = opts.out_file.clone(); + + test_it_converts( + &input, + &output, + &opts, + ColorType::GrayscaleAlpha, + BitDepth::Eight, + ColorType::GrayscaleAlpha, + BitDepth::Eight, + ); +} + +#[test] +fn rgba_16_reduce_alpha_up() { + let input = PathBuf::from("tests/files/rgba_16_reduce_alpha_up.png"); + let mut opts = get_opts(&input); + opts.alphas = HashSet::with_capacity(1); + opts.alphas.insert(AlphaOptim::Up); + let output = opts.out_file.clone(); + + test_it_converts( + &input, + &output, + &opts, + ColorType::RGBA, + BitDepth::Sixteen, + ColorType::RGBA, + BitDepth::Eight, + ); +} + +#[test] +fn rgba_8_reduce_alpha_up() { + let input = PathBuf::from("tests/files/rgba_8_reduce_alpha_up.png"); + let mut opts = get_opts(&input); + opts.alphas = HashSet::with_capacity(1); + opts.alphas.insert(AlphaOptim::Up); + let output = opts.out_file.clone(); + + test_it_converts( + &input, + &output, + &opts, + ColorType::RGBA, + BitDepth::Eight, + ColorType::RGBA, + BitDepth::Eight, + ); +} + +#[test] +fn grayscale_alpha_16_reduce_alpha_up() { + let input = PathBuf::from("tests/files/grayscale_alpha_16_reduce_alpha_up.png"); + let mut opts = get_opts(&input); + opts.alphas = HashSet::with_capacity(1); + opts.alphas.insert(AlphaOptim::Up); + let output = opts.out_file.clone(); + + test_it_converts( + &input, + &output, + &opts, + ColorType::GrayscaleAlpha, + BitDepth::Sixteen, + ColorType::GrayscaleAlpha, + BitDepth::Eight, + ); +} + +#[test] +fn grayscale_alpha_8_reduce_alpha_up() { + let input = PathBuf::from("tests/files/grayscale_alpha_8_reduce_alpha_up.png"); + let mut opts = get_opts(&input); + opts.alphas = HashSet::with_capacity(1); + opts.alphas.insert(AlphaOptim::Up); + let output = opts.out_file.clone(); + + test_it_converts( + &input, + &output, + &opts, + ColorType::GrayscaleAlpha, + BitDepth::Eight, + ColorType::GrayscaleAlpha, + BitDepth::Eight, + ); +} + +#[test] +fn rgba_16_reduce_alpha_left() { + let input = PathBuf::from("tests/files/rgba_16_reduce_alpha_left.png"); + let mut opts = get_opts(&input); + opts.alphas = HashSet::with_capacity(1); + opts.alphas.insert(AlphaOptim::Left); + let output = opts.out_file.clone(); + + test_it_converts( + &input, + &output, + &opts, + ColorType::RGBA, + BitDepth::Sixteen, + ColorType::RGBA, + BitDepth::Eight, + ); +} + +#[test] +fn rgba_8_reduce_alpha_left() { + let input = PathBuf::from("tests/files/rgba_8_reduce_alpha_left.png"); + let mut opts = get_opts(&input); + opts.alphas = HashSet::with_capacity(1); + opts.alphas.insert(AlphaOptim::Left); + let output = opts.out_file.clone(); + + test_it_converts( + &input, + &output, + &opts, + ColorType::RGBA, + BitDepth::Eight, + ColorType::RGBA, + BitDepth::Eight, + ); +} + +#[test] +fn grayscale_alpha_16_reduce_alpha_left() { + let input = PathBuf::from("tests/files/grayscale_alpha_16_reduce_alpha_left.png"); + let mut opts = get_opts(&input); + opts.alphas = HashSet::with_capacity(1); + opts.alphas.insert(AlphaOptim::Left); + let output = opts.out_file.clone(); + + test_it_converts( + &input, + &output, + &opts, + ColorType::GrayscaleAlpha, + BitDepth::Sixteen, + ColorType::GrayscaleAlpha, + BitDepth::Eight, + ); +} + +#[test] +fn grayscale_alpha_8_reduce_alpha_left() { + let input = PathBuf::from("tests/files/grayscale_alpha_8_reduce_alpha_left.png"); + let mut opts = get_opts(&input); + opts.alphas = HashSet::with_capacity(1); + opts.alphas.insert(AlphaOptim::Left); + let output = opts.out_file.clone(); + + test_it_converts( + &input, + &output, + &opts, + ColorType::GrayscaleAlpha, + BitDepth::Eight, + ColorType::GrayscaleAlpha, + BitDepth::Eight, + ); +} + +#[test] +fn rgba_16_reduce_alpha_right() { + let input = PathBuf::from("tests/files/rgba_16_reduce_alpha_right.png"); + let mut opts = get_opts(&input); + opts.alphas = HashSet::with_capacity(1); + opts.alphas.insert(AlphaOptim::Right); + let output = opts.out_file.clone(); + + test_it_converts( + &input, + &output, + &opts, + ColorType::RGBA, + BitDepth::Sixteen, + ColorType::RGBA, + BitDepth::Eight, + ); +} + +#[test] +fn rgba_8_reduce_alpha_right() { + let input = PathBuf::from("tests/files/rgba_8_reduce_alpha_right.png"); + let mut opts = get_opts(&input); + opts.alphas = HashSet::with_capacity(1); + opts.alphas.insert(AlphaOptim::Right); + let output = opts.out_file.clone(); + + test_it_converts( + &input, + &output, + &opts, + ColorType::RGBA, + BitDepth::Eight, + ColorType::RGBA, + BitDepth::Eight, + ); +} + +#[test] +fn grayscale_alpha_16_reduce_alpha_right() { + let input = PathBuf::from("tests/files/grayscale_alpha_16_reduce_alpha_right.png"); + let mut opts = get_opts(&input); + opts.alphas = HashSet::with_capacity(1); + opts.alphas.insert(AlphaOptim::Right); + let output = opts.out_file.clone(); + + test_it_converts( + &input, + &output, + &opts, + ColorType::GrayscaleAlpha, + BitDepth::Sixteen, + ColorType::GrayscaleAlpha, + BitDepth::Eight, + ); +} + +#[test] +fn grayscale_alpha_8_reduce_alpha_right() { + let input = PathBuf::from("tests/files/grayscale_alpha_8_reduce_alpha_right.png"); + let mut opts = get_opts(&input); + opts.alphas = HashSet::with_capacity(1); + opts.alphas.insert(AlphaOptim::Right); + let output = opts.out_file.clone(); + + test_it_converts( + &input, + &output, + &opts, + ColorType::GrayscaleAlpha, + BitDepth::Eight, + ColorType::GrayscaleAlpha, + BitDepth::Eight, + ); +} diff --git a/tests/regression.rs b/tests/regression.rs index 626bf7a1..d8cf6d65 100644 --- a/tests/regression.rs +++ b/tests/regression.rs @@ -20,13 +20,15 @@ fn get_opts(input: &Path) -> oxipng::Options { options } -fn test_it_converts(input: &Path, - output: &Path, - opts: &oxipng::Options, - color_type_in: ColorType, - bit_depth_in: BitDepth, - color_type_out: ColorType, - bit_depth_out: BitDepth) { +fn test_it_converts( + input: &Path, + output: &Path, + opts: &oxipng::Options, + color_type_in: ColorType, + bit_depth_in: BitDepth, + color_type_out: ColorType, + bit_depth_out: BitDepth, +) { let png = png::PngData::new(input, opts.fix_errors).unwrap(); assert_eq!(png.ihdr_data.color_type, color_type_in); @@ -58,13 +60,15 @@ fn issue_29() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGB, - BitDepth::Eight, - ColorType::RGB, - BitDepth::Eight); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGB, + BitDepth::Eight, + ColorType::RGB, + BitDepth::Eight, + ); } #[test] @@ -107,13 +111,15 @@ fn issue_52_01() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGBA, - BitDepth::Eight, - ColorType::Indexed, - BitDepth::Eight); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGBA, + BitDepth::Eight, + ColorType::Indexed, + BitDepth::Eight, + ); } #[test] @@ -122,13 +128,15 @@ fn issue_52_02() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGBA, - BitDepth::Eight, - ColorType::Indexed, - BitDepth::Eight); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGBA, + BitDepth::Eight, + ColorType::Indexed, + BitDepth::Eight, + ); } #[test] @@ -137,13 +145,15 @@ fn issue_52_03() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGBA, - BitDepth::Eight, - ColorType::Indexed, - BitDepth::Eight); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGBA, + BitDepth::Eight, + ColorType::Indexed, + BitDepth::Eight, + ); } #[test] @@ -152,13 +162,15 @@ fn issue_52_04() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGBA, - BitDepth::Eight, - ColorType::Indexed, - BitDepth::One); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGBA, + BitDepth::Eight, + ColorType::Indexed, + BitDepth::One, + ); } #[test] @@ -167,13 +179,15 @@ fn issue_52_05() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGBA, - BitDepth::Eight, - ColorType::Indexed, - BitDepth::One); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGBA, + BitDepth::Eight, + ColorType::Indexed, + BitDepth::One, + ); } #[test] @@ -182,13 +196,15 @@ fn issue_52_06() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGBA, - BitDepth::Eight, - ColorType::Indexed, - BitDepth::Two); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGBA, + BitDepth::Eight, + ColorType::Indexed, + BitDepth::Two, + ); } #[test] @@ -197,13 +213,15 @@ fn issue_56() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::Indexed, - BitDepth::Four, - ColorType::Indexed, - BitDepth::Four); + test_it_converts( + &input, + &output, + &opts, + ColorType::Indexed, + BitDepth::Four, + ColorType::Indexed, + BitDepth::Four, + ); } #[test] @@ -212,13 +230,15 @@ fn issue_58() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::Indexed, - BitDepth::Four, - ColorType::Indexed, - BitDepth::Four); + test_it_converts( + &input, + &output, + &opts, + ColorType::Indexed, + BitDepth::Four, + ColorType::Indexed, + BitDepth::Four, + ); } #[test] @@ -227,13 +247,15 @@ fn issue_59() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGBA, - BitDepth::Eight, - ColorType::RGBA, - BitDepth::Eight); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGBA, + BitDepth::Eight, + ColorType::RGBA, + BitDepth::Eight, + ); } #[test] @@ -242,11 +264,13 @@ fn issue_60() { let opts = get_opts(&input); let output = opts.out_file.clone(); - test_it_converts(&input, - &output, - &opts, - ColorType::RGBA, - BitDepth::Eight, - ColorType::GrayscaleAlpha, - BitDepth::Eight); + test_it_converts( + &input, + &output, + &opts, + ColorType::RGBA, + BitDepth::Eight, + ColorType::GrayscaleAlpha, + BitDepth::Eight, + ); }