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
This commit is contained in:
Bastien Orivel 2019-08-12 12:39:47 +00:00
parent 4665febab6
commit 9c386d0de9
69 changed files with 4384 additions and 1421 deletions

View File

@ -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"}

41
third_party/rust/crc32fast/Cargo.toml vendored Normal file
View File

@ -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 <srijs@airpost.net>", "Alex Crichton <alex@alexcrichton.com>"]
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 = []

View File

@ -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.

21
third_party/rust/crc32fast/LICENSE-MIT vendored Normal file
View File

@ -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.

81
third_party/rust/crc32fast/README.md vendored Normal file
View File

@ -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.

View File

@ -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);

35
third_party/rust/crc32fast/build.rs vendored Normal file
View File

@ -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<u32> {
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()
}

View File

@ -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<u8>) -> bool {
super::update_fast_16(crc, &bytes) == super::update_slow(crc, &bytes)
}
}
}

View File

@ -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;
}

178
third_party/rust/crc32fast/src/lib.rs vendored Normal file
View File

@ -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<Self> {
{
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<u8>, bytes_2: Vec<u8>) -> 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()
}
}
}

View File

@ -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<Self> {
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::<u64>();
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<u8>, 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()
}
}
}

View File

@ -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<Self> {
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 {}
}
}
}
}

View File

@ -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<Self> {
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<Self> {
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<u8>, 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()
}
}
}

626
third_party/rust/crc32fast/src/table.rs vendored Normal file
View File

@ -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,
],
];

View File

@ -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"}
{"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"}

View File

@ -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

View File

@ -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 <bvssvni@gmail.com>", "nwin", "TyOverby <ty@pre-alpha.com>", "HeroicKatora", "Calum", "CensoredUsername <cens.username@gmail.com>", "fintelia <fintelia@gmail.com>"]
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"

View File

@ -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<u8>).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()

View File

@ -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

View File

