From 9c386d0de95bd29187f48fffc14cb05fc535bd02 Mon Sep 17 00:00:00 2001 From: Bastien Orivel Date: Mon, 12 Aug 2019 12:39:47 +0000 Subject: [PATCH] Bug 1573039 - Part 2: Revendor dependencies. r=emilio Differential Revision: https://phabricator.services.mozilla.com/D41489 --HG-- rename : third_party/rust/image/src/hdr/hdr_decoder.rs => third_party/rust/image/src/hdr/decoder.rs rename : third_party/rust/image/src/hdr/hdr_encoder.rs => third_party/rust/image/src/hdr/encoder.rs extra : moz-landing-system : lando --- .../rust/crc32fast/.cargo-checksum.json | 1 + third_party/rust/crc32fast/Cargo.toml | 41 ++ third_party/rust/crc32fast/LICENSE-APACHE | 202 ++++++ third_party/rust/crc32fast/LICENSE-MIT | 21 + third_party/rust/crc32fast/README.md | 81 +++ third_party/rust/crc32fast/benches/bench.rs | 49 ++ third_party/rust/crc32fast/build.rs | 35 + third_party/rust/crc32fast/src/baseline.rs | 94 +++ third_party/rust/crc32fast/src/combine.rs | 77 +++ third_party/rust/crc32fast/src/lib.rs | 178 +++++ .../rust/crc32fast/src/specialized/aarch64.rs | 88 +++ .../rust/crc32fast/src/specialized/mod.rs | 36 + .../crc32fast/src/specialized/pclmulqdq.rs | 225 +++++++ third_party/rust/crc32fast/src/table.rs | 626 ++++++++++++++++++ third_party/rust/image/.cargo-checksum.json | 2 +- third_party/rust/image/CHANGES.md | 35 + third_party/rust/image/Cargo.toml | 17 +- third_party/rust/image/README.md | 52 +- third_party/rust/image/benches/README.md | 6 + third_party/rust/image/src/animation.rs | 4 +- third_party/rust/image/src/bmp/decoder.rs | 172 +++-- third_party/rust/image/src/bmp/encoder.rs | 141 ++-- third_party/rust/image/src/buffer.rs | 327 ++++++++- third_party/rust/image/src/color.rs | 271 ++++---- third_party/rust/image/src/dxt.rs | 12 +- third_party/rust/image/src/dynimage.rs | 153 ++++- third_party/rust/image/src/flat.rs | 32 +- third_party/rust/image/src/gif.rs | 30 +- .../src/hdr/{hdr_decoder.rs => decoder.rs} | 171 +++-- .../src/hdr/{hdr_encoder.rs => encoder.rs} | 32 +- third_party/rust/image/src/hdr/mod.rs | 10 +- third_party/rust/image/src/ico/decoder.rs | 70 +- third_party/rust/image/src/ico/encoder.rs | 28 +- third_party/rust/image/src/image.rs | 98 +-- third_party/rust/image/src/imageops/affine.rs | 35 +- .../rust/image/src/imageops/colorops.rs | 4 +- third_party/rust/image/src/imageops/mod.rs | 12 +- third_party/rust/image/src/imageops/sample.rs | 23 +- third_party/rust/image/src/jpeg/decoder.rs | 26 +- third_party/rust/image/src/jpeg/encoder.rs | 62 +- third_party/rust/image/src/lib.rs | 23 +- third_party/rust/image/src/math/nq.rs | 4 +- third_party/rust/image/src/png.rs | 102 ++- third_party/rust/image/src/pnm/decoder.rs | 36 +- third_party/rust/image/src/pnm/encoder.rs | 16 +- third_party/rust/image/src/pnm/header.rs | 2 +- third_party/rust/image/src/pnm/mod.rs | 6 +- third_party/rust/image/src/tga/decoder.rs | 46 +- third_party/rust/image/src/tiff.rs | 57 +- third_party/rust/image/src/utils/mod.rs | 17 +- third_party/rust/image/src/webp/decoder.rs | 50 +- third_party/rust/image/src/webp/transform.rs | 61 +- third_party/rust/image/src/webp/vp8.rs | 450 ++++++++----- third_party/rust/png/.cargo-checksum.json | 2 +- third_party/rust/png/Cargo.toml | 21 +- third_party/rust/png/README.md | 25 +- third_party/rust/png/benches/README.md | 6 + third_party/rust/png/benches/decoder.rs | 25 + third_party/rust/png/examples/pngcheck.rs | 153 ++--- third_party/rust/png/examples/show.rs | 16 +- third_party/rust/png/src/common.rs | 162 ++++- third_party/rust/png/src/crc.rs | 88 --- third_party/rust/png/src/decoder/mod.rs | 174 ++--- third_party/rust/png/src/decoder/stream.rs | 103 +-- third_party/rust/png/src/encoder.rs | 280 ++++++-- third_party/rust/png/src/filter.rs | 5 + third_party/rust/png/src/lib.rs | 41 +- third_party/rust/png/src/traits.rs | 22 +- third_party/rust/png/src/utils.rs | 233 ++++++- 69 files changed, 4384 insertions(+), 1421 deletions(-) create mode 100644 third_party/rust/crc32fast/.cargo-checksum.json create mode 100644 third_party/rust/crc32fast/Cargo.toml create mode 100644 third_party/rust/crc32fast/LICENSE-APACHE create mode 100644 third_party/rust/crc32fast/LICENSE-MIT create mode 100644 third_party/rust/crc32fast/README.md create mode 100644 third_party/rust/crc32fast/benches/bench.rs create mode 100644 third_party/rust/crc32fast/build.rs create mode 100644 third_party/rust/crc32fast/src/baseline.rs create mode 100644 third_party/rust/crc32fast/src/combine.rs create mode 100644 third_party/rust/crc32fast/src/lib.rs create mode 100644 third_party/rust/crc32fast/src/specialized/aarch64.rs create mode 100644 third_party/rust/crc32fast/src/specialized/mod.rs create mode 100644 third_party/rust/crc32fast/src/specialized/pclmulqdq.rs create mode 100644 third_party/rust/crc32fast/src/table.rs create mode 100644 third_party/rust/image/benches/README.md rename third_party/rust/image/src/hdr/{hdr_decoder.rs => decoder.rs} (87%) rename third_party/rust/image/src/hdr/{hdr_encoder.rs => encoder.rs} (95%) create mode 100644 third_party/rust/png/benches/README.md create mode 100644 third_party/rust/png/benches/decoder.rs delete mode 100644 third_party/rust/png/src/crc.rs diff --git a/third_party/rust/crc32fast/.cargo-checksum.json b/third_party/rust/crc32fast/.cargo-checksum.json new file mode 100644 index 000000000000..7c08c96555a9 --- /dev/null +++ b/third_party/rust/crc32fast/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"c85c0241394119d8887c5e5624aba9a1a1fd21578f1a1e3f2a0d50d95d752cff","LICENSE-APACHE":"c6596eb7be8581c18be736c846fb9173b69eccf6ef94c5135893ec56bd92ba08","LICENSE-MIT":"61d383b05b87d78f94d2937e2580cce47226d17823c0430fbcad09596537efcf","README.md":"c0891c7ff327441bf16da593b0e721951f9f6d10bb26f9356aba6a7b0b0c4575","benches/bench.rs":"9a45a7ebc8fecf7f9976bea0e3c00c13731c0b3566536b0bc83788986e801770","build.rs":"4ccc50c3da67eb27f0b622440d2b7aee2f73fa9c71884571f3c041122231d105","src/baseline.rs":"bbe8fe49ceccbf9749052fa9c2756cf95f0fc79a063e5d3b509e3600283464ea","src/combine.rs":"7147fc4002190d36d253ea5e194e0419035b087304bcb17887efe09a8a198815","src/lib.rs":"25c55822d7fd53ff1ff0769bcffbdbcade00d45ac042a541b7189c2e94b91ee7","src/specialized/aarch64.rs":"cc8097e68f1269cee32aa856b4f7e4ba7b7472df6c2f4cecd600d292a838fe83","src/specialized/mod.rs":"bc92450e8522e9df202b346b3a209153cbb0d6587804cbfd2b947fda0f190ed6","src/specialized/pclmulqdq.rs":"6ace803b42ff70a571fd8b5f3f7c2d5a836873ce28759381c2882319b8edba70","src/table.rs":"3201c520d97c5e2cf80b8a03d72fa2e3f1270bbdf93c2fbf85498a8ea39bc64b"},"package":"ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1"} \ No newline at end of file diff --git a/third_party/rust/crc32fast/Cargo.toml b/third_party/rust/crc32fast/Cargo.toml new file mode 100644 index 000000000000..ca8bbcc1e7c9 --- /dev/null +++ b/third_party/rust/crc32fast/Cargo.toml @@ -0,0 +1,41 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "crc32fast" +version = "1.2.0" +authors = ["Sam Rijs ", "Alex Crichton "] +description = "Fast, SIMD-accelerated CRC32 (IEEE) checksum computation" +readme = "README.md" +keywords = ["checksum", "crc", "crc32", "simd", "fast"] +license = "MIT OR Apache-2.0" +repository = "https://github.com/srijs/rust-crc32fast" + +[[bench]] +name = "bench" +harness = false +[dependencies.cfg-if] +version = "0.1" +[dev-dependencies.bencher] +version = "0.1" + +[dev-dependencies.quickcheck] +version = "0.6" +default-features = false + +[dev-dependencies.rand] +version = "0.4" + +[features] +default = ["std"] +nightly = [] +std = [] diff --git a/third_party/rust/crc32fast/LICENSE-APACHE b/third_party/rust/crc32fast/LICENSE-APACHE new file mode 100644 index 000000000000..8f71f43fee3f --- /dev/null +++ b/third_party/rust/crc32fast/LICENSE-APACHE @@ -0,0 +1,202 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + diff --git a/third_party/rust/crc32fast/LICENSE-MIT b/third_party/rust/crc32fast/LICENSE-MIT new file mode 100644 index 000000000000..f558267301a4 --- /dev/null +++ b/third_party/rust/crc32fast/LICENSE-MIT @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018 Sam Rijs, Alex Crichton and contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/third_party/rust/crc32fast/README.md b/third_party/rust/crc32fast/README.md new file mode 100644 index 000000000000..4267dfaf2d45 --- /dev/null +++ b/third_party/rust/crc32fast/README.md @@ -0,0 +1,81 @@ +# crc32fast [![Build Status][travis-img]][travis] [![Crates.io][crates-img]][crates] [![Documentation][docs-img]][docs] + +[travis-img]: https://travis-ci.com/srijs/rust-crc32fast.svg?branch=master +[travis]: https://travis-ci.com/srijs/rust-crc32fast +[crates-img]: https://img.shields.io/crates/v/crc32fast.svg +[crates]: https://crates.io/crates/crc32fast +[docs-img]: https://docs.rs/crc32fast/badge.svg +[docs]: https://docs.rs/crc32fast + +_Fast, SIMD-accelerated CRC32 (IEEE) checksum computation_ + +## Usage + +```rust +extern crate crc32fast; + +use crc32fast::Hasher; + +let mut hasher = Hasher::new(); +hasher.update(b"foo bar baz"); +let checksum = hasher.finalize(); +``` + +## Performance + +This crate contains multiple CRC32 implementations: + +- A fast baseline implementation which processes up to 16 bytes per iteration +- An optimized implementation for modern `x86` using `sse` and `pclmulqdq` instructions +- An optimized implementation for `aarch64` using `crc32` instructions + +Calling the `Hasher::new` constructor at runtime will perform a feature detection to select the most +optimal implementation for the current CPU feature set. + +| crate | version | variant | ns/iter | MB/s | +|-------------------------------------|---------|-----------|---------|------| +| [crc](https://crates.io/crates/crc) | 1.8.1 | n/a | 4,926 | 207 | +| crc32fast (this crate) | 1.0.0 | baseline | 683 | 1499 | +| crc32fast (this crate) | 1.0.0 | pclmulqdq | 140 | 7314 | + +## Memory Safety + +Due to the use of SIMD intrinsics for the optimized implementations, this crate contains some amount of `unsafe` code. + +In order to ensure memory safety, the relevant code has been fuzz tested using [afl.rs](https://github.com/rust-fuzz/afl.rs) with millions of iterations in both `debug` and `release` build settings. You can inspect the test setup in the `fuzz` sub-directory, which also has instructions on how to run the tests yourself. + +On top of that, every commit is tested using an address sanitizer in CI to catch any out of bounds memory accesses. + +Even though neither fuzzing not sanitization has revealed any safety bugs yet, please don't hesitate to file an issue if you run into any crashes or other unexpected behaviour. + +## Available feature flags + +### `std` (default: enabled) + +This library supports being built without the Rust `std` library, which is useful for low-level use-cases such as embedded where no operating system is available. To build the crate in a `no_std` context, disable the default `std` feature. + +Note: Because runtime CPU feature detection requires OS support, the specialized SIMD implementations will be unavailable when the `std` feature is disabled. + +### `nightly` (default: disabled) + +This feature flag enables unstable features that are only available on the `nightly` channel. Keep in mind that when enabling this feature flag, you +might experience breaking changes when updating compiler versions. + +Currently, enabling this feature flag will make the optimized `aarch64` implementation available. + +## License + +This project is licensed under either of + + * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or + http://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or + http://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in this project by you, as defined in the Apache-2.0 license, +shall be dual licensed as above, without any additional terms or conditions. diff --git a/third_party/rust/crc32fast/benches/bench.rs b/third_party/rust/crc32fast/benches/bench.rs new file mode 100644 index 000000000000..91fbbb6de8dd --- /dev/null +++ b/third_party/rust/crc32fast/benches/bench.rs @@ -0,0 +1,49 @@ +#[macro_use] +extern crate bencher; +extern crate crc32fast; +extern crate rand; + +use bencher::Bencher; +use crc32fast::Hasher; +use rand::Rng; + +fn bench(b: &mut Bencher, size: usize, hasher_init: Hasher) { + let mut bytes = vec![0u8; size]; + rand::thread_rng().fill_bytes(&mut bytes); + + b.iter(|| { + let mut hasher = hasher_init.clone(); + hasher.update(&bytes); + bencher::black_box(hasher.finalize()) + }); + + b.bytes = size as u64; +} + +fn bench_kilobyte_baseline(b: &mut Bencher) { + bench(b, 1024, Hasher::internal_new_baseline(0)) +} + +fn bench_kilobyte_specialized(b: &mut Bencher) { + bench(b, 1024, Hasher::internal_new_specialized(0).unwrap()) +} + +fn bench_megabyte_baseline(b: &mut Bencher) { + bench(b, 1024 * 1024, Hasher::internal_new_baseline(0)) +} + +fn bench_megabyte_specialized(b: &mut Bencher) { + bench(b, 1024 * 1024, Hasher::internal_new_specialized(0).unwrap()) +} + +benchmark_group!( + bench_baseline, + bench_kilobyte_baseline, + bench_megabyte_baseline +); +benchmark_group!( + bench_specialized, + bench_kilobyte_specialized, + bench_megabyte_specialized +); +benchmark_main!(bench_baseline, bench_specialized); diff --git a/third_party/rust/crc32fast/build.rs b/third_party/rust/crc32fast/build.rs new file mode 100644 index 000000000000..563cb21732ba --- /dev/null +++ b/third_party/rust/crc32fast/build.rs @@ -0,0 +1,35 @@ +use std::env; +use std::process::Command; +use std::str; + +fn main() { + println!("cargo:rerun-if-changed=build.rs"); + + let minor = match rustc_minor_version() { + Some(n) => n, + None => return, + }; + + if minor >= 27 { + println!("cargo:rustc-cfg=crc32fast_stdarchx86"); + } +} + +fn rustc_minor_version() -> Option { + macro_rules! otry { + ($e:expr) => { + match $e { + Some(e) => e, + None => return None, + } + }; + } + let rustc = otry!(env::var_os("RUSTC")); + let output = otry!(Command::new(rustc).arg("--version").output().ok()); + let version = otry!(str::from_utf8(&output.stdout).ok()); + let mut pieces = version.split('.'); + if pieces.next() != Some("rustc 1") { + return None; + } + otry!(pieces.next()).parse().ok() +} diff --git a/third_party/rust/crc32fast/src/baseline.rs b/third_party/rust/crc32fast/src/baseline.rs new file mode 100644 index 000000000000..fbc4136baec8 --- /dev/null +++ b/third_party/rust/crc32fast/src/baseline.rs @@ -0,0 +1,94 @@ +use table::CRC32_TABLE; + +#[derive(Clone)] +pub struct State { + state: u32, +} + +impl State { + pub fn new(state: u32) -> Self { + State { state } + } + + pub fn update(&mut self, buf: &[u8]) { + self.state = update_fast_16(self.state, buf); + } + + pub fn finalize(self) -> u32 { + self.state + } + + pub fn reset(&mut self) { + self.state = 0; + } + + pub fn combine(&mut self, other: u32, amount: u64) { + self.state = ::combine::combine(self.state, other, amount); + } +} + +pub(crate) fn update_fast_16(prev: u32, mut buf: &[u8]) -> u32 { + const UNROLL: usize = 4; + const BYTES_AT_ONCE: usize = 16 * UNROLL; + + let mut crc = !prev; + + while buf.len() >= BYTES_AT_ONCE { + for _ in 0..UNROLL { + crc = CRC32_TABLE[0x0][buf[0xf] as usize] + ^ CRC32_TABLE[0x1][buf[0xe] as usize] + ^ CRC32_TABLE[0x2][buf[0xd] as usize] + ^ CRC32_TABLE[0x3][buf[0xc] as usize] + ^ CRC32_TABLE[0x4][buf[0xb] as usize] + ^ CRC32_TABLE[0x5][buf[0xa] as usize] + ^ CRC32_TABLE[0x6][buf[0x9] as usize] + ^ CRC32_TABLE[0x7][buf[0x8] as usize] + ^ CRC32_TABLE[0x8][buf[0x7] as usize] + ^ CRC32_TABLE[0x9][buf[0x6] as usize] + ^ CRC32_TABLE[0xa][buf[0x5] as usize] + ^ CRC32_TABLE[0xb][buf[0x4] as usize] + ^ CRC32_TABLE[0xc][buf[0x3] as usize ^ ((crc >> 0x18) & 0xFF) as usize] + ^ CRC32_TABLE[0xd][buf[0x2] as usize ^ ((crc >> 0x10) & 0xFF) as usize] + ^ CRC32_TABLE[0xe][buf[0x1] as usize ^ ((crc >> 0x08) & 0xFF) as usize] + ^ CRC32_TABLE[0xf][buf[0x0] as usize ^ ((crc >> 0x00) & 0xFF) as usize]; + buf = &buf[16..]; + } + } + + update_slow(!crc, buf) +} + +pub(crate) fn update_slow(prev: u32, buf: &[u8]) -> u32 { + let mut crc = !prev; + + for &byte in buf.iter() { + crc = CRC32_TABLE[0][((crc as u8) ^ byte) as usize] ^ (crc >> 8); + } + + !crc +} + +#[cfg(test)] +mod test { + #[test] + fn slow() { + assert_eq!(super::update_slow(0, b""), 0); + + // test vectors from the iPXE project (input and output are bitwise negated) + assert_eq!(super::update_slow(!0x12345678, b""), !0x12345678); + assert_eq!(super::update_slow(!0xffffffff, b"hello world"), !0xf2b5ee7a); + assert_eq!(super::update_slow(!0xffffffff, b"hello"), !0xc9ef5979); + assert_eq!(super::update_slow(!0xc9ef5979, b" world"), !0xf2b5ee7a); + + // Some vectors found on Rosetta code + assert_eq!(super::update_slow(0, b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"), 0x190A55AD); + assert_eq!(super::update_slow(0, b"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"), 0xFF6CAB0B); + assert_eq!(super::update_slow(0, b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F"), 0x91267E8A); + } + + quickcheck! { + fn fast_16_is_the_same_as_slow(crc: u32, bytes: Vec) -> bool { + super::update_fast_16(crc, &bytes) == super::update_slow(crc, &bytes) + } + } +} diff --git a/third_party/rust/crc32fast/src/combine.rs b/third_party/rust/crc32fast/src/combine.rs new file mode 100644 index 000000000000..4dd0ee06552a --- /dev/null +++ b/third_party/rust/crc32fast/src/combine.rs @@ -0,0 +1,77 @@ +const GF2_DIM: usize = 32; + +fn gf2_matrix_times(mat: &[u32; GF2_DIM], mut vec: u32) -> u32 { + let mut sum = 0; + let mut idx = 0; + while vec > 0 { + if vec & 1 == 1 { + sum ^= mat[idx]; + } + vec >>= 1; + idx += 1; + } + return sum; +} + +fn gf2_matrix_square(square: &mut [u32; GF2_DIM], mat: &[u32; GF2_DIM]) { + for n in 0..GF2_DIM { + square[n] = gf2_matrix_times(mat, mat[n]); + } +} + +pub(crate) fn combine(mut crc1: u32, crc2: u32, mut len2: u64) -> u32 { + let mut row: u32; + let mut even = [0u32; GF2_DIM]; /* even-power-of-two zeros operator */ + let mut odd = [0u32; GF2_DIM]; /* odd-power-of-two zeros operator */ + + /* degenerate case (also disallow negative lengths) */ + if len2 <= 0 { + return crc1; + } + + /* put operator for one zero bit in odd */ + odd[0] = 0xedb88320; /* CRC-32 polynomial */ + row = 1; + for n in 1..GF2_DIM { + odd[n] = row; + row <<= 1; + } + + /* put operator for two zero bits in even */ + gf2_matrix_square(&mut even, &odd); + + /* put operator for four zero bits in odd */ + gf2_matrix_square(&mut odd, &even); + + /* apply len2 zeros to crc1 (first square will put the operator for one + zero byte, eight zero bits, in even) */ + loop { + /* apply zeros operator for this bit of len2 */ + gf2_matrix_square(&mut even, &odd); + if len2 & 1 == 1 { + crc1 = gf2_matrix_times(&even, crc1); + } + len2 >>= 1; + + /* if no more bits set, then done */ + if len2 == 0 { + break; + } + + /* another iteration of the loop with odd and even swapped */ + gf2_matrix_square(&mut odd, &even); + if len2 & 1 == 1 { + crc1 = gf2_matrix_times(&odd, crc1); + } + len2 >>= 1; + + /* if no more bits set, then done */ + if len2 == 0 { + break; + } + } + + /* return combined crc */ + crc1 ^= crc2; + return crc1; +} diff --git a/third_party/rust/crc32fast/src/lib.rs b/third_party/rust/crc32fast/src/lib.rs new file mode 100644 index 000000000000..f14728653181 --- /dev/null +++ b/third_party/rust/crc32fast/src/lib.rs @@ -0,0 +1,178 @@ +//! ## Example +//! +//! ```rust +//! use crc32fast::Hasher; +//! +//! let mut hasher = Hasher::new(); +//! hasher.update(b"foo bar baz"); +//! let checksum = hasher.finalize(); +//! ``` +//! +//! ## Performance +//! +//! This crate contains multiple CRC32 implementations: +//! +//! - A fast baseline implementation which processes up to 16 bytes per iteration +//! - An optimized implementation for modern `x86` using `sse` and `pclmulqdq` instructions +//! +//! Calling the `Hasher::new` constructor at runtime will perform a feature detection to select the most +//! optimal implementation for the current CPU feature set. + +#![cfg_attr(not(feature = "std"), no_std)] +#![cfg_attr( + all(feature = "nightly", target_arch = "aarch64"), + feature(stdsimd, aarch64_target_feature) +)] + +#[deny(missing_docs)] +#[cfg(test)] +#[macro_use] +extern crate quickcheck; + +#[macro_use] +extern crate cfg_if; + +#[cfg(feature = "std")] +use std as core; + +use core::fmt; +use core::hash; + +mod baseline; +mod combine; +mod specialized; +mod table; + +#[derive(Clone)] +enum State { + Baseline(baseline::State), + Specialized(specialized::State), +} + +#[derive(Clone)] +/// Represents an in-progress CRC32 computation. +pub struct Hasher { + amount: u64, + state: State, +} + +const DEFAULT_INIT_STATE: u32 = 0; + +impl Hasher { + /// Create a new `Hasher`. + /// + /// This will perform a CPU feature detection at runtime to select the most + /// optimal implementation for the current processor architecture. + pub fn new() -> Self { + Self::new_with_initial(DEFAULT_INIT_STATE) + } + + /// Create a new `Hasher` with an initial CRC32 state. + /// + /// This works just like `Hasher::new`, except that it allows for an initial + /// CRC32 state to be passed in. + pub fn new_with_initial(init: u32) -> Self { + Self::internal_new_specialized(init).unwrap_or_else(|| Self::internal_new_baseline(init)) + } + + #[doc(hidden)] + // Internal-only API. Don't use. + pub fn internal_new_baseline(init: u32) -> Self { + Hasher { + amount: 0, + state: State::Baseline(baseline::State::new(init)), + } + } + + #[doc(hidden)] + // Internal-only API. Don't use. + pub fn internal_new_specialized(init: u32) -> Option { + { + if let Some(state) = specialized::State::new(init) { + return Some(Hasher { + amount: 0, + state: State::Specialized(state), + }); + } + } + None + } + + /// Process the given byte slice and update the hash state. + pub fn update(&mut self, buf: &[u8]) { + self.amount += buf.len() as u64; + match self.state { + State::Baseline(ref mut state) => state.update(buf), + State::Specialized(ref mut state) => state.update(buf), + } + } + + /// Finalize the hash state and return the computed CRC32 value. + pub fn finalize(self) -> u32 { + match self.state { + State::Baseline(state) => state.finalize(), + State::Specialized(state) => state.finalize(), + } + } + + /// Reset the hash state. + pub fn reset(&mut self) { + self.amount = 0; + match self.state { + State::Baseline(ref mut state) => state.reset(), + State::Specialized(ref mut state) => state.reset(), + } + } + + /// Combine the hash state with the hash state for the subsequent block of bytes. + pub fn combine(&mut self, other: &Self) { + self.amount += other.amount; + let other_crc = other.clone().finalize(); + match self.state { + State::Baseline(ref mut state) => state.combine(other_crc, other.amount), + State::Specialized(ref mut state) => state.combine(other_crc, other.amount), + } + } +} + +impl fmt::Debug for Hasher { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("crc32fast::Hasher").finish() + } +} + +impl Default for Hasher { + fn default() -> Self { + Self::new() + } +} + +impl hash::Hasher for Hasher { + fn write(&mut self, bytes: &[u8]) { + self.update(bytes) + } + + fn finish(&self) -> u64 { + u64::from(self.clone().finalize()) + } +} + +#[cfg(test)] +mod test { + use super::Hasher; + + quickcheck! { + fn combine(bytes_1: Vec, bytes_2: Vec) -> bool { + let mut hash_a = Hasher::new(); + hash_a.update(&bytes_1); + hash_a.update(&bytes_2); + let mut hash_b = Hasher::new(); + hash_b.update(&bytes_2); + let mut hash_c = Hasher::new(); + hash_c.update(&bytes_1); + hash_c.combine(&hash_b); + + hash_a.finalize() == hash_c.finalize() + } + } +} diff --git a/third_party/rust/crc32fast/src/specialized/aarch64.rs b/third_party/rust/crc32fast/src/specialized/aarch64.rs new file mode 100644 index 000000000000..ce052618d8d4 --- /dev/null +++ b/third_party/rust/crc32fast/src/specialized/aarch64.rs @@ -0,0 +1,88 @@ +use std::arch::aarch64 as arch; + +#[derive(Clone)] +pub struct State { + state: u32, +} + +impl State { + pub fn new(state: u32) -> Option { + if is_aarch64_feature_detected!("crc") { + // SAFETY: The conditions above ensure that all + // required instructions are supported by the CPU. + Some(Self { state }) + } else { + None + } + } + + pub fn update(&mut self, buf: &[u8]) { + // SAFETY: The `State::new` constructor ensures that all + // required instructions are supported by the CPU. + self.state = unsafe { calculate(self.state, buf) } + } + + pub fn finalize(self) -> u32 { + self.state + } + + pub fn reset(&mut self) { + self.state = 0; + } + + pub fn combine(&mut self, other: u32, amount: u64) { + self.state = ::combine::combine(self.state, other, amount); + } +} + +// target_feature is necessary to allow rustc to inline the crc32* wrappers +#[target_feature(enable = "crc")] +pub unsafe fn calculate(crc: u32, data: &[u8]) -> u32 { + let mut c32 = !crc; + let (pre_quad, quads, post_quad) = data.align_to::(); + + c32 = pre_quad.iter().fold(c32, |acc, &b| arch::__crc32b(acc, b)); + + // unrolling increases performance by a lot + let mut quad_iter = quads.chunks_exact(8); + for chunk in &mut quad_iter { + c32 = arch::__crc32d(c32, chunk[0]); + c32 = arch::__crc32d(c32, chunk[1]); + c32 = arch::__crc32d(c32, chunk[2]); + c32 = arch::__crc32d(c32, chunk[3]); + c32 = arch::__crc32d(c32, chunk[4]); + c32 = arch::__crc32d(c32, chunk[5]); + c32 = arch::__crc32d(c32, chunk[6]); + c32 = arch::__crc32d(c32, chunk[7]); + } + c32 = quad_iter + .remainder() + .iter() + .fold(c32, |acc, &q| arch::__crc32d(acc, q)); + + c32 = post_quad.iter().fold(c32, |acc, &b| arch::__crc32b(acc, b)); + + !c32 +} + +#[cfg(test)] +mod test { + quickcheck! { + fn check_against_baseline(init: u32, chunks: Vec<(Vec, usize)>) -> bool { + let mut baseline = super::super::super::baseline::State::new(init); + let mut aarch64 = super::State::new(init).expect("not supported"); + for (chunk, mut offset) in chunks { + // simulate random alignments by offsetting the slice by up to 15 bytes + offset &= 0xF; + if chunk.len() <= offset { + baseline.update(&chunk); + aarch64.update(&chunk); + } else { + baseline.update(&chunk[offset..]); + aarch64.update(&chunk[offset..]); + } + } + aarch64.finalize() == baseline.finalize() + } + } +} diff --git a/third_party/rust/crc32fast/src/specialized/mod.rs b/third_party/rust/crc32fast/src/specialized/mod.rs new file mode 100644 index 000000000000..d4b0b8dca4d6 --- /dev/null +++ b/third_party/rust/crc32fast/src/specialized/mod.rs @@ -0,0 +1,36 @@ +cfg_if! { + if #[cfg(all( + crc32fast_stdarchx86, + any(target_arch = "x86", target_arch = "x86_64") + ))] { + mod pclmulqdq; + pub use self::pclmulqdq::State; + } else if #[cfg(all(feature = "nightly", target_arch = "aarch64"))] { + mod aarch64; + pub use self::aarch64::State; + } else { + #[derive(Clone)] + pub enum State {} + impl State { + pub fn new(_: u32) -> Option { + None + } + + pub fn update(&mut self, _buf: &[u8]) { + match *self {} + } + + pub fn finalize(self) -> u32 { + match self{} + } + + pub fn reset(&mut self) { + match *self {} + } + + pub fn combine(&mut self, _other: u32, _amount: u64) { + match *self {} + } + } + } +} diff --git a/third_party/rust/crc32fast/src/specialized/pclmulqdq.rs b/third_party/rust/crc32fast/src/specialized/pclmulqdq.rs new file mode 100644 index 000000000000..6abb08b6018c --- /dev/null +++ b/third_party/rust/crc32fast/src/specialized/pclmulqdq.rs @@ -0,0 +1,225 @@ +#[cfg(target_arch = "x86")] +use core::arch::x86 as arch; +#[cfg(target_arch = "x86_64")] +use core::arch::x86_64 as arch; + +#[derive(Clone)] +pub struct State { + state: u32, +} + +impl State { + #[cfg(not(feature = "std"))] + pub fn new(state: u32) -> Option { + if cfg!(target_feature = "pclmulqdq") + && cfg!(target_feature = "sse2") + && cfg!(target_feature = "sse4.1") + { + // SAFETY: The conditions above ensure that all + // required instructions are supported by the CPU. + Some(Self { state }) + } else { + None + } + } + + #[cfg(feature = "std")] + pub fn new(state: u32) -> Option { + if is_x86_feature_detected!("pclmulqdq") + && is_x86_feature_detected!("sse2") + && is_x86_feature_detected!("sse4.1") + { + // SAFETY: The conditions above ensure that all + // required instructions are supported by the CPU. + Some(Self { state }) + } else { + None + } + } + + pub fn update(&mut self, buf: &[u8]) { + // SAFETY: The `State::new` constructor ensures that all + // required instructions are supported by the CPU. + self.state = unsafe { calculate(self.state, buf) } + } + + pub fn finalize(self) -> u32 { + self.state + } + + pub fn reset(&mut self) { + self.state = 0; + } + + pub fn combine(&mut self, other: u32, amount: u64) { + self.state = ::combine::combine(self.state, other, amount); + } +} + +const K1: i64 = 0x154442bd4; +const K2: i64 = 0x1c6e41596; +const K3: i64 = 0x1751997d0; +const K4: i64 = 0x0ccaa009e; +const K5: i64 = 0x163cd6124; +const K6: i64 = 0x1db710640; + +const P_X: i64 = 0x1DB710641; +const U_PRIME: i64 = 0x1F7011641; + +#[cfg(feature = "std")] +unsafe fn debug(s: &str, a: arch::__m128i) -> arch::__m128i { + if false { + union A { + a: arch::__m128i, + b: [u8; 16], + } + let x = A { a }.b; + print!(" {:20} | ", s); + for x in x.iter() { + print!("{:02x} ", x); + } + println!(); + } + return a; +} + +#[cfg(not(feature = "std"))] +unsafe fn debug(_s: &str, a: arch::__m128i) -> arch::__m128i { + a +} + +#[target_feature(enable = "pclmulqdq", enable = "sse2", enable = "sse4.1")] +pub unsafe fn calculate(crc: u32, mut data: &[u8]) -> u32 { + // In theory we can accelerate smaller chunks too, but for now just rely on + // the fallback implementation as it's too much hassle and doesn't seem too + // beneficial. + if data.len() < 128 { + return ::baseline::update_fast_16(crc, data); + } + + // Step 1: fold by 4 loop + let mut x3 = get(&mut data); + let mut x2 = get(&mut data); + let mut x1 = get(&mut data); + let mut x0 = get(&mut data); + + // fold in our initial value, part of the incremental crc checksum + x3 = arch::_mm_xor_si128(x3, arch::_mm_cvtsi32_si128(!crc as i32)); + + let k1k2 = arch::_mm_set_epi64x(K2, K1); + while data.len() >= 64 { + x3 = reduce128(x3, get(&mut data), k1k2); + x2 = reduce128(x2, get(&mut data), k1k2); + x1 = reduce128(x1, get(&mut data), k1k2); + x0 = reduce128(x0, get(&mut data), k1k2); + } + + let k3k4 = arch::_mm_set_epi64x(K4, K3); + let mut x = reduce128(x3, x2, k3k4); + x = reduce128(x, x1, k3k4); + x = reduce128(x, x0, k3k4); + + // Step 2: fold by 1 loop + while data.len() >= 16 { + x = reduce128(x, get(&mut data), k3k4); + } + + debug("128 > 64 init", x); + + // Perform step 3, reduction from 128 bits to 64 bits. This is + // significantly different from the paper and basically doesn't follow it + // at all. It's not really clear why, but implementations of this algorithm + // in Chrome/Linux diverge in the same way. It is beyond me why this is + // different than the paper, maybe the paper has like errata or something? + // Unclear. + // + // It's also not clear to me what's actually happening here and/or why, but + // algebraically what's happening is: + // + // x = (x[0:63] • K4) ^ x[64:127] // 96 bit result + // x = ((x[0:31] as u64) • K5) ^ x[32:95] // 64 bit result + // + // It's... not clear to me what's going on here. The paper itself is pretty + // vague on this part but definitely uses different constants at least. + // It's not clear to me, reading the paper, where the xor operations are + // happening or why things are shifting around. This implementation... + // appears to work though! + drop(K6); + let x = arch::_mm_xor_si128( + arch::_mm_clmulepi64_si128(x, k3k4, 0x10), + arch::_mm_srli_si128(x, 8), + ); + let x = arch::_mm_xor_si128( + arch::_mm_clmulepi64_si128( + arch::_mm_and_si128(x, arch::_mm_set_epi32(0, 0, 0, !0)), + arch::_mm_set_epi64x(0, K5), + 0x00, + ), + arch::_mm_srli_si128(x, 4), + ); + debug("128 > 64 xx", x); + + // Perform a Barrett reduction from our now 64 bits to 32 bits. The + // algorithm for this is described at the end of the paper, and note that + // this also implements the "bit reflected input" variant. + let pu = arch::_mm_set_epi64x(U_PRIME, P_X); + + // T1(x) = ⌊(R(x) % x^32)⌋ • μ + let t1 = arch::_mm_clmulepi64_si128( + arch::_mm_and_si128(x, arch::_mm_set_epi32(0, 0, 0, !0)), + pu, + 0x10, + ); + // T2(x) = ⌊(T1(x) % x^32)⌋ • P(x) + let t2 = arch::_mm_clmulepi64_si128( + arch::_mm_and_si128(t1, arch::_mm_set_epi32(0, 0, 0, !0)), + pu, + 0x00, + ); + // We're doing the bit-reflected variant, so get the upper 32-bits of the + // 64-bit result instead of the lower 32-bits. + // + // C(x) = R(x) ^ T2(x) / x^32 + let c = arch::_mm_extract_epi32(arch::_mm_xor_si128(x, t2), 1) as u32; + + if !data.is_empty() { + ::baseline::update_fast_16(!c, data) + } else { + !c + } +} + +unsafe fn reduce128(a: arch::__m128i, b: arch::__m128i, keys: arch::__m128i) -> arch::__m128i { + let t1 = arch::_mm_clmulepi64_si128(a, keys, 0x00); + let t2 = arch::_mm_clmulepi64_si128(a, keys, 0x11); + arch::_mm_xor_si128(arch::_mm_xor_si128(b, t1), t2) +} + +unsafe fn get(a: &mut &[u8]) -> arch::__m128i { + debug_assert!(a.len() >= 16); + let r = arch::_mm_loadu_si128(a.as_ptr() as *const arch::__m128i); + *a = &a[16..]; + return r; +} + +#[cfg(test)] +mod test { + quickcheck! { + fn check_against_baseline(init: u32, chunks: Vec<(Vec, usize)>) -> bool { + let mut baseline = super::super::super::baseline::State::new(init); + let mut pclmulqdq = super::State::new(init).expect("not supported"); + for (chunk, mut offset) in chunks { + // simulate random alignments by offsetting the slice by up to 15 bytes + offset &= 0xF; + if chunk.len() <= offset { + baseline.update(&chunk); + pclmulqdq.update(&chunk); + } else { + baseline.update(&chunk[offset..]); + pclmulqdq.update(&chunk[offset..]); + } + } + pclmulqdq.finalize() == baseline.finalize() + } + } +} diff --git a/third_party/rust/crc32fast/src/table.rs b/third_party/rust/crc32fast/src/table.rs new file mode 100644 index 000000000000..9354601baafb --- /dev/null +++ b/third_party/rust/crc32fast/src/table.rs @@ -0,0 +1,626 @@ +pub const CRC32_TABLE: [[u32; 256]; 16] = [ + [ + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, + 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, + 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, + 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, + 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, + 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, + 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, + 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, + 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, + 0xb6662d3d, 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, + 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, + 0x086d3d2d, 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, + 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, + 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 0x4db26158, 0x3ab551ce, + 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, + 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, + 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, + 0xce61e49f, 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, + 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, + 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, + 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, 0x8708a3d2, 0x1e01f268, + 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, + 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, + 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, + 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, + 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, + 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, + 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, + 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, + 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, + 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 0x88085ae6, + 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, + 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, + 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, + 0x47b2cf7f, 0x30b5ffe9, 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, + 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, + 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d, + ], + [ + 0x00000000, 0x191B3141, 0x32366282, 0x2B2D53C3, 0x646CC504, 0x7D77F445, 0x565AA786, + 0x4F4196C7, 0xC8D98A08, 0xD1C2BB49, 0xFAEFE88A, 0xE3F4D9CB, 0xACB54F0C, 0xB5AE7E4D, + 0x9E832D8E, 0x87981CCF, 0x4AC21251, 0x53D92310, 0x78F470D3, 0x61EF4192, 0x2EAED755, + 0x37B5E614, 0x1C98B5D7, 0x05838496, 0x821B9859, 0x9B00A918, 0xB02DFADB, 0xA936CB9A, + 0xE6775D5D, 0xFF6C6C1C, 0xD4413FDF, 0xCD5A0E9E, 0x958424A2, 0x8C9F15E3, 0xA7B24620, + 0xBEA97761, 0xF1E8E1A6, 0xE8F3D0E7, 0xC3DE8324, 0xDAC5B265, 0x5D5DAEAA, 0x44469FEB, + 0x6F6BCC28, 0x7670FD69, 0x39316BAE, 0x202A5AEF, 0x0B07092C, 0x121C386D, 0xDF4636F3, + 0xC65D07B2, 0xED705471, 0xF46B6530, 0xBB2AF3F7, 0xA231C2B6, 0x891C9175, 0x9007A034, + 0x179FBCFB, 0x0E848DBA, 0x25A9DE79, 0x3CB2EF38, 0x73F379FF, 0x6AE848BE, 0x41C51B7D, + 0x58DE2A3C, 0xF0794F05, 0xE9627E44, 0xC24F2D87, 0xDB541CC6, 0x94158A01, 0x8D0EBB40, + 0xA623E883, 0xBF38D9C2, 0x38A0C50D, 0x21BBF44C, 0x0A96A78F, 0x138D96CE, 0x5CCC0009, + 0x45D73148, 0x6EFA628B, 0x77E153CA, 0xBABB5D54, 0xA3A06C15, 0x888D3FD6, 0x91960E97, + 0xDED79850, 0xC7CCA911, 0xECE1FAD2, 0xF5FACB93, 0x7262D75C, 0x6B79E61D, 0x4054B5DE, + 0x594F849F, 0x160E1258, 0x0F152319, 0x243870DA, 0x3D23419B, 0x65FD6BA7, 0x7CE65AE6, + 0x57CB0925, 0x4ED03864, 0x0191AEA3, 0x188A9FE2, 0x33A7CC21, 0x2ABCFD60, 0xAD24E1AF, + 0xB43FD0EE, 0x9F12832D, 0x8609B26C, 0xC94824AB, 0xD05315EA, 0xFB7E4629, 0xE2657768, + 0x2F3F79F6, 0x362448B7, 0x1D091B74, 0x04122A35, 0x4B53BCF2, 0x52488DB3, 0x7965DE70, + 0x607EEF31, 0xE7E6F3FE, 0xFEFDC2BF, 0xD5D0917C, 0xCCCBA03D, 0x838A36FA, 0x9A9107BB, + 0xB1BC5478, 0xA8A76539, 0x3B83984B, 0x2298A90A, 0x09B5FAC9, 0x10AECB88, 0x5FEF5D4F, + 0x46F46C0E, 0x6DD93FCD, 0x74C20E8C, 0xF35A1243, 0xEA412302, 0xC16C70C1, 0xD8774180, + 0x9736D747, 0x8E2DE606, 0xA500B5C5, 0xBC1B8484, 0x71418A1A, 0x685ABB5B, 0x4377E898, + 0x5A6CD9D9, 0x152D4F1E, 0x0C367E5F, 0x271B2D9C, 0x3E001CDD, 0xB9980012, 0xA0833153, + 0x8BAE6290, 0x92B553D1, 0xDDF4C516, 0xC4EFF457, 0xEFC2A794, 0xF6D996D5, 0xAE07BCE9, + 0xB71C8DA8, 0x9C31DE6B, 0x852AEF2A, 0xCA6B79ED, 0xD37048AC, 0xF85D1B6F, 0xE1462A2E, + 0x66DE36E1, 0x7FC507A0, 0x54E85463, 0x4DF36522, 0x02B2F3E5, 0x1BA9C2A4, 0x30849167, + 0x299FA026, 0xE4C5AEB8, 0xFDDE9FF9, 0xD6F3CC3A, 0xCFE8FD7B, 0x80A96BBC, 0x99B25AFD, + 0xB29F093E, 0xAB84387F, 0x2C1C24B0, 0x350715F1, 0x1E2A4632, 0x07317773, 0x4870E1B4, + 0x516BD0F5, 0x7A468336, 0x635DB277, 0xCBFAD74E, 0xD2E1E60F, 0xF9CCB5CC, 0xE0D7848D, + 0xAF96124A, 0xB68D230B, 0x9DA070C8, 0x84BB4189, 0x03235D46, 0x1A386C07, 0x31153FC4, + 0x280E0E85, 0x674F9842, 0x7E54A903, 0x5579FAC0, 0x4C62CB81, 0x8138C51F, 0x9823F45E, + 0xB30EA79D, 0xAA1596DC, 0xE554001B, 0xFC4F315A, 0xD7626299, 0xCE7953D8, 0x49E14F17, + 0x50FA7E56, 0x7BD72D95, 0x62CC1CD4, 0x2D8D8A13, 0x3496BB52, 0x1FBBE891, 0x06A0D9D0, + 0x5E7EF3EC, 0x4765C2AD, 0x6C48916E, 0x7553A02F, 0x3A1236E8, 0x230907A9, 0x0824546A, + 0x113F652B, 0x96A779E4, 0x8FBC48A5, 0xA4911B66, 0xBD8A2A27, 0xF2CBBCE0, 0xEBD08DA1, + 0xC0FDDE62, 0xD9E6EF23, 0x14BCE1BD, 0x0DA7D0FC, 0x268A833F, 0x3F91B27E, 0x70D024B9, + 0x69CB15F8, 0x42E6463B, 0x5BFD777A, 0xDC656BB5, 0xC57E5AF4, 0xEE530937, 0xF7483876, + 0xB809AEB1, 0xA1129FF0, 0x8A3FCC33, 0x9324FD72, + ], + [ + 0x00000000, 0x01C26A37, 0x0384D46E, 0x0246BE59, 0x0709A8DC, 0x06CBC2EB, 0x048D7CB2, + 0x054F1685, 0x0E1351B8, 0x0FD13B8F, 0x0D9785D6, 0x0C55EFE1, 0x091AF964, 0x08D89353, + 0x0A9E2D0A, 0x0B5C473D, 0x1C26A370, 0x1DE4C947, 0x1FA2771E, 0x1E601D29, 0x1B2F0BAC, + 0x1AED619B, 0x18ABDFC2, 0x1969B5F5, 0x1235F2C8, 0x13F798FF, 0x11B126A6, 0x10734C91, + 0x153C5A14, 0x14FE3023, 0x16B88E7A, 0x177AE44D, 0x384D46E0, 0x398F2CD7, 0x3BC9928E, + 0x3A0BF8B9, 0x3F44EE3C, 0x3E86840B, 0x3CC03A52, 0x3D025065, 0x365E1758, 0x379C7D6F, + 0x35DAC336, 0x3418A901, 0x3157BF84, 0x3095D5B3, 0x32D36BEA, 0x331101DD, 0x246BE590, + 0x25A98FA7, 0x27EF31FE, 0x262D5BC9, 0x23624D4C, 0x22A0277B, 0x20E69922, 0x2124F315, + 0x2A78B428, 0x2BBADE1F, 0x29FC6046, 0x283E0A71, 0x2D711CF4, 0x2CB376C3, 0x2EF5C89A, + 0x2F37A2AD, 0x709A8DC0, 0x7158E7F7, 0x731E59AE, 0x72DC3399, 0x7793251C, 0x76514F2B, + 0x7417F172, 0x75D59B45, 0x7E89DC78, 0x7F4BB64F, 0x7D0D0816, 0x7CCF6221, 0x798074A4, + 0x78421E93, 0x7A04A0CA, 0x7BC6CAFD, 0x6CBC2EB0, 0x6D7E4487, 0x6F38FADE, 0x6EFA90E9, + 0x6BB5866C, 0x6A77EC5B, 0x68315202, 0x69F33835, 0x62AF7F08, 0x636D153F, 0x612BAB66, + 0x60E9C151, 0x65A6D7D4, 0x6464BDE3, 0x662203BA, 0x67E0698D, 0x48D7CB20, 0x4915A117, + 0x4B531F4E, 0x4A917579, 0x4FDE63FC, 0x4E1C09CB, 0x4C5AB792, 0x4D98DDA5, 0x46C49A98, + 0x4706F0AF, 0x45404EF6, 0x448224C1, 0x41CD3244, 0x400F5873, 0x4249E62A, 0x438B8C1D, + 0x54F16850, 0x55330267, 0x5775BC3E, 0x56B7D609, 0x53F8C08C, 0x523AAABB, 0x507C14E2, + 0x51BE7ED5, 0x5AE239E8, 0x5B2053DF, 0x5966ED86, 0x58A487B1, 0x5DEB9134, 0x5C29FB03, + 0x5E6F455A, 0x5FAD2F6D, 0xE1351B80, 0xE0F771B7, 0xE2B1CFEE, 0xE373A5D9, 0xE63CB35C, + 0xE7FED96B, 0xE5B86732, 0xE47A0D05, 0xEF264A38, 0xEEE4200F, 0xECA29E56, 0xED60F461, + 0xE82FE2E4, 0xE9ED88D3, 0xEBAB368A, 0xEA695CBD, 0xFD13B8F0, 0xFCD1D2C7, 0xFE976C9E, + 0xFF5506A9, 0xFA1A102C, 0xFBD87A1B, 0xF99EC442, 0xF85CAE75, 0xF300E948, 0xF2C2837F, + 0xF0843D26, 0xF1465711, 0xF4094194, 0xF5CB2BA3, 0xF78D95FA, 0xF64FFFCD, 0xD9785D60, + 0xD8BA3757, 0xDAFC890E, 0xDB3EE339, 0xDE71F5BC, 0xDFB39F8B, 0xDDF521D2, 0xDC374BE5, + 0xD76B0CD8, 0xD6A966EF, 0xD4EFD8B6, 0xD52DB281, 0xD062A404, 0xD1A0CE33, 0xD3E6706A, + 0xD2241A5D, 0xC55EFE10, 0xC49C9427, 0xC6DA2A7E, 0xC7184049, 0xC25756CC, 0xC3953CFB, + 0xC1D382A2, 0xC011E895, 0xCB4DAFA8, 0xCA8FC59F, 0xC8C97BC6, 0xC90B11F1, 0xCC440774, + 0xCD866D43, 0xCFC0D31A, 0xCE02B92D, 0x91AF9640, 0x906DFC77, 0x922B422E, 0x93E92819, + 0x96A63E9C, 0x976454AB, 0x9522EAF2, 0x94E080C5, 0x9FBCC7F8, 0x9E7EADCF, 0x9C381396, + 0x9DFA79A1, 0x98B56F24, 0x99770513, 0x9B31BB4A, 0x9AF3D17D, 0x8D893530, 0x8C4B5F07, + 0x8E0DE15E, 0x8FCF8B69, 0x8A809DEC, 0x8B42F7DB, 0x89044982, 0x88C623B5, 0x839A6488, + 0x82580EBF, 0x801EB0E6, 0x81DCDAD1, 0x8493CC54, 0x8551A663, 0x8717183A, 0x86D5720D, + 0xA9E2D0A0, 0xA820BA97, 0xAA6604CE, 0xABA46EF9, 0xAEEB787C, 0xAF29124B, 0xAD6FAC12, + 0xACADC625, 0xA7F18118, 0xA633EB2F, 0xA4755576, 0xA5B73F41, 0xA0F829C4, 0xA13A43F3, + 0xA37CFDAA, 0xA2BE979D, 0xB5C473D0, 0xB40619E7, 0xB640A7BE, 0xB782CD89, 0xB2CDDB0C, + 0xB30FB13B, 0xB1490F62, 0xB08B6555, 0xBBD72268, 0xBA15485F, 0xB853F606, 0xB9919C31, + 0xBCDE8AB4, 0xBD1CE083, 0xBF5A5EDA, 0xBE9834ED, + ], + [ + 0x00000000, 0xB8BC6765, 0xAA09C88B, 0x12B5AFEE, 0x8F629757, 0x37DEF032, 0x256B5FDC, + 0x9DD738B9, 0xC5B428EF, 0x7D084F8A, 0x6FBDE064, 0xD7018701, 0x4AD6BFB8, 0xF26AD8DD, + 0xE0DF7733, 0x58631056, 0x5019579F, 0xE8A530FA, 0xFA109F14, 0x42ACF871, 0xDF7BC0C8, + 0x67C7A7AD, 0x75720843, 0xCDCE6F26, 0x95AD7F70, 0x2D111815, 0x3FA4B7FB, 0x8718D09E, + 0x1ACFE827, 0xA2738F42, 0xB0C620AC, 0x087A47C9, 0xA032AF3E, 0x188EC85B, 0x0A3B67B5, + 0xB28700D0, 0x2F503869, 0x97EC5F0C, 0x8559F0E2, 0x3DE59787, 0x658687D1, 0xDD3AE0B4, + 0xCF8F4F5A, 0x7733283F, 0xEAE41086, 0x525877E3, 0x40EDD80D, 0xF851BF68, 0xF02BF8A1, + 0x48979FC4, 0x5A22302A, 0xE29E574F, 0x7F496FF6, 0xC7F50893, 0xD540A77D, 0x6DFCC018, + 0x359FD04E, 0x8D23B72B, 0x9F9618C5, 0x272A7FA0, 0xBAFD4719, 0x0241207C, 0x10F48F92, + 0xA848E8F7, 0x9B14583D, 0x23A83F58, 0x311D90B6, 0x89A1F7D3, 0x1476CF6A, 0xACCAA80F, + 0xBE7F07E1, 0x06C36084, 0x5EA070D2, 0xE61C17B7, 0xF4A9B859, 0x4C15DF3C, 0xD1C2E785, + 0x697E80E0, 0x7BCB2F0E, 0xC377486B, 0xCB0D0FA2, 0x73B168C7, 0x6104C729, 0xD9B8A04C, + 0x446F98F5, 0xFCD3FF90, 0xEE66507E, 0x56DA371B, 0x0EB9274D, 0xB6054028, 0xA4B0EFC6, + 0x1C0C88A3, 0x81DBB01A, 0x3967D77F, 0x2BD27891, 0x936E1FF4, 0x3B26F703, 0x839A9066, + 0x912F3F88, 0x299358ED, 0xB4446054, 0x0CF80731, 0x1E4DA8DF, 0xA6F1CFBA, 0xFE92DFEC, + 0x462EB889, 0x549B1767, 0xEC277002, 0x71F048BB, 0xC94C2FDE, 0xDBF98030, 0x6345E755, + 0x6B3FA09C, 0xD383C7F9, 0xC1366817, 0x798A0F72, 0xE45D37CB, 0x5CE150AE, 0x4E54FF40, + 0xF6E89825, 0xAE8B8873, 0x1637EF16, 0x048240F8, 0xBC3E279D, 0x21E91F24, 0x99557841, + 0x8BE0D7AF, 0x335CB0CA, 0xED59B63B, 0x55E5D15E, 0x47507EB0, 0xFFEC19D5, 0x623B216C, + 0xDA874609, 0xC832E9E7, 0x708E8E82, 0x28ED9ED4, 0x9051F9B1, 0x82E4565F, 0x3A58313A, + 0xA78F0983, 0x1F336EE6, 0x0D86C108, 0xB53AA66D, 0xBD40E1A4, 0x05FC86C1, 0x1749292F, + 0xAFF54E4A, 0x322276F3, 0x8A9E1196, 0x982BBE78, 0x2097D91D, 0x78F4C94B, 0xC048AE2E, + 0xD2FD01C0, 0x6A4166A5, 0xF7965E1C, 0x4F2A3979, 0x5D9F9697, 0xE523F1F2, 0x4D6B1905, + 0xF5D77E60, 0xE762D18E, 0x5FDEB6EB, 0xC2098E52, 0x7AB5E937, 0x680046D9, 0xD0BC21BC, + 0x88DF31EA, 0x3063568F, 0x22D6F961, 0x9A6A9E04, 0x07BDA6BD, 0xBF01C1D8, 0xADB46E36, + 0x15080953, 0x1D724E9A, 0xA5CE29FF, 0xB77B8611, 0x0FC7E174, 0x9210D9CD, 0x2AACBEA8, + 0x38191146, 0x80A57623, 0xD8C66675, 0x607A0110, 0x72CFAEFE, 0xCA73C99B, 0x57A4F122, + 0xEF189647, 0xFDAD39A9, 0x45115ECC, 0x764DEE06, 0xCEF18963, 0xDC44268D, 0x64F841E8, + 0xF92F7951, 0x41931E34, 0x5326B1DA, 0xEB9AD6BF, 0xB3F9C6E9, 0x0B45A18C, 0x19F00E62, + 0xA14C6907, 0x3C9B51BE, 0x842736DB, 0x96929935, 0x2E2EFE50, 0x2654B999, 0x9EE8DEFC, + 0x8C5D7112, 0x34E11677, 0xA9362ECE, 0x118A49AB, 0x033FE645, 0xBB838120, 0xE3E09176, + 0x5B5CF613, 0x49E959FD, 0xF1553E98, 0x6C820621, 0xD43E6144, 0xC68BCEAA, 0x7E37A9CF, + 0xD67F4138, 0x6EC3265D, 0x7C7689B3, 0xC4CAEED6, 0x591DD66F, 0xE1A1B10A, 0xF3141EE4, + 0x4BA87981, 0x13CB69D7, 0xAB770EB2, 0xB9C2A15C, 0x017EC639, 0x9CA9FE80, 0x241599E5, + 0x36A0360B, 0x8E1C516E, 0x866616A7, 0x3EDA71C2, 0x2C6FDE2C, 0x94D3B949, 0x090481F0, + 0xB1B8E695, 0xA30D497B, 0x1BB12E1E, 0x43D23E48, 0xFB6E592D, 0xE9DBF6C3, 0x516791A6, + 0xCCB0A91F, 0x740CCE7A, 0x66B96194, 0xDE0506F1, + ], + [ + 0x00000000, 0x3D6029B0, 0x7AC05360, 0x47A07AD0, 0xF580A6C0, 0xC8E08F70, 0x8F40F5A0, + 0xB220DC10, 0x30704BC1, 0x0D106271, 0x4AB018A1, 0x77D03111, 0xC5F0ED01, 0xF890C4B1, + 0xBF30BE61, 0x825097D1, 0x60E09782, 0x5D80BE32, 0x1A20C4E2, 0x2740ED52, 0x95603142, + 0xA80018F2, 0xEFA06222, 0xD2C04B92, 0x5090DC43, 0x6DF0F5F3, 0x2A508F23, 0x1730A693, + 0xA5107A83, 0x98705333, 0xDFD029E3, 0xE2B00053, 0xC1C12F04, 0xFCA106B4, 0xBB017C64, + 0x866155D4, 0x344189C4, 0x0921A074, 0x4E81DAA4, 0x73E1F314, 0xF1B164C5, 0xCCD14D75, + 0x8B7137A5, 0xB6111E15, 0x0431C205, 0x3951EBB5, 0x7EF19165, 0x4391B8D5, 0xA121B886, + 0x9C419136, 0xDBE1EBE6, 0xE681C256, 0x54A11E46, 0x69C137F6, 0x2E614D26, 0x13016496, + 0x9151F347, 0xAC31DAF7, 0xEB91A027, 0xD6F18997, 0x64D15587, 0x59B17C37, 0x1E1106E7, + 0x23712F57, 0x58F35849, 0x659371F9, 0x22330B29, 0x1F532299, 0xAD73FE89, 0x9013D739, + 0xD7B3ADE9, 0xEAD38459, 0x68831388, 0x55E33A38, 0x124340E8, 0x2F236958, 0x9D03B548, + 0xA0639CF8, 0xE7C3E628, 0xDAA3CF98, 0x3813CFCB, 0x0573E67B, 0x42D39CAB, 0x7FB3B51B, + 0xCD93690B, 0xF0F340BB, 0xB7533A6B, 0x8A3313DB, 0x0863840A, 0x3503ADBA, 0x72A3D76A, + 0x4FC3FEDA, 0xFDE322CA, 0xC0830B7A, 0x872371AA, 0xBA43581A, 0x9932774D, 0xA4525EFD, + 0xE3F2242D, 0xDE920D9D, 0x6CB2D18D, 0x51D2F83D, 0x167282ED, 0x2B12AB5D, 0xA9423C8C, + 0x9422153C, 0xD3826FEC, 0xEEE2465C, 0x5CC29A4C, 0x61A2B3FC, 0x2602C92C, 0x1B62E09C, + 0xF9D2E0CF, 0xC4B2C97F, 0x8312B3AF, 0xBE729A1F, 0x0C52460F, 0x31326FBF, 0x7692156F, + 0x4BF23CDF, 0xC9A2AB0E, 0xF4C282BE, 0xB362F86E, 0x8E02D1DE, 0x3C220DCE, 0x0142247E, + 0x46E25EAE, 0x7B82771E, 0xB1E6B092, 0x8C869922, 0xCB26E3F2, 0xF646CA42, 0x44661652, + 0x79063FE2, 0x3EA64532, 0x03C66C82, 0x8196FB53, 0xBCF6D2E3, 0xFB56A833, 0xC6368183, + 0x74165D93, 0x49767423, 0x0ED60EF3, 0x33B62743, 0xD1062710, 0xEC660EA0, 0xABC67470, + 0x96A65DC0, 0x248681D0, 0x19E6A860, 0x5E46D2B0, 0x6326FB00, 0xE1766CD1, 0xDC164561, + 0x9BB63FB1, 0xA6D61601, 0x14F6CA11, 0x2996E3A1, 0x6E369971, 0x5356B0C1, 0x70279F96, + 0x4D47B626, 0x0AE7CCF6, 0x3787E546, 0x85A73956, 0xB8C710E6, 0xFF676A36, 0xC2074386, + 0x4057D457, 0x7D37FDE7, 0x3A978737, 0x07F7AE87, 0xB5D77297, 0x88B75B27, 0xCF1721F7, + 0xF2770847, 0x10C70814, 0x2DA721A4, 0x6A075B74, 0x576772C4, 0xE547AED4, 0xD8278764, + 0x9F87FDB4, 0xA2E7D404, 0x20B743D5, 0x1DD76A65, 0x5A7710B5, 0x67173905, 0xD537E515, + 0xE857CCA5, 0xAFF7B675, 0x92979FC5, 0xE915E8DB, 0xD475C16B, 0x93D5BBBB, 0xAEB5920B, + 0x1C954E1B, 0x21F567AB, 0x66551D7B, 0x5B3534CB, 0xD965A31A, 0xE4058AAA, 0xA3A5F07A, + 0x9EC5D9CA, 0x2CE505DA, 0x11852C6A, 0x562556BA, 0x6B457F0A, 0x89F57F59, 0xB49556E9, + 0xF3352C39, 0xCE550589, 0x7C75D999, 0x4115F029, 0x06B58AF9, 0x3BD5A349, 0xB9853498, + 0x84E51D28, 0xC34567F8, 0xFE254E48, 0x4C059258, 0x7165BBE8, 0x36C5C138, 0x0BA5E888, + 0x28D4C7DF, 0x15B4EE6F, 0x521494BF, 0x6F74BD0F, 0xDD54611F, 0xE03448AF, 0xA794327F, + 0x9AF41BCF, 0x18A48C1E, 0x25C4A5AE, 0x6264DF7E, 0x5F04F6CE, 0xED242ADE, 0xD044036E, + 0x97E479BE, 0xAA84500E, 0x4834505D, 0x755479ED, 0x32F4033D, 0x0F942A8D, 0xBDB4F69D, + 0x80D4DF2D, 0xC774A5FD, 0xFA148C4D, 0x78441B9C, 0x4524322C, 0x028448FC, 0x3FE4614C, + 0x8DC4BD5C, 0xB0A494EC, 0xF704EE3C, 0xCA64C78C, + ], + [ + 0x00000000, 0xCB5CD3A5, 0x4DC8A10B, 0x869472AE, 0x9B914216, 0x50CD91B3, 0xD659E31D, + 0x1D0530B8, 0xEC53826D, 0x270F51C8, 0xA19B2366, 0x6AC7F0C3, 0x77C2C07B, 0xBC9E13DE, + 0x3A0A6170, 0xF156B2D5, 0x03D6029B, 0xC88AD13E, 0x4E1EA390, 0x85427035, 0x9847408D, + 0x531B9328, 0xD58FE186, 0x1ED33223, 0xEF8580F6, 0x24D95353, 0xA24D21FD, 0x6911F258, + 0x7414C2E0, 0xBF481145, 0x39DC63EB, 0xF280B04E, 0x07AC0536, 0xCCF0D693, 0x4A64A43D, + 0x81387798, 0x9C3D4720, 0x57619485, 0xD1F5E62B, 0x1AA9358E, 0xEBFF875B, 0x20A354FE, + 0xA6372650, 0x6D6BF5F5, 0x706EC54D, 0xBB3216E8, 0x3DA66446, 0xF6FAB7E3, 0x047A07AD, + 0xCF26D408, 0x49B2A6A6, 0x82EE7503, 0x9FEB45BB, 0x54B7961E, 0xD223E4B0, 0x197F3715, + 0xE82985C0, 0x23755665, 0xA5E124CB, 0x6EBDF76E, 0x73B8C7D6, 0xB8E41473, 0x3E7066DD, + 0xF52CB578, 0x0F580A6C, 0xC404D9C9, 0x4290AB67, 0x89CC78C2, 0x94C9487A, 0x5F959BDF, + 0xD901E971, 0x125D3AD4, 0xE30B8801, 0x28575BA4, 0xAEC3290A, 0x659FFAAF, 0x789ACA17, + 0xB3C619B2, 0x35526B1C, 0xFE0EB8B9, 0x0C8E08F7, 0xC7D2DB52, 0x4146A9FC, 0x8A1A7A59, + 0x971F4AE1, 0x5C439944, 0xDAD7EBEA, 0x118B384F, 0xE0DD8A9A, 0x2B81593F, 0xAD152B91, + 0x6649F834, 0x7B4CC88C, 0xB0101B29, 0x36846987, 0xFDD8BA22, 0x08F40F5A, 0xC3A8DCFF, + 0x453CAE51, 0x8E607DF4, 0x93654D4C, 0x58399EE9, 0xDEADEC47, 0x15F13FE2, 0xE4A78D37, + 0x2FFB5E92, 0xA96F2C3C, 0x6233FF99, 0x7F36CF21, 0xB46A1C84, 0x32FE6E2A, 0xF9A2BD8F, + 0x0B220DC1, 0xC07EDE64, 0x46EAACCA, 0x8DB67F6F, 0x90B34FD7, 0x5BEF9C72, 0xDD7BEEDC, + 0x16273D79, 0xE7718FAC, 0x2C2D5C09, 0xAAB92EA7, 0x61E5FD02, 0x7CE0CDBA, 0xB7BC1E1F, + 0x31286CB1, 0xFA74BF14, 0x1EB014D8, 0xD5ECC77D, 0x5378B5D3, 0x98246676, 0x852156CE, + 0x4E7D856B, 0xC8E9F7C5, 0x03B52460, 0xF2E396B5, 0x39BF4510, 0xBF2B37BE, 0x7477E41B, + 0x6972D4A3, 0xA22E0706, 0x24BA75A8, 0xEFE6A60D, 0x1D661643, 0xD63AC5E6, 0x50AEB748, + 0x9BF264ED, 0x86F75455, 0x4DAB87F0, 0xCB3FF55E, 0x006326FB, 0xF135942E, 0x3A69478B, + 0xBCFD3525, 0x77A1E680, 0x6AA4D638, 0xA1F8059D, 0x276C7733, 0xEC30A496, 0x191C11EE, + 0xD240C24B, 0x54D4B0E5, 0x9F886340, 0x828D53F8, 0x49D1805D, 0xCF45F2F3, 0x04192156, + 0xF54F9383, 0x3E134026, 0xB8873288, 0x73DBE12D, 0x6EDED195, 0xA5820230, 0x2316709E, + 0xE84AA33B, 0x1ACA1375, 0xD196C0D0, 0x5702B27E, 0x9C5E61DB, 0x815B5163, 0x4A0782C6, + 0xCC93F068, 0x07CF23CD, 0xF6999118, 0x3DC542BD, 0xBB513013, 0x700DE3B6, 0x6D08D30E, + 0xA65400AB, 0x20C07205, 0xEB9CA1A0, 0x11E81EB4, 0xDAB4CD11, 0x5C20BFBF, 0x977C6C1A, + 0x8A795CA2, 0x41258F07, 0xC7B1FDA9, 0x0CED2E0C, 0xFDBB9CD9, 0x36E74F7C, 0xB0733DD2, + 0x7B2FEE77, 0x662ADECF, 0xAD760D6A, 0x2BE27FC4, 0xE0BEAC61, 0x123E1C2F, 0xD962CF8A, + 0x5FF6BD24, 0x94AA6E81, 0x89AF5E39, 0x42F38D9C, 0xC467FF32, 0x0F3B2C97, 0xFE6D9E42, + 0x35314DE7, 0xB3A53F49, 0x78F9ECEC, 0x65FCDC54, 0xAEA00FF1, 0x28347D5F, 0xE368AEFA, + 0x16441B82, 0xDD18C827, 0x5B8CBA89, 0x90D0692C, 0x8DD55994, 0x46898A31, 0xC01DF89F, + 0x0B412B3A, 0xFA1799EF, 0x314B4A4A, 0xB7DF38E4, 0x7C83EB41, 0x6186DBF9, 0xAADA085C, + 0x2C4E7AF2, 0xE712A957, 0x15921919, 0xDECECABC, 0x585AB812, 0x93066BB7, 0x8E035B0F, + 0x455F88AA, 0xC3CBFA04, 0x089729A1, 0xF9C19B74, 0x329D48D1, 0xB4093A7F, 0x7F55E9DA, + 0x6250D962, 0xA90C0AC7, 0x2F987869, 0xE4C4ABCC, + ], + [ + 0x00000000, 0xA6770BB4, 0x979F1129, 0x31E81A9D, 0xF44F2413, 0x52382FA7, 0x63D0353A, + 0xC5A73E8E, 0x33EF4E67, 0x959845D3, 0xA4705F4E, 0x020754FA, 0xC7A06A74, 0x61D761C0, + 0x503F7B5D, 0xF64870E9, 0x67DE9CCE, 0xC1A9977A, 0xF0418DE7, 0x56368653, 0x9391B8DD, + 0x35E6B369, 0x040EA9F4, 0xA279A240, 0x5431D2A9, 0xF246D91D, 0xC3AEC380, 0x65D9C834, + 0xA07EF6BA, 0x0609FD0E, 0x37E1E793, 0x9196EC27, 0xCFBD399C, 0x69CA3228, 0x582228B5, + 0xFE552301, 0x3BF21D8F, 0x9D85163B, 0xAC6D0CA6, 0x0A1A0712, 0xFC5277FB, 0x5A257C4F, + 0x6BCD66D2, 0xCDBA6D66, 0x081D53E8, 0xAE6A585C, 0x9F8242C1, 0x39F54975, 0xA863A552, + 0x0E14AEE6, 0x3FFCB47B, 0x998BBFCF, 0x5C2C8141, 0xFA5B8AF5, 0xCBB39068, 0x6DC49BDC, + 0x9B8CEB35, 0x3DFBE081, 0x0C13FA1C, 0xAA64F1A8, 0x6FC3CF26, 0xC9B4C492, 0xF85CDE0F, + 0x5E2BD5BB, 0x440B7579, 0xE27C7ECD, 0xD3946450, 0x75E36FE4, 0xB044516A, 0x16335ADE, + 0x27DB4043, 0x81AC4BF7, 0x77E43B1E, 0xD19330AA, 0xE07B2A37, 0x460C2183, 0x83AB1F0D, + 0x25DC14B9, 0x14340E24, 0xB2430590, 0x23D5E9B7, 0x85A2E203, 0xB44AF89E, 0x123DF32A, + 0xD79ACDA4, 0x71EDC610, 0x4005DC8D, 0xE672D739, 0x103AA7D0, 0xB64DAC64, 0x87A5B6F9, + 0x21D2BD4D, 0xE47583C3, 0x42028877, 0x73EA92EA, 0xD59D995E, 0x8BB64CE5, 0x2DC14751, + 0x1C295DCC, 0xBA5E5678, 0x7FF968F6, 0xD98E6342, 0xE86679DF, 0x4E11726B, 0xB8590282, + 0x1E2E0936, 0x2FC613AB, 0x89B1181F, 0x4C162691, 0xEA612D25, 0xDB8937B8, 0x7DFE3C0C, + 0xEC68D02B, 0x4A1FDB9F, 0x7BF7C102, 0xDD80CAB6, 0x1827F438, 0xBE50FF8C, 0x8FB8E511, + 0x29CFEEA5, 0xDF879E4C, 0x79F095F8, 0x48188F65, 0xEE6F84D1, 0x2BC8BA5F, 0x8DBFB1EB, + 0xBC57AB76, 0x1A20A0C2, 0x8816EAF2, 0x2E61E146, 0x1F89FBDB, 0xB9FEF06F, 0x7C59CEE1, + 0xDA2EC555, 0xEBC6DFC8, 0x4DB1D47C, 0xBBF9A495, 0x1D8EAF21, 0x2C66B5BC, 0x8A11BE08, + 0x4FB68086, 0xE9C18B32, 0xD82991AF, 0x7E5E9A1B, 0xEFC8763C, 0x49BF7D88, 0x78576715, + 0xDE206CA1, 0x1B87522F, 0xBDF0599B, 0x8C184306, 0x2A6F48B2, 0xDC27385B, 0x7A5033EF, + 0x4BB82972, 0xEDCF22C6, 0x28681C48, 0x8E1F17FC, 0xBFF70D61, 0x198006D5, 0x47ABD36E, + 0xE1DCD8DA, 0xD034C247, 0x7643C9F3, 0xB3E4F77D, 0x1593FCC9, 0x247BE654, 0x820CEDE0, + 0x74449D09, 0xD23396BD, 0xE3DB8C20, 0x45AC8794, 0x800BB91A, 0x267CB2AE, 0x1794A833, + 0xB1E3A387, 0x20754FA0, 0x86024414, 0xB7EA5E89, 0x119D553D, 0xD43A6BB3, 0x724D6007, + 0x43A57A9A, 0xE5D2712E, 0x139A01C7, 0xB5ED0A73, 0x840510EE, 0x22721B5A, 0xE7D525D4, + 0x41A22E60, 0x704A34FD, 0xD63D3F49, 0xCC1D9F8B, 0x6A6A943F, 0x5B828EA2, 0xFDF58516, + 0x3852BB98, 0x9E25B02C, 0xAFCDAAB1, 0x09BAA105, 0xFFF2D1EC, 0x5985DA58, 0x686DC0C5, + 0xCE1ACB71, 0x0BBDF5FF, 0xADCAFE4B, 0x9C22E4D6, 0x3A55EF62, 0xABC30345, 0x0DB408F1, + 0x3C5C126C, 0x9A2B19D8, 0x5F8C2756, 0xF9FB2CE2, 0xC813367F, 0x6E643DCB, 0x982C4D22, + 0x3E5B4696, 0x0FB35C0B, 0xA9C457BF, 0x6C636931, 0xCA146285, 0xFBFC7818, 0x5D8B73AC, + 0x03A0A617, 0xA5D7ADA3, 0x943FB73E, 0x3248BC8A, 0xF7EF8204, 0x519889B0, 0x6070932D, + 0xC6079899, 0x304FE870, 0x9638E3C4, 0xA7D0F959, 0x01A7F2ED, 0xC400CC63, 0x6277C7D7, + 0x539FDD4A, 0xF5E8D6FE, 0x647E3AD9, 0xC209316D, 0xF3E12BF0, 0x55962044, 0x90311ECA, + 0x3646157E, 0x07AE0FE3, 0xA1D90457, 0x579174BE, 0xF1E67F0A, 0xC00E6597, 0x66796E23, + 0xA3DE50AD, 0x05A95B19, 0x34414184, 0x92364A30, + ], + [ + 0x00000000, 0xCCAA009E, 0x4225077D, 0x8E8F07E3, 0x844A0EFA, 0x48E00E64, 0xC66F0987, + 0x0AC50919, 0xD3E51BB5, 0x1F4F1B2B, 0x91C01CC8, 0x5D6A1C56, 0x57AF154F, 0x9B0515D1, + 0x158A1232, 0xD92012AC, 0x7CBB312B, 0xB01131B5, 0x3E9E3656, 0xF23436C8, 0xF8F13FD1, + 0x345B3F4F, 0xBAD438AC, 0x767E3832, 0xAF5E2A9E, 0x63F42A00, 0xED7B2DE3, 0x21D12D7D, + 0x2B142464, 0xE7BE24FA, 0x69312319, 0xA59B2387, 0xF9766256, 0x35DC62C8, 0xBB53652B, + 0x77F965B5, 0x7D3C6CAC, 0xB1966C32, 0x3F196BD1, 0xF3B36B4F, 0x2A9379E3, 0xE639797D, + 0x68B67E9E, 0xA41C7E00, 0xAED97719, 0x62737787, 0xECFC7064, 0x205670FA, 0x85CD537D, + 0x496753E3, 0xC7E85400, 0x0B42549E, 0x01875D87, 0xCD2D5D19, 0x43A25AFA, 0x8F085A64, + 0x562848C8, 0x9A824856, 0x140D4FB5, 0xD8A74F2B, 0xD2624632, 0x1EC846AC, 0x9047414F, + 0x5CED41D1, 0x299DC2ED, 0xE537C273, 0x6BB8C590, 0xA712C50E, 0xADD7CC17, 0x617DCC89, + 0xEFF2CB6A, 0x2358CBF4, 0xFA78D958, 0x36D2D9C6, 0xB85DDE25, 0x74F7DEBB, 0x7E32D7A2, + 0xB298D73C, 0x3C17D0DF, 0xF0BDD041, 0x5526F3C6, 0x998CF358, 0x1703F4BB, 0xDBA9F425, + 0xD16CFD3C, 0x1DC6FDA2, 0x9349FA41, 0x5FE3FADF, 0x86C3E873, 0x4A69E8ED, 0xC4E6EF0E, + 0x084CEF90, 0x0289E689, 0xCE23E617, 0x40ACE1F4, 0x8C06E16A, 0xD0EBA0BB, 0x1C41A025, + 0x92CEA7C6, 0x5E64A758, 0x54A1AE41, 0x980BAEDF, 0x1684A93C, 0xDA2EA9A2, 0x030EBB0E, + 0xCFA4BB90, 0x412BBC73, 0x8D81BCED, 0x8744B5F4, 0x4BEEB56A, 0xC561B289, 0x09CBB217, + 0xAC509190, 0x60FA910E, 0xEE7596ED, 0x22DF9673, 0x281A9F6A, 0xE4B09FF4, 0x6A3F9817, + 0xA6959889, 0x7FB58A25, 0xB31F8ABB, 0x3D908D58, 0xF13A8DC6, 0xFBFF84DF, 0x37558441, + 0xB9DA83A2, 0x7570833C, 0x533B85DA, 0x9F918544, 0x111E82A7, 0xDDB48239, 0xD7718B20, + 0x1BDB8BBE, 0x95548C5D, 0x59FE8CC3, 0x80DE9E6F, 0x4C749EF1, 0xC2FB9912, 0x0E51998C, + 0x04949095, 0xC83E900B, 0x46B197E8, 0x8A1B9776, 0x2F80B4F1, 0xE32AB46F, 0x6DA5B38C, + 0xA10FB312, 0xABCABA0B, 0x6760BA95, 0xE9EFBD76, 0x2545BDE8, 0xFC65AF44, 0x30CFAFDA, + 0xBE40A839, 0x72EAA8A7, 0x782FA1BE, 0xB485A120, 0x3A0AA6C3, 0xF6A0A65D, 0xAA4DE78C, + 0x66E7E712, 0xE868E0F1, 0x24C2E06F, 0x2E07E976, 0xE2ADE9E8, 0x6C22EE0B, 0xA088EE95, + 0x79A8FC39, 0xB502FCA7, 0x3B8DFB44, 0xF727FBDA, 0xFDE2F2C3, 0x3148F25D, 0xBFC7F5BE, + 0x736DF520, 0xD6F6D6A7, 0x1A5CD639, 0x94D3D1DA, 0x5879D144, 0x52BCD85D, 0x9E16D8C3, + 0x1099DF20, 0xDC33DFBE, 0x0513CD12, 0xC9B9CD8C, 0x4736CA6F, 0x8B9CCAF1, 0x8159C3E8, + 0x4DF3C376, 0xC37CC495, 0x0FD6C40B, 0x7AA64737, 0xB60C47A9, 0x3883404A, 0xF42940D4, + 0xFEEC49CD, 0x32464953, 0xBCC94EB0, 0x70634E2E, 0xA9435C82, 0x65E95C1C, 0xEB665BFF, + 0x27CC5B61, 0x2D095278, 0xE1A352E6, 0x6F2C5505, 0xA386559B, 0x061D761C, 0xCAB77682, + 0x44387161, 0x889271FF, 0x825778E6, 0x4EFD7878, 0xC0727F9B, 0x0CD87F05, 0xD5F86DA9, + 0x19526D37, 0x97DD6AD4, 0x5B776A4A, 0x51B26353, 0x9D1863CD, 0x1397642E, 0xDF3D64B0, + 0x83D02561, 0x4F7A25FF, 0xC1F5221C, 0x0D5F2282, 0x079A2B9B, 0xCB302B05, 0x45BF2CE6, + 0x89152C78, 0x50353ED4, 0x9C9F3E4A, 0x121039A9, 0xDEBA3937, 0xD47F302E, 0x18D530B0, + 0x965A3753, 0x5AF037CD, 0xFF6B144A, 0x33C114D4, 0xBD4E1337, 0x71E413A9, 0x7B211AB0, + 0xB78B1A2E, 0x39041DCD, 0xF5AE1D53, 0x2C8E0FFF, 0xE0240F61, 0x6EAB0882, 0xA201081C, + 0xA8C40105, 0x646E019B, 0xEAE10678, 0x264B06E6, + ], + [ + 0x00000000, 0x177B1443, 0x2EF62886, 0x398D3CC5, 0x5DEC510C, 0x4A97454F, 0x731A798A, + 0x64616DC9, 0xBBD8A218, 0xACA3B65B, 0x952E8A9E, 0x82559EDD, 0xE634F314, 0xF14FE757, + 0xC8C2DB92, 0xDFB9CFD1, 0xACC04271, 0xBBBB5632, 0x82366AF7, 0x954D7EB4, 0xF12C137D, + 0xE657073E, 0xDFDA3BFB, 0xC8A12FB8, 0x1718E069, 0x0063F42A, 0x39EEC8EF, 0x2E95DCAC, + 0x4AF4B165, 0x5D8FA526, 0x640299E3, 0x73798DA0, 0x82F182A3, 0x958A96E0, 0xAC07AA25, + 0xBB7CBE66, 0xDF1DD3AF, 0xC866C7EC, 0xF1EBFB29, 0xE690EF6A, 0x392920BB, 0x2E5234F8, + 0x17DF083D, 0x00A41C7E, 0x64C571B7, 0x73BE65F4, 0x4A335931, 0x5D484D72, 0x2E31C0D2, + 0x394AD491, 0x00C7E854, 0x17BCFC17, 0x73DD91DE, 0x64A6859D, 0x5D2BB958, 0x4A50AD1B, + 0x95E962CA, 0x82927689, 0xBB1F4A4C, 0xAC645E0F, 0xC80533C6, 0xDF7E2785, 0xE6F31B40, + 0xF1880F03, 0xDE920307, 0xC9E91744, 0xF0642B81, 0xE71F3FC2, 0x837E520B, 0x94054648, + 0xAD887A8D, 0xBAF36ECE, 0x654AA11F, 0x7231B55C, 0x4BBC8999, 0x5CC79DDA, 0x38A6F013, + 0x2FDDE450, 0x1650D895, 0x012BCCD6, 0x72524176, 0x65295535, 0x5CA469F0, 0x4BDF7DB3, + 0x2FBE107A, 0x38C50439, 0x014838FC, 0x16332CBF, 0xC98AE36E, 0xDEF1F72D, 0xE77CCBE8, + 0xF007DFAB, 0x9466B262, 0x831DA621, 0xBA909AE4, 0xADEB8EA7, 0x5C6381A4, 0x4B1895E7, + 0x7295A922, 0x65EEBD61, 0x018FD0A8, 0x16F4C4EB, 0x2F79F82E, 0x3802EC6D, 0xE7BB23BC, + 0xF0C037FF, 0xC94D0B3A, 0xDE361F79, 0xBA5772B0, 0xAD2C66F3, 0x94A15A36, 0x83DA4E75, + 0xF0A3C3D5, 0xE7D8D796, 0xDE55EB53, 0xC92EFF10, 0xAD4F92D9, 0xBA34869A, 0x83B9BA5F, + 0x94C2AE1C, 0x4B7B61CD, 0x5C00758E, 0x658D494B, 0x72F65D08, 0x169730C1, 0x01EC2482, + 0x38611847, 0x2F1A0C04, 0x6655004F, 0x712E140C, 0x48A328C9, 0x5FD83C8A, 0x3BB95143, + 0x2CC24500, 0x154F79C5, 0x02346D86, 0xDD8DA257, 0xCAF6B614, 0xF37B8AD1, 0xE4009E92, + 0x8061F35B, 0x971AE718, 0xAE97DBDD, 0xB9ECCF9E, 0xCA95423E, 0xDDEE567D, 0xE4636AB8, + 0xF3187EFB, 0x97791332, 0x80020771, 0xB98F3BB4, 0xAEF42FF7, 0x714DE026, 0x6636F465, + 0x5FBBC8A0, 0x48C0DCE3, 0x2CA1B12A, 0x3BDAA569, 0x025799AC, 0x152C8DEF, 0xE4A482EC, + 0xF3DF96AF, 0xCA52AA6A, 0xDD29BE29, 0xB948D3E0, 0xAE33C7A3, 0x97BEFB66, 0x80C5EF25, + 0x5F7C20F4, 0x480734B7, 0x718A0872, 0x66F11C31, 0x029071F8, 0x15EB65BB, 0x2C66597E, + 0x3B1D4D3D, 0x4864C09D, 0x5F1FD4DE, 0x6692E81B, 0x71E9FC58, 0x15889191, 0x02F385D2, + 0x3B7EB917, 0x2C05AD54, 0xF3BC6285, 0xE4C776C6, 0xDD4A4A03, 0xCA315E40, 0xAE503389, + 0xB92B27CA, 0x80A61B0F, 0x97DD0F4C, 0xB8C70348, 0xAFBC170B, 0x96312BCE, 0x814A3F8D, + 0xE52B5244, 0xF2504607, 0xCBDD7AC2, 0xDCA66E81, 0x031FA150, 0x1464B513, 0x2DE989D6, + 0x3A929D95, 0x5EF3F05C, 0x4988E41F, 0x7005D8DA, 0x677ECC99, 0x14074139, 0x037C557A, + 0x3AF169BF, 0x2D8A7DFC, 0x49EB1035, 0x5E900476, 0x671D38B3, 0x70662CF0, 0xAFDFE321, + 0xB8A4F762, 0x8129CBA7, 0x9652DFE4, 0xF233B22D, 0xE548A66E, 0xDCC59AAB, 0xCBBE8EE8, + 0x3A3681EB, 0x2D4D95A8, 0x14C0A96D, 0x03BBBD2E, 0x67DAD0E7, 0x70A1C4A4, 0x492CF861, + 0x5E57EC22, 0x81EE23F3, 0x969537B0, 0xAF180B75, 0xB8631F36, 0xDC0272FF, 0xCB7966BC, + 0xF2F45A79, 0xE58F4E3A, 0x96F6C39A, 0x818DD7D9, 0xB800EB1C, 0xAF7BFF5F, 0xCB1A9296, + 0xDC6186D5, 0xE5ECBA10, 0xF297AE53, 0x2D2E6182, 0x3A5575C1, 0x03D84904, 0x14A35D47, + 0x70C2308E, 0x67B924CD, 0x5E341808, 0x494F0C4B, + ], + [ + 0x00000000, 0xEFC26B3E, 0x04F5D03D, 0xEB37BB03, 0x09EBA07A, 0xE629CB44, 0x0D1E7047, + 0xE2DC1B79, 0x13D740F4, 0xFC152BCA, 0x172290C9, 0xF8E0FBF7, 0x1A3CE08E, 0xF5FE8BB0, + 0x1EC930B3, 0xF10B5B8D, 0x27AE81E8, 0xC86CEAD6, 0x235B51D5, 0xCC993AEB, 0x2E452192, + 0xC1874AAC, 0x2AB0F1AF, 0xC5729A91, 0x3479C11C, 0xDBBBAA22, 0x308C1121, 0xDF4E7A1F, + 0x3D926166, 0xD2500A58, 0x3967B15B, 0xD6A5DA65, 0x4F5D03D0, 0xA09F68EE, 0x4BA8D3ED, + 0xA46AB8D3, 0x46B6A3AA, 0xA974C894, 0x42437397, 0xAD8118A9, 0x5C8A4324, 0xB348281A, + 0x587F9319, 0xB7BDF827, 0x5561E35E, 0xBAA38860, 0x51943363, 0xBE56585D, 0x68F38238, + 0x8731E906, 0x6C065205, 0x83C4393B, 0x61182242, 0x8EDA497C, 0x65EDF27F, 0x8A2F9941, + 0x7B24C2CC, 0x94E6A9F2, 0x7FD112F1, 0x901379CF, 0x72CF62B6, 0x9D0D0988, 0x763AB28B, + 0x99F8D9B5, 0x9EBA07A0, 0x71786C9E, 0x9A4FD79D, 0x758DBCA3, 0x9751A7DA, 0x7893CCE4, + 0x93A477E7, 0x7C661CD9, 0x8D6D4754, 0x62AF2C6A, 0x89989769, 0x665AFC57, 0x8486E72E, + 0x6B448C10, 0x80733713, 0x6FB15C2D, 0xB9148648, 0x56D6ED76, 0xBDE15675, 0x52233D4B, + 0xB0FF2632, 0x5F3D4D0C, 0xB40AF60F, 0x5BC89D31, 0xAAC3C6BC, 0x4501AD82, 0xAE361681, + 0x41F47DBF, 0xA32866C6, 0x4CEA0DF8, 0xA7DDB6FB, 0x481FDDC5, 0xD1E70470, 0x3E256F4E, + 0xD512D44D, 0x3AD0BF73, 0xD80CA40A, 0x37CECF34, 0xDCF97437, 0x333B1F09, 0xC2304484, + 0x2DF22FBA, 0xC6C594B9, 0x2907FF87, 0xCBDBE4FE, 0x24198FC0, 0xCF2E34C3, 0x20EC5FFD, + 0xF6498598, 0x198BEEA6, 0xF2BC55A5, 0x1D7E3E9B, 0xFFA225E2, 0x10604EDC, 0xFB57F5DF, + 0x14959EE1, 0xE59EC56C, 0x0A5CAE52, 0xE16B1551, 0x0EA97E6F, 0xEC756516, 0x03B70E28, + 0xE880B52B, 0x0742DE15, 0xE6050901, 0x09C7623F, 0xE2F0D93C, 0x0D32B202, 0xEFEEA97B, + 0x002CC245, 0xEB1B7946, 0x04D91278, 0xF5D249F5, 0x1A1022CB, 0xF12799C8, 0x1EE5F2F6, + 0xFC39E98F, 0x13FB82B1, 0xF8CC39B2, 0x170E528C, 0xC1AB88E9, 0x2E69E3D7, 0xC55E58D4, + 0x2A9C33EA, 0xC8402893, 0x278243AD, 0xCCB5F8AE, 0x23779390, 0xD27CC81D, 0x3DBEA323, + 0xD6891820, 0x394B731E, 0xDB976867, 0x34550359, 0xDF62B85A, 0x30A0D364, 0xA9580AD1, + 0x469A61EF, 0xADADDAEC, 0x426FB1D2, 0xA0B3AAAB, 0x4F71C195, 0xA4467A96, 0x4B8411A8, + 0xBA8F4A25, 0x554D211B, 0xBE7A9A18, 0x51B8F126, 0xB364EA5F, 0x5CA68161, 0xB7913A62, + 0x5853515C, 0x8EF68B39, 0x6134E007, 0x8A035B04, 0x65C1303A, 0x871D2B43, 0x68DF407D, + 0x83E8FB7E, 0x6C2A9040, 0x9D21CBCD, 0x72E3A0F3, 0x99D41BF0, 0x761670CE, 0x94CA6BB7, + 0x7B080089, 0x903FBB8A, 0x7FFDD0B4, 0x78BF0EA1, 0x977D659F, 0x7C4ADE9C, 0x9388B5A2, + 0x7154AEDB, 0x9E96C5E5, 0x75A17EE6, 0x9A6315D8, 0x6B684E55, 0x84AA256B, 0x6F9D9E68, + 0x805FF556, 0x6283EE2F, 0x8D418511, 0x66763E12, 0x89B4552C, 0x5F118F49, 0xB0D3E477, + 0x5BE45F74, 0xB426344A, 0x56FA2F33, 0xB938440D, 0x520FFF0E, 0xBDCD9430, 0x4CC6CFBD, + 0xA304A483, 0x48331F80, 0xA7F174BE, 0x452D6FC7, 0xAAEF04F9, 0x41D8BFFA, 0xAE1AD4C4, + 0x37E20D71, 0xD820664F, 0x3317DD4C, 0xDCD5B672, 0x3E09AD0B, 0xD1CBC635, 0x3AFC7D36, + 0xD53E1608, 0x24354D85, 0xCBF726BB, 0x20C09DB8, 0xCF02F686, 0x2DDEEDFF, 0xC21C86C1, + 0x292B3DC2, 0xC6E956FC, 0x104C8C99, 0xFF8EE7A7, 0x14B95CA4, 0xFB7B379A, 0x19A72CE3, + 0xF66547DD, 0x1D52FCDE, 0xF29097E0, 0x039BCC6D, 0xEC59A753, 0x076E1C50, 0xE8AC776E, + 0x0A706C17, 0xE5B20729, 0x0E85BC2A, 0xE147D714, + ], + [ + 0x00000000, 0xC18EDFC0, 0x586CB9C1, 0x99E26601, 0xB0D97382, 0x7157AC42, 0xE8B5CA43, + 0x293B1583, 0xBAC3E145, 0x7B4D3E85, 0xE2AF5884, 0x23218744, 0x0A1A92C7, 0xCB944D07, + 0x52762B06, 0x93F8F4C6, 0xAEF6C4CB, 0x6F781B0B, 0xF69A7D0A, 0x3714A2CA, 0x1E2FB749, + 0xDFA16889, 0x46430E88, 0x87CDD148, 0x1435258E, 0xD5BBFA4E, 0x4C599C4F, 0x8DD7438F, + 0xA4EC560C, 0x656289CC, 0xFC80EFCD, 0x3D0E300D, 0x869C8FD7, 0x47125017, 0xDEF03616, + 0x1F7EE9D6, 0x3645FC55, 0xF7CB2395, 0x6E294594, 0xAFA79A54, 0x3C5F6E92, 0xFDD1B152, + 0x6433D753, 0xA5BD0893, 0x8C861D10, 0x4D08C2D0, 0xD4EAA4D1, 0x15647B11, 0x286A4B1C, + 0xE9E494DC, 0x7006F2DD, 0xB1882D1D, 0x98B3389E, 0x593DE75E, 0xC0DF815F, 0x01515E9F, + 0x92A9AA59, 0x53277599, 0xCAC51398, 0x0B4BCC58, 0x2270D9DB, 0xE3FE061B, 0x7A1C601A, + 0xBB92BFDA, 0xD64819EF, 0x17C6C62F, 0x8E24A02E, 0x4FAA7FEE, 0x66916A6D, 0xA71FB5AD, + 0x3EFDD3AC, 0xFF730C6C, 0x6C8BF8AA, 0xAD05276A, 0x34E7416B, 0xF5699EAB, 0xDC528B28, + 0x1DDC54E8, 0x843E32E9, 0x45B0ED29, 0x78BEDD24, 0xB93002E4, 0x20D264E5, 0xE15CBB25, + 0xC867AEA6, 0x09E97166, 0x900B1767, 0x5185C8A7, 0xC27D3C61, 0x03F3E3A1, 0x9A1185A0, + 0x5B9F5A60, 0x72A44FE3, 0xB32A9023, 0x2AC8F622, 0xEB4629E2, 0x50D49638, 0x915A49F8, + 0x08B82FF9, 0xC936F039, 0xE00DE5BA, 0x21833A7A, 0xB8615C7B, 0x79EF83BB, 0xEA17777D, + 0x2B99A8BD, 0xB27BCEBC, 0x73F5117C, 0x5ACE04FF, 0x9B40DB3F, 0x02A2BD3E, 0xC32C62FE, + 0xFE2252F3, 0x3FAC8D33, 0xA64EEB32, 0x67C034F2, 0x4EFB2171, 0x8F75FEB1, 0x169798B0, + 0xD7194770, 0x44E1B3B6, 0x856F6C76, 0x1C8D0A77, 0xDD03D5B7, 0xF438C034, 0x35B61FF4, + 0xAC5479F5, 0x6DDAA635, 0x77E1359F, 0xB66FEA5F, 0x2F8D8C5E, 0xEE03539E, 0xC738461D, + 0x06B699DD, 0x9F54FFDC, 0x5EDA201C, 0xCD22D4DA, 0x0CAC0B1A, 0x954E6D1B, 0x54C0B2DB, + 0x7DFBA758, 0xBC757898, 0x25971E99, 0xE419C159, 0xD917F154, 0x18992E94, 0x817B4895, + 0x40F59755, 0x69CE82D6, 0xA8405D16, 0x31A23B17, 0xF02CE4D7, 0x63D41011, 0xA25ACFD1, + 0x3BB8A9D0, 0xFA367610, 0xD30D6393, 0x1283BC53, 0x8B61DA52, 0x4AEF0592, 0xF17DBA48, + 0x30F36588, 0xA9110389, 0x689FDC49, 0x41A4C9CA, 0x802A160A, 0x19C8700B, 0xD846AFCB, + 0x4BBE5B0D, 0x8A3084CD, 0x13D2E2CC, 0xD25C3D0C, 0xFB67288F, 0x3AE9F74F, 0xA30B914E, + 0x62854E8E, 0x5F8B7E83, 0x9E05A143, 0x07E7C742, 0xC6691882, 0xEF520D01, 0x2EDCD2C1, + 0xB73EB4C0, 0x76B06B00, 0xE5489FC6, 0x24C64006, 0xBD242607, 0x7CAAF9C7, 0x5591EC44, + 0x941F3384, 0x0DFD5585, 0xCC738A45, 0xA1A92C70, 0x6027F3B0, 0xF9C595B1, 0x384B4A71, + 0x11705FF2, 0xD0FE8032, 0x491CE633, 0x889239F3, 0x1B6ACD35, 0xDAE412F5, 0x430674F4, + 0x8288AB34, 0xABB3BEB7, 0x6A3D6177, 0xF3DF0776, 0x3251D8B6, 0x0F5FE8BB, 0xCED1377B, + 0x5733517A, 0x96BD8EBA, 0xBF869B39, 0x7E0844F9, 0xE7EA22F8, 0x2664FD38, 0xB59C09FE, + 0x7412D63E, 0xEDF0B03F, 0x2C7E6FFF, 0x05457A7C, 0xC4CBA5BC, 0x5D29C3BD, 0x9CA71C7D, + 0x2735A3A7, 0xE6BB7C67, 0x7F591A66, 0xBED7C5A6, 0x97ECD025, 0x56620FE5, 0xCF8069E4, + 0x0E0EB624, 0x9DF642E2, 0x5C789D22, 0xC59AFB23, 0x041424E3, 0x2D2F3160, 0xECA1EEA0, + 0x754388A1, 0xB4CD5761, 0x89C3676C, 0x484DB8AC, 0xD1AFDEAD, 0x1021016D, 0x391A14EE, + 0xF894CB2E, 0x6176AD2F, 0xA0F872EF, 0x33008629, 0xF28E59E9, 0x6B6C3FE8, 0xAAE2E028, + 0x83D9F5AB, 0x42572A6B, 0xDBB54C6A, 0x1A3B93AA, + ], + [ + 0x00000000, 0x9BA54C6F, 0xEC3B9E9F, 0x779ED2F0, 0x03063B7F, 0x98A37710, 0xEF3DA5E0, + 0x7498E98F, 0x060C76FE, 0x9DA93A91, 0xEA37E861, 0x7192A40E, 0x050A4D81, 0x9EAF01EE, + 0xE931D31E, 0x72949F71, 0x0C18EDFC, 0x97BDA193, 0xE0237363, 0x7B863F0C, 0x0F1ED683, + 0x94BB9AEC, 0xE325481C, 0x78800473, 0x0A149B02, 0x91B1D76D, 0xE62F059D, 0x7D8A49F2, + 0x0912A07D, 0x92B7EC12, 0xE5293EE2, 0x7E8C728D, 0x1831DBF8, 0x83949797, 0xF40A4567, + 0x6FAF0908, 0x1B37E087, 0x8092ACE8, 0xF70C7E18, 0x6CA93277, 0x1E3DAD06, 0x8598E169, + 0xF2063399, 0x69A37FF6, 0x1D3B9679, 0x869EDA16, 0xF10008E6, 0x6AA54489, 0x14293604, + 0x8F8C7A6B, 0xF812A89B, 0x63B7E4F4, 0x172F0D7B, 0x8C8A4114, 0xFB1493E4, 0x60B1DF8B, + 0x122540FA, 0x89800C95, 0xFE1EDE65, 0x65BB920A, 0x11237B85, 0x8A8637EA, 0xFD18E51A, + 0x66BDA975, 0x3063B7F0, 0xABC6FB9F, 0xDC58296F, 0x47FD6500, 0x33658C8F, 0xA8C0C0E0, + 0xDF5E1210, 0x44FB5E7F, 0x366FC10E, 0xADCA8D61, 0xDA545F91, 0x41F113FE, 0x3569FA71, + 0xAECCB61E, 0xD95264EE, 0x42F72881, 0x3C7B5A0C, 0xA7DE1663, 0xD040C493, 0x4BE588FC, + 0x3F7D6173, 0xA4D82D1C, 0xD346FFEC, 0x48E3B383, 0x3A772CF2, 0xA1D2609D, 0xD64CB26D, + 0x4DE9FE02, 0x3971178D, 0xA2D45BE2, 0xD54A8912, 0x4EEFC57D, 0x28526C08, 0xB3F72067, + 0xC469F297, 0x5FCCBEF8, 0x2B545777, 0xB0F11B18, 0xC76FC9E8, 0x5CCA8587, 0x2E5E1AF6, + 0xB5FB5699, 0xC2658469, 0x59C0C806, 0x2D582189, 0xB6FD6DE6, 0xC163BF16, 0x5AC6F379, + 0x244A81F4, 0xBFEFCD9B, 0xC8711F6B, 0x53D45304, 0x274CBA8B, 0xBCE9F6E4, 0xCB772414, + 0x50D2687B, 0x2246F70A, 0xB9E3BB65, 0xCE7D6995, 0x55D825FA, 0x2140CC75, 0xBAE5801A, + 0xCD7B52EA, 0x56DE1E85, 0x60C76FE0, 0xFB62238F, 0x8CFCF17F, 0x1759BD10, 0x63C1549F, + 0xF86418F0, 0x8FFACA00, 0x145F866F, 0x66CB191E, 0xFD6E5571, 0x8AF08781, 0x1155CBEE, + 0x65CD2261, 0xFE686E0E, 0x89F6BCFE, 0x1253F091, 0x6CDF821C, 0xF77ACE73, 0x80E41C83, + 0x1B4150EC, 0x6FD9B963, 0xF47CF50C, 0x83E227FC, 0x18476B93, 0x6AD3F4E2, 0xF176B88D, + 0x86E86A7D, 0x1D4D2612, 0x69D5CF9D, 0xF27083F2, 0x85EE5102, 0x1E4B1D6D, 0x78F6B418, + 0xE353F877, 0x94CD2A87, 0x0F6866E8, 0x7BF08F67, 0xE055C308, 0x97CB11F8, 0x0C6E5D97, + 0x7EFAC2E6, 0xE55F8E89, 0x92C15C79, 0x09641016, 0x7DFCF999, 0xE659B5F6, 0x91C76706, + 0x0A622B69, 0x74EE59E4, 0xEF4B158B, 0x98D5C77B, 0x03708B14, 0x77E8629B, 0xEC4D2EF4, + 0x9BD3FC04, 0x0076B06B, 0x72E22F1A, 0xE9476375, 0x9ED9B185, 0x057CFDEA, 0x71E41465, + 0xEA41580A, 0x9DDF8AFA, 0x067AC695, 0x50A4D810, 0xCB01947F, 0xBC9F468F, 0x273A0AE0, + 0x53A2E36F, 0xC807AF00, 0xBF997DF0, 0x243C319F, 0x56A8AEEE, 0xCD0DE281, 0xBA933071, + 0x21367C1E, 0x55AE9591, 0xCE0BD9FE, 0xB9950B0E, 0x22304761, 0x5CBC35EC, 0xC7197983, + 0xB087AB73, 0x2B22E71C, 0x5FBA0E93, 0xC41F42FC, 0xB381900C, 0x2824DC63, 0x5AB04312, + 0xC1150F7D, 0xB68BDD8D, 0x2D2E91E2, 0x59B6786D, 0xC2133402, 0xB58DE6F2, 0x2E28AA9D, + 0x489503E8, 0xD3304F87, 0xA4AE9D77, 0x3F0BD118, 0x4B933897, 0xD03674F8, 0xA7A8A608, + 0x3C0DEA67, 0x4E997516, 0xD53C3979, 0xA2A2EB89, 0x3907A7E6, 0x4D9F4E69, 0xD63A0206, + 0xA1A4D0F6, 0x3A019C99, 0x448DEE14, 0xDF28A27B, 0xA8B6708B, 0x33133CE4, 0x478BD56B, + 0xDC2E9904, 0xABB04BF4, 0x3015079B, 0x428198EA, 0xD924D485, 0xAEBA0675, 0x351F4A1A, + 0x4187A395, 0xDA22EFFA, 0xADBC3D0A, 0x36197165, + ], + [ + 0x00000000, 0xDD96D985, 0x605CB54B, 0xBDCA6CCE, 0xC0B96A96, 0x1D2FB313, 0xA0E5DFDD, + 0x7D730658, 0x5A03D36D, 0x87950AE8, 0x3A5F6626, 0xE7C9BFA3, 0x9ABAB9FB, 0x472C607E, + 0xFAE60CB0, 0x2770D535, 0xB407A6DA, 0x69917F5F, 0xD45B1391, 0x09CDCA14, 0x74BECC4C, + 0xA92815C9, 0x14E27907, 0xC974A082, 0xEE0475B7, 0x3392AC32, 0x8E58C0FC, 0x53CE1979, + 0x2EBD1F21, 0xF32BC6A4, 0x4EE1AA6A, 0x937773EF, 0xB37E4BF5, 0x6EE89270, 0xD322FEBE, + 0x0EB4273B, 0x73C72163, 0xAE51F8E6, 0x139B9428, 0xCE0D4DAD, 0xE97D9898, 0x34EB411D, + 0x89212DD3, 0x54B7F456, 0x29C4F20E, 0xF4522B8B, 0x49984745, 0x940E9EC0, 0x0779ED2F, + 0xDAEF34AA, 0x67255864, 0xBAB381E1, 0xC7C087B9, 0x1A565E3C, 0xA79C32F2, 0x7A0AEB77, + 0x5D7A3E42, 0x80ECE7C7, 0x3D268B09, 0xE0B0528C, 0x9DC354D4, 0x40558D51, 0xFD9FE19F, + 0x2009381A, 0xBD8D91AB, 0x601B482E, 0xDDD124E0, 0x0047FD65, 0x7D34FB3D, 0xA0A222B8, + 0x1D684E76, 0xC0FE97F3, 0xE78E42C6, 0x3A189B43, 0x87D2F78D, 0x5A442E08, 0x27372850, + 0xFAA1F1D5, 0x476B9D1B, 0x9AFD449E, 0x098A3771, 0xD41CEEF4, 0x69D6823A, 0xB4405BBF, + 0xC9335DE7, 0x14A58462, 0xA96FE8AC, 0x74F93129, 0x5389E41C, 0x8E1F3D99, 0x33D55157, + 0xEE4388D2, 0x93308E8A, 0x4EA6570F, 0xF36C3BC1, 0x2EFAE244, 0x0EF3DA5E, 0xD36503DB, + 0x6EAF6F15, 0xB339B690, 0xCE4AB0C8, 0x13DC694D, 0xAE160583, 0x7380DC06, 0x54F00933, + 0x8966D0B6, 0x34ACBC78, 0xE93A65FD, 0x944963A5, 0x49DFBA20, 0xF415D6EE, 0x29830F6B, + 0xBAF47C84, 0x6762A501, 0xDAA8C9CF, 0x073E104A, 0x7A4D1612, 0xA7DBCF97, 0x1A11A359, + 0xC7877ADC, 0xE0F7AFE9, 0x3D61766C, 0x80AB1AA2, 0x5D3DC327, 0x204EC57F, 0xFDD81CFA, + 0x40127034, 0x9D84A9B1, 0xA06A2517, 0x7DFCFC92, 0xC036905C, 0x1DA049D9, 0x60D34F81, + 0xBD459604, 0x008FFACA, 0xDD19234F, 0xFA69F67A, 0x27FF2FFF, 0x9A354331, 0x47A39AB4, + 0x3AD09CEC, 0xE7464569, 0x5A8C29A7, 0x871AF022, 0x146D83CD, 0xC9FB5A48, 0x74313686, + 0xA9A7EF03, 0xD4D4E95B, 0x094230DE, 0xB4885C10, 0x691E8595, 0x4E6E50A0, 0x93F88925, + 0x2E32E5EB, 0xF3A43C6E, 0x8ED73A36, 0x5341E3B3, 0xEE8B8F7D, 0x331D56F8, 0x13146EE2, + 0xCE82B767, 0x7348DBA9, 0xAEDE022C, 0xD3AD0474, 0x0E3BDDF1, 0xB3F1B13F, 0x6E6768BA, + 0x4917BD8F, 0x9481640A, 0x294B08C4, 0xF4DDD141, 0x89AED719, 0x54380E9C, 0xE9F26252, + 0x3464BBD7, 0xA713C838, 0x7A8511BD, 0xC74F7D73, 0x1AD9A4F6, 0x67AAA2AE, 0xBA3C7B2B, + 0x07F617E5, 0xDA60CE60, 0xFD101B55, 0x2086C2D0, 0x9D4CAE1E, 0x40DA779B, 0x3DA971C3, + 0xE03FA846, 0x5DF5C488, 0x80631D0D, 0x1DE7B4BC, 0xC0716D39, 0x7DBB01F7, 0xA02DD872, + 0xDD5EDE2A, 0x00C807AF, 0xBD026B61, 0x6094B2E4, 0x47E467D1, 0x9A72BE54, 0x27B8D29A, + 0xFA2E0B1F, 0x875D0D47, 0x5ACBD4C2, 0xE701B80C, 0x3A976189, 0xA9E01266, 0x7476CBE3, + 0xC9BCA72D, 0x142A7EA8, 0x695978F0, 0xB4CFA175, 0x0905CDBB, 0xD493143E, 0xF3E3C10B, + 0x2E75188E, 0x93BF7440, 0x4E29ADC5, 0x335AAB9D, 0xEECC7218, 0x53061ED6, 0x8E90C753, + 0xAE99FF49, 0x730F26CC, 0xCEC54A02, 0x13539387, 0x6E2095DF, 0xB3B64C5A, 0x0E7C2094, + 0xD3EAF911, 0xF49A2C24, 0x290CF5A1, 0x94C6996F, 0x495040EA, 0x342346B2, 0xE9B59F37, + 0x547FF3F9, 0x89E92A7C, 0x1A9E5993, 0xC7088016, 0x7AC2ECD8, 0xA754355D, 0xDA273305, + 0x07B1EA80, 0xBA7B864E, 0x67ED5FCB, 0x409D8AFE, 0x9D0B537B, 0x20C13FB5, 0xFD57E630, + 0x8024E068, 0x5DB239ED, 0xE0785523, 0x3DEE8CA6, + ], + [ + 0x00000000, 0x9D0FE176, 0xE16EC4AD, 0x7C6125DB, 0x19AC8F1B, 0x84A36E6D, 0xF8C24BB6, + 0x65CDAAC0, 0x33591E36, 0xAE56FF40, 0xD237DA9B, 0x4F383BED, 0x2AF5912D, 0xB7FA705B, + 0xCB9B5580, 0x5694B4F6, 0x66B23C6C, 0xFBBDDD1A, 0x87DCF8C1, 0x1AD319B7, 0x7F1EB377, + 0xE2115201, 0x9E7077DA, 0x037F96AC, 0x55EB225A, 0xC8E4C32C, 0xB485E6F7, 0x298A0781, + 0x4C47AD41, 0xD1484C37, 0xAD2969EC, 0x3026889A, 0xCD6478D8, 0x506B99AE, 0x2C0ABC75, + 0xB1055D03, 0xD4C8F7C3, 0x49C716B5, 0x35A6336E, 0xA8A9D218, 0xFE3D66EE, 0x63328798, + 0x1F53A243, 0x825C4335, 0xE791E9F5, 0x7A9E0883, 0x06FF2D58, 0x9BF0CC2E, 0xABD644B4, + 0x36D9A5C2, 0x4AB88019, 0xD7B7616F, 0xB27ACBAF, 0x2F752AD9, 0x53140F02, 0xCE1BEE74, + 0x988F5A82, 0x0580BBF4, 0x79E19E2F, 0xE4EE7F59, 0x8123D599, 0x1C2C34EF, 0x604D1134, + 0xFD42F042, 0x41B9F7F1, 0xDCB61687, 0xA0D7335C, 0x3DD8D22A, 0x581578EA, 0xC51A999C, + 0xB97BBC47, 0x24745D31, 0x72E0E9C7, 0xEFEF08B1, 0x938E2D6A, 0x0E81CC1C, 0x6B4C66DC, + 0xF64387AA, 0x8A22A271, 0x172D4307, 0x270BCB9D, 0xBA042AEB, 0xC6650F30, 0x5B6AEE46, + 0x3EA74486, 0xA3A8A5F0, 0xDFC9802B, 0x42C6615D, 0x1452D5AB, 0x895D34DD, 0xF53C1106, + 0x6833F070, 0x0DFE5AB0, 0x90F1BBC6, 0xEC909E1D, 0x719F7F6B, 0x8CDD8F29, 0x11D26E5F, + 0x6DB34B84, 0xF0BCAAF2, 0x95710032, 0x087EE144, 0x741FC49F, 0xE91025E9, 0xBF84911F, + 0x228B7069, 0x5EEA55B2, 0xC3E5B4C4, 0xA6281E04, 0x3B27FF72, 0x4746DAA9, 0xDA493BDF, + 0xEA6FB345, 0x77605233, 0x0B0177E8, 0x960E969E, 0xF3C33C5E, 0x6ECCDD28, 0x12ADF8F3, + 0x8FA21985, 0xD936AD73, 0x44394C05, 0x385869DE, 0xA55788A8, 0xC09A2268, 0x5D95C31E, + 0x21F4E6C5, 0xBCFB07B3, 0x8373EFE2, 0x1E7C0E94, 0x621D2B4F, 0xFF12CA39, 0x9ADF60F9, + 0x07D0818F, 0x7BB1A454, 0xE6BE4522, 0xB02AF1D4, 0x2D2510A2, 0x51443579, 0xCC4BD40F, + 0xA9867ECF, 0x34899FB9, 0x48E8BA62, 0xD5E75B14, 0xE5C1D38E, 0x78CE32F8, 0x04AF1723, + 0x99A0F655, 0xFC6D5C95, 0x6162BDE3, 0x1D039838, 0x800C794E, 0xD698CDB8, 0x4B972CCE, + 0x37F60915, 0xAAF9E863, 0xCF3442A3, 0x523BA3D5, 0x2E5A860E, 0xB3556778, 0x4E17973A, + 0xD318764C, 0xAF795397, 0x3276B2E1, 0x57BB1821, 0xCAB4F957, 0xB6D5DC8C, 0x2BDA3DFA, + 0x7D4E890C, 0xE041687A, 0x9C204DA1, 0x012FACD7, 0x64E20617, 0xF9EDE761, 0x858CC2BA, + 0x188323CC, 0x28A5AB56, 0xB5AA4A20, 0xC9CB6FFB, 0x54C48E8D, 0x3109244D, 0xAC06C53B, + 0xD067E0E0, 0x4D680196, 0x1BFCB560, 0x86F35416, 0xFA9271CD, 0x679D90BB, 0x02503A7B, + 0x9F5FDB0D, 0xE33EFED6, 0x7E311FA0, 0xC2CA1813, 0x5FC5F965, 0x23A4DCBE, 0xBEAB3DC8, + 0xDB669708, 0x4669767E, 0x3A0853A5, 0xA707B2D3, 0xF1930625, 0x6C9CE753, 0x10FDC288, + 0x8DF223FE, 0xE83F893E, 0x75306848, 0x09514D93, 0x945EACE5, 0xA478247F, 0x3977C509, + 0x4516E0D2, 0xD81901A4, 0xBDD4AB64, 0x20DB4A12, 0x5CBA6FC9, 0xC1B58EBF, 0x97213A49, + 0x0A2EDB3F, 0x764FFEE4, 0xEB401F92, 0x8E8DB552, 0x13825424, 0x6FE371FF, 0xF2EC9089, + 0x0FAE60CB, 0x92A181BD, 0xEEC0A466, 0x73CF4510, 0x1602EFD0, 0x8B0D0EA6, 0xF76C2B7D, + 0x6A63CA0B, 0x3CF77EFD, 0xA1F89F8B, 0xDD99BA50, 0x40965B26, 0x255BF1E6, 0xB8541090, + 0xC435354B, 0x593AD43D, 0x691C5CA7, 0xF413BDD1, 0x8872980A, 0x157D797C, 0x70B0D3BC, + 0xEDBF32CA, 0x91DE1711, 0x0CD1F667, 0x5A454291, 0xC74AA3E7, 0xBB2B863C, 0x2624674A, + 0x43E9CD8A, 0xDEE62CFC, 0xA2870927, 0x3F88E851, + ], + [ + 0x00000000, 0xB9FBDBE8, 0xA886B191, 0x117D6A79, 0x8A7C6563, 0x3387BE8B, 0x22FAD4F2, + 0x9B010F1A, 0xCF89CC87, 0x7672176F, 0x670F7D16, 0xDEF4A6FE, 0x45F5A9E4, 0xFC0E720C, + 0xED731875, 0x5488C39D, 0x44629F4F, 0xFD9944A7, 0xECE42EDE, 0x551FF536, 0xCE1EFA2C, + 0x77E521C4, 0x66984BBD, 0xDF639055, 0x8BEB53C8, 0x32108820, 0x236DE259, 0x9A9639B1, + 0x019736AB, 0xB86CED43, 0xA911873A, 0x10EA5CD2, 0x88C53E9E, 0x313EE576, 0x20438F0F, + 0x99B854E7, 0x02B95BFD, 0xBB428015, 0xAA3FEA6C, 0x13C43184, 0x474CF219, 0xFEB729F1, + 0xEFCA4388, 0x56319860, 0xCD30977A, 0x74CB4C92, 0x65B626EB, 0xDC4DFD03, 0xCCA7A1D1, + 0x755C7A39, 0x64211040, 0xDDDACBA8, 0x46DBC4B2, 0xFF201F5A, 0xEE5D7523, 0x57A6AECB, + 0x032E6D56, 0xBAD5B6BE, 0xABA8DCC7, 0x1253072F, 0x89520835, 0x30A9D3DD, 0x21D4B9A4, + 0x982F624C, 0xCAFB7B7D, 0x7300A095, 0x627DCAEC, 0xDB861104, 0x40871E1E, 0xF97CC5F6, + 0xE801AF8F, 0x51FA7467, 0x0572B7FA, 0xBC896C12, 0xADF4066B, 0x140FDD83, 0x8F0ED299, + 0x36F50971, 0x27886308, 0x9E73B8E0, 0x8E99E432, 0x37623FDA, 0x261F55A3, 0x9FE48E4B, + 0x04E58151, 0xBD1E5AB9, 0xAC6330C0, 0x1598EB28, 0x411028B5, 0xF8EBF35D, 0xE9969924, + 0x506D42CC, 0xCB6C4DD6, 0x7297963E, 0x63EAFC47, 0xDA1127AF, 0x423E45E3, 0xFBC59E0B, + 0xEAB8F472, 0x53432F9A, 0xC8422080, 0x71B9FB68, 0x60C49111, 0xD93F4AF9, 0x8DB78964, + 0x344C528C, 0x253138F5, 0x9CCAE31D, 0x07CBEC07, 0xBE3037EF, 0xAF4D5D96, 0x16B6867E, + 0x065CDAAC, 0xBFA70144, 0xAEDA6B3D, 0x1721B0D5, 0x8C20BFCF, 0x35DB6427, 0x24A60E5E, + 0x9D5DD5B6, 0xC9D5162B, 0x702ECDC3, 0x6153A7BA, 0xD8A87C52, 0x43A97348, 0xFA52A8A0, + 0xEB2FC2D9, 0x52D41931, 0x4E87F0BB, 0xF77C2B53, 0xE601412A, 0x5FFA9AC2, 0xC4FB95D8, + 0x7D004E30, 0x6C7D2449, 0xD586FFA1, 0x810E3C3C, 0x38F5E7D4, 0x29888DAD, 0x90735645, + 0x0B72595F, 0xB28982B7, 0xA3F4E8CE, 0x1A0F3326, 0x0AE56FF4, 0xB31EB41C, 0xA263DE65, + 0x1B98058D, 0x80990A97, 0x3962D17F, 0x281FBB06, 0x91E460EE, 0xC56CA373, 0x7C97789B, + 0x6DEA12E2, 0xD411C90A, 0x4F10C610, 0xF6EB1DF8, 0xE7967781, 0x5E6DAC69, 0xC642CE25, + 0x7FB915CD, 0x6EC47FB4, 0xD73FA45C, 0x4C3EAB46, 0xF5C570AE, 0xE4B81AD7, 0x5D43C13F, + 0x09CB02A2, 0xB030D94A, 0xA14DB333, 0x18B668DB, 0x83B767C1, 0x3A4CBC29, 0x2B31D650, + 0x92CA0DB8, 0x8220516A, 0x3BDB8A82, 0x2AA6E0FB, 0x935D3B13, 0x085C3409, 0xB1A7EFE1, + 0xA0DA8598, 0x19215E70, 0x4DA99DED, 0xF4524605, 0xE52F2C7C, 0x5CD4F794, 0xC7D5F88E, + 0x7E2E2366, 0x6F53491F, 0xD6A892F7, 0x847C8BC6, 0x3D87502E, 0x2CFA3A57, 0x9501E1BF, + 0x0E00EEA5, 0xB7FB354D, 0xA6865F34, 0x1F7D84DC, 0x4BF54741, 0xF20E9CA9, 0xE373F6D0, + 0x5A882D38, 0xC1892222, 0x7872F9CA, 0x690F93B3, 0xD0F4485B, 0xC01E1489, 0x79E5CF61, + 0x6898A518, 0xD1637EF0, 0x4A6271EA, 0xF399AA02, 0xE2E4C07B, 0x5B1F1B93, 0x0F97D80E, + 0xB66C03E6, 0xA711699F, 0x1EEAB277, 0x85EBBD6D, 0x3C106685, 0x2D6D0CFC, 0x9496D714, + 0x0CB9B558, 0xB5426EB0, 0xA43F04C9, 0x1DC4DF21, 0x86C5D03B, 0x3F3E0BD3, 0x2E4361AA, + 0x97B8BA42, 0xC33079DF, 0x7ACBA237, 0x6BB6C84E, 0xD24D13A6, 0x494C1CBC, 0xF0B7C754, + 0xE1CAAD2D, 0x583176C5, 0x48DB2A17, 0xF120F1FF, 0xE05D9B86, 0x59A6406E, 0xC2A74F74, + 0x7B5C949C, 0x6A21FEE5, 0xD3DA250D, 0x8752E690, 0x3EA93D78, 0x2FD45701, 0x962F8CE9, + 0x0D2E83F3, 0xB4D5581B, 0xA5A83262, 0x1C53E98A, + ], + [ + 0x00000000, 0xAE689191, 0x87A02563, 0x29C8B4F2, 0xD4314C87, 0x7A59DD16, 0x539169E4, + 0xFDF9F875, 0x73139F4F, 0xDD7B0EDE, 0xF4B3BA2C, 0x5ADB2BBD, 0xA722D3C8, 0x094A4259, + 0x2082F6AB, 0x8EEA673A, 0xE6273E9E, 0x484FAF0F, 0x61871BFD, 0xCFEF8A6C, 0x32167219, + 0x9C7EE388, 0xB5B6577A, 0x1BDEC6EB, 0x9534A1D1, 0x3B5C3040, 0x129484B2, 0xBCFC1523, + 0x4105ED56, 0xEF6D7CC7, 0xC6A5C835, 0x68CD59A4, 0x173F7B7D, 0xB957EAEC, 0x909F5E1E, + 0x3EF7CF8F, 0xC30E37FA, 0x6D66A66B, 0x44AE1299, 0xEAC68308, 0x642CE432, 0xCA4475A3, + 0xE38CC151, 0x4DE450C0, 0xB01DA8B5, 0x1E753924, 0x37BD8DD6, 0x99D51C47, 0xF11845E3, + 0x5F70D472, 0x76B86080, 0xD8D0F111, 0x25290964, 0x8B4198F5, 0xA2892C07, 0x0CE1BD96, + 0x820BDAAC, 0x2C634B3D, 0x05ABFFCF, 0xABC36E5E, 0x563A962B, 0xF85207BA, 0xD19AB348, + 0x7FF222D9, 0x2E7EF6FA, 0x8016676B, 0xA9DED399, 0x07B64208, 0xFA4FBA7D, 0x54272BEC, + 0x7DEF9F1E, 0xD3870E8F, 0x5D6D69B5, 0xF305F824, 0xDACD4CD6, 0x74A5DD47, 0x895C2532, + 0x2734B4A3, 0x0EFC0051, 0xA09491C0, 0xC859C864, 0x663159F5, 0x4FF9ED07, 0xE1917C96, + 0x1C6884E3, 0xB2001572, 0x9BC8A180, 0x35A03011, 0xBB4A572B, 0x1522C6BA, 0x3CEA7248, + 0x9282E3D9, 0x6F7B1BAC, 0xC1138A3D, 0xE8DB3ECF, 0x46B3AF5E, 0x39418D87, 0x97291C16, + 0xBEE1A8E4, 0x10893975, 0xED70C100, 0x43185091, 0x6AD0E463, 0xC4B875F2, 0x4A5212C8, + 0xE43A8359, 0xCDF237AB, 0x639AA63A, 0x9E635E4F, 0x300BCFDE, 0x19C37B2C, 0xB7ABEABD, + 0xDF66B319, 0x710E2288, 0x58C6967A, 0xF6AE07EB, 0x0B57FF9E, 0xA53F6E0F, 0x8CF7DAFD, + 0x229F4B6C, 0xAC752C56, 0x021DBDC7, 0x2BD50935, 0x85BD98A4, 0x784460D1, 0xD62CF140, + 0xFFE445B2, 0x518CD423, 0x5CFDEDF4, 0xF2957C65, 0xDB5DC897, 0x75355906, 0x88CCA173, + 0x26A430E2, 0x0F6C8410, 0xA1041581, 0x2FEE72BB, 0x8186E32A, 0xA84E57D8, 0x0626C649, + 0xFBDF3E3C, 0x55B7AFAD, 0x7C7F1B5F, 0xD2178ACE, 0xBADAD36A, 0x14B242FB, 0x3D7AF609, + 0x93126798, 0x6EEB9FED, 0xC0830E7C, 0xE94BBA8E, 0x47232B1F, 0xC9C94C25, 0x67A1DDB4, + 0x4E696946, 0xE001F8D7, 0x1DF800A2, 0xB3909133, 0x9A5825C1, 0x3430B450, 0x4BC29689, + 0xE5AA0718, 0xCC62B3EA, 0x620A227B, 0x9FF3DA0E, 0x319B4B9F, 0x1853FF6D, 0xB63B6EFC, + 0x38D109C6, 0x96B99857, 0xBF712CA5, 0x1119BD34, 0xECE04541, 0x4288D4D0, 0x6B406022, + 0xC528F1B3, 0xADE5A817, 0x038D3986, 0x2A458D74, 0x842D1CE5, 0x79D4E490, 0xD7BC7501, + 0xFE74C1F3, 0x501C5062, 0xDEF63758, 0x709EA6C9, 0x5956123B, 0xF73E83AA, 0x0AC77BDF, + 0xA4AFEA4E, 0x8D675EBC, 0x230FCF2D, 0x72831B0E, 0xDCEB8A9F, 0xF5233E6D, 0x5B4BAFFC, + 0xA6B25789, 0x08DAC618, 0x211272EA, 0x8F7AE37B, 0x01908441, 0xAFF815D0, 0x8630A122, + 0x285830B3, 0xD5A1C8C6, 0x7BC95957, 0x5201EDA5, 0xFC697C34, 0x94A42590, 0x3ACCB401, + 0x130400F3, 0xBD6C9162, 0x40956917, 0xEEFDF886, 0xC7354C74, 0x695DDDE5, 0xE7B7BADF, + 0x49DF2B4E, 0x60179FBC, 0xCE7F0E2D, 0x3386F658, 0x9DEE67C9, 0xB426D33B, 0x1A4E42AA, + 0x65BC6073, 0xCBD4F1E2, 0xE21C4510, 0x4C74D481, 0xB18D2CF4, 0x1FE5BD65, 0x362D0997, + 0x98459806, 0x16AFFF3C, 0xB8C76EAD, 0x910FDA5F, 0x3F674BCE, 0xC29EB3BB, 0x6CF6222A, + 0x453E96D8, 0xEB560749, 0x839B5EED, 0x2DF3CF7C, 0x043B7B8E, 0xAA53EA1F, 0x57AA126A, + 0xF9C283FB, 0xD00A3709, 0x7E62A698, 0xF088C1A2, 0x5EE05033, 0x7728E4C1, 0xD9407550, + 0x24B98D25, 0x8AD11CB4, 0xA319A846, 0x0D7139D7, + ], +]; diff --git a/third_party/rust/image/.cargo-checksum.json b/third_party/rust/image/.cargo-checksum.json index ea276b2db1bb..62af1d9ef9c9 100644 --- a/third_party/rust/image/.cargo-checksum.json +++ b/third_party/rust/image/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"CHANGES.md":"57cd46de14af5277954df2d56b141fb8fd7eff75a026e11805281c167df13013","Cargo.toml":"42a0083afb5bffbcfde1f58caac0c9afe9642784afff80fdc5eefc3657c8abb1","LICENSE":"c7766d2e29f88a4be81b6ac6216c62d2d0918c7d3f2fc98be6fecac8f6595e60","README.md":"387f486de9a191fde35fd2ed93390824dd3f6b86b4971071a229ab9c4c4b82fc","benches/encode_jpeg.rs":"614f7ff101d8737fec76db00520d86d7a30cc4e1482e30c0414bfac868373427","benches/load.rs":"b50384f027734a1b6df6612f56b70ba95978138eb0d3894a8b8dbe0748d984bd","docs/2019-04-23-memory-unsafety.md":"b59a9af84bdb5efa1bc1f33c8aa22ff42590701817fb03f55ca2dd50af91bb8d","release.sh":"70f8d6272ab65f5ca80ac95e6ceeeb5041f9c183c87a1fdac2b7f2d16e0827d4","src/animation.rs":"c4bcc97aac7d929162e7d1e782ef4e20f3df72a891893ac68d8cda3b7aa431b3","src/bmp/decoder.rs":"f1abbda7c984122d990e1509cbdd6b1d488a49845662dc74815587f7befb302a","src/bmp/encoder.rs":"60b0ad7f086eead46799d78dd10fc7f1a27c6385d6a6c4ee2afd533e6ad1418f","src/bmp/mod.rs":"7105812c5bc077c8619359b6201110feeccec20b01f29a8f84aaef02be9b87d4","src/buffer.rs":"2e5a7d983794e71068f065a801b5483106fcf51fd74487ddd0c3f76a97f49ea0","src/color.rs":"6dde85a7fbc44d536bf7648fe1172277c6e9e3fbcd514df9bd53f277a10f85db","src/dxt.rs":"e17eef3e9abf53e89abb3a62264fb830639f2a63e48098d54e6e052b00e57342","src/dynimage.rs":"a9f598bf40bec92230dd5226cee87685d55dbb0053a54593c7083d7a394139d1","src/flat.rs":"01fd4f5a777d1e292b6f2a6a25cbac0d40ab8317898097caa32b28ba27d9baaf","src/gif.rs":"99df3010c731b6ad6f6a77a63c3b6071a801f4e171bbe01717fa273212f4767e","src/hdr/hdr_decoder.rs":"3ec4b069be9bfb43a646d9f6f13586fed93b47ac70c7fdb51ec36ef4199ecbd3","src/hdr/hdr_encoder.rs":"ed0d1845b1414bcdec641f2e158a364c04b717d41662ef40adb63bd32762c56f","src/hdr/mod.rs":"72f33fe6479cf4ce87765715c896bf0374bd2f4e0f98f50a63e084c0ff313ea8","src/ico/decoder.rs":"e3ea1fb1ff41b8cff58dd260902e8061cf6b44ca8721a68f76dce6a66ea4be19","src/ico/encoder.rs":"be5c290922c2fa91a174e22a221fce7730a1696e31c8a6e7dd45950afd63c80d","src/ico/mod.rs":"d94e6878c79c97eb9d9f9f9f9fb479ec8ccc1c8e788030ebe3b045ed44c0be5c","src/image.rs":"508dead9a324042c5307362ed246865bf5436391369a2e13d0192bd4949ab894","src/imageops/affine.rs":"46835b6c6eee3542f893789927053399a8d173a69c38685a48bfa632bd417140","src/imageops/colorops.rs":"5bff8d20a280793d0510d2e04f47f81b6b2be13a363cefe18264db0e1e3f6554","src/imageops/mod.rs":"148553f9ed42f256b1c59f61686fe247e560e5253d64492813ad2670f39223af","src/imageops/sample.rs":"4de9f0ab52459d446fe289c3e962d577c9b7019f85fd3ffd325c76d634256675","src/jpeg/decoder.rs":"9a3aa05db5d652901428a64e912670443a5c98843695394795e173cfb4a13549","src/jpeg/encoder.rs":"6ec6f205dbbb869ed3858a1c2e82b468d1b9341243f23c81ffbdcfcd79debd07","src/jpeg/entropy.rs":"31856ebc9b8647552e3ebe50f6c0608dadb181e75f8ce502395e6a713c12ad25","src/jpeg/mod.rs":"14a2ee879f88d27aca68a59d6b29112c66e1d61eaf9cad80ff73beabe1c092fe","src/jpeg/transform.rs":"c28670debd1cb6576c190495c64fa30610a2c29db65a2d3be3f625439df87031","src/lib.rs":"46dd648fab4da71d963552769325b03f10a2202780e2d6a2e23dbbdd960acaa7","src/math/mod.rs":"36b79d81c9192a3ec1e6107762623e1e7572d50825472ab824ab5d7b199e9380","src/math/nq.rs":"c6d25ac0f19db5d75668e0448df3580ddf0028261eb81517cc8c0acfaa0616cd","src/math/utils.rs":"2ae7ac728c6831559da97ed31d133cad81b3b5fe64998829b5579f34330a548e","src/png.rs":"2d356edc8d70670b72e712decb7b3e79c019f7ff8ef681acd579bcb311780d4c","src/pnm/autobreak.rs":"811445935b9217232af805a9f5521c2471b4397b804c0a5a2a87bb3240fcee96","src/pnm/decoder.rs":"c171eaaebfcfe760ba54dd3d61e62546cb114357672319e15344f4b8b2d6e700","src/pnm/encoder.rs":"d0980927546841d604b4f8dee06bd433b6a99cef3a6cdd721e819228805d00f5","src/pnm/header.rs":"42cf54d491095a4c5af706f6d67904387239f50430b167a12da74e2513c35065","src/pnm/mod.rs":"addb907337e7ef24c47de251b46ccafc9ea1f6d34f4141e14cf6da2481740fb6","src/tga/decoder.rs":"f021616befc9edf5d8f2d4912e296d5bc4f954b1f68c9f51d2d01a4288ddcbec","src/tga/mod.rs":"0a8001c03350156fad3ed9aefb3b3fb2a9112414cce2a0b31070cb1859ef2548","src/tiff.rs":"60297f928ad4ad94b2b57bb1c0b5800de8af9549fae6090f82a15ac995ce40b7","src/traits.rs":"58a12b0ddd1d7386447693d682a1df771e29263daeb5c27ad8829462ef3d1423","src/utils/mod.rs":"b1a3573f429d5bbe4ef13128152808a47f0e91602331f63ea65638edb29d9ed8","src/webp/decoder.rs":"963cea7fe4732ca74e8fa06b8fe32192158917664d2f2f7fd61fb160f42e7daf","src/webp/mod.rs":"f06f5e78091f7a0913fb5cd74d4880a71754ac4f33ee34f502474154be0af27a","src/webp/transform.rs":"f4eb9230045bc5bc277f0bd686014646716c2ebcb126f7d51b9fac622076517a","src/webp/vp8.rs":"d4f82d581ff1f689f46db1e662654577d99ef7e436273d6b07b9004bd50b09a7"},"package":"293e54ce142a936a39da748ba8178ae6aa1914b82d846a4278f11590c89bf116"} \ No newline at end of file +{"files":{"CHANGES.md":"c791f6ca0016110889db58e22a8a7a0f38fec9c1e4f5066c2367a7c240324dc6","Cargo.toml":"706b43137bd0e8115d6dce2bf140ecd658a7c1cacc7849c7d80583f890c79642","LICENSE":"c7766d2e29f88a4be81b6ac6216c62d2d0918c7d3f2fc98be6fecac8f6595e60","README.md":"ad289be7955af45c631d8f398fb0d6e22c5bf81bfc8ce2e46d6c67a5128b1e28","benches/README.md":"87b2ea4d1cea80c1e24fc18f1222a7ee1a38f5a92e98110bb84a4827fb997b62","benches/encode_jpeg.rs":"614f7ff101d8737fec76db00520d86d7a30cc4e1482e30c0414bfac868373427","benches/load.rs":"b50384f027734a1b6df6612f56b70ba95978138eb0d3894a8b8dbe0748d984bd","docs/2019-04-23-memory-unsafety.md":"b59a9af84bdb5efa1bc1f33c8aa22ff42590701817fb03f55ca2dd50af91bb8d","release.sh":"70f8d6272ab65f5ca80ac95e6ceeeb5041f9c183c87a1fdac2b7f2d16e0827d4","src/animation.rs":"9afe0c9ee5de50c35f075839ecde79ad8be95627c8efbe68b5a69028a4061908","src/bmp/decoder.rs":"6a6ae94414e9fcc874041c29922ce11d27f840a2281e905babc9d0c15859cb9f","src/bmp/encoder.rs":"f97c6e0dc9c9404bd5191821d30f08410416a5a7cf516682de83888f3052e828","src/bmp/mod.rs":"7105812c5bc077c8619359b6201110feeccec20b01f29a8f84aaef02be9b87d4","src/buffer.rs":"bfd76adf1770ec544d9aecba1990fca8cc32b31de9e4b78eb717f47b0f93a60c","src/color.rs":"d43f63f8e38a356cbc45677e4cfc7043bbd9b0904883ce4792ab0267fdc64179","src/dxt.rs":"c887e91615dadff094f1e1f1d746b85366f704581e384febddd98be983aabbee","src/dynimage.rs":"353e4238e64671a6dffafa32be38cfe90fadb05e3b8b88a4696b5cc532bad827","src/flat.rs":"3fed74ddb298336f36337f789d11934cf9aad25615133f3b5c21f59fc61b34f2","src/gif.rs":"96d258a24f87a039b1447d647945e41c1eeedbc3b6c631edc001962c65da722a","src/hdr/decoder.rs":"c9ca526389b6f045cf7a46af0aeb34f114ebf985ca271a6b30b5a2387382d121","src/hdr/encoder.rs":"0555eed8ea351ad73a9af349f990311d660f35f4f46719d01b88fad41942f2e8","src/hdr/mod.rs":"96eb63b7e43f117cb46b8ffe705b477426dde75881f2dea63cab29ffd820e01d","src/ico/decoder.rs":"07fccb6e968e6821cda9ef1e9af77c4fbf969030fdd76dab516eb67462dc321e","src/ico/encoder.rs":"941b226433b25399e51ed4b9204e896b4a1cad6552cbd44c60b2b6d97627e52c","src/ico/mod.rs":"d94e6878c79c97eb9d9f9f9f9fb479ec8ccc1c8e788030ebe3b045ed44c0be5c","src/image.rs":"70192ee57a9daff27041c25ef32f8f911d0e4d7e40751e361b3eac80ed989431","src/imageops/affine.rs":"74ecc183bd739eb3168122613d245dd939770b8328a5e9e0737f0c24640f49c6","src/imageops/colorops.rs":"cd58e6553f3da0790e1cb406e50da0400658843440bbb47d016daf1965018b7f","src/imageops/mod.rs":"3856c7917c2a3805f1aced1f499da6b121b4ccb08f2b7a66eda5592641c06c2e","src/imageops/sample.rs":"8d746c4cedec21e249dab3585bd61c0e475a88e0917fea9378c36d4afddeb9aa","src/jpeg/decoder.rs":"df206c5bae9c39fd34dc41d304e5dc29df0d581ba7ed47f8604c3b7a756573c3","src/jpeg/encoder.rs":"66c28cfc9abca2db71f76016934c533d2843b2dfc64a3cb92d23d5bec417702b","src/jpeg/entropy.rs":"31856ebc9b8647552e3ebe50f6c0608dadb181e75f8ce502395e6a713c12ad25","src/jpeg/mod.rs":"14a2ee879f88d27aca68a59d6b29112c66e1d61eaf9cad80ff73beabe1c092fe","src/jpeg/transform.rs":"c28670debd1cb6576c190495c64fa30610a2c29db65a2d3be3f625439df87031","src/lib.rs":"1d0073935d587f57c0485208bac5e37333e66838cf09699d0ea42afe3e2beac0","src/math/mod.rs":"36b79d81c9192a3ec1e6107762623e1e7572d50825472ab824ab5d7b199e9380","src/math/nq.rs":"a3fe77839826ca1d446f496f53e33d081a623a248c087f1a08b8afb1eca4bcda","src/math/utils.rs":"2ae7ac728c6831559da97ed31d133cad81b3b5fe64998829b5579f34330a548e","src/png.rs":"5ba453410ada2026bcf935426639b93356f6e4b7edd2b8acd6a42c5770955eb6","src/pnm/autobreak.rs":"811445935b9217232af805a9f5521c2471b4397b804c0a5a2a87bb3240fcee96","src/pnm/decoder.rs":"25ac23fc8e67ea42d479a103e3cda1b51a4421950be9ee2c11eeec17552081c8","src/pnm/encoder.rs":"c87dc870e15515ff9ffcd003310904f303ba416fef72352e2a314357c4cae96a","src/pnm/header.rs":"81a0cf72c3b113b490054f4f2201b448cbb1fed63fc1354e457a94294bf3761f","src/pnm/mod.rs":"74ec15ee6d92dec08e7d0870bf31ad3c30687b2c52f74abdeb4bf127f3afda23","src/tga/decoder.rs":"f05fa02aba31bc5b423644be31f1c8b874e6557b8db211bc837d07dcee455bca","src/tga/mod.rs":"0a8001c03350156fad3ed9aefb3b3fb2a9112414cce2a0b31070cb1859ef2548","src/tiff.rs":"5fb6019db0ffbbad6a2c2aa083dd31514917885a030cd9aed8e89322aac6ef5f","src/traits.rs":"58a12b0ddd1d7386447693d682a1df771e29263daeb5c27ad8829462ef3d1423","src/utils/mod.rs":"5a9d379f45d6d626d63e6839f93cd41ed33d67186b205fe3a574a956b52dc4e7","src/webp/decoder.rs":"82666a293692c3043e3bcf6ab988e470f6b2f9cedf0b6b1202bb974d4ebbeddc","src/webp/mod.rs":"f06f5e78091f7a0913fb5cd74d4880a71754ac4f33ee34f502474154be0af27a","src/webp/transform.rs":"9772d4a3172122200482e09d763e554f41d8de8ab629f94c10d64ccac038faa1","src/webp/vp8.rs":"2d1f4522ceb43d541462030b2125e637a9b63ccc0205af5cfbb2f60cc879433e"},"package":"663a975007e0b49903e2e8ac0db2c432c465855f2d65f17883ba1476e85f0b42"} \ No newline at end of file diff --git a/third_party/rust/image/CHANGES.md b/third_party/rust/image/CHANGES.md index 840de4668ce4..2bb8629a1ebb 100644 --- a/third_party/rust/image/CHANGES.md +++ b/third_party/rust/image/CHANGES.md @@ -8,6 +8,41 @@ Rust image aims to be a pure-Rust implementation of various popular image format ## Changes +### Version 0.22 + +- The required Rust version is now `1.34.2`. +- Note the website and blog: [image-rs.org][1] and [blog.image-rs.org][2] +- `PixelMut` now only on `ImageBuffer` and removed from `GenericImage` + interface. Prefer iterating manually in the generic case. +- Replaced an unsafe interface in the hdr decoder with a safe variant. +- Support loading 2-bit BMP images +- Add method to save an `ImageBuffer`/`DynamicImage` with specified format +- Update tiff to `0.3` with a writer +- Update png to `0.15`, fixes reading of interlaced sub-byte pixels +- Always use custom struct for `ImageDecoder::Reader` +- Added `apply_without_alpha` and `map_without_alpha` to `Pixel` trait +- Pixel information now with associated constants instead of static methods +- Changed color structs to tuple types with single component. Improves + ergonomics of destructuring assignment and construction. +- Add lifetime parameter on `ImageDecoder` trait. +- Remove unecessary `'static` bounds on affine operations +- Add function to retrieve image dimensions without loading full image +- Allow different image types in overlay and replace +- Iterators over rows of `ImageBuffer`, mutable variants + +[1]: https://www.image-rs.org +[2]: https://blog.image-rs.org + +### Version 0.21.2 + +- Fixed a variety of crashes and opaque errors in webp +- Updated the png limits to be less restrictive +- Reworked even more `unsafe` operations into safe alternatives +- Derived Debug on FilterType and Deref on Pixel +- Removed a restriction on DXT to always require power of two dimensions +- Change the encoding of RGBA in bmp using bitfields +- Corrected various urls + ### Version 0.21.1 - A fairly important bugfix backport diff --git a/third_party/rust/image/Cargo.toml b/third_party/rust/image/Cargo.toml index 38ed87e85306..42e3db6b0d9b 100644 --- a/third_party/rust/image/Cargo.toml +++ b/third_party/rust/image/Cargo.toml @@ -3,7 +3,7 @@ # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g. crates.io) dependencies +# to registry (e.g., crates.io) dependencies # # If you believe there's an error in this file please file an # issue against the rust-lang/cargo repository. If you're @@ -12,16 +12,16 @@ [package] name = "image" -version = "0.21.1" +version = "0.22.1" authors = ["ccgn", "bvssvni ", "nwin", "TyOverby ", "HeroicKatora", "Calum", "CensoredUsername ", "fintelia "] exclude = ["src/png/testdata/*", "examples/*", "tests/*"] description = "Imaging library written in Rust. Provides basic filters and decoders for the most common image formats." -homepage = "https://github.com/PistonDevelopers/image" +homepage = "https://github.com/image-rs/image" documentation = "https://docs.rs/image" readme = "README.md" categories = ["multimedia::images", "multimedia::encoding"] license = "MIT" -repository = "https://github.com/PistonDevelopers/image.git" +repository = "https://github.com/image-rs/image.git" [lib] name = "image" @@ -52,7 +52,7 @@ default-features = false version = "0.2.0" [dependencies.png] -version = "0.14" +version = "0.15" optional = true [dependencies.scoped_threadpool] @@ -60,10 +60,13 @@ version = "0.1" optional = true [dependencies.tiff] -version = "0.2.0" +version = "0.3.1" optional = true +[dev-dependencies.crc32fast] +version = "1.2.0" + [dev-dependencies.glob] -version = "0.2.10" +version = "0.3" [dev-dependencies.num-complex] version = "0.2.0" diff --git a/third_party/rust/image/README.md b/third_party/rust/image/README.md index 86f6e56564db..62fcf6727714 100644 --- a/third_party/rust/image/README.md +++ b/third_party/rust/image/README.md @@ -1,8 +1,8 @@ -# Image [![Build Status](https://travis-ci.org/PistonDevelopers/image.svg?branch=master)](https://travis-ci.org/PistonDevelopers/image) +# Image [![crates.io](https://img.shields.io/crates/v/image.svg)](https://crates.io/crates/image) [![Build Status](https://travis-ci.org/image-rs/image.svg?branch=master)](https://travis-ci.org/image-rs/image) [![Gitter](https://badges.gitter.im/image-rs/image.svg)](https://gitter.im/image-rs/image?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) Maintainers: @nwin, @ccgn -[How to contribute](https://github.com/PistonDevelopers/piston/blob/master/CONTRIBUTING.md) +[How to contribute](https://github.com/image-rs/organization/blob/master/CONTRIBUTING.md) ## An Image Processing Library @@ -10,23 +10,6 @@ This crate provides basic imaging processing functions and methods for convertin All image processing functions provided operate on types that implement the ```GenericImage``` trait and return an ```ImageBuffer```. -### Usage - -Add the following to the Cargo.toml in your project: - -```toml -[dependencies] -image = "*" -``` - -and import using ```extern crate```: - -```rust -extern crate image; - -// use image:: -``` - ## 1. Documentation https://docs.rs/image @@ -42,7 +25,7 @@ https://docs.rs/image | GIF | Yes | Yes | | BMP | Yes | RGB(8), RGBA(8), Gray(8), GrayA(8) | | ICO | Yes | Yes | -| TIFF | Baseline(no fax support) + LZW + PackBits | No | +| TIFF | Baseline(no fax support) + LZW + PackBits | RGB(8), RGBA(8), Gray(8) | | Webp | Lossy(Luma channel only) | No | | PNM | PBM, PGM, PPM, standard PAM | Yes | @@ -69,6 +52,7 @@ All pixels are parameterised by their component type. A trait that provides functions for manipulating images, parameterised over the image's pixel type. ```rust +# use image::{Pixel, Pixels}; pub trait GenericImage { /// The pixel type. type Pixel: Pixel; @@ -101,13 +85,13 @@ An image parameterised by its Pixel types, represented by a width and height and ```rust extern crate image; -use image::{GenericImage, ImageBuffer}; +use image::{GenericImage, GenericImageView, ImageBuffer, RgbImage}; -// Construct a new ImageBuffer with the specified width and height. -let img = ImageBuffer::new(512, 512); +// Construct a new RGB ImageBuffer with the specified width and height. +let img: RgbImage = ImageBuffer::new(512, 512); // Construct a new by repeated calls to the supplied closure. -let img = ImageBuffer::from_fn(512, 512, |x, y| { +let mut img = ImageBuffer::from_fn(512, 512, |x, y| { if x % 2 == 0 { image::Luma([0u8]) } else { @@ -122,7 +106,7 @@ let (width, height) = img.dimensions(); let pixel = img[(100, 100)]; // Or use the ```get_pixel``` method from the ```GenericImage``` trait. -let pixel = img.get_pixel(100, 100); +let pixel = *img.get_pixel(100, 100); // Put a pixel at coordinate (100, 100). img.put_pixel(100, 100, pixel); @@ -147,10 +131,10 @@ This is used to perform image processing functions on a subregion of an image. ```rust extern crate image; -use image::{GenericImage, ImageBuffer, imageops}; +use image::{GenericImageView, ImageBuffer, RgbImage, imageops}; -let ref mut img = ImageBuffer::new(512, 512); -let subimg = imageops::crop(img, 0, 0, 100, 100); +let mut img: RgbImage = ImageBuffer::new(512, 512); +let subimg = imageops::crop(&mut img, 0, 0, 100, 100); assert!(subimg.dimensions() == (100, 100)); ``` @@ -180,7 +164,7 @@ These are the functions defined in the ```imageops``` module. All functions oper The image format is determined from the path's file extension. -```rust +```rust,no_run extern crate image; use image::GenericImageView; @@ -188,7 +172,7 @@ use image::GenericImageView; fn main() { // Use the open function to load an image from a Path. // ```open``` returns a `DynamicImage` on success. - let img = image::open("test.jpg").unwrap(); + let img = image::open("tests/images/jpg/progressive/cat.jpg").unwrap(); // The dimensions method returns the images width and height. println!("dimensions {:?}", img.dimensions()); @@ -202,7 +186,7 @@ fn main() { ``` ### 6.2 Generating Fractals -```rust +```rust,no_run //! An example of generating julia fractals. extern crate image; extern crate num_complex; @@ -240,7 +224,7 @@ fn main() { } let pixel = imgbuf.get_pixel_mut(x, y); - let data = (*pixel as image::Rgb).data; + let image::Rgb(data) = *pixel; *pixel = image::Rgb([data[0], i as u8, data[2]]); } } @@ -257,12 +241,12 @@ Example output: ### 6.3 Writing raw buffers If the high level interface is not needed because the image was obtained by other means, `image` provides the function `save_buffer` to save a buffer to a file. -```rust +```rust,no_run extern crate image; fn main() { - let buffer: &[u8] = ...; // Generate the image data + let buffer: &[u8] = unimplemented!(); // Generate the image data // Save the buffer as "image.png" image::save_buffer("image.png", buffer, 800, 600, image::RGB(8)).unwrap() diff --git a/third_party/rust/image/benches/README.md b/third_party/rust/image/benches/README.md new file mode 100644 index 000000000000..9516f2cb626c --- /dev/null +++ b/third_party/rust/image/benches/README.md @@ -0,0 +1,6 @@ +# Getting started with benchmarking + +To run the benchmarks you need a nightly rust toolchain. +Then you launch it with + + cargo +nightly bench --features=benchmarks diff --git a/third_party/rust/image/src/animation.rs b/third_party/rust/image/src/animation.rs index 6072d68b2409..50e4be531cd9 100644 --- a/third_party/rust/image/src/animation.rs +++ b/third_party/rust/image/src/animation.rs @@ -7,12 +7,12 @@ use image::ImageResult; /// An implementation dependent iterator, reading the frames as requested pub struct Frames<'a> { - iterator: Box> + 'a> + iterator: Box> + 'a> } impl<'a> Frames<'a> { /// Creates a new `Frames` from an implementation specific iterator. - pub fn new(iterator: Box> + 'a>) -> Self { + pub fn new(iterator: Box> + 'a>) -> Self { Frames { iterator } } diff --git a/third_party/rust/image/src/bmp/decoder.rs b/third_party/rust/image/src/bmp/decoder.rs index 008b6c28a6f3..38f73407033d 100644 --- a/third_party/rust/image/src/bmp/decoder.rs +++ b/third_party/rust/image/src/bmp/decoder.rs @@ -1,7 +1,7 @@ -use std::cmp; -use std::io; -use std::io::{Cursor, Read, Seek, SeekFrom}; +use std::{cmp, mem}; +use std::io::{self, Cursor, Read, Seek, SeekFrom}; use std::iter::{repeat, Iterator, Rev}; +use std::marker::PhantomData; use std::slice::ChunksMut; use byteorder::{LittleEndian, ReadBytesExt}; @@ -217,19 +217,19 @@ where if !top_down { for row in buffer.chunks_mut(row_width).rev() { - try!(func(row)); + func(row)?; } // If we need more space, extend the buffer. if buffer.len() < full_image_size { let new_space = extend_buffer(buffer, full_image_size, false); for row in new_space.chunks_mut(row_width).rev() { - try!(func(row)); + func(row)?; } } } else { for row in buffer.chunks_mut(row_width) { - try!(func(row)); + func(row)?; } if buffer.len() < full_image_size { // If the image is stored in top-down order, we can simply use the extend function @@ -238,7 +238,7 @@ where buffer.extend(repeat(0xFF).take(extend)); let len = buffer.len(); for row in buffer[len - row_width..].chunks_mut(row_width) { - try!(func(row)); + func(row)?; } }; } @@ -293,6 +293,37 @@ fn set_4bit_pixel_run<'a, T: Iterator>( true } +fn set_2bit_pixel_run<'a, T: Iterator>( + pixel_iter: &mut ChunksMut, + palette: &[(u8, u8, u8)], + indices: T, + mut n_pixels: usize, +) -> bool { + for idx in indices { + macro_rules! set_pixel { + ($i:expr) => { + if n_pixels == 0 { + break; + } + if let Some(pixel) = pixel_iter.next() { + let (r, g, b) = palette[$i as usize]; + pixel[0] = r; + pixel[1] = g; + pixel[2] = b; + } else { + return false; + } + n_pixels -= 1; + }; + } + set_pixel!((idx >> 6) & 0x3u8); + set_pixel!((idx >> 4) & 0x3u8); + set_pixel!((idx >> 2) & 0x3u8); + set_pixel!( idx & 0x3u8); + } + true +} + fn set_1bit_pixel_run<'a, T: Iterator>( pixel_iter: &mut ChunksMut, palette: &[(u8, u8, u8)], @@ -379,10 +410,10 @@ impl Bitfields { max_len: u32, ) -> ImageResult { let bitfields = Bitfields { - r: try!(Bitfield::from_mask(r_mask, max_len)), - g: try!(Bitfield::from_mask(g_mask, max_len)), - b: try!(Bitfield::from_mask(b_mask, max_len)), - a: try!(Bitfield::from_mask(a_mask, max_len)), + r: Bitfield::from_mask(r_mask, max_len)?, + g: Bitfield::from_mask(g_mask, max_len)?, + b: Bitfield::from_mask(b_mask, max_len)?, + a: Bitfield::from_mask(a_mask, max_len)?, }; if bitfields.r.len == 0 || bitfields.g.len == 0 || bitfields.b.len == 0 { return Err(ImageError::FormatError("Missing bitfield mask".to_string())); @@ -540,7 +571,7 @@ impl BMPDecoder { return Ok(()); } let mut signature = [0; 2]; - try!(self.r.read_exact(&mut signature)); + self.r.read_exact(&mut signature)?; if signature != b"BM"[..] { return Err(ImageError::FormatError( @@ -550,8 +581,8 @@ impl BMPDecoder { // The next 8 bytes represent file size, followed the 4 reserved bytes // We're not interesting these values - try!(self.r.read_u32::()); - try!(self.r.read_u32::()); + self.r.read_u32::()?; + self.r.read_u32::()?; self.data_offset = u64::from(self.r.read_u32::()?); @@ -576,11 +607,11 @@ impl BMPDecoder { // Number of planes (format specifies that this should be 1). if try!(self.r.read_u16::()) != 1 { return Err(ImageError::FormatError( - "Invalid number of planes.".to_string(), + "More than one plane".to_string(), )); } - self.bit_count = try!(self.r.read_u16::()); + self.bit_count = self.r.read_u16::()?; self.image_type = match self.bit_count { 1 | 4 | 8 => ImageType::Palette, 24 => ImageType::RGB24, @@ -595,8 +626,8 @@ impl BMPDecoder { /// /// returns Err if any of the values are invalid. fn read_bitmap_info_header(&mut self) -> ImageResult<()> { - self.width = try!(self.r.read_i32::()); - self.height = try!(self.r.read_i32::()); + self.width = self.r.read_i32::()?; + self.height = self.r.read_i32::()?; // Width can not be negative if self.width < 0 { @@ -626,12 +657,12 @@ impl BMPDecoder { // Number of planes (format specifies that this should be 1). if try!(self.r.read_u16::()) != 1 { return Err(ImageError::FormatError( - "Invalid number of planes.".to_string(), + "More than one plane".to_string(), )); } - self.bit_count = try!(self.r.read_u16::()); - let image_type_u32 = try!(self.r.read_u32::()); + self.bit_count = self.r.read_u16::()?; + let image_type_u32 = self.r.read_u32::()?; // Top-down dibs can not be compressed. if self.top_down && image_type_u32 != 0 && image_type_u32 != 3 { @@ -641,7 +672,7 @@ impl BMPDecoder { } self.image_type = match image_type_u32 { 0 => match self.bit_count { - 1 | 4 | 8 => ImageType::Palette, + 1 | 2 | 4 | 8 => ImageType::Palette, 16 => ImageType::RGB16, 24 => ImageType::RGB24, 32 => if self.add_alpha_channel { @@ -649,7 +680,7 @@ impl BMPDecoder { } else { ImageType::RGB32 }, - _ => return Err(ImageError::FormatError("Invalid RGB bit count".to_string())), + _ => return Err(ImageError::FormatError(format!("Invalid RGB bit count {}", self.bit_count).to_string())), }, 1 => match self.bit_count { 8 => ImageType::RLE8, @@ -688,23 +719,23 @@ impl BMPDecoder { // followed the horizontal and vertical printing resolutions // We will calculate the pixel array size using width & height of image // We're not interesting the horz or vert printing resolutions - try!(self.r.read_u32::()); - try!(self.r.read_u32::()); - try!(self.r.read_u32::()); + self.r.read_u32::()?; + self.r.read_u32::()?; + self.r.read_u32::()?; - self.colors_used = try!(self.r.read_u32::()); + self.colors_used = self.r.read_u32::()?; // The next 4 bytes represent number of "important" colors // We're not interested in this value, so we'll skip it - try!(self.r.read_u32::()); + self.r.read_u32::()?; Ok(()) } fn read_bitmasks(&mut self) -> ImageResult<()> { - let r_mask = try!(self.r.read_u32::()); - let g_mask = try!(self.r.read_u32::()); - let b_mask = try!(self.r.read_u32::()); + let r_mask = self.r.read_u32::()?; + let g_mask = self.r.read_u32::()?; + let b_mask = self.r.read_u32::()?; let a_mask = match self.bmp_header_type { BMPHeaderType::V3 | BMPHeaderType::V4 | BMPHeaderType::V5 => { @@ -732,9 +763,9 @@ impl BMPDecoder { fn read_metadata(&mut self) -> ImageResult<()> { if !self.has_loaded_metadata { - try!(self.read_file_header()); - let bmp_header_offset = try!(self.r.seek(SeekFrom::Current(0))); - let bmp_header_size = try!(self.r.read_u32::()); + self.read_file_header()?; + let bmp_header_offset = self.r.seek(SeekFrom::Current(0))?; + let bmp_header_size = self.r.read_u32::()?; let bmp_header_end = bmp_header_offset + u64::from(bmp_header_size); self.bmp_header_type = match bmp_header_size { @@ -753,32 +784,32 @@ impl BMPDecoder { match self.bmp_header_type { BMPHeaderType::Core => { - try!(self.read_bitmap_core_header()); + self.read_bitmap_core_header()?; } BMPHeaderType::Info | BMPHeaderType::V2 | BMPHeaderType::V3 | BMPHeaderType::V4 | BMPHeaderType::V5 => { - try!(self.read_bitmap_info_header()); + self.read_bitmap_info_header()?; } }; match self.image_type { - ImageType::Bitfields16 | ImageType::Bitfields32 => try!(self.read_bitmasks()), + ImageType::Bitfields16 | ImageType::Bitfields32 => self.read_bitmasks()?, _ => {} }; - try!(self.r.seek(SeekFrom::Start(bmp_header_end))); + self.r.seek(SeekFrom::Start(bmp_header_end))?; match self.image_type { - ImageType::Palette | ImageType::RLE4 | ImageType::RLE8 => try!(self.read_palette()), + ImageType::Palette | ImageType::RLE4 | ImageType::RLE8 => self.read_palette()?, _ => {} }; if self.no_file_header { // Use the offset of the end of metadata instead of reading a BMP file header. - self.data_offset = try!(self.r.seek(SeekFrom::Current(0))); + self.data_offset = self.r.seek(SeekFrom::Current(0))?; } self.has_loaded_metadata = true; @@ -791,7 +822,7 @@ impl BMPDecoder { pub fn read_metadata_in_ico_format(&mut self) -> ImageResult<()> { self.no_file_header = true; self.add_alpha_channel = true; - try!(self.read_metadata()); + self.read_metadata()?; // The height field in an ICO file is doubled to account for the AND mask // (whether or not an AND mask is actually present). @@ -825,7 +856,7 @@ impl BMPDecoder { const MAX_PALETTE_SIZE: usize = 256; // Palette indices are u8. let bytes_per_color = self.bytes_per_color(); - let palette_size = try!(self.get_palette_size()); + let palette_size = self.get_palette_size()?; let max_length = MAX_PALETTE_SIZE * bytes_per_color; let length = palette_size * bytes_per_color; @@ -835,7 +866,7 @@ impl BMPDecoder { // We limit the buffer to at most 256 colours to avoid any oom issues as // 8-bit images can't reference more than 256 indexes anyhow. buf.resize(cmp::min(length, max_length), 0); - try!(self.r.by_ref().read_exact(&mut buf)); + self.r.by_ref().read_exact(&mut buf)?; // Allocate 256 entries even if palette_size is smaller, to prevent corrupt files from // causing an out-of-bounds array access. @@ -843,7 +874,7 @@ impl BMPDecoder { buf.resize(max_length, 0); } else if length > max_length { // Ignore any excess palette colors. - try!(self.r.seek(SeekFrom::Current((length - max_length) as i64))); + self.r.seek(SeekFrom::Current((length - max_length) as i64))?; }; let p: Vec<(u8, u8, u8)> = (0..MAX_PALETTE_SIZE) @@ -905,7 +936,7 @@ impl BMPDecoder { let reader = &mut self.r; let width = self.width as usize; - try!(reader.seek(SeekFrom::Start(self.data_offset))); + reader.seek(SeekFrom::Start(self.data_offset))?; try!(with_rows( &mut pixel_data, @@ -914,12 +945,15 @@ impl BMPDecoder { num_channels, self.top_down, |row| { - try!(reader.read_exact(&mut indices)); + reader.read_exact(&mut indices)?; let mut pixel_iter = row.chunks_mut(num_channels); match bit_count { 1 => { set_1bit_pixel_run(&mut pixel_iter, palette, indices.iter()); } + 2 => { + set_2bit_pixel_run(&mut pixel_iter, palette, indices.iter(), width); + } 4 => { set_4bit_pixel_run(&mut pixel_iter, palette, indices.iter(), width); } @@ -946,7 +980,7 @@ impl BMPDecoder { }; let reader = &mut self.r; - try!(reader.seek(SeekFrom::Start(self.data_offset))); + reader.seek(SeekFrom::Start(self.data_offset))?; try!(with_rows( &mut pixel_data, @@ -980,7 +1014,7 @@ impl BMPDecoder { let bitfields = self.bitfields.as_ref().unwrap(); let reader = &mut self.r; - try!(reader.seek(SeekFrom::Start(self.data_offset))); + reader.seek(SeekFrom::Start(self.data_offset))?; try!(with_rows( &mut pixel_data, @@ -990,7 +1024,7 @@ impl BMPDecoder { self.top_down, |row| { for pixel in row.chunks_mut(num_channels) { - let data = try!(reader.read_u32::()); + let data = reader.read_u32::()?; pixel[0] = bitfields.r.read(data); pixel[1] = bitfields.g.read(data); @@ -1016,7 +1050,7 @@ impl BMPDecoder { }; let row_padding = &mut [0; 4][..row_padding_len]; - try!(self.r.seek(SeekFrom::Start(self.data_offset))); + self.r.seek(SeekFrom::Start(self.data_offset))?; let reader = &mut self.r; @@ -1029,22 +1063,22 @@ impl BMPDecoder { |row| { for pixel in row.chunks_mut(num_channels) { if *format == FormatFullBytes::Format888 { - try!(reader.read_u8()); + reader.read_u8()?; } // Read the colour values (b, g, r). // Reading 3 bytes and reversing them is significantly faster than reading one // at a time. - try!(reader.read_exact(&mut pixel[0..3])); + reader.read_exact(&mut pixel[0..3])?; pixel[0..3].reverse(); if *format == FormatFullBytes::RGB32 { - try!(reader.read_u8()); + reader.read_u8()?; } // Read the alpha channel if present if *format == FormatFullBytes::RGBA32 { - try!(reader.read_exact(&mut pixel[3..4])); + reader.read_exact(&mut pixel[3..4])?; } } reader.read_exact(row_padding) @@ -1056,7 +1090,7 @@ impl BMPDecoder { fn read_rle_data(&mut self, image_type: ImageType) -> ImageResult> { // Seek to the start of the actual image data. - try!(self.r.seek(SeekFrom::Start(self.data_offset))); + self.r.seek(SeekFrom::Start(self.data_offset))?; let full_image_size = try!( num_bytes(self.width, self.height, self.num_channels()).ok_or_else(|| { @@ -1065,7 +1099,7 @@ impl BMPDecoder { ); let mut pixel_data = self.create_pixel_data(); let (skip_pixels, skip_rows, eof_hit) = - try!(self.read_rle_data_step(&mut pixel_data, image_type, 0, 0)); + self.read_rle_data_step(&mut pixel_data, image_type, 0, 0)?; // Extend the buffer if there is still data left. // If eof_hit is true, it means that we hit an end-of-file marker in the last step and // we won't extend the buffer further to avoid small files with a large specified size causing memory issues. @@ -1073,7 +1107,7 @@ impl BMPDecoder { // file would now have to at least have some data in it. if pixel_data.len() < full_image_size && !eof_hit { let new = extend_buffer(&mut pixel_data, full_image_size, true); - try!(self.read_rle_data_step(new, image_type, skip_pixels, skip_rows)); + self.read_rle_data_step(new, image_type, skip_pixels, skip_rows)?; } Ok(pixel_data) } @@ -1255,8 +1289,24 @@ impl BMPDecoder { } } -impl ImageDecoder for BMPDecoder { - type Reader = Cursor>; +/// Wrapper struct around a `Cursor>` +pub struct BmpReader(Cursor>, PhantomData); +impl Read for BmpReader { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + self.0.read(buf) + } + fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { + if self.0.position() == 0 && buf.is_empty() { + mem::swap(buf, self.0.get_mut()); + Ok(buf.len()) + } else { + self.0.read_to_end(buf) + } + } +} + +impl<'a, R: 'a + Read + Seek> ImageDecoder<'a> for BMPDecoder { + type Reader = BmpReader; fn dimensions(&self) -> (u64, u64) { (self.width as u64, self.height as u64) @@ -1271,7 +1321,7 @@ impl ImageDecoder for BMPDecoder { } fn into_reader(self) -> ImageResult { - Ok(Cursor::new(self.read_image()?)) + Ok(BmpReader(Cursor::new(self.read_image()?), PhantomData)) } fn read_image(mut self) -> ImageResult> { @@ -1279,7 +1329,7 @@ impl ImageDecoder for BMPDecoder { } } -impl ImageDecoderExt for BMPDecoder { +impl<'a, R: 'a + Read + Seek> ImageDecoderExt<'a> for BMPDecoder { fn read_rect_with_progress( &mut self, x: u64, diff --git a/third_party/rust/image/src/bmp/encoder.rs b/third_party/rust/image/src/bmp/encoder.rs index 3e3eb30b3d0a..b8b834f7aa14 100644 --- a/third_party/rust/image/src/bmp/encoder.rs +++ b/third_party/rust/image/src/bmp/encoder.rs @@ -3,6 +3,10 @@ use std::io::{self, Write}; use color; +const BITMAPFILEHEADER_SIZE: u32 = 14; +const BITMAPINFOHEADER_SIZE: u32 = 40; +const BITMAPV4HEADER_SIZE: u32 = 108; + /// The representation of a BMP encoder. pub struct BMPEncoder<'a, W: 'a> { writer: &'a mut W, @@ -24,10 +28,9 @@ impl<'a, W: Write + 'a> BMPEncoder<'a, W> { height: u32, c: color::ColorType, ) -> io::Result<()> { - let bmp_header_size = 14; - let dib_header_size = 40; // using BITMAPINFOHEADER + let bmp_header_size = BITMAPFILEHEADER_SIZE; - let (raw_pixel_size, written_pixel_size, palette_color_count) = try!(get_pixel_info(c)); + let (dib_header_size, written_pixel_size, palette_color_count) = get_pixel_info(c)?; let row_pad_size = (4 - (width * written_pixel_size) % 4) % 4; // each row must be padded to a multiple of 4 bytes let image_size = width * height * written_pixel_size + (height * row_pad_size); @@ -35,39 +38,62 @@ impl<'a, W: Write + 'a> BMPEncoder<'a, W> { let file_size = bmp_header_size + dib_header_size + palette_size + image_size; // write BMP header - try!(self.writer.write_u8(b'B')); - try!(self.writer.write_u8(b'M')); - try!(self.writer.write_u32::(file_size)); // file size - try!(self.writer.write_u16::(0)); // reserved 1 - try!(self.writer.write_u16::(0)); // reserved 2 + self.writer.write_u8(b'B')?; + self.writer.write_u8(b'M')?; + self.writer.write_u32::(file_size)?; // file size + self.writer.write_u16::(0)?; // reserved 1 + self.writer.write_u16::(0)?; // reserved 2 try!( self.writer .write_u32::(bmp_header_size + dib_header_size + palette_size) ); // image data offset // write DIB header - try!(self.writer.write_u32::(dib_header_size)); - try!(self.writer.write_i32::(width as i32)); - try!(self.writer.write_i32::(height as i32)); - try!(self.writer.write_u16::(1)); // color planes + self.writer.write_u32::(dib_header_size)?; + self.writer.write_i32::(width as i32)?; + self.writer.write_i32::(height as i32)?; + self.writer.write_u16::(1)?; // color planes try!( self.writer .write_u16::((written_pixel_size * 8) as u16) ); // bits per pixel - try!(self.writer.write_u32::(0)); // compression method - no compression - try!(self.writer.write_u32::(image_size)); - try!(self.writer.write_i32::(0)); // horizontal ppm - try!(self.writer.write_i32::(0)); // vertical ppm - try!(self.writer.write_u32::(palette_color_count)); - try!(self.writer.write_u32::(0)); // all colors are important + if dib_header_size >= BITMAPV4HEADER_SIZE { + // Assume BGRA32 + self.writer.write_u32::(3)?; // compression method - bitfields + } else { + self.writer.write_u32::(0)?; // compression method - no compression + } + self.writer.write_u32::(image_size)?; + self.writer.write_i32::(0)?; // horizontal ppm + self.writer.write_i32::(0)?; // vertical ppm + self.writer.write_u32::(palette_color_count)?; + self.writer.write_u32::(0)?; // all colors are important + if dib_header_size >= BITMAPV4HEADER_SIZE { + // Assume BGRA32 + self.writer.write_u32::(0xff << 16)?; // red mask + self.writer.write_u32::(0xff << 8)?; // green mask + self.writer.write_u32::(0xff << 0)?; // blue mask + self.writer.write_u32::(0xff << 24)?; // alpha mask + self.writer.write_u32::(0x73524742)?; // colorspace - sRGB + // endpoints (3x3) and gamma (3) + for _ in 0..12 { + self.writer.write_u32::(0)?; + } + } // write image data match c { - color::ColorType::RGB(8) | color::ColorType::RGBA(8) => { - try!(self.encode_rgb(image, width, height, row_pad_size, raw_pixel_size)) + color::ColorType::RGB(8) => { + self.encode_rgb(image, width, height, row_pad_size, 3)? } - color::ColorType::Gray(8) | color::ColorType::GrayA(8) => { - try!(self.encode_gray(image, width, height, row_pad_size, raw_pixel_size)) + color::ColorType::RGBA(8) => { + self.encode_rgba(image, width, height, row_pad_size, 4)? + } + color::ColorType::Gray(8) => { + self.encode_gray(image, width, height, row_pad_size, 1)? + } + color::ColorType::GrayA(8) => { + self.encode_gray(image, width, height, row_pad_size, 2)? } _ => { return Err(io::Error::new( @@ -99,13 +125,45 @@ impl<'a, W: Write + 'a> BMPEncoder<'a, W> { let g = image[pixel_start + 1]; let b = image[pixel_start + 2]; // written as BGR - try!(self.writer.write_u8(b)); - try!(self.writer.write_u8(g)); - try!(self.writer.write_u8(r)); + self.writer.write_u8(b)?; + self.writer.write_u8(g)?; + self.writer.write_u8(r)?; // alpha is never written as it's not widely supported } - try!(self.write_row_pad(row_pad_size)); + self.write_row_pad(row_pad_size)?; + } + + Ok(()) + } + + fn encode_rgba( + &mut self, + image: &[u8], + width: u32, + height: u32, + row_pad_size: u32, + bytes_per_pixel: u32, + ) -> io::Result<()> { + let x_stride = bytes_per_pixel; + let y_stride = width * x_stride; + for row in 0..height { + // from the bottom up + let row_start = (height - row - 1) * y_stride; + for col in 0..width { + let pixel_start = (row_start + (col * x_stride)) as usize; + let r = image[pixel_start]; + let g = image[pixel_start + 1]; + let b = image[pixel_start + 2]; + let a = image[pixel_start + 3]; + // written as BGRA + self.writer.write_u8(b)?; + self.writer.write_u8(g)?; + self.writer.write_u8(r)?; + self.writer.write_u8(a)?; + } + + self.write_row_pad(row_pad_size)?; } Ok(()) @@ -123,10 +181,10 @@ impl<'a, W: Write + 'a> BMPEncoder<'a, W> { for val in 0..256 { // each color is written as BGRA, where A is always 0 and since only grayscale is being written, B = G = R = index let val = val as u8; - try!(self.writer.write_u8(val)); - try!(self.writer.write_u8(val)); - try!(self.writer.write_u8(val)); - try!(self.writer.write_u8(0)); + self.writer.write_u8(val)?; + self.writer.write_u8(val)?; + self.writer.write_u8(val)?; + self.writer.write_u8(0)?; } // write image data @@ -138,11 +196,11 @@ impl<'a, W: Write + 'a> BMPEncoder<'a, W> { for col in 0..width { let pixel_start = (row_start + (col * x_stride)) as usize; // color value is equal to the palette index - try!(self.writer.write_u8(image[pixel_start])); + self.writer.write_u8(image[pixel_start])?; // alpha is never written as it's not widely supported } - try!(self.write_row_pad(row_pad_size)); + self.write_row_pad(row_pad_size)?; } Ok(()) @@ -150,7 +208,7 @@ impl<'a, W: Write + 'a> BMPEncoder<'a, W> { fn write_row_pad(&mut self, row_pad_size: u32) -> io::Result<()> { for _ in 0..row_pad_size { - try!(self.writer.write_u8(0)); + self.writer.write_u8(0)?; } Ok(()) @@ -164,13 +222,13 @@ fn get_unsupported_error_message(c: color::ColorType) -> String { ) } -/// Returns a tuple representing: (raw pixel size, written pixel size, palette color count). +/// Returns a tuple representing: (dib header size, written pixel size, palette color count). fn get_pixel_info(c: color::ColorType) -> io::Result<(u32, u32, u32)> { let sizes = match c { - color::ColorType::RGB(8) => (3, 3, 0), - color::ColorType::RGBA(8) => (4, 3, 0), - color::ColorType::Gray(8) => (1, 1, 256), - color::ColorType::GrayA(8) => (2, 1, 256), + color::ColorType::RGB(8) => (BITMAPINFOHEADER_SIZE, 3, 0), + color::ColorType::RGBA(8) => (BITMAPV4HEADER_SIZE, 4, 0), + color::ColorType::Gray(8) => (BITMAPINFOHEADER_SIZE, 1, 256), + color::ColorType::GrayA(8) => (BITMAPINFOHEADER_SIZE, 1, 256), _ => { return Err(io::Error::new( io::ErrorKind::InvalidInput, @@ -215,12 +273,9 @@ mod tests { #[test] fn round_trip_single_pixel_rgba() { - let image = [255u8, 0, 0, 0]; // single red pixel + let image = [1, 2, 3, 4]; let decoded = round_trip_image(&image, 1, 1, ColorType::RGBA(8)); - assert_eq!(3, decoded.len()); - assert_eq!(255, decoded[0]); - assert_eq!(0, decoded[1]); - assert_eq!(0, decoded[2]); + assert_eq!(&decoded[..], &image[..]); } #[test] diff --git a/third_party/rust/image/src/buffer.rs b/third_party/rust/image/src/buffer.rs index a6d02dcd94a0..d134d674a125 100644 --- a/third_party/rust/image/src/buffer.rs +++ b/third_party/rust/image/src/buffer.rs @@ -7,8 +7,8 @@ use std::slice::{Chunks, ChunksMut}; use color::{ColorType, FromColor, Luma, LumaA, Rgb, Rgba, Bgr, Bgra}; use flat::{FlatSamples, SampleLayout}; -use dynimage::save_buffer; -use image::{GenericImage, GenericImageView}; +use dynimage::{save_buffer, save_buffer_with_format}; +use image::{GenericImage, GenericImageView, ImageFormat}; use traits::Primitive; use utils::expand_packed; @@ -19,8 +19,13 @@ pub trait Pixel: Copy + Clone { /// The underlying subpixel type. type Subpixel: Primitive; + /// The number of channels of this pixel type. + const CHANNEL_COUNT: u8; /// Returns the number of channels of this pixel type. - fn channel_count() -> u8; + #[deprecated(note="please use CHANNEL_COUNT associated constant")] + fn channel_count() -> u8 { + Self::CHANNEL_COUNT + } /// Returns the components as a slice. fn channels(&self) -> &[Self::Subpixel]; @@ -28,12 +33,23 @@ pub trait Pixel: Copy + Clone { /// Returns the components as a mutable slice fn channels_mut(&mut self) -> &mut [Self::Subpixel]; + /// A string that can help to interpret the meaning each channel + /// See [gimp babl](http://gegl.org/babl/). + const COLOR_MODEL: &'static str; /// Returns a string that can help to interpret the meaning each channel /// See [gimp babl](http://gegl.org/babl/). - fn color_model() -> &'static str; + #[deprecated(note="please use COLOR_MODEL associated constant")] + fn color_model() -> &'static str { + Self::COLOR_MODEL + } + /// ColorType for this pixel format + const COLOR_TYPE: ColorType; /// Returns the ColorType for this pixel format - fn color_type() -> ColorType; + #[deprecated(note="please use COLOR_TYPE associated constant")] + fn color_type() -> ColorType { + Self::COLOR_TYPE + } /// Returns the channels of this pixel as a 4 tuple. If the pixel /// has less than 4 channels the remainder is filled with the maximum value @@ -112,6 +128,25 @@ pub trait Pixel: Copy + Clone { where F: FnMut(Self::Subpixel) -> Self::Subpixel, G: FnMut(Self::Subpixel) -> Self::Subpixel; + + /// Apply the function ```f``` to each channel except the alpha channel. + fn map_without_alpha(&self, f: F) -> Self + where + F: FnMut(Self::Subpixel) -> Self::Subpixel, + { + let mut this = *self; + this.apply_with_alpha(f, |x| x); + this + } + + /// Apply the function ```f``` to each channel except the alpha channel. + /// Works in place. + fn apply_without_alpha(&mut self, f: F) + where + F: FnMut(Self::Subpixel) -> Self::Subpixel, + { + self.apply_with_alpha(f, |x| x); + } /// Apply the function ```f``` to each channel of this pixel and /// ```other``` pairwise. @@ -212,6 +247,92 @@ where } } +/// Iterate over rows of an image +pub struct Rows<'a, P: Pixel + 'a> +where +

::Subpixel: 'a, +{ + chunks: Chunks<'a, P::Subpixel>, +} + +impl<'a, P: Pixel + 'a> Iterator for Rows<'a, P> +where + P::Subpixel: 'a, +{ + type Item = Pixels<'a, P>; + + #[inline(always)] + fn next(&mut self) -> Option> { + self.chunks.next().map(|row| Pixels { + chunks: row.chunks(

::CHANNEL_COUNT as usize), + }) + } +} + +impl<'a, P: Pixel + 'a> ExactSizeIterator for Rows<'a, P> +where + P::Subpixel: 'a, +{ + fn len(&self) -> usize { + self.chunks.len() + } +} + +impl<'a, P: Pixel + 'a> DoubleEndedIterator for Rows<'a, P> +where + P::Subpixel: 'a, +{ + #[inline(always)] + fn next_back(&mut self) -> Option> { + self.chunks.next_back().map(|row| Pixels { + chunks: row.chunks(

::CHANNEL_COUNT as usize), + }) + } +} + +/// Iterate over mutable rows of an image +pub struct RowsMut<'a, P: Pixel + 'a> +where +

::Subpixel: 'a, +{ + chunks: ChunksMut<'a, P::Subpixel>, +} + +impl<'a, P: Pixel + 'a> Iterator for RowsMut<'a, P> +where + P::Subpixel: 'a, +{ + type Item = PixelsMut<'a, P>; + + #[inline(always)] + fn next(&mut self) -> Option> { + self.chunks.next().map(|row| PixelsMut { + chunks: row.chunks_mut(

::CHANNEL_COUNT as usize), + }) + } +} + +impl<'a, P: Pixel + 'a> ExactSizeIterator for RowsMut<'a, P> +where + P::Subpixel: 'a, +{ + fn len(&self) -> usize { + self.chunks.len() + } +} + +impl<'a, P: Pixel + 'a> DoubleEndedIterator for RowsMut<'a, P> +where + P::Subpixel: 'a, +{ + #[inline(always)] + fn next_back(&mut self) -> Option> { + self.chunks.next_back().map(|row| PixelsMut { + chunks: row.chunks_mut(

::CHANNEL_COUNT as usize), + }) + } +} + /// Enumerate the pixels of an image. pub struct EnumeratePixels<'a, P: Pixel + 'a> where @@ -237,10 +358,7 @@ where } let (x, y) = (self.x, self.y); self.x += 1; - match self.pixels.next() { - None => None, - Some(p) => Some((x, y, p)), - } + self.pixels.next().map(|p| (x, y, p)) } } @@ -253,6 +371,49 @@ where } } +/// Enumerate the rows of an image. +pub struct EnumerateRows<'a, P: Pixel + 'a> +where +

::Subpixel: 'a, +{ + rows: Rows<'a, P>, + y: u32, + width: u32, +} + +impl<'a, P: Pixel + 'a> Iterator for EnumerateRows<'a, P> +where + P::Subpixel: 'a, +{ + type Item = (u32, EnumeratePixels<'a, P>); + + #[inline(always)] + fn next(&mut self) -> Option<(u32, EnumeratePixels<'a, P>)> { + let y = self.y; + self.y += 1; + self.rows.next().map(|r| { + ( + y, + EnumeratePixels { + x: 0, + y, + width: self.width, + pixels: r, + }, + ) + }) + } +} + +impl<'a, P: Pixel + 'a> ExactSizeIterator for EnumerateRows<'a, P> +where + P::Subpixel: 'a, +{ + fn len(&self) -> usize { + self.rows.len() + } +} + /// Enumerate the pixels of an image. pub struct EnumeratePixelsMut<'a, P: Pixel + 'a> where @@ -278,10 +439,7 @@ where } let (x, y) = (self.x, self.y); self.x += 1; - match self.pixels.next() { - None => None, - Some(p) => Some((x, y, p)), - } + self.pixels.next().map(|p| (x, y, p)) } } @@ -294,6 +452,49 @@ where } } +/// Enumerate the rows of an image. +pub struct EnumerateRowsMut<'a, P: Pixel + 'a> +where +

::Subpixel: 'a, +{ + rows: RowsMut<'a, P>, + y: u32, + width: u32, +} + +impl<'a, P: Pixel + 'a> Iterator for EnumerateRowsMut<'a, P> +where + P::Subpixel: 'a, +{ + type Item = (u32, EnumeratePixelsMut<'a, P>); + + #[inline(always)] + fn next(&mut self) -> Option<(u32, EnumeratePixelsMut<'a, P>)> { + let y = self.y; + self.y += 1; + self.rows.next().map(|r| { + ( + y, + EnumeratePixelsMut { + x: 0, + y, + width: self.width, + pixels: r, + }, + ) + }) + } +} + +impl<'a, P: Pixel + 'a> ExactSizeIterator for EnumerateRowsMut<'a, P> +where + P::Subpixel: 'a, +{ + fn len(&self) -> usize { + self.rows.len() + } +} + /// Generic image buffer #[derive(Debug)] pub struct ImageBuffer { @@ -304,6 +505,9 @@ pub struct ImageBuffer { } // generic implementation, shared along all image buffers +// +// TODO: Is the 'static bound on `I::Pixel` really required? Can we avoid it? Remember to remove +// the bounds on `imageops` in case this changes! impl ImageBuffer where P: Pixel + 'static, @@ -351,7 +555,16 @@ where /// Returns an iterator over the pixels of this image. pub fn pixels(&self) -> Pixels

{ Pixels { - chunks: self.data.chunks(

::channel_count() as usize), + chunks: self.data.chunks(

::CHANNEL_COUNT as usize), + } + } + + /// Returns an iterator over the rows of this image. + pub fn rows(&self) -> Rows

{ + Rows { + chunks: self + .data + .chunks(

::CHANNEL_COUNT as usize * self.width as usize), } } @@ -367,6 +580,17 @@ where } } + /// Enumerates over the rows of the image. + /// The iterator yields the y-coordinate of each row + /// along with a reference to them. + pub fn enumerate_rows(&self) -> EnumerateRows

{ + EnumerateRows { + rows: self.rows(), + y: 0, + width: self.width, + } + } + /// Gets a reference to the pixel at location `(x, y)` /// /// # Panics @@ -390,7 +614,7 @@ where } fn image_buffer_len(width: u32, height: u32) -> Option { - Some(

::channel_count() as usize) + Some(

::CHANNEL_COUNT as usize) .and_then(|size| size.checked_mul(width as usize)) .and_then(|size| size.checked_mul(height as usize)) } @@ -401,14 +625,12 @@ where return None } - Some(unsafe { - self.unsafe_pixel_indices(x, y) - }) + Some(self.pixel_indices_unchecked(x, y)) } #[inline(always)] - unsafe fn unsafe_pixel_indices(&self, x: u32, y: u32) -> Range { - let no_channels =

::channel_count() as usize; + fn pixel_indices_unchecked(&self, x: u32, y: u32) -> Range { + let no_channels =

::CHANNEL_COUNT as usize; // If in bounds, this can't overflow as we have tested that at construction! let min_index = (y as usize*self.width as usize + x as usize)*no_channels; min_index..min_index+no_channels @@ -417,7 +639,7 @@ where /// Get the format of the buffer when viewed as a matrix of samples. pub fn sample_layout(&self) -> SampleLayout { // None of these can overflow, as all our memory is addressable. - SampleLayout::row_major_packed(

::channel_count(), self.width, self.height) + SampleLayout::row_major_packed(

::CHANNEL_COUNT, self.width, self.height) } /// Return the raw sample buffer with its stride an dimension information. @@ -434,7 +656,7 @@ where FlatSamples { samples: self.data, layout, - color_hint: Some(P::color_type()), + color_hint: Some(P::COLOR_TYPE), } } @@ -448,7 +670,7 @@ where FlatSamples { samples: self.data.as_ref(), layout, - color_hint: Some(P::color_type()), + color_hint: Some(P::COLOR_TYPE), } } } @@ -462,7 +684,16 @@ where /// Returns an iterator over the mutable pixels of this image. pub fn pixels_mut(&mut self) -> PixelsMut

{ PixelsMut { - chunks: self.data.chunks_mut(

::channel_count() as usize), + chunks: self.data.chunks_mut(

::CHANNEL_COUNT as usize), + } + } + + /// Returns an iterator over the mutable rows of this image. + pub fn rows_mut(&mut self) -> RowsMut

{ + RowsMut { + chunks: self + .data + .chunks_mut(

::CHANNEL_COUNT as usize * self.width as usize), } } @@ -479,6 +710,18 @@ where } } + /// Enumerates over the rows of the image. + /// The iterator yields the y-coordinate of each row + /// along with a mutable reference to them. + pub fn enumerate_rows_mut(&mut self) -> EnumerateRowsMut

{ + let width = self.width; + EnumerateRowsMut { + rows: self.rows_mut(), + y: 0, + width, + } + } + /// Gets a reference to the mutable pixel at location `(x, y)` /// /// # Panics @@ -520,7 +763,33 @@ where self, self.width(), self.height(), -

::color_type(), +

::COLOR_TYPE, + ) + } +} + +impl ImageBuffer +where + P: Pixel + 'static, + Container: Deref, +{ + /// Saves the buffer to a file at the specified path in + /// the specified format. + /// + /// See [`save_buffer_with_format`](fn.save_buffer_with_format.html) for + /// supported types. + pub fn save_with_format(&self, path: Q, format: ImageFormat) -> io::Result<()> + where + Q: AsRef, + { + // This is valid as the subpixel is u8. + save_buffer_with_format( + path, + self, + self.width(), + self.height(), +

::COLOR_TYPE, + format, ) } } @@ -612,7 +881,7 @@ where /// Returns the pixel located at (x, y), ignoring bounds checking. #[inline(always)] unsafe fn unsafe_get_pixel(&self, x: u32, y: u32) -> P { - let indices = self.unsafe_pixel_indices(x, y); + let indices = self.pixel_indices_unchecked(x, y); *

::from_slice(self.data.get_unchecked(indices)) } @@ -640,7 +909,7 @@ where /// Puts a pixel at location (x, y), ignoring bounds checking. #[inline(always)] unsafe fn unsafe_put_pixel(&mut self, x: u32, y: u32, pixel: P) { - let indices = self.unsafe_pixel_indices(x, y); + let indices = self.pixel_indices_unchecked(x, y); let p =

::from_slice_mut(self.data.get_unchecked_mut(indices)); *p = pixel } @@ -753,9 +1022,7 @@ impl GrayImage { let (width, height) = self.dimensions(); let mut data = self.into_raw(); let entries = data.len(); - data.reserve_exact(entries.checked_mul(3).unwrap()); // 3 additional channels - // set_len is save since type is u8 an the data never read - unsafe { data.set_len(entries.checked_mul(4).unwrap()) }; // 4 channels in total + data.resize(entries.checked_mul(4).unwrap(), 0); let mut buffer = ImageBuffer::from_vec(width, height, data).unwrap(); expand_packed(&mut buffer, 4, 8, |idx, pixel| { let (r, g, b) = palette[idx as usize]; diff --git a/third_party/rust/image/src/color.rs b/third_party/rust/image/src/color.rs index daa74d95a835..d0ca439a39d9 100644 --- a/third_party/rust/image/src/color.rs +++ b/third_party/rust/image/src/color.rs @@ -68,40 +68,31 @@ $( // START Structure definitions #[derive(PartialEq, Eq, Clone, Debug, Copy, Hash)] #[repr(C)] #[allow(missing_docs)] -pub struct $ident { pub data: [T; $channels] } -#[allow(non_snake_case, missing_docs)] -pub fn $ident(data: [T; $channels]) -> $ident { - $ident { - data: data - } -} +pub struct $ident (pub [T; $channels]); impl Pixel for $ident { type Subpixel = T; - fn channel_count() -> u8 { - $channels - } - fn color_model() -> &'static str { - $interpretation - } - fn color_type() -> ColorType { - ColorType::$color_type(mem::size_of::() as u8 * 8) - } + const CHANNEL_COUNT: u8 = $channels; + + const COLOR_MODEL: &'static str = $interpretation; + + const COLOR_TYPE: ColorType = ColorType::$color_type(mem::size_of::() as u8 * 8); + #[inline(always)] fn channels(&self) -> &[T] { - &self.data + &self.0 } #[inline(always)] fn channels_mut(&mut self) -> &mut [T] { - &mut self.data + &mut self.0 } #[allow(trivial_casts)] fn channels4(&self) -> (T, T, T, T) { let mut channels = [T::max_value(); 4]; - channels[0..$channels].copy_from_slice(&self.data); + channels[0..$channels].copy_from_slice(&self.0); (channels[0], channels[1], channels[2], channels[3]) } @@ -119,37 +110,37 @@ impl Pixel for $ident { } fn to_rgb(&self) -> Rgb { - let mut pix = Rgb {data: [Zero::zero(), Zero::zero(), Zero::zero()]}; + let mut pix = Rgb([Zero::zero(), Zero::zero(), Zero::zero()]); pix.from_color(self); pix } fn to_bgr(&self) -> Bgr { - let mut pix = Bgr {data: [Zero::zero(), Zero::zero(), Zero::zero()]}; + let mut pix = Bgr([Zero::zero(), Zero::zero(), Zero::zero()]); pix.from_color(self); pix } fn to_rgba(&self) -> Rgba { - let mut pix = Rgba {data: [Zero::zero(), Zero::zero(), Zero::zero(), Zero::zero()]}; + let mut pix = Rgba([Zero::zero(), Zero::zero(), Zero::zero(), Zero::zero()]); pix.from_color(self); pix } fn to_bgra(&self) -> Bgra { - let mut pix = Bgra {data: [Zero::zero(), Zero::zero(), Zero::zero(), Zero::zero()]}; + let mut pix = Bgra([Zero::zero(), Zero::zero(), Zero::zero(), Zero::zero()]); pix.from_color(self); pix } fn to_luma(&self) -> Luma { - let mut pix = Luma {data: [Zero::zero()]}; + let mut pix = Luma([Zero::zero()]); pix.from_color(self); pix } fn to_luma_alpha(&self) -> LumaA { - let mut pix = LumaA {data: [Zero::zero(), Zero::zero()]}; + let mut pix = LumaA([Zero::zero(), Zero::zero()]); pix.from_color(self); pix } @@ -161,7 +152,7 @@ impl Pixel for $ident { } fn apply(&mut self, mut f: F) where F: FnMut(T) -> T { - for v in &mut self.data { + for v in &mut self.0 { *v = f(*v) } } @@ -174,11 +165,11 @@ impl Pixel for $ident { #[allow(trivial_casts)] fn apply_with_alpha(&mut self, mut f: F, mut g: G) where F: FnMut(T) -> T, G: FnMut(T) -> T { - for v in self.data[..$channels as usize-$alphas as usize].iter_mut() { + for v in self.0[..$channels as usize-$alphas as usize].iter_mut() { *v = f(*v) } if $alphas as usize != 0 { - let v = &mut self.data[$channels as usize-$alphas as usize]; + let v = &mut self.0[$channels as usize-$alphas as usize]; *v = g(*v) } } @@ -190,7 +181,7 @@ impl Pixel for $ident { } fn apply2(&mut self, other: &$ident, mut f: F) where F: FnMut(T, T) -> T { - for (a, &b) in self.data.iter_mut().zip(other.data.iter()) { + for (a, &b) in self.0.iter_mut().zip(other.0.iter()) { *a = f(*a, b) } } @@ -208,14 +199,14 @@ impl Index for $ident { type Output = T; #[inline(always)] fn index(&self, _index: usize) -> &T { - &self.data[_index] + &self.0[_index] } } impl IndexMut for $ident { #[inline(always)] fn index_mut(&mut self, _index: usize) -> &mut T { - &mut self.data[_index] + &mut self.0[_index] } } @@ -589,8 +580,8 @@ impl Blend for LumaA { fn blend(&mut self, other: &LumaA) { let max_t = T::max_value(); let max_t = max_t.to_f32().unwrap(); - let (bg_luma, bg_a) = (self.data[0], self.data[1]); - let (fg_luma, fg_a) = (other.data[0], other.data[1]); + let (bg_luma, bg_a) = (self.0[0], self.0[1]); + let (fg_luma, fg_a) = (other.0[0], other.0[1]); let (bg_luma, bg_a) = ( bg_luma.to_f32().unwrap() / max_t, @@ -631,8 +622,8 @@ impl Blend for Rgba { // First, as we don't know what type our pixel is, we have to convert to floats between 0.0 and 1.0 let max_t = T::max_value(); let max_t = max_t.to_f32().unwrap(); - let (bg_r, bg_g, bg_b, bg_a) = (self.data[0], self.data[1], self.data[2], self.data[3]); - let (fg_r, fg_g, fg_b, fg_a) = (other.data[0], other.data[1], other.data[2], other.data[3]); + let (bg_r, bg_g, bg_b, bg_a) = (self.0[0], self.0[1], self.0[2], self.0[3]); + let (fg_r, fg_g, fg_b, fg_a) = (other.0[0], other.0[1], other.0[2], other.0[3]); let (bg_r, bg_g, bg_b, bg_a) = ( bg_r.to_f32().unwrap() / max_t, bg_g.to_f32().unwrap() / max_t, @@ -689,8 +680,8 @@ impl Blend for Bgra { // First, as we don't know what type our pixel is, we have to convert to floats between 0.0 and 1.0 let max_t = T::max_value(); let max_t = max_t.to_f32().unwrap(); - let (bg_r, bg_g, bg_b, bg_a) = (self.data[2], self.data[1], self.data[0], self.data[3]); - let (fg_r, fg_g, fg_b, fg_a) = (other.data[2], other.data[1], other.data[0], other.data[3]); + let (bg_r, bg_g, bg_b, bg_a) = (self.0[2], self.0[1], self.0[0], self.0[3]); + let (fg_r, fg_g, fg_b, fg_a) = (other.0[2], other.0[1], other.0[0], other.0[3]); let (bg_r, bg_g, bg_b, bg_a) = ( bg_r.to_f32().unwrap() / max_t, bg_g.to_f32().unwrap() / max_t, @@ -759,7 +750,7 @@ pub trait Invert { impl Invert for LumaA { fn invert(&mut self) { - let l = self.data; + let l = self.0; let max = T::max_value(); *self = LumaA([max - l[0], l[1]]) @@ -768,18 +759,18 @@ impl Invert for LumaA { impl Invert for Luma { fn invert(&mut self) { - let l = self.data; + let l = self.0; let max = T::max_value(); let l1 = max - l[0]; - *self = Luma { data: [l1] } + *self = Luma([l1]) } } impl Invert for Rgba { fn invert(&mut self) { - let rgba = self.data; + let rgba = self.0; let max = T::max_value(); @@ -790,7 +781,7 @@ impl Invert for Rgba { impl Invert for Bgra { fn invert(&mut self) { - let bgra = self.data; + let bgra = self.0; let max = T::max_value(); @@ -801,7 +792,7 @@ impl Invert for Bgra { impl Invert for Rgb { fn invert(&mut self) { - let rgb = self.data; + let rgb = self.0; let max = T::max_value(); @@ -815,7 +806,7 @@ impl Invert for Rgb { impl Invert for Bgr { fn invert(&mut self) { - let bgr = self.data; + let bgr = self.0; let max = T::max_value(); @@ -833,157 +824,157 @@ mod tests { #[test] fn test_apply_with_alpha_rgba() { - let mut rgba = Rgba { data: [0, 0, 0, 0] }; + let mut rgba = Rgba([0, 0, 0, 0]); rgba.apply_with_alpha(|s| s, |_| 0xFF); - assert_eq!( - rgba, - Rgba { - data: [0, 0, 0, 0xFF] - } - ); + assert_eq!(rgba, Rgba([0, 0, 0, 0xFF])); } #[test] fn test_apply_with_alpha_bgra() { - let mut bgra = Bgra { data: [0, 0, 0, 0] }; + let mut bgra = Bgra([0, 0, 0, 0]); bgra.apply_with_alpha(|s| s, |_| 0xFF); - assert_eq!( - bgra, - Bgra { - data: [0, 0, 0, 0xFF] - } - ); + assert_eq!(bgra, Bgra([0, 0, 0, 0xFF])); } #[test] fn test_apply_with_alpha_rgb() { - let mut rgb = Rgb { data: [0, 0, 0] }; + let mut rgb = Rgb([0, 0, 0]); rgb.apply_with_alpha(|s| s, |_| panic!("bug")); - assert_eq!(rgb, Rgb { data: [0, 0, 0] }); + assert_eq!(rgb, Rgb([0, 0, 0])); } #[test] fn test_apply_with_alpha_bgr() { - let mut bgr = Bgr { data: [0, 0, 0] }; + let mut bgr = Bgr([0, 0, 0]); bgr.apply_with_alpha(|s| s, |_| panic!("bug")); - assert_eq!(bgr, Bgr { data: [0, 0, 0] }); + assert_eq!(bgr, Bgr([0, 0, 0])); } #[test] fn test_map_with_alpha_rgba() { - let rgba = Rgba { data: [0, 0, 0, 0] }.map_with_alpha(|s| s, |_| 0xFF); - assert_eq!( - rgba, - Rgba { - data: [0, 0, 0, 0xFF] - } - ); + let rgba = Rgba([0, 0, 0, 0]).map_with_alpha(|s| s, |_| 0xFF); + assert_eq!(rgba, Rgba([0, 0, 0, 0xFF])); } #[test] fn test_map_with_alpha_rgb() { - let rgb = Rgb { data: [0, 0, 0] }.map_with_alpha(|s| s, |_| panic!("bug")); - assert_eq!(rgb, Rgb { data: [0, 0, 0] }); + let rgb = Rgb([0, 0, 0]).map_with_alpha(|s| s, |_| panic!("bug")); + assert_eq!(rgb, Rgb([0, 0, 0])); } #[test] fn test_map_with_alpha_bgr() { - let bgr = Bgr { data: [0, 0, 0] }.map_with_alpha(|s| s, |_| panic!("bug")); - assert_eq!(bgr, Bgr { data: [0, 0, 0] }); + let bgr = Bgr([0, 0, 0]).map_with_alpha(|s| s, |_| panic!("bug")); + assert_eq!(bgr, Bgr([0, 0, 0])); } #[test] fn test_map_with_alpha_bgra() { - let bgra = Bgra { data: [0, 0, 0, 0] }.map_with_alpha(|s| s, |_| 0xFF); - assert_eq!( - bgra, - Bgra { - data: [0, 0, 0, 0xFF] - } - ); + let bgra = Bgra([0, 0, 0, 0]).map_with_alpha(|s| s, |_| 0xFF); + assert_eq!(bgra, Bgra([0, 0, 0, 0xFF])); } #[test] fn test_blend_luma_alpha() { - let ref mut a = LumaA { - data: [255 as u8, 255], - }; - let b = LumaA { - data: [255 as u8, 255], - }; + let ref mut a = LumaA([255 as u8, 255]); + let b = LumaA([255 as u8, 255]); a.blend(&b); - assert_eq!(a.data[0], 255); - assert_eq!(a.data[1], 255); + assert_eq!(a.0[0], 255); + assert_eq!(a.0[1], 255); - let ref mut a = LumaA { - data: [255 as u8, 0], - }; - let b = LumaA { - data: [255 as u8, 255], - }; + let ref mut a = LumaA([255 as u8, 0]); + let b = LumaA([255 as u8, 255]); a.blend(&b); - assert_eq!(a.data[0], 255); - assert_eq!(a.data[1], 255); + assert_eq!(a.0[0], 255); + assert_eq!(a.0[1], 255); - let ref mut a = LumaA { - data: [255 as u8, 255], - }; - let b = LumaA { - data: [255 as u8, 0], - }; + let ref mut a = LumaA([255 as u8, 255]); + let b = LumaA([255 as u8, 0]); a.blend(&b); - assert_eq!(a.data[0], 255); - assert_eq!(a.data[1], 255); + assert_eq!(a.0[0], 255); + assert_eq!(a.0[1], 255); - let ref mut a = LumaA { - data: [255 as u8, 0], - }; - let b = LumaA { - data: [255 as u8, 0], - }; + let ref mut a = LumaA([255 as u8, 0]); + let b = LumaA([255 as u8, 0]); a.blend(&b); - assert_eq!(a.data[0], 255); - assert_eq!(a.data[1], 0); + assert_eq!(a.0[0], 255); + assert_eq!(a.0[1], 0); } #[test] fn test_blend_rgba() { - let ref mut a = Rgba { - data: [255 as u8, 255, 255, 255], - }; - let b = Rgba { - data: [255 as u8, 255, 255, 255], - }; + let ref mut a = Rgba([255 as u8, 255, 255, 255]); + let b = Rgba([255 as u8, 255, 255, 255]); a.blend(&b); - assert_eq!(a.data, [255, 255, 255, 255]); + assert_eq!(a.0, [255, 255, 255, 255]); - let ref mut a = Rgba { - data: [255 as u8, 255, 255, 0], - }; - let b = Rgba { - data: [255 as u8, 255, 255, 255], - }; + let ref mut a = Rgba([255 as u8, 255, 255, 0]); + let b = Rgba([255 as u8, 255, 255, 255]); a.blend(&b); - assert_eq!(a.data, [255, 255, 255, 255]); + assert_eq!(a.0, [255, 255, 255, 255]); - let ref mut a = Rgba { - data: [255 as u8, 255, 255, 255], - }; - let b = Rgba { - data: [255 as u8, 255, 255, 0], - }; + let ref mut a = Rgba([255 as u8, 255, 255, 255]); + let b = Rgba([255 as u8, 255, 255, 0]); a.blend(&b); - assert_eq!(a.data, [255, 255, 255, 255]); + assert_eq!(a.0, [255, 255, 255, 255]); - let ref mut a = Rgba { - data: [255 as u8, 255, 255, 0], - }; - let b = Rgba { - data: [255 as u8, 255, 255, 0], - }; + let ref mut a = Rgba([255 as u8, 255, 255, 0]); + let b = Rgba([255 as u8, 255, 255, 0]); a.blend(&b); - assert_eq!(a.data, [255, 255, 255, 0]); + assert_eq!(a.0, [255, 255, 255, 0]); + } + + #[test] + fn test_apply_without_alpha_rgba() { + let mut rgba = Rgba([0, 0, 0, 0]); + rgba.apply_without_alpha(|s| s + 1); + assert_eq!(rgba, Rgba([1, 1, 1, 0])); + } + + #[test] + fn test_apply_without_alpha_bgra() { + let mut bgra = Bgra([0, 0, 0, 0]); + bgra.apply_without_alpha(|s| s + 1); + assert_eq!(bgra, Bgra([1, 1, 1, 0])); + } + + #[test] + fn test_apply_without_alpha_rgb() { + let mut rgb = Rgb([0, 0, 0]); + rgb.apply_without_alpha(|s| s + 1); + assert_eq!(rgb, Rgb([1, 1, 1])); + } + + #[test] + fn test_apply_without_alpha_bgr() { + let mut bgr = Bgr([0, 0, 0]); + bgr.apply_without_alpha(|s| s + 1); + assert_eq!(bgr, Bgr([1, 1, 1])); + } + + #[test] + fn test_map_without_alpha_rgba() { + let rgba = Rgba([0, 0, 0, 0]).map_without_alpha(|s| s + 1); + assert_eq!(rgba, Rgba([1, 1, 1, 0])); + } + + #[test] + fn test_map_without_alpha_rgb() { + let rgb = Rgb([0, 0, 0]).map_without_alpha(|s| s + 1); + assert_eq!(rgb, Rgb([1, 1, 1])); + } + + #[test] + fn test_map_without_alpha_bgr() { + let bgr = Bgr([0, 0, 0]).map_without_alpha(|s| s + 1); + assert_eq!(bgr, Bgr([1, 1, 1])); + } + + #[test] + fn test_map_without_alpha_bgra() { + let bgra = Bgra([0, 0, 0, 0]).map_without_alpha(|s| s + 1); + assert_eq!(bgra, Bgra([1, 1, 1, 0])); } } diff --git a/third_party/rust/image/src/dxt.rs b/third_party/rust/image/src/dxt.rs index 8f1ce099db66..c719ab8b88bb 100644 --- a/third_party/rust/image/src/dxt.rs +++ b/third_party/rust/image/src/dxt.rs @@ -83,9 +83,6 @@ impl DXTDecoder { } let width_blocks = width / 4; let height_blocks = height / 4; - if width.count_ones() != 1 || height.count_ones() != 1 { - return Err(ImageError::DimensionError); - } Ok(DXTDecoder { inner: r, width_blocks, @@ -113,7 +110,7 @@ impl DXTDecoder { // Note that, due to the way that DXT compression works, a scanline is considered to consist out of // 4 lines of pixels. -impl ImageDecoder for DXTDecoder { +impl<'a, R: 'a + Read> ImageDecoder<'a> for DXTDecoder { type Reader = DXTReader; fn dimensions(&self) -> (u64, u64) { @@ -152,7 +149,7 @@ impl ImageDecoder for DXTDecoder { } } -impl ImageDecoderExt for DXTDecoder { +impl<'a, R: 'a + Read + Seek> ImageDecoderExt<'a> for DXTDecoder { fn read_rect_with_progress( &mut self, x: u64, @@ -216,9 +213,6 @@ impl DXTEncoder { } let width_blocks = width / 4; let height_blocks = height / 4; - if width.count_ones() != 1 || height.count_ones() != 1 { - return Err(ImageError::DimensionError); - } let stride = variant.decoded_bytes_per_block(); @@ -624,7 +618,7 @@ fn encode_dxt_colors(source: &[u8], dest: &mut [u8]) { swap(&mut color0, &mut color1); // Indexes are packed 2 bits wide, swap index 0/1 but preserve 2/3. let filter = (chosen_indices & 0xAAAA_AAAA) >> 1; - chosen_indices ^= filter ^ 0x555_5555; + chosen_indices ^= filter ^ 0x5555_5555; } } else if !chosen_use_0 { swap(&mut color0, &mut color1); diff --git a/third_party/rust/image/src/dynimage.rs b/third_party/rust/image/src/dynimage.rs index 323a507266b5..4b7ace0b674e 100644 --- a/third_party/rust/image/src/dynimage.rs +++ b/third_party/rust/image/src/dynimage.rs @@ -3,6 +3,7 @@ use std::fs::File; use std::io; use std::io::{BufRead, BufReader, BufWriter, Seek, Write}; use std::path::Path; +use std::u32; #[cfg(feature = "bmp")] use bmp; @@ -491,7 +492,7 @@ impl DynamicImage { }, _ => {}, } - try!(p.encode(&bytes, width, height, color)); + p.encode(&bytes, width, height, color)?; Ok(()) } #[cfg(feature = "pnm")] @@ -508,14 +509,14 @@ impl DynamicImage { }, _ => {}, } - try!(p.encode(&bytes[..], width, height, color)); + p.encode(&bytes[..], width, height, color)?; Ok(()) } #[cfg(feature = "jpeg")] image::ImageOutputFormat::JPEG(quality) => { let mut j = jpeg::JPEGEncoder::new_with_quality(w, quality); - try!(j.encode(&bytes, width, height, color)); + j.encode(&bytes, width, height, color)?; Ok(()) } @@ -535,14 +536,14 @@ impl DynamicImage { image::ImageOutputFormat::ICO => { let i = ico::ICOEncoder::new(w); - try!(i.encode(&bytes, width, height, color)); + i.encode(&bytes, width, height, color)?; Ok(()) } #[cfg(feature = "bmp")] image::ImageOutputFormat::BMP => { let mut b = bmp::BMPEncoder::new(w); - try!(b.encode(&bytes, width, height, color)); + b.encode(&bytes, width, height, color)?; Ok(()) } @@ -563,6 +564,20 @@ impl DynamicImage { p.save(path) }) } + + /// Saves the buffer to a file at the specified path in + /// the specified format. + /// + /// See [`save_buffer_with_format`](fn.save_buffer_with_format.html) for + /// supported types. + pub fn save_with_format(&self, path: Q, format: ImageFormat) -> io::Result<()> + where + Q: AsRef, + { + dynamic_map!(*self, ref p -> { + p.save_with_format(path, format) + }) + } } #[allow(deprecated)] @@ -625,10 +640,10 @@ impl GenericImage for DynamicImage { } /// Decodes an image and stores it into a dynamic image -pub fn decoder_to_image(codec: I) -> ImageResult { +pub fn decoder_to_image<'a, I: ImageDecoder<'a>>(codec: I) -> ImageResult { let color = codec.colortype(); let (w, h) = codec.dimensions(); - let buf = try!(codec.read_image()); + let buf = codec.read_image()?; // TODO: Avoid this cast by having ImageBuffer use u64's assert!(w <= u32::max_value() as u64); @@ -760,13 +775,67 @@ fn open_impl(path: &Path) -> ImageResult { load(fin, format) } +/// Read the dimensions of the image located at the specified path. +/// This is faster than fully loading the image and then getting its dimensions. +pub fn image_dimensions

(path: P) -> ImageResult<(u32, u32)> +where + P: AsRef +{ + // thin wrapper function to strip generics before calling open_impl + image_dimensions_impl(path.as_ref()) +} + +fn image_dimensions_impl(path: &Path) -> ImageResult<(u32, u32)> { + let fin = File::open(path)?; + let fin = BufReader::new(fin); + + let ext = path + .extension() + .and_then(|s| s.to_str()) + .map_or("".to_string(), |s| s.to_ascii_lowercase()); + + let (w, h): (u64, u64) = match &ext[..] { + #[cfg(feature = "jpeg")] + "jpg" | "jpeg" => jpeg::JPEGDecoder::new(fin)?.dimensions(), + #[cfg(feature = "png_codec")] + "png" => png::PNGDecoder::new(fin)?.dimensions(), + #[cfg(feature = "gif_codec")] + "gif" => gif::Decoder::new(fin)?.dimensions(), + #[cfg(feature = "webp")] + "webp" => webp::WebpDecoder::new(fin)?.dimensions(), + #[cfg(feature = "tiff")] + "tif" | "tiff" => tiff::TIFFDecoder::new(fin)?.dimensions(), + #[cfg(feature = "tga")] + "tga" => tga::TGADecoder::new(fin)?.dimensions(), + #[cfg(feature = "bmp")] + "bmp" => bmp::BMPDecoder::new(fin)?.dimensions(), + #[cfg(feature = "ico")] + "ico" => ico::ICODecoder::new(fin)?.dimensions(), + #[cfg(feature = "hdr")] + "hdr" => hdr::HDRAdapter::new(fin)?.dimensions(), + #[cfg(feature = "pnm")] + "pbm" | "pam" | "ppm" | "pgm" => { + pnm::PNMDecoder::new(fin)?.dimensions() + } + format => return Err(image::ImageError::UnsupportedError(format!( + "Image format image/{:?} is not supported.", + format + ))), + }; + if w >= u32::MAX as u64 || h >= u32::MAX as u64 { + return Err(image::ImageError::DimensionError); + } + Ok((w as u32, h as u32)) +} + + /// Saves the supplied buffer to a file at the path specified. /// /// The image format is derived from the file extension. The buffer is assumed to have /// the correct format according to the specified color type. /// This will lead to corrupted files if the buffer contains malformed data. Currently only -/// jpeg and png files are supported. +/// jpeg, png, ico, pnm, bmp and tiff files are supported. pub fn save_buffer

( path: P, buf: &[u8], @@ -788,7 +857,7 @@ fn save_buffer_impl( height: u32, color: color::ColorType, ) -> io::Result<()> { - let fout = &mut BufWriter::new(try!(File::create(path))); + let fout = &mut BufWriter::new(File::create(path)?); let ext = path.extension() .and_then(|s| s.to_str()) .map_or("".to_string(), |s| s.to_ascii_lowercase()); @@ -816,6 +885,9 @@ fn save_buffer_impl( "pam" => pnm::PNMEncoder::new(fout).encode(buf, width, height, color), #[cfg(feature = "bmp")] "bmp" => bmp::BMPEncoder::new(fout).encode(buf, width, height, color), + #[cfg(feature = "tiff")] + "tif" | "tiff" => tiff::TiffEncoder::new(fout).encode(buf, width, height, color) + .map_err(|e| io::Error::new(io::ErrorKind::Other, Box::new(e))), // FIXME: see https://github.com/image-rs/image/issues/921 format => Err(io::Error::new( io::ErrorKind::InvalidInput, &format!("Unsupported image format image/{:?}", format)[..], @@ -823,6 +895,59 @@ fn save_buffer_impl( } } +/// Saves the supplied buffer to a file at the path specified +/// in the specified format. +/// +/// The buffer is assumed to have the correct format according +/// to the specified color type. +/// This will lead to corrupted files if the buffer contains +/// malformed data. Currently only jpeg, png, ico, bmp and +/// tiff files are supported. +pub fn save_buffer_with_format

( + path: P, + buf: &[u8], + width: u32, + height: u32, + color: color::ColorType, + format: ImageFormat, +) -> io::Result<()> +where + P: AsRef, +{ + // thin wrapper function to strip generics + save_buffer_with_format_impl(path.as_ref(), buf, width, height, color, format) +} + +fn save_buffer_with_format_impl( + path: &Path, + buf: &[u8], + width: u32, + height: u32, + color: color::ColorType, + format: ImageFormat, +) -> io::Result<()> { + let fout = &mut BufWriter::new(File::create(path)?); + + match format { + #[cfg(feature = "ico")] + image::ImageFormat::ICO => ico::ICOEncoder::new(fout).encode(buf, width, height, color), + #[cfg(feature = "jpeg")] + image::ImageFormat::JPEG => jpeg::JPEGEncoder::new(fout).encode(buf, width, height, color), + #[cfg(feature = "png_codec")] + image::ImageFormat::PNG => png::PNGEncoder::new(fout).encode(buf, width, height, color), + #[cfg(feature = "bmp")] + image::ImageFormat::BMP => bmp::BMPEncoder::new(fout).encode(buf, width, height, color), + #[cfg(feature = "tiff")] + image::ImageFormat::TIFF => tiff::TiffEncoder::new(fout) + .encode(buf, width, height, color) + .map_err(|e| io::Error::new(io::ErrorKind::Other, Box::new(e))), + _ => Err(io::Error::new( + io::ErrorKind::InvalidInput, + &format!("Unsupported image format image/{:?}", format)[..], + )), + } +} + /// Create a new image from a Reader pub fn load(r: R, format: ImageFormat) -> ImageResult { #[allow(deprecated, unreachable_patterns)] @@ -860,7 +985,7 @@ static MAGIC_BYTES: [(&'static [u8], ImageFormat); 17] = [ (&[0xff, 0xd8, 0xff], ImageFormat::JPEG), (b"GIF89a", ImageFormat::GIF), (b"GIF87a", ImageFormat::GIF), - (b"WEBP", ImageFormat::WEBP), + (b"RIFF", ImageFormat::WEBP), // TODO: better magic byte detection, see https://github.com/image-rs/image/issues/660 (b"MM.*", ImageFormat::TIFF), (b"II*.", ImageFormat::TIFF), (b"BM", ImageFormat::BMP), @@ -1033,4 +1158,12 @@ mod test { &[0b11110011, 0b00001100], vec![255, 0]); } + + #[cfg(feature = "jpeg")] + #[test] + fn image_dimensions() { + let im_path = "./tests/images/jpg/progressive/cat.jpg"; + let dims = super::image_dimensions(im_path).unwrap(); + assert_eq!(dims, (320, 240)); + } } diff --git a/third_party/rust/image/src/flat.rs b/third_party/rust/image/src/flat.rs index 8471d7ca89d3..51f85fbd485c 100644 --- a/third_party/rust/image/src/flat.rs +++ b/third_party/rust/image/src/flat.rs @@ -559,8 +559,8 @@ impl FlatSamples { pub fn as_view

(&self) -> Result, Error> where P: Pixel, Buffer: AsRef<[P::Subpixel]>, { - if self.layout.channels != P::channel_count() { - return Err(Error::WrongColor(P::color_type())) + if self.layout.channels != P::CHANNEL_COUNT { + return Err(Error::WrongColor(P::COLOR_TYPE)) } let as_ref = self.samples.as_ref(); @@ -596,8 +596,8 @@ impl FlatSamples { pub fn as_view_with_mut_samples

(&mut self) -> Result, Error> where P: Pixel, Buffer: AsMut<[P::Subpixel]>, { - if self.layout.channels != P::channel_count() { - return Err(Error::WrongColor(P::color_type())) + if self.layout.channels != P::CHANNEL_COUNT { + return Err(Error::WrongColor(P::COLOR_TYPE)) } let as_mut = self.samples.as_mut(); @@ -633,8 +633,8 @@ impl FlatSamples { return Err(Error::NormalFormRequired(NormalForm::PixelPacked)) } - if self.layout.channels != P::channel_count() { - return Err(Error::WrongColor(P::color_type())) + if self.layout.channels != P::CHANNEL_COUNT { + return Err(Error::WrongColor(P::COLOR_TYPE)) } let as_mut = self.samples.as_mut(); @@ -717,8 +717,8 @@ impl FlatSamples { return Err((Error::NormalFormRequired(NormalForm::RowMajorPacked), self)) } - if self.layout.channels != P::channel_count() { - return Err((Error::WrongColor(P::color_type()), self)) + if self.layout.channels != P::CHANNEL_COUNT { + return Err((Error::WrongColor(P::COLOR_TYPE), self)) } if !self.fits(self.samples.deref().len()) { @@ -1280,7 +1280,7 @@ impl GenericImageView for View let image = self.inner.samples.as_ref(); let base_index = self.inner.in_bounds_index(0, x, y); - let channels = P::channel_count() as usize; + let channels = P::CHANNEL_COUNT as usize; let mut buffer = [Zero::zero(); 256]; buffer.iter_mut().enumerate().take(channels).for_each(|(c, to)| { @@ -1325,7 +1325,7 @@ impl GenericImageView for ViewMut let image = self.inner.samples.as_ref(); let base_index = self.inner.in_bounds_index(0, x, y); - let channels = P::channel_count() as usize; + let channels = P::CHANNEL_COUNT as usize; let mut buffer = [Zero::zero(); 256]; buffer.iter_mut().enumerate().take(channels).for_each(|(c, to)| { @@ -1352,7 +1352,7 @@ impl GenericImage for ViewMut } let base_index = self.inner.in_bounds_index(0, x, y); - let channel_count =

::channel_count() as usize; + let channel_count =

::CHANNEL_COUNT as usize; let pixel_range = base_index..base_index + channel_count; P::from_slice_mut(&mut self.inner.samples.as_mut()[pixel_range]) } @@ -1461,12 +1461,10 @@ mod tests { { let mut view = buffer.as_view_mut::>() .expect("This should be a valid mutable buffer"); - #[allow(deprecated)] - let pixel_count = view.pixels_mut() - .enumerate() - .map(|(idx, (_, _, pixel))| *pixel = LumaA([2*idx, 2*idx + 1])) - .count(); - assert_eq!(pixel_count, 9); + assert_eq!(view.dimensions(), (3, 3)); + for i in 0..9 { + *view.get_pixel_mut(i % 3, i / 3) = LumaA([2 * i as usize, 2 * i as usize + 1]); + } } buffer.samples.iter() diff --git a/third_party/rust/image/src/gif.rs b/third_party/rust/image/src/gif.rs index 1891002789b6..2ffa03d11d93 100644 --- a/third_party/rust/image/src/gif.rs +++ b/third_party/rust/image/src/gif.rs @@ -30,7 +30,9 @@ extern crate gif; extern crate num_rational; use std::clone::Clone; -use std::io::{Cursor, Read, Write}; +use std::io::{self, Cursor, Read, Write}; +use std::marker::PhantomData; +use std::mem; use self::gif::{ColorOutput, SetParameter}; pub use self::gif::{DisposalMethod, Frame}; @@ -59,8 +61,24 @@ impl Decoder { } } -impl ImageDecoder for Decoder { - type Reader = Cursor>; +/// Wrapper struct around a `Cursor>` +pub struct GifReader(Cursor>, PhantomData); +impl Read for GifReader { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + self.0.read(buf) + } + fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { + if self.0.position() == 0 && buf.is_empty() { + mem::swap(buf, self.0.get_mut()); + Ok(buf.len()) + } else { + self.0.read_to_end(buf) + } + } +} + +impl<'a, R: 'a + Read> ImageDecoder<'a> for Decoder { + type Reader = GifReader; fn dimensions(&self) -> (u64, u64) { (self.reader.width() as u64, self.reader.height() as u64) @@ -71,7 +89,7 @@ impl ImageDecoder for Decoder { } fn into_reader(self) -> ImageResult { - Ok(Cursor::new(self.read_image()?)) + Ok(GifReader(Cursor::new(self.read_image()?), PhantomData)) } fn read_image(mut self) -> ImageResult> { @@ -194,7 +212,7 @@ impl Iterator for GifFrameIterator { // frame need to be used for (x, y, pixel) in image_buffer.enumerate_pixels_mut() { let previous_img_buffer = &self.non_disposed_frame; - let mut adjusted_pixel: &mut Rgba = pixel; + let adjusted_pixel: &mut Rgba = pixel; let previous_pixel: &Rgba = previous_img_buffer.get_pixel(x, y); let pixel_alpha = adjusted_pixel.channels()[3]; @@ -262,7 +280,7 @@ impl Encoder { result = encoder.write_frame(frame).map_err(|err| err.into()); } else { let writer = self.w.take().unwrap(); - let mut encoder = try!(gif::Encoder::new(writer, frame.width, frame.height, &[])); + let mut encoder = gif::Encoder::new(writer, frame.width, frame.height, &[])?; result = encoder.write_frame(&frame).map_err(|err| err.into()); self.gif_encoder = Some(encoder); } diff --git a/third_party/rust/image/src/hdr/hdr_decoder.rs b/third_party/rust/image/src/hdr/decoder.rs similarity index 87% rename from third_party/rust/image/src/hdr/hdr_decoder.rs rename to third_party/rust/image/src/hdr/decoder.rs index 56f39f40ef64..dbe0b47d0755 100644 --- a/third_party/rust/image/src/hdr/hdr_decoder.rs +++ b/third_party/rust/image/src/hdr/decoder.rs @@ -1,12 +1,13 @@ -use super::scoped_threadpool::Pool; +use scoped_threadpool::Pool; use num_traits::cast::NumCast; use num_traits::identities::Zero; use std::mem; #[cfg(test)] use std::borrow::Cow; use std::error::Error; -use std::io::{self, BufRead, Cursor, Seek}; +use std::io::{self, BufRead, Cursor, Read, Seek}; use std::iter::Iterator; +use std::marker::PhantomData; use std::path::Path; use Primitive; @@ -24,7 +25,7 @@ pub struct HDRAdapter { impl HDRAdapter { /// Creates adapter pub fn new(r: R) -> ImageResult> { - let decoder = try!(HDRDecoder::new(r)); + let decoder = HDRDecoder::new(r)?; let meta = decoder.metadata(); Ok(HDRAdapter { inner: Some(decoder), @@ -35,7 +36,7 @@ impl HDRAdapter { /// Allows reading old Radiance HDR images pub fn new_nonstrict(r: R) -> ImageResult> { - let decoder = try!(HDRDecoder::with_strictness(r, false)); + let decoder = HDRDecoder::with_strictness(r, false)?; let meta = decoder.metadata(); Ok(HDRAdapter { inner: Some(decoder), @@ -54,7 +55,7 @@ impl HDRAdapter { let target = self.data.get_or_insert_with(|| Vec::with_capacity(len)); target.clear(); - for Rgb { data } in img { + for Rgb(data) in img { target.extend_from_slice(&data); } @@ -66,8 +67,24 @@ impl HDRAdapter { } -impl ImageDecoder for HDRAdapter { - type Reader = Cursor>; +/// Wrapper struct around a `Cursor>` +pub struct HdrReader(Cursor>, PhantomData); +impl Read for HdrReader { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + self.0.read(buf) + } + fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { + if self.0.position() == 0 && buf.is_empty() { + mem::swap(buf, self.0.get_mut()); + Ok(buf.len()) + } else { + self.0.read_to_end(buf) + } + } +} + +impl<'a, R: 'a + BufRead> ImageDecoder<'a> for HDRAdapter { + type Reader = HdrReader; fn dimensions(&self) -> (u64, u64) { (self.meta.width as u64, self.meta.height as u64) @@ -78,7 +95,7 @@ impl ImageDecoder for HDRAdapter { } fn into_reader(self) -> ImageResult { - Ok(Cursor::new(self.read_image()?)) + Ok(HdrReader(Cursor::new(self.read_image()?), PhantomData)) } fn read_image(mut self) -> ImageResult> { @@ -91,7 +108,7 @@ impl ImageDecoder for HDRAdapter { } } -impl ImageDecoderExt for HDRAdapter { +impl<'a, R: 'a + BufRead + Seek> ImageDecoderExt<'a> for HDRAdapter { fn read_rect_with_progress( &mut self, x: u64, @@ -128,7 +145,7 @@ pub struct HDRDecoder { /// Refer to [wikipedia](https://en.wikipedia.org/wiki/RGBE_image_format) #[repr(C)] -#[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)] pub struct RGBE8Pixel { /// Color components pub c: [u8; 3], @@ -180,7 +197,7 @@ impl RGBE8Pixel { /// Panics when scale or gamma is NaN #[inline] pub fn to_ldr_scale_gamma(self, scale: f32, gamma: f32) -> Rgb { - let Rgb { data } = self.to_hdr(); + let Rgb(data) = self.to_hdr(); let (r, g, b) = (data[0], data[1], data[2]); #[inline] fn sg(v: f32, scale: f32, gamma: f32) -> T { @@ -229,21 +246,21 @@ impl HDRDecoder { let r = &mut reader; if strict { let mut signature = [0; SIGNATURE_LENGTH]; - try!(r.read_exact(&mut signature)); + r.read_exact(&mut signature)?; if signature != SIGNATURE { return Err(ImageError::FormatError( "Radiance HDR signature not found".to_string(), )); } // no else // skip signature line ending - try!(read_line_u8(r)); + read_line_u8(r)?; } else { // Old Radiance HDR files (*.pic) don't use signature // Let them be parsed in non-strict mode } // read header data until empty line loop { - match try!(read_line_u8(r)) { + match read_line_u8(r)? { None => { // EOF before end of header return Err(ImageError::FormatError("EOF in header".into())); @@ -259,20 +276,20 @@ impl HDRDecoder { } // no else // process attribute line let line = String::from_utf8_lossy(&line[..]); - try!(attributes.update_header_info(&line, strict)); + attributes.update_header_info(&line, strict)?; } // <= Some(line) } // match read_line_u8() } // loop } // scope to end borrow of reader // parse dimensions - let (width, height) = match try!(read_line_u8(&mut reader)) { + let (width, height) = match read_line_u8(&mut reader)? { None => { // EOF instead of image dimensions return Err(ImageError::FormatError("EOF in dimensions line".into())); } Some(dimensions) => { let dimensions = String::from_utf8_lossy(&dimensions[..]); - try!(parse_dimensions_line(&dimensions, strict)) + parse_dimensions_line(&dimensions, strict)? } }; @@ -302,13 +319,9 @@ impl HDRDecoder { } // expression self.width > 0 && self.height > 0 is true from now to the end of this method let pixel_count = self.width as usize * self.height as usize; - let mut ret = Vec::::with_capacity(pixel_count); - unsafe { - // RGBE8Pixel doesn't implement Drop, so it's Ok to drop half-initialized ret - ret.set_len(pixel_count); - } // ret contains uninitialized data, so now it's my responsibility to return fully initialized ret + let mut ret = vec![Default::default(); pixel_count]; for chunk in ret.chunks_mut(self.width as usize) { - try!(read_scanline(&mut self.r, chunk)); + read_scanline(&mut self.r, chunk)?; } Ok(ret) } @@ -317,57 +330,48 @@ impl HDRDecoder { pub fn read_image_transform T>( mut self, f: F, - ) -> ImageResult> { + output_slice: &mut [T], + ) -> ImageResult<()> { + assert_eq!(output_slice.len(), self.width as usize * self.height as usize); + // Don't read anything if image is empty if self.width == 0 || self.height == 0 { - return Ok(vec![]); + return Ok(()); } - // expression self.width > 0 && self.height > 0 is true from now to the end of this method - // scanline buffer - let uszwidth = self.width as usize; - let pixel_count = self.width as usize * self.height as usize; - let mut ret = Vec::with_capacity(pixel_count); - unsafe { - // RGBE8Pixel doesn't implement Drop, so it's Ok to drop half-initialized ret - ret.set_len(pixel_count); - } // ret contains uninitialized data, so now it's my responsibility to return fully initialized ret + let chunks_iter = output_slice.chunks_mut(self.width as usize); + let mut pool = Pool::new(8); // - { - let chunks_iter = ret.chunks_mut(uszwidth); - let mut pool = Pool::new(8); // - - try!(pool.scoped(|scope| { - for chunk in chunks_iter { - let mut buf = Vec::::with_capacity(uszwidth); - unsafe { - buf.set_len(uszwidth); + try!(pool.scoped(|scope| { + for chunk in chunks_iter { + let mut buf = vec![Default::default(); self.width as usize]; + read_scanline(&mut self.r, &mut buf[..])?; + let f = &f; + scope.execute(move || { + for (dst, &pix) in chunk.iter_mut().zip(buf.iter()) { + *dst = f(pix); } - try!(read_scanline(&mut self.r, &mut buf[..])); - let f = &f; - scope.execute(move || { - for (dst, &pix) in chunk.iter_mut().zip(buf.iter()) { - *dst = f(pix); - } - }); - } - Ok(()) - }) as Result<(), ImageError>); - } - - Ok(ret) + }); + } + Ok(()) + }) as Result<(), ImageError>); + Ok(()) } /// Consumes decoder and returns a vector of Rgb pixels. /// scale = 1, gamma = 2.2 pub fn read_image_ldr(self) -> ImageResult>> { - self.read_image_transform(|pix| pix.to_ldr()) + let mut ret = vec![Rgb([0,0,0]); self.width as usize * self.height as usize]; + self.read_image_transform(|pix| pix.to_ldr(), &mut ret[..])?; + Ok(ret) } /// Consumes decoder and returns a vector of Rgb pixels. /// pub fn read_image_hdr(self) -> ImageResult>> { - self.read_image_transform(|pix| pix.to_hdr()) + let mut ret = vec![Rgb([0.0, 0.0, 0.0]); self.width as usize * self.height as usize]; + self.read_image_transform(|pix| pix.to_hdr(), &mut ret[..])?; + Ok(ret) } } @@ -376,17 +380,10 @@ impl IntoIterator for HDRDecoder { type IntoIter = HDRImageDecoderIterator; fn into_iter(self) -> Self::IntoIter { - // scanline buffer - let mut buf = Vec::with_capacity(self.width as usize); - unsafe { - // dropping half-initialized vector of RGBE8Pixel is safe - // and I took care to hide half-initialized vector from a user - buf.set_len(self.width as usize); - } HDRImageDecoderIterator { r: self.r, scanline_cnt: self.height as usize, - buf, + buf: vec![Default::default(); self.width as usize], col: 0, scanline: 0, trouble: true, // make first call to `next()` read scanline @@ -475,18 +472,18 @@ fn read_scanline(r: &mut R, buf: &mut [RGBE8Pixel]) -> ImageResult<( assert!(!buf.is_empty()); let width = buf.len(); // first 4 bytes in scanline allow to determine compression method - let fb = try!(read_rgbe(r)); + let fb = read_rgbe(r)?; if fb.c[0] == 2 && fb.c[1] == 2 && fb.c[2] < 128 { // denormalized pixel value (2,2,<128,_) indicates new per component RLE method // decode_component guarantees that offset is within 0 .. width // therefore we can skip bounds checking here, but we will not - try!(decode_component(r, width, |offset, value| buf[offset].c[0] = value)); - try!(decode_component(r, width, |offset, value| buf[offset].c[1] = value)); - try!(decode_component(r, width, |offset, value| buf[offset].c[2] = value)); - try!(decode_component(r, width, |offset, value| buf[offset].e = value)); + decode_component(r, width, |offset, value| buf[offset].c[0] = value)?; + decode_component(r, width, |offset, value| buf[offset].c[1] = value)?; + decode_component(r, width, |offset, value| buf[offset].c[2] = value)?; + decode_component(r, width, |offset, value| buf[offset].e = value)?; } else { // old RLE method (it was considered old around 1991, should it be here?) - try!(decode_old_rle(r, fb, buf)); + decode_old_rle(r, fb, buf)?; } Ok(()) } @@ -494,7 +491,7 @@ fn read_scanline(r: &mut R, buf: &mut [RGBE8Pixel]) -> ImageResult<( #[inline(always)] fn read_byte(r: &mut R) -> io::Result { let mut buf = [0u8]; - try!(r.read_exact(&mut buf[..])); + r.read_exact(&mut buf[..])?; Ok(buf[0]) } @@ -510,7 +507,7 @@ fn decode_component( while pos < width { // increment position by a number of decompressed values pos += { - let rl = try!(read_byte(r)); + let rl = read_byte(r)?; if rl <= 128 { // sanity check if pos + rl as usize > width { @@ -519,7 +516,7 @@ fn decode_component( )); } // read values - try!(r.read_exact(&mut buf[0..rl as usize])); + r.read_exact(&mut buf[0..rl as usize])?; for (offset, &value) in buf[0..rl as usize].iter().enumerate() { set_component(pos + offset, value); } @@ -534,7 +531,7 @@ fn decode_component( )); } // fill with same value - let value = try!(read_byte(r)); + let value = read_byte(r)?; for offset in 0..rl as usize { set_component(pos + offset, value); } @@ -583,7 +580,7 @@ fn decode_old_rle( let mut rl_mult = 1; // current run length multiplier let mut prev_pixel = fb; while x_off < width { - let pix = try!(read_rgbe(r)); + let pix = read_rgbe(r)?; // it's harder to forget to increase x_off if I write this this way. x_off += { if let Some(rl) = rl_marker(pix) { @@ -619,7 +616,7 @@ fn decode_old_rle( fn read_rgbe(r: &mut R) -> io::Result { let mut buf = [0u8; 4]; - try!(r.read_exact(&mut buf[..])); + r.read_exact(&mut buf[..])?; Ok(RGBE8Pixel {c: [buf[0], buf[1], buf[2]], e: buf[3] }) } @@ -808,8 +805,8 @@ fn parse_dimensions_line(line: &str, strict: bool) -> ImageResult<(u32, u32)> { ("-Y", "+X") => { // Common orientation (left-right, top-down) // c1_str is height, c2_str is width - let height = try!(c1_str.parse::().into_image_error(err)); - let width = try!(c2_str.parse::().into_image_error(err)); + let height = c1_str.parse::().into_image_error(err)?; + let width = c2_str.parse::().into_image_error(err)?; Ok((width, height)) } _ => Err(ImageError::FormatError(format!( @@ -920,17 +917,17 @@ pub fn read_raw_file>(path: P) -> ::std::io::Result> use std::fs::File; use std::io::BufReader; - let mut r = BufReader::new(try!(File::open(path))); - let w = try!(r.read_u32::()) as usize; - let h = try!(r.read_u32::()) as usize; - let c = try!(r.read_u32::()) as usize; + let mut r = BufReader::new(File::open(path)?); + let w = r.read_u32::()? as usize; + let h = r.read_u32::()? as usize; + let c = r.read_u32::()? as usize; assert_eq!(c, 3); let cnt = w * h; let mut ret = Vec::with_capacity(cnt); for _ in 0..cnt { - let cr = try!(r.read_f32::()); - let cg = try!(r.read_f32::()); - let cb = try!(r.read_f32::()); + let cr = r.read_f32::()?; + let cg = r.read_f32::()?; + let cb = r.read_f32::()?; ret.push(Rgb([cr, cg, cb])); } Ok(ret) diff --git a/third_party/rust/image/src/hdr/hdr_encoder.rs b/third_party/rust/image/src/hdr/encoder.rs similarity index 95% rename from third_party/rust/image/src/hdr/hdr_encoder.rs rename to third_party/rust/image/src/hdr/encoder.rs index 9304d537b11f..3f32503f7d9a 100644 --- a/third_party/rust/image/src/hdr/hdr_encoder.rs +++ b/third_party/rust/image/src/hdr/encoder.rs @@ -18,15 +18,15 @@ impl HDREncoder { pub fn encode(mut self, data: &[Rgb], width: usize, height: usize) -> Result<()> { assert!(data.len() >= width * height); let w = &mut self.w; - try!(w.write_all(SIGNATURE)); - try!(w.write_all(b"\n")); - try!(w.write_all(b"# Rust HDR encoder\n")); - try!(w.write_all(b"FORMAT=32-bit_rle_rgbe\n\n")); - try!(w.write_all(format!("-Y {} +X {}\n", height, width).as_bytes())); + w.write_all(SIGNATURE)?; + w.write_all(b"\n")?; + w.write_all(b"# Rust HDR encoder\n")?; + w.write_all(b"FORMAT=32-bit_rle_rgbe\n\n")?; + w.write_all(format!("-Y {} +X {}\n", height, width).as_bytes())?; if width < 8 || width > 32_768 { for &pix in data { - try!(write_rgbe8(w, to_rgbe8(pix))); + write_rgbe8(w, to_rgbe8(pix))?; } } else { // new RLE marker contains scanline width @@ -54,19 +54,19 @@ impl HDREncoder { *b = cp.c[2]; *e = cp.e; } - try!(write_rgbe8(w, marker)); // New RLE encoding marker + write_rgbe8(w, marker)?; // New RLE encoding marker rle_buf.clear(); rle_compress(&bufr[..], &mut rle_buf); - try!(w.write_all(&rle_buf[..])); + w.write_all(&rle_buf[..])?; rle_buf.clear(); rle_compress(&bufg[..], &mut rle_buf); - try!(w.write_all(&rle_buf[..])); + w.write_all(&rle_buf[..])?; rle_buf.clear(); rle_compress(&bufb[..], &mut rle_buf); - try!(w.write_all(&rle_buf[..])); + w.write_all(&rle_buf[..])?; rle_buf.clear(); rle_compress(&bufe[..], &mut rle_buf); - try!(w.write_all(&rle_buf[..])); + w.write_all(&rle_buf[..])?; } } Ok(()) @@ -226,7 +226,7 @@ fn write_rgbe8(w: &mut W, v: RGBE8Pixel) -> Result<()> { /// Converts ```Rgb``` into ```RGBE8Pixel``` pub fn to_rgbe8(pix: Rgb) -> RGBE8Pixel { - let pix = pix.data; + let pix = pix.0; let mx = f32::max(pix[0], f32::max(pix[1], pix[2])); if mx <= 0.0 { RGBE8Pixel { c: [0, 0, 0], e: 0 } @@ -274,13 +274,13 @@ fn to_rgbe8_test() { } fn relative_dist(a: Rgb, b: Rgb) -> f32 { // maximal difference divided by maximal value - let max_diff = a.data + let max_diff = a.0 .iter() - .zip(b.data.iter()) + .zip(b.0.iter()) .fold(0.0, |diff, (&a, &b)| f32::max(diff, (a - b).abs())); - let max_val = a.data + let max_val = a.0 .iter() - .chain(b.data.iter()) + .chain(b.0.iter()) .fold(0.0, |maxv, &a| f32::max(maxv, a)); if max_val == 0.0 { 0.0 diff --git a/third_party/rust/image/src/hdr/mod.rs b/third_party/rust/image/src/hdr/mod.rs index bccf5bd8d8ef..b3325bc6487a 100644 --- a/third_party/rust/image/src/hdr/mod.rs +++ b/third_party/rust/image/src/hdr/mod.rs @@ -8,10 +8,8 @@ //! * //! -extern crate scoped_threadpool; +mod decoder; +mod encoder; -mod hdr_decoder; -mod hdr_encoder; - -pub use self::hdr_decoder::*; -pub use self::hdr_encoder::*; +pub use self::decoder::*; +pub use self::encoder::*; diff --git a/third_party/rust/image/src/ico/decoder.rs b/third_party/rust/image/src/ico/decoder.rs index a984bfc1a9b6..61ee8f6bd5a7 100644 --- a/third_party/rust/image/src/ico/decoder.rs +++ b/third_party/rust/image/src/ico/decoder.rs @@ -1,5 +1,7 @@ use byteorder::{LittleEndian, ReadBytesExt}; -use std::io::{Cursor, Read, Seek, SeekFrom}; +use std::io::{self, Cursor, Read, Seek, SeekFrom}; +use std::marker::PhantomData; +use std::mem; use color::ColorType; use image::{ImageDecoder, ImageError, ImageResult}; @@ -40,9 +42,9 @@ struct DirEntry { impl ICODecoder { /// Create a new decoder that decodes from the stream ```r``` pub fn new(mut r: R) -> ImageResult> { - let entries = try!(read_entries(&mut r)); - let entry = try!(best_entry(entries)); - let decoder = try!(entry.decoder(r)); + let entries = read_entries(&mut r)?; + let entry = best_entry(entries)?; + let decoder = entry.decoder(r)?; Ok(ICODecoder { selected_entry: entry, @@ -52,24 +54,24 @@ impl ICODecoder { } fn read_entries(r: &mut R) -> ImageResult> { - let _reserved = try!(r.read_u16::()); - let _type = try!(r.read_u16::()); - let count = try!(r.read_u16::()); + let _reserved = r.read_u16::()?; + let _type = r.read_u16::()?; + let count = r.read_u16::()?; (0..count).map(|_| read_entry(r)).collect() } fn read_entry(r: &mut R) -> ImageResult { let mut entry = DirEntry::default(); - entry.width = try!(r.read_u8()); - entry.height = try!(r.read_u8()); - entry.color_count = try!(r.read_u8()); + entry.width = r.read_u8()?; + entry.height = r.read_u8()?; + entry.color_count = r.read_u8()?; // Reserved value (not used) - entry.reserved = try!(r.read_u8()); + entry.reserved = r.read_u8()?; // This may be either the number of color planes (0 or 1), or the horizontal coordinate // of the hotspot for CUR files. - entry.num_color_planes = try!(r.read_u16::()); + entry.num_color_planes = r.read_u16::()?; if entry.num_color_planes > 256 { return Err(ImageError::FormatError( "ICO image entry has a too large color planes/hotspot value".to_string(), @@ -78,22 +80,22 @@ fn read_entry(r: &mut R) -> ImageResult { // This may be either the bit depth (may be 0 meaning unspecified), // or the vertical coordinate of the hotspot for CUR files. - entry.bits_per_pixel = try!(r.read_u16::()); + entry.bits_per_pixel = r.read_u16::()?; if entry.bits_per_pixel > 256 { return Err(ImageError::FormatError( "ICO image entry has a too large bits per pixel/hotspot value".to_string(), )); } - entry.image_length = try!(r.read_u32::()); - entry.image_offset = try!(r.read_u32::()); + entry.image_length = r.read_u32::()?; + entry.image_offset = r.read_u32::()?; Ok(entry) } /// Find the entry with the highest (color depth, size). fn best_entry(mut entries: Vec) -> ImageResult { - let mut best = try!(entries.pop().ok_or(ImageError::ImageEnd)); + let mut best = entries.pop().ok_or(ImageError::ImageEnd)?; let mut best_score = ( best.bits_per_pixel, u32::from(best.real_width()) * u32::from(best.real_height()), @@ -132,23 +134,23 @@ impl DirEntry { } fn seek_to_start(&self, r: &mut R) -> ImageResult<()> { - try!(r.seek(SeekFrom::Start(u64::from(self.image_offset)))); + r.seek(SeekFrom::Start(u64::from(self.image_offset)))?; Ok(()) } fn is_png(&self, r: &mut R) -> ImageResult { - try!(self.seek_to_start(r)); + self.seek_to_start(r)?; // Read the first 8 bytes to sniff the image. let mut signature = [0u8; 8]; - try!(r.read_exact(&mut signature)); + r.read_exact(&mut signature)?; Ok(signature == PNG_SIGNATURE) } fn decoder(&self, mut r: R) -> ImageResult> { - let is_png = try!(self.is_png(&mut r)); - try!(self.seek_to_start(&mut r)); + let is_png = self.is_png(&mut r)?; + self.seek_to_start(&mut r)?; if is_png { Ok(PNG(PNGDecoder::new(r)?)) @@ -158,8 +160,24 @@ impl DirEntry { } } -impl ImageDecoder for ICODecoder { - type Reader = Cursor>; +/// Wrapper struct around a `Cursor>` +pub struct IcoReader(Cursor>, PhantomData); +impl Read for IcoReader { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + self.0.read(buf) + } + fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { + if self.0.position() == 0 && buf.is_empty() { + mem::swap(buf, self.0.get_mut()); + Ok(buf.len()) + } else { + self.0.read_to_end(buf) + } + } +} + +impl<'a, R: 'a + Read + Seek> ImageDecoder<'a> for ICODecoder { + type Reader = IcoReader; fn dimensions(&self) -> (u64, u64) { match self.inner_decoder { @@ -176,7 +194,7 @@ impl ImageDecoder for ICODecoder { } fn into_reader(self) -> ImageResult { - Ok(Cursor::new(self.read_image()?)) + Ok(IcoReader(Cursor::new(self.read_image()?), PhantomData)) } fn read_image(self) -> ImageResult> { @@ -227,7 +245,7 @@ impl ImageDecoder for ICODecoder { // If there's an AND mask following the image, read and apply it. let r = decoder.reader(); - let mask_start = try!(r.seek(SeekFrom::Current(0))); + let mask_start = r.seek(SeekFrom::Current(0))?; let mask_end = u64::from(self.selected_entry.image_offset + self.selected_entry.image_length); let mask_length = mask_end - mask_start; @@ -244,7 +262,7 @@ impl ImageDecoder for ICODecoder { let mut x = 0; for _ in 0..mask_row_bytes { // Apply the bits of each byte until we reach the end of the row. - let mask_byte = try!(r.read_u8()); + let mask_byte = r.read_u8()?; for bit in (0..8).rev() { if x >= width { break; diff --git a/third_party/rust/image/src/ico/encoder.rs b/third_party/rust/image/src/ico/encoder.rs index 6d49eb8ad1d5..fe32499d6b9e 100644 --- a/third_party/rust/image/src/ico/encoder.rs +++ b/third_party/rust/image/src/ico/encoder.rs @@ -34,9 +34,9 @@ impl ICOEncoder { color: ColorType, ) -> io::Result<()> { let mut image_data: Vec = Vec::new(); - try!(PNGEncoder::new(&mut image_data).encode(data, width, height, color)); + PNGEncoder::new(&mut image_data).encode(data, width, height, color)?; - try!(write_icondir(&mut self.w, 1)); + write_icondir(&mut self.w, 1)?; try!(write_direntry( &mut self.w, width, @@ -45,18 +45,18 @@ impl ICOEncoder { ICO_ICONDIR_SIZE + ICO_DIRENTRY_SIZE, image_data.len() as u32 )); - try!(self.w.write_all(&image_data)); + self.w.write_all(&image_data)?; Ok(()) } } fn write_icondir(w: &mut W, num_images: u16) -> io::Result<()> { // Reserved field (must be zero): - try!(w.write_u16::(0)); + w.write_u16::(0)?; // Image type (ICO or CUR): - try!(w.write_u16::(ICO_IMAGE_TYPE)); + w.write_u16::(ICO_IMAGE_TYPE)?; // Number of images in the file: - try!(w.write_u16::(num_images)); + w.write_u16::(num_images)?; Ok(()) } @@ -69,20 +69,20 @@ fn write_direntry( data_size: u32, ) -> io::Result<()> { // Image dimensions: - try!(write_width_or_height(w, width)); - try!(write_width_or_height(w, height)); + write_width_or_height(w, width)?; + write_width_or_height(w, height)?; // Number of colors in palette (or zero for no palette): - try!(w.write_u8(0)); + w.write_u8(0)?; // Reserved field (must be zero): - try!(w.write_u8(0)); + w.write_u8(0)?; // Color planes: - try!(w.write_u16::(0)); + w.write_u16::(0)?; // Bits per pixel: - try!(w.write_u16::(bits_per_pixel(color) as u16)); + w.write_u16::(bits_per_pixel(color) as u16)?; // Image data size, in bytes: - try!(w.write_u32::(data_size)); + w.write_u32::(data_size)?; // Image data offset, in bytes: - try!(w.write_u32::(data_start)); + w.write_u32::(data_start)?; Ok(()) } diff --git a/third_party/rust/image/src/image.rs b/third_party/rust/image/src/image.rs index f5d900f92578..0ff9f33bdc36 100644 --- a/third_party/rust/image/src/image.rs +++ b/third_party/rust/image/src/image.rs @@ -2,7 +2,6 @@ use std::error::Error; use std::fmt; use std::io; use std::io::Read; -use std::mem; use std::ops::{Deref, DerefMut}; use buffer::{ImageBuffer, Pixel}; @@ -90,7 +89,7 @@ impl Error for ImageError { } } - fn cause(&self) -> Option<&Error> { + fn cause(&self) -> Option<&dyn Error> { match *self { ImageError::IoError(ref e) => Some(e), _ => None, @@ -264,12 +263,12 @@ impl ImageReadBuffer { /// Decodes a specific region of the image, represented by the rectangle /// starting from ```x``` and ```y``` and having ```length``` and ```width``` -pub(crate) fn load_rect(x: u64, y: u64, width: u64, height: u64, buf: &mut [u8], - progress_callback: F, - decoder: &mut D, - mut seek_scanline: F1, - mut read_scanline: F2) -> ImageResult<()> - where D: ImageDecoder, +pub(crate) fn load_rect<'a, D, F, F1, F2>(x: u64, y: u64, width: u64, height: u64, buf: &mut [u8], + progress_callback: F, + decoder: &mut D, + mut seek_scanline: F1, + mut read_scanline: F2) -> ImageResult<()> + where D: ImageDecoder<'a>, F: Fn(Progress), F1: FnMut(&mut D, u64) -> io::Result<()>, F2: FnMut(&mut D, &mut [u8]) -> io::Result @@ -359,9 +358,9 @@ pub struct Progress { } /// The trait that all decoders implement -pub trait ImageDecoder: Sized { +pub trait ImageDecoder<'a>: Sized { /// The type of reader produced by `into_reader`. - type Reader: Read; + type Reader: Read + 'a; /// Returns a tuple containing the width and height of the image fn dimensions(&self) -> (u64, u64); @@ -435,7 +434,7 @@ pub trait ImageDecoder: Sized { } /// ImageDecoderExt trait -pub trait ImageDecoderExt: ImageDecoder + Sized { +pub trait ImageDecoderExt<'a>: ImageDecoder<'a> + Sized { /// Read a rectangular section of the image. fn read_rect( &mut self, @@ -497,48 +496,6 @@ impl<'a, I: GenericImageView> Iterator for Pixels<'a, I> { } } -/// Mutable pixel iterator -/// -/// DEPRECATED: It is currently not possible to create a safe iterator for this in Rust. You have to use an iterator over the image buffer instead. -pub struct MutPixels<'a, I: ?Sized + 'a> { - image: &'a mut I, - x: u32, - y: u32, - width: u32, - height: u32, -} - -impl<'a, I: GenericImage + 'a> Iterator for MutPixels<'a, I> -where - I::Pixel: 'a, - ::Subpixel: 'a, -{ - type Item = (u32, u32, &'a mut I::Pixel); - - fn next(&mut self) -> Option<(u32, u32, &'a mut I::Pixel)> { - if self.x >= self.width { - self.x = 0; - self.y += 1; - } - - if self.y >= self.height { - None - } else { - let tmp = self.image.get_pixel_mut(self.x, self.y); - - // NOTE: This is potentially dangerous. It would require the signature fn next(&'a mut self) to be safe. - // error: lifetime of `self` is too short to guarantee its contents can be safely reborrowed... - let ptr = unsafe { mem::transmute(tmp) }; - - let p = (self.x, self.y, ptr); - - self.x += 1; - - Some(p) - } - } -} - /// Trait to inspect an image. pub trait GenericImageView { /// The type of pixel. @@ -585,6 +542,7 @@ pub trait GenericImageView { /// Returns the pixel located at (x, y) /// /// This function can be implemented in a way that ignores bounds checking. + #[deprecated = "Generally offers little advantage over get_pixel. If you must, prefer dedicated methods or other realizations on the specific image type instead."] unsafe fn unsafe_get_pixel(&self, x: u32, y: u32) -> Self::Pixel { self.get_pixel(x, y) } @@ -637,6 +595,7 @@ pub trait GenericImage: GenericImageView { /// Puts a pixel at location (x, y) /// /// This function can be implemented in a way that ignores bounds checking. + #[deprecated = "Generally offers little advantage over put_pixel. If you must, prefer dedicated methods or other realizations on the specific image type instead."] unsafe fn unsafe_put_pixel(&mut self, x: u32, y: u32, pixel: Self::Pixel) { self.put_pixel(x, y, pixel); } @@ -646,24 +605,6 @@ pub trait GenericImage: GenericImageView { /// DEPRECATED: This method will be removed. Blend the pixel directly instead. fn blend_pixel(&mut self, x: u32, y: u32, pixel: Self::Pixel); - /// Returns an Iterator over mutable pixels of this image. - /// The iterator yields the coordinates of each pixel - /// along with a mutable reference to them. - #[deprecated( - note = "This cannot be implemented safely in Rust. Please use the image buffer directly." - )] - fn pixels_mut(&mut self) -> MutPixels { - let (width, height) = self.dimensions(); - - MutPixels { - image: self, - x: 0, - y: 0, - width, - height, - } - } - /// Copies all of the pixels from another image into this image. /// /// The other image is copied with the top-left corner of the @@ -686,10 +627,8 @@ pub trait GenericImage: GenericImageView { for i in 0..other.width() { for k in 0..other.height() { - unsafe { - let p = other.unsafe_get_pixel(i, k); - self.unsafe_put_pixel(i + x, k + y, p); - } + let p = other.get_pixel(i, k); + self.put_pixel(i + x, k + y, p); } } true @@ -839,8 +778,9 @@ where #[cfg(test)] mod tests { + use std::io; - use super::{GenericImage, GenericImageView}; + use super::{ColorType, ImageDecoder, ImageResult, GenericImage, GenericImageView, load_rect}; use buffer::ImageBuffer; use color::Rgba; @@ -913,11 +853,9 @@ mod tests { #[test] fn test_load_rect() { - use super::*; - struct MockDecoder {scanline_number: u64, scanline_bytes: u64} - impl ImageDecoder for MockDecoder { - type Reader = Box<::std::io::Read>; + impl<'a> ImageDecoder<'a> for MockDecoder { + type Reader = Box; fn dimensions(&self) -> (u64, u64) {(5, 5)} fn colortype(&self) -> ColorType { ColorType::Gray(8) } fn into_reader(self) -> ImageResult {unimplemented!()} diff --git a/third_party/rust/image/src/imageops/affine.rs b/third_party/rust/image/src/imageops/affine.rs index f6a284f05097..29fa07040610 100644 --- a/third_party/rust/image/src/imageops/affine.rs +++ b/third_party/rust/image/src/imageops/affine.rs @@ -4,13 +4,10 @@ use buffer::{ImageBuffer, Pixel}; use image::GenericImageView; /// Rotate an image 90 degrees clockwise. -// TODO: Is the 'static bound on `I` really required? Can we avoid it? -pub fn rotate90( +pub fn rotate90( image: &I, ) -> ImageBuffer::Subpixel>> -where - I::Pixel: 'static, - ::Subpixel: 'static, + where I::Pixel: 'static, { let (width, height) = image.dimensions(); let mut out = ImageBuffer::new(height, width); @@ -26,13 +23,10 @@ where } /// Rotate an image 180 degrees clockwise. -// TODO: Is the 'static bound on `I` really required? Can we avoid it? -pub fn rotate180( +pub fn rotate180( image: &I, ) -> ImageBuffer::Subpixel>> -where - I::Pixel: 'static, - ::Subpixel: 'static, + where I::Pixel: 'static, { let (width, height) = image.dimensions(); let mut out = ImageBuffer::new(width, height); @@ -48,13 +42,10 @@ where } /// Rotate an image 270 degrees clockwise. -// TODO: Is the 'static bound on `I` really required? Can we avoid it? -pub fn rotate270( +pub fn rotate270( image: &I, ) -> ImageBuffer::Subpixel>> -where - I::Pixel: 'static, - ::Subpixel: 'static, + where I::Pixel: 'static, { let (width, height) = image.dimensions(); let mut out = ImageBuffer::new(height, width); @@ -70,13 +61,10 @@ where } /// Flip an image horizontally -// TODO: Is the 'static bound on `I` really required? Can we avoid it? -pub fn flip_horizontal( +pub fn flip_horizontal( image: &I, ) -> ImageBuffer::Subpixel>> -where - I::Pixel: 'static, - ::Subpixel: 'static, + where I::Pixel: 'static, { let (width, height) = image.dimensions(); let mut out = ImageBuffer::new(width, height); @@ -92,13 +80,10 @@ where } /// Flip an image vertically -// TODO: Is the 'static bound on `I` really required? Can we avoid it? -pub fn flip_vertical( +pub fn flip_vertical( image: &I, ) -> ImageBuffer::Subpixel>> -where - I::Pixel: 'static, - ::Subpixel: 'static, + where I::Pixel: 'static, { let (width, height) = image.dimensions(); let mut out = ImageBuffer::new(width, height); diff --git a/third_party/rust/image/src/imageops/colorops.rs b/third_party/rust/image/src/imageops/colorops.rs index f1a91142b8ed..053b8271b291 100644 --- a/third_party/rust/image/src/imageops/colorops.rs +++ b/third_party/rust/image/src/imageops/colorops.rs @@ -196,7 +196,7 @@ impl ColorMap for BiLevel { #[inline(always)] fn index_of(&self, color: &Luma) -> usize { - let luma = color.data; + let luma = color.0; if luma[0] > 127 { 1 } else { @@ -207,7 +207,7 @@ impl ColorMap for BiLevel { #[inline(always)] fn map_color(&self, color: &mut Luma) { let new_color = 0xFF * self.index_of(color) as u8; - let luma = &mut color.data; + let luma = &mut color.0; luma[0] = new_color; } } diff --git a/third_party/rust/image/src/imageops/mod.rs b/third_party/rust/image/src/imageops/mod.rs index 922bf0ca3d65..83c1de5d4a22 100644 --- a/third_party/rust/image/src/imageops/mod.rs +++ b/third_party/rust/image/src/imageops/mod.rs @@ -117,7 +117,11 @@ pub fn overlay_bounds( } /// Overlay an image at a given coordinate (x, y) -pub fn overlay(bottom: &mut I, top: &I, x: u32, y: u32) { +pub fn overlay(bottom: &mut I, top: &J, x: u32, y: u32) +where + I: GenericImage, + J: GenericImageView, +{ let bottom_dims = bottom.dimensions(); let top_dims = top.dimensions(); @@ -136,7 +140,11 @@ pub fn overlay(bottom: &mut I, top: &I, x: u32, y: u32) { } /// Replace the contents of an image at a given coordinate (x, y) -pub fn replace(bottom: &mut I, top: &I, x: u32, y: u32) { +pub fn replace(bottom: &mut I, top: &J, x: u32, y: u32) +where + I: GenericImage, + J: GenericImageView, +{ let bottom_dims = bottom.dimensions(); let top_dims = top.dimensions(); diff --git a/third_party/rust/image/src/imageops/sample.rs b/third_party/rust/image/src/imageops/sample.rs index b712da21eddb..f085e558c91c 100644 --- a/third_party/rust/image/src/imageops/sample.rs +++ b/third_party/rust/image/src/imageops/sample.rs @@ -13,7 +13,7 @@ use math::utils::clamp; use traits::{Enlargeable, Primitive}; /// Available Sampling Filters -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Debug)] pub enum FilterType { /// Nearest Neighbor Nearest, @@ -34,7 +34,7 @@ pub enum FilterType { /// A Representation of a separable filter. pub struct Filter<'a> { /// The filter's filter function. - pub kernel: Box f32 + 'a>, + pub kernel: Box f32 + 'a>, /// The window on which this filter operates. pub support: f32, @@ -122,14 +122,13 @@ pub fn box_kernel(_x: f32) -> f32 { // The height of the image remains unchanged. // ```new_width``` is the desired width of the new image // ```filter``` is the filter to use for sampling. -// TODO: Do we really need the 'static bound on `I`? Can we avoid it? fn horizontal_sample( image: &I, new_width: u32, filter: &mut Filter, ) -> ImageBuffer> where - I: GenericImageView + 'static, + I: GenericImageView, P: Pixel + 'static, S: Primitive + 'static, { @@ -214,14 +213,13 @@ where // The width of the image remains unchanged. // ```new_height``` is the desired height of the new image // ```filter``` is the filter to use for sampling. -// TODO: Do we really need the 'static bound on `I`? Can we avoid it? fn vertical_sample( image: &I, new_height: u32, filter: &mut Filter, ) -> ImageBuffer> where - I: GenericImageView + 'static, + I: GenericImageView, P: Pixel + 'static, S: Primitive + 'static, { @@ -566,10 +564,9 @@ where /// Perform a 3x3 box filter on the supplied image. /// ```kernel``` is an array of the filter weights of length 9. -// TODO: Do we really need the 'static bound on `I`? Can we avoid it? pub fn filter3x3(image: &I, kernel: &[f32]) -> ImageBuffer> where - I: GenericImageView + 'static, + I: GenericImageView, P: Pixel + 'static, S: Primitive + 'static, { @@ -647,8 +644,7 @@ where /// Resize the supplied image to the specified dimensions. /// ```nwidth``` and ```nheight``` are the new dimensions. /// ```filter``` is the sampling filter to use. -// TODO: Do we really need the 'static bound on `I`? Can we avoid it? -pub fn resize( +pub fn resize( image: &I, nwidth: u32, nheight: u32, @@ -687,14 +683,12 @@ where /// Performs a Gaussian blur on the supplied image. /// ```sigma``` is a measure of how much to blur by. -// TODO: Do we really need the 'static bound on `I`? Can we avoid it? -pub fn blur( +pub fn blur( image: &I, sigma: f32, ) -> ImageBuffer::Subpixel>> where I::Pixel: 'static, - ::Subpixel: 'static, { let sigma = if sigma < 0.0 { 1.0 } else { sigma }; @@ -716,10 +710,9 @@ where /// ```threshold``` is the threshold for the difference between /// /// See -// TODO: Do we really need the 'static bound on `I`? Can we avoid it? pub fn unsharpen(image: &I, sigma: f32, threshold: i32) -> ImageBuffer> where - I: GenericImageView + 'static, + I: GenericImageView, P: Pixel + 'static, S: Primitive + 'static, { diff --git a/third_party/rust/image/src/jpeg/decoder.rs b/third_party/rust/image/src/jpeg/decoder.rs index 7d20e02be67c..4f6eb9f13afc 100644 --- a/third_party/rust/image/src/jpeg/decoder.rs +++ b/third_party/rust/image/src/jpeg/decoder.rs @@ -1,6 +1,8 @@ extern crate jpeg_decoder; -use std::io::{Cursor, Read}; +use std::io::{self, Cursor, Read}; +use std::marker::PhantomData; +use std::mem; use color::ColorType; use image::{ImageDecoder, ImageError, ImageResult}; @@ -31,8 +33,24 @@ impl JPEGDecoder { } } -impl ImageDecoder for JPEGDecoder { - type Reader = Cursor>; +/// Wrapper struct around a `Cursor>` +pub struct JpegReader(Cursor>, PhantomData); +impl Read for JpegReader { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + self.0.read(buf) + } + fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { + if self.0.position() == 0 && buf.is_empty() { + mem::swap(buf, self.0.get_mut()); + Ok(buf.len()) + } else { + self.0.read_to_end(buf) + } + } +} + +impl<'a, R: 'a + Read> ImageDecoder<'a> for JPEGDecoder { + type Reader = JpegReader; fn dimensions(&self) -> (u64, u64) { (self.metadata.width as u64, self.metadata.height as u64) @@ -43,7 +61,7 @@ impl ImageDecoder for JPEGDecoder { } fn into_reader(self) -> ImageResult { - Ok(Cursor::new(self.read_image()?)) + Ok(JpegReader(Cursor::new(self.read_image()?), PhantomData)) } fn read_image(mut self) -> ImageResult> { diff --git a/third_party/rust/image/src/jpeg/encoder.rs b/third_party/rust/image/src/jpeg/encoder.rs index 716f72ac65c8..ffb08a74a68c 100644 --- a/third_party/rust/image/src/jpeg/encoder.rs +++ b/third_party/rust/image/src/jpeg/encoder.rs @@ -182,10 +182,10 @@ impl<'a, W: Write + 'a> BitWriter<'a, W> { while self.nbits >= 8 { let byte = (self.accumulator & (0xFFFF_FFFFu32 << 24)) >> 24; - try!(self.w.write_all(&[byte as u8])); + self.w.write_all(&[byte as u8])?; if byte == 0xFF { - try!(self.w.write_all(&[0x00])); + self.w.write_all(&[0x00])?; } self.nbits -= 8; @@ -221,8 +221,8 @@ impl<'a, W: Write + 'a> BitWriter<'a, W> { let diff = dcval - prevdc; let (size, value) = encode_coefficient(diff); - try!(self.huffman_encode(size, dctable)); - try!(self.write_bits(value, size)); + self.huffman_encode(size, dctable)?; + self.write_bits(value, size)?; // Figure F.2 let mut zero_run = 0; @@ -233,22 +233,22 @@ impl<'a, W: Write + 'a> BitWriter<'a, W> { if block[UNZIGZAG[k] as usize] == 0 { if k == 63 { - try!(self.huffman_encode(0x00, actable)); + self.huffman_encode(0x00, actable)?; break; } zero_run += 1; } else { while zero_run > 15 { - try!(self.huffman_encode(0xF0, actable)); + self.huffman_encode(0xF0, actable)?; zero_run -= 16; } let (size, value) = encode_coefficient(block[UNZIGZAG[k] as usize]); let symbol = (zero_run << 4) | size; - try!(self.huffman_encode(symbol, actable)); - try!(self.write_bits(value, size)); + self.huffman_encode(symbol, actable)?; + self.write_bits(value, size)?; zero_run = 0; @@ -262,12 +262,12 @@ impl<'a, W: Write + 'a> BitWriter<'a, W> { } fn write_segment(&mut self, marker: u8, data: Option<&[u8]>) -> io::Result<()> { - try!(self.w.write_all(&[0xFF])); - try!(self.w.write_all(&[marker])); + self.w.write_all(&[0xFF])?; + self.w.write_all(&[marker])?; if let Some(b) = data { - try!(self.w.write_u16::(b.len() as u16 + 2)); - try!(self.w.write_all(b)); + self.w.write_u16::(b.len() as u16 + 2)?; + self.w.write_all(b)?; } Ok(()) } @@ -377,12 +377,12 @@ impl<'a, W: Write> JPEGEncoder<'a, W> { let n = color::num_components(c); let num_components = if n == 1 || n == 2 { 1 } else { 3 }; - try!(self.writer.write_segment(SOI, None)); + self.writer.write_segment(SOI, None)?; let mut buf = Vec::new(); build_jfif_header(&mut buf); - try!(self.writer.write_segment(APP0, Some(&buf))); + self.writer.write_segment(APP0, Some(&buf))?; build_frame_header( &mut buf, @@ -391,14 +391,14 @@ impl<'a, W: Write> JPEGEncoder<'a, W> { height as u16, &self.components[..num_components], ); - try!(self.writer.write_segment(SOF0, Some(&buf))); + self.writer.write_segment(SOF0, Some(&buf))?; assert_eq!(self.tables.len() / 64, 2); let numtables = if num_components == 1 { 1 } else { 2 }; for (i, table) in self.tables.chunks(64).enumerate().take(numtables) { build_quantization_segment(&mut buf, 8, i as u8, table); - try!(self.writer.write_segment(DQT, Some(&buf))); + self.writer.write_segment(DQT, Some(&buf))?; } build_huffman_segment( @@ -408,7 +408,7 @@ impl<'a, W: Write> JPEGEncoder<'a, W> { &STD_LUMA_DC_CODE_LENGTHS, &STD_LUMA_DC_VALUES, ); - try!(self.writer.write_segment(DHT, Some(&buf))); + self.writer.write_segment(DHT, Some(&buf))?; build_huffman_segment( &mut buf, @@ -417,7 +417,7 @@ impl<'a, W: Write> JPEGEncoder<'a, W> { &STD_LUMA_AC_CODE_LENGTHS, &STD_LUMA_AC_VALUES, ); - try!(self.writer.write_segment(DHT, Some(&buf))); + self.writer.write_segment(DHT, Some(&buf))?; if num_components == 3 { build_huffman_segment( @@ -427,7 +427,7 @@ impl<'a, W: Write> JPEGEncoder<'a, W> { &STD_CHROMA_DC_CODE_LENGTHS, &STD_CHROMA_DC_VALUES, ); - try!(self.writer.write_segment(DHT, Some(&buf))); + self.writer.write_segment(DHT, Some(&buf))?; build_huffman_segment( &mut buf, @@ -436,24 +436,24 @@ impl<'a, W: Write> JPEGEncoder<'a, W> { &STD_CHROMA_AC_CODE_LENGTHS, &STD_CHROMA_AC_VALUES, ); - try!(self.writer.write_segment(DHT, Some(&buf))); + self.writer.write_segment(DHT, Some(&buf))?; } build_scan_header(&mut buf, &self.components[..num_components]); - try!(self.writer.write_segment(SOS, Some(&buf))); + self.writer.write_segment(SOS, Some(&buf))?; match c { color::ColorType::RGB(8) => { - try!(self.encode_rgb(image, width as usize, height as usize, 3)) + self.encode_rgb(image, width as usize, height as usize, 3)? } color::ColorType::RGBA(8) => { - try!(self.encode_rgb(image, width as usize, height as usize, 4)) + self.encode_rgb(image, width as usize, height as usize, 4)? } color::ColorType::Gray(8) => { - try!(self.encode_gray(image, width as usize, height as usize, 1)) + self.encode_gray(image, width as usize, height as usize, 1)? } color::ColorType::GrayA(8) => { - try!(self.encode_gray(image, width as usize, height as usize, 2)) + self.encode_gray(image, width as usize, height as usize, 2)? } _ => { return Err(io::Error::new( @@ -466,8 +466,8 @@ impl<'a, W: Write> JPEGEncoder<'a, W> { } }; - try!(self.writer.pad_byte()); - try!(self.writer.write_segment(EOI, None)); + self.writer.pad_byte()?; + self.writer.write_segment(EOI, None)?; Ok(()) } @@ -499,7 +499,7 @@ impl<'a, W: Write> JPEGEncoder<'a, W> { let la = &*self.luma_actable; let ld = &*self.luma_dctable; - y_dcprev = try!(self.writer.write_block(&dct_yblock, y_dcprev, ld, la)); + y_dcprev = self.writer.write_block(&dct_yblock, y_dcprev, ld, la)?; } } @@ -562,9 +562,9 @@ impl<'a, W: Write> JPEGEncoder<'a, W> { let cd = &*self.chroma_dctable; let ca = &*self.chroma_actable; - y_dcprev = try!(self.writer.write_block(&dct_yblock, y_dcprev, ld, la)); - cb_dcprev = try!(self.writer.write_block(&dct_cb_block, cb_dcprev, cd, ca)); - cr_dcprev = try!(self.writer.write_block(&dct_cr_block, cr_dcprev, cd, ca)); + y_dcprev = self.writer.write_block(&dct_yblock, y_dcprev, ld, la)?; + cb_dcprev = self.writer.write_block(&dct_cb_block, cb_dcprev, cd, ca)?; + cr_dcprev = self.writer.write_block(&dct_cr_block, cr_dcprev, cd, ca)?; } } diff --git a/third_party/rust/image/src/lib.rs b/third_party/rust/image/src/lib.rs index e131e3d7741f..31bcdf893be3 100644 --- a/third_party/rust/image/src/lib.rs +++ b/third_party/rust/image/src/lib.rs @@ -14,6 +14,8 @@ extern crate lzw; extern crate num_iter; extern crate num_rational; extern crate num_traits; +#[cfg(feature = "hdr")] +extern crate scoped_threadpool; #[cfg(all(test, feature = "benchmarks"))] extern crate test; @@ -34,7 +36,6 @@ pub use image::{AnimationDecoder, ImageDecoderExt, ImageError, ImageResult, - MutPixels, // Iterators Pixels, SubImage}; @@ -61,7 +62,7 @@ pub use traits::Primitive; // Opening and loading images pub use dynimage::{guess_format, load, load_from_memory, load_from_memory_with_format, open, - save_buffer}; + save_buffer, save_buffer_with_format, image_dimensions}; pub use dynimage::DynamicImage::{self, ImageLuma8, ImageLumaA8, ImageRgb8, ImageRgba8, ImageBgr8, ImageBgra8}; @@ -108,6 +109,24 @@ mod image; mod traits; mod utils; +// Can't use the macro-call itself within the `doc` attribute. So force it to eval it as part of +// the macro invocation. +// +// The inspiration for the macro and implementation is from +// +// +// MIT License +// +// Copyright (c) 2018 Guillaume Gomez +macro_rules! insert_as_doc { + { $content:expr } => { + #[doc = $content] extern { } + } +} + +// Provides the README.md as doc, to ensure the example works! +insert_as_doc!(include_str!("../README.md")); + // Copies data from `src` to `dst` // // Panics if the length of `dst` is less than the length of `src`. diff --git a/third_party/rust/image/src/math/nq.rs b/third_party/rust/image/src/math/nq.rs index cf0f2b4e5236..fdb49f706a33 100644 --- a/third_party/rust/image/src/math/nq.rs +++ b/third_party/rust/image/src/math/nq.rs @@ -2,7 +2,7 @@ //! See "Kohonen neural networks for optimal colour quantization" //! in "Network: Computation in Neural Systems" Vol. 5 (1994) pp 351-367. //! for a discussion of the algorithm. -//! See also +//! See also /* NeuQuant Neural-Net Quantization Algorithm * ------------------------------------------ @@ -13,7 +13,7 @@ * See "Kohonen neural networks for optimal colour quantization" * in "Network: Computation in Neural Systems" Vol. 5 (1994) pp 351-367. * for a discussion of the algorithm. - * See also http://www.acm.org/~dekker/NEUQUANT.HTML + * See also https://scientificgems.wordpress.com/stuff/neuquant-fast-high-quality-image-quantization/ * * Any party obtaining a copy of these files from the author, directly or * indirectly, is granted, free of charge, a full and unrestricted irrevocable, diff --git a/third_party/rust/image/src/png.rs b/third_party/rust/image/src/png.rs index cc0111c7c74e..d19a06762aad 100644 --- a/third_party/rust/image/src/png.rs +++ b/third_party/rust/image/src/png.rs @@ -8,13 +8,86 @@ extern crate png; -use self::png::HasParameters; - -use std::io::{self, Cursor, Read, Write}; +use std::io::{self, Read, Write}; use color::ColorType; use image::{ImageDecoder, ImageError, ImageResult}; +/// PNG Reader +/// +/// This reader will try to read the png one row at a time, +/// however for interlaced png files this is not posible and +/// these are therefore readed at once. +pub struct PNGReader { + reader: png::Reader, + buffer: Vec, + index: usize, +} + +impl PNGReader { + fn new(mut reader: png::Reader) -> ImageResult> { + let len = reader.output_buffer_size(); + // Since interlaced images do not come in + // scanline order it is almost impossible to + // read them in a streaming fashion, however + // this shouldn't be a too big of a problem + // as most interlaced images should fit in memory. + let buffer = if reader.info().interlaced { + let mut buffer = vec![0; len]; + reader.next_frame(&mut buffer)?; + buffer + } else { + Vec::new() + }; + + Ok(PNGReader { + reader, + buffer, + index: 0, + }) + } +} + +impl Read for PNGReader { + fn read(&mut self, mut buf: &mut [u8]) -> io::Result { + // io::Write::write for slice cannot fail + let readed = buf.write(&self.buffer[self.index..]).unwrap(); + + let mut bytes = readed; + self.index += readed; + + while self.index + 1 >= self.buffer.len() { + match self.reader.next_row()? { + Some(row) => { + // Faster to copy directly to external buffer + let readed = buf.write(row).unwrap(); + bytes += readed; + + self.buffer = (&row[readed..]).to_owned(); + self.index = 0; + } + None => return Ok(bytes) + } + } + + Ok(bytes) + } + + fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { + let mut bytes = self.buffer.len(); + buf.extend_from_slice(&self.buffer); + self.buffer = Vec::new(); + self.index = 0; + + while let Some(row) = self.reader.next_row()? { + buf.extend_from_slice(row); + bytes += row.len(); + } + + Ok(bytes) + } +} + /// PNG decoder pub struct PNGDecoder { colortype: ColorType, @@ -24,7 +97,10 @@ pub struct PNGDecoder { impl PNGDecoder { /// Creates a new decoder that decodes from the stream ```r``` pub fn new(r: R) -> ImageResult> { - let decoder = png::Decoder::new(r); + let limits = png::Limits { + bytes: usize::max_value(), + }; + let decoder = png::Decoder::new_with_limits(r, limits); let (_, mut reader) = decoder.read_info()?; let colortype = reader.output_color_type().into(); @@ -32,8 +108,8 @@ impl PNGDecoder { } } -impl ImageDecoder for PNGDecoder { - type Reader = Cursor>; +impl<'a, R: 'a + Read> ImageDecoder<'a> for PNGDecoder { + type Reader = PNGReader; fn dimensions(&self) -> (u64, u64) { let (w, h) = self.reader.info().size(); @@ -45,14 +121,20 @@ impl ImageDecoder for PNGDecoder { } fn into_reader(self) -> ImageResult { - Ok(Cursor::new(self.read_image()?)) + PNGReader::new(self.reader) } fn read_image(mut self) -> ImageResult> { + // This should be slightly faster than the default implementation let mut data = vec![0; self.reader.output_buffer_size()]; self.reader.next_frame(&mut data)?; Ok(data) } + + fn scanline_bytes(&self) -> u64 { + let width = self.reader.info().width; + self.reader.output_line_size(width) as u64 + } } /// PNG encoder @@ -72,8 +154,9 @@ impl PNGEncoder { pub fn encode(self, data: &[u8], width: u32, height: u32, color: ColorType) -> io::Result<()> { let (ct, bits) = color.into(); let mut encoder = png::Encoder::new(self.w, width, height); - encoder.set(ct).set(bits); - let mut writer = try!(encoder.write_header()); + encoder.set_color(ct); + encoder.set_depth(bits); + let mut writer = encoder.write_header()?; writer.write_image_data(data).map_err(|e| e.into()) } } @@ -120,6 +203,7 @@ impl From for ImageError { CorruptFlateStream => { ImageError::FormatError("compressed data stream corrupted".into()) } + LimitsExceeded => ImageError::InsufficientMemory, } } } diff --git a/third_party/rust/image/src/pnm/decoder.rs b/third_party/rust/image/src/pnm/decoder.rs index 799aebfd15b4..4f7686e3907a 100644 --- a/third_party/rust/image/src/pnm/decoder.rs +++ b/third_party/rust/image/src/pnm/decoder.rs @@ -1,6 +1,8 @@ use std::io::{self, BufRead, BufReader, Cursor, Read}; use std::str::{self, FromStr}; use std::fmt::Display; +use std::marker::PhantomData; +use std::mem; use super::{ArbitraryHeader, ArbitraryTuplType, BitmapHeader, GraymapHeader, PixmapHeader}; use super::{HeaderRecord, PNMHeader, PNMSubtype, SampleEncoding}; @@ -27,7 +29,7 @@ trait Sample { fn from_bytes(bytes: &[u8], width: u32, height: u32, samples: u32) -> ImageResult>; - fn from_ascii(reader: &mut Read, width: u32, height: u32, samples: u32) + fn from_ascii(reader: &mut dyn Read, width: u32, height: u32, samples: u32) -> ImageResult>; } @@ -406,8 +408,24 @@ trait HeaderReader: BufRead { impl HeaderReader for BufReader {} -impl ImageDecoder for PNMDecoder { - type Reader = Cursor>; +/// Wrapper struct around a `Cursor>` +pub struct PnmReader(Cursor>, PhantomData); +impl Read for PnmReader { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + self.0.read(buf) + } + fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { + if self.0.position() == 0 && buf.is_empty() { + mem::swap(buf, self.0.get_mut()); + Ok(buf.len()) + } else { + self.0.read_to_end(buf) + } + } +} + +impl<'a, R: 'a + Read> ImageDecoder<'a> for PNMDecoder { + type Reader = PnmReader; fn dimensions(&self) -> (u64, u64) { (self.header.width() as u64, self.header.height() as u64) @@ -418,7 +436,7 @@ impl ImageDecoder for PNMDecoder { } fn into_reader(self) -> ImageResult { - Ok(Cursor::new(self.read_image()?)) + Ok(PnmReader(Cursor::new(self.read_image()?), PhantomData)) } fn read_image(mut self) -> ImageResult> { @@ -482,7 +500,7 @@ impl TupleType { } } -fn read_separated_ascii(reader: &mut Read) -> ImageResult +fn read_separated_ascii(reader: &mut dyn Read) -> ImageResult where T::Err: Display { let is_separator = |v: &u8| match *v { @@ -529,7 +547,7 @@ impl Sample for U8 { } fn from_ascii( - reader: &mut Read, + reader: &mut dyn Read, width: u32, height: u32, samples: u32, @@ -562,7 +580,7 @@ impl Sample for U16 { } fn from_ascii( - reader: &mut Read, + reader: &mut dyn Read, width: u32, height: u32, samples: u32, @@ -596,7 +614,7 @@ impl Sample for PbmBit { } fn from_ascii( - reader: &mut Read, + reader: &mut dyn Read, width: u32, height: u32, samples: u32, @@ -650,7 +668,7 @@ impl Sample for BWBit { } fn from_ascii( - _reader: &mut Read, + _reader: &mut dyn Read, _width: u32, _height: u32, _samples: u32, diff --git a/third_party/rust/image/src/pnm/encoder.rs b/third_party/rust/image/src/pnm/encoder.rs index c41a4decffc6..dd503423238c 100644 --- a/third_party/rust/image/src/pnm/encoder.rs +++ b/third_party/rust/image/src/pnm/encoder.rs @@ -170,10 +170,10 @@ impl PNMEncoder { let (maxval, tupltype) = match color { ColorType::Gray(1) => (1, ArbitraryTuplType::BlackAndWhite), ColorType::GrayA(1) => (1, ArbitraryTuplType::BlackAndWhiteAlpha), - ColorType::Gray(n @ 1...16) => ((1 << n) - 1, ArbitraryTuplType::Grayscale), - ColorType::GrayA(n @ 1...16) => ((1 << n) - 1, ArbitraryTuplType::GrayscaleAlpha), - ColorType::RGB(n @ 1...16) => ((1 << n) - 1, ArbitraryTuplType::RGB), - ColorType::RGBA(n @ 1...16) => ((1 << n) - 1, ArbitraryTuplType::RGBAlpha), + ColorType::Gray(n @ 1..=16) => ((1 << n) - 1, ArbitraryTuplType::Grayscale), + ColorType::GrayA(n @ 1..=16) => ((1 << n) - 1, ArbitraryTuplType::GrayscaleAlpha), + ColorType::RGB(n @ 1..=16) => ((1 << n) - 1, ArbitraryTuplType::RGB), + ColorType::RGBA(n @ 1..=16) => ((1 << n) - 1, ArbitraryTuplType::RGBAlpha), _ => { return Err(io::Error::new( io::ErrorKind::InvalidInput, @@ -251,7 +251,7 @@ impl PNMEncoder { /// /// Returns how the body should be written if successful. fn write_with_header( - writer: &mut Write, + writer: &mut dyn Write, header: &PNMHeader, image: FlatSamples, width: u32, @@ -472,7 +472,7 @@ impl<'a> CheckedHeaderColor<'a> { } impl<'a> CheckedHeader<'a> { - fn write_header(self, writer: &mut Write) -> io::Result> { + fn write_header(self, writer: &mut dyn Write) -> io::Result> { self.header().write(writer)?; Ok(self.encoding) } @@ -482,7 +482,7 @@ impl<'a> CheckedHeader<'a> { } } -struct SampleWriter<'a>(&'a mut Write); +struct SampleWriter<'a>(&'a mut dyn Write); impl<'a> SampleWriter<'a> { fn write_samples_ascii(self, samples: V) -> io::Result<()> @@ -596,7 +596,7 @@ impl<'a> From<&'a [u16]> for FlatSamples<'a> { } impl<'a> TupleEncoding<'a> { - fn write_image(&self, writer: &mut Write) -> io::Result<()> { + fn write_image(&self, writer: &mut dyn Write) -> io::Result<()> { match *self { TupleEncoding::PbmBits { samples: FlatSamples::U8(samples), diff --git a/third_party/rust/image/src/pnm/header.rs b/third_party/rust/image/src/pnm/header.rs index 9e743aaa6ff3..927d8fa64cd5 100644 --- a/third_party/rust/image/src/pnm/header.rs +++ b/third_party/rust/image/src/pnm/header.rs @@ -232,7 +232,7 @@ impl PNMHeader { } /// Write the header back into a binary stream - pub fn write(&self, writer: &mut io::Write) -> io::Result<()> { + pub fn write(&self, writer: &mut dyn io::Write) -> io::Result<()> { writer.write_all(self.subtype().magic_constant())?; match *self { PNMHeader { diff --git a/third_party/rust/image/src/pnm/mod.rs b/third_party/rust/image/src/pnm/mod.rs index b2cc626fdc1d..a21ea2a6d1f5 100644 --- a/third_party/rust/image/src/pnm/mod.rs +++ b/third_party/rust/image/src/pnm/mod.rs @@ -34,7 +34,7 @@ mod tests { } let (header, loaded_color, loaded_image) = { - let mut decoder = PNMDecoder::new(&encoded_buffer[..]).unwrap(); + let decoder = PNMDecoder::new(&encoded_buffer[..]).unwrap(); let colortype = decoder.colortype(); let image = decoder.read_image().expect("Failed to decode the image"); let (_, header) = PNMDecoder::new(&encoded_buffer[..]).unwrap().into_inner(); @@ -64,7 +64,7 @@ mod tests { } let (header, loaded_color, loaded_image) = { - let mut decoder = PNMDecoder::new(&encoded_buffer[..]).unwrap(); + let decoder = PNMDecoder::new(&encoded_buffer[..]).unwrap(); let colortype = decoder.colortype(); let image = decoder.read_image().expect("Failed to decode the image"); let (_, header) = PNMDecoder::new(&encoded_buffer[..]).unwrap().into_inner(); @@ -89,7 +89,7 @@ mod tests { } let (header, loaded_color, loaded_image) = { - let mut decoder = PNMDecoder::new(&encoded_buffer[..]).unwrap(); + let decoder = PNMDecoder::new(&encoded_buffer[..]).unwrap(); let colortype = decoder.colortype(); let image = decoder.read_image().expect("Failed to decode the image"); let (_, header) = PNMDecoder::new(&encoded_buffer[..]).unwrap().into_inner(); diff --git a/third_party/rust/image/src/tga/decoder.rs b/third_party/rust/image/src/tga/decoder.rs index 449814799d9c..50c450c6bbec 100644 --- a/third_party/rust/image/src/tga/decoder.rs +++ b/third_party/rust/image/src/tga/decoder.rs @@ -101,20 +101,20 @@ impl Header { } /// Load the header with values from the reader - fn from_reader(r: &mut Read) -> ImageResult

{ + fn from_reader(r: &mut dyn Read) -> ImageResult
{ Ok(Header { - id_length: try!(r.read_u8()), - map_type: try!(r.read_u8()), - image_type: try!(r.read_u8()), - map_origin: try!(r.read_u16::()), - map_length: try!(r.read_u16::()), - map_entry_size: try!(r.read_u8()), - x_origin: try!(r.read_u16::()), - y_origin: try!(r.read_u16::()), - image_width: try!(r.read_u16::()), - image_height: try!(r.read_u16::()), - pixel_depth: try!(r.read_u8()), - image_desc: try!(r.read_u8()), + id_length: r.read_u8()?, + map_type: r.read_u8()?, + image_type: r.read_u8()?, + map_origin: r.read_u16::()?, + map_length: r.read_u16::()?, + map_entry_size: r.read_u8()?, + x_origin: r.read_u16::()?, + y_origin: r.read_u16::()?, + image_width: r.read_u16::()?, + image_height: r.read_u16::()?, + pixel_depth: r.read_u8()?, + image_desc: r.read_u8()?, }) } } @@ -128,7 +128,7 @@ struct ColorMap { impl ColorMap { pub fn from_reader( - r: &mut Read, + r: &mut dyn Read, start_offset: u16, num_entries: u16, bits_per_entry: u8, @@ -136,7 +136,7 @@ impl ColorMap { let bytes_per_entry = (bits_per_entry as usize + 7) / 8; let mut bytes = vec![0; bytes_per_entry * num_entries as usize]; - try!(r.read_exact(&mut bytes)); + r.read_exact(&mut bytes)?; Ok(ColorMap { entry_size: bytes_per_entry, @@ -197,7 +197,7 @@ impl TGADecoder { } fn read_header(&mut self) -> ImageResult<()> { - self.header = try!(Header::from_reader(&mut self.r)); + self.header = Header::from_reader(&mut self.r)?; self.image_type = ImageType::new(self.header.image_type); self.width = self.header.image_width as usize; self.height = self.header.image_height as usize; @@ -207,10 +207,10 @@ impl TGADecoder { fn read_metadata(&mut self) -> ImageResult<()> { if !self.has_loaded_metadata { - try!(self.read_header()); - try!(self.read_image_id()); - try!(self.read_color_map()); - try!(self.read_color_information()); + self.read_header()?; + self.read_image_id()?; + self.read_color_map()?; + self.read_color_information()?; self.has_loaded_metadata = true; } Ok(()) @@ -326,7 +326,7 @@ impl TGADecoder { } else { let num_raw_bytes = self.width * self.height * self.bytes_per_pixel; let mut buf = vec![0; num_raw_bytes]; - try!(self.r.by_ref().read_exact(&mut buf)); + self.r.by_ref().read_exact(&mut buf)?; buf }; @@ -347,7 +347,7 @@ impl TGADecoder { let mut pixel_data = Vec::with_capacity(num_bytes); while pixel_data.len() < num_bytes { - let run_packet = try!(self.r.read_u8()); + let run_packet = self.r.read_u8()?; // If the highest bit in `run_packet` is set, then we repeat pixels // // Note: the TGA format adds 1 to both counts because having a count @@ -498,7 +498,7 @@ impl TGADecoder { } } -impl ImageDecoder for TGADecoder { +impl<'a, R: 'a + Read + Seek> ImageDecoder<'a> for TGADecoder { type Reader = TGAReader; fn dimensions(&self) -> (u64, u64) { diff --git a/third_party/rust/image/src/tiff.rs b/third_party/rust/image/src/tiff.rs index a65b961a866a..453f013d1456 100644 --- a/third_party/rust/image/src/tiff.rs +++ b/third_party/rust/image/src/tiff.rs @@ -8,7 +8,9 @@ extern crate tiff; -use std::io::{Cursor, Read, Seek}; +use std::io::{self, Cursor, Read, Write, Seek}; +use std::marker::PhantomData; +use std::mem; use color::ColorType; use image::{ImageDecoder, ImageResult, ImageError}; @@ -46,6 +48,7 @@ impl From for ImageError { tiff::TiffError::IoError(err) => ImageError::IoError(err), tiff::TiffError::FormatError(desc) => ImageError::FormatError(desc.to_string()), tiff::TiffError::UnsupportedError(desc) => ImageError::UnsupportedError(desc.to_string()), + tiff::TiffError::LimitsExceeded => ImageError::InsufficientMemory, } } } @@ -63,8 +66,24 @@ impl From for ColorType { } } -impl ImageDecoder for TIFFDecoder { - type Reader = Cursor>; +/// Wrapper struct around a `Cursor>` +pub struct TiffReader(Cursor>, PhantomData); +impl Read for TiffReader { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + self.0.read(buf) + } + fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { + if self.0.position() == 0 && buf.is_empty() { + mem::swap(buf, self.0.get_mut()); + Ok(buf.len()) + } else { + self.0.read_to_end(buf) + } + } +} + +impl<'a, R: 'a + Read + Seek> ImageDecoder<'a> for TIFFDecoder { + type Reader = TiffReader; fn dimensions(&self) -> (u64, u64) { (self.dimensions.0 as u64, self.dimensions.1 as u64) @@ -75,7 +94,7 @@ impl ImageDecoder for TIFFDecoder { } fn into_reader(self) -> ImageResult { - Ok(Cursor::new(self.read_image()?)) + Ok(TiffReader(Cursor::new(self.read_image()?), PhantomData)) } fn read_image(mut self) -> ImageResult> { @@ -85,3 +104,33 @@ impl ImageDecoder for TIFFDecoder { } } } + +/// Encoder for tiff images +pub struct TiffEncoder { + w: W, +} + +impl TiffEncoder { + /// Create a new encoder that writes its output to `w` + pub fn new(w: W) -> TiffEncoder { + TiffEncoder { w } + } + + /// Encodes the image `image` + /// that has dimensions `width` and `height` + /// and `ColorType` `c`. + /// + /// 16-bit colortypes are not yet supported. + pub fn encode(self, data: &[u8], width: u32, height: u32, color: ColorType) -> ImageResult<()> { + // TODO: 16bit support + let mut encoder = tiff::encoder::TiffEncoder::new(self.w)?; + match color { + ColorType::Gray(8) => encoder.write_image::(width, height, data)?, + ColorType::RGB(8) => encoder.write_image::(width, height, data)?, + ColorType::RGBA(8) => encoder.write_image::(width, height, data)?, + _ => return Err(ImageError::UnsupportedColor(color)) + } + + Ok(()) + } +} diff --git a/third_party/rust/image/src/utils/mod.rs b/third_party/rust/image/src/utils/mod.rs index 985421aeb2b8..b83bdc958122 100644 --- a/third_party/rust/image/src/utils/mod.rs +++ b/third_party/rust/image/src/utils/mod.rs @@ -1,7 +1,8 @@ //! Utilities +use byteorder::{NativeEndian, ByteOrder}; use num_iter::range_step; -use std::{mem, slice}; +use std::mem; use std::iter::repeat; #[inline(always)] @@ -39,15 +40,7 @@ pub fn vec_u16_into_u8(vec: Vec) -> Vec { } pub fn vec_u16_copy_u8(vec: &Vec) -> Vec { - let original_slice = vec.as_slice(); - let ptr = original_slice.as_ptr() as *const u8; - let len = original_slice.len() * mem::size_of::(); - - // Note: The original pointer points to `len` bytes and all bytes are initialized thus it is - // valid for this slice and for the lifetime of the method. Also, the alignment of `u8` is - // smaller than that of `u16` as per the assert. The `ptr` is non-null because it originates - // from a slice itself. - assert!(mem::align_of::() <= mem::align_of::()); - let byte_slice = unsafe { slice::from_raw_parts(ptr, len) }; - byte_slice.to_owned() + let mut new = vec![0; vec.len() * mem::size_of::()]; + NativeEndian::write_u16_into(&vec[..], &mut new[..]); + new } diff --git a/third_party/rust/image/src/webp/decoder.rs b/third_party/rust/image/src/webp/decoder.rs index cd52b35429cb..e7bf517b93fb 100644 --- a/third_party/rust/image/src/webp/decoder.rs +++ b/third_party/rust/image/src/webp/decoder.rs @@ -1,7 +1,8 @@ use byteorder::{LittleEndian, ReadBytesExt}; use std::default::Default; -use std::io; -use std::io::{Cursor, Read}; +use std::io::{self, Cursor, Read}; +use std::marker::PhantomData; +use std::mem; use image; use image::ImageDecoder; @@ -12,7 +13,8 @@ use color; use super::vp8::Frame; use super::vp8::VP8Decoder; -/// A Representation of a Webp Image format decoder. +/// Webp Image format decoder. Currently only supportes the luma channel (meaning that decoded +/// images will be grayscale). pub struct WebpDecoder { r: R, frame: Frame, @@ -36,10 +38,10 @@ impl WebpDecoder { fn read_riff_header(&mut self) -> ImageResult { let mut riff = Vec::with_capacity(4); - try!(self.r.by_ref().take(4).read_to_end(&mut riff)); - let size = try!(self.r.read_u32::()); + self.r.by_ref().take(4).read_to_end(&mut riff)?; + let size = self.r.read_u32::()?; let mut webp = Vec::with_capacity(4); - try!(self.r.by_ref().take(4).read_to_end(&mut webp)); + self.r.by_ref().take(4).read_to_end(&mut webp)?; if &*riff != b"RIFF" { return Err(image::ImageError::FormatError( @@ -58,7 +60,7 @@ impl WebpDecoder { fn read_vp8_header(&mut self) -> ImageResult<()> { let mut vp8 = Vec::with_capacity(4); - try!(self.r.by_ref().take(4).read_to_end(&mut vp8)); + self.r.by_ref().take(4).read_to_end(&mut vp8)?; if &*vp8 != b"VP8 " { return Err(image::ImageError::FormatError( @@ -66,18 +68,18 @@ impl WebpDecoder { )); } - let _len = try!(self.r.read_u32::()); + let _len = self.r.read_u32::()?; Ok(()) } fn read_frame(&mut self) -> ImageResult<()> { let mut framedata = Vec::new(); - try!(self.r.read_to_end(&mut framedata)); + self.r.read_to_end(&mut framedata)?; let m = io::Cursor::new(framedata); let mut v = VP8Decoder::new(m); - let frame = try!(v.decode_frame()); + let frame = v.decode_frame()?; self.frame = frame.clone(); @@ -86,9 +88,9 @@ impl WebpDecoder { fn read_metadata(&mut self) -> ImageResult<()> { if !self.have_frame { - try!(self.read_riff_header()); - try!(self.read_vp8_header()); - try!(self.read_frame()); + self.read_riff_header()?; + self.read_vp8_header()?; + self.read_frame()?; self.have_frame = true; } @@ -97,8 +99,24 @@ impl WebpDecoder { } } -impl ImageDecoder for WebpDecoder { - type Reader = Cursor>; +/// Wrapper struct around a `Cursor>` +pub struct WebpReader(Cursor>, PhantomData); +impl Read for WebpReader { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + self.0.read(buf) + } + fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { + if self.0.position() == 0 && buf.is_empty() { + mem::swap(buf, self.0.get_mut()); + Ok(buf.len()) + } else { + self.0.read_to_end(buf) + } + } +} + +impl<'a, R: 'a + Read> ImageDecoder<'a> for WebpDecoder { + type Reader = WebpReader; fn dimensions(&self) -> (u64, u64) { (self.frame.width as u64, self.frame.height as u64) @@ -109,7 +127,7 @@ impl ImageDecoder for WebpDecoder { } fn into_reader(self) -> ImageResult { - Ok(Cursor::new(self.frame.ybuf)) + Ok(WebpReader(Cursor::new(self.frame.ybuf), PhantomData)) } fn read_image(self) -> ImageResult> { diff --git a/third_party/rust/image/src/webp/transform.rs b/third_party/rust/image/src/webp/transform.rs index 664305eb9f6f..796405c0c93b 100644 --- a/third_party/rust/image/src/webp/transform.rs +++ b/third_party/rust/image/src/webp/transform.rs @@ -1,41 +1,46 @@ -static CONST1: i32 = 20091; -static CONST2: i32 = 35468; +static CONST1: i64 = 20091; +static CONST2: i64 = 35468; pub fn idct4x4(block: &mut [i32]) { - for i in 0usize..4 { - let a1 = block[i] + block[8 + i]; - let b1 = block[i] - block[8 + i]; - - let t1 = (block[4 + i] * CONST2) >> 16; - let t2 = block[12 + i] + ((block[12 + i] * CONST1) >> 16); - let c1 = t1 - t2; - - let t1 = block[4 + i] + ((block[4 + i] * CONST1) >> 16); - let t2 = (block[12 + i] * CONST2) >> 16; - let d1 = t1 + t2; - - block[i] = a1 + d1; - block[4 + i] = b1 + c1; - block[4 * 3 + i] = a1 - d1; - block[4 * 2 + i] = b1 - c1; + // The intermediate results may overflow the types, so we stretch the type. + fn fetch(block: &mut [i32], idx: usize) -> i64 { + i64::from(block[idx]) } for i in 0usize..4 { - let a1 = block[4 * i] + block[4 * i + 2]; - let b1 = block[4 * i] - block[4 * i + 2]; + let a1 = fetch(block, i) + fetch(block, 8 + i); + let b1 = fetch(block, i) - fetch(block, 8 + i); - let t1 = (block[4 * i + 1] * CONST2) >> 16; - let t2 = block[4 * i + 3] + ((block[4 * i + 3] * CONST1) >> 16); + let t1 = (fetch(block, 4 + i) * CONST2) >> 16; + let t2 = fetch(block, 12 + i) + ((fetch(block, 12 + i) * CONST1) >> 16); let c1 = t1 - t2; - let t1 = block[4 * i + 1] + ((block[4 * i + 1] * CONST1) >> 16); - let t2 = (block[4 * i + 3] * CONST2) >> 16; + let t1 = fetch(block, 4 + i) + ((fetch(block, 4 + i) * CONST1) >> 16); + let t2 = (fetch(block, 12 + i) * CONST2) >> 16; let d1 = t1 + t2; - block[4 * i] = (a1 + d1 + 4) >> 3; - block[4 * i + 3] = (a1 - d1 + 4) >> 3; - block[4 * i + 1] = (b1 + c1 + 4) >> 3; - block[4 * i + 2] = (b1 - c1 + 4) >> 3; + block[i] = (a1 + d1) as i32; + block[4 + i] = (b1 + c1) as i32; + block[4 * 3 + i] = (a1 - d1) as i32; + block[4 * 2 + i] = (b1 - c1) as i32; + } + + for i in 0usize..4 { + let a1 = fetch(block, 4 * i) + fetch(block, 4 * i + 2); + let b1 = fetch(block, 4 * i) - fetch(block, 4 * i + 2); + + let t1 = (fetch(block, 4 * i + 1) * CONST2) >> 16; + let t2 = fetch(block, 4 * i + 3) + ((fetch(block, 4 * i + 3) * CONST1) >> 16); + let c1 = t1 - t2; + + let t1 = fetch(block, 4 * i + 1) + ((fetch(block, 4 * i + 1) * CONST1) >> 16); + let t2 = (fetch(block, 4 * i + 3) * CONST2) >> 16; + let d1 = t1 + t2; + + block[4 * i] = ((a1 + d1 + 4) >> 3) as i32; + block[4 * i + 3] = ((a1 - d1 + 4) >> 3) as i32; + block[4 * i + 1] = ((b1 + c1 + 4) >> 3) as i32; + block[4 * i + 2] = ((b1 - c1 + 4) >> 3) as i32; } } diff --git a/third_party/rust/image/src/webp/vp8.rs b/third_party/rust/image/src/webp/vp8.rs index c512526d7c00..3e664099f8df 100644 --- a/third_party/rust/image/src/webp/vp8.rs +++ b/third_party/rust/image/src/webp/vp8.rs @@ -14,10 +14,11 @@ use byteorder::{LittleEndian, ReadBytesExt}; use std::default::Default; -use std::io; +use std::cmp; use std::io::Read; use super::transform; +use ::{ImageError, ImageResult}; use math::utils::clamp; @@ -42,6 +43,57 @@ const B_VL_PRED: i8 = 7; const B_HD_PRED: i8 = 8; const B_HU_PRED: i8 = 9; +// Prediction mode enum +#[repr(i8)] +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +enum LumaMode { + /// Predict DC using row above and column to the left. + DC = DC_PRED, + + /// Predict rows using row above. + V = V_PRED, + + /// Predict columns using column to the left. + H = H_PRED, + + /// Propagate second differences. + TM = TM_PRED, + + /// Each Y subblock is independently predicted. + B = B_PRED, +} + +#[repr(i8)] +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +enum ChromaMode { + /// Predict DC using row above and column to the left. + DC = DC_PRED, + + /// Predict rows using row above. + V = V_PRED, + + /// Predict columns using column to the left. + H = H_PRED, + + /// Propagate second differences. + TM = TM_PRED, +} + +#[repr(i8)] +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +enum IntraMode { + DC = B_DC_PRED, + TM = B_TM_PRED, + VE = B_VE_PRED, + HE = B_HE_PRED, + LD = B_LD_PRED, + RD = B_RD_PRED, + VR = B_VR_PRED, + VL = B_VL_PRED, + HD = B_HD_PRED, + HU = B_HU_PRED, +} + type Prob = u8; static SEGMENT_ID_TREE: [i8; 6] = [2, 4, -0, -1, -2, -3]; @@ -630,30 +682,33 @@ impl BoolReader { } } - pub fn init(&mut self, buf: Vec) { - self.buf = buf; - self.value = 0; - - for _ in 0usize..2 { - self.value = (self.value << 8) | u32::from(self.buf[self.index]); - self.index += 1; + pub fn init(&mut self, buf: Vec) -> ImageResult<()> { + if buf.len() < 2 { + return Err(ImageError::FormatError( + "Expected at least 2 bytes of decoder initialization data".into())); } + self.buf = buf; + // Direct access safe, since length has just been validated. + self.value = (u32::from(self.buf[0]) << 8) | u32::from(self.buf[1]); + self.index = 2; self.range = 255; self.bit_count = 0; + + Ok(()) } - pub fn read_bool(&mut self, probability: u8) -> u8 { + pub fn read_bool(&mut self, probability: u8) -> bool { let split = 1 + (((self.range - 1) * u32::from(probability)) >> 8); let bigsplit = split << 8; let retval = if self.value >= bigsplit { self.range -= split; self.value -= bigsplit; - 1 + true } else { self.range = split; - 0 + false }; while self.range < 128 { @@ -663,8 +718,13 @@ impl BoolReader { if self.bit_count == 8 { self.bit_count = 0; - self.value |= u32::from(self.buf[self.index]); - self.index += 1; + + // If no more bits are available, just don't do anything. + // This strategy is suggested in the reference implementation of RFC6386 (p.135) + if self.index < self.buf.len() { + self.value |= u32::from(self.buf[self.index]); + self.index += 1; + } } } @@ -676,7 +736,7 @@ impl BoolReader { let mut n = n; while n != 0 { - v = (v << 1) + self.read_bool(128u8); + v = (v << 1) + self.read_bool(128u8) as u8; n -= 1; } @@ -715,27 +775,15 @@ impl BoolReader { } } -#[derive(Clone, Copy)] +#[derive(Default, Clone, Copy)] struct MacroBlock { - bpred: [i8; 16], + bpred: [IntraMode; 16], complexity: [u8; 9], - luma_mode: i8, - chroma_mode: i8, + luma_mode: LumaMode, + chroma_mode: ChromaMode, segmentid: u8, } -impl MacroBlock { - fn new() -> MacroBlock { - MacroBlock { - bpred: [0i8; 16], - complexity: [0u8; 9], - luma_mode: 0, - chroma_mode: 0, - segmentid: 0, - } - } -} - /// A Representation of the last decoded video frame #[derive(Default, Debug, Clone)] pub struct Frame { @@ -823,9 +871,9 @@ impl VP8Decoder { /// Create a new decoder. /// The reader must present a raw vp8 bitstream to the decoder pub fn new(r: R) -> VP8Decoder { - let f: Frame = Default::default(); - let s: Segment = Default::default(); - let m = MacroBlock::new(); + let f = Frame::default(); + let s = Segment::default(); + let m = MacroBlock::default(); VP8Decoder { r, @@ -874,7 +922,7 @@ impl VP8Decoder { for (j, js) in is.iter().enumerate() { for (k, ks) in js.iter().enumerate() { for (t, prob) in ks.iter().enumerate().take(NUM_DCT_TOKENS - 1) { - if self.b.read_bool(*prob) != 0 { + if self.b.read_bool(*prob) { let v = self.b.read_literal(8); self.token_probs[i][j][k][t] = v; } @@ -884,33 +932,38 @@ impl VP8Decoder { } } - fn init_partitions(&mut self, n: usize) -> io::Result<()> { + fn init_partitions(&mut self, n: usize) -> ImageResult<()> { if n > 1 { - let mut sizes = Vec::with_capacity(3 * n - 3); - try!( - self.r - .by_ref() - .take(3 * n as u64 - 3) - .read_to_end(&mut sizes) - ); + let mut sizes = vec![0; 3 * n - 3]; + self.r.read_exact(sizes.as_mut_slice())?; for (i, s) in sizes.chunks(3).enumerate() { - let size = u32::from(s[0]) + ((u32::from(s[1])) << 8) + ((u32::from(s[2])) << 8); - let mut buf = Vec::with_capacity(size as usize); - try!(self.r.by_ref().take(u64::from(size)).read_to_end(&mut buf)); + let size = {s}.read_u24::() + .expect("Reading from &[u8] can't fail and the chunk is complete"); - self.partitions[i].init(buf); + let mut buf = vec![0; size as usize]; + self.r.read_exact(buf.as_mut_slice())?; + + self.partitions[i].init(buf)?; } } let mut buf = Vec::new(); - try!(self.r.read_to_end(&mut buf)); - self.partitions[n - 1].init(buf); + self.r.read_to_end(&mut buf)?; + self.partitions[n - 1].init(buf)?; Ok(()) } fn read_quantization_indices(&mut self) { + fn dc_quant(index: i32) -> i16 { + DC_QUANT[clamp(index, 0, 127) as usize] + } + + fn ac_quant(index: i32) -> i16 { + AC_QUANT[clamp(index, 0, 127) as usize] + } + let yac_abs = self.b.read_literal(7); let ydc_delta = if self.b.read_flag() { self.b.read_magnitude_and_sign(4) @@ -954,14 +1007,15 @@ impl VP8Decoder { i16::from(self.segment[i].quantizer_level) + i16::from(yac_abs) }); - self.segment[i].ydc = DC_QUANT[clamp(base + ydc_delta, 0, 127) as usize]; - self.segment[i].yac = AC_QUANT[clamp(base, 0, 127) as usize]; + self.segment[i].ydc = dc_quant(base + ydc_delta); + self.segment[i].yac = ac_quant(base); - self.segment[i].y2dc = DC_QUANT[clamp(base + y2dc_delta, 0, 127) as usize] * 2; - self.segment[i].y2ac = AC_QUANT[clamp(base + y2ac_delta, 0, 127) as usize] * 155 / 100; + self.segment[i].y2dc = dc_quant(base + y2dc_delta) * 2; + // The intermediate result (max`284*155`) can be larger than the `i16` range. + self.segment[i].y2ac = (i32::from(ac_quant(base + y2ac_delta)) * 155 / 100) as i16; - self.segment[i].uvdc = DC_QUANT[clamp(base + uvdc_delta, 0, 127) as usize]; - self.segment[i].uvac = AC_QUANT[clamp(base + uvac_delta, 0, 127) as usize]; + self.segment[i].uvdc = dc_quant(base + uvdc_delta); + self.segment[i].uvac = ac_quant(base + uvac_delta); if self.segment[i].y2ac < 8 { self.segment[i].y2ac = 8; @@ -1039,29 +1093,34 @@ impl VP8Decoder { } } - fn read_frame_header(&mut self) -> io::Result<()> { - let mut tag = [0u8; 3]; - try!(self.r.read_exact(&mut tag)); + fn read_frame_header(&mut self) -> ImageResult<()> { + let tag = self.r.read_u24::()?; - self.frame.keyframe = tag[0] & 1 == 0; - self.frame.version = (tag[0] >> 1) & 7; - self.frame.for_display = (tag[0] >> 4) & 1 != 0; + self.frame.keyframe = tag & 1 == 0; + self.frame.version = ((tag >> 1) & 7) as u8; + self.frame.for_display = (tag >> 4) & 1 != 0; - let first_partition_size = - ((u32::from(tag[2]) << 16) | (u32::from(tag[1]) << 8) | u32::from(tag[0])) >> 5; + let first_partition_size = tag >> 5; if self.frame.keyframe { - try!(self.r.read_exact(&mut tag)); - assert_eq!(tag, [0x9d, 0x01, 0x2a]); + let mut tag = [0u8; 3]; + self.r.read_exact(&mut tag)?; - let w = try!(self.r.read_u16::()); - let h = try!(self.r.read_u16::()); + if tag != [0x9d, 0x01, 0x2a] { + return Err(ImageError::FormatError( + format!("Invalid magic bytes {:?} for vp8", tag))) + } + + let w = self.r.read_u16::()?; + let h = self.r.read_u16::()?; self.frame.width = w & 0x3FFF; self.frame.height = h & 0x3FFF; self.top = init_top_macroblocks(self.frame.width as usize); - self.left = MacroBlock { ..self.top[0] }; + // Almost always the first macro block, except when non exists (i.e. `width == 0`) + self.left = self.top.get(0).cloned() + .unwrap_or_else(MacroBlock::default); self.mbwidth = (self.frame.width + 15) / 16; self.mbheight = (self.frame.height + 15) / 16; @@ -1072,20 +1131,20 @@ impl VP8Decoder { self.left_border = vec![129u8; 1 + 16]; } - let mut buf = Vec::with_capacity(first_partition_size as usize); - try!( - self.r - .by_ref() - .take(u64::from(first_partition_size)) - .read_to_end(&mut buf) - ); + let mut buf = vec![0; first_partition_size as usize]; + self.r.read_exact(&mut buf)?; + // initialise binary decoder - self.b.init(buf); + self.b.init(buf)?; if self.frame.keyframe { let color_space = self.b.read_literal(1); self.frame.pixel_type = self.b.read_literal(1); - assert_eq!(color_space, 0); + + if color_space != 0 { + return Err(ImageError::FormatError( + format!("Only YUV color space is specified."))) + } } self.segments_enabled = self.b.read_flag(); @@ -1104,13 +1163,15 @@ impl VP8Decoder { self.num_partitions = (1usize << self.b.read_literal(2) as usize) as u8; let num_partitions = self.num_partitions as usize; - try!(self.init_partitions(num_partitions)); + self.init_partitions(num_partitions)?; self.read_quantization_indices(); if !self.frame.keyframe { // 9.7 refresh golden frame and altref frame - panic!("unimplemented") + return Err(ImageError::UnsupportedError( + "Frames that are not keyframes are not supported".into())) + // FIXME: support this? } else { // Refresh entropy probs ????? let _ = self.b.read_literal(1); @@ -1129,7 +1190,9 @@ impl VP8Decoder { // 9.10 remaining frame data self.prob_intra = 0; - panic!("unimplemented") + return Err(ImageError::UnsupportedError( + "Frames that are not keyframes are not supported".into())) + // FIXME: support this? } else { // Reset motion vectors } @@ -1137,8 +1200,8 @@ impl VP8Decoder { Ok(()) } - fn read_macroblock_header(&mut self, mbx: usize) -> (bool, MacroBlock) { - let mut mb = MacroBlock::new(); + fn read_macroblock_header(&mut self, mbx: usize) -> ImageResult<(bool, MacroBlock)> { + let mut mb = MacroBlock::default(); mb.segmentid = if self.segments_enabled && self.segments_update_map { self.b @@ -1148,67 +1211,75 @@ impl VP8Decoder { }; let skip_coeff = if self.prob_skip_false.is_some() { - 1 == self.b.read_bool(*self.prob_skip_false.as_ref().unwrap()) + self.b.read_bool(*self.prob_skip_false.as_ref().unwrap()) } else { false }; let inter_predicted = if !self.frame.keyframe { - 1 == self.b.read_bool(self.prob_intra) + self.b.read_bool(self.prob_intra) } else { false }; if inter_predicted { - panic!("inter prediction not implemented"); + return Err(ImageError::UnsupportedError( + "VP8 inter prediction is not implemented yet".into())); } if self.frame.keyframe { // intra prediction - mb.luma_mode = self.b + let luma = self.b .read_with_tree(&KEYFRAME_YMODE_TREE, &KEYFRAME_YMODE_PROBS, 0); + mb.luma_mode = LumaMode::from_i8(luma) + .ok_or_else(|| ImageError::FormatError( + format!("Invalid luma prediction mode {}", luma)) + )?; - if mb.luma_mode == B_PRED { - for y in 0usize..4 { - for x in 0usize..4 { - let top = self.top[mbx].bpred[12 + x]; - let left = self.left.bpred[y]; - let bmode = self.b.read_with_tree( - &KEYFRAME_BPRED_MODE_TREE, - &KEYFRAME_BPRED_MODE_PROBS[top as usize][left as usize], - 0, - ); - mb.bpred[x + y * 4] = bmode; + match mb.luma_mode.into_intra() { + // `LumaMode::B` - This is predicted individually + None => { + for y in 0usize..4 { + for x in 0usize..4 { + let top = self.top[mbx].bpred[12 + x]; + let left = self.left.bpred[y]; + let intra = self.b.read_with_tree( + &KEYFRAME_BPRED_MODE_TREE, + &KEYFRAME_BPRED_MODE_PROBS[top as usize][left as usize], + 0, + ); + let bmode = IntraMode::from_i8(intra) + .ok_or_else(|| ImageError::FormatError( + format!("Invalid intra prediction mode {}", intra)) + )?; + mb.bpred[x + y * 4] = bmode; - self.top[mbx].bpred[12 + x] = bmode; - self.left.bpred[y] = bmode; + self.top[mbx].bpred[12 + x] = bmode; + self.left.bpred[y] = bmode; + } + } + }, + Some(mode) => { + for i in 0usize..4 { + mb.bpred[12 + i] = mode; + self.left.bpred[i] = mode; } - } - } else { - for i in 0usize..4 { - let mode = match mb.luma_mode { - DC_PRED => B_DC_PRED, - V_PRED => B_VE_PRED, - H_PRED => B_HE_PRED, - TM_PRED => B_TM_PRED, - _ => panic!("unreachable"), - }; - - mb.bpred[12 + i] = mode; - self.left.bpred[i] = mode; } } - mb.chroma_mode = - self.b - .read_with_tree(&KEYFRAME_UV_MODE_TREE, &KEYFRAME_UV_MODE_PROBS, 0); + let chroma = self.b + .read_with_tree(&KEYFRAME_UV_MODE_TREE, &KEYFRAME_UV_MODE_PROBS, 0); + mb.chroma_mode = ChromaMode::from_i8(chroma) + .ok_or_else(|| ImageError::FormatError( + format!("Invalid chroma prediction mode {}", chroma)) + )?; } self.top[mbx].chroma_mode = mb.chroma_mode; self.top[mbx].luma_mode = mb.luma_mode; self.top[mbx].bpred = mb.bpred; - (skip_coeff, mb) + Ok((skip_coeff, mb)) } fn intra_predict(&mut self, mbx: usize, mby: usize, mb: &MacroBlock, resdata: &[i32]) { @@ -1218,15 +1289,14 @@ impl VP8Decoder { let mut ws = create_border(mbx, mby, mw, &self.top_border, &self.left_border); match mb.luma_mode { - V_PRED => predict_vpred(&mut ws, 16, 1, 1, stride), - H_PRED => predict_hpred(&mut ws, 16, 1, 1, stride), - TM_PRED => predict_tmpred(&mut ws, 16, 1, 1, stride), - DC_PRED => predict_dcpred(&mut ws, 16, stride, mby != 0, mbx != 0), - B_PRED => predict_4x4(&mut ws, stride, &mb.bpred, resdata), - _ => panic!("unknown luma intra prediction mode"), + LumaMode::V => predict_vpred(&mut ws, 16, 1, 1, stride), + LumaMode::H => predict_hpred(&mut ws, 16, 1, 1, stride), + LumaMode::TM => predict_tmpred(&mut ws, 16, 1, 1, stride), + LumaMode::DC => predict_dcpred(&mut ws, 16, stride, mby != 0, mbx != 0), + LumaMode::B => predict_4x4(&mut ws, stride, &mb.bpred, resdata), } - if mb.luma_mode != B_PRED { + if mb.luma_mode != LumaMode::B { for y in 0usize..4 { for x in 0usize..4 { let i = x + y * 4; @@ -1246,17 +1316,9 @@ impl VP8Decoder { self.left_border[i + 1] = ws[(i + 1) * stride + 16]; } - let ylength = if mby < self.mbheight as usize - 1 || self.frame.height % 16 == 0 { - 16usize - } else { - (16 - (self.frame.height as usize & 15)) % 16 - }; - - let xlength = if mbx < self.mbwidth as usize - 1 || self.frame.width % 16 == 0 { - 16usize - } else { - (16 - (self.frame.width as usize & 15)) % 16 - }; + // Length is the remainder to the border, but maximally the current chunk. + let ylength = cmp::min(self.frame.height as usize - mby*16, 16); + let xlength = cmp::min(self.frame.width as usize - mbx*16, 16); for y in 0usize..ylength { for x in 0usize..xlength { @@ -1301,16 +1363,16 @@ impl VP8Decoder { continue; } - literal @ DCT_1...DCT_4 => i16::from(literal), + literal @ DCT_1..=DCT_4 => i16::from(literal), - category @ DCT_CAT1...DCT_CAT6 => { + category @ DCT_CAT1..=DCT_CAT6 => { let t = PROB_DCT_CAT[(category - DCT_CAT1) as usize]; let mut extra = 0i16; let mut j = 0; while t[j] > 0 { - extra = extra + extra + i16::from(self.partitions[p].read_bool(t[j])); + extra = extra + extra + self.partitions[p].read_bool(t[j]) as i16; j += 1; } @@ -1330,7 +1392,7 @@ impl VP8Decoder { 2 }; - if self.partitions[p].read_bool(128) == 1 { + if self.partitions[p].read_bool(128) { abs_value = -abs_value; } @@ -1346,7 +1408,7 @@ impl VP8Decoder { fn read_residual_data(&mut self, mb: &MacroBlock, mbx: usize, p: usize) -> [i32; 384] { let sindex = mb.segmentid as usize; let mut blocks = [0i32; 384]; - let mut plane = if mb.luma_mode == B_PRED { 3 } else { 1 }; + let mut plane = if mb.luma_mode == LumaMode::B { 3 } else { 1 }; if plane == 1 { let complexity = self.top[mbx].complexity[0] + self.left.complexity[0]; @@ -1421,19 +1483,19 @@ impl VP8Decoder { } /// Decodes the current frame and returns a reference to it - pub fn decode_frame(&mut self) -> io::Result<&Frame> { - try!(self.read_frame_header()); + pub fn decode_frame(&mut self) -> ImageResult<&Frame> { + self.read_frame_header()?; for mby in 0..self.mbheight as usize { let p = mby % self.num_partitions as usize; - self.left = MacroBlock::new(); + self.left = MacroBlock::default(); for mbx in 0..self.mbwidth as usize { - let (skip, mb) = self.read_macroblock_header(mbx); + let (skip, mb) = self.read_macroblock_header(mbx)?; let blocks = if !skip { self.read_residual_data(&mb, mbx, p) } else { - if mb.luma_mode != B_PRED { + if mb.luma_mode != LumaMode::B { self.left.complexity[0] = 0; self.top[mbx].complexity[0] = 0; } @@ -1456,17 +1518,88 @@ impl VP8Decoder { } } +impl LumaMode { + fn from_i8(val: i8) -> Option { + Some(match val { + DC_PRED => LumaMode::DC, + V_PRED => LumaMode::V, + H_PRED => LumaMode::H, + TM_PRED => LumaMode::TM, + B_PRED => LumaMode::B, + _ => return None, + }) + } + + fn into_intra(self) -> Option { + Some(match self { + LumaMode::DC => IntraMode::DC, + LumaMode::V => IntraMode::VE, + LumaMode::H => IntraMode::HE, + LumaMode::TM => IntraMode::TM, + LumaMode::B => return None, + }) + } +} + +impl Default for LumaMode { + fn default() -> Self { + LumaMode::DC + } +} + +impl ChromaMode { + fn from_i8(val: i8) -> Option { + Some(match val { + DC_PRED => ChromaMode::DC, + V_PRED => ChromaMode::V, + H_PRED => ChromaMode::H, + TM_PRED => ChromaMode::TM, + _ => return None, + }) + } +} + +impl Default for ChromaMode { + fn default() -> Self { + ChromaMode::DC + } +} + +impl IntraMode { + fn from_i8(val: i8) -> Option { + Some(match val { + B_DC_PRED => IntraMode::DC, + B_TM_PRED => IntraMode::TM, + B_VE_PRED => IntraMode::VE, + B_HE_PRED => IntraMode::HE, + B_LD_PRED => IntraMode::LD, + B_RD_PRED => IntraMode::RD, + B_VR_PRED => IntraMode::VR, + B_VL_PRED => IntraMode::VL, + B_HD_PRED => IntraMode::HD, + B_HU_PRED => IntraMode::HU, + _ => return None, + }) + } +} + +impl Default for IntraMode { + fn default() -> Self { + IntraMode::DC + } +} + fn init_top_macroblocks(width: usize) -> Vec { let mb_width = (width + 15) / 16; let mb = MacroBlock { // Section 11.3 #3 - bpred: [B_DC_PRED; 16], - luma_mode: DC_PRED, - ..MacroBlock::new() + bpred: [IntraMode::DC; 16], + luma_mode: LumaMode::DC, + .. MacroBlock::default() }; - (0..mb_width).map(|_| mb).collect() + vec![mb; mb_width] } fn create_border(mbx: usize, mby: usize, mbw: usize, top: &[u8], left: &[u8]) -> [u8; 357] { @@ -1547,7 +1680,7 @@ fn add_residue(pblock: &mut [u8], rblock: &[i32], y0: usize, x0: usize, stride: } } -fn predict_4x4(ws: &mut [u8], stride: usize, modes: &[i8], resdata: &[i32]) { +fn predict_4x4(ws: &mut [u8], stride: usize, modes: &[IntraMode], resdata: &[i32]) { for sby in 0usize..4 { for sbx in 0usize..4 { let i = sbx + sby * 4; @@ -1556,17 +1689,16 @@ fn predict_4x4(ws: &mut [u8], stride: usize, modes: &[i8], resdata: &[i32]) { let rb = &resdata[i * 16..i * 16 + 16]; match modes[i] { - B_TM_PRED => predict_tmpred(ws, 4, x0, y0, stride), - B_VE_PRED => predict_bvepred(ws, x0, y0, stride), - B_HE_PRED => predict_bhepred(ws, x0, y0, stride), - B_DC_PRED => predict_bdcpred(ws, x0, y0, stride), - B_LD_PRED => predict_bldpred(ws, x0, y0, stride), - B_RD_PRED => predict_brdpred(ws, x0, y0, stride), - B_VR_PRED => predict_bvrpred(ws, x0, y0, stride), - B_VL_PRED => predict_bvlpred(ws, x0, y0, stride), - B_HD_PRED => predict_bhdpred(ws, x0, y0, stride), - B_HU_PRED => predict_bhupred(ws, x0, y0, stride), - _ => panic!("unknown intra bmode"), + IntraMode::TM => predict_tmpred(ws, 4, x0, y0, stride), + IntraMode::VE => predict_bvepred(ws, x0, y0, stride), + IntraMode::HE => predict_bhepred(ws, x0, y0, stride), + IntraMode::DC => predict_bdcpred(ws, x0, y0, stride), + IntraMode::LD => predict_bldpred(ws, x0, y0, stride), + IntraMode::RD => predict_brdpred(ws, x0, y0, stride), + IntraMode::VR => predict_bvrpred(ws, x0, y0, stride), + IntraMode::VL => predict_bvlpred(ws, x0, y0, stride), + IntraMode::HD => predict_bhdpred(ws, x0, y0, stride), + IntraMode::HU => predict_bhupred(ws, x0, y0, stride), } add_residue(ws, rb, y0, x0, stride); diff --git a/third_party/rust/png/.cargo-checksum.json b/third_party/rust/png/.cargo-checksum.json index 2c6637cae4e7..fe4471782ca5 100644 --- a/third_party/rust/png/.cargo-checksum.json +++ b/third_party/rust/png/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"8cc6eb1d08623955951841761c9757e67a43048d6cb40197ebabf2de1f6c46d4","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"eaf40297c75da471f7cda1f3458e8d91b4b2ec866e609527a13acfa93b638652","README.md":"4556c29a1c1dd656eb7a85bb1929f4112c7d8525216fc508e616bef4036ef023","examples/pngcheck.rs":"9eea856ab45e0daf3f470f7f86d0c3521cf3de7e06f0fcc8764800fa57ffd86d","examples/show.rs":"0cf8a74a1b8a0c350fee5eacfee082607e8adcd51968a1460ee6305d83041d19","src/chunk.rs":"f8aa01e68683b5cd41ac2580ac11f2d6a6190c52007e3f115dc5b7c3b0354e63","src/common.rs":"4f80198a5131de872a19e0b443d88def80d1688f4f1317cfd05a6b773564a48e","src/crc.rs":"7136e3ae5564db1aadfd45c3c4d65d1d41ede797b2e8be7ca1e731bd567d04bc","src/decoder/mod.rs":"e4d7e58c5f80ccccd445d22278ce46a77c9f64db8d0a8c20530917fcd6df3a1a","src/decoder/stream.rs":"917285c321e3de1b07b6aa5943bfef315e9b7bdc8035dca65b5c8c4b605b4796","src/encoder.rs":"ff0582366827a84a9a742d1781fcc41c005d34b422edeef9e063804f4b9a86c2","src/filter.rs":"74015c3e328bc0b5c03826f971ffb48f16903488f54ce16b0245b5a1467c0c08","src/lib.rs":"be7360d6f5c278f78da90e578b14bae6a4fc1e249538ff5e6aaf1d75d1bdea34","src/traits.rs":"f326ebcba17b87b609b564ff2aa4aaf1f5de4dcff991aa4d21f3d9b0ba39affc","src/utils.rs":"c5b45039c9903962842544d8ef5203a1ce820cb8010bd1bf8cc1f517d45ef160"},"package":"9adebf7fb91ccf5eac9da1a8e00e83cb8ae882c3e8d8e4ad59da73cb8c82a2c9"} \ No newline at end of file +{"files":{"Cargo.toml":"cbabe74b9508336598dee4e2736e644607fbaa05b1aa7b03cf324c14c02c747e","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"eaf40297c75da471f7cda1f3458e8d91b4b2ec866e609527a13acfa93b638652","README.md":"a29453dab1a440374ed18881bfbb73651e2b84c35eabc0a7b293ab553ef345f4","benches/README.md":"0c60c3d497abdf6c032863aa47da41bc6bb4f5ff696d45dec0e6eb33459b14b0","benches/decoder.rs":"81a13f5c731f674cc21a6aa472bcf4cc6c3581a41b1e002fa3996fc9a6e0dfe5","examples/pngcheck.rs":"191ff0b61734a75befd0d3ecd3f39226e9f3ef89a5d7a16870808f5ebf0e054d","examples/show.rs":"22be41150fa02d42500c48920cf3b7277090680e336ab8744aac0cece8bccc68","src/chunk.rs":"f8aa01e68683b5cd41ac2580ac11f2d6a6190c52007e3f115dc5b7c3b0354e63","src/common.rs":"a0bc64f16cfdf511925a2869d9fda70ed07272a8278c1d2db142821babd4c931","src/decoder/mod.rs":"ec173948f4cd09837b5e59b30ba209a0b96d2cc23570152c4850891058632eff","src/decoder/stream.rs":"28ef3d00fc65463019f22e95b568b9776d6249de388d2af2af116017330a6bdd","src/encoder.rs":"8bc2f8a5f6f45a59de4933d230f3340f11c934d2c5f5493dbc202505d398319f","src/filter.rs":"7de56800200b15b7a6bf79eefb8771ae29c37accce8a1044f37620153060f8ba","src/lib.rs":"1d56a30f6283bbeaeb2cf7c03061b2081e8f85284b206104d08865a801b944e9","src/traits.rs":"3afe302164f1d5ffdc0482489332c6fc78120ce19c0a7db5a1f4bda0326d8f62","src/utils.rs":"03af618a3d2fe6d49828a7afc876d4561472588f542bb49191735b93f533c921"},"package":"8422b27bb2c013dd97b9aef69e161ce262236f49aaf46a0489011c8ff0264602"} \ No newline at end of file diff --git a/third_party/rust/png/Cargo.toml b/third_party/rust/png/Cargo.toml index fb3a7a007eb2..43e12e315250 100644 --- a/third_party/rust/png/Cargo.toml +++ b/third_party/rust/png/Cargo.toml @@ -3,7 +3,7 @@ # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g. crates.io) dependencies +# to registry (e.g., crates.io) dependencies # # If you believe there's an error in this file please file an # issue against the rust-lang/cargo repository. If you're @@ -11,25 +11,27 @@ # will likely look very different (and much more reasonable) [package] +edition = "2018" name = "png" -version = "0.14.0" +version = "0.15.0" authors = ["nwin "] exclude = ["tests/*"] description = "PNG decoding and encoding library in pure Rust" -license = "MIT/Apache-2.0" -repository = "https://github.com/PistonDevelopers/image-png.git" +categories = ["multimedia::images"] +license = "MIT OR Apache-2.0" +repository = "https://github.com/image-rs/image-png.git" [dependencies.bitflags] version = "1.0" +[dependencies.crc32fast] +version = "1.2.0" + [dependencies.deflate] -version = "0.7.2" +version = "0.7.12" optional = true [dependencies.inflate] version = "0.4.2" - -[dependencies.num-iter] -version = "0.1.32" [dev-dependencies.getopts] version = "0.2.14" @@ -39,7 +41,7 @@ features = ["glutin"] default-features = false [dev-dependencies.glob] -version = "0.2.11" +version = "0.3" [dev-dependencies.rand] version = "0.5.5" @@ -48,6 +50,7 @@ version = "0.5.5" version = "0.4" [features] +benchmarks = [] default = ["png-encoding"] png-encoding = ["deflate"] unstable = [] diff --git a/third_party/rust/png/README.md b/third_party/rust/png/README.md index f71d720350c9..1e56419072fa 100644 --- a/third_party/rust/png/README.md +++ b/third_party/rust/png/README.md @@ -1,11 +1,26 @@ # PNG Decoder/Encoder -[![Build Status](https://travis-ci.org/PistonDevelopers/image-png.svg?branch=master)](https://travis-ci.org/PistonDevelopers/image-png) -[![Crates.io](https://docs.rs/png/badge.svg)](https://docs.rs/png) +[![Build Status](https://travis-ci.org/image-rs/image-png.svg?branch=master)](https://travis-ci.org/image-rs/image-png) +[![Documentation](https://docs.rs/png/badge.svg)](https://docs.rs/png) [![Crates.io](https://img.shields.io/crates/v/png.svg)](https://crates.io/crates/png) -![Lines of Code](https://tokei.rs/b1/github/PistonDevelopers/image-png) -[![License](https://img.shields.io/crates/l/png.svg)](https://github.com/PistonDevelopers/image-png) +![Lines of Code](https://tokei.rs/b1/github/image-rs/image-png) +[![License](https://img.shields.io/crates/l/png.svg)](https://github.com/image-rs/image-png) -PNG decoder/encoder in pure Rust. Currently `pngcheck` is the most usable part. Build with `cargo build --release --example pngcheck`. +PNG decoder/encoder in pure Rust. + +It contains all features required to handle the entirety of [the PngSuite by +Willem van Schack][PngSuite]. + +[PngSuite]: http://www.schaik.com/pngsuite2011/pngsuite.html + +## pngcheck + +The `pngcheck` utility is a small demonstration binary that checks and prints +metadata on every `.png` image provided via parameter. You can run it (for +example on the test directories) with + +```bash +cargo run --release --example pngcheck ./tests/pngsuite/* +``` ## License diff --git a/third_party/rust/png/benches/README.md b/third_party/rust/png/benches/README.md new file mode 100644 index 000000000000..bf13a5544a52 --- /dev/null +++ b/third_party/rust/png/benches/README.md @@ -0,0 +1,6 @@ +# Getting started with benchmarking + +To run the benchmarks you need a nightly rust toolchain. +Then you launch it with + + rustup run nightly cargo bench --features=benchmarks diff --git a/third_party/rust/png/benches/decoder.rs b/third_party/rust/png/benches/decoder.rs new file mode 100644 index 000000000000..7d9cce933cc7 --- /dev/null +++ b/third_party/rust/png/benches/decoder.rs @@ -0,0 +1,25 @@ +#![cfg(feature = "benchmarks")] +#![feature(test)] + +extern crate png; +extern crate test; + +use std::fs::File; +use std::io::Read; + +use png::Decoder; + +#[bench] +fn bench_big(b: &mut test::Bencher) { + let mut data = Vec::new(); + File::open("tests/pngsuite/PngSuite.png").unwrap().read_to_end(&mut data).unwrap(); + let decoder = Decoder::new(&*data); + let (info, _) = decoder.read_info().unwrap(); + let mut image = vec![0; info.buffer_size()]; + b.iter(|| { + let decoder = Decoder::new(&*data); + let (_, mut decoder) = decoder.read_info().unwrap(); + test::black_box(decoder.next_frame(&mut image)).unwrap(); + }); + b.bytes = info.buffer_size() as u64 +} diff --git a/third_party/rust/png/examples/pngcheck.rs b/third_party/rust/png/examples/pngcheck.rs index a0b0553cd4af..127be55e062f 100644 --- a/third_party/rust/png/examples/pngcheck.rs +++ b/third_party/rust/png/examples/pngcheck.rs @@ -14,7 +14,7 @@ use std::env; use getopts::{Matches, Options, ParsingStyle}; use term::{color, Attr}; -fn parse_args() -> Option { +fn parse_args() -> Matches { let args: Vec = env::args().collect(); let mut opts = Options::new(); opts.optflag("c", "", "colorize output (for ANSI terminals)") @@ -24,12 +24,12 @@ fn parse_args() -> Option { .parsing_style(ParsingStyle::StopAtFirstFree); if args.len() > 1 { match opts.parse(&args[1..]) { - Ok(matches) => return Some(matches), + Ok(matches) => return matches, Err(err) => println!("{}", err) } } println!("{}", opts.usage(&format!("Usage: pngcheck [-cpt] [file ...]"))); - None + std::process::exit(0); } #[derive(Clone, Copy)] @@ -75,15 +75,15 @@ fn final_channels(c: png::ColorType, trns: bool) -> u8 { fn check_image>(c: Config, fname: P) -> io::Result<()> { // TODO improve performance by resusing allocations from decoder use png::Decoded::*; - let mut t = try!(term::stdout().ok_or(io::Error::new( + let mut t = term::stdout().ok_or(io::Error::new( io::ErrorKind::Other, "could not open terminal" - ))); + ))?; let mut data = vec![0; 10*1024]; let data_p = data.as_mut_ptr(); - let mut reader = io::BufReader::new(try!(File::open(&fname))); + let mut reader = io::BufReader::new(File::open(&fname)?); let fname = fname.as_ref().to_string_lossy(); - let n = try!(reader.read(&mut data)); + let n = reader.read(&mut data)?; let mut buf = &data[..n]; let mut pos = 0; let mut decoder = png::StreamingDecoder::new(); @@ -107,18 +107,18 @@ fn check_image>(c: Config, fname: P) -> io::Result<()> { }); ); let display_error = |err| -> Result<_, io::Error> { - let mut t = try!(term::stdout().ok_or(io::Error::new( + let mut t = term::stdout().ok_or(io::Error::new( io::ErrorKind::Other, "could not open terminal" - ))); + ))?; if c.verbose { if c.color { print!(": "); - try!(t.fg(color::RED)); - try!(writeln!(t, "{}", err)); - try!(t.attr(Attr::Bold)); - try!(write!(t, "ERRORS DETECTED")); - try!(t.reset()); + t.fg(color::RED)?; + writeln!(t, "{}", err)?; + t.attr(Attr::Bold)?; + write!(t, "ERRORS DETECTED")?; + t.reset()?; } else { println!(": {}", err); print!("ERRORS DETECTED") @@ -126,22 +126,22 @@ fn check_image>(c: Config, fname: P) -> io::Result<()> { println!(" in {}", fname); } else { if !c.quiet { if c.color { - try!(t.fg(color::RED)); - try!(t.attr(Attr::Bold)); - try!(write!(t, "ERROR")); - try!(t.reset()); - try!(write!(t, ": ")); - try!(t.fg(color::YELLOW)); - try!(writeln!(t, "{}", fname)); - try!(t.reset()); + t.fg(color::RED)?; + t.attr(Attr::Bold)?; + write!(t, "ERROR")?; + t.reset()?; + write!(t, ": ")?; + t.fg(color::YELLOW)?; + writeln!(t, "{}", fname)?; + t.reset()?; } else { println!("ERROR: {}", fname) }} print!("{}: ", fname); if c.color { - try!(t.fg(color::RED)); - try!(writeln!(t, "{}", err)); - try!(t.reset()); + t.fg(color::RED)?; + writeln!(t, "{}", err)?; + t.reset()?; } else { println!("{}", err); } @@ -153,9 +153,9 @@ fn check_image>(c: Config, fname: P) -> io::Result<()> { if c.verbose { print!("File: "); if c.color { - try!(t.attr(Attr::Bold)); - try!(write!(t, "{}", fname)); - try!(t.reset()); + t.attr(Attr::Bold)?; + write!(t, "{}", fname)?; + t.reset()?; } else { print!("{}", fname); } @@ -165,27 +165,34 @@ fn check_image>(c: Config, fname: P) -> io::Result<()> { loop { if buf.len() == 0 { // circumvent borrow checker - let n = try!(reader.read(unsafe { + assert!(!data.is_empty()); + let n = reader.read(unsafe { ::std::slice::from_raw_parts_mut(data_p, data.len()) - })); + })?; + + // EOF + if n == 0 { + println!("ERROR: premature end of file {}", fname); + break; + } buf = &data[..n]; } match decoder.update(buf, &mut Vec::new()) { Ok((_, ImageEnd)) => { if !have_idat { - try!(display_error(png::DecodingError::Format("IDAT chunk missing".into()))); + display_error(png::DecodingError::Format("IDAT chunk missing".into()))?; break; } if !c.verbose && !c.quiet { if c.color { - try!(t.fg(color::GREEN)); - try!(t.attr(Attr::Bold)); - try!(write!(t, "OK")); - try!(t.reset()); - try!(write!(t, ": ")); - try!(t.fg(color::YELLOW)); - try!(write!(t, "{}", fname)); - try!(t.reset()); + t.fg(color::GREEN)?; + t.attr(Attr::Bold)?; + write!(t, "OK")?; + t.reset()?; + write!(t, ": ")?; + t.fg(color::YELLOW)?; + write!(t, "{}", fname)?; + t.reset()?; } else { print!("OK: {}", fname) } @@ -201,10 +208,10 @@ fn check_image>(c: Config, fname: P) -> io::Result<()> { } else if !c.quiet { println!(""); if c.color { - try!(t.fg(color::GREEN)); - try!(t.attr(Attr::Bold)); - try!(write!(t, "No errors detected ")); - try!(t.reset()); + t.fg(color::GREEN)?; + t.attr(Attr::Bold)?; + write!(t, "No errors detected ")?; + t.reset()?; } else { print!("No errors detected "); } @@ -236,9 +243,9 @@ fn check_image>(c: Config, fname: P) -> io::Result<()> { println!(""); print!(" chunk "); if c.color { - try!(t.fg(color::YELLOW)); - try!(write!(t, "{}", chunk)); - try!(t.reset()); + t.fg(color::YELLOW)?; + write!(t, "{}", chunk)?; + t.reset()?; } else { print!("{}", chunk) } @@ -323,34 +330,32 @@ fn check_image>(c: Config, fname: P) -> io::Result<()> { } fn main() { - if let Some(m) = parse_args() { - let config = Config { - quiet: m.opt_present("q"), - verbose: m.opt_present("v"), - color: m.opt_present("c") + let m = parse_args(); + + let config = Config { + quiet: m.opt_present("q"), + verbose: m.opt_present("v"), + color: m.opt_present("c") + }; + + for file in m.free { + let result = if file.contains("*") { + glob::glob(&file).map_err(|err| { + io::Error::new(io::ErrorKind::Other, err) + }).and_then(|mut glob| glob.try_for_each(|entry| { + entry.map_err(|err| { + io::Error::new(io::ErrorKind::Other, err) + }).and_then(|file| { + check_image(config, file) + }) + })) + } else { + check_image(config, &file) }; - for file in m.free { - match if file.contains("*") { - (|| -> io::Result<_> { - for entry in try!(glob::glob(&file).map_err(|err| { - io::Error::new(io::ErrorKind::Other, err.msg) - })) { - try!(check_image(config, try!(entry.map_err(|_| { - io::Error::new(io::ErrorKind::Other, "glob error") - })))) - } - Ok(()) - })() - } else { - check_image(config, &file) - } { - Ok(_) => (), - Err(err) => { - println!("{}: {}", file, err); - break - } - } - - } + + result.unwrap_or_else(|err| { + println!("{}: {}", file, err); + std::process::exit(1) + }); } } diff --git a/third_party/rust/png/examples/show.rs b/third_party/rust/png/examples/show.rs index e143d5470626..b0dfe6a570d4 100644 --- a/third_party/rust/png/examples/show.rs +++ b/third_party/rust/png/examples/show.rs @@ -17,10 +17,10 @@ use glium::backend::glutin::Display; /// Load the image using `png` fn load_image(path: &path::PathBuf) -> io::Result> { use png::ColorType::*; - let decoder = png::Decoder::new(try!(File::open(path))); - let (info, mut reader) = try!(decoder.read_info()); + let decoder = png::Decoder::new(File::open(path)?); + let (info, mut reader) = decoder.read_info()?; let mut img_data = vec![0; info.buffer_size()]; - try!(reader.next_frame(&mut img_data)); + reader.next_frame(&mut img_data)?; let (data, format) = match info.color_type { RGB => (img_data, ClientFormat::U8U8U8), @@ -61,7 +61,7 @@ fn main_loop(files: Vec) -> io::Result<()> { use glium::glutin::{KeyboardInput, WindowEvent}; let mut files = files.iter(); - let image = try!(load_image(files.next().unwrap())); + let image = load_image(files.next().unwrap())?; let mut events_loop = glutin::EventsLoop::new(); let window = glutin::WindowBuilder::new(); @@ -169,12 +169,12 @@ fn main() { for file in args.iter().skip(1) { match if file.contains("*") { (|| -> io::Result<_> { - for entry in try!(glob::glob(&file).map_err(|err| { + for entry in glob::glob(&file).map_err(|err| { io::Error::new(io::ErrorKind::Other, err.msg) - })) { - files.push(try!(entry.map_err(|_| { + })? { + files.push(entry.map_err(|_| { io::Error::new(io::ErrorKind::Other, "glob error") - }))) + })?) } Ok(()) })() diff --git a/third_party/rust/png/src/common.rs b/third_party/rust/png/src/common.rs index bdb21d96adff..014efb751e35 100644 --- a/third_party/rust/png/src/common.rs +++ b/third_party/rust/png/src/common.rs @@ -1,7 +1,9 @@ //! Common types shared between the encoder and decoder -extern crate deflate; -use filter; +use crate::filter; +use std::fmt; + +/// Describes the layout of samples in a pixel #[derive(Debug, Clone, Copy, PartialEq, Eq)] #[repr(u8)] pub enum ColorType { @@ -92,8 +94,74 @@ impl Unit { } } +/// How to reset buffer of an animated png (APNG) at the end of a frame. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[repr(u8)] +pub enum DisposeOp { + /// Leave the buffer unchanged. + None = 0, + /// Clear buffer with the background color. + Background = 1, + /// Reset the buffer to the state before the current frame. + Previous = 2, +} + +impl DisposeOp { + /// u8 -> Self. Using enum_primitive or transmute is probably the right thing but this will do for now. + pub fn from_u8(n: u8) -> Option { + match n { + 0 => Some(DisposeOp::None), + 1 => Some(DisposeOp::Background), + 2 => Some(DisposeOp::Previous), + _ => None + } + } +} + +impl fmt::Display for DisposeOp { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let name = match *self { + DisposeOp::None => "DISPOSE_OP_NONE", + DisposeOp::Background => "DISPOSE_OP_BACKGROUND", + DisposeOp::Previous => "DISPOSE_OP_PREVIOUS", + }; + write!(f, "{}", name) + } +} + +/// How pixels are written into the buffer. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[repr(u8)] +pub enum BlendOp { + /// Pixels overwrite the value at their position. + Source = 0, + /// The new pixels are blended into the current state based on alpha. + Over = 1, +} + +impl BlendOp { + /// u8 -> Self. Using enum_primitive or transmute is probably the right thing but this will do for now. + pub fn from_u8(n: u8) -> Option { + match n { + 0 => Some(BlendOp::Source), + 1 => Some(BlendOp::Over), + _ => None + } + } +} + +impl fmt::Display for BlendOp { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let name = match *self { + BlendOp::Source => "BLEND_OP_SOURCE", + BlendOp::Over => "BLEND_OP_OVER", + }; + write!(f, "{}", name) + } +} + /// Frame control information -#[derive(Clone, Debug)] +#[derive(Clone, Copy, Debug)] pub struct FrameControl { /// Sequence number of the animation chunk, starting from 0 pub sequence_number: u32, @@ -110,9 +178,36 @@ pub struct FrameControl { /// Frame delay fraction denominator pub delay_den: u16, /// Type of frame area disposal to be done after rendering this frame - pub dispose_op: u8, + pub dispose_op: DisposeOp, /// Type of frame area rendering for this frame - pub blend_op: u8, + pub blend_op: BlendOp, +} + +impl Default for FrameControl { + fn default() -> FrameControl { + FrameControl { + sequence_number: 0, + width: 0, + height: 0, + x_offset: 0, + y_offset: 0, + delay_num: 1, + delay_den: 30, + dispose_op: DisposeOp::None, + blend_op: BlendOp::Source, + } + } +} + +impl FrameControl { + pub fn set_seq_num(&mut self, s: u32) { + self.sequence_number = s; + } + + pub fn inc_seq_num(&mut self, i: u32) { + self.sequence_number += i; + } + } /// Animation control information @@ -124,6 +219,7 @@ pub struct AnimationControl { pub num_plays: u32, } +/// The type and strength of applied compression. #[derive(Debug, Clone)] pub enum Compression { /// Default level @@ -140,28 +236,6 @@ pub enum Compression { Rle, } -impl From for Compression { - fn from(c: deflate::Compression) -> Self { - match c { - deflate::Compression::Default => Compression::Default, - deflate::Compression::Fast => Compression::Fast, - deflate::Compression::Best => Compression::Best, - } - } -} - -impl From for deflate::CompressionOptions { - fn from(c: Compression) -> Self { - match c { - Compression::Default => deflate::CompressionOptions::default(), - Compression::Fast => deflate::CompressionOptions::fast(), - Compression::Best => deflate::CompressionOptions::high(), - Compression::Huffman => deflate::CompressionOptions::huffman_only(), - Compression::Rle => deflate::CompressionOptions::rle(), - } - } -} - /// PNG info struct #[derive(Debug)] pub struct Info { @@ -194,7 +268,7 @@ impl Default for Info { animation_control: None, // Default to `deflate::Compresion::Fast` and `filter::FilterType::Sub` // to maintain backward compatible output. - compression: deflate::Compression::Fast.into(), + compression: Compression::Fast, filter: filter::FilterType::Sub, } } @@ -296,3 +370,35 @@ bitflags! { } } +/// Mod to encapsulate the converters depending on the `deflate` crate. +/// +/// Since this only contains trait impls, there is no need to make this public, they are simply +/// available when the mod is compiled as well. +#[cfg(feature = "png-encoding")] +mod deflate_convert { + extern crate deflate; + use super::Compression; + + impl From for Compression { + fn from(c: deflate::Compression) -> Self { + match c { + deflate::Compression::Default => Compression::Default, + deflate::Compression::Fast => Compression::Fast, + deflate::Compression::Best => Compression::Best, + } + } + } + + impl From for deflate::CompressionOptions { + fn from(c: Compression) -> Self { + match c { + Compression::Default => deflate::CompressionOptions::default(), + Compression::Fast => deflate::CompressionOptions::fast(), + Compression::Best => deflate::CompressionOptions::high(), + Compression::Huffman => deflate::CompressionOptions::huffman_only(), + Compression::Rle => deflate::CompressionOptions::rle(), + } + } + } +} + diff --git a/third_party/rust/png/src/crc.rs b/third_party/rust/png/src/crc.rs deleted file mode 100644 index 2ec9f5b64dbf..000000000000 --- a/third_party/rust/png/src/crc.rs +++ /dev/null @@ -1,88 +0,0 @@ - -const CRC_TABLE: [u32; 256] = [ - 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, - 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, - 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, - 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, - 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, - 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, - 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, - 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, - 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, - 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, - 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, - 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, - 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, - 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, - 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, - 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, - 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, - 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, - 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, - 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, - 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, - 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, - 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, - 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, - 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, - 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, - 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, - 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, - 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, - 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, - 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, - 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, - 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, - 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, - 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, - 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, - 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, - 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, - 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, - 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, - 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, - 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, - 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, - 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, - 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, - 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, - 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, - 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, - 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, - 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, - 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, - 0x2d02ef8d -]; - -/// Crc-32 checksum calculation -#[derive(Debug)] -pub struct Crc32 { - crc: u32, -} - -impl Crc32 { - /// Create a new hasher. - pub fn new() -> Crc32 { - Crc32 {crc: 0xFFFFFFFF} - } - - /// Resets the hasher. - pub fn reset(&mut self) { - *self = Self::new() - } - - /// Update the internal hasher with the bytes from ```buf``` - pub fn update(&mut self, buf: &[u8]) { - for &byte in buf { - let a = (self.crc ^ byte as u32) & 0xFF; - let b = self.crc >> 8; - - self.crc = CRC_TABLE[a as usize] ^ b; - } - } - - /// Return the computed hash. - pub fn checksum(&self) -> u32 { - self.crc ^ 0xFFFFFFFF - } -} diff --git a/third_party/rust/png/src/decoder/mod.rs b/third_party/rust/png/src/decoder/mod.rs index d8ba025e7c1e..6d8e26d1213f 100644 --- a/third_party/rust/png/src/decoder/mod.rs +++ b/third_party/rust/png/src/decoder/mod.rs @@ -7,11 +7,10 @@ use std::mem; use std::borrow; use std::io::{Read, Write, BufReader, BufRead}; -use traits::{HasParameters, Parameter}; -use common::{ColorType, BitDepth, Info, Transformations}; -use filter::{unfilter, FilterType}; -use chunk::IDAT; -use utils; +use crate::common::{ColorType, BitDepth, Info, Transformations}; +use crate::filter::{unfilter, FilterType}; +use crate::chunk::IDAT; +use crate::utils; /* pub enum InterlaceHandling { @@ -22,22 +21,10 @@ pub enum InterlaceHandling { /// Only fill the needed pixels Sparkle } - -impl Parameter for InterlaceHandling { - fn set_param(self, this: &mut Reader) { - this.color_output = self - } -}*/ - - -impl Parameter> for Transformations { - fn set_param(self, this: &mut Decoder) { - this.transform = self - } -} - +*/ /// Output info +#[derive(Debug)] pub struct OutputInfo { pub width: u32, pub height: u32, @@ -54,15 +41,16 @@ impl OutputInfo { } #[derive(Clone, Copy, Debug)] +/// Limits on the resources the `Decoder` is allowed too use pub struct Limits { - /// max number of pixels: `width * height` (default: 67M = 226) - pub pixels: u64, + /// maximum number of bytes the decoder is allowed to allocate, default is 64Mib + pub bytes: usize, } impl Default for Limits { fn default() -> Limits { Limits { - pixels: 1 << 26, + bytes: 1024*1024*64, } } } @@ -73,7 +61,7 @@ pub struct Decoder { r: R, /// Output transformations transform: Transformations, - /// Images that are considered too big + /// Limits on resources the Decoder is allowed to use limits: Limits, } @@ -85,24 +73,24 @@ impl Decoder { pub fn new_with_limits(r: R, l: Limits) -> Decoder { Decoder { r: r, - transform: ::Transformations::EXPAND | ::Transformations::SCALE_16 | ::Transformations::STRIP_16, + transform: crate::Transformations::EXPAND | crate::Transformations::SCALE_16 | crate::Transformations::STRIP_16, limits: l, } } - /// Images that are considered too big + /// Limit resource usage /// /// ``` /// use std::fs::File; /// use png::{Decoder, Limits}; - /// // This image is 32x32 pixels, so it's more than four pixels in size. + /// // This image is 32x32 pixels, so the deocder will allocate more than four bytes /// let mut limits = Limits::default(); - /// limits.pixels = 4; + /// limits.bytes = 4; /// let mut decoder = Decoder::new_with_limits(File::open("tests/pngsuite/basi0g01.png").unwrap(), limits); /// assert!(decoder.read_info().is_err()); - /// // This image is 32x32 pixels, so it's exactly 1024 pixels in size. + /// // This image is 32x32 pixels, so the decoder will allocate less than 10Kib /// let mut limits = Limits::default(); - /// limits.pixels = 1024; + /// limits.bytes = 10*1024; /// let mut decoder = Decoder::new_with_limits(File::open("tests/pngsuite/basi0g01.png").unwrap(), limits); /// assert!(decoder.read_info().is_ok()); /// ``` @@ -112,8 +100,8 @@ impl Decoder { /// Reads all meta data until the first IDAT chunk pub fn read_info(self) -> Result<(OutputInfo, Reader), DecodingError> { - let mut r = Reader::new(self.r, StreamingDecoder::new(), self.transform); - try!(r.init()); + let mut r = Reader::new(self.r, StreamingDecoder::new(), self.transform, self.limits); + r.init()?; let (ct, bits) = r.output_color_type(); let info = { let info = r.info(); @@ -125,17 +113,17 @@ impl Decoder { line_size: r.output_line_size(info.width), } }; - let (width, height, pixels) = (info.width as u64, info.height as u64, self.limits.pixels); - if width.checked_mul(height).map(|p| p > pixels).unwrap_or(true) { - // DecodingError::Other is used for backwards compatibility. - // In the next major version, add a variant for this. - return Err(DecodingError::Other(borrow::Cow::Borrowed("pixels limit exceeded"))); - } Ok((info, r)) } -} -impl HasParameters for Decoder {} + /// Set the allowed and performed transformations. + /// + /// A transformation is a pre-processing on the raw image data modifying content or encoding. + /// Many options have an impact on memory or CPU usage during decoding. + pub fn set_transformations(&mut self, transform: Transformations) { + self.transform = transform; + } +} struct ReadDecoder { reader: BufReader, @@ -149,13 +137,13 @@ impl ReadDecoder { fn decode_next(&mut self, image_data: &mut Vec) -> Result, DecodingError> { while !self.at_eof { let (consumed, result) = { - let buf = try!(self.reader.fill_buf()); + let buf = self.reader.fill_buf()?; if buf.is_empty() { return Err(DecodingError::Format( "unexpected EOF".into() )) } - try!(self.decoder.update(buf, image_data)) + self.decoder.update(buf, image_data)? }; self.reader.consume(consumed); match result { @@ -187,7 +175,8 @@ pub struct Reader { /// Output transformations transform: Transformations, /// Processed line - processed: Vec + processed: Vec, + limits: Limits, } macro_rules! get_info( @@ -198,7 +187,7 @@ macro_rules! get_info( impl Reader { /// Creates a new PNG reader - fn new(r: R, d: StreamingDecoder, t: Transformations) -> Reader { + fn new(r: R, d: StreamingDecoder, t: Transformations, limits: Limits) -> Reader { Reader { decoder: ReadDecoder { reader: BufReader::with_capacity(CHUNCK_BUFFER_SIZE, r), @@ -211,18 +200,19 @@ impl Reader { prev: Vec::new(), current: Vec::new(), transform: t, - processed: Vec::new() + processed: Vec::new(), + limits, } } /// Reads all meta data until the first IDAT chunk fn init(&mut self) -> Result<(), DecodingError> { - use Decoded::*; + use crate::Decoded::*; if self.decoder.info().is_some() { Ok(()) } else { loop { - match try!(self.decoder.decode_next(&mut Vec::new())) { + match self.decoder.decode_next(&mut Vec::new())? { Some(ChunkBegin(_, IDAT)) => break, None => return Err(DecodingError::Format( "IDAT chunk missing".into() @@ -243,7 +233,7 @@ impl Reader { self.adam7 = Some(utils::Adam7Iterator::new(info.width, info.height)) } } - self.allocate_out_buf(); + self.allocate_out_buf()?; self.prev = vec![0; self.rowlen]; Ok(()) } @@ -256,7 +246,7 @@ impl Reader { /// Decodes the next frame into `buf` pub fn next_frame(&mut self, buf: &mut [u8]) -> Result<(), DecodingError> { // TODO 16 bit - let (color_type, _) = self.output_color_type(); + let (color_type, bit_depth) = self.output_color_type(); let width = get_info!(self).width; if buf.len() < self.output_buffer_size() { return Err(DecodingError::Other( @@ -264,15 +254,15 @@ impl Reader { )) } if get_info!(self).interlaced { - while let Some((row, adam7)) = try!(self.next_interlaced_row()) { + while let Some((row, adam7)) = self.next_interlaced_row()? { let (pass, line, _) = adam7.unwrap(); - let bytes = color_type.samples() as u8; - utils::expand_pass(buf, width * bytes as u32, row, pass, line, bytes); + let samples = color_type.samples() as u8; + utils::expand_pass(buf, width, row, pass, line, samples * (bit_depth as u8)); } } else { let mut len = 0; - while let Some(row) = try!(self.next_row()) { - len += try!((&mut buf[len..]).write(row)); + while let Some(row) = self.next_row()? { + len += (&mut buf[len..]).write(row)?; } } Ok(()) @@ -285,15 +275,15 @@ impl Reader { /// Returns the next processed row of the image pub fn next_interlaced_row(&mut self) -> Result)>, DecodingError> { - use common::ColorType::*; + use crate::common::ColorType::*; let transform = self.transform; - if transform == ::Transformations::IDENTITY { + if transform == crate::Transformations::IDENTITY { self.next_raw_interlaced_row() } else { // swap buffer to circumvent borrow issues let mut buffer = mem::replace(&mut self.processed, Vec::new()); - let (got_next, adam7) = if let Some((row, adam7)) = try!(self.next_raw_interlaced_row()) { - try!((&mut buffer[..]).write(row)); + let (got_next, adam7) = if let Some((row, adam7)) = self.next_raw_interlaced_row()? { + (&mut buffer[..]).write(row)?; (true, adam7) } else { (false, None) @@ -312,7 +302,7 @@ impl Reader { &mut *self.processed }; let mut len = output_buffer.len(); - if transform.contains(::Transformations::EXPAND) { + if transform.contains(crate::Transformations::EXPAND) { match color_type { Indexed => { expand_paletted(output_buffer, get_info!(self))? @@ -332,7 +322,7 @@ impl Reader { _ => () } } - if bit_depth == 16 && transform.intersects(::Transformations::SCALE_16 | ::Transformations::STRIP_16) { + if bit_depth == 16 && transform.intersects(crate::Transformations::SCALE_16 | crate::Transformations::STRIP_16) { len /= 2; for i in 0..len { output_buffer[i] = output_buffer[2 * i]; @@ -351,20 +341,20 @@ impl Reader { /// Returns the color type and the number of bits per sample /// of the data returned by `Reader::next_row` and Reader::frames`. pub fn output_color_type(&mut self) -> (ColorType, BitDepth) { - use common::ColorType::*; + use crate::common::ColorType::*; let t = self.transform; let info = get_info!(self); - if t == ::Transformations::IDENTITY { + if t == crate::Transformations::IDENTITY { (info.color_type, info.bit_depth) } else { let bits = match info.bit_depth as u8 { 16 if t.intersects( - ::Transformations::SCALE_16 | ::Transformations::STRIP_16 + crate::Transformations::SCALE_16 | crate::Transformations::STRIP_16 ) => 8, - _ if t.contains(::Transformations::EXPAND) => 8, + _ if t.contains(crate::Transformations::EXPAND) => 8, n => n }; - let color_type = if t.contains(::Transformations::EXPAND) { + let color_type = if t.contains(crate::Transformations::EXPAND) { let has_trns = info.trns.is_some(); match info.color_type { Grayscale if has_trns => GrayscaleAlpha, @@ -392,7 +382,7 @@ impl Reader { pub fn output_line_size(&self, width: u32) -> usize { let size = self.line_size(width); if get_info!(self).bit_depth as u8 == 16 && self.transform.intersects( - ::Transformations::SCALE_16 | ::Transformations::STRIP_16 + crate::Transformations::SCALE_16 | crate::Transformations::STRIP_16 ) { size / 2 } else { @@ -402,18 +392,18 @@ impl Reader { /// Returns the number of bytes required to decode a deinterlaced row. fn line_size(&self, width: u32) -> usize { - use common::ColorType::*; + use crate::common::ColorType::*; let t = self.transform; let info = get_info!(self); let trns = info.trns.is_some(); // TODO 16 bit let bits = match info.color_type { - Indexed if trns && t.contains(::Transformations::EXPAND) => 4 * 8, - Indexed if t.contains(::Transformations::EXPAND) => 3 * 8, - RGB if trns && t.contains(::Transformations::EXPAND) => 4 * 8, - Grayscale if trns && t.contains(::Transformations::EXPAND) => 2 * 8, - Grayscale if t.contains(::Transformations::EXPAND) => 1 * 8, - GrayscaleAlpha if t.contains(::Transformations::EXPAND) => 2 * 8, + Indexed if trns && t.contains(crate::Transformations::EXPAND) => 4 * 8, + Indexed if t.contains(crate::Transformations::EXPAND) => 3 * 8, + RGB if trns && t.contains(crate::Transformations::EXPAND) => 4 * 8, + Grayscale if trns && t.contains(crate::Transformations::EXPAND) => 2 * 8, + Grayscale if t.contains(crate::Transformations::EXPAND) => 1 * 8, + GrayscaleAlpha if t.contains(crate::Transformations::EXPAND) => 2 * 8, // divide by 2 as it will get mutiplied by two later _ if info.bit_depth as u8 == 16 => info.bits_per_pixel() / 2, _ => info.bits_per_pixel() @@ -425,9 +415,14 @@ impl Reader { len + match extra { 0 => 0, _ => 1 } } - fn allocate_out_buf(&mut self) { + fn allocate_out_buf(&mut self) -> Result<(), DecodingError> { let width = get_info!(self).width; - self.processed = vec![0; self.line_size(width)] + let bytes = self.limits.bytes; + if bytes < self.line_size(width) { + return Err(DecodingError::LimitsExceeded); + } + self.processed = vec![0; self.line_size(width)]; + Ok(()) } /// Returns the next raw row of the image @@ -473,7 +468,7 @@ impl Reader { )) } } else { - let val = try!(self.decoder.decode_next(&mut self.current)); + let val = self.decoder.decode_next(&mut self.current)?; match val { Some(Decoded::ImageData) => {} None => { @@ -546,32 +541,3 @@ fn expand_gray_u8(buffer: &mut [u8], info: &Info) { }) } } -/* -#[cfg(test)] -mod test { - extern crate test; - - use std::fs::File; - use std::io::Read; - - use super::Decoder; - use HasParameters; - - #[bench] - fn bench_big(b: &mut test::Bencher) { - let mut data = Vec::new(); - File::open("tests/pngsuite/PngSuite.png").unwrap().read_to_end(&mut data).unwrap(); - let mut decoder = Decoder::new(&*data); - decoder.set(::Transformations::IDENTITY); - let (info, _) = decoder.read_info().unwrap(); - let mut image = vec![0; info.buffer_size()]; - b.iter(|| { - let mut decoder = Decoder::new(&*data); - decoder.set(::Transformations::IDENTITY); - let (_, mut decoder) = decoder.read_info().unwrap(); - test::black_box(decoder.next_frame(&mut image)).unwrap(); - }); - b.bytes = info.buffer_size() as u64 - } -} -*/ diff --git a/third_party/rust/png/src/decoder/stream.rs b/third_party/rust/png/src/decoder/stream.rs index 4fd2a354cb9f..3ea98b9cf3f3 100644 --- a/third_party/rust/png/src/decoder/stream.rs +++ b/third_party/rust/png/src/decoder/stream.rs @@ -1,3 +1,6 @@ +extern crate crc32fast; +extern crate inflate; + use std::borrow::Cow; use std::default::Default; use std::error; @@ -6,17 +9,30 @@ use std::io; use std::cmp::min; use std::convert::From; -extern crate inflate; +use crc32fast::Hasher as Crc32; use self::inflate::InflateStream; -use crc::Crc32; -use traits::ReadBytesExt; -use common::{ColorType, BitDepth, Info, Unit, PixelDimensions, AnimationControl, FrameControl}; -use chunk::{self, ChunkType, IHDR, IDAT, IEND}; +use crate::traits::ReadBytesExt; +use crate::common::{BitDepth, BlendOp, ColorType, DisposeOp, Info, Unit, PixelDimensions, AnimationControl, FrameControl}; +use crate::chunk::{self, ChunkType, IHDR, IDAT, IEND}; /// TODO check if these size are reasonable pub const CHUNCK_BUFFER_SIZE: usize = 32*1024; +/// Determines if checksum checks should be disabled globally. +/// +/// This is used only in fuzzing. `afl` automatically adds `--cfg fuzzing` to RUSTFLAGS which can +/// be used to detect that build. +const CHECKSUM_DISABLED: bool = cfg!(fuzzing); + +fn zlib_stream() -> InflateStream { + if CHECKSUM_DISABLED { + InflateStream::from_zlib_no_checksum() + } else { + InflateStream::from_zlib() + } +} + #[derive(Debug)] enum U32Value { // CHUNKS @@ -69,7 +85,8 @@ pub enum DecodingError { chunk: ChunkType }, Other(Cow<'static, str>), - CorruptFlateStream + CorruptFlateStream, + LimitsExceeded, } impl error::Error for DecodingError { @@ -80,14 +97,15 @@ impl error::Error for DecodingError { Format(ref desc) | Other(ref desc) => &desc, InvalidSignature => "invalid signature", CrcMismatch { .. } => "CRC error", - CorruptFlateStream => "compressed data stream corrupted" + CorruptFlateStream => "compressed data stream corrupted", + LimitsExceeded => "limits are exceeded" } } } impl fmt::Display for DecodingError { fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { - write!(fmt, "{}", (self as &error::Error).description()) + write!(fmt, "{}", (self as &dyn error::Error).description()) } } @@ -134,7 +152,7 @@ impl StreamingDecoder { StreamingDecoder { state: Some(State::Signature(0, [0; 7])), current_chunk: (Crc32::new(), 0, Vec::with_capacity(CHUNCK_BUFFER_SIZE)), - inflater: if cfg!(fuzzing) {InflateStream::from_zlib_no_checksum()} else {InflateStream::from_zlib()}, + inflater: zlib_stream(), info: None, current_seq_no: None, have_idat: false @@ -147,7 +165,7 @@ impl StreamingDecoder { self.current_chunk.0 = Crc32::new(); self.current_chunk.1 = 0; self.current_chunk.2.clear(); - self.inflater = if cfg!(fuzzing) {InflateStream::from_zlib_no_checksum()} else {InflateStream::from_zlib()}; + self.inflater = zlib_stream(); self.info = None; self.current_seq_no = None; self.have_idat = false; @@ -237,7 +255,8 @@ impl StreamingDecoder { ) }, Crc(type_str) => { - if cfg!(fuzzing) || val == self.current_chunk.0.checksum() { + let sum = self.current_chunk.0.clone().finalize(); + if CHECKSUM_DISABLED || val == sum { goto!( State::U32(U32Value::Length), emit if type_str == IEND { @@ -250,7 +269,7 @@ impl StreamingDecoder { Err(DecodingError::CrcMismatch { recover: 1, crc_val: val, - crc_sum: self.current_chunk.0.checksum(), + crc_sum: sum, chunk: type_str }) } @@ -279,7 +298,7 @@ impl StreamingDecoder { chunk::fdAT => { if let Some(seq_no) = self.current_seq_no { let mut buf = &self.current_chunk.2[..]; - let next_seq_no = try!(buf.read_be()); + let next_seq_no = buf.read_be()?; if next_seq_no != seq_no + 1 { return Err(DecodingError::Format(format!( "Sequence is not in order, expected #{} got #{}.", @@ -300,7 +319,7 @@ impl StreamingDecoder { // Handle other chunks _ => { if self.current_chunk.1 == 0 { // complete chunk - Ok((0, try!(self.parse_chunk(type_str)))) + Ok((0, self.parse_chunk(type_str)?)) } else { goto!( 0, ReadChunk(type_str, true), @@ -341,7 +360,7 @@ impl StreamingDecoder { } DecodeData(type_str, mut n) => { let chunk_len = self.current_chunk.2.len(); - let (c, data) = try!(self.inflater.update(&self.current_chunk.2[n..])); + let (c, data) = self.inflater.update(&self.current_chunk.2[n..])?; image_data.extend_from_slice(data); n += c; if n == chunk_len && data.len() == 0 && c == 0 { @@ -408,7 +427,7 @@ impl StreamingDecoder { fn parse_fctl(&mut self) -> Result { let mut buf = &self.current_chunk.2[..]; - let next_seq_no = try!(buf.read_be()); + let next_seq_no = buf.read_be()?; // Asuming that fcTL is required before *every* fdAT-sequence self.current_seq_no = Some(if let Some(seq_no) = self.current_seq_no { @@ -430,17 +449,23 @@ impl StreamingDecoder { } 0 }); - self.inflater = if cfg!(fuzzing) {InflateStream::from_zlib_no_checksum()} else {InflateStream::from_zlib()}; + self.inflater = zlib_stream(); let fc = FrameControl { sequence_number: next_seq_no, - width: try!(buf.read_be()), - height: try!(buf.read_be()), - x_offset: try!(buf.read_be()), - y_offset: try!(buf.read_be()), - delay_num: try!(buf.read_be()), - delay_den: try!(buf.read_be()), - dispose_op: try!(buf.read_be()), - blend_op : try!(buf.read_be()), + width: buf.read_be()?, + height: buf.read_be()?, + x_offset: buf.read_be()?, + y_offset: buf.read_be()?, + delay_num: buf.read_be()?, + delay_den: buf.read_be()?, + dispose_op: match DisposeOp::from_u8(buf.read_be()?) { + Some(dispose_op) => dispose_op, + None => return Err(DecodingError::Format("invalid dispose operation".into())) + }, + blend_op : match BlendOp::from_u8(buf.read_be()?) { + Some(blend_op) => blend_op, + None => return Err(DecodingError::Format("invalid blend operation".into())) + }, }; self.info.as_mut().unwrap().frame_control = Some(fc.clone()); Ok(Decoded::FrameControl(fc)) @@ -455,8 +480,8 @@ impl StreamingDecoder { } else { let mut buf = &self.current_chunk.2[..]; let actl = AnimationControl { - num_frames: try!(buf.read_be()), - num_plays: try!(buf.read_be()) + num_frames: buf.read_be()?, + num_plays: buf.read_be()? }; self.info.as_mut().unwrap().animation_control = Some(actl); Ok(Decoded::AnimationControl(actl)) @@ -475,9 +500,9 @@ impl StreamingDecoder { fn parse_trns(&mut self) -> Result { - use common::ColorType::*; + use crate::common::ColorType::*; let (color_type, bit_depth) = { - let info = try!(self.get_info_or_err()); + let info = self.get_info_or_err()?; (info.color_type, info.bit_depth as u8) }; let mut vec = Vec::new(); @@ -539,9 +564,9 @@ impl StreamingDecoder { )) } else { let mut buf = &self.current_chunk.2[..]; - let xppu = try!(buf.read_be()); - let yppu = try!(buf.read_be()); - let unit = try!(buf.read_be()); + let xppu = buf.read_be()?; + let yppu = buf.read_be()?; + let unit = buf.read_be()?; let unit = match Unit::from_u8(unit) { Some(unit) => unit, None => return Err(DecodingError::Format( @@ -562,35 +587,35 @@ impl StreamingDecoder { -> Result { // TODO: check if color/bit depths combination is valid let mut buf = &self.current_chunk.2[..]; - let width = try!(buf.read_be()); - let height = try!(buf.read_be()); - let bit_depth = try!(buf.read_be()); + let width = buf.read_be()?; + let height = buf.read_be()?; + let bit_depth = buf.read_be()?; let bit_depth = match BitDepth::from_u8(bit_depth) { Some(bits) => bits, None => return Err(DecodingError::Format( format!("invalid bit depth ({})", bit_depth).into() )) }; - let color_type = try!(buf.read_be()); + let color_type = buf.read_be()?; let color_type = match ColorType::from_u8(color_type) { Some(color_type) => color_type, None => return Err(DecodingError::Format( format!("invalid color type ({})", color_type).into() )) }; - match try!(buf.read_be()) { // compression method + match buf.read_be()? { // compression method 0u8 => (), n => return Err(DecodingError::Format( format!("unknown compression method ({})", n).into() )) } - match try!(buf.read_be()) { // filter method + match buf.read_be()? { // filter method 0u8 => (), n => return Err(DecodingError::Format( format!("unknown filter method ({})", n).into() )) } - let interlaced = match try!(buf.read_be()) { + let interlaced = match buf.read_be()? { 0u8 => false, 1 => { true diff --git a/third_party/rust/png/src/encoder.rs b/third_party/rust/png/src/encoder.rs index f84444bdbc33..4fcab987f480 100644 --- a/third_party/rust/png/src/encoder.rs +++ b/third_party/rust/png/src/encoder.rs @@ -1,17 +1,19 @@ +extern crate crc32fast; extern crate deflate; use std::borrow::Cow; use std::error; use std::fmt; -use std::io::{self, Write}; +use std::io::{self, Read, Write}; use std::mem; use std::result; -use chunk; -use crc::Crc32; -use common::{Info, ColorType, BitDepth, Compression}; -use filter::{FilterType, filter}; -use traits::{WriteBytesExt, HasParameters, Parameter}; +use crc32fast::Hasher as Crc32; + +use crate::chunk; +use crate::common::{Info, ColorType, BitDepth, Compression}; +use crate::filter::{FilterType, filter}; +use crate::traits::WriteBytesExt; pub type Result = result::Result; @@ -33,7 +35,7 @@ impl error::Error for EncodingError { impl fmt::Display for EncodingError { fn fmt(&self, fmt: &mut fmt::Formatter) -> result::Result<(), fmt::Error> { - write!(fmt, "{}", (self as &error::Error).description()) + write!(fmt, "{}", (self as &dyn error::Error).description()) } } @@ -44,7 +46,7 @@ impl From for EncodingError { } impl From for io::Error { fn from(err: EncodingError) -> io::Error { - io::Error::new(io::ErrorKind::Other, (&err as &error::Error).description()) + io::Error::new(io::ErrorKind::Other, (&err as &dyn error::Error).description()) } } @@ -65,34 +67,39 @@ impl Encoder { pub fn write_header(self) -> Result> { Writer::new(self.w, self.info).init() } -} -impl HasParameters for Encoder {} - -impl Parameter> for ColorType { - fn set_param(self, this: &mut Encoder) { - this.info.color_type = self + /// Set the color of the encoded image. + /// + /// These correspond to the color types in the png IHDR data that will be written. The length + /// of the image data that is later supplied must match the color type, otherwise an error will + /// be emitted. + pub fn set_color(&mut self, color: ColorType) { + self.info.color_type = color; } -} -impl Parameter> for BitDepth { - fn set_param(self, this: &mut Encoder) { - this.info.bit_depth = self + /// Set the indicated depth of the image data. + pub fn set_depth(&mut self, depth: BitDepth) { + self.info.bit_depth = depth; } -} -/// Set compression param for a ```Compression``` or any type that can transform -/// into a ```Compression```, notably ```deflate::Compression``` and -/// ```deflate::CompressionOptions``` which "just work". -impl> Parameter> for C { - fn set_param(self, this: &mut Encoder) { - this.info.compression = self.into() + /// Set compression parameters. + /// + /// Accepts a `Compression` or any type that can transform into a `Compression`. Notably `deflate::Compression` and + /// `deflate::CompressionOptions` which "just work". + pub fn set_compression>(&mut self, compression: C) { + self.info.compression = compression.into(); } -} -impl Parameter> for FilterType { - fn set_param(self, this: &mut Encoder) { - this.info.filter = self + /// Set the used filter type. + /// + /// The default filter is [`FilterType::Sub`] which provides a basic prediction algorithm for + /// sample values based on the previous. For a potentially better compression ratio, at the + /// cost of more complex processing, try out [`FilterType::Paeth`]. + /// + /// [`FilterType::Sub`]: enum.FilterType.html#variant.Sub + /// [`FilterType::Paeth`]: enum.FilterType.html#variant.Paeth + pub fn set_filter(&mut self, filter: FilterType) { + self.info.filter = filter; } } @@ -109,25 +116,25 @@ impl Writer { } fn init(mut self) -> Result { - try!(self.w.write_all(&[137, 80, 78, 71, 13, 10, 26, 10])); + self.w.write_all(&[137, 80, 78, 71, 13, 10, 26, 10])?; let mut data = [0; 13]; - try!((&mut data[..]).write_be(self.info.width)); - try!((&mut data[4..]).write_be(self.info.height)); + (&mut data[..]).write_be(self.info.width)?; + (&mut data[4..]).write_be(self.info.height)?; data[8] = self.info.bit_depth as u8; data[9] = self.info.color_type as u8; data[12] = if self.info.interlaced { 1 } else { 0 }; - try!(self.write_chunk(chunk::IHDR, &data)); + self.write_chunk(chunk::IHDR, &data)?; Ok(self) } pub fn write_chunk(&mut self, name: [u8; 4], data: &[u8]) -> Result<()> { - try!(self.w.write_be(data.len() as u32)); - try!(self.w.write_all(&name)); - try!(self.w.write_all(data)); + self.w.write_be(data.len() as u32)?; + self.w.write_all(&name)?; + self.w.write_all(data)?; let mut crc = Crc32::new(); crc.update(&name); crc.update(data); - try!(self.w.write_be(crc.checksum())); + self.w.write_be(crc.finalize())?; Ok(()) } @@ -146,12 +153,29 @@ impl Writer { let filter_method = self.info.filter; for line in data.chunks(in_len) { current.copy_from_slice(&line); - try!(zlib.write_all(&[filter_method as u8])); + zlib.write_all(&[filter_method as u8])?; filter(filter_method, bpp, &prev, &mut current); - try!(zlib.write_all(¤t)); + zlib.write_all(¤t)?; mem::swap(&mut prev, &mut current); } - self.write_chunk(chunk::IDAT, &try!(zlib.finish())) + self.write_chunk(chunk::IDAT, &zlib.finish()?) + } + + /// Create an stream writer. + /// + /// This allows you create images that do not fit + /// in memory. The default chunk size is 4K, use + /// `stream_writer_with_size` to set another chuck + /// size. + pub fn stream_writer(&mut self) -> StreamWriter { + self.stream_writer_with_size(4 * 1024) + } + + /// Create a stream writer with custom buffer size. + /// + /// See `stream_writer` + pub fn stream_writer_with_size(&mut self, size: usize) -> StreamWriter { + StreamWriter::new(self, size) } } @@ -161,6 +185,125 @@ impl Drop for Writer { } } +struct ChunkWriter<'a, W: Write> { + writer: &'a mut Writer, + buffer: Vec, + index: usize, +} + +impl<'a, W: Write> ChunkWriter<'a, W> { + fn new(writer: &'a mut Writer, buf_len: usize) -> ChunkWriter<'a, W> { + ChunkWriter { + writer, + buffer: vec![0; buf_len], + index: 0, + } + } +} + +impl<'a, W: Write> Write for ChunkWriter<'a, W> { + fn write(&mut self, mut buf: &[u8]) -> io::Result { + let written = buf.read(&mut self.buffer[self.index..])?; + self.index += written; + + if self.index + 1 >= self.buffer.len() { + self.writer.write_chunk(chunk::IDAT, &self.buffer)?; + self.index = 0; + } + + Ok(written) + } + + fn flush(&mut self) -> io::Result<()> { + if self.index > 0 { + self.writer.write_chunk(chunk::IDAT, &self.buffer[..self.index+1])?; + } + self.index = 0; + Ok(()) + } +} + +impl<'a, W: Write> Drop for ChunkWriter<'a, W> { + fn drop(&mut self) { + let _ = self.flush(); + } +} + + +/// Streaming png writer +/// +/// This may may silently fail in the destructor so it is a good idea to call +/// `finish` or `flush` before droping. +pub struct StreamWriter<'a, W: Write> { + writer: deflate::write::ZlibEncoder>, + prev_buf: Vec, + curr_buf: Vec, + index: usize, + bpp: usize, + filter: FilterType, +} + +impl<'a, W: Write> StreamWriter<'a, W> { + fn new(writer: &'a mut Writer, buf_len: usize) -> StreamWriter<'a, W> { + let bpp = writer.info.bytes_per_pixel(); + let in_len = writer.info.raw_row_length() - 1; + let filter = writer.info.filter; + let prev_buf = vec![0; in_len]; + let curr_buf = vec![0; in_len]; + + let compression = writer.info.compression.clone(); + let chunk_writer = ChunkWriter::new(writer, buf_len); + let zlib = deflate::write::ZlibEncoder::new(chunk_writer, compression); + + StreamWriter { + writer: zlib, + index: 0, + prev_buf, + curr_buf, + bpp, + filter, + } + } + + pub fn finish(mut self) -> Result<()> { + // TODO: call `writer.finish` somehow? + self.flush()?; + Ok(()) + } +} + +impl<'a, W: Write> Write for StreamWriter<'a, W> { + fn write(&mut self, mut buf: &[u8]) -> io::Result { + let written = buf.read(&mut self.curr_buf[self.index..])?; + self.index += written; + + if self.index >= self.curr_buf.len() { + self.writer.write_all(&[self.filter as u8])?; + filter(self.filter, self.bpp, &self.prev_buf, &mut self.curr_buf); + self.writer.write_all(&self.curr_buf)?; + mem::swap(&mut self.prev_buf, &mut self.curr_buf); + self.index = 0; + } + + Ok(written) + } + + fn flush(&mut self) -> io::Result<()> { + self.writer.flush()?; + if self.index > 0 { + let message = format!("wrong data size, got {} bytes too many", self.index); + return Err(EncodingError::Format(message.into()).into()); + } + Ok(()) + } +} + +impl<'a, W: Write> Drop for StreamWriter<'a, W> { + fn drop(&mut self) { + let _ = self.flush(); + } +} + #[cfg(test)] mod tests { use super::*; @@ -183,7 +326,7 @@ mod tests { continue; } // Decode image - let decoder = ::Decoder::new(File::open(path).unwrap()); + let decoder = crate::Decoder::new(File::open(path).unwrap()); let (info, mut reader) = decoder.read_info().unwrap(); if info.line_size != 32 { // TODO encoding only works with line size 32? @@ -203,7 +346,54 @@ mod tests { encoder.write_image_data(&buf).unwrap(); } // Decode encoded decoded image - let decoder = ::Decoder::new(&*out); + let decoder = crate::Decoder::new(&*out); + let (info, mut reader) = decoder.read_info().unwrap(); + let mut buf2 = vec![0; info.buffer_size()]; + reader.next_frame(&mut buf2).unwrap(); + // check if the encoded image is ok: + assert_eq!(buf, buf2); + } + } + } + + #[test] + fn roundtrip_stream() { + // More loops = more random testing, but also more test wait time + for _ in 0..10 { + for path in glob::glob("tests/pngsuite/*.png").unwrap().map(|r| r.unwrap()) { + if path.file_name().unwrap().to_str().unwrap().starts_with("x") { + // x* files are expected to fail to decode + continue; + } + // Decode image + let decoder = crate::Decoder::new(File::open(path).unwrap()); + let (info, mut reader) = decoder.read_info().unwrap(); + if info.line_size != 32 { + // TODO encoding only works with line size 32? + continue; + } + let mut buf = vec![0; info.buffer_size()]; + reader.next_frame(&mut buf).unwrap(); + // Encode decoded image + let mut out = Vec::new(); + { + let mut wrapper = RandomChunkWriter { + rng: self::rand::thread_rng(), + w: &mut out + }; + + let mut encoder = Encoder::new(&mut wrapper, info.width, info.height).write_header().unwrap(); + let mut stream_writer = encoder.stream_writer(); + + let mut outer_wrapper = RandomChunkWriter { + rng: self::rand::thread_rng(), + w: &mut stream_writer + }; + + outer_wrapper.write_all(&buf).unwrap(); + } + // Decode encoded decoded image + let decoder = crate::Decoder::new(&*out); let (info, mut reader) = decoder.read_info().unwrap(); let mut buf2 = vec![0; info.buffer_size()]; reader.next_frame(&mut buf2).unwrap(); @@ -223,8 +413,8 @@ mod tests { let output = vec![0u8; 1024]; let writer = Cursor::new(output); let mut encoder = Encoder::new(writer, width as u32, height as u32); - encoder.set(BitDepth::Eight); - encoder.set(ColorType::RGB); + encoder.set_depth(BitDepth::Eight); + encoder.set_color(ColorType::RGB); let mut png_writer = encoder.write_header()?; let correct_image_size = width * height * 3; @@ -254,4 +444,4 @@ mod tests { } } -} \ No newline at end of file +} diff --git a/third_party/rust/png/src/filter.rs b/third_party/rust/png/src/filter.rs index 7db9afe320e5..b11751f6f59e 100644 --- a/third_party/rust/png/src/filter.rs +++ b/third_party/rust/png/src/filter.rs @@ -1,5 +1,10 @@ use std; +/// The byte level filter applied to scanlines to prepare them for compression. +/// +/// Compression in general benefits from repetitive data. The filter is a content-aware method of +/// compressing the range of occurring byte values to help the compression algorithm. Note that +/// this does not operate on pixels but on raw bytes of a scanline. #[derive(Debug, Clone, Copy, PartialEq, Eq)] #[repr(u8)] pub enum FilterType { diff --git a/third_party/rust/png/src/lib.rs b/third_party/rust/png/src/lib.rs index 1d0a353312e2..49ece4337cff 100644 --- a/third_party/rust/png/src/lib.rs +++ b/third_party/rust/png/src/lib.rs @@ -21,33 +21,30 @@ //! ## Encoder //! ### Using the encoder //! ```ignore -//! // For reading and opening files -//! use std::path::Path; -//! use std::fs::File; -//! use std::io::BufWriter; -//! // To use encoder.set() -//! use png::HasParameters; +//! // For reading and opening files +//! use std::path::Path; +//! use std::fs::File; +//! use std::io::BufWriter; +//! // To use encoder.set() +//! use png::HasParameters; //! -//! let path = Path::new(r"/path/to/image.png"); -//! let file = File::create(path).unwrap(); -//! let ref mut w = BufWriter::new(file); +//! let path = Path::new(r"/path/to/image.png"); +//! let file = File::create(path).unwrap(); +//! let ref mut w = BufWriter::new(file); //! -//! let mut encoder = png::Encoder::new(w, 2, 1); // Width is 2 pixels and height is 1. -//! encoder.set(png::ColorType::RGBA).set(png::BitDepth::Eight); -//! let mut writer = encoder.write_header().unwrap(); +//! let mut encoder = png::Encoder::new(w, 2, 1); // Width is 2 pixels and height is 1. +//! encoder.set(png::ColorType::RGBA).set(png::BitDepth::Eight); +//! let mut writer = encoder.write_header().unwrap(); //! -//! let data = [255, 0, 0, 255, 0, 0, 0, 255]; // An array containing a RGBA sequence. First pixel is red and second pixel is black. -//! writer.write_image_data(&data).unwrap(); // Save +//! let data = [255, 0, 0, 255, 0, 0, 0, 255]; // An array containing a RGBA sequence. First pixel is red and second pixel is black. +//! writer.write_image_data(&data).unwrap(); // Save //! ``` //! //#![cfg_attr(test, feature(test))] #[macro_use] extern crate bitflags; -extern crate num_iter; - pub mod chunk; -mod crc; mod decoder; #[cfg(feature = "png-encoding")] mod encoder; @@ -56,10 +53,8 @@ mod traits; mod common; mod utils; -pub use common::*; -pub use decoder::{Decoder, Reader, OutputInfo, StreamingDecoder, Decoded, DecodingError, Limits}; +pub use crate::common::*; +pub use crate::decoder::{Decoder, Reader, OutputInfo, StreamingDecoder, Decoded, DecodingError, Limits}; #[cfg(feature = "png-encoding")] -pub use encoder::{Encoder, Writer, EncodingError}; -pub use filter::FilterType; - -pub use traits::{Parameter, HasParameters}; +pub use crate::encoder::{Encoder, Writer, StreamWriter, EncodingError}; +pub use crate::filter::FilterType; diff --git a/third_party/rust/png/src/traits.rs b/third_party/rust/png/src/traits.rs index 6778b839261a..1fe20bf50609 100644 --- a/third_party/rust/png/src/traits.rs +++ b/third_party/rust/png/src/traits.rs @@ -1,19 +1,5 @@ use std::io; -/// Configuration parameter trait -pub trait Parameter { - fn set_param(self, &mut Object); -} - -/// Object has parameters -pub trait HasParameters: Sized { - fn set>(&mut self, value: T) -> &mut Self { - value.set_param(self); - self - } -} - - // Will be replaced by stdlib solution fn read_all(this: &mut R, buf: &mut [u8]) -> io::Result<()> { let mut total = 0; @@ -39,7 +25,7 @@ pub trait ReadBytesExt: io::Read { /// Write extension to write big endian data pub trait WriteBytesExt: io::Write { /// Writes `T` to a bytes stream. Most significant byte first. - fn write_be(&mut self, T) -> io::Result<()>; + fn write_be(&mut self, _: T) -> io::Result<()>; } @@ -47,7 +33,7 @@ impl ReadBytesExt for W { #[inline] fn read_be(&mut self) -> io::Result { let mut byte = [0]; - try!(read_all(self, &mut byte)); + read_all(self, &mut byte)?; Ok(byte[0]) } } @@ -55,7 +41,7 @@ impl ReadBytesExt for W { #[inline] fn read_be(&mut self) -> io::Result { let mut bytes = [0, 0]; - try!(read_all(self, &mut bytes)); + read_all(self, &mut bytes)?; Ok((bytes[0] as u16) << 8 | bytes[1] as u16) } } @@ -64,7 +50,7 @@ impl ReadBytesExt for W { #[inline] fn read_be(&mut self) -> io::Result { let mut bytes = [0, 0, 0, 0]; - try!(read_all(self, &mut bytes)); + read_all(self, &mut bytes)?; Ok( (bytes[0] as u32) << 24 | (bytes[1] as u32) << 16 | (bytes[2] as u32) << 8 diff --git a/third_party/rust/png/src/utils.rs b/third_party/rust/png/src/utils.rs index cbad3afafc21..84a9542bff39 100644 --- a/third_party/rust/png/src/utils.rs +++ b/third_party/rust/png/src/utils.rs @@ -1,6 +1,6 @@ //! Utility functions -use std::iter::repeat; -use num_iter::range_step; +use std::iter::{repeat, StepBy}; +use std::ops::Range; #[inline(always)] pub fn unpack_bits(buf: &mut [u8], channels: usize, bit_depth: u8, func: F) @@ -21,13 +21,11 @@ where F: Fn(u8, &mut[u8]) { .rev() // reverse iterator .flat_map(|idx| // this has to be reversed too - range_step(0, 8, bit_depth) + (0..8).step_by(bit_depth.into()) .zip(repeat(idx)) ) .skip(skip); - let channels = channels as isize; - let j = range_step(buf.len() as isize - channels, -channels, -channels); - //let j = range_step(0, buf.len(), channels).rev(); // ideal solution; + let j = (0..=buf.len() - channels).rev().step_by(channels); for ((shift, i), j) in i.zip(j) { let pixel = (buf[i] & (mask << shift)) >> shift; func(pixel, &mut buf[j as usize..(j + channels) as usize]) @@ -35,10 +33,8 @@ where F: Fn(u8, &mut[u8]) { } pub fn expand_trns_line(buf: &mut[u8], trns: &[u8], channels: usize) { - let channels = channels as isize; - let i = range_step(buf.len() as isize / (channels+1) * channels - channels, -channels, -channels); - let j = range_step(buf.len() as isize - (channels+1), -(channels+1), -(channels+1)); - let channels = channels as usize; + let i = (0..=buf.len() / (channels+1) * channels - channels).rev().step_by(channels); + let j = (0..=buf.len() - (channels+1)).rev().step_by(channels+1); for (i, j) in i.zip(j) { let i_pixel = i as usize; let j_chunk = j as usize; @@ -54,11 +50,9 @@ pub fn expand_trns_line(buf: &mut[u8], trns: &[u8], channels: usize) { } pub fn expand_trns_line16(buf: &mut[u8], trns: &[u8], channels: usize) { - let channels = channels as isize; let c2 = 2 * channels; - let i = range_step(buf.len() as isize / (c2+2) * c2 - c2, -c2, -c2); - let j = range_step(buf.len() as isize - (c2+2), -(c2+2), -(c2+2)); - let c2 = c2 as usize; + let i = (0..=buf.len() / (c2+2) * c2 - c2).rev().step_by(c2); + let j = (0..=buf.len() - (c2+2)).rev().step_by(c2+2); for (i, j) in i.zip(j) { let i_pixel = i as usize; let j_chunk = j as usize; @@ -155,33 +149,76 @@ impl Iterator for Adam7Iterator { } } -macro_rules! expand_pass( - ($img:expr, $scanline:expr, $j:ident, $pos:expr, $bytes_pp:expr) => { - for ($j, pixel) in $scanline.chunks($bytes_pp).enumerate() { - for (offset, val) in pixel.iter().enumerate() { - $img[$pos + offset] = *val - } +fn subbyte_pixels<'a>(scanline: &'a [u8], bits_pp: usize) -> impl Iterator + 'a { + (0..scanline.len() * 8).step_by(bits_pp).map(move |bit_idx| { + let byte_idx = bit_idx / 8; + + // sub-byte samples start in the high-order bits + let rem = 8 - bit_idx % 8 - bits_pp; + + match bits_pp { + // evenly divides bytes + 1 => (scanline[byte_idx] >> rem) & 1, + 2 => (scanline[byte_idx] >> rem) & 3, + 4 => (scanline[byte_idx] >> rem) & 15, + _ => unreachable!(), } - } -); + }) +} + +/// Given pass, image width, and line number, produce an iterator of bit positions of pixels to copy +/// from the input scanline to the image buffer. +fn expand_adam7_bits(pass: u8, width: usize, line_no: usize, bits_pp: usize) -> StepBy> { + let (line_mul, line_off, samp_mul, samp_off) = match pass { + 1 => (8, 0, 8, 0), + 2 => (8, 0, 8, 4), + 3 => (8, 4, 4, 0), + 4 => (4, 0, 4, 2), + 5 => (4, 2, 2, 0), + 6 => (2, 0, 2, 1), + 7 => (2, 1, 1, 0), + _ => panic!("Adam7 pass out of range: {}", pass) + }; + + // the equivalent line number in progressive scan + let prog_line = line_mul * line_no + line_off; + // line width is rounded up to the next byte + let line_width = width * bits_pp + 7 & !7; + let line_start = prog_line * line_width; + let start = line_start + (samp_off * bits_pp); + let stop = line_start + (width * bits_pp); + + (start .. stop).step_by(bits_pp * samp_mul) +} /// Expands an Adam 7 pass pub fn expand_pass( img: &mut [u8], width: u32, scanline: &[u8], - pass: u8, line_no: u32, bytes_pp: u8) { - let line_no = line_no as usize; + pass: u8, line_no: u32, bits_pp: u8) { + let width = width as usize; - let bytes_pp = bytes_pp as usize; - match pass { - 1 => expand_pass!(img, scanline, j, 8*line_no * width + bytes_pp * j*8 , bytes_pp), - 2 => expand_pass!(img, scanline, j, 8*line_no * width + bytes_pp *(j*8 + 4), bytes_pp), - 3 => expand_pass!(img, scanline, j, (8*line_no+4) * width + bytes_pp * j*4 , bytes_pp), - 4 => expand_pass!(img, scanline, j, 4*line_no * width + bytes_pp *(j*4 + 2), bytes_pp), - 5 => expand_pass!(img, scanline, j, (4*line_no+2) * width + bytes_pp * j*2 , bytes_pp), - 6 => expand_pass!(img, scanline, j, 2*line_no * width + bytes_pp *(j*2+1) , bytes_pp), - 7 => expand_pass!(img, scanline, j, (2*line_no+1) * width + bytes_pp * j , bytes_pp), - _ => {} - } + let line_no = line_no as usize; + let bits_pp = bits_pp as usize; + + // pass is out of range but don't blow up + if pass == 0 || pass > 7 { return; } + + let bit_indices = expand_adam7_bits(pass, width, line_no, bits_pp); + + if bits_pp < 8 { + for (pos, px) in bit_indices.zip(subbyte_pixels(scanline, bits_pp)) { + let rem = 8 - pos % 8 - bits_pp; + img[pos / 8] |= px << rem as u8; + } + } else { + let bytes_pp = bits_pp / 8; + + for (bitpos, px) in bit_indices.zip(scanline.chunks(bytes_pp)) { + for (offset, val) in px.iter().enumerate() { + img[bitpos / 8 + offset] = *val; + } + } + } } #[test] @@ -196,3 +233,129 @@ fn test_adam7() { let passes: Vec<_> = it.collect(); assert_eq!(&*passes, &[(1, 0, 1), (4, 0, 1), (5, 0, 2), (6, 0, 2), (6, 1, 2), (7, 0, 4), (7, 1, 4)]); } + +#[test] +fn test_subbyte_pixels() { + let scanline = &[0b10101010, 0b10101010]; + + + let pixels = subbyte_pixels(scanline, 1).collect::>(); + assert_eq!(pixels.len(), 16); + assert_eq!(pixels, [1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0]); +} + +#[test] +fn test_expand_adam7_bits() { + let width = 32; + let bits_pp = 1; + + let expected = |offset: usize, step: usize, count: usize| (0 .. count).map(move |i| step * i + offset).collect::>(); + + for line_no in 0..8 { + let start = 8 * line_no * width; + + assert_eq!( + expand_adam7_bits(1, width, line_no, bits_pp).collect::>(), + expected(start, 8, 4) + ); + + let start = start + 4; + + assert_eq!( + expand_adam7_bits(2, width, line_no, bits_pp).collect::>(), + expected(start, 8, 4) + ); + + let start = (8 * line_no + 4) as usize * width as usize; + + assert_eq!( + expand_adam7_bits(3, width, line_no, bits_pp).collect::>(), + expected(start, 4, 8) + ); + } + + for line_no in 0 .. 16 { + let start = 4 * line_no * width + 2; + + assert_eq!( + expand_adam7_bits(4, width, line_no, bits_pp).collect::>(), + expected(start, 4, 8) + ); + + let start = (4 * line_no + 2) * width; + + assert_eq!( + expand_adam7_bits(5, width, line_no, bits_pp).collect::>(), + expected(start, 2, 16) + ) + } + + for line_no in 0 .. 32 { + let start = 2 * line_no * width + 1; + + assert_eq!( + expand_adam7_bits(6, width, line_no, bits_pp).collect::>(), + expected(start, 2, 16), + "line_no: {}", line_no + ); + + let start = (2 * line_no + 1) * width; + + assert_eq!( + expand_adam7_bits(7, width, line_no, bits_pp).collect::>(), + expected(start, 1, 32) + ); + } +} + +#[test] +fn test_expand_pass_subbyte() { + let mut img = [0u8; 8]; + let width = 8; + let bits_pp = 1; + + expand_pass(&mut img, width, &[0b10000000], 1, 0, bits_pp); + assert_eq!(img, [0b10000000u8, 0, 0, 0, 0, 0, 0, 0]); + + expand_pass(&mut img, width, &[0b10000000], 2, 0, bits_pp); + assert_eq!(img, [0b10001000u8, 0, 0, 0, 0, 0, 0, 0]); + + expand_pass(&mut img, width, &[0b11000000], 3, 0, bits_pp); + assert_eq!(img, [0b10001000u8, 0, 0, 0, 0b10001000, 0, 0, 0]); + + expand_pass(&mut img, width, &[0b11000000], 4, 0, bits_pp); + assert_eq!(img, [0b10101010u8, 0, 0, 0, 0b10001000, 0, 0, 0]); + + expand_pass(&mut img, width, &[0b11000000], 4, 1, bits_pp); + assert_eq!(img, [0b10101010u8, 0, 0, 0, 0b10101010, 0, 0, 0]); + + expand_pass(&mut img, width, &[0b11110000], 5, 0, bits_pp); + assert_eq!(img, [0b10101010u8, 0, 0b10101010, 0, 0b10101010, 0, 0, 0]); + + expand_pass(&mut img, width, &[0b11110000], 5, 1, bits_pp); + assert_eq!(img, [0b10101010u8, 0, 0b10101010, 0, 0b10101010, 0, 0b10101010, 0]); + + expand_pass(&mut img, width, &[0b11110000], 6, 0, bits_pp); + assert_eq!(img, [0b11111111u8, 0, 0b10101010, 0, 0b10101010, 0, 0b10101010, 0]); + + expand_pass(&mut img, width, &[0b11110000], 6, 1, bits_pp); + assert_eq!(img, [0b11111111u8, 0, 0b11111111, 0, 0b10101010, 0, 0b10101010, 0]); + + expand_pass(&mut img, width, &[0b11110000], 6, 2, bits_pp); + assert_eq!(img, [0b11111111u8, 0, 0b11111111, 0, 0b11111111, 0, 0b10101010, 0]); + + expand_pass(&mut img, width, &[0b11110000], 6, 3, bits_pp); + assert_eq!([0b11111111u8, 0, 0b11111111, 0, 0b11111111, 0, 0b11111111, 0], img); + + expand_pass(&mut img, width, &[0b11111111], 7, 0, bits_pp); + assert_eq!([0b11111111u8, 0b11111111, 0b11111111, 0, 0b11111111, 0, 0b11111111, 0], img); + + expand_pass(&mut img, width, &[0b11111111], 7, 1, bits_pp); + assert_eq!([0b11111111u8, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0, 0b11111111, 0], img); + + expand_pass(&mut img, width, &[0b11111111], 7, 2, bits_pp); + assert_eq!([0b11111111u8, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0], img); + + expand_pass(&mut img, width, &[0b11111111], 7, 3, bits_pp); + assert_eq!([0b11111111u8, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111], img); +}