From e33d120481cf7eef15e25b58ab9d2e0cf5b36e57 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 18 Mar 2020 14:07:48 -0400 Subject: [PATCH 1/7] Bump minimist from 1.2.0 to 1.2.5 (#201) Bumps [minimist](https://github.com/substack/minimist) from 1.2.0 to 1.2.5. - [Release notes](https://github.com/substack/minimist/releases) - [Commits](https://github.com/substack/minimist/compare/1.2.0...1.2.5) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 811dc5b4..1d65199e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -177,9 +177,9 @@ } }, "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", "dev": true }, "normalize-package-data": { From 6593a5f6fe51bdf384e43584dfa4a07f55b51ace Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 18 Mar 2020 18:12:20 +0000 Subject: [PATCH 2/7] Bump itertools from 0.8.2 to 0.9.0 Bumps [itertools](https://github.com/bluss/rust-itertools) from 0.8.2 to 0.9.0. - [Release notes](https://github.com/bluss/rust-itertools/releases) - [Changelog](https://github.com/rust-itertools/itertools/blob/master/CHANGELOG.md) - [Commits](https://github.com/bluss/rust-itertools/commits) Signed-off-by: dependabot-preview[bot] --- Cargo.lock | 6 +++--- Cargo.toml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d65aec9a..cd2cdfb1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -202,7 +202,7 @@ dependencies = [ [[package]] name = "itertools" -version = "0.8.2" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -295,7 +295,7 @@ dependencies = [ "cloudflare-zlib 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "image 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)", - "itertools 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", + "itertools 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "miniz_oxide 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -461,7 +461,7 @@ dependencies = [ "checksum hermit-abi 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "1010591b26bbfe835e9faeabeb11866061cc7dcebffd56ad7d0942d0e61aefd8" "checksum image 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ef4e336ec01a678e7ab692914c641181528e8656451e6252f8f9e33728882eaf" "checksum inflate 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "1cdb29978cc5797bd8dcc8e5bf7de604891df2a8dc576973d71a281e916db2ff" -"checksum itertools 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f56a2d0bc861f9165be4eb3442afd3c236d8a98afd426f65d92324ae1091a484" +"checksum itertools 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b" "checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" "checksum libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)" = "eb147597cdf94ed43ab7a9038716637d2d1bf2bc571da995d0028dec06bd3018" "checksum maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" diff --git a/Cargo.toml b/Cargo.toml index a59df56f..d37fa5b6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,7 +31,7 @@ required-features = ["binary"] bit-vec = "^0.6.0" byteorder = "^1.0.0" crc = "^1.2.0" -itertools = "^0.8.0" +itertools = "^0.9.0" num_cpus = "^1.0.0" zopfli = "^0.4.0" miniz_oxide = "0.3" From d417a712d31e3c85a002020ff0ae2dee82f66b29 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 19 Mar 2020 04:04:31 +0000 Subject: [PATCH 3/7] Bump image from 0.23.0 to 0.23.2 Bumps [image](https://github.com/image-rs/image) from 0.23.0 to 0.23.2. - [Release notes](https://github.com/image-rs/image/releases) - [Changelog](https://github.com/image-rs/image/blob/master/CHANGES.md) - [Commits](https://github.com/image-rs/image/compare/v0.23.0...v0.23.2) Signed-off-by: dependabot-preview[bot] --- Cargo.lock | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cd2cdfb1..6be5ec18 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -154,7 +154,7 @@ dependencies = [ [[package]] name = "deflate" -version = "0.7.20" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "adler32 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -181,7 +181,7 @@ dependencies = [ [[package]] name = "image" -version = "0.23.0" +version = "0.23.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bytemuck 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -189,7 +189,7 @@ dependencies = [ "num-iter 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", "num-rational 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "png 0.15.3 (registry+https://github.com/rust-lang/crates.io-index)", + "png 0.16.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -294,7 +294,7 @@ dependencies = [ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "cloudflare-zlib 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "image 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)", + "image 0.23.2 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "miniz_oxide 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -306,12 +306,12 @@ dependencies = [ [[package]] name = "png" -version = "0.15.3" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "deflate 0.7.20 (registry+https://github.com/rust-lang/crates.io-index)", + "deflate 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)", "inflate 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -455,11 +455,11 @@ dependencies = [ "checksum crossbeam-epoch 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "058ed274caafc1f60c4997b5fc07bf7dc7cca454af7c6e81edffe5f33f70dace" "checksum crossbeam-queue 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c695eeca1e7173472a32221542ae469b3e9aac3a4fc81f7696bcad82029493db" "checksum crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" -"checksum deflate 0.7.20 (registry+https://github.com/rust-lang/crates.io-index)" = "707b6a7b384888a70c8d2e8650b3e60170dfc6a67bb4aa67b6dfca57af4bedb4" +"checksum deflate 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)" = "050ef6de42a33903b30a7497b76b40d3d58691d4d3eec355348c122444a388f0" "checksum either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3" "checksum glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" "checksum hermit-abi 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "1010591b26bbfe835e9faeabeb11866061cc7dcebffd56ad7d0942d0e61aefd8" -"checksum image 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ef4e336ec01a678e7ab692914c641181528e8656451e6252f8f9e33728882eaf" +"checksum image 0.23.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9062b90712d25bc6bb165d110aa59c6b47c849246e341e7b86a98daff9d49f60" "checksum inflate 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "1cdb29978cc5797bd8dcc8e5bf7de604891df2a8dc576973d71a281e916db2ff" "checksum itertools 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b" "checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" @@ -472,7 +472,7 @@ dependencies = [ "checksum num-rational 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "da4dc79f9e6c81bef96148c8f6b8e72ad4541caa4a24373e900a36da07de03a3" "checksum num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "c62be47e61d1842b9170f0fdeec8eba98e60e90e5446449a0545e5152acd7096" "checksum num_cpus 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "46203554f085ff89c235cd12f7075f3233af9b11ed7c9e16dfe2560d03313ce6" -"checksum png 0.15.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ef859a23054bbfee7811284275ae522f0434a3c8e7f4b74bd4a35ae7e1c4a283" +"checksum png 0.16.1 (registry+https://github.com/rust-lang/crates.io-index)" = "46060468187c21c00ffa2a920690b29997d7fd543f5a4d400461e4a7d4fccde8" "checksum rayon 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "db6ce3297f9c85e16621bb8cca38a06779ffc31bb8184e1be4bed2be4678a098" "checksum rayon-core 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "08a89b46efaf957e52b18062fb2f4660f8b8a4dde1807ca002690868ef2c85a9" "checksum rgb 0.8.16 (registry+https://github.com/rust-lang/crates.io-index)" = "5ec4ab2cf0b27e111e266e161cf7f9efd20125a161190da1c0945c4a4408fef3" From 681089f8c7c85662c88c642dbdca9d60ba0eb820 Mon Sep 17 00:00:00 2001 From: Kornel Date: Wed, 1 Apr 2020 00:28:22 +0100 Subject: [PATCH 4/7] Remove the concept of size bias (#199) Closes #198 --- src/evaluate.rs | 31 ++++++------------------------- src/lib.rs | 10 +++++----- src/reduction/alpha.rs | 2 +- 3 files changed, 12 insertions(+), 31 deletions(-) diff --git a/src/evaluate.rs b/src/evaluate.rs index c6be4d9a..cc083b7f 100644 --- a/src/evaluate.rs +++ b/src/evaluate.rs @@ -24,8 +24,6 @@ use std::thread; struct Candidate { image: PngData, - // compressed size multiplier. Fudge factor to prefer more promising formats. - bias: f32, // if false, that's baseline file to throw away is_reduction: bool, filter: u8, @@ -42,30 +40,16 @@ impl Comparator { fn evaluate(&mut self, new: Candidate) { // a tie-breaker is required to make evaluation deterministic let is_best = if let Some(ref old) = self.best_result { - // ordering is important - later file gets to use bias over earlier, but not the other way - // (this way bias=0 replaces, but doesn't forbid later optimizations) - let new_len = (new.image.idat_data.len() as f64 - * if new.nth > old.nth { - f64::from(new.bias) - } else { - 1.0 - }) as usize; - let old_len = (old.image.idat_data.len() as f64 - * if new.nth < old.nth { - f64::from(old.bias) - } else { - 1.0 - }) as usize; // choose smallest compressed, or if compresses the same, smallest uncompressed, or cheaper filter let new = ( - new_len, + new.image.idat_data.len(), new.image.raw.data.len(), new.image.raw.ihdr.bit_depth, new.filter, new.nth, ); let old = ( - old_len, + old.image.idat_data.len(), old.image.raw.data.len(), old.image.raw.ihdr.bit_depth, old.filter, @@ -141,17 +125,15 @@ impl Evaluator { /// Set baseline image. It will be used only to measure minimum compression level required pub fn set_baseline(&self, image: Arc) { - self.try_image_inner(image, 1.0, false) + self.try_image_inner(image, false) } /// Check if the image is smaller than others - /// Bias is a value in 0..=1 range. Compressed size is multiplied by - /// this fraction when comparing to the best, so 0.95 allows 5% larger size. - pub fn try_image(&self, image: Arc, bias: f32) { - self.try_image_inner(image, bias, true) + pub fn try_image(&self, image: Arc) { + self.try_image_inner(image, true) } - fn try_image_inner(&self, image: Arc, bias: f32, is_reduction: bool) { + fn try_image_inner(&self, image: Arc, is_reduction: bool) { let nth = self.nth.fetch_add(1, SeqCst); // These clones are only cheap refcounts let deadline = self.deadline.clone(); @@ -186,7 +168,6 @@ impl Evaluator { idat_data, raw: Arc::clone(&image), }, - bias, filter, is_reduction, nth, diff --git a/src/lib.rs b/src/lib.rs index 5227bc0f..d56f264d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -740,7 +740,7 @@ fn perform_reductions( if let Some(interlacing) = opts.interlace { if let Some(reduced) = png.change_interlacing(interlacing) { png = Arc::new(reduced); - eval.try_image(png.clone(), 0.); + eval.try_image(png.clone()); } if deadline.passed() { return; @@ -750,7 +750,7 @@ fn perform_reductions( if opts.palette_reduction { if let Some(reduced) = reduced_palette(&png) { png = Arc::new(reduced); - eval.try_image(png.clone(), 0.95); + eval.try_image(png.clone()); if opts.verbosity == Some(1) { report_reduction(&png); } @@ -765,13 +765,13 @@ fn perform_reductions( let previous = png.clone(); let bits = reduced.ihdr.bit_depth; png = Arc::new(reduced); - eval.try_image(png.clone(), 1.0); + eval.try_image(png.clone()); if (bits == BitDepth::One || bits == BitDepth::Two) && previous.ihdr.bit_depth != BitDepth::Four { // Also try 16-color mode for all lower bits images, since that may compress better if let Some(reduced) = reduce_bit_depth(&previous, 4) { - eval.try_image(Arc::new(reduced), 0.98); + eval.try_image(Arc::new(reduced)); } } if opts.verbosity == Some(1) { @@ -786,7 +786,7 @@ fn perform_reductions( if opts.color_type_reduction { if let Some(reduced) = reduce_color_type(&png) { png = Arc::new(reduced); - eval.try_image(png.clone(), 0.96); + eval.try_image(png.clone()); if opts.verbosity == Some(1) { report_reduction(&png); } diff --git a/src/reduction/alpha.rs b/src/reduction/alpha.rs index 95b03744..9c4a0446 100644 --- a/src/reduction/alpha.rs +++ b/src/reduction/alpha.rs @@ -24,7 +24,7 @@ pub(crate) fn try_alpha_reductions( let alphas_iter = alphas.par_iter().with_max_len(1); alphas_iter .filter_map(|&alpha| filtered_alpha_channel(&png, *alpha)) - .for_each(|image| eval.try_image(Arc::new(image), 0.99)); + .for_each(|image| eval.try_image(Arc::new(image))); } pub fn filtered_alpha_channel(png: &PngImage, optim: AlphaOptim) -> Option { From 121558bf5cb3883296a74b09b40b70bbd64930a2 Mon Sep 17 00:00:00 2001 From: Ingvar Stepanyan Date: Wed, 1 Apr 2020 01:24:57 +0100 Subject: [PATCH 5/7] Add libdeflater as an option (#203) libdeflater is a Rust wrapper around [libdeflate](https://github.com/ebiggers/libdeflate) - an alternative heavily optimised library for deflate/zlib/gzip compression and decompression that is intended for situations where upper bounds of the output are well-known. In my benchmarks on test files in the repo it has shown to be usually both slightly faster and providing better compressed output than cloudflare-zlib, but in some cases showing the opposite, so rather than swapping defaults, it's currently provided as another option, similarly to zopfli. Since it's not strictly better in all cases, I'm not providing median numbers, but you can check distribution histograms for time and size differences here (all using `oxipng -o 6 -t 6 -P`): https://docs.google.com/spreadsheets/d/1WOKgeYZBhLkQvMGAC36snN4azilElzOFhx63RJu0EZY/edit?usp=sharing --- Cargo.lock | 10 +++++++ Cargo.toml | 1 + benches/libdeflater.rs | 64 +++++++++++++++++++++++++++++++++++++++++ src/deflate/deflater.rs | 31 ++++++++++++++++++++ src/deflate/mod.rs | 5 ++++ src/lib.rs | 13 +++++---- src/main.rs | 8 ++++++ tests/flags.rs | 18 ++++++++++++ 8 files changed, 144 insertions(+), 6 deletions(-) create mode 100644 benches/libdeflater.rs create mode 100644 src/deflate/deflater.rs diff --git a/Cargo.lock b/Cargo.lock index 6be5ec18..365ae348 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -218,6 +218,14 @@ name = "libc" version = "0.2.67" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "libdeflater" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "maybe-uninit" version = "2.0.0" @@ -296,6 +304,7 @@ dependencies = [ "crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "image 0.23.2 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libdeflater 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "miniz_oxide 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -464,6 +473,7 @@ dependencies = [ "checksum itertools 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b" "checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" "checksum libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)" = "eb147597cdf94ed43ab7a9038716637d2d1bf2bc571da995d0028dec06bd3018" +"checksum libdeflater 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "66dca08b13369865b2f6dca1dd05f833985cbe6c12a676b04d55f78b85e80246" "checksum maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" "checksum memoffset 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "75189eb85871ea5c2e2c15abbdd541185f63b408415e5051f5cac122d8c774b9" "checksum miniz_oxide 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "aa679ff6578b1cddee93d7e82e263b94a575e0bfced07284eb0c037c1d2416a5" diff --git a/Cargo.toml b/Cargo.toml index d37fa5b6..c7afb897 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,6 +36,7 @@ num_cpus = "^1.0.0" zopfli = "^0.4.0" miniz_oxide = "0.3" rgb = "0.8.11" +libdeflater = "0.2.0" [dependencies.rayon] optional = true diff --git a/benches/libdeflater.rs b/benches/libdeflater.rs new file mode 100644 index 00000000..d3323253 --- /dev/null +++ b/benches/libdeflater.rs @@ -0,0 +1,64 @@ +#![feature(test)] + +extern crate oxipng; +extern crate test; + +use oxipng::internal_tests::*; +use std::path::PathBuf; +use test::Bencher; + +#[bench] +fn libdeflater_16_bits_strategy_0(b: &mut Bencher) { + let input = test::black_box(PathBuf::from("tests/files/rgb_16_should_be_rgb_16.png")); + let png = PngData::new(&input, false).unwrap(); + + b.iter(|| { + libdeflater_deflate(png.raw.data.as_ref()).ok(); + }); +} + +#[bench] +fn libdeflater_8_bits_strategy_0(b: &mut Bencher) { + let input = test::black_box(PathBuf::from("tests/files/rgb_8_should_be_rgb_8.png")); + let png = PngData::new(&input, false).unwrap(); + + b.iter(|| { + libdeflater_deflate(png.raw.data.as_ref()).ok(); + }); +} + +#[bench] +fn libdeflater_4_bits_strategy_0(b: &mut Bencher) { + let input = test::black_box(PathBuf::from( + "tests/files/palette_4_should_be_palette_4.png", + )); + let png = PngData::new(&input, false).unwrap(); + + b.iter(|| { + libdeflater_deflate(png.raw.data.as_ref()).ok(); + }); +} + +#[bench] +fn libdeflater_2_bits_strategy_0(b: &mut Bencher) { + let input = test::black_box(PathBuf::from( + "tests/files/palette_2_should_be_palette_2.png", + )); + let png = PngData::new(&input, false).unwrap(); + + b.iter(|| { + libdeflater_deflate(png.raw.data.as_ref()).ok(); + }); +} + +#[bench] +fn libdeflater_1_bits_strategy_0(b: &mut Bencher) { + let input = test::black_box(PathBuf::from( + "tests/files/palette_1_should_be_palette_1.png", + )); + let png = PngData::new(&input, false).unwrap(); + + b.iter(|| { + libdeflater_deflate(png.raw.data.as_ref()).ok(); + }); +} diff --git a/src/deflate/deflater.rs b/src/deflate/deflater.rs new file mode 100644 index 00000000..19f93db8 --- /dev/null +++ b/src/deflate/deflater.rs @@ -0,0 +1,31 @@ +use crate::{PngError, PngResult}; +use crate::atomicmin::AtomicMin; +use libdeflater::{CompressionError, CompressionLvl, Compressor}; + +pub fn deflate(data: &[u8], max_size: &AtomicMin) -> PngResult> { + let mut compressor = Compressor::new(CompressionLvl::best()); + let capacity = max_size.get().unwrap_or(data.len() / 2); + let mut dest = Vec::with_capacity(capacity); + unsafe { + // This is ok because the Vec contains Copy-able data (u8) + // and because libdeflater wrapper doesn't try to read + // the bytes from the target. + // + // That said, it should be able to accept MaybeUninit instead, + // so I raised an upstream issue that should make this safer: + // https://github.com/adamkewley/libdeflater/issues/1 + dest.set_len(capacity); + } + let len = compressor + .zlib_compress(data, &mut dest) + .map_err(|err| match err { + CompressionError::InsufficientSpace => PngError::DeflatedDataTooLong(capacity), + })?; + if let Some(max) = max_size.get() { + if len > max { + return Err(PngError::DeflatedDataTooLong(max)); + } + } + dest.truncate(len); + Ok(dest) +} diff --git a/src/deflate/mod.rs b/src/deflate/mod.rs index c04a8e4a..e7b5dcca 100644 --- a/src/deflate/mod.rs +++ b/src/deflate/mod.rs @@ -9,6 +9,9 @@ use zopfli; #[doc(hidden)] pub mod miniz_stream; +mod deflater; +pub use deflater::deflate as libdeflater_deflate; + #[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))] pub mod cfzlib; @@ -62,4 +65,6 @@ pub enum Deflaters { Zlib, /// Use the better but slower Zopfli implementation Zopfli, + /// Use libdeflater. + Libdeflater, } diff --git a/src/lib.rs b/src/lib.rs index d56f264d..6e22d03f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -353,6 +353,7 @@ pub fn optimize(input: &InFile, output: &OutFile, opts: &Options) -> PngResult<( data } }; + let mut png = PngData::from_slice(&in_data, opts.fix_errors)?; // Run the optimizer on the decoded PNG. @@ -565,7 +566,7 @@ fn optimize_png( } } } else { - // Zopfli compression has no additional options + // Zopfli and Libdeflater compression have no additional options. results.push(TrialOptions { filter: *f, compression: 0, @@ -600,17 +601,17 @@ fn optimize_png( return None; } let filtered = &filters[&trial.filter]; - let new_idat = if opts.deflate == Deflaters::Zlib { - deflate::deflate( + let new_idat = match opts.deflate { + Deflaters::Zlib => deflate::deflate( filtered, trial.compression, trial.strategy, opts.window, &best_size, &deadline, - ) - } else { - deflate::zopfli_deflate(filtered) + ), + Deflaters::Zopfli => deflate::zopfli_deflate(filtered), + Deflaters::Libdeflater => deflate::libdeflater_deflate(filtered, &best_size), }; let new_idat = match new_idat { diff --git a/src/main.rs b/src/main.rs index 29631f58..d39d83d1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -193,6 +193,10 @@ fn main() { .help("Use the slower but better compressing Zopfli algorithm, overrides zlib-specific options") .short("Z") .long("zopfli")) + .arg(Arg::with_name("libdeflater") + .help("Use an alternative Libdeflater algorithm, overrides zlib-specific options") + .short("D") + .long("libdeflater")) .arg(Arg::with_name("timeout") .help("Maximum amount of time, in seconds, to spend on optimizations") .takes_value(true) @@ -481,6 +485,10 @@ fn parse_opts_into_struct( opts.deflate = Deflaters::Zopfli; } + if matches.is_present("libdeflater") { + opts.deflate = Deflaters::Libdeflater; + } + if let Some(x) = matches.value_of("threads") { opts.threads = x.parse::().unwrap(); } diff --git a/tests/flags.rs b/tests/flags.rs index 1e9a43f7..d9f7b477 100644 --- a/tests/flags.rs +++ b/tests/flags.rs @@ -438,3 +438,21 @@ fn zopfli_mode() { BitDepth::Eight, ); } + + +#[test] +fn libdeflater_mode() { + let input = PathBuf::from("tests/files/zopfli_mode.png"); + let (output, mut opts) = get_opts(&input); + opts.deflate = Deflaters::Libdeflater; + + test_it_converts( + input, + &output, + &opts, + ColorType::RGB, + BitDepth::Eight, + ColorType::RGB, + BitDepth::Eight, + ); +} From 4b1a47e9029b0037e46f0c74a3d8d394b88d13df Mon Sep 17 00:00:00 2001 From: Josh Holmer Date: Tue, 31 Mar 2020 20:57:50 -0400 Subject: [PATCH 6/7] Bump minimum rust version to 1.41 --- .travis.yml | 2 +- README.md | 2 +- README.template.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 626b2b9d..6e4b97f7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,7 +11,7 @@ matrix: env: TARGET=x86_64-apple-darwin cache: cargo - os: linux - rust: 1.36.0 + rust: 1.41.0 env: TARGET=x86_64-unknown-linux-gnu cache: cargo - os: linux diff --git a/README.md b/README.md index 5d524d9d..1bd742ea 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ cargo build --release cp target/release/oxipng /usr/local/bin ``` -The current minimum supported Rust version is **1.36.0**. Oxipng may compile on earlier versions of Rust, +The current minimum supported Rust version is **1.41.0**. Oxipng may compile on earlier versions of Rust, but there is no guarantee. Oxipng follows Semantic Versioning. diff --git a/README.template.md b/README.template.md index 942e6148..c1d6adf5 100644 --- a/README.template.md +++ b/README.template.md @@ -26,7 +26,7 @@ cargo build --release cp target/release/oxipng /usr/local/bin ``` -The current minimum supported Rust version is **1.36.0**. Oxipng may compile on earlier versions of Rust, +The current minimum supported Rust version is **1.41.0**. Oxipng may compile on earlier versions of Rust, but there is no guarantee. Oxipng follows Semantic Versioning. From 878bbedb372fe81520ad370c9c98890b5416b506 Mon Sep 17 00:00:00 2001 From: Ingvar Stepanyan Date: Wed, 1 Apr 2020 02:54:05 +0100 Subject: [PATCH 7/7] Improve performance consistency (#202) * Improve performance consistency Switch from HashMap / HashSet to IndexMap / IndexSet for consistent iteration order of various options and, as a result, more predictable performance. --- Cargo.lock | 12 +++++++++++ Cargo.toml | 1 + src/headers.rs | 4 ++-- src/lib.rs | 45 ++++++++++++++++++++---------------------- src/main.rs | 6 +++--- src/png/mod.rs | 6 +++--- src/reduction/alpha.rs | 12 +++++------ src/reduction/color.rs | 6 +++--- src/reduction/mod.rs | 5 ++--- tests/filters.rs | 8 +++----- tests/flags.rs | 8 +++----- tests/interlaced.rs | 6 ++---- tests/reduction.rs | 6 ++---- tests/regression.rs | 30 +++++++++++++--------------- 14 files changed, 77 insertions(+), 78 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 365ae348..b97d72f4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -192,6 +192,15 @@ dependencies = [ "png 0.16.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "indexmap" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rayon 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "inflate" version = "0.4.5" @@ -303,12 +312,14 @@ dependencies = [ "cloudflare-zlib 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "image 0.23.2 (registry+https://github.com/rust-lang/crates.io-index)", + "indexmap 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "libdeflater 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "miniz_oxide 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "rgb 0.8.16 (registry+https://github.com/rust-lang/crates.io-index)", + "vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "wild 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "zopfli 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -469,6 +480,7 @@ dependencies = [ "checksum glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" "checksum hermit-abi 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "1010591b26bbfe835e9faeabeb11866061cc7dcebffd56ad7d0942d0e61aefd8" "checksum image 0.23.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9062b90712d25bc6bb165d110aa59c6b47c849246e341e7b86a98daff9d49f60" +"checksum indexmap 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "076f042c5b7b98f31d205f1249267e12a6518c1481e9dae9764af19b707d2292" "checksum inflate 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "1cdb29978cc5797bd8dcc8e5bf7de604891df2a8dc576973d71a281e916db2ff" "checksum itertools 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b" "checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" diff --git a/Cargo.toml b/Cargo.toml index c7afb897..55e409d9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,6 +36,7 @@ num_cpus = "^1.0.0" zopfli = "^0.4.0" miniz_oxide = "0.3" rgb = "0.8.11" +indexmap = { version = "1.3.2", features = ["rayon"] } libdeflater = "0.2.0" [dependencies.rayon] diff --git a/src/headers.rs b/src/headers.rs index 1667bdbf..fcf92ae5 100644 --- a/src/headers.rs +++ b/src/headers.rs @@ -1,9 +1,9 @@ +use indexmap::IndexSet; use crate::colors::{BitDepth, ColorType}; use crate::error::PngError; use crate::PngResult; use byteorder::{BigEndian, ReadBytesExt}; use crc::crc32; -use std::collections::HashSet; use std::io::Cursor; #[derive(Debug, Clone, Copy)] @@ -35,7 +35,7 @@ pub enum Headers { /// Headers that won't affect rendering (all but cHRM, gAMA, iCCP, sBIT, sRGB, bKGD, hIST, pHYs, sPLT) Safe, /// Remove all non-critical chunks except these - Keep(HashSet), + Keep(IndexSet), /// All non-critical headers All, } diff --git a/src/lib.rs b/src/lib.rs index 6e22d03f..a22b1c38 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -28,8 +28,8 @@ use crate::png::PngImage; use crate::reduction::*; use crc::crc32; use image::{DynamicImage, GenericImageView, ImageFormat, Pixel}; +use indexmap::{IndexSet, IndexMap}; use rayon::prelude::*; -use std::collections::{BTreeMap, HashMap, HashSet}; use std::fmt; use std::fs::{copy, File}; use std::io::{stdin, stdout, BufWriter, Read, Write}; @@ -154,7 +154,7 @@ pub struct Options { /// Which filters to try on the file (0-5) /// /// Default: `0,5` - pub filter: HashSet, + pub filter: IndexSet, /// Whether to change the interlacing type of the file. /// /// `None` will not change the current interlacing type. @@ -166,11 +166,11 @@ pub struct Options { /// Which zlib compression levels to try on the file (1-9) /// /// Default: `9` - pub compression: HashSet, + pub compression: IndexSet, /// Which zlib compression strategies to try on the file (0-3) /// /// Default: `0-3` - pub strategies: HashSet, + pub strategies: IndexSet, /// Window size to use when compressing the file, as `2^window` bytes. /// /// Doesn't affect compression but may affect speed and memory usage. @@ -179,7 +179,7 @@ pub struct Options { /// Default: `15` pub window: u8, /// Alpha filtering strategies to use - pub alphas: HashSet, + pub alphas: IndexSet, /// Whether to attempt bit depth reduction /// /// Default: `true` @@ -286,17 +286,17 @@ impl Options { impl Default for Options { fn default() -> Options { // Default settings based on -o 2 from the CLI interface - let mut filter = HashSet::new(); + let mut filter = IndexSet::new(); filter.insert(0); filter.insert(5); - let mut compression = HashSet::new(); + let mut compression = IndexSet::new(); compression.insert(9); - let mut strategies = HashSet::new(); + let mut strategies = IndexSet::new(); for i in 0..4 { strategies.insert(i); } // We always need NoOp to be present - let mut alphas = HashSet::new(); + let mut alphas = IndexSet::new(); alphas.insert(AlphaOptim::NoOp); Options { @@ -502,7 +502,7 @@ fn optimize_png( eprintln!(" File size = {} bytes", file_original_size); } - let mut filter = opts.filter.iter().cloned().collect::>(); + let mut filter = opts.filter.clone(); let compression = &opts.compression; let mut strategies = opts.strategies.clone(); @@ -512,14 +512,14 @@ fn optimize_png( && png.raw.ihdr.color_type != colors::ColorType::Indexed { if filter.is_empty() { - filter.push(5); + filter.insert(5); } if strategies.is_empty() { strategies.insert(1); } } else { if filter.is_empty() { - filter.push(0); + filter.insert(0); } if strategies.is_empty() { strategies.insert(0); @@ -583,8 +583,10 @@ fn optimize_png( eprintln!("Trying: {} combinations", results.len()); } - let filter_iter = filter.par_iter().with_max_len(1); - let filters: HashMap> = filter_iter + let filters: IndexMap> = + filter + .par_iter() + .with_max_len(1) .map(|f| { let png = png.clone(); (*f, png.raw.filter_image(*f)) @@ -865,15 +867,10 @@ fn perform_strip(png: &mut PngData, opts: &Options) { // Strip headers Headers::None => (), Headers::Keep(ref hdrs) => { - let keys: Vec<[u8; 4]> = raw.aux_headers.keys().cloned().collect(); - for hdr in &keys { - let preserve = std::str::from_utf8(hdr) - .ok() - .map_or(false, |name| hdrs.contains(name)); - if !preserve { - raw.aux_headers.remove(hdr); - } - } + raw.aux_headers.retain(|hdr, _| { + std::str::from_utf8(hdr) + .map_or(false, |name| hdrs.contains(name)) + }) } Headers::Strip(ref hdrs) => { for hdr in hdrs { @@ -893,7 +890,7 @@ fn perform_strip(png: &mut PngData, opts: &Options) { } } Headers::All => { - raw.aux_headers = BTreeMap::new(); + raw.aux_headers = IndexMap::new(); } } diff --git a/src/main.rs b/src/main.rs index d39d83d1..bafdc2bd 100644 --- a/src/main.rs +++ b/src/main.rs @@ -14,13 +14,13 @@ #![allow(clippy::cognitive_complexity)] use clap::{App, AppSettings, Arg, ArgMatches}; +use indexmap::IndexSet; use oxipng::AlphaOptim; use oxipng::Deflaters; use oxipng::Headers; use oxipng::Options; use oxipng::PngResult; use oxipng::{InFile, OutFile}; -use std::collections::HashSet; use std::fs::DirBuilder; use std::path::PathBuf; use std::process::exit; @@ -500,9 +500,9 @@ fn parse_numeric_range_opts( input: &str, min_value: u8, max_value: u8, -) -> Result, String> { +) -> Result, String> { const ERROR_MESSAGE: &str = "Not a valid input"; - let mut items = HashSet::new(); + let mut items = IndexSet::new(); // one value if let Ok(one_value) = input.parse::() { diff --git a/src/png/mod.rs b/src/png/mod.rs index 5ad3bed6..ee425ae6 100644 --- a/src/png/mod.rs +++ b/src/png/mod.rs @@ -6,9 +6,9 @@ use crate::headers::*; use crate::interlace::{deinterlace_image, interlace_image}; use byteorder::{BigEndian, WriteBytesExt}; use crc::crc32; +use indexmap::IndexMap; use rgb::ComponentSlice; use rgb::RGBA8; -use std::collections::BTreeMap; use std::fs::File; use std::io::{Read, Seek, SeekFrom}; use std::iter::Iterator; @@ -38,7 +38,7 @@ pub struct PngImage { /// The pixel value that should be rendered as transparent pub transparency_pixel: Option>, /// All non-critical headers from the PNG are stored here - pub aux_headers: BTreeMap<[u8; 4], Vec>, + pub aux_headers: IndexMap<[u8; 4], Vec>, } /// Contains all data relevant to a PNG image @@ -97,7 +97,7 @@ impl PngData { } byte_offset += 8; // Read the data headers - let mut aux_headers: BTreeMap<[u8; 4], Vec> = BTreeMap::new(); + let mut aux_headers: IndexMap<[u8; 4], Vec> = IndexMap::new(); let mut idat_headers: Vec = Vec::new(); while let Some(header) = parse_next_header(byte_data, &mut byte_offset, fix_errors)? { match &header.name { diff --git a/src/reduction/alpha.rs b/src/reduction/alpha.rs index 9c4a0446..71d23a08 100644 --- a/src/reduction/alpha.rs +++ b/src/reduction/alpha.rs @@ -1,3 +1,4 @@ +use indexmap::IndexSet; use crate::colors::AlphaOptim; use crate::colors::ColorType; use crate::evaluate::Evaluator; @@ -8,22 +9,21 @@ use crate::png::PngImage; use crate::rayon::prelude::*; #[cfg(feature = "parallel")] use rayon::prelude::*; -use std::collections::HashSet; use std::sync::Arc; pub(crate) fn try_alpha_reductions( png: Arc, - alphas: &HashSet, + alphas: &IndexSet, eval: &Evaluator, ) { if alphas.is_empty() { return; } - let alphas = alphas.iter().collect::>(); - let alphas_iter = alphas.par_iter().with_max_len(1); - alphas_iter - .filter_map(|&alpha| filtered_alpha_channel(&png, *alpha)) + alphas + .par_iter() + .with_max_len(1) + .filter_map(|&alpha| filtered_alpha_channel(&png, alpha)) .for_each(|image| eval.try_image(Arc::new(image))); } diff --git a/src/reduction/color.rs b/src/reduction/color.rs index bd692dc8..8be17402 100644 --- a/src/reduction/color.rs +++ b/src/reduction/color.rs @@ -1,9 +1,9 @@ use crate::colors::{BitDepth, ColorType}; use crate::headers::IhdrData; use crate::png::PngImage; +use indexmap::IndexMap; use itertools::Itertools; use rgb::{FromSlice, RGB8, RGBA8}; -use std::collections::HashMap; use std::hash::Hash; #[must_use] @@ -76,7 +76,7 @@ pub fn reduce_rgba_to_grayscale_alpha(png: &PngImage) -> Option { fn reduce_scanline_to_palette( iter: impl IntoIterator, - palette: &mut HashMap, + palette: &mut IndexMap, reduced: &mut Vec, ) -> bool where @@ -105,7 +105,7 @@ pub fn reduced_color_to_palette(png: &PngImage) -> Option { return None; } let mut raw_data = Vec::with_capacity(png.data.len()); - let mut palette = HashMap::with_capacity(257); + let mut palette = IndexMap::with_capacity(257); let transparency_pixel = png .transparency_pixel .as_ref() diff --git a/src/reduction/mod.rs b/src/reduction/mod.rs index 702e9cf0..b486d8fc 100644 --- a/src/reduction/mod.rs +++ b/src/reduction/mod.rs @@ -1,10 +1,9 @@ use crate::colors::{BitDepth, ColorType}; use crate::headers::IhdrData; use crate::png::PngImage; +use indexmap::map::{IndexMap, Entry::*}; use rgb::RGBA8; use std::borrow::Cow; -use std::collections::hash_map::Entry::*; -use std::collections::HashMap; pub mod alpha; use crate::alpha::*; @@ -79,7 +78,7 @@ pub fn reduced_palette(png: &PngImage) -> Option { }); let mut next_index = 0u16; - let mut seen = HashMap::with_capacity(palette.len()); + let mut seen = IndexMap::with_capacity(palette.len()); for (i, used) in used_enumerated.iter().cloned() { if !used { continue; diff --git a/tests/filters.rs b/tests/filters.rs index 3bc4e56e..41f92ca8 100644 --- a/tests/filters.rs +++ b/tests/filters.rs @@ -1,8 +1,6 @@ -use oxipng; - +use indexmap::IndexSet; use oxipng::internal_tests::*; use oxipng::{InFile, OutFile}; -use std::collections::HashSet; use std::fs::remove_file; use std::path::Path; use std::path::PathBuf; @@ -11,7 +9,7 @@ fn get_opts(input: &Path) -> (OutFile, oxipng::Options) { let mut options = oxipng::Options::default(); options.verbosity = None; options.force = true; - let mut filter = HashSet::new(); + let mut filter = IndexSet::new(); filter.insert(0); options.filter = filter; @@ -33,7 +31,7 @@ fn test_it_converts( let (output, mut opts) = get_opts(&input); let png = PngData::new(&input, opts.fix_errors).unwrap(); - opts.filter = HashSet::new(); + opts.filter = IndexSet::new(); opts.filter.insert(filter); assert_eq!(png.raw.ihdr.color_type, color_type_in); assert_eq!(png.raw.ihdr.bit_depth, bit_depth_in); diff --git a/tests/flags.rs b/tests/flags.rs index d9f7b477..928420a8 100644 --- a/tests/flags.rs +++ b/tests/flags.rs @@ -1,8 +1,6 @@ -extern crate oxipng; - +use indexmap::IndexSet; use oxipng::internal_tests::*; use oxipng::{InFile, OutFile}; -use std::collections::HashSet; use std::fs::remove_file; use std::path::Path; use std::path::PathBuf; @@ -11,7 +9,7 @@ fn get_opts(input: &Path) -> (OutFile, oxipng::Options) { let mut options = oxipng::Options::default(); options.verbosity = None; options.force = true; - let mut filter = HashSet::new(); + let mut filter = IndexSet::new(); filter.insert(0); options.filter = filter; @@ -342,7 +340,7 @@ fn interlaced_0_to_1_other_filter_mode() { let input = PathBuf::from("tests/files/interlaced_0_to_1_other_filter_mode.png"); let (output, mut opts) = get_opts(&input); opts.interlace = Some(1); - let mut filter = HashSet::new(); + let mut filter = IndexSet::new(); filter.insert(4); opts.filter = filter; diff --git a/tests/interlaced.rs b/tests/interlaced.rs index 7b93f0ee..8bc93df1 100644 --- a/tests/interlaced.rs +++ b/tests/interlaced.rs @@ -1,8 +1,6 @@ -extern crate oxipng; - +use indexmap::IndexSet; use oxipng::internal_tests::*; use oxipng::{InFile, OutFile}; -use std::collections::HashSet; use std::fs::remove_file; use std::path::Path; use std::path::PathBuf; @@ -11,7 +9,7 @@ fn get_opts(input: &Path) -> (OutFile, oxipng::Options) { let mut options = oxipng::Options::default(); options.verbosity = None; options.force = true; - let mut filter = HashSet::new(); + let mut filter = IndexSet::new(); filter.insert(0); options.filter = filter; diff --git a/tests/reduction.rs b/tests/reduction.rs index d3b5cc5a..a27cd2a0 100644 --- a/tests/reduction.rs +++ b/tests/reduction.rs @@ -1,8 +1,6 @@ -use oxipng; - +use indexmap::IndexSet; use oxipng::internal_tests::*; use oxipng::{InFile, OutFile}; -use std::collections::HashSet; use std::fs::remove_file; use std::path::Path; use std::path::PathBuf; @@ -11,7 +9,7 @@ fn get_opts(input: &Path) -> (OutFile, oxipng::Options) { let mut options = oxipng::Options::default(); options.verbosity = None; options.force = true; - let mut filter = HashSet::new(); + let mut filter = IndexSet::new(); filter.insert(0); options.filter = filter; diff --git a/tests/regression.rs b/tests/regression.rs index 867902ab..096fe8d8 100644 --- a/tests/regression.rs +++ b/tests/regression.rs @@ -1,8 +1,6 @@ -use oxipng; - +use indexmap::IndexSet; use oxipng::internal_tests::*; use oxipng::{InFile, OutFile}; -use std::collections::HashSet; use std::fs::remove_file; use std::path::Path; use std::path::PathBuf; @@ -11,7 +9,7 @@ fn get_opts(input: &Path) -> (OutFile, oxipng::Options) { let mut options = oxipng::Options::default(); options.verbosity = None; options.force = true; - let mut filter = HashSet::new(); + let mut filter = IndexSet::new(); filter.insert(0); options.filter = filter; @@ -309,7 +307,7 @@ fn issue_113_white() { let input = "tests/files/issue-113.png"; let (_, mut opts) = get_opts(Path::new(input)); opts.interlace = Some(1); - opts.alphas = HashSet::new(); + opts.alphas = IndexSet::new(); opts.alphas.insert(AlphaOptim::Black); let output = OutFile::Path(Some( Path::new(input).with_extension("-white-out.png").to_owned(), @@ -329,7 +327,7 @@ fn issue_113_black() { let input = "tests/files/issue-113.png"; let (_, mut opts) = get_opts(Path::new(input)); opts.interlace = Some(1); - opts.alphas = HashSet::new(); + opts.alphas = IndexSet::new(); opts.alphas.insert(AlphaOptim::Black); let output = OutFile::Path(Some( Path::new(input).with_extension("-black-out.png").to_owned(), @@ -349,7 +347,7 @@ fn issue_113_right() { let input = "tests/files/issue-113.png"; let (_, mut opts) = get_opts(Path::new(input)); opts.interlace = Some(1); - opts.alphas = HashSet::new(); + opts.alphas = IndexSet::new(); opts.alphas.insert(AlphaOptim::Right); let output = OutFile::Path(Some( Path::new(input).with_extension("-right-out.png").to_owned(), @@ -369,7 +367,7 @@ fn issue_113_left() { let input = "tests/files/issue-113.png"; let (_, mut opts) = get_opts(Path::new(input)); opts.interlace = Some(1); - opts.alphas = HashSet::new(); + opts.alphas = IndexSet::new(); opts.alphas.insert(AlphaOptim::Left); let output = OutFile::Path(Some( Path::new(input).with_extension("-left-out.png").to_owned(), @@ -389,7 +387,7 @@ fn issue_113_up() { let input = "tests/files/issue-113.png"; let (_, mut opts) = get_opts(Path::new(input)); opts.interlace = Some(1); - opts.alphas = HashSet::new(); + opts.alphas = IndexSet::new(); opts.alphas.insert(AlphaOptim::Up); let output = OutFile::Path(Some( Path::new(input).with_extension("-up-out.png").to_owned(), @@ -409,7 +407,7 @@ fn issue_113_down() { let input = "tests/files/issue-113.png"; let (_, mut opts) = get_opts(Path::new(input)); opts.interlace = Some(1); - opts.alphas = HashSet::new(); + opts.alphas = IndexSet::new(); opts.alphas.insert(AlphaOptim::Down); let output = OutFile::Path(Some( Path::new(input).with_extension("-down-out.png").to_owned(), @@ -441,7 +439,7 @@ fn issue_129() { fn issue_133_black() { let input = "tests/files/issue-133.png"; let (_, mut opts) = get_opts(Path::new(input)); - opts.alphas = HashSet::new(); + opts.alphas = IndexSet::new(); opts.alphas.insert(AlphaOptim::Black); let output = OutFile::Path(Some( Path::new(input).with_extension("-black-out.png").to_owned(), @@ -460,7 +458,7 @@ fn issue_133_black() { fn issue_133_white() { let input = "tests/files/issue-133.png"; let (_, mut opts) = get_opts(Path::new(input)); - opts.alphas = HashSet::new(); + opts.alphas = IndexSet::new(); opts.alphas.insert(AlphaOptim::White); let output = OutFile::Path(Some( Path::new(input).with_extension("-white-out.png").to_owned(), @@ -479,7 +477,7 @@ fn issue_133_white() { fn issue_133_up() { let input = "tests/files/issue-133.png"; let (_, mut opts) = get_opts(Path::new(input)); - opts.alphas = HashSet::new(); + opts.alphas = IndexSet::new(); opts.alphas.insert(AlphaOptim::Up); let output = OutFile::Path(Some( Path::new(input).with_extension("-up-out.png").to_owned(), @@ -498,7 +496,7 @@ fn issue_133_up() { fn issue_133_down() { let input = "tests/files/issue-133.png"; let (_, mut opts) = get_opts(Path::new(input)); - opts.alphas = HashSet::new(); + opts.alphas = IndexSet::new(); opts.alphas.insert(AlphaOptim::Down); let output = OutFile::Path(Some( Path::new(input).with_extension("-down-out.png").to_owned(), @@ -517,7 +515,7 @@ fn issue_133_down() { fn issue_133_right() { let input = "tests/files/issue-133.png"; let (_, mut opts) = get_opts(Path::new(input)); - opts.alphas = HashSet::new(); + opts.alphas = IndexSet::new(); opts.alphas.insert(AlphaOptim::Right); let output = OutFile::Path(Some( Path::new(input).with_extension("-right-out.png").to_owned(), @@ -536,7 +534,7 @@ fn issue_133_right() { fn issue_133_left() { let input = "tests/files/issue-133.png"; let (_, mut opts) = get_opts(Path::new(input)); - opts.alphas = HashSet::new(); + opts.alphas = IndexSet::new(); opts.alphas.insert(AlphaOptim::Left); let output = OutFile::Path(Some( Path::new(input).with_extension("-left-out.png").to_owned(),