Prepare for next release

This commit is contained in:
Josh Holmer 2019-02-01 17:27:03 -05:00
parent 485a127cf6
commit d86bc80f43
26 changed files with 593 additions and 352 deletions

View file

@ -1,3 +1,10 @@
### Version 2.2.0
- Various internal improvements ([#154](https://github.com/shssoichiro/oxipng/pull/154)) ([#158](https://github.com/shssoichiro/oxipng/pull/158)) ([#160](https://github.com/shssoichiro/oxipng/pull/160)) ([#161](https://github.com/shssoichiro/oxipng/pull/161)) ([#162](https://github.com/shssoichiro/oxipng/pull/162)) ([#163](https://github.com/shssoichiro/oxipng/pull/163))
- Update `image` crate to 0.21.0
- Update `itertools` crate to 0.8.0
- Update `zopfli` crate to 0.4.0
- Use Rust edition 2018
### Version 2.1.8
- Fix non-standard sBIT headers in other code locations ([#153](https://github.com/shssoichiro/oxipng/issues/153))

115
Cargo.lock generated
View file

@ -1,8 +1,3 @@
[[package]]
name = "adler32"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "adler32"
version = "1.0.3"
@ -18,7 +13,7 @@ dependencies = [
[[package]]
name = "arrayvec"
version = "0.4.8"
version = "0.4.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)",
@ -29,7 +24,7 @@ name = "atty"
version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
"termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -51,17 +46,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "byteorder"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "byteorder"
version = "1.2.7"
version = "1.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "cc"
version = "1.0.25"
version = "1.0.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@ -96,7 +86,7 @@ name = "cloudflare-zlib-sys"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
"cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -121,7 +111,7 @@ name = "crossbeam-epoch"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"arrayvec 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
"cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -144,7 +134,7 @@ version = "0.7.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -159,20 +149,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "image"
version = "0.20.1"
version = "0.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"lzw 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
"num-iter 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
"num-rational 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
"png 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
"png 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)",
"safe-transmute 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "inflate"
version = "0.4.3"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
@ -180,7 +171,7 @@ dependencies = [
[[package]]
name = "itertools"
version = "0.7.11"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -193,7 +184,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "libc"
version = "0.2.44"
version = "0.2.48"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@ -208,7 +199,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "miniz_oxide"
version = "0.2.0"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
@ -252,10 +243,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "num_cpus"
version = "1.8.0"
version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -263,28 +254,28 @@ name = "oxipng"
version = "2.1.8"
dependencies = [
"bit-vec 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)",
"cloudflare-zlib 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
"image 0.20.1 (registry+https://github.com/rust-lang/crates.io-index)",
"itertools 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)",
"miniz_oxide 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"image 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)",
"itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"miniz_oxide 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"num_cpus 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rayon 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
"rgb 0.8.11 (registry+https://github.com/rust-lang/crates.io-index)",
"rgb 0.8.12 (registry+https://github.com/rust-lang/crates.io-index)",
"wild 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"zopfli 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"zopfli 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "png"
version = "0.12.0"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"deflate 0.7.19 (registry+https://github.com/rust-lang/crates.io-index)",
"inflate 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
"inflate 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
"num-iter 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -305,13 +296,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
"num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
"num_cpus 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "redox_syscall"
version = "0.1.43"
version = "0.1.51"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@ -319,12 +310,17 @@ name = "redox_termios"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"redox_syscall 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rgb"
version = "0.8.11"
version = "0.8.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "safe-transmute"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@ -342,8 +338,8 @@ name = "termion"
version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_syscall 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -399,27 +395,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "zopfli"
version = "0.3.7"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"adler32 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
"adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
"typed-arena 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[metadata]
"checksum adler32 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e928aa58f6dbd754bda26eca562a242549cb606e27a2240fc305fc75a7f12af9"
"checksum adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7e522997b529f05601e05166c07ed17789691f562762c7f3b987263d2dedee5c"
"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
"checksum arrayvec 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "f405cc4c21cd8b784f6c8fc2adf9bc00f59558f0049b5ec21517f875963040cc"
"checksum arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "92c7fb76bc8826a8b33b4ee5bb07a247a81e76764ab4d55e8f73e3a4d8808c71"
"checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652"
"checksum bit-vec 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4440d5cb623bb7390ae27fec0bb6c61111969860f8e3ae198bfa0663645e67cf"
"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12"
"checksum build_const 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "39092a32794787acd8525ee150305ff051b0aa6cc2abaf193924f5ab05425f39"
"checksum byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0fc10e8cc6b2580fda3f36eb6dc5316657f812a3df879a44a66fc9f0fdbc4855"
"checksum byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "94f88df23a25417badc922ab0f5716cc1330e87f71ddd9203b3a3ccd9cedf75d"
"checksum cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)" = "f159dfd43363c4d08055a07703eb7a3406b0dac4d0584d96965a3262db3c9d16"
"checksum byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a019b10a2a7cdeb292db131fc8113e57ea2a908f6e7894b0c3c671893b65dbeb"
"checksum cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4a8b715cb4597106ea87c7c84b2f1d452c7492033765df7f32651e66fcf749"
"checksum cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "082bb9b28e00d3c9d39cc03e64ce4cea0f1bb9b3fde493f0cbc008472d22bdf4"
"checksum clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b957d88f4b6a63b9d70d5f454ac8011819c6efa7727858f458ab71c756ce2d3e"
"checksum cloudflare-zlib 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "cd97a72b7777ef134de513cef589e48c393dc2ea7180ff6dca87dcd3ee078dac"
@ -431,26 +425,27 @@ dependencies = [
"checksum deflate 0.7.19 (registry+https://github.com/rust-lang/crates.io-index)" = "8a6abb26e16e8d419b5c78662aa9f82857c2386a073da266840e474d5055ec86"
"checksum either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3be565ca5c557d7f59e7cfcf1844f9e3033650c929c6566f511e8005f205c1d0"
"checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb"
"checksum image 0.20.1 (registry+https://github.com/rust-lang/crates.io-index)" = "44665b4395d1844c96e7dc8ed5754782a1cdfd9ef458a80bbe45702681450504"
"checksum inflate 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6f53b811ee8e2057ccf9643ca6b4277de90efaf5e61e55fd5254576926bb4245"
"checksum itertools 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)" = "0d47946d458e94a1b7bcabbf6521ea7c037062c81f534615abcad76e84d4970d"
"checksum image 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)" = "52fb0666a1273dac46f9725aa4859bcd5595fc3554cf3495051b4de8db745e7d"
"checksum inflate 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "84c683bde2d8413b8f1be3e459c30e4817672b6e7a31d9212b0323154e76eba7"
"checksum itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5b8467d9c1cebe26feb08c640139247fac215782d35371ade9a2136ed6085358"
"checksum lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a374c89b9db55895453a74c1e38861d9deec0b01b405a82516e9d5de4820dea1"
"checksum libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)" = "10923947f84a519a45c8fefb7dd1b3e8c08747993381adee176d7a82b4195311"
"checksum libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)" = "e962c7641008ac010fa60a7dfdc1712449f29c44ef2d4702394aea943ee75047"
"checksum lzw 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7d947cbb889ed21c2a84be6ffbaebf5b4e0f4340638cba0444907e38b56be084"
"checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3"
"checksum miniz_oxide 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5ad30a47319c16cde58d0314f5d98202a80c9083b5f61178457403dfb14e509c"
"checksum miniz_oxide 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c468f2369f07d651a5d0bb2c9079f8488a66d5466efe42d0c5c6466edcb7f71e"
"checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945"
"checksum num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea"
"checksum num-iter 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "af3fdbbc3291a5464dc57b03860ec37ca6bf915ed6ee385e7c6c052c422b2124"
"checksum num-rational 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4e96f040177bb3da242b5b1ecf3f54b5d5af3efbbfb18608977a5d2767b22f10"
"checksum num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0b3a5d7cc97d6d30d8b9bc8fa19bf45349ffe46241e8816f50f62f6d6aaabee1"
"checksum num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c51a3322e4bca9d212ad9a158a02abc6934d005490c054a2778df73a70aa0a30"
"checksum png 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f54b9600d584d3b8a739e1662a595fab051329eff43f20e7d8cc22872962145b"
"checksum num_cpus 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5a69d464bdc213aaaff628444e99578ede64e9c854025aa43b9796530afa9238"
"checksum png 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9adebf7fb91ccf5eac9da1a8e00e83cb8ae882c3e8d8e4ad59da73cb8c82a2c9"
"checksum rayon 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "373814f27745b2686b350dd261bfd24576a6fb0e2c5919b3a2b6005f820b0473"
"checksum rayon-core 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b055d1e92aba6877574d8fe604a63c8b5df60f60e5982bf7ccbb1338ea527356"
"checksum redox_syscall 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "679da7508e9a6390aeaf7fbd02a800fdc64b73fe2204dd2c8ae66d22d9d5ad5d"
"checksum redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)" = "423e376fffca3dfa06c9e9790a9ccd282fafb3cc6e6397d01dbf64f9bacc6b85"
"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76"
"checksum rgb 0.8.11 (registry+https://github.com/rust-lang/crates.io-index)" = "002bebda58b24482d6911a59512e8a17fa1defecf5a2162521113b7cc5422dd1"
"checksum rgb 0.8.12 (registry+https://github.com/rust-lang/crates.io-index)" = "6909f703ab5260012430324d5e8a5c74b26080597cd465d0bd1d2338d6b24ab7"
"checksum safe-transmute 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9604873ffe1980bc1f179103704a65c8aca141c248d9e52b7af95ff10578166e"
"checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27"
"checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550"
"checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096"
@ -462,4 +457,4 @@ dependencies = [
"checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0"
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
"checksum zopfli 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "9fd2fb70c78a87410032abe2a9eb2bec4984a2d9bc26adb1f8f768e02673e84e"
"checksum zopfli 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4079b79464426ade2a1b0177fb0ce8396ba6b4084267407e333573c666073964"

View file

@ -6,6 +6,7 @@ categories = [
]
description = "A lossless PNG compression optimizer"
documentation = "https://docs.rs/oxipng"
edition = "2018"
exclude = [
"tests/*",
"bench/*",
@ -30,9 +31,9 @@ required-features = ["binary"]
bit-vec = "^0.5.0"
byteorder = "^1.0.0"
crc = "^1.2.0"
itertools = "^0.7.7"
itertools = "^0.8.0"
num_cpus = "^1.0.0"
zopfli = "^0.3.4"
zopfli = "^0.4.0"
miniz_oxide = "0.2.0"
rgb = "0.8.11"
@ -54,7 +55,7 @@ cloudflare-zlib = "^0.2.2"
[dependencies.image]
default-features = false
features = ["png_codec"]
version = "^0.20.0"
version = "^0.21.0"
[features]
binary = [

View file

@ -3,10 +3,12 @@
extern crate oxipng;
extern crate test;
use oxipng::internal_tests::*;
use std::path::PathBuf;
use test::Bencher;
use oxipng::internal_tests::*;
use oxipng::Deadline;
#[bench]
fn deflate_16_bits_strategy_0(b: &mut Bencher) {
let input = test::black_box(PathBuf::from("tests/files/rgb_16_should_be_rgb_16.png"));
@ -14,7 +16,14 @@ fn deflate_16_bits_strategy_0(b: &mut Bencher) {
b.iter(|| {
let min = AtomicMin::new(None);
deflate(png.raw.data.as_ref(), 9, 0, 15, &min)
deflate(
png.raw.data.as_ref(),
9,
0,
15,
&min,
&Deadline::new(None, false),
)
});
}
@ -25,7 +34,14 @@ fn deflate_8_bits_strategy_0(b: &mut Bencher) {
b.iter(|| {
let min = AtomicMin::new(None);
deflate(png.raw.data.as_ref(), 9, 0, 15, &min)
deflate(
png.raw.data.as_ref(),
9,
0,
15,
&min,
&Deadline::new(None, false),
)
});
}
@ -38,7 +54,14 @@ fn deflate_4_bits_strategy_0(b: &mut Bencher) {
b.iter(|| {
let min = AtomicMin::new(None);
deflate(png.raw.data.as_ref(), 9, 0, 15, &min)
deflate(
png.raw.data.as_ref(),
9,
0,
15,
&min,
&Deadline::new(None, false),
)
});
}
@ -51,7 +74,14 @@ fn deflate_2_bits_strategy_0(b: &mut Bencher) {
b.iter(|| {
let min = AtomicMin::new(None);
deflate(png.raw.data.as_ref(), 9, 0, 15, &min)
deflate(
png.raw.data.as_ref(),
9,
0,
15,
&min,
&Deadline::new(None, false),
)
});
}
@ -64,7 +94,14 @@ fn deflate_1_bits_strategy_0(b: &mut Bencher) {
b.iter(|| {
let min = AtomicMin::new(None);
deflate(png.raw.data.as_ref(), 9, 0, 15, &min)
deflate(
png.raw.data.as_ref(),
9,
0,
15,
&min,
&Deadline::new(None, false),
)
});
}
@ -75,7 +112,14 @@ fn deflate_16_bits_strategy_1(b: &mut Bencher) {
b.iter(|| {
let min = AtomicMin::new(None);
deflate(png.raw.data.as_ref(), 9, 1, 15, &min)
deflate(
png.raw.data.as_ref(),
9,
1,
15,
&min,
&Deadline::new(None, false),
)
});
}
@ -86,7 +130,14 @@ fn deflate_8_bits_strategy_1(b: &mut Bencher) {
b.iter(|| {
let min = AtomicMin::new(None);
deflate(png.raw.data.as_ref(), 9, 1, 15, &min)
deflate(
png.raw.data.as_ref(),
9,
1,
15,
&min,
&Deadline::new(None, false),
)
});
}
@ -99,7 +150,14 @@ fn deflate_4_bits_strategy_1(b: &mut Bencher) {
b.iter(|| {
let min = AtomicMin::new(None);
deflate(png.raw.data.as_ref(), 9, 1, 15, &min)
deflate(
png.raw.data.as_ref(),
9,
1,
15,
&min,
&Deadline::new(None, false),
)
});
}
@ -112,7 +170,14 @@ fn deflate_2_bits_strategy_1(b: &mut Bencher) {
b.iter(|| {
let min = AtomicMin::new(None);
deflate(png.raw.data.as_ref(), 9, 1, 15, &min)
deflate(
png.raw.data.as_ref(),
9,
1,
15,
&min,
&Deadline::new(None, false),
)
});
}
@ -125,7 +190,14 @@ fn deflate_1_bits_strategy_1(b: &mut Bencher) {
b.iter(|| {
let min = AtomicMin::new(None);
deflate(png.raw.data.as_ref(), 9, 1, 15, &min)
deflate(
png.raw.data.as_ref(),
9,
1,
15,
&min,
&Deadline::new(None, false),
)
});
}
@ -136,7 +208,14 @@ fn deflate_16_bits_strategy_2(b: &mut Bencher) {
b.iter(|| {
let min = AtomicMin::new(None);
deflate(png.raw.data.as_ref(), 9, 2, 15, &min)
deflate(
png.raw.data.as_ref(),
9,
2,
15,
&min,
&Deadline::new(None, false),
)
});
}
@ -147,7 +226,14 @@ fn deflate_8_bits_strategy_2(b: &mut Bencher) {
b.iter(|| {
let min = AtomicMin::new(None);
deflate(png.raw.data.as_ref(), 9, 2, 15, &min)
deflate(
png.raw.data.as_ref(),
9,
2,
15,
&min,
&Deadline::new(None, false),
)
});
}
@ -160,7 +246,14 @@ fn deflate_4_bits_strategy_2(b: &mut Bencher) {
b.iter(|| {
let min = AtomicMin::new(None);
deflate(png.raw.data.as_ref(), 9, 2, 15, &min)
deflate(
png.raw.data.as_ref(),
9,
2,
15,
&min,
&Deadline::new(None, false),
)
});
}
@ -173,7 +266,14 @@ fn deflate_2_bits_strategy_2(b: &mut Bencher) {
b.iter(|| {
let min = AtomicMin::new(None);
deflate(png.raw.data.as_ref(), 9, 2, 15, &min)
deflate(
png.raw.data.as_ref(),
9,
2,
15,
&min,
&Deadline::new(None, false),
)
});
}
@ -186,7 +286,14 @@ fn deflate_1_bits_strategy_2(b: &mut Bencher) {
b.iter(|| {
let min = AtomicMin::new(None);
deflate(png.raw.data.as_ref(), 9, 2, 15, &min)
deflate(
png.raw.data.as_ref(),
9,
2,
15,
&min,
&Deadline::new(None, false),
)
});
}
@ -197,7 +304,14 @@ fn deflate_16_bits_strategy_3(b: &mut Bencher) {
b.iter(|| {
let min = AtomicMin::new(None);
deflate(png.raw.data.as_ref(), 9, 3, 15, &min)
deflate(
png.raw.data.as_ref(),
9,
3,
15,
&min,
&Deadline::new(None, false),
)
});
}
@ -208,7 +322,14 @@ fn deflate_8_bits_strategy_3(b: &mut Bencher) {
b.iter(|| {
let min = AtomicMin::new(None);
deflate(png.raw.data.as_ref(), 9, 3, 15, &min)
deflate(
png.raw.data.as_ref(),
9,
3,
15,
&min,
&Deadline::new(None, false),
)
});
}
@ -221,7 +342,14 @@ fn deflate_4_bits_strategy_3(b: &mut Bencher) {
b.iter(|| {
let min = AtomicMin::new(None);
deflate(png.raw.data.as_ref(), 9, 3, 15, &min)
deflate(
png.raw.data.as_ref(),
9,
3,
15,
&min,
&Deadline::new(None, false),
)
});
}
@ -234,7 +362,14 @@ fn deflate_2_bits_strategy_3(b: &mut Bencher) {
b.iter(|| {
let min = AtomicMin::new(None);
deflate(png.raw.data.as_ref(), 9, 3, 15, &min)
deflate(
png.raw.data.as_ref(),
9,
3,
15,
&min,
&Deadline::new(None, false),
)
});
}
@ -247,7 +382,14 @@ fn deflate_1_bits_strategy_3(b: &mut Bencher) {
b.iter(|| {
let min = AtomicMin::new(None);
deflate(png.raw.data.as_ref(), 9, 3, 15, &min)
deflate(
png.raw.data.as_ref(),
9,
3,
15,
&min,
&Deadline::new(None, false),
)
});
}

View file

@ -17,7 +17,7 @@ pub enum ColorType {
impl fmt::Display for ColorType {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{}",
@ -73,7 +73,7 @@ pub enum BitDepth {
impl fmt::Display for BitDepth {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{}",
@ -127,7 +127,7 @@ pub enum AlphaOptim {
}
impl fmt::Display for AlphaOptim {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{}",

View file

@ -1,9 +1,9 @@
use Deadline;
use atomicmin::AtomicMin;
use crate::atomicmin::AtomicMin;
use crate::Deadline;
use crate::PngError;
use crate::PngResult;
pub use cloudflare_zlib::is_supported;
use cloudflare_zlib::*;
use PngError;
use PngResult;
impl From<ZError> for PngError {
fn from(err: ZError) -> Self {
@ -28,7 +28,7 @@ pub(crate) fn cfzlib_deflate(
// max size is generally checked after each split,
// so splitting the buffer into pieces gives more checks
// = better chance of hitting it sooner.
let chunk_size = (data.len()/4).max(1<<15).min(1<<18); // 32-256KB
let chunk_size = (data.len() / 4).max(1 << 15).min(1 << 18); // 32-256KB
for chunk in data.chunks(chunk_size) {
stream.compress_with_limit(chunk, max_size)?;
if deadline.passed() {
@ -47,7 +47,8 @@ fn compress_test() {
15,
&AtomicMin::new(None),
&Deadline::new(None, false),
).unwrap();
let res = ::deflate::inflate(&vec).unwrap();
)
.unwrap();
let res = crate::deflate::inflate(&vec).unwrap();
assert_eq!(&res, b"azxcvbnm");
}

View file

@ -1,7 +1,7 @@
use atomicmin::AtomicMin;
use error::PngError;
use crate::atomicmin::AtomicMin;
use crate::error::PngError;
use crate::PngResult;
use miniz_oxide::deflate::core::*;
use PngResult;
pub fn compress_to_vec_oxipng(
input: &[u8],

View file

@ -1,10 +1,10 @@
use Deadline;
use atomicmin::AtomicMin;
use error::PngError;
use crate::atomicmin::AtomicMin;
use crate::error::PngError;
use crate::Deadline;
use crate::PngResult;
use miniz_oxide;
use std::cmp::max;
use zopfli;
use PngResult;
#[doc(hidden)]
pub mod miniz_stream;
@ -26,7 +26,14 @@ pub fn inflate(data: &[u8]) -> PngResult<Vec<u8>> {
}
/// Compress a data stream using the DEFLATE algorithm
pub(crate) fn deflate(data: &[u8], zc: u8, zs: u8, zw: u8, max_size: &AtomicMin, deadline: &Deadline) -> PngResult<Vec<u8>> {
pub(crate) fn deflate(
data: &[u8],
zc: u8,
zs: u8,
zw: u8,
max_size: &AtomicMin,
deadline: &Deadline,
) -> PngResult<Vec<u8>> {
#[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))]
{
if cfzlib::is_supported() {

View file

@ -26,7 +26,7 @@ impl Error for PngError {
impl fmt::Display for PngError {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
PngError::DeflatedDataTooLong(_) => f.write_str("deflated data too long"),
PngError::TimedOut => f.write_str("timed out"),

View file

@ -1,22 +1,28 @@
//! Check if a reduction makes file smaller, and keep best reductions.
//! Works asynchronously when possible
use atomicmin::AtomicMin;
use crate::atomicmin::AtomicMin;
use crate::deflate;
use crate::png::PngData;
use crate::png::PngImage;
use crate::png::STD_COMPRESSION;
use crate::png::STD_FILTERS;
use crate::png::STD_STRATEGY;
use crate::png::STD_WINDOW;
#[cfg(not(feature = "parallel"))]
use crate::rayon;
#[cfg(not(feature = "parallel"))]
use crate::rayon::prelude::*;
use crate::Deadline;
#[cfg(feature = "parallel")]
use rayon;
#[cfg(feature = "parallel")]
use rayon::prelude::*;
use std::sync::atomic::AtomicUsize;
use std::sync::atomic::Ordering::SeqCst;
use deflate;
use Deadline;
use png::PngData;
use png::PngImage;
use png::STD_COMPRESSION;
use png::STD_FILTERS;
use png::STD_STRATEGY;
use png::STD_WINDOW;
use rayon::prelude::*;
use std::sync::mpsc::*;
use std::sync::Arc;
use std::thread;
use rayon;
struct Candidate {
image: PngData,
@ -100,16 +106,20 @@ impl Evaluator {
) {
best_candidate_size.set_min(idat_data.len());
// the rest is shipped to the evavluation/collection thread
eval_send.as_ref().expect("not finished yet").send(Candidate {
image: PngData {
idat_data,
raw: Arc::clone(&image),
},
bias,
filter,
is_reduction,
nth,
}).expect("send");
eval_send
.as_ref()
.expect("not finished yet")
.send(Candidate {
image: PngData {
idat_data,
raw: Arc::clone(&image),
},
bias,
filter,
is_reduction,
nth,
})
.expect("send");
}
});
});
@ -124,11 +134,33 @@ impl Evaluator {
let is_best = if let Some(ref old) = best_result {
// ordering is important - later file gets to use bias over earlier, but not the other way
// (this way bias=0 replaces, but doesn't forbid later optimizations)
let new_len = (new.image.idat_data.len() as f64 * if new.nth > old.nth {new.bias as f64} else {1.0}) as usize;
let old_len = (old.image.idat_data.len() as f64 * if new.nth < old.nth {old.bias as f64} else {1.0}) as usize;
let new_len = (new.image.idat_data.len() as f64
* if new.nth > old.nth {
f64::from(new.bias)
} else {
1.0
}) as usize;
let old_len = (old.image.idat_data.len() as f64
* if new.nth < old.nth {
f64::from(old.bias)
} else {
1.0
}) as usize;
// choose smallest compressed, or if compresses the same, smallest uncompressed, or cheaper filter
let new = (new_len, new.image.raw.data.len(), new.image.raw.ihdr.bit_depth, new.filter, new.nth);
let old = (old_len, old.image.raw.data.len(), old.image.raw.ihdr.bit_depth, old.filter, old.nth);
let new = (
new_len,
new.image.raw.data.len(),
new.image.raw.ihdr.bit_depth,
new.filter,
new.nth,
);
let old = (
old_len,
old.image.raw.data.len(),
old.image.raw.ihdr.bit_depth,
old.filter,
old.nth,
);
// <= instead of < is important, because best_candidate_size has been set already,
// so the current result may be comparing its size with itself
new <= old
@ -136,14 +168,9 @@ impl Evaluator {
true
};
if is_best {
best_result = if new.is_reduction {
Some(new)
} else {
None
};
best_result = if new.is_reduction { Some(new) } else { None };
}
}
best_result.map(|res| res.image)
}
}

View file

@ -24,35 +24,40 @@ pub fn filter_line(filter: u8, bpp: usize, data: &[u8], last_line: &[u8]) -> Vec
);
};
}
3 => for (i, byte) in data.iter().enumerate() {
if last_line.is_empty() {
filtered.push(match i.checked_sub(bpp) {
Some(x) => byte.wrapping_sub(data[x] >> 1),
None => *byte,
});
} else {
filtered.push(match i.checked_sub(bpp) {
Some(x) => byte
.wrapping_sub(((u16::from(data[x]) + u16::from(last_line[i])) >> 1) as u8),
None => byte.wrapping_sub(last_line[i] >> 1),
});
};
},
4 => for (i, byte) in data.iter().enumerate() {
if last_line.is_empty() {
filtered.push(match i.checked_sub(bpp) {
Some(x) => byte.wrapping_sub(data[x]),
None => *byte,
});
} else {
filtered.push(match i.checked_sub(bpp) {
Some(x) => {
byte.wrapping_sub(paeth_predictor(data[x], last_line[i], last_line[x]))
}
None => byte.wrapping_sub(last_line[i]),
});
};
},
3 => {
for (i, byte) in data.iter().enumerate() {
if last_line.is_empty() {
filtered.push(match i.checked_sub(bpp) {
Some(x) => byte.wrapping_sub(data[x] >> 1),
None => *byte,
});
} else {
filtered.push(match i.checked_sub(bpp) {
Some(x) => byte.wrapping_sub(
((u16::from(data[x]) + u16::from(last_line[i])) >> 1) as u8,
),
None => byte.wrapping_sub(last_line[i] >> 1),
});
};
}
}
4 => {
for (i, byte) in data.iter().enumerate() {
if last_line.is_empty() {
filtered.push(match i.checked_sub(bpp) {
Some(x) => byte.wrapping_sub(data[x]),
None => *byte,
});
} else {
filtered.push(match i.checked_sub(bpp) {
Some(x) => {
byte.wrapping_sub(paeth_predictor(data[x], last_line[i], last_line[x]))
}
None => byte.wrapping_sub(last_line[i]),
});
};
}
}
_ => unreachable!(),
}
filtered
@ -64,17 +69,19 @@ pub fn unfilter_line(filter: u8, bpp: usize, data: &[u8], last_line: &[u8]) -> V
0 => {
unfiltered.extend_from_slice(data);
}
1 => for (i, byte) in data.iter().enumerate() {
match i.checked_sub(bpp) {
Some(x) => {
let b = unfiltered[x];
unfiltered.push(byte.wrapping_add(b));
}
None => {
unfiltered.push(*byte);
}
};
},
1 => {
for (i, byte) in data.iter().enumerate() {
match i.checked_sub(bpp) {
Some(x) => {
let b = unfiltered[x];
unfiltered.push(byte.wrapping_add(b));
}
None => {
unfiltered.push(*byte);
}
};
}
}
2 => {
if last_line.is_empty() {
unfiltered.extend_from_slice(data);
@ -113,33 +120,35 @@ pub fn unfilter_line(filter: u8, bpp: usize, data: &[u8], last_line: &[u8]) -> V
};
}
}
4 => for (i, byte) in data.iter().enumerate() {
if last_line.is_empty() {
match i.checked_sub(bpp) {
Some(x) => {
let b = unfiltered[x];
unfiltered.push(byte.wrapping_add(b));
}
None => {
unfiltered.push(*byte);
}
4 => {
for (i, byte) in data.iter().enumerate() {
if last_line.is_empty() {
match i.checked_sub(bpp) {
Some(x) => {
let b = unfiltered[x];
unfiltered.push(byte.wrapping_add(b));
}
None => {
unfiltered.push(*byte);
}
};
} else {
match i.checked_sub(bpp) {
Some(x) => {
let b = unfiltered[x];
unfiltered.push(byte.wrapping_add(paeth_predictor(
b,
last_line[i],
last_line[x],
)));
}
None => {
unfiltered.push(byte.wrapping_add(last_line[i]));
}
};
};
} else {
match i.checked_sub(bpp) {
Some(x) => {
let b = unfiltered[x];
unfiltered.push(byte.wrapping_add(paeth_predictor(
b,
last_line[i],
last_line[x],
)));
}
None => {
unfiltered.push(byte.wrapping_add(last_line[i]));
}
};
};
},
}
}
_ => unreachable!(),
}
unfiltered

View file

@ -1,10 +1,10 @@
use crate::colors::{BitDepth, ColorType};
use crate::error::PngError;
use crate::PngResult;
use byteorder::{BigEndian, ReadBytesExt};
use colors::{BitDepth, ColorType};
use crc::crc32;
use error::PngError;
use std::collections::HashSet;
use std::io::Cursor;
use PngResult;
#[derive(Debug, Clone, Copy)]
/// Headers from the IHDR chunk of the image

View file

@ -1,6 +1,6 @@
use headers::IhdrData;
use crate::headers::IhdrData;
use crate::png::PngImage;
use bit_vec::BitVec;
use png::PngImage;
#[must_use]
pub fn interlace_image(png: &PngImage) -> PngImage {

View file

@ -1,28 +1,18 @@
extern crate bit_vec;
extern crate byteorder;
#[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))]
extern crate cloudflare_zlib;
extern crate crc;
extern crate image;
extern crate itertools;
extern crate miniz_oxide;
extern crate num_cpus;
use num_cpus;
#[cfg(feature = "parallel")]
extern crate rayon;
#[cfg(not(feature = "parallel"))]
mod rayon;
extern crate rgb;
extern crate zopfli;
use reduction::*;
use atomicmin::AtomicMin;
use crate::atomicmin::AtomicMin;
use crate::colors::BitDepth;
use crate::deflate::inflate;
use crate::evaluate::Evaluator;
use crate::png::PngData;
use crate::png::PngImage;
use crate::reduction::*;
use crc::crc32;
use deflate::inflate;
use evaluate::Evaluator;
use image::{DynamicImage, GenericImageView, ImageFormat, Pixel};
use png::PngImage;
use png::PngData;
use colors::BitDepth;
use rayon::prelude::*;
use std::collections::{HashMap, HashSet};
use std::fmt;
@ -30,13 +20,13 @@ use std::fs::{copy, File};
use std::io::{stdin, stdout, BufWriter, Read, Write};
use std::path::{Path, PathBuf};
use std::sync::atomic::{AtomicBool, Ordering};
use std::time::{Duration, Instant};
use std::sync::Arc;
use std::time::{Duration, Instant};
pub use colors::AlphaOptim;
pub use deflate::Deflaters;
pub use error::PngError;
pub use headers::Headers;
pub use crate::colors::AlphaOptim;
pub use crate::deflate::Deflaters;
pub use crate::error::PngError;
pub use crate::headers::Headers;
mod atomicmin;
mod colors;
@ -52,11 +42,11 @@ mod reduction;
/// Private to oxipng; don't use outside tests and benches
#[doc(hidden)]
pub mod internal_tests {
pub use atomicmin::*;
pub use colors::*;
pub use deflate::*;
pub use headers::*;
pub use png::*;
pub use crate::atomicmin::*;
pub use crate::colors::*;
pub use crate::deflate::*;
pub use crate::headers::*;
pub use crate::png::*;
}
#[derive(Clone, Debug)]
@ -92,7 +82,7 @@ impl InFile {
}
impl fmt::Display for InFile {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
InFile::Path(ref p) => write!(f, "{}", p.display()),
InFile::StdIn => f.write_str("stdin"),
@ -465,7 +455,12 @@ struct TrialOptions {
}
/// Perform optimization on the input PNG object using the options provided
fn optimize_png(png: &mut PngData, original_data: &[u8], opts: &Options, deadline: Arc<Deadline>) -> PngResult<Vec<u8>> {
fn optimize_png(
png: &mut PngData,
original_data: &[u8],
opts: &Options,
deadline: Arc<Deadline>,
) -> PngResult<Vec<u8>> {
type TrialWithData = (TrialOptions, Vec<u8>);
let original_png = png.clone();
@ -582,7 +577,8 @@ fn optimize_png(png: &mut PngData, original_data: &[u8], opts: &Options, deadlin
.map(|f| {
let png = png.clone();
(*f, png.raw.filter_image(*f))
}).collect();
})
.collect();
let original_len = original_png.idat_data.len();
let added_interlacing = opts.interlace == Some(1) && original_png.raw.ihdr.interlaced == 0;
@ -639,9 +635,8 @@ fn optimize_png(png: &mut PngData, original_data: &[u8], opts: &Options, deadlin
None
}
});
let best: Option<TrialWithData> = best.reduce_with(|i, j| {
if i.1.len() <= j.1.len() { i } else { j }
});
let best: Option<TrialWithData> =
best.reduce_with(|i, j| if i.1.len() <= j.1.len() { i } else { j });
if let Some(better) = best {
png.idat_data = better.1;
@ -698,7 +693,7 @@ fn optimize_png(png: &mut PngData, original_data: &[u8], opts: &Options, deadlin
let (old_png, new_png) = rayon::join(
|| image::load_from_memory_with_format(original_data, ImageFormat::PNG),
|| image::load_from_memory_with_format(&output, ImageFormat::PNG)
|| image::load_from_memory_with_format(&output, ImageFormat::PNG),
);
if let Ok(new_png) = new_png {
@ -720,8 +715,12 @@ fn optimize_png(png: &mut PngData, original_data: &[u8], opts: &Options, deadlin
Err(PngError::new("The resulting image is corrupted"))
}
fn perform_reductions(mut png: Arc<PngImage>, opts: &Options, deadline: &Deadline, eval: &Evaluator) {
fn perform_reductions(
mut png: Arc<PngImage>,
opts: &Options,
deadline: &Deadline,
eval: &Evaluator,
) {
// must be done first to evaluate rest with the correct interlacing
if let Some(interlacing) = opts.interlace {
if let Some(reduced) = png.change_interlacing(interlacing) {
@ -752,7 +751,9 @@ fn perform_reductions(mut png: Arc<PngImage>, opts: &Options, deadline: &Deadlin
let bits = reduced.ihdr.bit_depth;
png = Arc::new(reduced);
eval.try_image(png.clone(), 1.0);
if (bits == BitDepth::One || bits == BitDepth::Two) && previous.ihdr.bit_depth != BitDepth::Four {
if (bits == BitDepth::One || bits == BitDepth::Two)
&& previous.ihdr.bit_depth != BitDepth::Four
{
// Also try 16-color mode for all lower bits images, since that may compress better
if let Some(reduced) = reduce_bit_depth(&previous, 4) {
eval.try_image(Arc::new(reduced), 0.98);
@ -848,9 +849,11 @@ fn perform_strip(png: &mut PngData, opts: &Options) {
.map_or(false, |name| hdrs.contains(name))
});
}
Headers::Strip(ref hdrs) => for hdr in hdrs {
raw.aux_headers.remove(hdr.as_bytes());
},
Headers::Strip(ref hdrs) => {
for hdr in hdrs {
raw.aux_headers.remove(hdr.as_bytes());
}
}
Headers::Safe => {
const PRESERVED_HEADERS: [[u8; 4]; 9] = [
*b"cHRM", *b"gAMA", *b"iCCP", *b"sBIT", *b"sRGB", *b"bKGD", *b"hIST", *b"pHYs",

View file

@ -1,10 +1,6 @@
#![warn(trivial_casts, trivial_numeric_casts, unused_import_braces)]
#![deny(missing_debug_implementations, missing_copy_implementations)]
extern crate clap;
extern crate oxipng;
extern crate wild;
use clap::{App, AppSettings, Arg, ArgMatches};
use oxipng::AlphaOptim;
use oxipng::Deflaters;

View file

@ -1,11 +1,11 @@
use crate::colors::ColorType;
use crate::deflate;
use crate::error::PngError;
use crate::filters::*;
use crate::headers::*;
use crate::interlace::{deinterlace_image, interlace_image};
use byteorder::{BigEndian, WriteBytesExt};
use colors::ColorType;
use crc::crc32;
use deflate;
use error::PngError;
use filters::*;
use headers::*;
use interlace::{deinterlace_image, interlace_image};
use rgb::ComponentSlice;
use rgb::RGBA8;
use std::collections::HashMap;
@ -180,7 +180,8 @@ impl PngData {
let _ = ihdr_data.write_u8(self.raw.ihdr.interlaced);
write_png_block(b"IHDR", &ihdr_data, &mut output);
// Ancillary headers
for (key, header) in self.raw
for (key, header) in self
.raw
.aux_headers
.iter()
.filter(|&(key, _)| !(key == b"bKGD" || key == b"hIST" || key == b"tRNS"))
@ -196,16 +197,20 @@ impl PngData {
}
write_png_block(b"PLTE", &palette_data, &mut output);
let num_transparent =
palette.iter().take(max_palette_size).enumerate().fold(
0,
|prev, (index, px)| {
if px.a != 255 {
index + 1
} else {
prev
}
},
);
palette
.iter()
.take(max_palette_size)
.enumerate()
.fold(
0,
|prev, (index, px)| {
if px.a != 255 {
index + 1
} else {
prev
}
},
);
if num_transparent > 0 {
let trns_data: Vec<_> = palette[0..num_transparent].iter().map(|px| px.a).collect();
write_png_block(b"tRNS", &trns_data, &mut output);
@ -215,7 +220,8 @@ impl PngData {
write_png_block(b"tRNS", transparency_pixel, &mut output);
}
// Special ancillary headers that need to come after PLTE but before IDAT
for (key, header) in self.raw
for (key, header) in self
.raw
.aux_headers
.iter()
.filter(|&(key, _)| key == b"bKGD" || key == b"hIST" || key == b"tRNS")
@ -232,7 +238,6 @@ impl PngData {
}
impl PngImage {
/// Convert the image to the specified interlacing type
/// Returns true if the interlacing was changed, false otherwise
/// The `interlace` parameter specifies the *new* interlacing mode
@ -261,13 +266,13 @@ impl PngImage {
/// Return an iterator over the scanlines of the image
#[inline]
pub fn scan_lines(&self) -> ScanLines {
pub fn scan_lines(&self) -> ScanLines<'_> {
ScanLines::new(self)
}
/// Return an iterator over the scanlines of the image
#[inline]
pub fn scan_lines_mut(&mut self) -> ScanLinesMut {
pub fn scan_lines_mut(&mut self) -> ScanLinesMut<'_> {
ScanLinesMut::new(self)
}
@ -331,7 +336,8 @@ impl PngImage {
let signed = x as i8;
acc + i16::from(signed).abs() as u64
})
}).unwrap();
})
.unwrap();
filtered.push(*best_filter);
filtered.extend_from_slice(best_line);
}

View file

@ -1,4 +1,4 @@
use png::PngImage;
use crate::png::PngImage;
#[derive(Debug, Clone)]
/// An iterator over the scan lines of a PNG image

View file

@ -3,8 +3,13 @@ pub mod prelude {
}
pub trait ParallelIterator: Iterator + Sized {
fn with_max_len(self, _l: usize) -> Self {self}
fn reduce_with<OP>(mut self, op: OP) -> Option<Self::Item> where OP: Fn(Self::Item, Self::Item) -> Self::Item + Sync {
fn with_max_len(self, _l: usize) -> Self {
self
}
fn reduce_with<OP>(mut self, op: OP) -> Option<Self::Item>
where
OP: Fn(Self::Item, Self::Item) -> Self::Item + Sync,
{
if let Some(a) = self.next() {
Some(self.fold(a, op))
} else {
@ -14,18 +19,21 @@ pub trait ParallelIterator: Iterator + Sized {
}
pub trait IntoParallelIterator {
type Iter: Iterator<Item=Self::Item>;
type Iter: Iterator<Item = Self::Item>;
type Item: Send;
fn into_par_iter(self) -> Self::Iter;
}
pub trait IntoParallelRefIterator<'data> {
type Iter: Iterator<Item=Self::Item>;
type Iter: Iterator<Item = Self::Item>;
type Item: Send + 'data;
fn par_iter(&'data self) -> Self::Iter;
}
impl<I: IntoIterator> IntoParallelIterator for I where I::Item: Send {
impl<I: IntoIterator> IntoParallelIterator for I
where
I::Item: Send,
{
type Iter = I::IntoIter;
type Item = I::Item;
@ -35,7 +43,8 @@ impl<I: IntoIterator> IntoParallelIterator for I where I::Item: Send {
}
impl<'data, I: 'data + ?Sized> IntoParallelRefIterator<'data> for I
where &'data I: IntoParallelIterator
where
&'data I: IntoParallelIterator,
{
type Iter = <&'data I as IntoParallelIterator>::Iter;
type Item = <&'data I as IntoParallelIterator>::Item;
@ -45,13 +54,12 @@ impl<'data, I: 'data + ?Sized> IntoParallelRefIterator<'data> for I
}
}
impl<I: Iterator> ParallelIterator for I {
}
impl<I: Iterator> ParallelIterator for I {}
pub fn join<A, B>(a: impl FnOnce() -> A, b: impl FnOnce() -> B) -> (A, B) {
(a(), b())
}
pub fn spawn(a: impl FnOnce() -> A) -> A {
pub fn spawn<A>(a: impl FnOnce() -> A) -> A {
a()
}

View file

@ -1,15 +1,21 @@
use evaluate::Evaluator;
use itertools::flatten;
use png::scan_lines::ScanLine;
use crate::colors::AlphaOptim;
use crate::colors::ColorType;
use crate::evaluate::Evaluator;
use crate::headers::IhdrData;
use crate::png::scan_lines::ScanLine;
use crate::png::PngImage;
#[cfg(not(feature = "parallel"))]
use crate::rayon::prelude::*;
#[cfg(feature = "parallel")]
use rayon::prelude::*;
use std::collections::HashSet;
use std::sync::Arc;
use colors::AlphaOptim;
use headers::IhdrData;
use png::PngImage;
use colors::ColorType;
use rayon::prelude::*;
pub(crate) fn try_alpha_reductions(png: Arc<PngImage>, alphas: &HashSet<AlphaOptim>, eval: &Evaluator) {
pub(crate) fn try_alpha_reductions(
png: Arc<PngImage>,
alphas: &HashSet<AlphaOptim>,
eval: &Evaluator,
) {
assert!(!alphas.is_empty());
let alphas = alphas.iter().collect::<Vec<_>>();
let alphas_iter = alphas.par_iter().with_max_len(1);
@ -88,7 +94,7 @@ fn reduced_alpha_to_white(png: &PngImage, bpc: usize, bpp: usize) -> Vec<u8> {
fn reduced_alpha_to_up(png: &PngImage, bpc: usize, bpp: usize) -> Vec<u8> {
let mut lines = Vec::new();
let mut scan_lines = png.scan_lines().collect::<Vec<ScanLine>>();
let mut scan_lines = png.scan_lines().collect::<Vec<ScanLine<'_>>>();
scan_lines.reverse();
let mut last_line = Vec::new();
let mut current_line = Vec::with_capacity(last_line.len());
@ -111,7 +117,7 @@ fn reduced_alpha_to_up(png: &PngImage, bpc: usize, bpp: usize) -> Vec<u8> {
lines.push(current_line.clone());
current_line.clear();
}
flatten(lines.into_iter().rev()).collect()
lines.into_iter().rev().flatten().collect()
}
fn reduced_alpha_to_down(png: &PngImage, bpc: usize, bpp: usize) -> Vec<u8> {
@ -154,7 +160,7 @@ fn reduced_alpha_to_left(png: &PngImage, bpc: usize, bpp: usize) -> Vec<u8> {
last_pixel = pixel.to_owned();
}
reduced.push(line.filter);
reduced.extend(flatten(line_bytes.chunks(bpp).rev()));
reduced.extend(line_bytes.chunks(bpp).rev().flatten());
}
reduced
}

View file

@ -1,7 +1,7 @@
use headers::IhdrData;
use crate::colors::{BitDepth, ColorType};
use crate::headers::IhdrData;
use crate::png::PngImage;
use bit_vec::BitVec;
use colors::{BitDepth, ColorType};
use png::PngImage;
const ONE_BIT_PERMUTATIONS: [u8; 2] = [0b0000_0000, 0b1111_1111];
const TWO_BIT_PERMUTATIONS: [u8; 5] = [
@ -30,8 +30,7 @@ const FOUR_BIT_PERMUTATIONS: [u8; 11] = [
#[must_use]
pub fn reduce_bit_depth(png: &PngImage, minimum_bits: usize) -> Option<PngImage> {
if png.ihdr.bit_depth != BitDepth::Sixteen {
if png.ihdr.color_type == ColorType::Indexed
|| png.ihdr.color_type == ColorType::Grayscale
if png.ihdr.color_type == ColorType::Indexed || png.ihdr.color_type == ColorType::Grayscale
{
return reduce_bit_depth_8_or_less(png, minimum_bits);
}
@ -40,8 +39,8 @@ pub fn reduce_bit_depth(png: &PngImage, minimum_bits: usize) -> Option<PngImage>
// Reduce from 16 to 8 bits per channel per pixel
let mut reduced = Vec::with_capacity(
(png.ihdr.width * png.ihdr.height * u32::from(png.channels_per_pixel())
+ png.ihdr.height) as usize,
(png.ihdr.width * png.ihdr.height * u32::from(png.channels_per_pixel()) + png.ihdr.height)
as usize,
);
let mut high_byte = 0;
@ -84,17 +83,25 @@ pub fn reduce_bit_depth_8_or_less(png: &PngImage, mut minimum_bits: usize) -> Op
}
for line in png.scan_lines() {
if png.ihdr.color_type == ColorType::Indexed {
let line_max = line.data.iter().map(|&byte| match png.ihdr.bit_depth {
BitDepth::Two => (byte & 0x3).max((byte >> 2) & 0x3).max((byte >> 4) & 0x3).max(byte >> 6),
let line_max = line
.data
.iter()
.map(|&byte| match png.ihdr.bit_depth {
BitDepth::Two => (byte & 0x3)
.max((byte >> 2) & 0x3)
.max((byte >> 4) & 0x3)
.max(byte >> 6),
BitDepth::Four => (byte & 0xF).max(byte >> 4),
_ => byte,
}).max().unwrap_or(0);
_ => byte,
})
.max()
.unwrap_or(0);
let required_bits = match line_max {
x if x > 0x0F => 8,
x if x > 0x03 => 4,
x if x > 0x01 => 2,
_ => 1,
};
};
if required_bits > minimum_bits {
minimum_bits = required_bits;
if minimum_bits >= bit_depth {

View file

@ -1,7 +1,7 @@
use headers::IhdrData;
use colors::{BitDepth, ColorType};
use crate::colors::{BitDepth, ColorType};
use crate::headers::IhdrData;
use crate::png::PngImage;
use itertools::Itertools;
use png::PngImage;
use rgb::{FromSlice, RGB8, RGBA8};
use std::collections::HashMap;
use std::hash::Hash;
@ -145,7 +145,8 @@ pub fn reduced_color_to_palette(png: &PngImage) -> Option<PngImage> {
} else {
None
}
}).max();
})
.max();
let trns_size = num_transparent.map(|n| n + 8).unwrap_or(0);
let headers_size = palette.len() * 3 + 8 + trns_size;
@ -212,9 +213,9 @@ pub fn reduce_rgb_to_grayscale(png: &PngImage) -> Option<PngImage> {
} else {
let pixel_bytes = cur_pixel
.iter()
.step(2)
.step_by(2)
.cloned()
.zip(cur_pixel.iter().skip(1).step(2).cloned())
.zip(cur_pixel.iter().skip(1).step_by(2).cloned())
.unique()
.collect::<Vec<(u8, u8)>>();
if pixel_bytes.len() > 1 {
@ -254,7 +255,7 @@ pub fn reduce_rgb_to_grayscale(png: &PngImage) -> Option<PngImage> {
data: reduced,
ihdr: IhdrData {
color_type: ColorType::Grayscale,
.. png.ihdr
..png.ihdr
},
aux_headers,
palette: None,

View file

@ -1,20 +1,20 @@
use headers::IhdrData;
use std::collections::HashMap;
use colors::{BitDepth, ColorType};
use std::collections::hash_map::Entry::*;
use png::PngImage;
use crate::colors::{BitDepth, ColorType};
use crate::headers::IhdrData;
use crate::png::PngImage;
use rgb::RGBA8;
use std::borrow::Cow;
use std::collections::hash_map::Entry::*;
use std::collections::HashMap;
pub mod alpha;
use alpha::*;
use crate::alpha::*;
pub mod bit_depth;
use bit_depth::*;
use crate::bit_depth::*;
pub mod color;
use color::*;
use crate::color::*;
pub(crate) use bit_depth::reduce_bit_depth;
pub(crate) use alpha::try_alpha_reductions;
pub(crate) use crate::alpha::try_alpha_reductions;
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
@ -38,33 +38,41 @@ pub fn reduced_palette(png: &PngImage) -> Option<PngImage> {
// Find palette entries that are never used
for line in png.scan_lines() {
match png.ihdr.bit_depth {
BitDepth::Eight => for &byte in line.data {
used[byte as usize] = true;
},
BitDepth::Four => for &byte in line.data {
used[(byte & 0x0F) as usize] = true;
used[(byte >> 4) as usize] = true;
},
BitDepth::Two => for &byte in line.data {
used[(byte & 0x03) as usize] = true;
used[((byte >> 2) & 0x03) as usize] = true;
used[((byte >> 4) & 0x03) as usize] = true;
used[(byte >> 6) as usize] = true;
},
BitDepth::Eight => {
for &byte in line.data {
used[byte as usize] = true;
}
}
BitDepth::Four => {
for &byte in line.data {
used[(byte & 0x0F) as usize] = true;
used[(byte >> 4) as usize] = true;
}
}
BitDepth::Two => {
for &byte in line.data {
used[(byte & 0x03) as usize] = true;
used[((byte >> 2) & 0x03) as usize] = true;
used[((byte >> 4) & 0x03) as usize] = true;
used[(byte >> 6) as usize] = true;
}
}
_ => unreachable!(),
}
}
let mut next_index = 0u16;
let mut seen = HashMap::with_capacity(palette.len());
for (i, (used, palette_map)) in
used.iter().cloned().zip(palette_map.iter_mut()).enumerate()
for (i, (used, palette_map)) in used.iter().cloned().zip(palette_map.iter_mut()).enumerate()
{
if !used {
continue;
}
// There are invalid files that use pixel indices beyond palette size
let color = palette.get(i).cloned().unwrap_or(RGBA8::new(0, 0, 0, 255));
let color = palette
.get(i)
.cloned()
.unwrap_or_else(|| RGBA8::new(0, 0, 0, 255));
match seen.entry(color) {
Vacant(new) => {
*palette_map = Some(next_index as u8);
@ -96,7 +104,10 @@ fn do_palette_reduction(png: &PngImage, palette_map: &[Option<u8>; 256]) -> Opti
let mut aux_headers = png.aux_headers.clone();
if let Some(bkgd_header) = png.aux_headers.get(b"bKGD") {
if let Some(Some(map_to)) = bkgd_header.get(0).and_then(|&idx| palette_map.get(idx as usize)) {
if let Some(Some(map_to)) = bkgd_header
.get(0)
.and_then(|&idx| palette_map.get(idx as usize))
{
aux_headers.insert(*b"bKGD", vec![*map_to]);
}
}
@ -146,11 +157,13 @@ fn palette_map_to_byte_map(png: &PngImage, palette_map: &[Option<u8>; 256]) -> O
_ => {}
}
return Some(byte_map)
Some(byte_map)
}
fn reordered_palette(palette: &[RGBA8], palette_map: &[Option<u8>; 256]) -> Vec<RGBA8> {
let max_index = palette_map.iter().cloned()
let max_index = palette_map
.iter()
.cloned()
.filter_map(|x| x)
.max()
.unwrap_or(0) as usize;
@ -163,7 +176,6 @@ fn reordered_palette(palette: &[RGBA8], palette_map: &[Option<u8>; 256]) -> Vec<
new_palette
}
/// 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<PngImage> {
@ -173,7 +185,9 @@ pub fn reduce_color_type(png: &PngImage) -> Option<PngImage> {
// 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) =
reduce_rgba_to_grayscale_alpha(&reduced).or_else(|| reduced_alpha_channel(&reduced))
{
reduced = Cow::Owned(r);
} else if let Some(r) = reduced_color_to_palette(&reduced) {
reduced = Cow::Owned(r);
@ -189,7 +203,9 @@ pub fn reduce_color_type(png: &PngImage) -> Option<PngImage> {
}
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) =
reduce_rgb_to_grayscale(&reduced).or_else(|| reduced_color_to_palette(&reduced))
{
reduced = Cow::Owned(r);
should_reduce_bit_depth = true;
}

View file

@ -1,4 +1,4 @@
extern crate oxipng;
use oxipng;
use oxipng::internal_tests::*;
use oxipng::{InFile, OutFile};

View file

@ -1,4 +1,4 @@
extern crate oxipng;
use oxipng;
use oxipng::Headers;
use oxipng::OutFile;

View file

@ -1,4 +1,4 @@
extern crate oxipng;
use oxipng;
use oxipng::internal_tests::*;
use oxipng::{InFile, OutFile};

View file

@ -1,4 +1,4 @@
extern crate oxipng;
use oxipng;
use oxipng::internal_tests::*;
use oxipng::{InFile, OutFile};
@ -33,7 +33,10 @@ fn test_it_converts(
let (output, opts) = custom.unwrap_or_else(|| get_opts(&input));
let png = PngData::new(&input, opts.fix_errors).unwrap();
assert_eq!(png.raw.ihdr.color_type, color_type_in, "test file is broken");
assert_eq!(
png.raw.ihdr.color_type, color_type_in,
"test file is broken"
);
assert_eq!(png.raw.ihdr.bit_depth, bit_depth_in, "test file is broken");
match oxipng::optimize(&InFile::Path(input), &output, &opts) {
@ -51,8 +54,14 @@ fn test_it_converts(
}
};
assert_eq!(png.raw.ihdr.color_type, color_type_out, "optimized to wrong color type");
assert_eq!(png.raw.ihdr.bit_depth, bit_depth_out, "optimized to wrong bit depth");
assert_eq!(
png.raw.ihdr.color_type, color_type_out,
"optimized to wrong color type"
);
assert_eq!(
png.raw.ihdr.bit_depth, bit_depth_out,
"optimized to wrong bit depth"
);
if let Some(palette) = png.raw.palette.as_ref() {
assert!(palette.len() <= 1 << (png.raw.ihdr.bit_depth.as_u8() as usize));
} else {