diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index ec3680a1..01ae14f8 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -11,7 +11,10 @@ jobs: strategy: matrix: - conf: [x86_64, i686] + conf: [x86_64] +# Temporarily disable i686 binaries, they are failing on linking libdeflate +# and I don't have a Windows machine set up to experiment with fixing it. +# conf: [x86_64, i686] runs-on: windows-latest diff --git a/CHANGELOG.md b/CHANGELOG.md index 66c8999d..813a9bc1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +### Version 4.0.3 +- Bump itertools to 0.10.x +- Temporarily disable i686 releases, which were failing due to an odd linker issue, + so that at least amd64 builds will publish successfully + - This only relates to the releases published on Github. You can still manually compile oxipng for any platform. + ### Version 4.0.2 - Includes another update to libdeflater that improves support for targets without a C stdlib, like wasm32. diff --git a/Cargo.lock b/Cargo.lock index cdcb1b03..c4feccdc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,9 +2,9 @@ # It is not intended for manual editing. [[package]] name = "adler" -version = "0.2.3" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee2a4ec343196209d6594e19543ae87a39f96d5534d7174822a3ad825dd6ed7e" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "adler32" @@ -58,27 +58,21 @@ checksum = "39092a32794787acd8525ee150305ff051b0aa6cc2abaf193924f5ab05425f39" [[package]] name = "bytemuck" -version = "1.4.1" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41aa2ec95ca3b5c54cf73c91acf06d24f4495d5f1b1c12506ae3483d646177ac" +checksum = "bed57e2090563b83ba8f83366628ce535a7584c9afa4c9fc0612a03925c6df58" [[package]] name = "byteorder" -version = "1.3.4" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" +checksum = "ae44d1a3d5a19df61dd0c8beb138458ac2a53a7ac09eba97d55592540004306b" [[package]] name = "cc" -version = "1.0.66" +version = "1.0.67" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c0496836a84f8d0495758516b8621a622beb77c0fed418570e50764093ced48" - -[[package]] -name = "cfg-if" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" +checksum = "e3c69b077ad434294d3ce9f1f6143a2a4b89a8a2d54ef813d85003a4fd1137fd" [[package]] name = "cfg-if" @@ -138,12 +132,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" -[[package]] -name = "const_fn" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd51eab21ab4fd6a3bf889e2d0958c0a6e3a61ad04260325e919e652a2a62826" - [[package]] name = "crc" version = "1.8.1" @@ -159,7 +147,7 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81156fece84ab6a9f2afdb109ce3ae577e42b1228441eded99bd77f627953b1a" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", ] [[package]] @@ -168,7 +156,7 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dca26ee1f8d361640700bde38b2c37d8c22b3ce2d360e1fc1c74ea4b0aa7d775" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "crossbeam-utils", ] @@ -178,19 +166,18 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94af6efb46fef72616855b036a624cf27ba656ffc9be1b9a3c931cfc7749a9a9" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "crossbeam-epoch", "crossbeam-utils", ] [[package]] name = "crossbeam-epoch" -version = "0.9.1" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1aaa739f95311c2c7887a76863f500026092fb1dce0161dab577e559ef3569d" +checksum = "2584f639eb95fea8c798496315b297cf81b9b58b6d30ab066a75455333cf4b12" dependencies = [ - "cfg-if 1.0.0", - "const_fn", + "cfg-if", "crossbeam-utils", "lazy_static", "memoffset", @@ -199,12 +186,12 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.1" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02d96d1e189ef58269ebe5b97953da3274d83a93af647c2ddd6f9dab28cedb8d" +checksum = "e7e9d99fa91428effe99c5c6d4634cdeba32b8cf784fc428a2a687f61a952c49" dependencies = [ "autocfg", - "cfg-if 1.0.0", + "cfg-if", "lazy_static", ] @@ -250,18 +237,18 @@ checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04" [[package]] name = "hermit-abi" -version = "0.1.17" +version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aca5565f760fb5b220e499d72710ed156fdb74e631659e99377d9ebfbd13ae8" +checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c" dependencies = [ "libc", ] [[package]] name = "image" -version = "0.23.12" +version = "0.23.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ce04077ead78e39ae8610ad26216aed811996b043d47beed5090db674f9e9b5" +checksum = "24ffcb7e7244a9bf19d35bf2883b9c080c4ced3c07a9895572178cdb8f13f6a1" dependencies = [ "bytemuck", "byteorder", @@ -285,9 +272,9 @@ dependencies = [ [[package]] name = "itertools" -version = "0.9.0" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b" +checksum = "37d572918e350e82412fe766d24b15e6682fb2ed2bbe018280caa810397cb319" dependencies = [ "either", ] @@ -300,9 +287,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.81" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1482821306169ec4d07f6aca392a4681f66c75c9918aa49641a2595db64053cb" +checksum = "265d751d31d6780a3f956bb5b8022feba2d94eeee5a84ba64f4212eedca42213" [[package]] name = "libdeflate-sys" @@ -324,11 +311,11 @@ dependencies = [ [[package]] name = "log" -version = "0.4.11" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b" +checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" dependencies = [ - "cfg-if 0.1.10", + "cfg-if", ] [[package]] @@ -351,9 +338,9 @@ dependencies = [ [[package]] name = "miniz_oxide" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f2d26ec3309788e423cfbf68ad1800f061638098d76a83681af979dc4eda19d" +checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b" dependencies = [ "adler", "autocfg", @@ -412,7 +399,7 @@ dependencies = [ [[package]] name = "oxipng" -version = "4.0.2" +version = "4.0.3" dependencies = [ "bit-vec", "byteorder", @@ -426,7 +413,7 @@ dependencies = [ "itertools", "libdeflater", "log", - "miniz_oxide 0.4.3", + "miniz_oxide 0.4.4", "rayon", "rgb", "rustc_version", @@ -498,9 +485,9 @@ dependencies = [ [[package]] name = "rustc_version" -version = "0.3.0" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65c94201b44764d6d1f7e37c15a8289ed55e546c1762c7f1d57f616966e0c181" +checksum = "f0dfe2087c51c460008730de8b57e6a320782fbfb312e1f4d520e6c6fae155ee" dependencies = [ "semver", ] @@ -522,18 +509,18 @@ dependencies = [ [[package]] name = "semver-parser" -version = "0.10.1" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ef146c2ad5e5f4b037cd6ce2ebb775401729b19a82040c1beac9d36c7d1428" +checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7" dependencies = [ "pest", ] [[package]] name = "stderrlog" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b02f316286ae558d83acc93dd81eaba096e746987a7961d4a9ae026842bae67f" +checksum = "45a53e2eff3e94a019afa6265e8ee04cb05b9d33fe9f5078b14e4e391d155a38" dependencies = [ "atty", "chrono", diff --git a/Cargo.toml b/Cargo.toml index f60bb5b0..fd4b63f3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,7 +16,7 @@ license = "MIT" name = "oxipng" repository = "https://github.com/shssoichiro/oxipng" build = "build.rs" -version = "4.0.2" +version = "4.0.3" [badges] travis-ci = { repository = "shssoichiro/oxipng", branch = "master" } @@ -30,16 +30,16 @@ required-features = ["binary"] [dependencies] bit-vec = "^0.6.3" -byteorder = "^1.0.0" +byteorder = "^1.4.2" crc = "^1.2.0" -itertools = "^0.9.0" +itertools = "^0.10.0" zopfli = { version = "^0.4.0", optional = true } miniz_oxide = "0.4" rgb = "0.8.25" indexmap = "1.6.1" libdeflater = { version = "0.7.1", optional = true } -log = "0.4.11" -stderrlog = { version = "0.5.0", optional = true } +log = "0.4.14" +stderrlog = { version = "0.5.1", optional = true } crossbeam-channel = "0.5.0" [dependencies.filetime] @@ -82,7 +82,12 @@ parallel = ["rayon", "indexmap/rayon"] [lib] name = "oxipng" path = "src/lib.rs" + [profile.dev] opt-level = 2 + [profile.release] lto = "thin" + +[profile.dev.package.bit-vec] +opt-level = 3 diff --git a/benches/reductions.rs b/benches/reductions.rs index e94d8280..30eebe17 100644 --- a/benches/reductions.rs +++ b/benches/reductions.rs @@ -80,7 +80,7 @@ fn reductions_rgba_to_rgb_16(b: &mut Bencher) { let input = test::black_box(PathBuf::from("tests/files/rgba_16_should_be_rgb_16.png")); let png = PngData::new(&input, false).unwrap(); - b.iter(|| reduce_color_type(&png.raw)); + b.iter(|| reduce_color_type(&png.raw, true)); } #[bench] @@ -88,7 +88,7 @@ fn reductions_rgba_to_rgb_8(b: &mut Bencher) { let input = test::black_box(PathBuf::from("tests/files/rgba_8_should_be_rgb_8.png")); let png = PngData::new(&input, false).unwrap(); - b.iter(|| reduce_color_type(&png.raw)); + b.iter(|| reduce_color_type(&png.raw, true)); } #[bench] @@ -98,7 +98,7 @@ fn reductions_rgba_to_grayscale_alpha_16(b: &mut Bencher) { )); let png = PngData::new(&input, false).unwrap(); - b.iter(|| reduce_color_type(&png.raw)); + b.iter(|| reduce_color_type(&png.raw, true)); } #[bench] @@ -108,7 +108,7 @@ fn reductions_rgba_to_grayscale_alpha_8(b: &mut Bencher) { )); let png = PngData::new(&input, false).unwrap(); - b.iter(|| reduce_color_type(&png.raw)); + b.iter(|| reduce_color_type(&png.raw, true)); } #[bench] @@ -118,7 +118,7 @@ fn reductions_rgba_to_grayscale_16(b: &mut Bencher) { )); let png = PngData::new(&input, false).unwrap(); - b.iter(|| reduce_color_type(&png.raw)); + b.iter(|| reduce_color_type(&png.raw, true)); } #[bench] @@ -128,7 +128,7 @@ fn reductions_rgba_to_grayscale_8(b: &mut Bencher) { )); let png = PngData::new(&input, false).unwrap(); - b.iter(|| reduce_color_type(&png.raw)); + b.iter(|| reduce_color_type(&png.raw, true)); } #[bench] @@ -138,7 +138,7 @@ fn reductions_rgb_to_grayscale_16(b: &mut Bencher) { )); let png = PngData::new(&input, false).unwrap(); - b.iter(|| reduce_color_type(&png.raw)); + b.iter(|| reduce_color_type(&png.raw, true)); } #[bench] @@ -146,7 +146,7 @@ fn reductions_rgb_to_grayscale_8(b: &mut Bencher) { let input = test::black_box(PathBuf::from("tests/files/rgb_8_should_be_grayscale_8.png")); let png = PngData::new(&input, false).unwrap(); - b.iter(|| reduce_color_type(&png.raw)); + b.iter(|| reduce_color_type(&png.raw, true)); } #[bench] @@ -154,7 +154,7 @@ fn reductions_rgba_to_palette_8(b: &mut Bencher) { let input = test::black_box(PathBuf::from("tests/files/rgba_8_should_be_palette_8.png")); let png = PngData::new(&input, false).unwrap(); - b.iter(|| reduce_color_type(&png.raw)); + b.iter(|| reduce_color_type(&png.raw, true)); } #[bench] @@ -162,7 +162,7 @@ fn reductions_rgb_to_palette_8(b: &mut Bencher) { let input = test::black_box(PathBuf::from("tests/files/rgb_8_should_be_palette_8.png")); let png = PngData::new(&input, false).unwrap(); - b.iter(|| reduce_color_type(&png.raw)); + b.iter(|| reduce_color_type(&png.raw, true)); } #[bench] diff --git a/package-lock.json b/package-lock.json index 1d65199e..f45ccc43 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,386 +1,1337 @@ { "name": "oxipng", "version": "1.0.0", - "lockfileVersion": 1, + "lockfileVersion": 2, "requires": true, - "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "packages": { + "": { + "version": "1.0.0", + "license": "ISC", + "devDependencies": { + "strip-ansi-cli": "^3.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.14.5.tgz", + "integrity": "sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.5.tgz", + "integrity": "sha512-5lsetuxCLilmVGyiLEfoHBRX8UCFD+1m2x3Rj97WrW3V7H3u4RWRXA4evMjImCsin2J2YT0QaVDGf+z8ondbAg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz", + "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.14.5", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@types/minimist": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.2.tgz", + "integrity": "sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==", "dev": true }, - "array-find-index": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", - "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=", + "node_modules/@types/normalize-package-data": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz", + "integrity": "sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==", "dev": true }, - "builtin-modules": { + "node_modules/ansi-regex": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.0.tgz", + "integrity": "sha512-tAaOSrWCHF+1Ear1Z4wnJCXA9GGox4K6Ic85a5qalES2aeEwQGr7UC93mwef49536PkCYjzkp0zIxfFvexJ6zQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase-keys": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.2.tgz", + "integrity": "sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==", + "dev": true, + "dependencies": { + "camelcase": "^5.3.1", + "map-obj": "^4.0.0", + "quick-lru": "^4.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/decamelize-keys": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.0.tgz", + "integrity": "sha1-0XGoeTMlKAfrPLYdwcFEXQeN8tk=", + "dev": true, + "dependencies": { + "decamelize": "^1.1.0", + "map-obj": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/decamelize-keys/node_modules/map-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", + "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/function-bind": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", - "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "node_modules/get-stdin": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-9.0.0.tgz", + "integrity": "sha512-dVKBjfWisLAicarI2Sf+JuBE/DghV4UzNAVe9yhEJuzeREd3JhOTE9cUaJTeSa77fsbQUK3pcOpJfM59+VKZaA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/hard-rejection": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz", + "integrity": "sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/hosted-git-info": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.0.2.tgz", + "integrity": "sha512-c9OGXbZ3guC/xOlCg1Ci/VgWlwsqDv1yMQL1CWqXDL0hDjXuNcq0zuR4xqPSuasI3kqFDhqSyTjREz5gzq0fXg==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "node_modules/is-core-module": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.4.0.tgz", + "integrity": "sha512-6A2fkfq1rfeQZjxrZJGerpLCTHRNEBiSgnu0+obeJpEPZRUooHgsizvzv0ZjJwOz3iWIHdJtVWJ/tmPr3D21/A==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-plain-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", + "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/lines-and-columns": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz", + "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=", + "dev": true + }, + "node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/map-obj": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.2.1.tgz", + "integrity": "sha512-+WA2/1sPmDj1dlvvJmB5G6JKfY9dpn7EVBUL06+y6PoljPkh+6V1QihwxNkbcGxCRjt2b0F9K0taiCuo7MbdFQ==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/meow": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/meow/-/meow-9.0.0.tgz", + "integrity": "sha512-+obSblOQmRhcyBt62furQqRAQpNyWXo8BuQ5bN7dG8wmwQ+vwHKp/rCFD4CrTP8CsDQD1sjoZ94K417XEUk8IQ==", + "dev": true, + "dependencies": { + "@types/minimist": "^1.2.0", + "camelcase-keys": "^6.2.2", + "decamelize": "^1.2.0", + "decamelize-keys": "^1.1.0", + "hard-rejection": "^2.1.0", + "minimist-options": "4.1.0", + "normalize-package-data": "^3.0.0", + "read-pkg-up": "^7.0.1", + "redent": "^3.0.0", + "trim-newlines": "^3.0.0", + "type-fest": "^0.18.0", + "yargs-parser": "^20.2.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/minimist-options": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-4.1.0.tgz", + "integrity": "sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==", + "dev": true, + "dependencies": { + "arrify": "^1.0.1", + "is-plain-obj": "^1.1.0", + "kind-of": "^6.0.3" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/normalize-package-data": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.2.tgz", + "integrity": "sha512-6CdZocmfGaKnIHPVFhJJZ3GuR8SsLKvDANFp47Jmy51aKIr8akjAWTSxtpI+MBgBFdSMRyo4hMpDlT6dTffgZg==", + "dev": true, + "dependencies": { + "hosted-git-info": "^4.0.1", + "resolve": "^1.20.0", + "semver": "^7.3.4", + "validate-npm-package-license": "^3.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/quick-lru": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz", + "integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/read-pkg": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", + "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", + "dev": true, + "dependencies": { + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^2.5.0", + "parse-json": "^5.0.0", + "type-fest": "^0.6.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/read-pkg-up": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", + "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", + "dev": true, + "dependencies": { + "find-up": "^4.1.0", + "read-pkg": "^5.2.0", + "type-fest": "^0.8.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/read-pkg-up/node_modules/type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/read-pkg/node_modules/hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true + }, + "node_modules/read-pkg/node_modules/normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "dependencies": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "node_modules/read-pkg/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/read-pkg/node_modules/type-fest": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/redent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", + "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", + "dev": true, + "dependencies": { + "indent-string": "^4.0.0", + "strip-indent": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve": { + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", + "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", + "dev": true, + "dependencies": { + "is-core-module": "^2.2.0", + "path-parse": "^1.0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/spdx-correct": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", + "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", + "dev": true, + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "dev": true + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.9.tgz", + "integrity": "sha512-Ki212dKK4ogX+xDo4CtOZBVIwhsKBEfsEEcwmJfLQzirgc2jIWdzg40Unxz/HzEUqM1WFzVlQSMF9kZZ2HboLQ==", + "dev": true + }, + "node_modules/strip-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.0.tgz", + "integrity": "sha512-UhDTSnGF1dc0DRbUqr1aXwNoY3RgVkSWG8BrpnuFIxhP57IqbS7IRta2Gfiavds4yCxc5+fEAVVOgBZWnYkvzg==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-ansi-cli": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi-cli/-/strip-ansi-cli-3.0.1.tgz", + "integrity": "sha512-iLTUGQ0XT0QM/MsG5MJzl91C48/NekgP1M5K41rDG+z1zvgsaXgwYnL0i7+a3JixnGmjWsqa9JpFY3q/Zn92Rg==", + "dev": true, + "dependencies": { + "get-stdin": "^9.0.0", + "meow": "^9.0.0", + "strip-ansi": "^7.0.0" + }, + "bin": { + "strip-ansi": "cli.js" + }, + "engines": { + "node": ">=12.17" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi-cli?sponsor=1" + } + }, + "node_modules/strip-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "dev": true, + "dependencies": { + "min-indent": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/trim-newlines": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz", + "integrity": "sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/type-fest": { + "version": "0.18.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.18.1.tgz", + "integrity": "sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true, + "engines": { + "node": ">=10" + } + } + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.14.5.tgz", + "integrity": "sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw==", + "dev": true, + "requires": { + "@babel/highlight": "^7.14.5" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.5.tgz", + "integrity": "sha512-5lsetuxCLilmVGyiLEfoHBRX8UCFD+1m2x3Rj97WrW3V7H3u4RWRXA4evMjImCsin2J2YT0QaVDGf+z8ondbAg==", + "dev": true + }, + "@babel/highlight": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz", + "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.14.5", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "@types/minimist": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.2.tgz", + "integrity": "sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==", + "dev": true + }, + "@types/normalize-package-data": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz", + "integrity": "sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==", + "dev": true + }, + "ansi-regex": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.0.tgz", + "integrity": "sha512-tAaOSrWCHF+1Ear1Z4wnJCXA9GGox4K6Ic85a5qalES2aeEwQGr7UC93mwef49536PkCYjzkp0zIxfFvexJ6zQ==", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", "dev": true }, "camelcase": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", - "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=", + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", "dev": true }, "camelcase-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", - "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=", + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.2.tgz", + "integrity": "sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==", "dev": true, "requires": { - "camelcase": "^2.0.0", - "map-obj": "^1.0.0" + "camelcase": "^5.3.1", + "map-obj": "^4.0.0", + "quick-lru": "^4.0.1" } }, - "currently-unhandled": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", - "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=", + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "dev": true, "requires": { - "array-find-index": "^1.0.1" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" } }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, "decamelize": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", "dev": true }, + "decamelize-keys": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.0.tgz", + "integrity": "sha1-0XGoeTMlKAfrPLYdwcFEXQeN8tk=", + "dev": true, + "requires": { + "decamelize": "^1.1.0", + "map-obj": "^1.0.0" + }, + "dependencies": { + "map-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", + "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", + "dev": true + } + } + }, "error-ex": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.1.tgz", - "integrity": "sha1-+FWobOYa3E6GIcPNoh56dhLDqNw=", + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", "dev": true, "requires": { "is-arrayish": "^0.2.1" } }, - "find-up": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", - "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", - "dev": true, - "requires": { - "path-exists": "^2.0.0", - "pinkie-promise": "^2.0.0" - } - }, - "get-stdin": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", - "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=", + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", "dev": true }, - "graceful-fs": { - "version": "4.1.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", - "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "get-stdin": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-9.0.0.tgz", + "integrity": "sha512-dVKBjfWisLAicarI2Sf+JuBE/DghV4UzNAVe9yhEJuzeREd3JhOTE9cUaJTeSa77fsbQUK3pcOpJfM59+VKZaA==", + "dev": true + }, + "hard-rejection": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz", + "integrity": "sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==", + "dev": true + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", "dev": true }, "hosted-git-info": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.5.0.tgz", - "integrity": "sha512-pNgbURSuab90KbTqvRPsseaTxOJCZBD0a7t+haSN33piP9cCM4l0CqdzAif2hUqm716UovKB2ROmiabGAKVXyg==", - "dev": true - }, - "indent-string": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz", - "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.0.2.tgz", + "integrity": "sha512-c9OGXbZ3guC/xOlCg1Ci/VgWlwsqDv1yMQL1CWqXDL0hDjXuNcq0zuR4xqPSuasI3kqFDhqSyTjREz5gzq0fXg==", "dev": true, "requires": { - "repeating": "^2.0.0" + "lru-cache": "^6.0.0" } }, + "indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true + }, "is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", "dev": true }, - "is-builtin-module": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", - "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", + "is-core-module": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.4.0.tgz", + "integrity": "sha512-6A2fkfq1rfeQZjxrZJGerpLCTHRNEBiSgnu0+obeJpEPZRUooHgsizvzv0ZjJwOz3iWIHdJtVWJ/tmPr3D21/A==", "dev": true, "requires": { - "builtin-modules": "^1.0.0" + "has": "^1.0.3" } }, - "is-finite": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz", - "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", - "dev": true, - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "is-utf8": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", - "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", + "is-plain-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", + "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=", "dev": true }, - "load-json-file": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", - "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true + }, + "lines-and-columns": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz", + "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=", + "dev": true + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", "dev": true, "requires": { - "graceful-fs": "^4.1.2", - "parse-json": "^2.2.0", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0", - "strip-bom": "^2.0.0" + "p-locate": "^4.1.0" } }, - "loud-rejection": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz", - "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=", + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dev": true, "requires": { - "currently-unhandled": "^0.4.1", - "signal-exit": "^3.0.0" + "yallist": "^4.0.0" } }, "map-obj": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", - "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.2.1.tgz", + "integrity": "sha512-+WA2/1sPmDj1dlvvJmB5G6JKfY9dpn7EVBUL06+y6PoljPkh+6V1QihwxNkbcGxCRjt2b0F9K0taiCuo7MbdFQ==", "dev": true }, "meow": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", - "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/meow/-/meow-9.0.0.tgz", + "integrity": "sha512-+obSblOQmRhcyBt62furQqRAQpNyWXo8BuQ5bN7dG8wmwQ+vwHKp/rCFD4CrTP8CsDQD1sjoZ94K417XEUk8IQ==", "dev": true, "requires": { - "camelcase-keys": "^2.0.0", - "decamelize": "^1.1.2", - "loud-rejection": "^1.0.0", - "map-obj": "^1.0.1", - "minimist": "^1.1.3", - "normalize-package-data": "^2.3.4", - "object-assign": "^4.0.1", - "read-pkg-up": "^1.0.1", - "redent": "^1.0.0", - "trim-newlines": "^1.0.0" + "@types/minimist": "^1.2.0", + "camelcase-keys": "^6.2.2", + "decamelize": "^1.2.0", + "decamelize-keys": "^1.1.0", + "hard-rejection": "^2.1.0", + "minimist-options": "4.1.0", + "normalize-package-data": "^3.0.0", + "read-pkg-up": "^7.0.1", + "redent": "^3.0.0", + "trim-newlines": "^3.0.0", + "type-fest": "^0.18.0", + "yargs-parser": "^20.2.3" } }, - "minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", "dev": true }, - "normalize-package-data": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", - "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==", + "minimist-options": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-4.1.0.tgz", + "integrity": "sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==", "dev": true, "requires": { - "hosted-git-info": "^2.1.4", - "is-builtin-module": "^1.0.0", - "semver": "2 || 3 || 4 || 5", + "arrify": "^1.0.1", + "is-plain-obj": "^1.1.0", + "kind-of": "^6.0.3" + } + }, + "normalize-package-data": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.2.tgz", + "integrity": "sha512-6CdZocmfGaKnIHPVFhJJZ3GuR8SsLKvDANFp47Jmy51aKIr8akjAWTSxtpI+MBgBFdSMRyo4hMpDlT6dTffgZg==", + "dev": true, + "requires": { + "hosted-git-info": "^4.0.1", + "resolve": "^1.20.0", + "semver": "^7.3.4", "validate-npm-package-license": "^3.0.1" } }, - "number-is-nan": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", - "dev": true + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } }, - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", "dev": true }, "parse-json": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", - "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", "dev": true, "requires": { - "error-ex": "^1.2.0" + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" } }, "path-exists": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", - "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", - "dev": true, - "requires": { - "pinkie-promise": "^2.0.0" - } - }, - "path-type": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", - "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0" - } - }, - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "dev": true }, - "pinkie": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", + "path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, - "pinkie-promise": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", - "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", - "dev": true, - "requires": { - "pinkie": "^2.0.0" - } + "quick-lru": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz", + "integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==", + "dev": true }, "read-pkg": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", - "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", + "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", "dev": true, "requires": { - "load-json-file": "^1.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^1.0.0" + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^2.5.0", + "parse-json": "^5.0.0", + "type-fest": "^0.6.0" + }, + "dependencies": { + "hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true + }, + "normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "requires": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + }, + "type-fest": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", + "dev": true + } } }, "read-pkg-up": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", - "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", + "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", "dev": true, "requires": { - "find-up": "^1.0.0", - "read-pkg": "^1.0.0" + "find-up": "^4.1.0", + "read-pkg": "^5.2.0", + "type-fest": "^0.8.1" + }, + "dependencies": { + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true + } } }, "redent": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz", - "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", + "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", "dev": true, "requires": { - "indent-string": "^2.1.0", - "strip-indent": "^1.0.1" + "indent-string": "^4.0.0", + "strip-indent": "^3.0.0" } }, - "repeating": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", - "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", + "resolve": { + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", + "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", "dev": true, "requires": { - "is-finite": "^1.0.0" + "is-core-module": "^2.2.0", + "path-parse": "^1.0.6" } }, "semver": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", - "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==", - "dev": true - }, - "signal-exit": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", - "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", - "dev": true - }, - "spdx-correct": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-1.0.2.tgz", - "integrity": "sha1-SzBz2TP/UfORLwOsVRlJikFQ20A=", + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", "dev": true, "requires": { - "spdx-license-ids": "^1.0.2" + "lru-cache": "^6.0.0" } }, - "spdx-expression-parse": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz", - "integrity": "sha1-m98vIOH0DtRH++JzJmGR/O1RYmw=", + "spdx-correct": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", + "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", + "dev": true, + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", "dev": true }, + "spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, "spdx-license-ids": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz", - "integrity": "sha1-yd96NCRZSt5r0RkA1ZZpbcBrrFc=", + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.9.tgz", + "integrity": "sha512-Ki212dKK4ogX+xDo4CtOZBVIwhsKBEfsEEcwmJfLQzirgc2jIWdzg40Unxz/HzEUqM1WFzVlQSMF9kZZ2HboLQ==", "dev": true }, "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.0.tgz", + "integrity": "sha512-UhDTSnGF1dc0DRbUqr1aXwNoY3RgVkSWG8BrpnuFIxhP57IqbS7IRta2Gfiavds4yCxc5+fEAVVOgBZWnYkvzg==", "dev": true, "requires": { - "ansi-regex": "^3.0.0" + "ansi-regex": "^6.0.0" } }, "strip-ansi-cli": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi-cli/-/strip-ansi-cli-2.0.0.tgz", - "integrity": "sha1-D91Cq86DJTm/cv+ROSpxqzVGIIw=", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi-cli/-/strip-ansi-cli-3.0.1.tgz", + "integrity": "sha512-iLTUGQ0XT0QM/MsG5MJzl91C48/NekgP1M5K41rDG+z1zvgsaXgwYnL0i7+a3JixnGmjWsqa9JpFY3q/Zn92Rg==", "dev": true, "requires": { - "meow": "^3.7.0", - "strip-ansi": "^4.0.0" - } - }, - "strip-bom": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", - "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", - "dev": true, - "requires": { - "is-utf8": "^0.2.0" + "get-stdin": "^9.0.0", + "meow": "^9.0.0", + "strip-ansi": "^7.0.0" } }, "strip-indent": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz", - "integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", "dev": true, "requires": { - "get-stdin": "^4.0.1" + "min-indent": "^1.0.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" } }, "trim-newlines": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz", - "integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz", + "integrity": "sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==", + "dev": true + }, + "type-fest": { + "version": "0.18.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.18.1.tgz", + "integrity": "sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==", "dev": true }, "validate-npm-package-license": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz", - "integrity": "sha1-KAS6vnEq0zeUWaz74kdGqywwP7w=", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", "dev": true, "requires": { - "spdx-correct": "~1.0.0", - "spdx-expression-parse": "~1.0.0" + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true } } } diff --git a/package.json b/package.json index 59339f1b..7b2d35f6 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,6 @@ }, "homepage": "https://github.com/shssoichiro/oxipng#readme", "devDependencies": { - "strip-ansi-cli": "^2.0.0" + "strip-ansi-cli": "^3.0.0" } } diff --git a/src/atomicmin.rs b/src/atomicmin.rs index af2287a9..73c3d997 100644 --- a/src/atomicmin.rs +++ b/src/atomicmin.rs @@ -9,13 +9,13 @@ pub struct AtomicMin { impl AtomicMin { pub fn new(init: Option) -> Self { Self { - val: AtomicUsize::new(init.unwrap_or(usize::max_value())), + val: AtomicUsize::new(init.unwrap_or(usize::MAX)), } } pub fn get(&self) -> Option { let val = self.val.load(SeqCst); - if val == usize::max_value() { + if val == usize::MAX { None } else { Some(val) diff --git a/src/colors.rs b/src/colors.rs index f5fe57ec..ae698dca 100644 --- a/src/colors.rs +++ b/src/colors.rs @@ -101,6 +101,10 @@ impl BitDepth { } } /// Parse a number of bits per channel per pixel into a `BitDepth` + /// + /// # Panics + /// + /// If depth is unsupported #[inline] pub fn from_u8(depth: u8) -> BitDepth { match depth { diff --git a/src/error.rs b/src/error.rs index 0198379f..0f099d5d 100644 --- a/src/error.rs +++ b/src/error.rs @@ -14,15 +14,11 @@ pub enum PngError { Other(Box), } -impl Error for PngError { - // deprecated - fn description(&self) -> &str { - "" - } -} +impl Error for PngError {} impl fmt::Display for PngError { #[inline] + #[cold] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { PngError::DeflatedDataTooLong(_) => f.write_str("deflated data too long"), @@ -40,7 +36,7 @@ impl fmt::Display for PngError { } impl PngError { - #[inline] + #[cold] pub fn new(description: &str) -> PngError { PngError::Other(description.into()) } diff --git a/src/filters.rs b/src/filters.rs index 54b9bb63..c0c10b10 100644 --- a/src/filters.rs +++ b/src/filters.rs @@ -1,4 +1,8 @@ +use crate::error::PngError; + pub fn filter_line(filter: u8, bpp: usize, data: &[u8], last_line: &[u8], buf: &mut Vec) { + assert!(data.len() >= bpp); + assert!(last_line.is_empty() || data.len() == last_line.len()); buf.reserve(data.len()); match filter { 0 => { @@ -17,6 +21,7 @@ pub fn filter_line(filter: u8, bpp: usize, data: &[u8], last_line: &[u8], buf: & if last_line.is_empty() { buf.extend_from_slice(data); } else { + assert_eq!(data.len(), last_line.len()); buf.extend( data.iter() .zip(last_line.iter()) @@ -62,95 +67,64 @@ pub fn filter_line(filter: u8, bpp: usize, data: &[u8], last_line: &[u8], buf: & } } -pub fn unfilter_line(filter: u8, bpp: usize, data: &[u8], last_line: &[u8], buf: &mut Vec) { - assert_eq!(buf.len(), 0); +pub fn unfilter_line( + filter: u8, + bpp: usize, + data: &[u8], + last_line: &[u8], + buf: &mut Vec, +) -> Result<(), PngError> { + buf.clear(); buf.reserve(data.len()); + assert!(data.len() >= bpp); + assert_eq!(data.len(), last_line.len()); match filter { 0 => { buf.extend_from_slice(data); } 1 => { - for (i, byte) in data.iter().enumerate() { - match i.checked_sub(bpp) { - Some(x) => { - let b = buf[x]; - buf.push(byte.wrapping_add(b)); - } - None => { - buf.push(*byte); - } - }; + for (i, &cur) in data.iter().enumerate() { + let prev_byte = i.checked_sub(bpp).and_then(|x| buf.get(x).copied()); + buf.push(match prev_byte { + Some(b) => cur.wrapping_add(b), + None => cur, + }); } } 2 => { - if last_line.is_empty() { - buf.extend_from_slice(data); - } else { - buf.extend( - data.iter() - .zip(last_line.iter()) - .map(|(cur, last)| cur.wrapping_add(*last)), - ); - }; + buf.extend( + data.iter() + .zip(last_line) + .map(|(&cur, &last)| cur.wrapping_add(last)), + ); } 3 => { - for (i, byte) in data.iter().enumerate() { - if last_line.is_empty() { - match i.checked_sub(bpp) { - Some(x) => { - let b = buf[x]; - buf.push(byte.wrapping_add(b >> 1)); - } - None => { - buf.push(*byte); - } - }; - } else { - match i.checked_sub(bpp) { - Some(x) => { - let b = buf[x]; - buf.push(byte.wrapping_add( - ((u16::from(b) + u16::from(last_line[i])) >> 1) as u8, - )); - } - None => { - buf.push(byte.wrapping_add(last_line[i] >> 1)); - } - }; - }; + for (i, (&cur, &last)) in data.iter().zip(last_line).enumerate() { + let prev_byte = i.checked_sub(bpp).and_then(|x| buf.get(x).copied()); + buf.push(match prev_byte { + Some(b) => cur.wrapping_add(((u16::from(b) + u16::from(last)) >> 1) as u8), + None => cur.wrapping_add(last >> 1), + }); } } 4 => { - for (i, byte) in data.iter().enumerate() { - if last_line.is_empty() { - match i.checked_sub(bpp) { - Some(x) => { - let b = buf[x]; - buf.push(byte.wrapping_add(b)); + for (i, (&cur, &up)) in data.iter().zip(last_line).enumerate() { + buf.push( + match i + .checked_sub(bpp) + .map(|x| (buf.get(x).copied(), last_line.get(x).copied())) + { + Some((Some(left), Some(left_up))) => { + cur.wrapping_add(paeth_predictor(left, up, left_up)) } - None => { - buf.push(*byte); - } - }; - } else { - match i.checked_sub(bpp) { - Some(x) => { - let b = buf[x]; - buf.push(byte.wrapping_add(paeth_predictor( - b, - last_line[i], - last_line[x], - ))); - } - None => { - buf.push(byte.wrapping_add(last_line[i])); - } - }; - }; + _ => cur.wrapping_add(up), + }, + ); } } - _ => unreachable!(), + _ => return Err(PngError::InvalidData), } + Ok(()) } fn paeth_predictor(a: u8, b: u8, c: u8) -> u8 { diff --git a/src/headers.rs b/src/headers.rs index 0695bd0e..be0381d9 100644 --- a/src/headers.rs +++ b/src/headers.rs @@ -25,6 +25,45 @@ pub struct IhdrData { pub interlaced: u8, } +impl IhdrData { + /// Bits per pixel + #[must_use] + #[inline] + pub fn bpp(&self) -> u8 { + self.bit_depth.as_u8() * self.color_type.channels_per_pixel() + } + + /// Byte length of IDAT that is correct for this IHDR + #[must_use] + pub fn raw_data_size(&self) -> usize { + let w = self.width as usize; + let h = self.height as usize; + let bpp = self.bpp(); + + fn bitmap_size(bpp: u8, w: usize, h: usize) -> usize { + (((w / 8) * bpp as usize) + ((w & 7) * bpp as usize + 7) / 8) * h + } + + if self.interlaced == 0 { + bitmap_size(bpp, w, h) + h + } else { + let mut size = bitmap_size(bpp, (w + 7) >> 3, (h + 7) >> 3) + ((h + 7) >> 3); + if w > 4 { + size += bitmap_size(bpp, (w + 3) >> 3, (h + 7) >> 3) + ((h + 7) >> 3); + } + size += bitmap_size(bpp, (w + 3) >> 2, (h + 3) >> 3) + ((h + 3) >> 3); + if w > 2 { + size += bitmap_size(bpp, (w + 1) >> 2, (h + 3) >> 2) + ((h + 3) >> 2); + } + size += bitmap_size(bpp, (w + 1) >> 1, (h + 1) >> 2) + ((h + 1) >> 2); + if w > 1 { + size += bitmap_size(bpp, w >> 1, (h + 1) >> 1) + ((h + 1) >> 1); + } + size + bitmap_size(bpp, w, h >> 1) + (h >> 1) + } + } +} + #[derive(Debug, PartialEq, Clone)] /// Options to use for performing operations on headers (such as stripping) pub enum Headers { @@ -98,12 +137,14 @@ pub fn parse_next_header<'a>( ))); } - let mut name = [0u8; 4]; + let mut name = [0_u8; 4]; name.copy_from_slice(chunk_name); Ok(Some(RawHeader { name, data })) } pub fn parse_ihdr_header(byte_data: &[u8]) -> PngResult { + // This eliminates bounds checks for the rest of the function + let interlaced = byte_data.get(12).copied().ok_or(PngError::TruncatedData)?; let mut rdr = Cursor::new(&byte_data[0..8]); Ok(IhdrData { color_type: match byte_data[9] { @@ -122,10 +163,14 @@ pub fn parse_ihdr_header(byte_data: &[u8]) -> PngResult { 16 => BitDepth::Sixteen, _ => return Err(PngError::new("Unexpected bit depth in header")), }, - width: rdr.read_u32::().unwrap(), - height: rdr.read_u32::().unwrap(), + width: rdr + .read_u32::() + .map_err(|_| PngError::TruncatedData)?, + height: rdr + .read_u32::() + .map_err(|_| PngError::TruncatedData)?, compression: byte_data[10], filter: byte_data[11], - interlaced: byte_data[12], + interlaced, }) } diff --git a/src/interlace.rs b/src/interlace.rs index 2d391934..81928c7d 100644 --- a/src/interlace.rs +++ b/src/interlace.rs @@ -5,7 +5,7 @@ use bit_vec::BitVec; #[must_use] pub fn interlace_image(png: &PngImage) -> PngImage { let mut passes: Vec = vec![BitVec::new(); 7]; - let bits_per_pixel = png.ihdr.bit_depth.as_u8() * png.channels_per_pixel(); + let bits_per_pixel = png.ihdr.bpp(); for (index, line) in png.scan_lines().enumerate() { match index % 8 { // Add filter bytes to passes that will be in the output image @@ -40,7 +40,7 @@ pub fn interlace_image(png: &PngImage) -> PngImage { passes[6].extend(BitVec::from_elem(8, false)); } } - let bit_vec = BitVec::from_bytes(&line.data); + let bit_vec = BitVec::from_bytes(line.data); for (i, bit) in bit_vec.iter().enumerate() { // Avoid moving padded 0's into new image if i >= (png.ihdr.width * u32::from(bits_per_pixel)) as usize { @@ -95,7 +95,7 @@ pub fn interlace_image(png: &PngImage) -> PngImage { } pub fn deinterlace_image(png: &PngImage) -> PngImage { - let bits_per_pixel = png.ihdr.bit_depth.as_u8() * png.channels_per_pixel(); + let bits_per_pixel = png.ihdr.bpp(); let bits_per_line = 8 + bits_per_pixel as usize * png.ihdr.width as usize; // Initialize each output line with a starting filter byte of 0 // as well as some blank data @@ -105,7 +105,7 @@ pub fn deinterlace_image(png: &PngImage) -> PngImage { 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 bit_vec = BitVec::from_bytes(line.data); let bits_in_line = ((png.ihdr.width - u32::from(pass_constants.x_shift) + u32::from(pass_constants.x_step) - 1) diff --git a/src/lib.rs b/src/lib.rs index 867490f5..5dbc94c9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -12,6 +12,7 @@ #![warn(clippy::path_buf_push_overwrite)] #![warn(clippy::range_plus_one)] #![allow(clippy::cognitive_complexity)] +#![allow(clippy::upper_case_acronyms)] #![cfg_attr( not(any(feature = "libdeflater", feature = "zopfli")), allow(irrefutable_let_patterns), @@ -97,7 +98,7 @@ impl InFile { pub fn path(&self) -> Option<&Path> { match *self { InFile::Path(ref p) => Some(p.as_path()), - _ => None, + InFile::StdIn => None, } } } @@ -168,6 +169,10 @@ pub struct Options { /// /// Default: `true` pub palette_reduction: bool, + /// Whether to attempt grayscale reduction + /// + /// Default: `true` + pub grayscale_reduction: bool, /// Whether to perform IDAT recoding /// /// If any type of reduction is performed, IDAT recoding will be performed @@ -304,6 +309,7 @@ impl Default for Options { bit_depth_reduction: true, color_type_reduction: true, palette_reduction: true, + grayscale_reduction: true, idat_recoding: true, strip: Headers::None, deflate: Deflaters::Zlib { @@ -616,7 +622,7 @@ fn optimize_png( ); return None; } - _ => return None, + Err(_) => return None, }; // update best size across all threads @@ -682,14 +688,14 @@ fn optimize_png( " 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 + (file_original_size - output.len()) as f64 / file_original_size as f64 * 100_f64 ); } else { info!( " 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 + (output.len() - file_original_size) as f64 / file_original_size as f64 * 100_f64 ); } @@ -767,7 +773,7 @@ fn perform_reductions( } if opts.color_type_reduction { - if let Some(reduced) = reduce_color_type(&png) { + if let Some(reduced) = reduce_color_type(&png, opts.grayscale_reduction) { png = Arc::new(reduced); eval.try_image(png.clone()); report_reduction(&png); @@ -812,10 +818,14 @@ impl Deadline { if let Some(imp) = &self.imp { let elapsed = imp.start.elapsed(); if elapsed > imp.timeout { - if imp - .print_message - .compare_and_swap(true, false, Ordering::SeqCst) - { + if match imp.print_message.compare_exchange( + true, + false, + Ordering::SeqCst, + Ordering::SeqCst, + ) { + Ok(x) | Err(x) => x, + } { warn!("Timed out after {} second(s)", elapsed.as_secs()); } return true; diff --git a/src/main.rs b/src/main.rs index 20c8f16b..1a269dd4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -184,6 +184,9 @@ fn main() { .arg(Arg::with_name("no-palette-reduction") .help("No palette reduction") .long("np")) + .arg(Arg::with_name("no-grayscale-reduction") + .help("No grayscale reduction") + .long("ng")) .arg(Arg::with_name("no-reductions") .help("No reductions") .long("nx")) @@ -433,10 +436,15 @@ fn parse_opts_into_struct( opts.palette_reduction = false; } + if matches.is_present("no-grayscale-reduction") { + opts.grayscale_reduction = false; + } + if matches.is_present("no-reductions") { opts.bit_depth_reduction = false; opts.color_type_reduction = false; opts.palette_reduction = false; + opts.grayscale_reduction = false; } if matches.is_present("no-recoding") { diff --git a/src/png/mod.rs b/src/png/mod.rs index f2aa30b9..2ae3b116 100644 --- a/src/png/mod.rs +++ b/src/png/mod.rs @@ -100,7 +100,7 @@ impl PngData { let mut idat_headers: Vec = Vec::new(); while let Some(header) = parse_next_header(byte_data, &mut byte_offset, fix_errors)? { match &header.name { - b"IDAT" => idat_headers.extend(header.data), + b"IDAT" => idat_headers.extend_from_slice(header.data), b"acTL" => return Err(PngError::APNGNotSupported), _ => { aux_headers.insert(header.name, header.data.to_owned()); @@ -118,6 +118,11 @@ impl PngData { let ihdr_header = parse_ihdr_header(&ihdr)?; let raw_data = deflate::inflate(idat_headers.as_ref())?; + // Reject files with incorrect width/height or truncated data + if raw_data.len() != ihdr_header.raw_data_size() { + return Err(PngError::TruncatedData); + } + let (palette, transparency_pixel) = Self::palette_to_rgba( ihdr_header.color_type, aux_headers.remove(b"PLTE"), @@ -131,7 +136,7 @@ impl PngData { transparency_pixel, aux_headers, }; - raw.data = raw.unfilter_image(); + raw.data = raw.unfilter_image()?; // Return the PngData Ok(Self { idat_data: idat_headers, @@ -203,10 +208,10 @@ impl PngData { .fold( 0, |prev, (index, px)| { - if px.a != 255 { - index + 1 - } else { + if px.a == 255 { prev + } else { + index + 1 } }, ); @@ -276,32 +281,25 @@ impl PngImage { } /// Reverse all filters applied on the image, returning an unfiltered IDAT bytestream - fn unfilter_image(&self) -> Vec { + fn unfilter_image(&self) -> Result, PngError> { let mut unfiltered = Vec::with_capacity(self.data.len()); let bpp = ((self.ihdr.bit_depth.as_u8() * self.channels_per_pixel() + 7) / 8) as usize; let mut last_line: Vec = Vec::new(); - let mut last_pass = 1; + let mut last_pass = None; let mut unfiltered_buf = Vec::new(); for line in self.scan_lines() { - if let Some(pass) = line.pass { - if pass != last_pass { - last_line.clear(); - last_pass = pass; - } + if last_pass != line.pass { + last_line.clear(); + last_pass = line.pass; } - unfilter_line( - line.filter, - bpp, - &line.data, - &last_line, - &mut unfiltered_buf, - ); + last_line.resize(line.data.len(), 0); + unfilter_line(line.filter, bpp, line.data, &last_line, &mut unfiltered_buf)?; unfiltered.push(0); unfiltered.extend_from_slice(&unfiltered_buf); std::mem::swap(&mut last_line, &mut unfiltered_buf); unfiltered_buf.clear(); } - unfiltered + Ok(unfiltered) } /// Apply the specified filter type to all rows in the image @@ -319,6 +317,9 @@ impl PngImage { let mut f_buf = Vec::new(); for line in self.scan_lines() { f_buf.clear(); + if last_pass != line.pass { + last_line = &[]; + } match filter { 0 | 1 | 2 | 3 | 4 => { let filter = if last_pass == line.pass || filter <= 1 { @@ -327,7 +328,7 @@ impl PngImage { 0 }; filtered.push(filter); - filter_line(filter, bpp, &line.data, last_line, &mut f_buf); + filter_line(filter, bpp, line.data, last_line, &mut f_buf); filtered.extend_from_slice(&f_buf); } 5 => { @@ -336,12 +337,12 @@ impl PngImage { // http://www.libpng.org/pub/png/book/chapter09.html let mut best_filter = 0; let mut best_line = Vec::new(); - let mut best_size = std::u64::MAX; + let mut best_size = u64::MAX; // Avoid vertical filtering on first line of each interlacing pass for filter in if last_pass == line.pass { 0..5 } else { 0..2 } { - filter_line(filter, bpp, &line.data, last_line, &mut f_buf); - let size = f_buf.iter().fold(0u64, |acc, &x| { + filter_line(filter, bpp, line.data, last_line, &mut f_buf); + let size = f_buf.iter().fold(0_u64, |acc, &x| { let signed = x as i8; acc + i16::from(signed).abs() as u64 }); diff --git a/src/png/scan_lines.rs b/src/png/scan_lines.rs index dc923cca..2a13941f 100644 --- a/src/png/scan_lines.rs +++ b/src/png/scan_lines.rs @@ -1,7 +1,7 @@ use crate::png::PngImage; -#[derive(Debug, Clone)] /// An iterator over the scan lines of a PNG image +#[derive(Debug, Clone)] pub struct ScanLines<'a> { iter: ScanLineRanges, /// A reference to the PNG image being iterated upon @@ -167,8 +167,7 @@ impl Iterator for ScanLineRanges { let bits_per_line = pixels_per_line * u32::from(self.bits_per_pixel); let bytes_per_line = ((bits_per_line + 7) / 8) as usize; let len = bytes_per_line + 1; - assert!(self.left >= len); - self.left -= len; + self.left = self.left.checked_sub(len)?; Some((len, current_pass)) } } diff --git a/src/rayon.rs b/src/rayon.rs index c0ffd8c5..768db04c 100644 --- a/src/rayon.rs +++ b/src/rayon.rs @@ -10,11 +10,7 @@ pub trait ParallelIterator: Iterator + Sized { where OP: Fn(Self::Item, Self::Item) -> Self::Item + Sync, { - if let Some(a) = self.next() { - Some(self.fold(a, op)) - } else { - None - } + self.next().map(|a| self.fold(a, op)) } } diff --git a/src/reduction/alpha.rs b/src/reduction/alpha.rs index cd25a81a..9190672b 100644 --- a/src/reduction/alpha.rs +++ b/src/reduction/alpha.rs @@ -185,7 +185,9 @@ pub fn reduced_alpha_channel(png: &PngImage) -> Option { let channels = png.channels_per_pixel(); let bpp = channels * byte_depth; let bpp_mask = bpp - 1; - assert_eq!(0, bpp & bpp_mask); + if 0 != bpp & bpp_mask { + return None; + } let colored_bytes = bpp - byte_depth; for line in png.scan_lines() { for (i, &byte) in line.data.iter().enumerate() { diff --git a/src/reduction/bit_depth.rs b/src/reduction/bit_depth.rs index 24cb1e3d..12c837f6 100644 --- a/src/reduction/bit_depth.rs +++ b/src/reduction/bit_depth.rs @@ -74,8 +74,7 @@ pub fn reduce_bit_depth(png: &PngImage, minimum_bits: usize) -> Option #[must_use] pub fn reduce_bit_depth_8_or_less(png: &PngImage, mut minimum_bits: usize) -> Option { - assert!(minimum_bits >= 1 && minimum_bits < 8); - let mut reduced = BitVec::with_capacity(png.data.len() * 8); + assert!((1..8).contains(&minimum_bits)); let bit_depth: usize = png.ihdr.bit_depth.as_u8() as usize; if minimum_bits >= bit_depth { return None; @@ -109,7 +108,7 @@ pub fn reduce_bit_depth_8_or_less(png: &PngImage, mut minimum_bits: usize) -> Op } } } else { - let bit_vec = BitVec::from_bytes(&line.data); + let bit_vec = BitVec::from_bytes(line.data); for byte in bit_vec.to_bytes() { while minimum_bits < bit_depth { let permutations: &[u8] = if minimum_bits == 1 { @@ -123,17 +122,17 @@ pub fn reduce_bit_depth_8_or_less(png: &PngImage, mut minimum_bits: usize) -> Op }; if permutations.iter().any(|perm| *perm == byte) { break; - } else { - minimum_bits <<= 1; } + minimum_bits <<= 1; } } } } + let mut reduced = BitVec::with_capacity(png.data.len() * 8); for line in png.scan_lines() { reduced.extend(BitVec::from_bytes(&[line.filter])); - let bit_vec = BitVec::from_bytes(&line.data); + let bit_vec = BitVec::from_bytes(line.data); for (i, bit) in bit_vec.iter().enumerate() { let bit_index = bit_depth - (i % bit_depth); if bit_index <= minimum_bits { diff --git a/src/reduction/color.rs b/src/reduction/color.rs index 8be17402..11686fc6 100644 --- a/src/reduction/color.rs +++ b/src/reduction/color.rs @@ -12,7 +12,9 @@ pub fn reduce_rgba_to_grayscale_alpha(png: &PngImage) -> Option { let byte_depth = png.ihdr.bit_depth.as_u8() >> 3; let bpp = 4 * byte_depth; let bpp_mask = bpp - 1; - assert_eq!(0, bpp & bpp_mask); + if 0 != bpp & bpp_mask { + return None; + } let colored_bytes = bpp - byte_depth; for line in png.scan_lines() { reduced.push(line.filter); @@ -109,6 +111,7 @@ pub fn reduced_color_to_palette(png: &PngImage) -> Option { let transparency_pixel = png .transparency_pixel .as_ref() + .filter(|t| png.ihdr.color_type == ColorType::RGB && t.len() >= 6) .map(|t| RGB8::new(t[1], t[3], t[5])); for line in png.scan_lines() { raw_data.push(line.filter); @@ -147,7 +150,7 @@ pub fn reduced_color_to_palette(png: &PngImage) -> Option { } }) .max(); - let trns_size = num_transparent.map(|n| n + 8).unwrap_or(0); + let trns_size = num_transparent.map_or(0, |n| n + 8); let headers_size = palette.len() * 3 + 8 + trns_size; if raw_data.len() + headers_size > png.data.len() { @@ -157,7 +160,10 @@ pub fn reduced_color_to_palette(png: &PngImage) -> Option { let mut aux_headers = png.aux_headers.clone(); if let Some(bkgd_header) = png.aux_headers.get(b"bKGD") { - assert_eq!(bkgd_header.len(), 6); + if bkgd_header.len() != 6 { + // malformed chunk? + return None; + } // In bKGD 16-bit values are used even for 8-bit images let bg = RGBA8::new(bkgd_header[1], bkgd_header[3], bkgd_header[5], 255); let entry = if let Some(&entry) = palette.get(&bg) { diff --git a/src/reduction/mod.rs b/src/reduction/mod.rs index 1b9f7fc7..6b89b839 100644 --- a/src/reduction/mod.rs +++ b/src/reduction/mod.rs @@ -6,9 +6,9 @@ use rgb::RGBA8; use std::borrow::Cow; pub mod alpha; -use crate::alpha::*; +use crate::alpha::reduced_alpha_channel; pub mod bit_depth; -use crate::bit_depth::*; +use crate::bit_depth::reduce_bit_depth_8_or_less; pub mod color; use crate::color::*; @@ -17,7 +17,6 @@ pub(crate) use crate::bit_depth::reduce_bit_depth; /// Attempt to reduce the number of colors in the palette /// Returns `None` if palette hasn't changed -#[must_use] pub fn reduced_palette(png: &PngImage) -> Option { if png.ihdr.color_type != ColorType::Indexed { // Can't reduce if there is no palette @@ -70,14 +69,14 @@ pub fn reduced_palette(png: &PngImage) -> Option { .unwrap_or_else(|| RGBA8::new(0, 0, 0, 255)); ((color.a as i32) << 18) // These are coefficients for standard sRGB to luma conversion - - (color.r as i32) * 299 - - (color.g as i32) * 587 - - (color.b as i32) * 114 + - i32::from(color.r) * 299 + - i32::from(color.g) * 587 + - i32::from(color.b) * 114 }; color_val(a.0).cmp(&color_val(b.0)) }); - let mut next_index = 0u16; + let mut next_index = 0_u16; let mut seen = IndexMap::with_capacity(palette.len()); for (i, used) in used_enumerated.iter().cloned() { if !used { @@ -138,33 +137,33 @@ fn do_palette_reduction(png: &PngImage, palette_map: &[Option; 256]) -> Opti } fn palette_map_to_byte_map(png: &PngImage, palette_map: &[Option; 256]) -> Option<[u8; 256]> { - let len = png.palette.as_ref().map(|p| p.len()).unwrap_or(0); + let len = png.palette.as_ref().map_or(0, |p| p.len()); if (0..len).all(|i| palette_map[i].map_or(true, |to| to == i as u8)) { // No reduction necessary return None; } - let mut byte_map = [0u8; 256]; + let mut byte_map = [0_u8; 256]; // low bit-depths can be pre-computed for every byte value match png.ihdr.bit_depth { BitDepth::Eight => { - for byte in 0..=255 { - byte_map[byte as usize] = palette_map[byte as usize].unwrap_or(0) + for byte in 0..=255usize { + byte_map[byte] = palette_map[byte].unwrap_or(0) } } BitDepth::Four => { - for byte in 0..=255 { - byte_map[byte as usize] = palette_map[(byte & 0x0F) as usize].unwrap_or(0) - | (palette_map[(byte >> 4) as usize].unwrap_or(0) << 4); + for byte in 0..=255usize { + byte_map[byte] = palette_map[(byte & 0x0F)].unwrap_or(0) + | (palette_map[(byte >> 4)].unwrap_or(0) << 4); } } BitDepth::Two => { - for byte in 0..=255 { - byte_map[byte as usize] = palette_map[(byte & 0x03) as usize].unwrap_or(0) - | (palette_map[((byte >> 2) & 0x03) as usize].unwrap_or(0) << 2) - | (palette_map[((byte >> 4) & 0x03) as usize].unwrap_or(0) << 4) - | (palette_map[(byte >> 6) as usize].unwrap_or(0) << 6); + for byte in 0..=255usize { + byte_map[byte] = palette_map[(byte & 0x03)].unwrap_or(0) + | (palette_map[((byte >> 2) & 0x03)].unwrap_or(0) << 2) + | (palette_map[((byte >> 4) & 0x03)].unwrap_or(0) << 4) + | (palette_map[(byte >> 6)].unwrap_or(0) << 6); } } _ => {} @@ -174,12 +173,7 @@ fn palette_map_to_byte_map(png: &PngImage, palette_map: &[Option; 256]) -> O } fn reordered_palette(palette: &[RGBA8], palette_map: &[Option; 256]) -> Vec { - let max_index = palette_map - .iter() - .cloned() - .filter_map(|x| x) - .max() - .unwrap_or(0) as usize; + let max_index = palette_map.iter().cloned().flatten().max().unwrap_or(0) as usize; let mut new_palette = vec![RGBA8::new(0, 0, 0, 255); max_index + 1]; for (&color, &map_to) in palette.iter().zip(palette_map.iter()) { if let Some(map_to) = map_to { @@ -191,15 +185,19 @@ fn reordered_palette(palette: &[RGBA8], palette_map: &[Option; 256]) -> Vec< /// Attempt to reduce the color type of the image /// Returns true if the color type was reduced, false otherwise -pub fn reduce_color_type(png: &PngImage) -> Option { +pub fn reduce_color_type(png: &PngImage, grayscale_reduction: bool) -> Option { let mut should_reduce_bit_depth = false; let mut reduced = Cow::Borrowed(png); // Go down one step at a time // Maybe not the most efficient, but it's safe if reduced.ihdr.color_type == ColorType::RGBA { - if let Some(r) = - reduce_rgba_to_grayscale_alpha(&reduced).or_else(|| reduced_alpha_channel(&reduced)) + if let Some(r) = if grayscale_reduction { + reduce_rgba_to_grayscale_alpha(&reduced) + } else { + None + } + .or_else(|| reduced_alpha_channel(&reduced)) { reduced = Cow::Owned(r); } else if let Some(r) = reduced_color_to_palette(&reduced) { @@ -216,8 +214,12 @@ pub fn reduce_color_type(png: &PngImage) -> Option { } if reduced.ihdr.color_type == ColorType::RGB { - if let Some(r) = - reduce_rgb_to_grayscale(&reduced).or_else(|| reduced_color_to_palette(&reduced)) + if let Some(r) = if grayscale_reduction { + reduce_rgb_to_grayscale(&reduced) + } else { + None + } + .or_else(|| reduced_color_to_palette(&reduced)) { reduced = Cow::Owned(r); should_reduce_bit_depth = true; diff --git a/tests/files/issue-182.png b/tests/files/issue-182.png new file mode 100644 index 00000000..10d48000 Binary files /dev/null and b/tests/files/issue-182.png differ diff --git a/tests/filters.rs b/tests/filters.rs index 124baed4..4da00a8c 100644 --- a/tests/filters.rs +++ b/tests/filters.rs @@ -6,14 +6,16 @@ use std::path::Path; use std::path::PathBuf; fn get_opts(input: &Path) -> (OutFile, oxipng::Options) { - let mut options = oxipng::Options::default(); - options.force = true; + let mut options = oxipng::Options { + force: true, + ..Default::default() + }; let mut filter = IndexSet::new(); filter.insert(0); options.filter = filter; ( - OutFile::Path(Some(input.with_extension("out.png").to_owned())), + OutFile::Path(Some(input.with_extension("out.png"))), options, ) } @@ -55,7 +57,7 @@ fn test_it_converts( if let Some(palette) = png.raw.palette.as_ref() { assert!(palette.len() <= 1 << (png.raw.ihdr.bit_depth.as_u8() as usize)); } else { - assert!(png.raw.ihdr.color_type != ColorType::Indexed); + assert_ne!(png.raw.ihdr.color_type, ColorType::Indexed); } remove_file(output).ok(); diff --git a/tests/flags.rs b/tests/flags.rs index b457f0bf..07f29d19 100644 --- a/tests/flags.rs +++ b/tests/flags.rs @@ -10,14 +10,16 @@ use std::path::Path; use std::path::PathBuf; fn get_opts(input: &Path) -> (OutFile, oxipng::Options) { - let mut options = oxipng::Options::default(); - options.force = true; + let mut options = oxipng::Options { + force: true, + ..Default::default() + }; let mut filter = IndexSet::new(); filter.insert(0); options.filter = filter; ( - OutFile::Path(Some(input.with_extension("out.png").to_owned())), + OutFile::Path(Some(input.with_extension("out.png"))), options, ) } @@ -200,7 +202,7 @@ fn strip_headers_list() { let output = output.path().unwrap(); assert!(output.exists()); - let png = match PngData::new(&output, opts.fix_errors) { + let png = match PngData::new(output, opts.fix_errors) { Ok(x) => x, Err(x) => { remove_file(output).ok(); @@ -234,7 +236,7 @@ fn strip_headers_safe() { let output = output.path().unwrap(); assert!(output.exists()); - let png = match PngData::new(&output, opts.fix_errors) { + let png = match PngData::new(output, opts.fix_errors) { Ok(x) => x, Err(x) => { remove_file(output).ok(); @@ -268,7 +270,7 @@ fn strip_headers_all() { let output = output.path().unwrap(); assert!(output.exists()); - let png = match PngData::new(&output, opts.fix_errors) { + let png = match PngData::new(output, opts.fix_errors) { Ok(x) => x, Err(x) => { remove_file(output).ok(); @@ -302,7 +304,7 @@ fn strip_headers_none() { let output = output.path().unwrap(); assert!(output.exists()); - let png = match PngData::new(&output, opts.fix_errors) { + let png = match PngData::new(output, opts.fix_errors) { Ok(x) => x, Err(x) => { remove_file(output).ok(); @@ -334,7 +336,7 @@ fn interlacing_0_to_1() { let output = output.path().unwrap(); assert!(output.exists()); - let png = match PngData::new(&output, opts.fix_errors) { + let png = match PngData::new(output, opts.fix_errors) { Ok(x) => x, Err(x) => { remove_file(output).ok(); @@ -364,7 +366,7 @@ fn interlacing_1_to_0() { let output = output.path().unwrap(); assert!(output.exists()); - let png = match PngData::new(&output, opts.fix_errors) { + let png = match PngData::new(output, opts.fix_errors) { Ok(x) => x, Err(x) => { remove_file(output).ok(); @@ -396,7 +398,7 @@ fn interlacing_0_to_1_small_files() { let output = output.path().unwrap(); assert!(output.exists()); - let png = match PngData::new(&output, opts.fix_errors) { + let png = match PngData::new(output, opts.fix_errors) { Ok(x) => x, Err(x) => { remove_file(output).ok(); @@ -430,7 +432,7 @@ fn interlacing_1_to_0_small_files() { let output = output.path().unwrap(); assert!(output.exists()); - let png = match PngData::new(&output, opts.fix_errors) { + let png = match PngData::new(output, opts.fix_errors) { Ok(x) => x, Err(x) => { remove_file(output).ok(); @@ -465,7 +467,7 @@ fn interlaced_0_to_1_other_filter_mode() { let output = output.path().unwrap(); assert!(output.exists()); - let png = match PngData::new(&output, opts.fix_errors) { + let png = match PngData::new(output, opts.fix_errors) { Ok(x) => x, Err(x) => { remove_file(output).ok(); @@ -560,7 +562,7 @@ fn fix_errors() { let output = output.path().unwrap(); assert!(output.exists()); - let png = match PngData::new(&output, false) { + let png = match PngData::new(output, false) { Ok(x) => x, Err(x) => { remove_file(output).ok(); @@ -576,6 +578,7 @@ fn fix_errors() { } #[test] +#[cfg(feature = "zopfli")] fn zopfli_mode() { let input = PathBuf::from("tests/files/zopfli_mode.png"); let (output, mut opts) = get_opts(&input); @@ -593,6 +596,7 @@ fn zopfli_mode() { } #[test] +#[cfg(feature = "libdeflater")] fn libdeflater_mode() { let input = PathBuf::from("tests/files/zopfli_mode.png"); let (output, mut opts) = get_opts(&input); diff --git a/tests/interlaced.rs b/tests/interlaced.rs index b7f15afc..65cc0ac2 100644 --- a/tests/interlaced.rs +++ b/tests/interlaced.rs @@ -6,14 +6,16 @@ use std::path::Path; use std::path::PathBuf; fn get_opts(input: &Path) -> (OutFile, oxipng::Options) { - let mut options = oxipng::Options::default(); - options.force = true; + let mut options = oxipng::Options { + force: true, + ..Default::default() + }; let mut filter = IndexSet::new(); filter.insert(0); options.filter = filter; ( - OutFile::Path(Some(input.with_extension("out.png").to_owned())), + OutFile::Path(Some(input.with_extension("out.png"))), options, ) } diff --git a/tests/lib.rs b/tests/lib.rs index cce5520e..8f5e28d1 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -1,5 +1,3 @@ -use oxipng; - use oxipng::Headers; use oxipng::OutFile; use std::default::Default; diff --git a/tests/reduction.rs b/tests/reduction.rs index 1431c586..0951c628 100644 --- a/tests/reduction.rs +++ b/tests/reduction.rs @@ -6,14 +6,16 @@ use std::path::Path; use std::path::PathBuf; fn get_opts(input: &Path) -> (OutFile, oxipng::Options) { - let mut options = oxipng::Options::default(); - options.force = true; + let mut options = oxipng::Options { + force: true, + ..Default::default() + }; let mut filter = IndexSet::new(); filter.insert(0); options.filter = filter; ( - OutFile::Path(Some(input.with_extension("out.png").to_owned())), + OutFile::Path(Some(input.with_extension("out.png"))), options, ) } @@ -711,7 +713,7 @@ fn small_files() { let output = output.path().unwrap(); assert!(output.exists()); - let png = match PngData::new(&output, opts.fix_errors) { + let png = match PngData::new(output, opts.fix_errors) { Ok(x) => x, Err(x) => { remove_file(&output).ok(); @@ -743,7 +745,7 @@ fn palette_should_be_reduced_with_dupes() { let output = output.path().unwrap(); assert!(output.exists()); - let png = match PngData::new(&output, opts.fix_errors) { + let png = match PngData::new(output, opts.fix_errors) { Ok(x) => x, Err(x) => { remove_file(&output).ok(); @@ -776,7 +778,7 @@ fn palette_should_be_reduced_with_unused() { let output = output.path().unwrap(); assert!(output.exists()); - let png = match PngData::new(&output, opts.fix_errors) { + let png = match PngData::new(output, opts.fix_errors) { Ok(x) => x, Err(x) => { remove_file(&output).ok(); @@ -809,7 +811,7 @@ fn palette_should_be_reduced_with_both() { let output = output.path().unwrap(); assert!(output.exists()); - let png = match PngData::new(&output, opts.fix_errors) { + let png = match PngData::new(output, opts.fix_errors) { Ok(x) => x, Err(x) => { remove_file(&output).ok(); diff --git a/tests/regression.rs b/tests/regression.rs index 2085741f..539ec88f 100644 --- a/tests/regression.rs +++ b/tests/regression.rs @@ -6,14 +6,16 @@ use std::path::Path; use std::path::PathBuf; fn get_opts(input: &Path) -> (OutFile, oxipng::Options) { - let mut options = oxipng::Options::default(); - options.force = true; + let mut options = oxipng::Options { + force: true, + ..Default::default() + }; let mut filter = IndexSet::new(); filter.insert(0); options.filter = filter; ( - OutFile::Path(Some(input.with_extension("out.png").to_owned())), + OutFile::Path(Some(input.with_extension("out.png"))), options, ) } @@ -62,7 +64,7 @@ fn test_it_converts( if let Some(palette) = png.raw.palette.as_ref() { assert!(palette.len() <= 1 << (png.raw.ihdr.bit_depth.as_u8() as usize)); } else { - assert!(png.raw.ihdr.color_type != ColorType::Indexed); + assert_ne!(png.raw.ihdr.color_type, ColorType::Indexed); } remove_file(output).ok(); @@ -99,7 +101,7 @@ fn issue_42() { let output = output.path().unwrap(); assert!(output.exists()); - let png = match PngData::new(&output, opts.fix_errors) { + let png = match PngData::new(output, opts.fix_errors) { Ok(x) => x, Err(x) => { remove_file(output).ok(); @@ -287,12 +289,10 @@ fn issue_92_filter_5() { let input = "tests/files/issue-92.png"; let (_, mut opts) = get_opts(Path::new(input)); opts.filter = [5].iter().cloned().collect(); - let output = OutFile::Path(Some( - Path::new(input).with_extension("-f5-out.png").to_owned(), - )); + let output = OutFile::Path(Some(Path::new(input).with_extension("-f5-out.png"))); test_it_converts( - &input, + input, Some((output, opts)), ColorType::Grayscale, BitDepth::Eight, @@ -308,9 +308,7 @@ fn issue_113_white() { opts.interlace = Some(1); opts.alphas = IndexSet::new(); opts.alphas.insert(AlphaOptim::Black); - let output = OutFile::Path(Some( - Path::new(input).with_extension("-white-out.png").to_owned(), - )); + let output = OutFile::Path(Some(Path::new(input).with_extension("-white-out.png"))); test_it_converts( input, Some((output, opts)), @@ -328,9 +326,7 @@ fn issue_113_black() { opts.interlace = Some(1); opts.alphas = IndexSet::new(); opts.alphas.insert(AlphaOptim::Black); - let output = OutFile::Path(Some( - Path::new(input).with_extension("-black-out.png").to_owned(), - )); + let output = OutFile::Path(Some(Path::new(input).with_extension("-black-out.png"))); test_it_converts( input, Some((output, opts)), @@ -348,9 +344,7 @@ fn issue_113_right() { opts.interlace = Some(1); opts.alphas = IndexSet::new(); opts.alphas.insert(AlphaOptim::Right); - let output = OutFile::Path(Some( - Path::new(input).with_extension("-right-out.png").to_owned(), - )); + let output = OutFile::Path(Some(Path::new(input).with_extension("-right-out.png"))); test_it_converts( input, Some((output, opts)), @@ -368,9 +362,7 @@ fn issue_113_left() { opts.interlace = Some(1); opts.alphas = IndexSet::new(); opts.alphas.insert(AlphaOptim::Left); - let output = OutFile::Path(Some( - Path::new(input).with_extension("-left-out.png").to_owned(), - )); + let output = OutFile::Path(Some(Path::new(input).with_extension("-left-out.png"))); test_it_converts( input, Some((output, opts)), @@ -388,9 +380,7 @@ fn issue_113_up() { opts.interlace = Some(1); opts.alphas = IndexSet::new(); opts.alphas.insert(AlphaOptim::Up); - let output = OutFile::Path(Some( - Path::new(input).with_extension("-up-out.png").to_owned(), - )); + let output = OutFile::Path(Some(Path::new(input).with_extension("-up-out.png"))); test_it_converts( input, Some((output, opts)), @@ -408,9 +398,7 @@ fn issue_113_down() { opts.interlace = Some(1); opts.alphas = IndexSet::new(); opts.alphas.insert(AlphaOptim::Down); - let output = OutFile::Path(Some( - Path::new(input).with_extension("-down-out.png").to_owned(), - )); + let output = OutFile::Path(Some(Path::new(input).with_extension("-down-out.png"))); test_it_converts( input, Some((output, opts)), @@ -440,9 +428,7 @@ fn issue_133_black() { let (_, mut opts) = get_opts(Path::new(input)); opts.alphas = IndexSet::new(); opts.alphas.insert(AlphaOptim::Black); - let output = OutFile::Path(Some( - Path::new(input).with_extension("-black-out.png").to_owned(), - )); + let output = OutFile::Path(Some(Path::new(input).with_extension("-black-out.png"))); test_it_converts( input, Some((output, opts)), @@ -459,9 +445,7 @@ fn issue_133_white() { let (_, mut opts) = get_opts(Path::new(input)); opts.alphas = IndexSet::new(); opts.alphas.insert(AlphaOptim::White); - let output = OutFile::Path(Some( - Path::new(input).with_extension("-white-out.png").to_owned(), - )); + let output = OutFile::Path(Some(Path::new(input).with_extension("-white-out.png"))); test_it_converts( input, Some((output, opts)), @@ -478,9 +462,7 @@ fn issue_133_up() { let (_, mut opts) = get_opts(Path::new(input)); opts.alphas = IndexSet::new(); opts.alphas.insert(AlphaOptim::Up); - let output = OutFile::Path(Some( - Path::new(input).with_extension("-up-out.png").to_owned(), - )); + let output = OutFile::Path(Some(Path::new(input).with_extension("-up-out.png"))); test_it_converts( input, Some((output, opts)), @@ -497,9 +479,7 @@ fn issue_133_down() { let (_, mut opts) = get_opts(Path::new(input)); opts.alphas = IndexSet::new(); opts.alphas.insert(AlphaOptim::Down); - let output = OutFile::Path(Some( - Path::new(input).with_extension("-down-out.png").to_owned(), - )); + let output = OutFile::Path(Some(Path::new(input).with_extension("-down-out.png"))); test_it_converts( input, Some((output, opts)), @@ -516,9 +496,7 @@ fn issue_133_right() { let (_, mut opts) = get_opts(Path::new(input)); opts.alphas = IndexSet::new(); opts.alphas.insert(AlphaOptim::Right); - let output = OutFile::Path(Some( - Path::new(input).with_extension("-right-out.png").to_owned(), - )); + let output = OutFile::Path(Some(Path::new(input).with_extension("-right-out.png"))); test_it_converts( input, Some((output, opts)), @@ -535,9 +513,7 @@ fn issue_133_left() { let (_, mut opts) = get_opts(Path::new(input)); opts.alphas = IndexSet::new(); opts.alphas.insert(AlphaOptim::Left); - let output = OutFile::Path(Some( - Path::new(input).with_extension("-left-out.png").to_owned(), - )); + let output = OutFile::Path(Some(Path::new(input).with_extension("-left-out.png"))); test_it_converts( input, Some((output, opts)), @@ -635,7 +611,7 @@ fn issue_175() { #[test] fn issue_182() { - let input = "tests/files/issue-175.png"; + let input = "tests/files/issue-182.png"; let (output, mut opts) = get_opts(Path::new(input)); opts.interlace = Some(0);