@ -7,12 +7,12 @@ use image::ImageResult;
/// An implementation dependent iterator, reading the frames as requested
pub struct Frames<'a> {
iterator: Box<Iterator<Item = ImageResult<Frame>> + 'a>
iterator: Box<dyn Iterator<Item = ImageResult<Frame>> + 'a>
}
impl<'a> Frames<'a> {
/// Creates a new `Frames` from an implementation specific iterator.
pub fn new(iterator: Box<Iterator<Item = ImageResult<Frame>> + 'a>) -> Self {
pub fn new(iterator: Box<dyn Iterator<Item = ImageResult<Frame>> + 'a>) -> Self {
Frames { iterator }
}

View File

@ -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<Item = &'a u8>>(
true
}
fn set_2bit_pixel_run<'a, T: Iterator<Item = &'a u8>>(
pixel_iter: &mut ChunksMut<u8>,
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<Item = &'a u8>>(
pixel_iter: &mut ChunksMut<u8>,
palette: &[(u8, u8, u8)],
@ -379,10 +410,10 @@ impl Bitfields {
max_len: u32,
) -> ImageResult<Bitfields> {
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<R: Read + Seek> BMPDecoder<R> {
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<R: Read + Seek> BMPDecoder<R> {
// The next 8 bytes represent file size, followed the 4 reserved bytes
// We're not interesting these values
try!(self.r.read_u32::<LittleEndian>());
try!(self.r.read_u32::<LittleEndian>());
self.r.read_u32::<LittleEndian>()?;
self.r.read_u32::<LittleEndian>()?;
self.data_offset = u64::from(self.r.read_u32::<LittleEndian>()?);
@ -576,11 +607,11 @@ impl<R: Read + Seek> BMPDecoder<R> {
// Number of planes (format specifies that this should be 1).
if try!(self.r.read_u16::<LittleEndian>()) != 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::<LittleEndian>());
self.bit_count = self.r.read_u16::<LittleEndian>()?;
self.image_type = match self.bit_count {
1 | 4 | 8 => ImageType::Palette,
24 => ImageType::RGB24,
@ -595,8 +626,8 @@ impl<R: Read + Seek> BMPDecoder<R> {
///
/// returns Err if any of the values are invalid.
fn read_bitmap_info_header(&mut self) -> ImageResult<()> {
self.width = try!(self.r.read_i32::<LittleEndian>());
self.height = try!(self.r.read_i32::<LittleEndian>());
self.width = self.r.read_i32::<LittleEndian>()?;
self.height = self.r.read_i32::<LittleEndian>()?;
// Width can not be negative
if self.width < 0 {
@ -626,12 +657,12 @@ impl<R: Read + Seek> BMPDecoder<R> {
// Number of planes (format specifies that this should be 1).
if try!(self.r.read_u16::<LittleEndian>()) != 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::<LittleEndian>());
let image_type_u32 = try!(self.r.read_u32::<LittleEndian>());
self.bit_count = self.r.read_u16::<LittleEndian>()?;
let image_type_u32 = self.r.read_u32::<LittleEndian>()?;
// Top-down dibs can not be compressed.
if self.top_down && image_type_u32 != 0 && image_type_u32 != 3 {
@ -641,7 +672,7 @@ impl<R: Read + Seek> BMPDecoder<R> {
}
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<R: Read + Seek> BMPDecoder<R> {
} 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<R: Read + Seek> BMPDecoder<R> {
// 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::<LittleEndian>());
try!(self.r.read_u32::<LittleEndian>());
try!(self.r.read_u32::<LittleEndian>());
self.r.read_u32::<LittleEndian>()?;
self.r.read_u32::<LittleEndian>()?;
self.r.read_u32::<LittleEndian>()?;
self.colors_used = try!(self.r.read_u32::<LittleEndian>());
self.colors_used = self.r.read_u32::<LittleEndian>()?;
// 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::<LittleEndian>());
self.r.read_u32::<LittleEndian>()?;
Ok(())
}
fn read_bitmasks(&mut self) -> ImageResult<()> {
let r_mask = try!(self.r.read_u32::<LittleEndian>());
let g_mask = try!(self.r.read_u32::<LittleEndian>());
let b_mask = try!(self.r.read_u32::<LittleEndian>());
let r_mask = self.r.read_u32::<LittleEndian>()?;
let g_mask = self.r.read_u32::<LittleEndian>()?;
let b_mask = self.r.read_u32::<LittleEndian>()?;
let a_mask = match self.bmp_header_type {
BMPHeaderType::V3 | BMPHeaderType::V4 | BMPHeaderType::V5 => {
@ -732,9 +763,9 @@ impl<R: Read + Seek> BMPDecoder<R> {
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::<LittleEndian>());
self.read_file_header()?;
let bmp_header_offset = self.r.seek(SeekFrom::Current(0))?;
let bmp_header_size = self.r.read_u32::<LittleEndian>()?;
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<R: Read + Seek> BMPDecoder<R> {
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<R: Read + Seek> BMPDecoder<R> {
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<R: Read + Seek> BMPDecoder<R> {
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<R: Read + Seek> BMPDecoder<R> {
// 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<R: Read + Seek> BMPDecoder<R> {
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<R: Read + Seek> BMPDecoder<R> {
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<R: Read + Seek> BMPDecoder<R> {
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<R: Read + Seek> BMPDecoder<R> {
};
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<R: Read + Seek> BMPDecoder<R> {
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<R: Read + Seek> BMPDecoder<R> {
self.top_down,
|row| {
for pixel in row.chunks_mut(num_channels) {
let data = try!(reader.read_u32::<LittleEndian>());
let data = reader.read_u32::<LittleEndian>()?;
pixel[0] = bitfields.r.read(data);
pixel[1] = bitfields.g.read(data);
@ -1016,7 +1050,7 @@ impl<R: Read + Seek> BMPDecoder<R> {
};
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<R: Read + Seek> BMPDecoder<R> {
|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<R: Read + Seek> BMPDecoder<R> {
fn read_rle_data(&mut self, image_type: ImageType) -> ImageResult<Vec<u8>> {
// 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<R: Read + Seek> BMPDecoder<R> {
);
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<R: Read + Seek> BMPDecoder<R> {
// 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<R: Read + Seek> BMPDecoder<R> {
}
}
impl<R: Read + Seek> ImageDecoder for BMPDecoder<R> {
type Reader = Cursor<Vec<u8>>;
/// Wrapper struct around a `Cursor<Vec<u8>>`
pub struct BmpReader<R>(Cursor<Vec<u8>>, PhantomData<R>);
impl<R> Read for BmpReader<R> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.0.read(buf)
}
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
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<R> {
type Reader = BmpReader<R>;
fn dimensions(&self) -> (u64, u64) {
(self.width as u64, self.height as u64)
@ -1271,7 +1321,7 @@ impl<R: Read + Seek> ImageDecoder for BMPDecoder<R> {
}
fn into_reader(self) -> ImageResult<Self::Reader> {
Ok(Cursor::new(self.read_image()?))
Ok(BmpReader(Cursor::new(self.read_image()?), PhantomData))
}
fn read_image(mut self) -> ImageResult<Vec<u8>> {
@ -1279,7 +1329,7 @@ impl<R: Read + Seek> ImageDecoder for BMPDecoder<R> {
}
}
impl<R: Read + Seek> ImageDecoderExt for BMPDecoder<R> {
impl<'a, R: 'a + Read + Seek> ImageDecoderExt<'a> for BMPDecoder<R> {
fn read_rect_with_progress<F: Fn(Progress)>(
&mut self,
x: u64,

View File

@ -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::<LittleEndian>(file_size)); // file size
try!(self.writer.write_u16::<LittleEndian>(0)); // reserved 1
try!(self.writer.write_u16::<LittleEndian>(0)); // reserved 2
self.writer.write_u8(b'B')?;
self.writer.write_u8(b'M')?;
self.writer.write_u32::<LittleEndian>(file_size)?; // file size
self.writer.write_u16::<LittleEndian>(0)?; // reserved 1
self.writer.write_u16::<LittleEndian>(0)?; // reserved 2
try!(
self.writer
.write_u32::<LittleEndian>(bmp_header_size + dib_header_size + palette_size)
); // image data offset
// write DIB header
try!(self.writer.write_u32::<LittleEndian>(dib_header_size));
try!(self.writer.write_i32::<LittleEndian>(width as i32));
try!(self.writer.write_i32::<LittleEndian>(height as i32));
try!(self.writer.write_u16::<LittleEndian>(1)); // color planes
self.writer.write_u32::<LittleEndian>(dib_header_size)?;
self.writer.write_i32::<LittleEndian>(width as i32)?;
self.writer.write_i32::<LittleEndian>(height as i32)?;
self.writer.write_u16::<LittleEndian>(1)?; // color planes
try!(
self.writer
.write_u16::<LittleEndian>((written_pixel_size * 8) as u16)
); // bits per pixel
try!(self.writer.write_u32::<LittleEndian>(0)); // compression method - no compression
try!(self.writer.write_u32::<LittleEndian>(image_size));
try!(self.writer.write_i32::<LittleEndian>(0)); // horizontal ppm
try!(self.writer.write_i32::<LittleEndian>(0)); // vertical ppm
try!(self.writer.write_u32::<LittleEndian>(palette_color_count));
try!(self.writer.write_u32::<LittleEndian>(0)); // all colors are important
if dib_header_size >= BITMAPV4HEADER_SIZE {
// Assume BGRA32
self.writer.write_u32::<LittleEndian>(3)?; // compression method - bitfields
} else {
self.writer.write_u32::<LittleEndian>(0)?; // compression method - no compression
}
self.writer.write_u32::<LittleEndian>(image_size)?;
self.writer.write_i32::<LittleEndian>(0)?; // horizontal ppm
self.writer.write_i32::<LittleEndian>(0)?; // vertical ppm
self.writer.write_u32::<LittleEndian>(palette_color_count)?;
self.writer.write_u32::<LittleEndian>(0)?; // all colors are important
if dib_header_size >= BITMAPV4HEADER_SIZE {
// Assume BGRA32
self.writer.write_u32::<LittleEndian>(0xff << 16)?; // red mask
self.writer.write_u32::<LittleEndian>(0xff << 8)?; // green mask
self.writer.write_u32::<LittleEndian>(0xff << 0)?; // blue mask
self.writer.write_u32::<LittleEndian>(0xff << 24)?; // alpha mask
self.writer.write_u32::<LittleEndian>(0x73524742)?; // colorspace - sRGB
// endpoints (3x3) and gamma (3)
for _ in 0..12 {
self.writer.write_u32::<LittleEndian>(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]

View File

@ -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<F>(&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<F>(&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
<P as Pixel>::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<Pixels<'a, P>> {
self.chunks.next().map(|row| Pixels {
chunks: row.chunks(<P as Pixel>::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<Pixels<'a, P>> {
self.chunks.next_back().map(|row| Pixels {
chunks: row.chunks(<P as Pixel>::CHANNEL_COUNT as usize),
})
}
}
/// Iterate over mutable rows of an image
pub struct RowsMut<'a, P: Pixel + 'a>
where
<P as Pixel>::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<PixelsMut<'a, P>> {
self.chunks.next().map(|row| PixelsMut {
chunks: row.chunks_mut(<P as Pixel>::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<PixelsMut<'a, P>> {
self.chunks.next_back().map(|row| PixelsMut {
chunks: row.chunks_mut(<P as Pixel>::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
<P as Pixel>::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
<P as Pixel>::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<P: Pixel, Container> {
@ -304,6 +505,9 @@ pub struct ImageBuffer<P: Pixel, Container> {
}
// 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<P, Container> ImageBuffer<P, Container>
where
P: Pixel + 'static,
@ -351,7 +555,16 @@ where
/// Returns an iterator over the pixels of this image.
pub fn pixels(&self) -> Pixels<P> {
Pixels {
chunks: self.data.chunks(<P as Pixel>::channel_count() as usize),
chunks: self.data.chunks(<P as Pixel>::CHANNEL_COUNT as usize),
}
}
/// Returns an iterator over the rows of this image.
pub fn rows(&self) -> Rows<P> {
Rows {
chunks: self
.data
.chunks(<P as Pixel>::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<P> {
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<usize> {
Some(<P as Pixel>::channel_count() as usize)
Some(<P as Pixel>::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<usize> {
let no_channels = <P as Pixel>::channel_count() as usize;
fn pixel_indices_unchecked(&self, x: u32, y: u32) -> Range<usize> {
let no_channels = <P as Pixel>::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(<P as Pixel>::channel_count(), self.width, self.height)
SampleLayout::row_major_packed(<P as Pixel>::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<P> {
PixelsMut {
chunks: self.data.chunks_mut(<P as Pixel>::channel_count() as usize),
chunks: self.data.chunks_mut(<P as Pixel>::CHANNEL_COUNT as usize),
}
}
/// Returns an iterator over the mutable rows of this image.
pub fn rows_mut(&mut self) -> RowsMut<P> {
RowsMut {
chunks: self
.data
.chunks_mut(<P as Pixel>::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<P> {
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(),
<P as Pixel>::color_type(),
<P as Pixel>::COLOR_TYPE,
)
}
}
impl<P, Container> ImageBuffer<P, Container>
where
P: Pixel<Subpixel = u8> + 'static,
Container: Deref<Target = [u8]>,
{
/// 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<Q>(&self, path: Q, format: ImageFormat) -> io::Result<()>
where
Q: AsRef<Path>,
{
// This is valid as the subpixel is u8.
save_buffer_with_format(
path,
self,
self.width(),
self.height(),
<P as Pixel>::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);
*<P as Pixel>::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 = <P as Pixel>::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];

View File

@ -68,40 +68,31 @@ $( // START Structure definitions
#[derive(PartialEq, Eq, Clone, Debug, Copy, Hash)]
#[repr(C)]
#[allow(missing_docs)]
pub struct $ident<T: Primitive> { pub data: [T; $channels] }
#[allow(non_snake_case, missing_docs)]
pub fn $ident<T: Primitive>(data: [T; $channels]) -> $ident<T> {
$ident {
data: data
}
}
pub struct $ident<T: Primitive> (pub [T; $channels]);
impl<T: Primitive + 'static> Pixel for $ident<T> {
type Subpixel = T;
fn channel_count() -> u8 {
$channels
}
fn color_model() -> &'static str {
$interpretation
}
fn color_type() -> ColorType {
ColorType::$color_type(mem::size_of::<T>() as u8 * 8)
}
const CHANNEL_COUNT: u8 = $channels;
const COLOR_MODEL: &'static str = $interpretation;
const COLOR_TYPE: ColorType = ColorType::$color_type(mem::size_of::<T>() 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<T: Primitive + 'static> Pixel for $ident<T> {
}
fn to_rgb(&self) -> Rgb<T> {
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<T> {
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<T> {
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<T> {
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<T> {
let mut pix = Luma {data: [Zero::zero()]};
let mut pix = Luma([Zero::zero()]);
pix.from_color(self);
pix
}
fn to_luma_alpha(&self) -> LumaA<T> {
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<T: Primitive + 'static> Pixel for $ident<T> {
}
fn apply<F>(&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<T: Primitive + 'static> Pixel for $ident<T> {
#[allow(trivial_casts)]
fn apply_with_alpha<F, G>(&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<T: Primitive + 'static> Pixel for $ident<T> {
}
fn apply2<F>(&mut self, other: &$ident<T>, 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<T: Primitive> Index<usize> for $ident<T> {
type Output = T;
#[inline(always)]
fn index(&self, _index: usize) -> &T {
&self.data[_index]
&self.0[_index]
}
}
impl<T: Primitive> IndexMut<usize> for $ident<T> {
#[inline(always)]
fn index_mut(&mut self, _index: usize) -> &mut T {
&mut self.data[_index]
&mut self.0[_index]
}
}
@ -589,8 +580,8 @@ impl<T: Primitive> Blend for LumaA<T> {
fn blend(&mut self, other: &LumaA<T>) {
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<T: Primitive> Blend for Rgba<T> {
// 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<T: Primitive> Blend for Bgra<T> {
// 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<T: Primitive> Invert for LumaA<T> {
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<T: Primitive> Invert for LumaA<T> {
impl<T: Primitive> Invert for Luma<T> {
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<T: Primitive> Invert for Rgba<T> {
fn invert(&mut self) {
let rgba = self.data;
let rgba = self.0;
let max = T::max_value();
@ -790,7 +781,7 @@ impl<T: Primitive> Invert for Rgba<T> {
impl<T: Primitive> Invert for Bgra<T> {
fn invert(&mut self) {
let bgra = self.data;
let bgra = self.0;
let max = T::max_value();
@ -801,7 +792,7 @@ impl<T: Primitive> Invert for Bgra<T> {
impl<T: Primitive> Invert for Rgb<T> {
fn invert(&mut self) {
let rgb = self.data;
let rgb = self.0;
let max = T::max_value();
@ -815,7 +806,7 @@ impl<T: Primitive> Invert for Rgb<T> {
impl<T: Primitive> Invert for Bgr<T> {
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]));
}
}

View File

@ -83,9 +83,6 @@ impl<R: Read> DXTDecoder<R> {
}
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<R: Read> DXTDecoder<R> {
// Note that, due to the way that DXT compression works, a scanline is considered to consist out of
// 4 lines of pixels.
impl<R: Read> ImageDecoder for DXTDecoder<R> {
impl<'a, R: 'a + Read> ImageDecoder<'a> for DXTDecoder<R> {
type Reader = DXTReader<R>;
fn dimensions(&self) -> (u64, u64) {
@ -152,7 +149,7 @@ impl<R: Read> ImageDecoder for DXTDecoder<R> {
}
}
impl<R: Read + Seek> ImageDecoderExt for DXTDecoder<R> {
impl<'a, R: 'a + Read + Seek> ImageDecoderExt<'a> for DXTDecoder<R> {
fn read_rect_with_progress<F: Fn(Progress)>(
&mut self,
x: u64,
@ -216,9 +213,6 @@ impl<W: Write> DXTEncoder<W> {
}
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);

View File

@ -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<Q>(&self, path: Q, format: ImageFormat) -> io::Result<()>
where
Q: AsRef<Path>,
{
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<I: ImageDecoder>(codec: I) -> ImageResult<DynamicImage> {
pub fn decoder_to_image<'a, I: ImageDecoder<'a>>(codec: I) -> ImageResult<DynamicImage> {
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<DynamicImage> {
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<P>(path: P) -> ImageResult<(u32, u32)>
where
P: AsRef<Path>
{
// 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<P>(
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<P>(
path: P,
buf: &[u8],
width: u32,
height: u32,
color: color::ColorType,
format: ImageFormat,
) -> io::Result<()>
where
P: AsRef<Path>,
{
// 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: BufRead + Seek>(r: R, format: ImageFormat) -> ImageResult<DynamicImage> {
#[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));
}
}

View File

@ -559,8 +559,8 @@ impl<Buffer> FlatSamples<Buffer> {
pub fn as_view<P>(&self) -> Result<View<&[P::Subpixel], P>, 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<Buffer> FlatSamples<Buffer> {
pub fn as_view_with_mut_samples<P>(&mut self) -> Result<View<&mut [P::Subpixel], P>, 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<Buffer> FlatSamples<Buffer> {
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<Buffer> FlatSamples<Buffer> {
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<Buffer, P: Pixel> GenericImageView for View<Buffer, P>
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<Buffer, P: Pixel> GenericImageView for ViewMut<Buffer, P>
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<Buffer, P: Pixel> GenericImage for ViewMut<Buffer, P>
}
let base_index = self.inner.in_bounds_index(0, x, y);
let channel_count = <P as Pixel>::channel_count() as usize;
let channel_count = <P as Pixel>::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::<LumaA<usize>>()
.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()

View File

@ -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<R: Read> Decoder<R> {
}
}
impl<R: Read> ImageDecoder for Decoder<R> {
type Reader = Cursor<Vec<u8>>;
/// Wrapper struct around a `Cursor<Vec<u8>>`
pub struct GifReader<R>(Cursor<Vec<u8>>, PhantomData<R>);
impl<R> Read for GifReader<R> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.0.read(buf)
}
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
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<R> {
type Reader = GifReader<R>;
fn dimensions(&self) -> (u64, u64) {
(self.reader.width() as u64, self.reader.height() as u64)
@ -71,7 +89,7 @@ impl<R: Read> ImageDecoder for Decoder<R> {
}
fn into_reader(self) -> ImageResult<Self::Reader> {
Ok(Cursor::new(self.read_image()?))
Ok(GifReader(Cursor::new(self.read_image()?), PhantomData))
}
fn read_image(mut self) -> ImageResult<Vec<u8>> {
@ -194,7 +212,7 @@ impl<R: Read> Iterator for GifFrameIterator<R> {
// 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<u8> = pixel;
let adjusted_pixel: &mut Rgba<u8> = pixel;
let previous_pixel: &Rgba<u8> = previous_img_buffer.get_pixel(x, y);
let pixel_alpha = adjusted_pixel.channels()[3];
@ -262,7 +280,7 @@ impl<W: Write> Encoder<W> {
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);
}

View File

@ -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<R: BufRead> {
impl<R: BufRead> HDRAdapter<R> {
/// Creates adapter
pub fn new(r: R) -> ImageResult<HDRAdapter<R>> {
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<R: BufRead> HDRAdapter<R> {
/// Allows reading old Radiance HDR images
pub fn new_nonstrict(r: R) -> ImageResult<HDRAdapter<R>> {
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<R: BufRead> HDRAdapter<R> {
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<R: BufRead> HDRAdapter<R> {
}
impl<R: BufRead> ImageDecoder for HDRAdapter<R> {
type Reader = Cursor<Vec<u8>>;
/// Wrapper struct around a `Cursor<Vec<u8>>`
pub struct HdrReader<R>(Cursor<Vec<u8>>, PhantomData<R>);
impl<R> Read for HdrReader<R> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.0.read(buf)
}
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
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<R> {
type Reader = HdrReader<R>;
fn dimensions(&self) -> (u64, u64) {
(self.meta.width as u64, self.meta.height as u64)
@ -78,7 +95,7 @@ impl<R: BufRead> ImageDecoder for HDRAdapter<R> {
}
fn into_reader(self) -> ImageResult<Self::Reader> {
Ok(Cursor::new(self.read_image()?))
Ok(HdrReader(Cursor::new(self.read_image()?), PhantomData))
}
fn read_image(mut self) -> ImageResult<Vec<u8>> {
@ -91,7 +108,7 @@ impl<R: BufRead> ImageDecoder for HDRAdapter<R> {
}
}
impl<R: BufRead + Seek> ImageDecoderExt for HDRAdapter<R> {
impl<'a, R: 'a + BufRead + Seek> ImageDecoderExt<'a> for HDRAdapter<R> {
fn read_rect_with_progress<F: Fn(Progress)>(
&mut self,
x: u64,
@ -128,7 +145,7 @@ pub struct HDRDecoder<R> {
/// 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<T: Primitive + Zero>(self, scale: f32, gamma: f32) -> Rgb<T> {
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<T: Primitive + Zero>(v: f32, scale: f32, gamma: f32) -> T {
@ -229,21 +246,21 @@ impl<R: BufRead> HDRDecoder<R> {
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<R: BufRead> HDRDecoder<R> {
} // 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<R: BufRead> HDRDecoder<R> {
}
// 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::<RGBE8Pixel>::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<R: BufRead> HDRDecoder<R> {
pub fn read_image_transform<T: Send, F: Send + Sync + Fn(RGBE8Pixel) -> T>(
mut self,
f: F,
) -> ImageResult<Vec<T>> {
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::<RGBE8Pixel>::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<u8> pixels.
/// scale = 1, gamma = 2.2
pub fn read_image_ldr(self) -> ImageResult<Vec<Rgb<u8>>> {
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<f32> pixels.
///
pub fn read_image_hdr(self) -> ImageResult<Vec<Rgb<f32>>> {
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<R: BufRead> IntoIterator for HDRDecoder<R> {
type IntoIter = HDRImageDecoderIterator<R>;
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: BufRead>(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: BufRead>(r: &mut R, buf: &mut [RGBE8Pixel]) -> ImageResult<(
#[inline(always)]
fn read_byte<R: BufRead>(r: &mut R) -> io::Result<u8> {
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<R: BufRead, S: FnMut(usize, u8)>(
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<R: BufRead, S: FnMut(usize, u8)>(
));
}
// 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<R: BufRead, S: FnMut(usize, u8)>(
));
}
// 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<R: BufRead>(
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<R: BufRead>(
fn read_rgbe<R: BufRead>(r: &mut R) -> io::Result<RGBE8Pixel> {
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::<u32>().into_image_error(err));
let width = try!(c2_str.parse::<u32>().into_image_error(err));
let height = c1_str.parse::<u32>().into_image_error(err)?;
let width = c2_str.parse::<u32>().into_image_error(err)?;
Ok((width, height))
}
_ => Err(ImageError::FormatError(format!(
@ -920,17 +917,17 @@ pub fn read_raw_file<P: AsRef<Path>>(path: P) -> ::std::io::Result<Vec<Rgb<f32>>
use std::fs::File;
use std::io::BufReader;
let mut r = BufReader::new(try!(File::open(path)));
let w = try!(r.read_u32::<LE>()) as usize;
let h = try!(r.read_u32::<LE>()) as usize;
let c = try!(r.read_u32::<LE>()) as usize;
let mut r = BufReader::new(File::open(path)?);
let w = r.read_u32::<LE>()? as usize;
let h = r.read_u32::<LE>()? as usize;
let c = r.read_u32::<LE>()? 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::<LE>());
let cg = try!(r.read_f32::<LE>());
let cb = try!(r.read_f32::<LE>());
let cr = r.read_f32::<LE>()?;
let cg = r.read_f32::<LE>()?;
let cb = r.read_f32::<LE>()?;
ret.push(Rgb([cr, cg, cb]));
}
Ok(ret)

View File

@ -18,15 +18,15 @@ impl<W: Write> HDREncoder<W> {
pub fn encode(mut self, data: &[Rgb<f32>], 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<W: Write> HDREncoder<W> {
*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: Write>(w: &mut W, v: RGBE8Pixel) -> Result<()> {
/// Converts ```Rgb<f32>``` into ```RGBE8Pixel```
pub fn to_rgbe8(pix: Rgb<f32>) -> 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<f32>, b: Rgb<f32>) -> 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

View File

@ -8,10 +8,8 @@
//! * <http://www.graphics.cornell.edu/~bjw/rgbe/rgbe.c>
//!
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::*;

View File

@ -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<R: Read + Seek> ICODecoder<R> {
/// Create a new decoder that decodes from the stream ```r```
pub fn new(mut r: R) -> ImageResult<ICODecoder<R>> {
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<R: Read + Seek> ICODecoder<R> {
}
fn read_entries<R: Read>(r: &mut R) -> ImageResult<Vec<DirEntry>> {
let _reserved = try!(r.read_u16::<LittleEndian>());
let _type = try!(r.read_u16::<LittleEndian>());
let count = try!(r.read_u16::<LittleEndian>());
let _reserved = r.read_u16::<LittleEndian>()?;
let _type = r.read_u16::<LittleEndian>()?;
let count = r.read_u16::<LittleEndian>()?;
(0..count).map(|_| read_entry(r)).collect()
}
fn read_entry<R: Read>(r: &mut R) -> ImageResult<DirEntry> {
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::<LittleEndian>());
entry.num_color_planes = r.read_u16::<LittleEndian>()?;
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: Read>(r: &mut R) -> ImageResult<DirEntry> {
// 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::<LittleEndian>());
entry.bits_per_pixel = r.read_u16::<LittleEndian>()?;
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::<LittleEndian>());
entry.image_offset = try!(r.read_u32::<LittleEndian>());
entry.image_length = r.read_u32::<LittleEndian>()?;
entry.image_offset = r.read_u32::<LittleEndian>()?;
Ok(entry)
}
/// Find the entry with the highest (color depth, size).
fn best_entry(mut entries: Vec<DirEntry>) -> ImageResult<DirEntry> {
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<R: Read + Seek>(&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<R: Read + Seek>(&self, r: &mut R) -> ImageResult<bool> {
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<R: Read + Seek>(&self, mut r: R) -> ImageResult<InnerDecoder<R>> {
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<R: Read + Seek> ImageDecoder for ICODecoder<R> {
type Reader = Cursor<Vec<u8>>;
/// Wrapper struct around a `Cursor<Vec<u8>>`
pub struct IcoReader<R>(Cursor<Vec<u8>>, PhantomData<R>);
impl<R> Read for IcoReader<R> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.0.read(buf)
}
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
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<R> {
type Reader = IcoReader<R>;
fn dimensions(&self) -> (u64, u64) {
match self.inner_decoder {
@ -176,7 +194,7 @@ impl<R: Read + Seek> ImageDecoder for ICODecoder<R> {
}
fn into_reader(self) -> ImageResult<Self::Reader> {
Ok(Cursor::new(self.read_image()?))
Ok(IcoReader(Cursor::new(self.read_image()?), PhantomData))
}
fn read_image(self) -> ImageResult<Vec<u8>> {
@ -227,7 +245,7 @@ impl<R: Read + Seek> ImageDecoder for ICODecoder<R> {
// 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<R: Read + Seek> ImageDecoder for ICODecoder<R> {
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;

View File

@ -34,9 +34,9 @@ impl<W: Write> ICOEncoder<W> {
color: ColorType,
) -> io::Result<()> {
let mut image_data: Vec<u8> = 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<W: Write> ICOEncoder<W> {
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: Write>(w: &mut W, num_images: u16) -> io::Result<()> {
// Reserved field (must be zero):
try!(w.write_u16::<LittleEndian>(0));
w.write_u16::<LittleEndian>(0)?;
// Image type (ICO or CUR):
try!(w.write_u16::<LittleEndian>(ICO_IMAGE_TYPE));
w.write_u16::<LittleEndian>(ICO_IMAGE_TYPE)?;
// Number of images in the file:
try!(w.write_u16::<LittleEndian>(num_images));
w.write_u16::<LittleEndian>(num_images)?;
Ok(())
}
@ -69,20 +69,20 @@ fn write_direntry<W: Write>(
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::<LittleEndian>(0));
w.write_u16::<LittleEndian>(0)?;
// Bits per pixel:
try!(w.write_u16::<LittleEndian>(bits_per_pixel(color) as u16));
w.write_u16::<LittleEndian>(bits_per_pixel(color) as u16)?;
// Image data size, in bytes:
try!(w.write_u32::<LittleEndian>(data_size));
w.write_u32::<LittleEndian>(data_size)?;
// Image data offset, in bytes:
try!(w.write_u32::<LittleEndian>(data_start));
w.write_u32::<LittleEndian>(data_start)?;
Ok(())
}

View File

@ -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<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,
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<usize>
@ -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,
<I::Pixel as Pixel>::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<Self> {
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<dyn io::Read>;
fn dimensions(&self) -> (u64, u64) {(5, 5)}
fn colortype(&self) -> ColorType { ColorType::Gray(8) }
fn into_reader(self) -> ImageResult<Self::Reader> {unimplemented!()}

View File

@ -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<I: GenericImageView + 'static>(
pub fn rotate90<I: GenericImageView>(
image: &I,
) -> ImageBuffer<I::Pixel, Vec<<I::Pixel as Pixel>::Subpixel>>
where
I::Pixel: 'static,
<I::Pixel as Pixel>::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<I: GenericImageView + 'static>(
pub fn rotate180<I: GenericImageView>(
image: &I,
) -> ImageBuffer<I::Pixel, Vec<<I::Pixel as Pixel>::Subpixel>>
where
I::Pixel: 'static,
<I::Pixel as Pixel>::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<I: GenericImageView + 'static>(
pub fn rotate270<I: GenericImageView>(
image: &I,
) -> ImageBuffer<I::Pixel, Vec<<I::Pixel as Pixel>::Subpixel>>
where
I::Pixel: 'static,
<I::Pixel as Pixel>::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<I: GenericImageView + 'static>(
pub fn flip_horizontal<I: GenericImageView>(
image: &I,
) -> ImageBuffer<I::Pixel, Vec<<I::Pixel as Pixel>::Subpixel>>
where
I::Pixel: 'static,
<I::Pixel as Pixel>::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<I: GenericImageView + 'static>(
pub fn flip_vertical<I: GenericImageView>(
image: &I,
) -> ImageBuffer<I::Pixel, Vec<<I::Pixel as Pixel>::Subpixel>>
where
I::Pixel: 'static,
<I::Pixel as Pixel>::Subpixel: 'static,
where I::Pixel: 'static,
{
let (width, height) = image.dimensions();
let mut out = ImageBuffer::new(width, height);

View File

@ -196,7 +196,7 @@ impl ColorMap for BiLevel {
#[inline(always)]
fn index_of(&self, color: &Luma<u8>) -> 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<u8>) {
let new_color = 0xFF * self.index_of(color) as u8;
let luma = &mut color.data;
let luma = &mut color.0;
luma[0] = new_color;
}
}

View File

@ -117,7 +117,11 @@ pub fn overlay_bounds(
}
/// Overlay an image at a given coordinate (x, y)
pub fn overlay<I: GenericImage>(bottom: &mut I, top: &I, x: u32, y: u32) {
pub fn overlay<I, J>(bottom: &mut I, top: &J, x: u32, y: u32)
where
I: GenericImage,
J: GenericImageView<Pixel = I::Pixel>,
{
let bottom_dims = bottom.dimensions();
let top_dims = top.dimensions();
@ -136,7 +140,11 @@ pub fn overlay<I: GenericImage>(bottom: &mut I, top: &I, x: u32, y: u32) {
}
/// Replace the contents of an image at a given coordinate (x, y)
pub fn replace<I: GenericImage>(bottom: &mut I, top: &I, x: u32, y: u32) {
pub fn replace<I, J>(bottom: &mut I, top: &J, x: u32, y: u32)
where
I: GenericImage,
J: GenericImageView<Pixel = I::Pixel>,
{
let bottom_dims = bottom.dimensions();
let top_dims = top.dimensions();

View File

@ -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<Fn(f32) -> f32 + 'a>,
pub kernel: Box<dyn Fn(f32) -> 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<I, P, S>(
image: &I,
new_width: u32,
filter: &mut Filter,
) -> ImageBuffer<P, Vec<S>>
where
I: GenericImageView<Pixel = P> + 'static,
I: GenericImageView<Pixel = P>,
P: Pixel<Subpixel = S> + '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<I, P, S>(
image: &I,
new_height: u32,
filter: &mut Filter,
) -> ImageBuffer<P, Vec<S>>
where
I: GenericImageView<Pixel = P> + 'static,
I: GenericImageView<Pixel = P>,
P: Pixel<Subpixel = S> + '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<I, P, S>(image: &I, kernel: &[f32]) -> ImageBuffer<P, Vec<S>>
where
I: GenericImageView<Pixel = P> + 'static,
I: GenericImageView<Pixel = P>,
P: Pixel<Subpixel = S> + '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<I: GenericImageView + 'static>(
pub fn resize<I: GenericImageView>(
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<I: GenericImageView + 'static>(
pub fn blur<I: GenericImageView>(
image: &I,
sigma: f32,
) -> ImageBuffer<I::Pixel, Vec<<I::Pixel as Pixel>::Subpixel>>
where
I::Pixel: 'static,
<I::Pixel as Pixel>::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 <https://en.wikipedia.org/wiki/Unsharp_masking#Digital_unsharp_masking>
// TODO: Do we really need the 'static bound on `I`? Can we avoid it?
pub fn unsharpen<I, P, S>(image: &I, sigma: f32, threshold: i32) -> ImageBuffer<P, Vec<S>>
where
I: GenericImageView<Pixel = P> + 'static,
I: GenericImageView<Pixel = P>,
P: Pixel<Subpixel = S> + 'static,
S: Primitive + 'static,
{

View File

@ -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<R: Read> JPEGDecoder<R> {
}
}
impl<R: Read> ImageDecoder for JPEGDecoder<R> {
type Reader = Cursor<Vec<u8>>;
/// Wrapper struct around a `Cursor<Vec<u8>>`
pub struct JpegReader<R>(Cursor<Vec<u8>>, PhantomData<R>);
impl<R> Read for JpegReader<R> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.0.read(buf)
}
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
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<R> {
type Reader = JpegReader<R>;
fn dimensions(&self) -> (u64, u64) {
(self.metadata.width as u64, self.metadata.height as u64)
@ -43,7 +61,7 @@ impl<R: Read> ImageDecoder for JPEGDecoder<R> {
}
fn into_reader(self) -> ImageResult<Self::Reader> {
Ok(Cursor::new(self.read_image()?))
Ok(JpegReader(Cursor::new(self.read_image()?), PhantomData))
}
fn read_image(mut self) -> ImageResult<Vec<u8>> {

View File

@ -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::<BigEndian>(b.len() as u16 + 2));
try!(self.w.write_all(b));
self.w.write_u16::<BigEndian>(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)?;
}
}

View File

@ -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
// <https://github.com/GuillaumeGomez/doc-comment>
//
// 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`.

View File

@ -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 <http://www.acm.org/~dekker/NEUQUANT.HTML>
//! See also <https://scientificgems.wordpress.com/stuff/neuquant-fast-high-quality-image-quantization/>
/* 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,

View File

@ -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<R: Read> {
reader: png::Reader<R>,
buffer: Vec<u8>,
index: usize,
}
impl<R: Read> PNGReader<R> {
fn new(mut reader: png::Reader<R>) -> ImageResult<PNGReader<R>> {
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<R: Read> Read for PNGReader<R> {
fn read(&mut self, mut buf: &mut [u8]) -> io::Result<usize> {
// 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<u8>) -> io::Result<usize> {
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<R: Read> {
colortype: ColorType,
@ -24,7 +97,10 @@ pub struct PNGDecoder<R: Read> {
impl<R: Read> PNGDecoder<R> {
/// Creates a new decoder that decodes from the stream ```r```
pub fn new(r: R) -> ImageResult<PNGDecoder<R>> {
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<R: Read> PNGDecoder<R> {
}
}
impl<R: Read> ImageDecoder for PNGDecoder<R> {
type Reader = Cursor<Vec<u8>>;
impl<'a, R: 'a + Read> ImageDecoder<'a> for PNGDecoder<R> {
type Reader = PNGReader<R>;
fn dimensions(&self) -> (u64, u64) {
let (w, h) = self.reader.info().size();
@ -45,14 +121,20 @@ impl<R: Read> ImageDecoder for PNGDecoder<R> {
}
fn into_reader(self) -> ImageResult<Self::Reader> {
Ok(Cursor::new(self.read_image()?))
PNGReader::new(self.reader)
}
fn read_image(mut self) -> ImageResult<Vec<u8>> {
// 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<W: Write> PNGEncoder<W> {
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<png::DecodingError> for ImageError {
CorruptFlateStream => {
ImageError::FormatError("compressed data stream corrupted".into())
}
LimitsExceeded => ImageError::InsufficientMemory,
}
}
}

View File

@ -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<Vec<u8>>;
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<Vec<u8>>;
}
@ -406,8 +408,24 @@ trait HeaderReader: BufRead {
impl<R: Read> HeaderReader for BufReader<R> {}
impl<R: Read> ImageDecoder for PNMDecoder<R> {
type Reader = Cursor<Vec<u8>>;
/// Wrapper struct around a `Cursor<Vec<u8>>`
pub struct PnmReader<R>(Cursor<Vec<u8>>, PhantomData<R>);
impl<R> Read for PnmReader<R> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.0.read(buf)
}
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
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<R> {
type Reader = PnmReader<R>;
fn dimensions(&self) -> (u64, u64) {
(self.header.width() as u64, self.header.height() as u64)
@ -418,7 +436,7 @@ impl<R: Read> ImageDecoder for PNMDecoder<R> {
}
fn into_reader(self) -> ImageResult<Self::Reader> {
Ok(Cursor::new(self.read_image()?))
Ok(PnmReader(Cursor::new(self.read_image()?), PhantomData))
}
fn read_image(mut self) -> ImageResult<Vec<u8>> {
@ -482,7 +500,7 @@ impl TupleType {
}
}
fn read_separated_ascii<T: FromStr>(reader: &mut Read) -> ImageResult<T>
fn read_separated_ascii<T: FromStr>(reader: &mut dyn Read) -> ImageResult<T>
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,

View File

@ -170,10 +170,10 @@ impl<W: Write> PNMEncoder<W> {
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<W: Write> PNMEncoder<W> {
///
/// 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<TupleEncoding<'a>> {
fn write_header(self, writer: &mut dyn Write) -> io::Result<TupleEncoding<'a>> {
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<V>(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),

View File

@ -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 {

View File

@ -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();

View File

@ -101,20 +101,20 @@ impl Header {
}
/// Load the header with values from the reader
fn from_reader(r: &mut Read) -> ImageResult<Header> {
fn from_reader(r: &mut dyn Read) -> ImageResult<Header> {
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::<LittleEndian>()),
map_length: try!(r.read_u16::<LittleEndian>()),
map_entry_size: try!(r.read_u8()),
x_origin: try!(r.read_u16::<LittleEndian>()),
y_origin: try!(r.read_u16::<LittleEndian>()),
image_width: try!(r.read_u16::<LittleEndian>()),
image_height: try!(r.read_u16::<LittleEndian>()),
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::<LittleEndian>()?,
map_length: r.read_u16::<LittleEndian>()?,
map_entry_size: r.read_u8()?,
x_origin: r.read_u16::<LittleEndian>()?,
y_origin: r.read_u16::<LittleEndian>()?,
image_width: r.read_u16::<LittleEndian>()?,
image_height: r.read_u16::<LittleEndian>()?,
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<R: Read + Seek> TGADecoder<R> {
}
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<R: Read + Seek> TGADecoder<R> {
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<R: Read + Seek> TGADecoder<R> {
} 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<R: Read + Seek> TGADecoder<R> {
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<R: Read + Seek> TGADecoder<R> {
}
}
impl<R: Read + Seek> ImageDecoder for TGADecoder<R> {
impl<'a, R: 'a + Read + Seek> ImageDecoder<'a> for TGADecoder<R> {
type Reader = TGAReader<R>;
fn dimensions(&self) -> (u64, u64) {

View File

@ -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<tiff::TiffError> 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<tiff::ColorType> for ColorType {
}
}
impl<R: Read + Seek> ImageDecoder for TIFFDecoder<R> {
type Reader = Cursor<Vec<u8>>;
/// Wrapper struct around a `Cursor<Vec<u8>>`
pub struct TiffReader<R>(Cursor<Vec<u8>>, PhantomData<R>);
impl<R> Read for TiffReader<R> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.0.read(buf)
}
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
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<R> {
type Reader = TiffReader<R>;
fn dimensions(&self) -> (u64, u64) {
(self.dimensions.0 as u64, self.dimensions.1 as u64)
@ -75,7 +94,7 @@ impl<R: Read + Seek> ImageDecoder for TIFFDecoder<R> {
}
fn into_reader(self) -> ImageResult<Self::Reader> {
Ok(Cursor::new(self.read_image()?))
Ok(TiffReader(Cursor::new(self.read_image()?), PhantomData))
}
fn read_image(mut self) -> ImageResult<Vec<u8>> {
@ -85,3 +104,33 @@ impl<R: Read + Seek> ImageDecoder for TIFFDecoder<R> {
}
}
}
/// Encoder for tiff images
pub struct TiffEncoder<W> {
w: W,
}
impl<W: Write + Seek> TiffEncoder<W> {
/// Create a new encoder that writes its output to `w`
pub fn new(w: W) -> TiffEncoder<W> {
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::<tiff::encoder::colortype::Gray8>(width, height, data)?,
ColorType::RGB(8) => encoder.write_image::<tiff::encoder::colortype::RGB8>(width, height, data)?,
ColorType::RGBA(8) => encoder.write_image::<tiff::encoder::colortype::RGBA8>(width, height, data)?,
_ => return Err(ImageError::UnsupportedColor(color))
}
Ok(())
}
}

View File

@ -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<u16>) -> Vec<u8> {
}
pub fn vec_u16_copy_u8(vec: &Vec<u16>) -> Vec<u8> {
let original_slice = vec.as_slice();
let ptr = original_slice.as_ptr() as *const u8;
let len = original_slice.len() * mem::size_of::<u16>();
// 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::<u8>() <= mem::align_of::<u16>());
let byte_slice = unsafe { slice::from_raw_parts(ptr, len) };
byte_slice.to_owned()
let mut new = vec![0; vec.len() * mem::size_of::<u16>()];
NativeEndian::write_u16_into(&vec[..], &mut new[..]);
new
}

View File

@ -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: R,
frame: Frame,
@ -36,10 +38,10 @@ impl<R: Read> WebpDecoder<R> {
fn read_riff_header(&mut self) -> ImageResult<u32> {
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::<LittleEndian>());
self.r.by_ref().take(4).read_to_end(&mut riff)?;
let size = self.r.read_u32::<LittleEndian>()?;
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<R: Read> WebpDecoder<R> {
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<R: Read> WebpDecoder<R> {
));
}
let _len = try!(self.r.read_u32::<LittleEndian>());
let _len = self.r.read_u32::<LittleEndian>()?;
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<R: Read> WebpDecoder<R> {
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<R: Read> WebpDecoder<R> {
}
}
impl<R: Read> ImageDecoder for WebpDecoder<R> {
type Reader = Cursor<Vec<u8>>;
/// Wrapper struct around a `Cursor<Vec<u8>>`
pub struct WebpReader<R>(Cursor<Vec<u8>>, PhantomData<R>);
impl<R> Read for WebpReader<R> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.0.read(buf)
}
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
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<R> {
type Reader = WebpReader<R>;
fn dimensions(&self) -> (u64, u64) {
(self.frame.width as u64, self.frame.height as u64)
@ -109,7 +127,7 @@ impl<R: Read> ImageDecoder for WebpDecoder<R> {
}
fn into_reader(self) -> ImageResult<Self::Reader> {
Ok(Cursor::new(self.frame.ybuf))
Ok(WebpReader(Cursor::new(self.frame.ybuf), PhantomData))
}
fn read_image(self) -> ImageResult<Vec<u8>> {

View File

@ -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;
}
}

View File

@ -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<u8>) {
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<u8>) -> 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<R: Read> VP8Decoder<R> {
/// Create a new decoder.
/// The reader must present a raw vp8 bitstream to the decoder
pub fn new(r: R) -> VP8Decoder<R> {
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<R: Read> VP8Decoder<R> {
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<R: Read> VP8Decoder<R> {
}
}
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::<LittleEndian>()
.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<R: Read> VP8Decoder<R> {
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<R: Read> VP8Decoder<R> {
}
}
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::<LittleEndian>()?;
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::<LittleEndian>());
let h = try!(self.r.read_u16::<LittleEndian>());
if tag != [0x9d, 0x01, 0x2a] {
return Err(ImageError::FormatError(
format!("Invalid magic bytes {:?} for vp8", tag)))
}
let w = self.r.read_u16::<LittleEndian>()?;
let h = self.r.read_u16::<LittleEndian>()?;
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<R: Read> VP8Decoder<R> {
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<R: Read> VP8Decoder<R> {
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<R: Read> VP8Decoder<R> {
// 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<R: Read> VP8Decoder<R> {
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<R: Read> VP8Decoder<R> {
};
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<R: Read> VP8Decoder<R> {
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<R: Read> VP8Decoder<R> {
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<R: Read> VP8Decoder<R> {
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<R: Read> VP8Decoder<R> {
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<R: Read> VP8Decoder<R> {
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<R: Read> VP8Decoder<R> {
}
/// 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<R: Read> VP8Decoder<R> {
}
}
impl LumaMode {
fn from_i8(val: i8) -> Option<Self> {
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<IntraMode> {
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<Self> {
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<Self> {
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<MacroBlock> {
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);

View File

@ -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"}
{"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"}

View File

@ -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 <nwin@users.noreply.github.com>"]
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 = []

View File

@ -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

View File

@ -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

25
third_party/rust/png/benches/decoder.rs vendored Normal file
View File

@ -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
}

View File

@ -14,7 +14,7 @@ use std::env;
use getopts::{Matches, Options, ParsingStyle};
use term::{color, Attr};
fn parse_args() -> Option<Matches> {
fn parse_args() -> Matches {
let args: Vec<String> = env::args().collect();
let mut opts = Options::new();
opts.optflag("c", "", "colorize output (for ANSI terminals)")
@ -24,12 +24,12 @@ fn parse_args() -> Option<Matches> {
.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<P: AsRef<Path>>(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<P: AsRef<Path>>(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<P: AsRef<Path>>(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<P: AsRef<Path>>(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<P: AsRef<Path>>(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<P: AsRef<Path>>(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<P: AsRef<Path>>(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<P: AsRef<Path>>(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)
});
}
}

View File

@ -17,10 +17,10 @@ use glium::backend::glutin::Display;
/// Load the image using `png`
fn load_image(path: &path::PathBuf) -> io::Result<RawImage2d<'static, u8>> {
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<path::PathBuf>) -> 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(())
})()

View File

@ -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<DisposeOp> {
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<BlendOp> {
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<deflate::Compression> 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<Compression> 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<deflate::Compression> 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<Compression> 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(),
}
}
}
}

View File

@ -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
}
}

View File

@ -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<Reader> for InterlaceHandling {
fn set_param(self, this: &mut Reader) {
this.color_output = self
}
}*/
impl<R: Read> Parameter<Decoder<R>> for Transformations {
fn set_param(self, this: &mut Decoder<R>) {
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 = 2<sup>26</sup>)
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: Read> {
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<R: Read> Decoder<R> {
pub fn new_with_limits(r: R, l: Limits) -> Decoder<R> {
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<R: Read> Decoder<R> {
/// Reads all meta data until the first IDAT chunk
pub fn read_info(self) -> Result<(OutputInfo, Reader<R>), 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<R: Read> Decoder<R> {
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<R: Read> HasParameters for Decoder<R> {}
/// 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<R: Read> {
reader: BufReader<R>,
@ -149,13 +137,13 @@ impl<R: Read> ReadDecoder<R> {
fn decode_next(&mut self, image_data: &mut Vec<u8>) -> Result<Option<Decoded>, 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<R: Read> {
/// Output transformations
transform: Transformations,
/// Processed line
processed: Vec<u8>
processed: Vec<u8>,
limits: Limits,
}
macro_rules! get_info(
@ -198,7 +187,7 @@ macro_rules! get_info(
impl<R: Read> Reader<R> {
/// Creates a new PNG reader
fn new(r: R, d: StreamingDecoder, t: Transformations) -> Reader<R> {
fn new(r: R, d: StreamingDecoder, t: Transformations, limits: Limits) -> Reader<R> {
Reader {
decoder: ReadDecoder {
reader: BufReader::with_capacity(CHUNCK_BUFFER_SIZE, r),
@ -211,18 +200,19 @@ impl<R: Read> Reader<R> {
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<R: Read> Reader<R> {
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<R: Read> Reader<R> {
/// 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<R: Read> Reader<R> {
))
}
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<R: Read> Reader<R> {
/// Returns the next processed row of the image
pub fn next_interlaced_row(&mut self) -> Result<Option<(&[u8], Option<(u8, u32, u32)>)>, 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<R: Read> Reader<R> {
&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<R: Read> Reader<R> {
_ => ()
}
}
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<R: Read> Reader<R> {
/// 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<R: Read> Reader<R> {
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<R: Read> Reader<R> {
/// 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<R: Read> Reader<R> {
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<R: Read> Reader<R> {
))
}
} 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
}
}
*/

View File

@ -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<Decoded, DecodingError> {
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<Decoded, DecodingError> {
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<Decoded, DecodingError> {
// 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

View File

@ -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<T> = result::Result<T, EncodingError>;
@ -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<io::Error> for EncodingError {
}
impl From<EncodingError> 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<W: Write> Encoder<W> {
pub fn write_header(self) -> Result<Writer<W>> {
Writer::new(self.w, self.info).init()
}
}
impl<W: Write> HasParameters for Encoder<W> {}
impl<W: Write> Parameter<Encoder<W>> for ColorType {
fn set_param(self, this: &mut Encoder<W>) {
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<W: Write> Parameter<Encoder<W>> for BitDepth {
fn set_param(self, this: &mut Encoder<W>) {
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<W: Write, C: Into<Compression>> Parameter<Encoder<W>> for C {
fn set_param(self, this: &mut Encoder<W>) {
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<C: Into<Compression>>(&mut self, compression: C) {
self.info.compression = compression.into();
}
}
impl <W: Write> Parameter<Encoder<W>> for FilterType {
fn set_param(self, this: &mut Encoder<W>) {
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<W: Write> Writer<W> {
}
fn init(mut self) -> Result<Self> {
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<W: Write> Writer<W> {
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(&current));
zlib.write_all(&current)?;
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<W> {
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<W> {
StreamWriter::new(self, size)
}
}
@ -161,6 +185,125 @@ impl<W: Write> Drop for Writer<W> {
}
}
struct ChunkWriter<'a, W: Write> {
writer: &'a mut Writer<W>,
buffer: Vec<u8>,
index: usize,
}
impl<'a, W: Write> ChunkWriter<'a, W> {
fn new(writer: &'a mut Writer<W>, 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<usize> {
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<ChunkWriter<'a, W>>,
prev_buf: Vec<u8>,
curr_buf: Vec<u8>,
index: usize,
bpp: usize,
filter: FilterType,
}
impl<'a, W: Write> StreamWriter<'a, W> {
fn new(writer: &'a mut Writer<W>, 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<usize> {
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 {
}
}
}
}

View File

@ -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 {

View File

@ -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;

View File

@ -1,19 +1,5 @@
use std::io;
/// Configuration parameter trait
pub trait Parameter<Object> {
fn set_param(self, &mut Object);
}
/// Object has parameters
pub trait HasParameters: Sized {
fn set<T: Parameter<Self>>(&mut self, value: T) -> &mut Self {
value.set_param(self);
self
}
}
// Will be replaced by stdlib solution
fn read_all<R: io::Read + ?Sized>(this: &mut R, buf: &mut [u8]) -> io::Result<()> {
let mut total = 0;
@ -39,7 +25,7 @@ pub trait ReadBytesExt<T>: io::Read {
/// Write extension to write big endian data
pub trait WriteBytesExt<T>: 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<W: io::Read + ?Sized> ReadBytesExt<u8> for W {
#[inline]
fn read_be(&mut self) -> io::Result<u8> {
let mut byte = [0];
try!(read_all(self, &mut byte));
read_all(self, &mut byte)?;
Ok(byte[0])
}
}
@ -55,7 +41,7 @@ impl<W: io::Read + ?Sized> ReadBytesExt<u16> for W {
#[inline]
fn read_be(&mut self) -> io::Result<u16> {
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<W: io::Read + ?Sized> ReadBytesExt<u32> for W {
#[inline]
fn read_be(&mut self) -> io::Result<u32> {
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

View File

@ -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<F>(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<Item=u8> + '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<Range<usize>> {
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::<Vec<_>>();
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::<Vec<_>>();
for line_no in 0..8 {
let start = 8 * line_no * width;
assert_eq!(
expand_adam7_bits(1, width, line_no, bits_pp).collect::<Vec<_>>(),
expected(start, 8, 4)
);
let start = start + 4;
assert_eq!(
expand_adam7_bits(2, width, line_no, bits_pp).collect::<Vec<_>>(),
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::<Vec<_>>(),
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::<Vec<_>>(),
expected(start, 4, 8)
);
let start = (4 * line_no + 2) * width;
assert_eq!(
expand_adam7_bits(5, width, line_no, bits_pp).collect::<Vec<_>>(),
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::<Vec<_>>(),
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::<Vec<_>>(),
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);
}