Refactoring of internal code into smaller chunks.
There is still more to be done.
This commit is contained in:
parent
4d81e23542
commit
ece85e6d15
10 changed files with 337 additions and 398 deletions
|
|
@ -1,3 +1,6 @@
|
|||
### Version 0.19.1 (unreleased)
|
||||
- Refactor of internal code.
|
||||
|
||||
### Version 0.19.0
|
||||
- [SEMVER_MAJOR] Default to overwriting the input file if `out_file` is not set.
|
||||
This does not affect the CLI, but with the library, it was easy to forget to set the `out_file`,
|
||||
|
|
@ -5,7 +8,7 @@
|
|||
- Bump dependencies, reduces binary size by a considerable amount
|
||||
- Hide all modules from documentation, and only export the specific structures that should be public.
|
||||
Previously there were too many implementation details made public. The modules are still public for the purposes of our integration tests,
|
||||
but we strongly advice against using undocumented modules. These may become private in the future.
|
||||
but we strongly advise against using undocumented modules. These may become private in the future.
|
||||
- Internal refactoring and code cleanup
|
||||
- Fix an error message that was displaying the wrong file path
|
||||
- Fix an issue where the output file would not be written if the input was already optimized,
|
||||
|
|
|
|||
84
Cargo.lock
generated
84
Cargo.lock
generated
|
|
@ -26,9 +26,9 @@ name = "atty"
|
|||
version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.35 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.36 (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.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -78,7 +78,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "2.29.1"
|
||||
version = "2.29.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"ansi_term 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
|
@ -92,17 +92,17 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clippy"
|
||||
version = "0.0.179"
|
||||
version = "0.0.183"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cargo_metadata 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"clippy_lints 0.0.179 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"clippy_lints 0.0.183 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clippy_lints"
|
||||
version = "0.0.179"
|
||||
version = "0.0.183"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"if_chain 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
|
@ -161,7 +161,7 @@ name = "enum_primitive"
|
|||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"num-traits 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -180,7 +180,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
|
||||
[[package]]
|
||||
name = "getopts"
|
||||
version = "0.2.15"
|
||||
version = "0.2.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
|
|
@ -211,8 +211,8 @@ dependencies = [
|
|||
"byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"enum_primitive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-iter 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-rational 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-rational 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"png 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
|
|
@ -257,7 +257,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.35"
|
||||
version = "0.2.36"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
|
|
@ -270,7 +270,7 @@ name = "memchr"
|
|||
version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.35 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -279,7 +279,7 @@ version = "0.1.10"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cc 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.35 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -287,7 +287,7 @@ name = "num-integer"
|
|||
version = "0.1.35"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"num-traits 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -296,21 +296,21 @@ version = "0.1.34"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"num-integer 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-rational"
|
||||
version = "0.1.40"
|
||||
version = "0.1.41"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"num-integer 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.1.41"
|
||||
version = "0.1.42"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
|
|
@ -318,7 +318,7 @@ name = "num_cpus"
|
|||
version = "1.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.35 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -327,13 +327,13 @@ version = "0.19.0"
|
|||
dependencies = [
|
||||
"bit-vec 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"clap 2.29.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"clippy 0.0.179 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"clap 2.29.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"clippy 0.0.183 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"crc 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"image 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"itertools 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.35 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"miniz-sys 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rayon 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
|
@ -363,7 +363,7 @@ version = "0.0.15"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"getopts 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"getopts 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -382,7 +382,7 @@ version = "0.3.20"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.35 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -401,7 +401,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
dependencies = [
|
||||
"coco 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.35 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
|
@ -486,7 +486,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
dependencies = [
|
||||
"dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"itoa 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
|
|
@ -523,7 +523,7 @@ name = "termion"
|
|||
version = "1.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.35 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
|
@ -616,21 +616,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.3"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi-i686-pc-windows-gnu 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi-x86_64-pc-windows-gnu 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-i686-pc-windows-gnu"
|
||||
version = "0.3.2"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.3.2"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
|
|
@ -658,9 +658,9 @@ dependencies = [
|
|||
"checksum byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "652805b7e73fada9d85e9a6682a4abd490cb52d96aeecc12e33a0de34dfd0d23"
|
||||
"checksum cargo_metadata 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "be1057b8462184f634c3a208ee35b0f935cfd94b694b26deadccd98732088d7b"
|
||||
"checksum cc 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "deaf9ec656256bb25b404c51ef50097207b9cbb29c933d31f92cae5a8a0ffee0"
|
||||
"checksum clap 2.29.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8f4a2b3bb7ef3c672d7c13d15613211d5a6976b6892c598b0fcb5d40765f19c2"
|
||||
"checksum clippy 0.0.179 (registry+https://github.com/rust-lang/crates.io-index)" = "f3865be451fd0a4f53376171c2e86e52ef6dfa2d51e8d137229851b332f5ab12"
|
||||
"checksum clippy_lints 0.0.179 (registry+https://github.com/rust-lang/crates.io-index)" = "78002b9b809798e082008d1a90d63b1053243b0b03ded66bb4d661a6248be896"
|
||||
"checksum clap 2.29.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4151c5790817c7d21bbdc6c3530811f798172915f93258244948b93ba19604a6"
|
||||
"checksum clippy 0.0.183 (registry+https://github.com/rust-lang/crates.io-index)" = "a5e81310a5a578c454fb713d381b332d67be11d0e108e5846eaadd7044003026"
|
||||
"checksum clippy_lints 0.0.183 (registry+https://github.com/rust-lang/crates.io-index)" = "0f7b3f5649a03ab72703d07bc53f0d6935e3a9f24f31c84003f801752e4d2692"
|
||||
"checksum coco 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c06169f5beb7e31c7c67ebf5540b8b472d23e3eade3b2ec7d1f5b504a85f91bd"
|
||||
"checksum crc 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bd5d02c0aac6bd68393ed69e00bbc2457f3e89075c6349db7189618dc4ddc1d7"
|
||||
"checksum deflate 0.7.17 (registry+https://github.com/rust-lang/crates.io-index)" = "4dddda59aaab719767ab11d3efd9a714e95b610c4445d4435765021e9d52dfb1"
|
||||
|
|
@ -669,7 +669,7 @@ dependencies = [
|
|||
"checksum enum_primitive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "be4551092f4d519593039259a9ed8daedf0da12e5109c5280338073eaeb81180"
|
||||
"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
|
||||
"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
|
||||
"checksum getopts 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)" = "65922871abd2f101a2eb0eaebadc66668e54a87ad9c3dd82520b5f86ede5eff9"
|
||||
"checksum getopts 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)" = "b900c08c1939860ce8b54dc6a89e26e00c04c380fd0e09796799bd7f12861e05"
|
||||
"checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb"
|
||||
"checksum idna 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "014b298351066f1512874135335d62a789ffe78a9974f94b43ed5621951eaf7d"
|
||||
"checksum if_chain 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "61bb90bdd39e3af69b0172dfc6130f6cd6332bf040fbb9bdd4401d37adbd48b8"
|
||||
|
|
@ -680,14 +680,14 @@ dependencies = [
|
|||
"checksum itoa 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8324a32baf01e2ae060e9de58ed0bc2320c9a2833491ee36cd3b4c414de4db8c"
|
||||
"checksum lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73"
|
||||
"checksum lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c8f31047daa365f19be14b47c29df4f7c3b581832407daabe6ae77397619237d"
|
||||
"checksum libc 0.2.35 (registry+https://github.com/rust-lang/crates.io-index)" = "96264e9b293e95d25bfcbbf8a88ffd1aedc85b754eba8b7d78012f638ba220eb"
|
||||
"checksum libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)" = "1e5d97d6708edaa407429faa671b942dc0f2727222fb6b6539bf1db936e4b121"
|
||||
"checksum matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "100aabe6b8ff4e4a7e32c1c13523379802df0772b82466207ac25b013f193376"
|
||||
"checksum memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "796fba70e76612589ed2ce7f45282f5af869e0fdd7cc6199fa1aa1f1d591ba9d"
|
||||
"checksum miniz-sys 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "609ce024854aeb19a0ef7567d348aaa5a746b32fb72e336df7fcc16869d7e2b4"
|
||||
"checksum num-integer 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)" = "d1452e8b06e448a07f0e6ebb0bb1d92b8890eea63288c0b627331d53514d0fba"
|
||||
"checksum num-iter 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)" = "7485fcc84f85b4ecd0ea527b14189281cf27d60e583ae65ebc9c088b13dffe01"
|
||||
"checksum num-rational 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "0c7cb72a95250d8a370105c828f388932373e0e94414919891a0f945222310fe"
|
||||
"checksum num-traits 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "cacfcab5eb48250ee7d0c7896b51a2c5eec99c1feea5f32025635f5ae4b00070"
|
||||
"checksum num-rational 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "0b950f75e042fdd710460084d19c8efdcd72d65183ead8ecd04b90483f5a55d2"
|
||||
"checksum num-traits 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "9936036cc70fe4a8b2d338ab665900323290efb03983c86cbe235ae800ad8017"
|
||||
"checksum num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c51a3322e4bca9d212ad9a158a02abc6934d005490c054a2778df73a70aa0a30"
|
||||
"checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831"
|
||||
"checksum png 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f0b0cabbbd20c2d7f06dbf015e06aad59b6ca3d9ed14848783e98af9aaf19925"
|
||||
|
|
@ -726,7 +726,7 @@ dependencies = [
|
|||
"checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122"
|
||||
"checksum vec_map 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "887b5b631c2ad01628bbbaa7dd4c869f80d3186688f8d0b6f58774fbe324988c"
|
||||
"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
|
||||
"checksum winapi 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b09fb3b6f248ea4cd42c9a65113a847d612e17505d6ebd1f7357ad68a8bf8693"
|
||||
"checksum winapi-i686-pc-windows-gnu 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ec6667f60c23eca65c561e63a13d81b44234c2e38a6b6c959025ee907ec614cc"
|
||||
"checksum winapi-x86_64-pc-windows-gnu 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "98f12c52b2630cd05d2c3ffd8e008f7f48252c042b4871c72aed9dc733b96668"
|
||||
"checksum winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "04e3bd221fcbe8a271359c04f21a76db7d0c6028862d1bb5512d85e1e2eb5bb3"
|
||||
"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.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ea92ee4d5ceb063a154706472afcf453c69c9d72485946c80e8f439fffbd0043"
|
||||
|
|
|
|||
|
|
@ -144,7 +144,6 @@ pub fn unfilter_line(filter: u8, bpp: usize, data: &[u8], last_line: &[u8]) -> V
|
|||
unfiltered
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn paeth_predictor(a: u8, b: u8, c: u8) -> u8 {
|
||||
let p = i32::from(a) + i32::from(b) - i32::from(c);
|
||||
let pa = (p - i32::from(a)).abs();
|
||||
|
|
|
|||
219
src/lib.rs
219
src/lib.rs
|
|
@ -12,7 +12,7 @@ extern crate num_cpus;
|
|||
extern crate rayon;
|
||||
extern crate zopfli;
|
||||
|
||||
use image::{GenericImage, ImageFormat, Pixel};
|
||||
use image::{DynamicImage, GenericImage, ImageFormat, Pixel};
|
||||
use png::PngData;
|
||||
use rayon::prelude::*;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
|
|
@ -173,19 +173,18 @@ impl Options {
|
|||
}
|
||||
}
|
||||
|
||||
// The following methods make assumptions that they are operating
|
||||
// on an `Options` struct generated by the `default` method.
|
||||
fn apply_preset_0(mut self) -> Self {
|
||||
self.idat_recoding = false;
|
||||
let mut compression = HashSet::new();
|
||||
compression.insert(3);
|
||||
self.compression = compression;
|
||||
self.compression.clear();
|
||||
self.compression.insert(3);
|
||||
self
|
||||
}
|
||||
|
||||
fn apply_preset_1(mut self) -> Self {
|
||||
let filter = HashSet::new();
|
||||
self.filter = filter;
|
||||
let strategies = HashSet::new();
|
||||
self.strategies = strategies;
|
||||
self.filter.clear();
|
||||
self.strategies.clear();
|
||||
self.use_heuristics = true;
|
||||
self
|
||||
}
|
||||
|
|
@ -195,94 +194,30 @@ impl Options {
|
|||
}
|
||||
|
||||
fn apply_preset_3(mut self) -> Self {
|
||||
let mut filter = HashSet::new();
|
||||
filter.insert(0);
|
||||
filter.insert(5);
|
||||
self.filter = filter;
|
||||
let mut compression = HashSet::new();
|
||||
compression.insert(9);
|
||||
self.compression = compression;
|
||||
let mut memory = HashSet::new();
|
||||
for i in 8..10 {
|
||||
memory.insert(i);
|
||||
}
|
||||
self.memory = memory;
|
||||
let mut strategies = HashSet::new();
|
||||
for i in 0..4 {
|
||||
strategies.insert(i);
|
||||
}
|
||||
self.strategies = strategies;
|
||||
self.memory.insert(8);
|
||||
self
|
||||
}
|
||||
|
||||
fn apply_preset_4(mut self) -> Self {
|
||||
let mut filter = HashSet::new();
|
||||
for i in 0..6 {
|
||||
filter.insert(i);
|
||||
for i in 1..5 {
|
||||
self.filter.insert(i);
|
||||
}
|
||||
self.filter = filter;
|
||||
let mut compression = HashSet::new();
|
||||
compression.insert(9);
|
||||
self.compression = compression;
|
||||
let mut memory = HashSet::new();
|
||||
for i in 8..10 {
|
||||
memory.insert(i);
|
||||
}
|
||||
self.memory = memory;
|
||||
let mut strategies = HashSet::new();
|
||||
for i in 0..4 {
|
||||
strategies.insert(i);
|
||||
}
|
||||
self.strategies = strategies;
|
||||
self
|
||||
self.apply_preset_3()
|
||||
}
|
||||
|
||||
fn apply_preset_5(mut self) -> Self {
|
||||
let mut filter = HashSet::new();
|
||||
for i in 0..6 {
|
||||
filter.insert(i);
|
||||
for i in 3..9 {
|
||||
self.compression.insert(i);
|
||||
}
|
||||
self.filter = filter;
|
||||
let mut compression = HashSet::new();
|
||||
for i in 3..10 {
|
||||
compression.insert(i);
|
||||
}
|
||||
self.compression = compression;
|
||||
let mut memory = HashSet::new();
|
||||
for i in 8..10 {
|
||||
memory.insert(i);
|
||||
}
|
||||
self.memory = memory;
|
||||
let mut strategies = HashSet::new();
|
||||
for i in 0..4 {
|
||||
strategies.insert(i);
|
||||
}
|
||||
self.strategies = strategies;
|
||||
self
|
||||
self.apply_preset_4()
|
||||
}
|
||||
|
||||
fn apply_preset_6(mut self) -> Self {
|
||||
let mut filter = HashSet::new();
|
||||
for i in 0..6 {
|
||||
filter.insert(i);
|
||||
for i in 1..3 {
|
||||
self.compression.insert(i);
|
||||
}
|
||||
self.filter = filter;
|
||||
let mut compression = HashSet::new();
|
||||
for i in 1..10 {
|
||||
compression.insert(i);
|
||||
}
|
||||
self.compression = compression;
|
||||
let mut memory = HashSet::new();
|
||||
for i in 7..10 {
|
||||
memory.insert(i);
|
||||
}
|
||||
self.memory = memory;
|
||||
let mut strategies = HashSet::new();
|
||||
for i in 0..4 {
|
||||
strategies.insert(i);
|
||||
}
|
||||
self.strategies = strategies;
|
||||
self
|
||||
self.memory.insert(7);
|
||||
self.apply_preset_5()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -321,11 +256,11 @@ impl Default for Options {
|
|||
force: false,
|
||||
preserve_attrs: false,
|
||||
verbosity: Some(0),
|
||||
filter: filter,
|
||||
filter,
|
||||
interlace: None,
|
||||
compression: compression,
|
||||
memory: memory,
|
||||
strategies: strategies,
|
||||
compression,
|
||||
memory,
|
||||
strategies,
|
||||
window: 15,
|
||||
alphas,
|
||||
bit_depth_reduction: true,
|
||||
|
|
@ -375,19 +310,7 @@ pub fn optimize(input_path: &Path, opts: &Options) -> Result<(), PngError> {
|
|||
}
|
||||
} else {
|
||||
if opts.backup {
|
||||
let backup_file = input_path.with_extension(format!(
|
||||
"bak.{}",
|
||||
input_path.extension().unwrap().to_str().unwrap()
|
||||
));
|
||||
match copy(input_path, &backup_file) {
|
||||
Ok(x) => x,
|
||||
Err(_) => {
|
||||
return Err(PngError::new(&format!(
|
||||
"Unable to write to backup file at {}",
|
||||
backup_file.display()
|
||||
)))
|
||||
}
|
||||
};
|
||||
perform_backup(input_path)?;
|
||||
}
|
||||
|
||||
if opts.stdout {
|
||||
|
|
@ -408,34 +331,7 @@ pub fn optimize(input_path: &Path, opts: &Options) -> Result<(), PngError> {
|
|||
};
|
||||
|
||||
if opts.preserve_attrs {
|
||||
match File::open(input_path) {
|
||||
Ok(f) => {
|
||||
match f.metadata() {
|
||||
Ok(metadata) => {
|
||||
// TODO: Implement full permission changing on Unix
|
||||
// Not available in stable, requires block cfg statements
|
||||
// See https://github.com/rust-lang/rust/issues/15701
|
||||
{
|
||||
match out_file.metadata() {
|
||||
Ok(out_meta) => {
|
||||
let readonly = metadata.permissions().readonly();
|
||||
out_meta.permissions().set_readonly(readonly);
|
||||
}
|
||||
Err(_) => if opts.verbosity.is_some() {
|
||||
eprintln!("Failed to set permissions on output file");
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(_) => if opts.verbosity.is_some() {
|
||||
eprintln!("Failed to read permissions on input file");
|
||||
},
|
||||
}
|
||||
}
|
||||
Err(_) => if opts.verbosity.is_some() {
|
||||
eprintln!("Failed to read permissions on input file");
|
||||
},
|
||||
};
|
||||
copy_permissions(input_path, &out_file, opts.verbosity);
|
||||
}
|
||||
|
||||
let mut buffer = BufWriter::new(out_file);
|
||||
|
|
@ -480,6 +376,15 @@ pub fn optimize_from_memory(data: &[u8], opts: &Options) -> Result<Vec<u8>, PngE
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Copy)]
|
||||
/// Defines options to be used for a single compression trial
|
||||
struct TrialOptions {
|
||||
pub filter: u8,
|
||||
pub compression: u8,
|
||||
pub memory: u8,
|
||||
pub strategy: u8,
|
||||
}
|
||||
|
||||
/// Perform optimization on the input PNG object using the options provided
|
||||
fn optimize_png(
|
||||
png: &mut PngData,
|
||||
|
|
@ -688,17 +593,7 @@ fn optimize_png(
|
|||
|
||||
if let Ok(new_png) = new_png {
|
||||
if let Ok(old_png) = old_png {
|
||||
if old_png
|
||||
.pixels()
|
||||
.map(|x| x.2.channels().to_owned())
|
||||
.filter(|p| !(p.len() == 4 && p[3] == 0))
|
||||
.collect::<Vec<Vec<u8>>>()
|
||||
== new_png
|
||||
.pixels()
|
||||
.map(|x| x.2.channels().to_owned())
|
||||
.filter(|p| !(p.len() == 4 && p[3] == 0))
|
||||
.collect::<Vec<Vec<u8>>>()
|
||||
{
|
||||
if image_to_pixel_array(&old_png) == image_to_pixel_array(&new_png) {
|
||||
return Ok(output);
|
||||
}
|
||||
} else {
|
||||
|
|
@ -758,7 +653,6 @@ fn perform_reductions(png: &mut png::PngData, opts: &Options) -> bool {
|
|||
}
|
||||
|
||||
/// Display the status of the image data after a reduction has taken place
|
||||
#[inline]
|
||||
fn report_reduction(png: &png::PngData) {
|
||||
if let Some(ref palette) = png.palette {
|
||||
eprintln!(
|
||||
|
|
@ -802,16 +696,45 @@ fn perform_strip(png: &mut png::PngData, opts: &Options) {
|
|||
}
|
||||
|
||||
/// Check if an image was already optimized prior to oxipng's operations
|
||||
#[inline]
|
||||
fn is_fully_optimized(original_size: usize, optimized_size: usize, opts: &Options) -> bool {
|
||||
original_size <= optimized_size && !opts.force && opts.interlace.is_none()
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Copy)]
|
||||
/// Defines options to be used for a single compression trial
|
||||
struct TrialOptions {
|
||||
pub filter: u8,
|
||||
pub compression: u8,
|
||||
pub memory: u8,
|
||||
pub strategy: u8,
|
||||
fn perform_backup(input_path: &Path) -> Result<(), PngError> {
|
||||
let backup_file = input_path.with_extension(format!(
|
||||
"bak.{}",
|
||||
input_path.extension().unwrap().to_str().unwrap()
|
||||
));
|
||||
copy(input_path, &backup_file).map(|_| ()).map_err(|_| {
|
||||
PngError::new(&format!(
|
||||
"Unable to write to backup file at {}",
|
||||
backup_file.display()
|
||||
))
|
||||
})
|
||||
}
|
||||
|
||||
fn copy_permissions(input_path: &Path, out_file: &File, verbosity: Option<u8>) {
|
||||
if let Ok(f) = File::open(input_path) {
|
||||
if let Ok(metadata) = f.metadata() {
|
||||
// TODO: Implement full permission changing on Unix
|
||||
// Not available in stable, requires block cfg statements
|
||||
// See https://github.com/rust-lang/rust/issues/15701
|
||||
if let Ok(out_meta) = out_file.metadata() {
|
||||
let readonly = metadata.permissions().readonly();
|
||||
out_meta.permissions().set_readonly(readonly);
|
||||
return;
|
||||
}
|
||||
}
|
||||
};
|
||||
if verbosity.is_some() {
|
||||
eprintln!("Failed to set permissions on output file");
|
||||
}
|
||||
}
|
||||
|
||||
fn image_to_pixel_array(image: &DynamicImage) -> Vec<Vec<u8>> {
|
||||
image
|
||||
.pixels()
|
||||
.map(|x| x.2.channels().to_owned())
|
||||
.filter(|p| !(p.len() == 4 && p[3] == 0))
|
||||
.collect()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,8 @@ use filters::*;
|
|||
use headers::*;
|
||||
use interlace::{deinterlace_image, interlace_image};
|
||||
use itertools::Itertools;
|
||||
use reduction::*;
|
||||
use reduction::bit_depth::*;
|
||||
use reduction::color::*;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::fs::File;
|
||||
use std::io::{Read, Seek, SeekFrom};
|
||||
|
|
@ -21,145 +22,9 @@ const STD_STRATEGY: u8 = 2; // Huffman only
|
|||
const STD_WINDOW: u8 = 15;
|
||||
const STD_FILTERS: [u8; 2] = [0, 5];
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
/// An iterator over the scan lines of a PNG image
|
||||
pub struct ScanLines<'a> {
|
||||
/// A reference to the PNG image being iterated upon
|
||||
pub png: &'a PngData,
|
||||
start: usize,
|
||||
end: usize,
|
||||
/// Current pass number, and 0-indexed row within the pass
|
||||
pass: Option<(u8, u32)>,
|
||||
}
|
||||
mod scan_lines;
|
||||
|
||||
impl<'a> Iterator for ScanLines<'a> {
|
||||
type Item = ScanLine;
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.end == self.png.raw_data.len() {
|
||||
None
|
||||
} else if self.png.ihdr_data.interlaced == 1 {
|
||||
// Scanlines for interlaced PNG files
|
||||
if self.pass.is_none() {
|
||||
self.pass = Some((1, 0));
|
||||
}
|
||||
// Handle edge cases for images smaller than 5 pixels in either direction
|
||||
if self.png.ihdr_data.width < 5 && self.pass.unwrap().0 == 2 {
|
||||
if let Some(pass) = self.pass.as_mut() {
|
||||
pass.0 = 3;
|
||||
pass.1 = 4;
|
||||
}
|
||||
}
|
||||
// Intentionally keep these separate so that they can be applied one after another
|
||||
if self.png.ihdr_data.height < 5 && self.pass.unwrap().0 == 3 {
|
||||
if let Some(pass) = self.pass.as_mut() {
|
||||
pass.0 = 4;
|
||||
pass.1 = 0;
|
||||
}
|
||||
}
|
||||
let bits_per_pixel = u32::from(self.png.ihdr_data.bit_depth.as_u8())
|
||||
* u32::from(self.png.channels_per_pixel());
|
||||
let y_steps;
|
||||
let pixels_factor;
|
||||
match self.pass {
|
||||
Some((1, _)) | Some((2, _)) => {
|
||||
pixels_factor = 8;
|
||||
y_steps = 8;
|
||||
}
|
||||
Some((3, _)) => {
|
||||
pixels_factor = 4;
|
||||
y_steps = 8;
|
||||
}
|
||||
Some((4, _)) => {
|
||||
pixels_factor = 4;
|
||||
y_steps = 4;
|
||||
}
|
||||
Some((5, _)) => {
|
||||
pixels_factor = 2;
|
||||
y_steps = 4;
|
||||
}
|
||||
Some((6, _)) => {
|
||||
pixels_factor = 2;
|
||||
y_steps = 2;
|
||||
}
|
||||
Some((7, _)) => {
|
||||
pixels_factor = 1;
|
||||
y_steps = 2;
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
let mut pixels_per_line = self.png.ihdr_data.width / pixels_factor as u32;
|
||||
// Determine whether to add pixels if there is a final, incomplete 8x8 block
|
||||
let gap = self.png.ihdr_data.width % pixels_factor;
|
||||
if gap > 0 {
|
||||
match self.pass.unwrap().0 {
|
||||
1 | 3 | 5 => {
|
||||
pixels_per_line += 1;
|
||||
}
|
||||
2 if gap >= 5 => {
|
||||
pixels_per_line += 1;
|
||||
}
|
||||
4 if gap >= 3 => {
|
||||
pixels_per_line += 1;
|
||||
}
|
||||
6 if gap >= 2 => {
|
||||
pixels_per_line += 1;
|
||||
}
|
||||
_ => (),
|
||||
};
|
||||
}
|
||||
let current_pass = if let Some(pass) = self.pass {
|
||||
Some(pass.0)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let bytes_per_line = ((pixels_per_line * bits_per_pixel + 7) / 8) as usize;
|
||||
self.start = self.end;
|
||||
self.end = self.start + bytes_per_line + 1;
|
||||
if let Some(pass) = self.pass.as_mut() {
|
||||
if pass.1 + y_steps >= self.png.ihdr_data.height {
|
||||
pass.0 += 1;
|
||||
pass.1 = match pass.0 {
|
||||
3 => 4,
|
||||
5 => 2,
|
||||
7 => 1,
|
||||
_ => 0,
|
||||
};
|
||||
} else {
|
||||
pass.1 += y_steps;
|
||||
}
|
||||
}
|
||||
Some(ScanLine {
|
||||
filter: self.png.raw_data[self.start],
|
||||
data: self.png.raw_data[(self.start + 1)..self.end].to_owned(),
|
||||
pass: current_pass,
|
||||
})
|
||||
} else {
|
||||
// Standard, non-interlaced PNG scanlines
|
||||
let bits_per_line = self.png.ihdr_data.width as usize
|
||||
* self.png.ihdr_data.bit_depth.as_u8() as usize
|
||||
* self.png.channels_per_pixel() as usize;
|
||||
let bytes_per_line = (bits_per_line + 7) / 8 as usize;
|
||||
self.start = self.end;
|
||||
self.end = self.start + bytes_per_line + 1;
|
||||
Some(ScanLine {
|
||||
filter: self.png.raw_data[self.start],
|
||||
data: self.png.raw_data[(self.start + 1)..self.end].to_owned(),
|
||||
pass: None,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
/// A scan line in a PNG image
|
||||
pub struct ScanLine {
|
||||
/// The filter type used to encode the current scan line (0-4)
|
||||
pub filter: u8,
|
||||
/// The byte data for the current scan line, encoded with the filter specified in the `filter` field
|
||||
pub data: Vec<u8>,
|
||||
/// The current pass if the image is interlaced
|
||||
pub pass: Option<u8>,
|
||||
}
|
||||
use self::scan_lines::{ScanLine, ScanLines};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
/// Contains all data relevant to a PNG image
|
||||
141
src/png/scan_lines.rs
Normal file
141
src/png/scan_lines.rs
Normal file
|
|
@ -0,0 +1,141 @@
|
|||
use super::PngData;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
/// An iterator over the scan lines of a PNG image
|
||||
pub struct ScanLines<'a> {
|
||||
/// A reference to the PNG image being iterated upon
|
||||
pub png: &'a PngData,
|
||||
pub start: usize,
|
||||
pub end: usize,
|
||||
/// Current pass number, and 0-indexed row within the pass
|
||||
pub pass: Option<(u8, u32)>,
|
||||
}
|
||||
|
||||
impl<'a> Iterator for ScanLines<'a> {
|
||||
type Item = ScanLine;
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.end == self.png.raw_data.len() {
|
||||
None
|
||||
} else if self.png.ihdr_data.interlaced == 1 {
|
||||
// Scanlines for interlaced PNG files
|
||||
if self.pass.is_none() {
|
||||
self.pass = Some((1, 0));
|
||||
}
|
||||
// Handle edge cases for images smaller than 5 pixels in either direction
|
||||
if self.png.ihdr_data.width < 5 && self.pass.unwrap().0 == 2 {
|
||||
if let Some(pass) = self.pass.as_mut() {
|
||||
pass.0 = 3;
|
||||
pass.1 = 4;
|
||||
}
|
||||
}
|
||||
// Intentionally keep these separate so that they can be applied one after another
|
||||
if self.png.ihdr_data.height < 5 && self.pass.unwrap().0 == 3 {
|
||||
if let Some(pass) = self.pass.as_mut() {
|
||||
pass.0 = 4;
|
||||
pass.1 = 0;
|
||||
}
|
||||
}
|
||||
let bits_per_pixel = u32::from(self.png.ihdr_data.bit_depth.as_u8())
|
||||
* u32::from(self.png.channels_per_pixel());
|
||||
let y_steps;
|
||||
let pixels_factor;
|
||||
match self.pass {
|
||||
Some((1, _)) | Some((2, _)) => {
|
||||
pixels_factor = 8;
|
||||
y_steps = 8;
|
||||
}
|
||||
Some((3, _)) => {
|
||||
pixels_factor = 4;
|
||||
y_steps = 8;
|
||||
}
|
||||
Some((4, _)) => {
|
||||
pixels_factor = 4;
|
||||
y_steps = 4;
|
||||
}
|
||||
Some((5, _)) => {
|
||||
pixels_factor = 2;
|
||||
y_steps = 4;
|
||||
}
|
||||
Some((6, _)) => {
|
||||
pixels_factor = 2;
|
||||
y_steps = 2;
|
||||
}
|
||||
Some((7, _)) => {
|
||||
pixels_factor = 1;
|
||||
y_steps = 2;
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
let mut pixels_per_line = self.png.ihdr_data.width / pixels_factor as u32;
|
||||
// Determine whether to add pixels if there is a final, incomplete 8x8 block
|
||||
let gap = self.png.ihdr_data.width % pixels_factor;
|
||||
if gap > 0 {
|
||||
match self.pass.unwrap().0 {
|
||||
1 | 3 | 5 => {
|
||||
pixels_per_line += 1;
|
||||
}
|
||||
2 if gap >= 5 => {
|
||||
pixels_per_line += 1;
|
||||
}
|
||||
4 if gap >= 3 => {
|
||||
pixels_per_line += 1;
|
||||
}
|
||||
6 if gap >= 2 => {
|
||||
pixels_per_line += 1;
|
||||
}
|
||||
_ => (),
|
||||
};
|
||||
}
|
||||
let current_pass = if let Some(pass) = self.pass {
|
||||
Some(pass.0)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let bytes_per_line = ((pixels_per_line * bits_per_pixel + 7) / 8) as usize;
|
||||
self.start = self.end;
|
||||
self.end = self.start + bytes_per_line + 1;
|
||||
if let Some(pass) = self.pass.as_mut() {
|
||||
if pass.1 + y_steps >= self.png.ihdr_data.height {
|
||||
pass.0 += 1;
|
||||
pass.1 = match pass.0 {
|
||||
3 => 4,
|
||||
5 => 2,
|
||||
7 => 1,
|
||||
_ => 0,
|
||||
};
|
||||
} else {
|
||||
pass.1 += y_steps;
|
||||
}
|
||||
}
|
||||
Some(ScanLine {
|
||||
filter: self.png.raw_data[self.start],
|
||||
data: self.png.raw_data[(self.start + 1)..self.end].to_owned(),
|
||||
pass: current_pass,
|
||||
})
|
||||
} else {
|
||||
// Standard, non-interlaced PNG scanlines
|
||||
let bits_per_line = self.png.ihdr_data.width as usize
|
||||
* self.png.ihdr_data.bit_depth.as_u8() as usize
|
||||
* self.png.channels_per_pixel() as usize;
|
||||
let bytes_per_line = (bits_per_line + 7) / 8 as usize;
|
||||
self.start = self.end;
|
||||
self.end = self.start + bytes_per_line + 1;
|
||||
Some(ScanLine {
|
||||
filter: self.png.raw_data[self.start],
|
||||
data: self.png.raw_data[(self.start + 1)..self.end].to_owned(),
|
||||
pass: None,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
/// A scan line in a PNG image
|
||||
pub struct ScanLine {
|
||||
/// The filter type used to encode the current scan line (0-4)
|
||||
pub filter: u8,
|
||||
/// The byte data for the current scan line, encoded with the filter specified in the `filter` field
|
||||
pub data: Vec<u8>,
|
||||
/// The current pass if the image is interlaced
|
||||
pub pass: Option<u8>,
|
||||
}
|
||||
26
src/reduction/alpha.rs
Normal file
26
src/reduction/alpha.rs
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
use png::PngData;
|
||||
|
||||
pub fn reduce_alpha_channel(png: &mut PngData, bpp_factor: usize) -> Option<Vec<u8>> {
|
||||
let mut reduced = Vec::with_capacity(png.raw_data.len());
|
||||
let byte_depth: u8 = png.ihdr_data.bit_depth.as_u8() >> 3;
|
||||
let bpp: usize = bpp_factor * byte_depth as usize;
|
||||
let colored_bytes = bpp - byte_depth as usize;
|
||||
for line in png.scan_lines() {
|
||||
reduced.push(line.filter);
|
||||
for (i, byte) in line.data.iter().enumerate() {
|
||||
if i % bpp >= colored_bytes {
|
||||
if *byte != 255 {
|
||||
return None;
|
||||
}
|
||||
} else {
|
||||
reduced.push(*byte);
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some(sbit_header) = png.aux_headers.get_mut(&"sBIT".to_string()) {
|
||||
assert_eq!(sbit_header.len(), bpp_factor);
|
||||
sbit_header.pop();
|
||||
}
|
||||
|
||||
Some(reduced)
|
||||
}
|
||||
45
src/reduction/bit_depth.rs
Normal file
45
src/reduction/bit_depth.rs
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
use bit_vec::BitVec;
|
||||
use colors::{BitDepth, ColorType};
|
||||
use png::PngData;
|
||||
|
||||
pub fn reduce_bit_depth_8_or_less(png: &mut PngData) -> bool {
|
||||
let mut reduced = BitVec::with_capacity(png.raw_data.len() * 8);
|
||||
let bit_depth: usize = png.ihdr_data.bit_depth.as_u8() as usize;
|
||||
let mut allowed_bits = 1;
|
||||
for line in png.scan_lines() {
|
||||
let bit_vec = BitVec::from_bytes(&line.data);
|
||||
for (i, bit) in bit_vec.iter().enumerate() {
|
||||
let bit_index = if png.ihdr_data.color_type == ColorType::Indexed {
|
||||
bit_depth - (i % bit_depth)
|
||||
} else {
|
||||
i % bit_depth
|
||||
};
|
||||
if bit && bit_index > allowed_bits {
|
||||
allowed_bits = bit_index.next_power_of_two();
|
||||
if allowed_bits == bit_depth {
|
||||
// Not reducable
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for line in png.scan_lines() {
|
||||
reduced.extend(BitVec::from_bytes(&[line.filter]));
|
||||
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 <= allowed_bits {
|
||||
reduced.push(bit);
|
||||
}
|
||||
}
|
||||
// Pad end of line to get 8 bits per byte
|
||||
while reduced.len() % 8 != 0 {
|
||||
reduced.push(false);
|
||||
}
|
||||
}
|
||||
|
||||
png.raw_data = reduced.to_bytes();
|
||||
png.ihdr_data.bit_depth = BitDepth::from_u8(allowed_bits as u8);
|
||||
true
|
||||
}
|
||||
|
|
@ -1,49 +1,8 @@
|
|||
use bit_vec::BitVec;
|
||||
use colors::{BitDepth, ColorType};
|
||||
use itertools::Itertools;
|
||||
use png::PngData;
|
||||
|
||||
pub fn reduce_bit_depth_8_or_less(png: &mut PngData) -> bool {
|
||||
let mut reduced = BitVec::with_capacity(png.raw_data.len() * 8);
|
||||
let bit_depth: usize = png.ihdr_data.bit_depth.as_u8() as usize;
|
||||
let mut allowed_bits = 1;
|
||||
for line in png.scan_lines() {
|
||||
let bit_vec = BitVec::from_bytes(&line.data);
|
||||
for (i, bit) in bit_vec.iter().enumerate() {
|
||||
let bit_index = if png.ihdr_data.color_type == ColorType::Indexed {
|
||||
bit_depth - (i % bit_depth)
|
||||
} else {
|
||||
i % bit_depth
|
||||
};
|
||||
if bit && bit_index > allowed_bits {
|
||||
allowed_bits = bit_index.next_power_of_two();
|
||||
if allowed_bits == bit_depth {
|
||||
// Not reducable
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for line in png.scan_lines() {
|
||||
reduced.extend(BitVec::from_bytes(&[line.filter]));
|
||||
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 <= allowed_bits {
|
||||
reduced.push(bit);
|
||||
}
|
||||
}
|
||||
// Pad end of line to get 8 bits per byte
|
||||
while reduced.len() % 8 != 0 {
|
||||
reduced.push(false);
|
||||
}
|
||||
}
|
||||
|
||||
png.raw_data = reduced.to_bytes();
|
||||
png.ihdr_data.bit_depth = BitDepth::from_u8(allowed_bits as u8);
|
||||
true
|
||||
}
|
||||
use super::alpha::reduce_alpha_channel;
|
||||
|
||||
pub fn reduce_rgba_to_rgb(png: &mut PngData) -> bool {
|
||||
if let Some(reduced) = reduce_alpha_channel(png, 4) {
|
||||
|
|
@ -325,28 +284,3 @@ pub fn reduce_grayscale_alpha_to_grayscale(png: &mut PngData) -> bool {
|
|||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn reduce_alpha_channel(png: &mut PngData, bpp_factor: usize) -> Option<Vec<u8>> {
|
||||
let mut reduced = Vec::with_capacity(png.raw_data.len());
|
||||
let byte_depth: u8 = png.ihdr_data.bit_depth.as_u8() >> 3;
|
||||
let bpp: usize = bpp_factor * byte_depth as usize;
|
||||
let colored_bytes = bpp - byte_depth as usize;
|
||||
for line in png.scan_lines() {
|
||||
reduced.push(line.filter);
|
||||
for (i, byte) in line.data.iter().enumerate() {
|
||||
if i % bpp >= colored_bytes {
|
||||
if *byte != 255 {
|
||||
return None;
|
||||
}
|
||||
} else {
|
||||
reduced.push(*byte);
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some(sbit_header) = png.aux_headers.get_mut(&"sBIT".to_string()) {
|
||||
assert_eq!(sbit_header.len(), bpp_factor);
|
||||
sbit_header.pop();
|
||||
}
|
||||
|
||||
Some(reduced)
|
||||
}
|
||||
3
src/reduction/mod.rs
Normal file
3
src/reduction/mod.rs
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
mod alpha;
|
||||
pub mod bit_depth;
|
||||
pub mod color;
|
||||
Loading…
Reference in a new issue