├── .gitattributes ├── rustfmt.toml ├── .gitignore ├── spng ├── tests │ ├── test-001.png │ ├── test-002.png │ └── tests.rs ├── Cargo.toml └── src │ ├── error.rs │ ├── lib.rs │ └── raw.rs ├── Cargo.toml ├── .gitmodules ├── bindgen.sh ├── spng-benchmarks ├── src │ └── lib.rs ├── Cargo.toml └── benches │ ├── png.rs │ └── spng.rs ├── spng-sys ├── build.rs ├── Cargo.toml └── src │ ├── lib.rs │ └── ffi.rs ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md ├── CHANGELOG.md └── .github └── workflows └── tests.yml /.gitattributes: -------------------------------------------------------------------------------- 1 | *.rs text eol=lf 2 | -------------------------------------------------------------------------------- /rustfmt.toml: -------------------------------------------------------------------------------- 1 | newline_style="Unix" 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | **/target 2 | Cargo.lock 3 | -------------------------------------------------------------------------------- /spng/tests/test-001.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aloucks/spng-rs/HEAD/spng/tests/test-001.png -------------------------------------------------------------------------------- /spng/tests/test-002.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aloucks/spng-rs/HEAD/spng/tests/test-002.png -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "spng-benchmarks", 4 | "spng-sys", 5 | "spng", 6 | ] 7 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "libspng"] 2 | path = spng-sys/libspng 3 | url = https://github.com/randy408/libspng.git 4 | -------------------------------------------------------------------------------- /bindgen.sh: -------------------------------------------------------------------------------- 1 | VERSION=$(bindgen --version) 2 | bindgen -o spng-sys/src/ffi.rs \ 3 | --raw-line "/* ${VERSION} */" \ 4 | --allowlist-type "spng_.*" \ 5 | --allowlist-var "SPNG_.*" \ 6 | --allowlist-function "spng_.*" \ 7 | --ctypes-prefix libc \ 8 | --use-core \ 9 | --impl-debug \ 10 | --impl-partialeq \ 11 | --opaque-type FILE \ 12 | spng-sys/libspng/spng/spng.h 13 | -------------------------------------------------------------------------------- /spng-benchmarks/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub static TEST_PNG_002: &[u8] = include_bytes!("../../spng/tests/test-002.png"); 2 | 3 | pub fn reserve(buf: &mut Vec, capacity: usize) { 4 | let cap = buf.capacity(); 5 | if cap < capacity { 6 | let additional = capacity - cap; 7 | buf.reserve(additional); 8 | buf.extend(std::iter::repeat(0).take(additional)); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /spng-sys/build.rs: -------------------------------------------------------------------------------- 1 | use std::env; 2 | 3 | fn main() { 4 | let mut build = cc::Build::new(); 5 | build.file("libspng/spng/spng.c"); 6 | if let Some(libz_include) = env::var_os("DEP_Z_INCLUDE") { 7 | build.include(libz_include); 8 | } 9 | if cfg!(target_feature = "sse4.1") { 10 | build.define("SPNG_SSE", Some("4")); 11 | } else if cfg!(target_feature = "ssse3") { 12 | build.define("SPNG_SSE", Some("3")); 13 | } 14 | build.compile("spng"); 15 | 16 | // DEP_SPNG_INCLUDE for other crates 17 | println!("cargo:include=libspng/spng"); 18 | } 19 | -------------------------------------------------------------------------------- /LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Copyright 2020 spng-rs developers 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. -------------------------------------------------------------------------------- /spng/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "spng" 3 | version = "0.2.0-alpha.3" 4 | authors = ["Aaron Loucks "] 5 | edition = "2018" 6 | keywords = ["spng", "png", "image", "decoder"] 7 | repository = "https://github.com/aloucks/spng-rs" 8 | documentation = "https://docs.rs/spng" 9 | license = "MIT OR Apache-2.0" 10 | description = "Rust bindings to libspng" 11 | readme = "../README.md" 12 | 13 | [dependencies] 14 | spng-sys = { version = "0.2.0-alpha.3", path = "../spng-sys" } 15 | bitflags = "2.4.1" 16 | libc = "0.2" 17 | 18 | [features] 19 | default = [] 20 | zlib-ng = ["spng-sys/zlib-ng"] 21 | -------------------------------------------------------------------------------- /spng-benchmarks/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "spng-benchmarks" 3 | version = "0.1.0" 4 | authors = ["Aaron Loucks "] 5 | edition = "2018" 6 | publish = false 7 | 8 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 9 | 10 | [features] 11 | zlib-ng = ["spng/zlib-ng"] 12 | 13 | [dev-dependencies] 14 | spng = { path = "../spng" } 15 | png = "0.17" 16 | criterion = { version = "0.3", features = ["html_reports"] } 17 | criterion-macro = "0.3" 18 | 19 | [[bench]] 20 | name = "spng" 21 | harness = false 22 | 23 | [[bench]] 24 | name = "png" 25 | harness = false -------------------------------------------------------------------------------- /spng-benchmarks/benches/png.rs: -------------------------------------------------------------------------------- 1 | use criterion::{black_box, criterion_group, criterion_main, Criterion}; 2 | 3 | fn png_decode(c: &mut Criterion) { 4 | c.bench_function("png_decode", |b| { 5 | let mut buf = Vec::new(); 6 | b.iter(|| { 7 | let d = png::Decoder::new(spng_benchmarks::TEST_PNG_002); 8 | let mut reader = d.read_info().unwrap(); 9 | spng_benchmarks::reserve(&mut buf, reader.output_buffer_size()); 10 | let _info = reader.next_frame(&mut buf).unwrap(); 11 | black_box(reader); 12 | }) 13 | }); 14 | } 15 | 16 | criterion_group!(benches, png_decode); 17 | criterion_main!(benches); 18 | -------------------------------------------------------------------------------- /spng-benchmarks/benches/spng.rs: -------------------------------------------------------------------------------- 1 | use criterion::{black_box, criterion_group, criterion_main, Criterion}; 2 | 3 | fn spng_decode(c: &mut Criterion) { 4 | c.bench_function("spng_decode", |b| { 5 | let mut buf = Vec::new(); 6 | b.iter(|| { 7 | let d = spng::Decoder::new(spng_benchmarks::TEST_PNG_002); 8 | let mut reader = d.read_info().unwrap(); 9 | spng_benchmarks::reserve(&mut buf, reader.output_buffer_size()); 10 | let _info = reader.next_frame(&mut buf).unwrap(); 11 | black_box(reader); 12 | }) 13 | }); 14 | } 15 | 16 | criterion_group!(benches, spng_decode); 17 | criterion_main!(benches); 18 | -------------------------------------------------------------------------------- /spng-sys/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "spng-sys" 3 | version = "0.2.0-alpha.3" 4 | authors = ["Aaron Loucks "] 5 | edition = "2018" 6 | keywords = ["spng", "png", "image", "decoder"] 7 | links = "spng" 8 | repository = "https://github.com/aloucks/spng-rs" 9 | documentation = "https://docs.rs/spng-sys" 10 | license = "MIT OR Apache-2.0" 11 | description = "Native bindings to libspng" 12 | readme = "../README.md" 13 | 14 | [dependencies] 15 | libz-sys = { version = "1.1.14", default-features = false, features = ["libc", "static"] } 16 | libc = "0.2" 17 | 18 | [build-dependencies] 19 | cc = "1.0" 20 | 21 | [features] 22 | default = ["libz-sys/static"] 23 | zlib-ng = ["libz-sys/zlib-ng"] 24 | -------------------------------------------------------------------------------- /spng-sys/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Native bindings to [libspng](https://libspng.org). 2 | 3 | #[allow(non_upper_case_globals)] 4 | #[allow(non_camel_case_types)] 5 | #[allow(non_snake_case)] 6 | #[allow(clippy::upper_case_acronyms)] 7 | mod ffi; 8 | 9 | pub use ffi::*; 10 | 11 | // Declaring this crate as extern is needed so that the Rust compiler thinks libz 12 | // is used, and thus passes the expected parameters to get libz linked in. See: 13 | // https://github.com/dtolnay/link-cplusplus/blob/75a186c35babbb7b39d0e5c544e1dfc9cc704800/README.md?plain=1#L54-L62 14 | extern crate libz_sys; 15 | 16 | #[test] 17 | fn create_context() { 18 | use std::ptr; 19 | unsafe { 20 | let ctx = spng_ctx_new(0); 21 | assert_ne!(ptr::null_mut(), ctx); 22 | spng_ctx_free(ctx); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 spng-rs developers 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # spng-rs 2 | 3 | [![crates.io](https://img.shields.io/crates/v/spng.svg)](https://crates.io/crates/spng) 4 | [![docs.rs](https://docs.rs/spng/badge.svg)](https://docs.rs/spng) 5 | [![tests](https://github.com/aloucks/spng-rs/actions/workflows/tests.yml/badge.svg)](https://github.com/aloucks/spng-rs/actions/workflows/tests.yml) 6 | 7 | Rust bindings to [libspng]. 8 | 9 | ## Version 10 | 11 | | spng-rs | libspng | 12 | |-----------------|---------------------------------------------------------------------------------------------| 13 | | `0.2.0-alpha.3` | [`0.7.4`](https://github.com/randy408/libspng/tree/v0.7.4) | 14 | | `0.2.0-alpha.2` | [`0.7.0-rc2`](https://github.com/randy408/libspng/tree/v0.7.0-rc2) | 15 | | `0.2.0-alpha.1` | [`0.7.0-rc2`](https://github.com/randy408/libspng/tree/v0.7.0-rc2) | 16 | | `0.1.0` | [`0.6.3`](https://github.com/randy408/libspng/tree/264476a1521bcb1d526c05ece0ed68b855fcfc4c) | 17 | 18 | ## Performance 19 | 20 | This [test image] is decoded ~ 3-5x faster than with the [png] crate. 21 | 22 | ``` 23 | png_decode time: [1.7354 ms 1.7372 ms 1.7392 ms] 24 | spng_decode time: [569.27 µs 570.86 µs 572.45 µs] 25 | spng_decode time: [311.84 µs 312.45 µs 313.13 µs] (--features=zlib-ng) 26 | ``` 27 | 28 | ## Examples 29 | 30 | A one-liner for simple use cases: 31 | 32 | ```rust 33 | let file = File::open("image.png")?; 34 | let (out_info, data) = spng::decode(file, spng::Format::Rgba8)?; 35 | 36 | assert_eq!(300, out_info.width); 37 | assert_eq!(300, out_info.height); 38 | assert_eq!(8, out_info.bit_depth); 39 | assert_eq!(4, out_info.color_type.samples()); 40 | assert_eq!(out_info.buffer_size, output_buffer_size); 41 | ``` 42 | 43 | The `Decoder` interface is modeled after the [png] crate: 44 | 45 | ```rust 46 | let file = File::open("image.png")?; 47 | let decoder = spng::Decoder::new(file) 48 | .with_output_format(spng::Format::Rgba8); 49 | let (out_info, mut reader) = decoder.read_info()?; 50 | let out_buffer_size = reader.output_buffer_size(); 51 | let mut data = vec![0; out_buffer_size]; 52 | reader.next_frame(&mut data)?; 53 | 54 | assert_eq!(300, out_info.width); 55 | assert_eq!(300, out_info.height); 56 | assert_eq!(8, out_info.bit_depth); 57 | assert_eq!(4, out_info.color_type.samples()); 58 | assert_eq!(out_info.buffer_size, out_buffer_size); 59 | ``` 60 | 61 | The `RawContext` interface is a safe and minimal wrapper over the full [libspng] `C` API. 62 | 63 | ```rust 64 | let file = File::open("image.png")?; 65 | let out_format = spng::Format::Rgba8; 66 | let mut ctx = spng::raw::RawContext::new()?; 67 | ctx.set_png_stream(file)?; 68 | let ihdr = ctx.get_ihdr()?; 69 | let out_buffer_size = ctx.decoded_image_size(out_format)?; 70 | let mut data = vec![0; out_buffer_size]; 71 | ctx.decode_image(&mut data, out_format, spng::DecodeFlags::empty())?; 72 | 73 | assert_eq!(300, ihdr.width); 74 | assert_eq!(300, ihdr.height); 75 | assert_eq!(8, ihdr.bit_depth); 76 | assert_eq!(4, spng::ColorType::try_from(ihdr.color_type)?.samples()); 77 | ``` 78 | 79 | [png]: https://crates.io/crates/png 80 | [libspng]: https://libspng.org 81 | [test image]: spng/tests/test-002.png 82 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | All notable changes to this project will be documented in this file. 3 | 4 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 5 | 6 | ## [Unreleased] 7 | 8 | ## [0.2.0-alpha.3] - 2024-08-21 9 | ### Added 10 | - Update to libspng `0.7.4` 11 | - `RawContext::get_gama_int` 12 | - `RawContext::decode_chunks` 13 | - `RawContext::set_option` 14 | - `RawContext::get_option` 15 | 16 | ### Changed 17 | - Updated the `Decoder` `read_info` and `next_frame` API to match recent changes in the PNG crate (`v0.17.0`). 18 | 19 | ## [0.2.0-alpha.2] - 2021-08-28 20 | ### Changed 21 | - `UnknownChunk::_type()` now returns a `Result` instead of `Option` to be consistent with similar methods 22 | ### Removed 23 | - Removed documentation safety notes that no longer apply due to lifetime constraints 24 | ### Fixed 25 | - The FFI error codes `SPNG_EWIDTH`, `SPNG_EHEIGHT`, and `SPNG_EUSER_WIDTH` are now converted correctly. 26 | 27 | ## [0.2.0-alpha.1] - 2021-06-23 28 | ### Added 29 | - Update to libspng `0.7.0-rc2` 30 | - `Limits`, `Info`, and `OutputInfo` now implment `Debug`, `Copy`, `Clone`, `PartialEq`, `Eq`, `Hash` 31 | - `RawContext::get_hist` 32 | - `RawContext::get_unknown_chunks` 33 | - The libspng `major`, `minor`, and `patch` version can be queried with `spng::version()` 34 | 35 | ## [0.1.0] - 2021-03-14 36 | ### Changed 37 | - Rename `Format::{GA8, GA16}` to `Format::{Ga8, Ga16}` to be consistent with other `Format` enum values 38 | - Rename `raw::IfPresent` to `raw::ChunkAvailable` 39 | - Create type aliases for non-wrapped chunks and move all to `raw::chunk` 40 | ### Added 41 | - Added `Reader::raw_context()` to enable access to `&RawContext`. 42 | 43 | ## [0.1.0-alpha.6] - 2021-03-14 44 | ### Changed 45 | - Update libspng to 264476a 46 | - Now zlib is linked to statically 47 | - Added `zlib-ng` crate feature to opt-in to `zlib-ng`, a fork of zlib with better performance 48 | 49 | ### Fixed 50 | - Now the `DEP_SPNG_INCLUDE` environment variable is correctly set to the include directory that contains libspng headers 51 | 52 | ## [0.1.0-alpha.5] - 2020-06-14 53 | ### Changed 54 | - Update libspng to 71a71a6 55 | ### Added 56 | - Grayscale output formats 57 | 58 | ## [0.1.0-alpha.4] - 2020-05-29 59 | ### Added 60 | - Expose the `RawContext` API 61 | - Add `spng::decode` for simple use cases 62 | ### Changed 63 | - Update libspng to f47ed26 64 | ### Added 65 | - Detect CPU target features and enable corresponding options in libspng 66 | 67 | ## [0.1.0-alpha.3] - 2020-03-13 68 | 69 | ## [0.1.0-alpha+2] - 2020-03-13 70 | ### Fixed 71 | - Buffered stream decoding now reads from the source buffer until the 72 | destination buffer is full. 73 | 74 | ## [0.1.0-alpha+1] - 2020-03-13 75 | ### Added 76 | - Initial rust wrapper with minimal API surface 77 | - Initial native bindings to [libspng] `master` ([2079ef6]) 78 | 79 | [Unreleased]: https://github.com/aloucks/spng-rs/compare/v0.2.0-alpha.2...HEAD 80 | [0.2.0-alpha.2]: https://github.com/aloucks/spng-rs/releases/tag/v0.2.0-alpha.2 81 | [0.2.0-alpha.1]: https://github.com/aloucks/spng-rs/releases/tag/v0.2.0-alpha.1 82 | [0.1.0]: https://github.com/aloucks/spng-rs/releases/tag/v0.1.0 83 | [0.1.0-alpha.6]: https://github.com/aloucks/spng-rs/releases/tag/v0.1.0-alpha.6 84 | [0.1.0-alpha.5]: https://github.com/aloucks/spng-rs/releases/tag/v0.1.0-alpha.5 85 | [0.1.0-alpha.4]: https://github.com/aloucks/spng-rs/releases/tag/v0.1.0-alpha.4 86 | [0.1.0-alpha.3]: https://github.com/aloucks/spng-rs/releases/tag/v0.1.0-alpha.3 87 | [0.1.0-alpha+2]: https://github.com/aloucks/spng-rs/releases/tag/v0.1.0-alpha+2 88 | [0.1.0-alpha+1]: https://github.com/aloucks/spng-rs/releases/tag/v0.1.0-alpha+1 89 | 90 | [libspng]: https://libspng.org 91 | [2079ef6]: https://github.com/randy408/libspng/tree/2079ef6f223feea2570b537c047c9140a5b72551 -------------------------------------------------------------------------------- /.github/workflows/tests.yml: -------------------------------------------------------------------------------- 1 | name: tests 2 | on: 3 | schedule: 4 | - cron: "0 0 * * 5" 5 | pull_request: 6 | push: 7 | branches: [master, workflows] 8 | paths-ignore: 9 | - CHANGELOG.md 10 | - README.md 11 | workflow_dispatch: 12 | 13 | jobs: 14 | clippy: 15 | name: Clippy 16 | runs-on: ubuntu-latest 17 | env: 18 | CARGO_TERM_COLOR: always 19 | steps: 20 | - uses: actions/checkout@v2 21 | with: 22 | submodules: true 23 | - uses: actions-rs/toolchain@v1 24 | id: rust 25 | with: 26 | toolchain: stable 27 | override: true 28 | profile: minimal 29 | components: clippy 30 | - name: Run clippy 31 | uses: actions-rs/cargo@v1 32 | with: 33 | command: clippy 34 | check: 35 | name: Check formatting 36 | runs-on: ubuntu-latest 37 | env: 38 | CARGO_TERM_COLOR: always 39 | steps: 40 | - uses: actions/checkout@v2 41 | - uses: actions-rs/toolchain@v1 42 | with: 43 | toolchain: stable 44 | override: true 45 | components: rustfmt 46 | profile: minimal 47 | - name: Check formatting 48 | uses: actions-rs/cargo@v1 49 | with: 50 | command: fmt 51 | args: --all -- --check 52 | test: 53 | name: Test 54 | strategy: 55 | matrix: 56 | os: [windows-latest, ubuntu-latest, macos-latest] 57 | toolchain: [stable, nightly] 58 | runs-on: ${{ matrix.os }} 59 | env: 60 | CARGO_TERM_COLOR: always 61 | RUST_BACKTRACE: 1 62 | CARGO_INCREMENTAL: 0 63 | steps: 64 | - uses: actions/checkout@v2 65 | with: 66 | submodules: true 67 | - uses: actions-rs/toolchain@v1 68 | with: 69 | toolchain: ${{ matrix.toolchain }} 70 | default: true 71 | override: true 72 | profile: minimal 73 | - name: Test 74 | uses: actions-rs/cargo@v1 75 | with: 76 | command: test 77 | args: --workspace --all-targets 78 | - name: Test (features="zlib-ng") 79 | uses: actions-rs/cargo@v1 80 | with: 81 | command: test 82 | args: --workspace --all-targets --features "zlib-ng" 83 | - name: Test (release) 84 | uses: actions-rs/cargo@v1 85 | with: 86 | command: test 87 | args: --workspace --all-targets --release 88 | - name: Test (release, features="zlib-ng") 89 | uses: actions-rs/cargo@v1 90 | with: 91 | command: test 92 | args: --workspace --all-targets --features "zlib-ng" --release 93 | 94 | test_arm: 95 | name: Test ARM 96 | strategy: 97 | matrix: 98 | os: [ubuntu-latest] 99 | toolchain: [stable] 100 | target: [aarch64-unknown-linux-gnu, armv7-unknown-linux-gnueabi] 101 | runs-on: ${{ matrix.os }} 102 | env: 103 | CARGO_TERM_COLOR: always 104 | RUST_BACKTRACE: 1 105 | CARGO_INCREMENTAL: 0 106 | steps: 107 | - uses: actions/checkout@v2 108 | with: 109 | submodules: true 110 | - uses: actions-rs/toolchain@v1 111 | with: 112 | toolchain: ${{ matrix.toolchain }} 113 | default: true 114 | override: true 115 | profile: minimal 116 | target: ${{ matrix.target }} 117 | - name: Test 118 | uses: actions-rs/cargo@v1 119 | with: 120 | command: test 121 | args: --workspace --all-targets 122 | - name: Test (features="zlib-ng") 123 | uses: actions-rs/cargo@v1 124 | with: 125 | command: test 126 | args: --workspace --all-targets --features "zlib-ng" 127 | - name: Test (release) 128 | uses: actions-rs/cargo@v1 129 | with: 130 | command: test 131 | args: --workspace --all-targets --release 132 | - name: Test (release, features="zlib-ng") 133 | uses: actions-rs/cargo@v1 134 | with: 135 | command: test 136 | args: --workspace --all-targets --features "zlib-ng" --release 137 | -------------------------------------------------------------------------------- /spng/tests/tests.rs: -------------------------------------------------------------------------------- 1 | use spng::{raw::ChunkAvail, BitDepth, ColorType, Decoder}; 2 | use std::io::{BufReader, Cursor, Read}; 3 | 4 | static TEST_PNG_001: &[u8] = include_bytes!("test-001.png"); 5 | static TEST_PNG_002: &[u8] = include_bytes!("test-002.png"); 6 | 7 | fn check_decoder( 8 | decoder: Decoder, 9 | width: u32, 10 | height: u32, 11 | bit_depth: BitDepth, 12 | color_type: ColorType, 13 | ) { 14 | let mut reader = decoder.read_info().expect("read_info failed"); 15 | let info = reader.info(); 16 | let output_buffer_size = reader.output_buffer_size(); 17 | assert_eq!(width, info.width); 18 | assert_eq!(height, info.height); 19 | assert_eq!(bit_depth, info.bit_depth); 20 | assert_eq!(color_type, info.color_type); 21 | let mut out = vec![0; output_buffer_size]; 22 | let out_info = reader.next_frame(&mut out).expect("next_frame failed"); 23 | assert_eq!(output_buffer_size, out_info.buffer_size()); 24 | assert_eq!(info.width, out_info.width); 25 | assert_eq!(info.height, out_info.height); 26 | assert_eq!(info.bit_depth, out_info.bit_depth); 27 | assert_eq!(info.color_type, out_info.color_type); 28 | } 29 | 30 | #[test] 31 | fn decode_001_cursor() { 32 | let cursor = Cursor::new(TEST_PNG_001); 33 | let decoder = Decoder::new(cursor); 34 | 35 | check_decoder(decoder, 300, 300, BitDepth::Eight, ColorType::RGBA); 36 | } 37 | 38 | #[test] 39 | fn decode_001_cursor_buffered() { 40 | let cursor = Cursor::new(TEST_PNG_001); 41 | let cursor_buffered = BufReader::new(cursor); 42 | let decoder = Decoder::new(cursor_buffered); 43 | 44 | check_decoder(decoder, 300, 300, BitDepth::Eight, ColorType::RGBA); 45 | } 46 | 47 | #[test] 48 | fn decode_001_slice() { 49 | let decoder = Decoder::new(TEST_PNG_001); 50 | 51 | check_decoder(decoder, 300, 300, BitDepth::Eight, ColorType::RGBA); 52 | } 53 | 54 | #[test] 55 | fn decode_002_cursor() { 56 | let cursor = Cursor::new(TEST_PNG_002); 57 | let decoder = Decoder::new(cursor); 58 | 59 | check_decoder(decoder, 380, 287, BitDepth::Eight, ColorType::RGBA); 60 | } 61 | 62 | #[test] 63 | fn decode_002_cursor_buffered() { 64 | let cursor = Cursor::new(TEST_PNG_002); 65 | let cursor_buffered = BufReader::new(cursor); 66 | let decoder = Decoder::new(cursor_buffered); 67 | 68 | check_decoder(decoder, 380, 287, BitDepth::Eight, ColorType::RGBA); 69 | } 70 | 71 | #[test] 72 | fn decode_002_slice() { 73 | let decoder = Decoder::new(TEST_PNG_002); 74 | 75 | check_decoder(decoder, 380, 287, BitDepth::Eight, ColorType::RGBA); 76 | } 77 | 78 | #[test] 79 | fn decode() -> Result<(), Box> { 80 | let (out_info, out) = spng::decode(TEST_PNG_001, spng::Format::Png)?; 81 | assert_eq!(300, out_info.width); 82 | assert_eq!(300, out_info.height); 83 | assert_eq!(8, out_info.bit_depth as u8); 84 | assert_eq!(4, out_info.color_type.samples()); 85 | assert_eq!(out_info.buffer_size, out.len()); 86 | Ok(()) 87 | } 88 | 89 | #[test] 90 | fn decode_001_raw_context() -> Result<(), Box> { 91 | use std::convert::TryFrom; 92 | let out_format = spng::Format::Rgba8; 93 | let mut ctx = spng::raw::RawContext::new()?; 94 | ctx.set_png_stream(TEST_PNG_001)?; 95 | let ihdr = ctx.get_ihdr()?; 96 | assert_eq!(300, ihdr.width); 97 | assert_eq!(300, ihdr.height); 98 | assert_eq!(8, ihdr.bit_depth); 99 | assert_eq!(4, spng::ColorType::try_from(ihdr.color_type)?.samples()); 100 | let buffer_size = ctx.decoded_image_size(out_format)?; 101 | let mut data = vec![0; buffer_size]; 102 | ctx.decode_image(&mut data, out_format, spng::DecodeFlags::empty())?; 103 | let text = ctx 104 | .get_text() 105 | .chunk_avail()? 106 | .expect("text chunk in test image"); 107 | let text_str = text[0].text()?; 108 | assert_eq!("Created with GIMP", text_str); 109 | Ok(()) 110 | } 111 | 112 | #[test] 113 | fn version() { 114 | println!("{:?}", spng::version()); 115 | } 116 | -------------------------------------------------------------------------------- /spng/src/error.rs: -------------------------------------------------------------------------------- 1 | use std::error::Error as StdError; 2 | use std::fmt; 3 | 4 | use spng_sys as sys; 5 | 6 | #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] 7 | #[repr(i32)] 8 | pub enum Error { 9 | IoError = sys::spng_errno_SPNG_IO_ERROR, 10 | IoEof = sys::spng_errno_SPNG_IO_EOF, 11 | // Ok = sys::spng_errno_SPNG_OK, 12 | Inval = sys::spng_errno_SPNG_EINVAL, 13 | Mem = sys::spng_errno_SPNG_EMEM, 14 | Overflow = sys::spng_errno_SPNG_EOVERFLOW, 15 | Signature = sys::spng_errno_SPNG_ESIGNATURE, 16 | Width = sys::spng_errno_SPNG_EWIDTH, 17 | Height = sys::spng_errno_SPNG_EHEIGHT, 18 | UserWidth = sys::spng_errno_SPNG_EUSER_WIDTH, 19 | UserHeight = sys::spng_errno_SPNG_EUSER_HEIGHT, 20 | BitDepth = sys::spng_errno_SPNG_EBIT_DEPTH, 21 | ColorType = sys::spng_errno_SPNG_ECOLOR_TYPE, 22 | CompressionMethod = sys::spng_errno_SPNG_ECOMPRESSION_METHOD, 23 | FilterMethod = sys::spng_errno_SPNG_EFILTER_METHOD, 24 | InterlaceMethod = sys::spng_errno_SPNG_EINTERLACE_METHOD, 25 | IhdrSize = sys::spng_errno_SPNG_EIHDR_SIZE, 26 | Noihdr = sys::spng_errno_SPNG_ENOIHDR, 27 | ChunkPos = sys::spng_errno_SPNG_ECHUNK_POS, 28 | ChunkSize = sys::spng_errno_SPNG_ECHUNK_SIZE, 29 | ChunkCrc = sys::spng_errno_SPNG_ECHUNK_CRC, 30 | ChunkType = sys::spng_errno_SPNG_ECHUNK_TYPE, 31 | ChunkUnknownCritical = sys::spng_errno_SPNG_ECHUNK_UNKNOWN_CRITICAL, 32 | DupPlte = sys::spng_errno_SPNG_EDUP_PLTE, 33 | DupChrm = sys::spng_errno_SPNG_EDUP_CHRM, 34 | DupGama = sys::spng_errno_SPNG_EDUP_GAMA, 35 | DupIccp = sys::spng_errno_SPNG_EDUP_ICCP, 36 | DupSbit = sys::spng_errno_SPNG_EDUP_SBIT, 37 | DupSrgb = sys::spng_errno_SPNG_EDUP_SRGB, 38 | DupBkgd = sys::spng_errno_SPNG_EDUP_BKGD, 39 | DupHist = sys::spng_errno_SPNG_EDUP_HIST, 40 | DupTrns = sys::spng_errno_SPNG_EDUP_TRNS, 41 | DupPhys = sys::spng_errno_SPNG_EDUP_PHYS, 42 | DupTime = sys::spng_errno_SPNG_EDUP_TIME, 43 | DupOffs = sys::spng_errno_SPNG_EDUP_OFFS, 44 | DupExif = sys::spng_errno_SPNG_EDUP_EXIF, 45 | Chrm = sys::spng_errno_SPNG_ECHRM, 46 | PlteIdx = sys::spng_errno_SPNG_EPLTE_IDX, 47 | TrnsColorType = sys::spng_errno_SPNG_ETRNS_COLOR_TYPE, 48 | TrnsNoPlte = sys::spng_errno_SPNG_ETRNS_NO_PLTE, 49 | Gama = sys::spng_errno_SPNG_EGAMA, 50 | IccpName = sys::spng_errno_SPNG_EICCP_NAME, 51 | IccpCompressionMethod = sys::spng_errno_SPNG_EICCP_COMPRESSION_METHOD, 52 | Sbit = sys::spng_errno_SPNG_ESBIT, 53 | Srgb = sys::spng_errno_SPNG_ESRGB, 54 | Text = sys::spng_errno_SPNG_ETEXT, 55 | TextKeyword = sys::spng_errno_SPNG_ETEXT_KEYWORD, 56 | Ztxt = sys::spng_errno_SPNG_EZTXT, 57 | ZtxtCompressionMethod = sys::spng_errno_SPNG_EZTXT_COMPRESSION_METHOD, 58 | Itxt = sys::spng_errno_SPNG_EITXT, 59 | ItxtCompressionFlag = sys::spng_errno_SPNG_EITXT_COMPRESSION_FLAG, 60 | ItxtCompressionMethod = sys::spng_errno_SPNG_EITXT_COMPRESSION_METHOD, 61 | ItxtLangTag = sys::spng_errno_SPNG_EITXT_LANG_TAG, 62 | ItxtTranslatedKey = sys::spng_errno_SPNG_EITXT_TRANSLATED_KEY, 63 | BkgdNoPlte = sys::spng_errno_SPNG_EBKGD_NO_PLTE, 64 | BkgdPlteIdx = sys::spng_errno_SPNG_EBKGD_PLTE_IDX, 65 | HistNoPlte = sys::spng_errno_SPNG_EHIST_NO_PLTE, 66 | Phys = sys::spng_errno_SPNG_EPHYS, 67 | SpltName = sys::spng_errno_SPNG_ESPLT_NAME, 68 | SpltDupName = sys::spng_errno_SPNG_ESPLT_DUP_NAME, 69 | SpltDepth = sys::spng_errno_SPNG_ESPLT_DEPTH, 70 | Time = sys::spng_errno_SPNG_ETIME, 71 | Offs = sys::spng_errno_SPNG_EOFFS, 72 | Exif = sys::spng_errno_SPNG_EEXIF, 73 | IdatTooShort = sys::spng_errno_SPNG_EIDAT_TOO_SHORT, 74 | IdatStream = sys::spng_errno_SPNG_EIDAT_STREAM, 75 | Zlib = sys::spng_errno_SPNG_EZLIB, 76 | Filter = sys::spng_errno_SPNG_EFILTER, 77 | Bufsiz = sys::spng_errno_SPNG_EBUFSIZ, 78 | Io = sys::spng_errno_SPNG_EIO, 79 | Eof = sys::spng_errno_SPNG_EOF, 80 | BufSet = sys::spng_errno_SPNG_EBUF_SET, 81 | Badstate = sys::spng_errno_SPNG_EBADSTATE, 82 | Fmt = sys::spng_errno_SPNG_EFMT, 83 | Flags = sys::spng_errno_SPNG_EFLAGS, 84 | Chunkavail = sys::spng_errno_SPNG_ECHUNKAVAIL, 85 | NcodeOnly = sys::spng_errno_SPNG_ENCODE_ONLY, 86 | Oi = sys::spng_errno_SPNG_EOI, 87 | Noplte = sys::spng_errno_SPNG_ENOPLTE, 88 | ChunkLimits = sys::spng_errno_SPNG_ECHUNK_LIMITS, 89 | ZlibInit = sys::spng_errno_SPNG_EZLIB_INIT, 90 | ChunkStdlen = sys::spng_errno_SPNG_ECHUNK_STDLEN, 91 | Internal = sys::spng_errno_SPNG_EINTERNAL, 92 | CtxType = sys::spng_errno_SPNG_ECTXTYPE, 93 | NoSrc = sys::spng_errno_SPNG_ENOSRC, 94 | NoDst = sys::spng_errno_SPNG_ENODST, 95 | OpState = sys::spng_errno_SPNG_EOPSTATE, 96 | NotFinal = sys::spng_errno_SPNG_ENOTFINAL, 97 | } 98 | 99 | pub fn check_err(e: i32) -> Result<(), Error> { 100 | use Error::*; 101 | match e { 102 | sys::spng_errno_SPNG_IO_ERROR => Err(IoError), 103 | sys::spng_errno_SPNG_IO_EOF => Err(IoEof), 104 | sys::spng_errno_SPNG_OK => Ok(()), 105 | sys::spng_errno_SPNG_EINVAL => Err(Inval), 106 | sys::spng_errno_SPNG_EMEM => Err(Mem), 107 | sys::spng_errno_SPNG_EOVERFLOW => Err(Overflow), 108 | sys::spng_errno_SPNG_ESIGNATURE => Err(Signature), 109 | sys::spng_errno_SPNG_EWIDTH => Err(Width), 110 | sys::spng_errno_SPNG_EHEIGHT => Err(Height), 111 | sys::spng_errno_SPNG_EUSER_WIDTH => Err(UserWidth), 112 | sys::spng_errno_SPNG_EUSER_HEIGHT => Err(UserHeight), 113 | sys::spng_errno_SPNG_EBIT_DEPTH => Err(BitDepth), 114 | sys::spng_errno_SPNG_ECOLOR_TYPE => Err(ColorType), 115 | sys::spng_errno_SPNG_ECOMPRESSION_METHOD => Err(CompressionMethod), 116 | sys::spng_errno_SPNG_EFILTER_METHOD => Err(FilterMethod), 117 | sys::spng_errno_SPNG_EINTERLACE_METHOD => Err(InterlaceMethod), 118 | sys::spng_errno_SPNG_EIHDR_SIZE => Err(IhdrSize), 119 | sys::spng_errno_SPNG_ENOIHDR => Err(Noihdr), 120 | sys::spng_errno_SPNG_ECHUNK_POS => Err(ChunkPos), 121 | sys::spng_errno_SPNG_ECHUNK_SIZE => Err(ChunkSize), 122 | sys::spng_errno_SPNG_ECHUNK_CRC => Err(ChunkCrc), 123 | sys::spng_errno_SPNG_ECHUNK_TYPE => Err(ChunkType), 124 | sys::spng_errno_SPNG_ECHUNK_UNKNOWN_CRITICAL => Err(ChunkUnknownCritical), 125 | sys::spng_errno_SPNG_EDUP_PLTE => Err(DupPlte), 126 | sys::spng_errno_SPNG_EDUP_CHRM => Err(DupChrm), 127 | sys::spng_errno_SPNG_EDUP_GAMA => Err(DupGama), 128 | sys::spng_errno_SPNG_EDUP_ICCP => Err(DupIccp), 129 | sys::spng_errno_SPNG_EDUP_SBIT => Err(DupSbit), 130 | sys::spng_errno_SPNG_EDUP_SRGB => Err(DupSrgb), 131 | sys::spng_errno_SPNG_EDUP_BKGD => Err(DupBkgd), 132 | sys::spng_errno_SPNG_EDUP_HIST => Err(DupHist), 133 | sys::spng_errno_SPNG_EDUP_TRNS => Err(DupTrns), 134 | sys::spng_errno_SPNG_EDUP_PHYS => Err(DupPhys), 135 | sys::spng_errno_SPNG_EDUP_TIME => Err(DupTime), 136 | sys::spng_errno_SPNG_EDUP_OFFS => Err(DupOffs), 137 | sys::spng_errno_SPNG_EDUP_EXIF => Err(DupExif), 138 | sys::spng_errno_SPNG_ECHRM => Err(Chrm), 139 | sys::spng_errno_SPNG_EPLTE_IDX => Err(PlteIdx), 140 | sys::spng_errno_SPNG_ETRNS_COLOR_TYPE => Err(TrnsColorType), 141 | sys::spng_errno_SPNG_ETRNS_NO_PLTE => Err(TrnsNoPlte), 142 | sys::spng_errno_SPNG_EGAMA => Err(Gama), 143 | sys::spng_errno_SPNG_EICCP_NAME => Err(IccpName), 144 | sys::spng_errno_SPNG_EICCP_COMPRESSION_METHOD => Err(IccpCompressionMethod), 145 | sys::spng_errno_SPNG_ESBIT => Err(Sbit), 146 | sys::spng_errno_SPNG_ESRGB => Err(Srgb), 147 | sys::spng_errno_SPNG_ETEXT => Err(Text), 148 | sys::spng_errno_SPNG_ETEXT_KEYWORD => Err(TextKeyword), 149 | sys::spng_errno_SPNG_EZTXT => Err(Ztxt), 150 | sys::spng_errno_SPNG_EZTXT_COMPRESSION_METHOD => Err(ZtxtCompressionMethod), 151 | sys::spng_errno_SPNG_EITXT => Err(Itxt), 152 | sys::spng_errno_SPNG_EITXT_COMPRESSION_FLAG => Err(ItxtCompressionFlag), 153 | sys::spng_errno_SPNG_EITXT_COMPRESSION_METHOD => Err(ItxtCompressionMethod), 154 | sys::spng_errno_SPNG_EITXT_LANG_TAG => Err(ItxtLangTag), 155 | sys::spng_errno_SPNG_EITXT_TRANSLATED_KEY => Err(ItxtTranslatedKey), 156 | sys::spng_errno_SPNG_EBKGD_NO_PLTE => Err(BkgdNoPlte), 157 | sys::spng_errno_SPNG_EBKGD_PLTE_IDX => Err(BkgdPlteIdx), 158 | sys::spng_errno_SPNG_EHIST_NO_PLTE => Err(HistNoPlte), 159 | sys::spng_errno_SPNG_EPHYS => Err(Phys), 160 | sys::spng_errno_SPNG_ESPLT_NAME => Err(SpltName), 161 | sys::spng_errno_SPNG_ESPLT_DUP_NAME => Err(SpltDupName), 162 | sys::spng_errno_SPNG_ESPLT_DEPTH => Err(SpltDepth), 163 | sys::spng_errno_SPNG_ETIME => Err(Time), 164 | sys::spng_errno_SPNG_EOFFS => Err(Offs), 165 | sys::spng_errno_SPNG_EEXIF => Err(Exif), 166 | sys::spng_errno_SPNG_EIDAT_TOO_SHORT => Err(IdatTooShort), 167 | sys::spng_errno_SPNG_EIDAT_STREAM => Err(IdatStream), 168 | sys::spng_errno_SPNG_EZLIB => Err(Zlib), 169 | sys::spng_errno_SPNG_EFILTER => Err(Filter), 170 | sys::spng_errno_SPNG_EBUFSIZ => Err(Bufsiz), 171 | sys::spng_errno_SPNG_EIO => Err(Io), 172 | sys::spng_errno_SPNG_EOF => Err(Eof), 173 | sys::spng_errno_SPNG_EBUF_SET => Err(BufSet), 174 | sys::spng_errno_SPNG_EBADSTATE => Err(Badstate), 175 | sys::spng_errno_SPNG_EFMT => Err(Fmt), 176 | sys::spng_errno_SPNG_EFLAGS => Err(Flags), 177 | sys::spng_errno_SPNG_ECHUNKAVAIL => Err(Chunkavail), 178 | sys::spng_errno_SPNG_ENCODE_ONLY => Err(NcodeOnly), 179 | sys::spng_errno_SPNG_EOI => Err(Oi), 180 | sys::spng_errno_SPNG_ENOPLTE => Err(Noplte), 181 | sys::spng_errno_SPNG_ECHUNK_LIMITS => Err(ChunkLimits), 182 | sys::spng_errno_SPNG_EZLIB_INIT => Err(ZlibInit), 183 | sys::spng_errno_SPNG_ECHUNK_STDLEN => Err(ChunkStdlen), 184 | sys::spng_errno_SPNG_EINTERNAL => Err(Internal), 185 | sys::spng_errno_SPNG_ECTXTYPE => Err(CtxType), 186 | sys::spng_errno_SPNG_ENOSRC => Err(NoSrc), 187 | sys::spng_errno_SPNG_ENODST => Err(NoDst), 188 | sys::spng_errno_SPNG_EOPSTATE => Err(OpState), 189 | sys::spng_errno_SPNG_ENOTFINAL => Err(NotFinal), 190 | _ => { 191 | eprintln!("unknown spng error code: {}", e); 192 | Err(Inval) 193 | } 194 | } 195 | } 196 | 197 | impl fmt::Display for Error { 198 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 199 | let errno = *self as i32; 200 | unsafe { 201 | let ptr = sys::spng_strerror(errno); 202 | let s = std::ffi::CStr::from_ptr(ptr); 203 | write!(f, "{}", s.to_string_lossy()) 204 | } 205 | } 206 | } 207 | 208 | impl StdError for Error {} 209 | -------------------------------------------------------------------------------- /spng/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! PNG image decoding 2 | //! 3 | //! Rust bindings to [libspng](https://libspng.org). 4 | //! 5 | //! # Examples 6 | //! 7 | //! ``` 8 | //! # static TEST_PNG: &[u8] = include_bytes!("../tests/test-001.png"); 9 | //! let cursor = std::io::Cursor::new(TEST_PNG); 10 | //! let decoder = spng::Decoder::new(cursor); 11 | //! let mut reader = decoder.read_info()?; 12 | //! let info = reader.info(); 13 | //! let output_buffer_size = reader.output_buffer_size(); 14 | //! assert_eq!(300, info.width); 15 | //! assert_eq!(300, info.height); 16 | //! assert_eq!(8, info.bit_depth as u8); 17 | //! assert_eq!(4, info.color_type.samples()); 18 | //! let mut out = vec![0; output_buffer_size]; 19 | //! let out_info = reader.next_frame(&mut out)?; 20 | //! assert_eq!(output_buffer_size, out_info.buffer_size()); 21 | //! # Ok::<(), Box>(()) 22 | //! ``` 23 | 24 | use std::convert::TryFrom; 25 | use std::io; 26 | 27 | use spng_sys as sys; 28 | 29 | mod error; 30 | pub mod raw; 31 | 32 | pub use error::Error; 33 | 34 | use raw::RawContext; 35 | 36 | #[repr(u32)] 37 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 38 | pub enum CrcAction { 39 | /// Return decode error. Default for critical chunks 40 | Error = sys::spng_crc_action_SPNG_CRC_ERROR, 41 | /// Discard chunk. Default for ancillary chunks, invalid for critical chunks 42 | Discard = sys::spng_crc_action_SPNG_CRC_DISCARD, 43 | /// Ignore and don't calculate checksum 44 | Use = sys::spng_crc_action_SPNG_CRC_USE, 45 | } 46 | 47 | /// PNG output format 48 | #[repr(u32)] 49 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 50 | pub enum Format { 51 | Rgba8 = sys::spng_format_SPNG_FMT_RGBA8, 52 | Rgba16 = sys::spng_format_SPNG_FMT_RGBA16, 53 | Rgb8 = sys::spng_format_SPNG_FMT_RGB8, 54 | G8 = sys::spng_format_SPNG_FMT_G8, 55 | Ga8 = sys::spng_format_SPNG_FMT_GA8, 56 | Ga16 = sys::spng_format_SPNG_FMT_GA16, 57 | /// The PNG's format in host-endian 58 | Png = sys::spng_format_SPNG_FMT_PNG, 59 | /// The PNG's format in big-endian 60 | Raw = sys::spng_format_SPNG_FMT_RAW, 61 | } 62 | 63 | #[repr(u8)] 64 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 65 | pub enum ColorType { 66 | Grayscale = sys::spng_color_type_SPNG_COLOR_TYPE_GRAYSCALE as u8, 67 | /// RGB 68 | Truecolor = sys::spng_color_type_SPNG_COLOR_TYPE_TRUECOLOR as u8, 69 | Indexed = sys::spng_color_type_SPNG_COLOR_TYPE_INDEXED as u8, 70 | GrayscaleAlpha = sys::spng_color_type_SPNG_COLOR_TYPE_GRAYSCALE_ALPHA as u8, 71 | /// RGBA 72 | TruecolorAlpha = sys::spng_color_type_SPNG_COLOR_TYPE_TRUECOLOR_ALPHA as u8, 73 | } 74 | 75 | impl ColorType { 76 | /// Alias for `Truecolor` 77 | pub const RGB: ColorType = ColorType::Truecolor; 78 | /// Alias for `TruecolorAlpha` 79 | pub const RGBA: ColorType = ColorType::TruecolorAlpha; 80 | /// Alias for `Grayscale` 81 | pub const G: ColorType = ColorType::Grayscale; 82 | /// Alias for `GrayscaleAlpha` 83 | pub const GA: ColorType = ColorType::GrayscaleAlpha; 84 | } 85 | 86 | impl TryFrom for ColorType { 87 | type Error = Error; 88 | fn try_from(value: u8) -> Result { 89 | use ColorType::*; 90 | match value as u32 { 91 | sys::spng_color_type_SPNG_COLOR_TYPE_GRAYSCALE => Ok(Grayscale), 92 | sys::spng_color_type_SPNG_COLOR_TYPE_TRUECOLOR => Ok(Truecolor), 93 | sys::spng_color_type_SPNG_COLOR_TYPE_INDEXED => Ok(Indexed), 94 | sys::spng_color_type_SPNG_COLOR_TYPE_GRAYSCALE_ALPHA => Ok(GrayscaleAlpha), 95 | sys::spng_color_type_SPNG_COLOR_TYPE_TRUECOLOR_ALPHA => Ok(TruecolorAlpha), 96 | _ => Err(Error::ColorType), 97 | } 98 | } 99 | } 100 | 101 | impl ColorType { 102 | /// Returns the number of samples per pixel 103 | pub fn samples(self) -> usize { 104 | use ColorType::*; 105 | match self { 106 | Grayscale | Indexed => 1, 107 | GrayscaleAlpha => 2, 108 | Truecolor => 3, 109 | TruecolorAlpha => 4, 110 | } 111 | } 112 | } 113 | 114 | #[repr(u8)] 115 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 116 | pub enum BitDepth { 117 | One = 1, 118 | Two = 2, 119 | Four = 4, 120 | Eight = 8, 121 | Sixteen = 16, 122 | } 123 | 124 | impl TryFrom for BitDepth { 125 | type Error = Error; 126 | fn try_from(value: u8) -> Result { 127 | use BitDepth::*; 128 | match value as i32 { 129 | 1 => Ok(One), 130 | 2 => Ok(Two), 131 | 4 => Ok(Four), 132 | 8 => Ok(Eight), 133 | 16 => Ok(Sixteen), 134 | _ => Err(Error::BitDepth), 135 | } 136 | } 137 | } 138 | 139 | bitflags::bitflags! { 140 | /// Decoding flags 141 | #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] 142 | pub struct DecodeFlags: u32 { 143 | /// Apply transparency 144 | const TRANSPARENCY = sys::spng_decode_flags_SPNG_DECODE_TRNS; 145 | /// Apply gamma correction 146 | const GAMMA = sys::spng_decode_flags_SPNG_DECODE_GAMMA; 147 | /// Initialize for progressive reads 148 | const PROGRESSIVE = sys::spng_decode_flags_SPNG_DECODE_PROGRESSIVE; 149 | #[doc(hidden)] 150 | const SIGNIFICANT_BIT = sys::spng_decode_flags_SPNG_DECODE_USE_SBIT; 151 | } 152 | } 153 | 154 | bitflags::bitflags! { 155 | #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] 156 | pub struct ContextFlags: u32 { 157 | /// Ignore checksum in `DEFLATE` streams 158 | const IGNORE_ADLER32 = sys::spng_ctx_flags_SPNG_CTX_IGNORE_ADLER32; 159 | } 160 | } 161 | 162 | #[repr(u32)] 163 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 164 | pub enum SpngOption { 165 | ZlibCompressionLevel = sys::spng_option_SPNG_IMG_COMPRESSION_LEVEL, 166 | ZlibWindowBits = sys::spng_option_SPNG_IMG_WINDOW_BITS, 167 | ChunkCountLimit = sys::spng_option_SPNG_CHUNK_COUNT_LIMIT, 168 | } 169 | 170 | /// Decoding limits 171 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 172 | pub struct Limits { 173 | /// Maximum image width 174 | pub max_width: u32, 175 | /// Maximum image height 176 | pub max_height: u32, 177 | } 178 | 179 | const PNG_U32_MAX: u32 = u32::MAX / 2 - 1; 180 | 181 | impl Default for Limits { 182 | fn default() -> Limits { 183 | Limits { 184 | max_width: PNG_U32_MAX, 185 | max_height: PNG_U32_MAX, 186 | } 187 | } 188 | } 189 | 190 | /// PNG decoder 191 | #[derive(Debug)] 192 | pub struct Decoder { 193 | reader: R, 194 | limits: Limits, 195 | context_flags: ContextFlags, 196 | decode_flags: DecodeFlags, 197 | critical_chunk_crc_action: CrcAction, 198 | ancillary_chunk_crc_action: CrcAction, 199 | output_format: Format, 200 | } 201 | 202 | /// Decoded output image information 203 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 204 | pub struct OutputInfo { 205 | /// The image width in pixels 206 | pub width: u32, 207 | /// The image height in pixels 208 | pub height: u32, 209 | /// The color channels 210 | pub color_type: ColorType, 211 | /// The per-component bit depth 212 | pub bit_depth: BitDepth, 213 | /// The minimum buffer size required for the decoded pixel output 214 | pub buffer_size: usize, 215 | } 216 | 217 | impl OutputInfo { 218 | /// The width of each row or scanline 219 | pub fn line_size(&self) -> usize { 220 | self.buffer_size / self.height as usize 221 | } 222 | 223 | pub fn buffer_size(&self) -> usize { 224 | self.buffer_size 225 | } 226 | } 227 | 228 | impl OutputInfo { 229 | fn from_ihdr_format_buffer_size( 230 | ihdr: &sys::spng_ihdr, 231 | output_format: Format, 232 | output_buffer_size: usize, 233 | ) -> Result { 234 | let bit_depth = match output_format { 235 | Format::Png | Format::Raw => BitDepth::try_from(ihdr.bit_depth)?, 236 | Format::Rgb8 | Format::Rgba8 | Format::G8 | Format::Ga8 => BitDepth::Eight, 237 | Format::Rgba16 | Format::Ga16 => BitDepth::Sixteen, 238 | }; 239 | let color_type = match output_format { 240 | Format::Png | Format::Raw => ColorType::try_from(ihdr.color_type)?, 241 | Format::Rgb8 => ColorType::Truecolor, 242 | Format::Rgba8 => ColorType::TruecolorAlpha, 243 | Format::Rgba16 => ColorType::TruecolorAlpha, 244 | Format::G8 => ColorType::Grayscale, 245 | Format::Ga8 | Format::Ga16 => ColorType::GrayscaleAlpha, 246 | }; 247 | Ok(OutputInfo { 248 | bit_depth, 249 | color_type, 250 | width: ihdr.width, 251 | height: ihdr.height, 252 | buffer_size: output_buffer_size, 253 | }) 254 | } 255 | } 256 | 257 | /// PNG image information 258 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 259 | pub struct Info { 260 | /// The image width in pixels 261 | pub width: u32, 262 | /// The image height in pixels 263 | pub height: u32, 264 | /// The color channels 265 | pub color_type: ColorType, 266 | /// The per-component bit depth 267 | pub bit_depth: BitDepth, 268 | } 269 | 270 | impl Info { 271 | fn from_ihdr(header: &sys::spng_ihdr) -> Result { 272 | Ok(Info { 273 | width: header.width, 274 | height: header.height, 275 | bit_depth: BitDepth::try_from(header.bit_depth)?, 276 | color_type: ColorType::try_from(header.color_type)?, 277 | }) 278 | } 279 | } 280 | 281 | #[derive(Debug)] 282 | /// PNG reader 283 | pub struct Reader { 284 | ctx: RawContext, 285 | ihdr: sys::spng_ihdr, 286 | output_buffer_size: usize, 287 | output_format: Format, 288 | decode_flags: DecodeFlags, 289 | } 290 | 291 | impl Decoder { 292 | /// Create a new `png` decoder with the default limits 293 | pub fn new(reader: R) -> Decoder { 294 | let decode_flags = DecodeFlags::empty(); 295 | let context_flags = ContextFlags::empty(); 296 | let output_format = Format::Png; 297 | let critical_chunk_crc_action = CrcAction::Error; 298 | let ancillary_chunk_crc_action = CrcAction::Discard; 299 | let limits = Limits::default(); 300 | Decoder { 301 | reader, 302 | limits, 303 | context_flags, 304 | decode_flags, 305 | critical_chunk_crc_action, 306 | ancillary_chunk_crc_action, 307 | output_format, 308 | } 309 | } 310 | 311 | pub fn with_limits(mut self, limits: Limits) -> Decoder { 312 | self.limits = limits; 313 | self 314 | } 315 | 316 | pub fn with_context_flags(mut self, context_flags: ContextFlags) -> Decoder { 317 | self.context_flags = context_flags; 318 | self 319 | } 320 | 321 | pub fn with_decode_flags(mut self, decode_flags: DecodeFlags) -> Decoder { 322 | self.decode_flags = decode_flags; 323 | self 324 | } 325 | 326 | pub fn with_crc_actions(mut self, critical: CrcAction, ancillary: CrcAction) -> Decoder { 327 | self.critical_chunk_crc_action = critical; 328 | self.ancillary_chunk_crc_action = ancillary; 329 | self 330 | } 331 | 332 | pub fn with_output_format(mut self, output_format: Format) -> Decoder { 333 | self.output_format = output_format; 334 | self 335 | } 336 | 337 | /// Set the limits 338 | pub fn set_limits(&mut self, limits: Limits) { 339 | self.limits = limits; 340 | } 341 | 342 | /// Set the decoding flags 343 | pub fn set_decode_flags(&mut self, decode_flags: DecodeFlags) { 344 | self.decode_flags = decode_flags; 345 | } 346 | 347 | /// Set the output image format 348 | pub fn set_output_format(&mut self, output_format: Format) { 349 | self.output_format = output_format; 350 | } 351 | 352 | pub fn set_context_flags(&mut self, context_flags: ContextFlags) { 353 | self.context_flags = context_flags; 354 | } 355 | 356 | /// Read the `png` header and initialize decoding. 357 | pub fn read_info(self) -> Result, Error> 358 | where 359 | R: io::Read, 360 | { 361 | let mut ctx = RawContext::with_flags(self.context_flags)?; 362 | ctx.set_image_limits(self.limits.max_width, self.limits.max_height)?; 363 | ctx.set_crc_action( 364 | self.critical_chunk_crc_action, 365 | self.ancillary_chunk_crc_action, 366 | )?; 367 | ctx.set_png_stream(self.reader)?; 368 | let ihdr = ctx.get_ihdr()?; 369 | let output_buffer_size = ctx.decoded_image_size(self.output_format)?; 370 | let reader = Reader { 371 | ctx, 372 | ihdr, 373 | output_format: self.output_format, 374 | decode_flags: self.decode_flags, 375 | output_buffer_size, 376 | }; 377 | 378 | Ok(reader) 379 | } 380 | } 381 | 382 | impl Reader { 383 | /// Returns input information 384 | pub fn info(&self) -> Info { 385 | Info::from_ihdr(&self.ihdr).expect("invalid ihdr") 386 | } 387 | 388 | /// Returns the minimum buffer size required for `next_frame` 389 | #[inline] 390 | pub fn output_buffer_size(&self) -> usize { 391 | self.output_buffer_size 392 | } 393 | 394 | /// Decodes the next frame of the `png`. This currently may only be called once. 395 | pub fn next_frame(&mut self, output: &mut [u8]) -> Result { 396 | self.ctx 397 | .decode_image(output, self.output_format, self.decode_flags)?; 398 | let ihdr = self.ctx.get_ihdr()?; 399 | let output_info = OutputInfo::from_ihdr_format_buffer_size( 400 | &ihdr, 401 | self.output_format, 402 | self.output_buffer_size(), 403 | )?; 404 | Ok(output_info) 405 | } 406 | 407 | /// Returns a reference to the `RawContext`. 408 | pub fn raw_context(&self) -> &RawContext { 409 | &self.ctx 410 | } 411 | } 412 | 413 | /// Decode `png` data. 414 | pub fn decode(reader: R, output_format: Format) -> Result<(OutputInfo, Vec), Error> 415 | where 416 | R: io::Read, 417 | { 418 | let decoder = Decoder::new(reader).with_output_format(output_format); 419 | let mut reader = decoder.read_info()?; 420 | let mut out = Vec::new(); 421 | out.reserve_exact(reader.output_buffer_size()); 422 | unsafe { 423 | out.set_len(reader.output_buffer_size()); 424 | } 425 | let out_info = reader.next_frame(&mut out)?; 426 | Ok((out_info, out)) 427 | } 428 | 429 | /// Returns the `libspng` version: `(major, minor, patch)` 430 | pub fn version() -> (u32, u32, u32) { 431 | ( 432 | spng_sys::SPNG_VERSION_MAJOR, 433 | spng_sys::SPNG_VERSION_MINOR, 434 | spng_sys::SPNG_VERSION_PATCH, 435 | ) 436 | } 437 | -------------------------------------------------------------------------------- /spng/src/raw.rs: -------------------------------------------------------------------------------- 1 | //! Raw decoding context 2 | 3 | use crate::{ 4 | error::{check_err, Error}, 5 | ContextFlags, CrcAction, DecodeFlags, Format, SpngOption, 6 | }; 7 | 8 | use self::chunk::*; 9 | 10 | use spng_sys as sys; 11 | use std::{io, marker::PhantomData, mem, mem::MaybeUninit, ptr::NonNull, slice}; 12 | 13 | unsafe extern "C" fn read_fn( 14 | _: *mut sys::spng_ctx, 15 | user: *mut libc::c_void, 16 | dest: *mut libc::c_void, 17 | len: usize, 18 | ) -> libc::c_int { 19 | let reader: &mut R = &mut *(user as *mut R as *mut _); 20 | let dest = slice::from_raw_parts_mut(dest as *mut u8, len); 21 | let mut offset = 0; 22 | while offset < len { 23 | let buf = &mut dest[offset..]; 24 | let ret = reader.read(buf); 25 | match ret { 26 | Ok(0) => return sys::spng_errno_SPNG_IO_EOF, 27 | Ok(n) => offset += n, 28 | Err(_) => return sys::spng_errno_SPNG_IO_ERROR, 29 | } 30 | } 31 | sys::spng_errno_SPNG_OK 32 | } 33 | 34 | /// Helper trait for converting optional ancillary chunks into `Option`. 35 | /// 36 | /// 37 | /// 38 | /// ## Ancilary chunks 39 | /// 40 | /// * BKGD 41 | /// * CHRM 42 | /// * GAMA 43 | /// * HIST 44 | /// * ICCP 45 | /// * PHYS 46 | /// * SBIT 47 | /// * SPLT 48 | /// * SRGB 49 | /// * TEXT 50 | /// * TIME 51 | /// * TRNS 52 | /// * ZTXT 53 | pub trait ChunkAvail { 54 | /// Converts `Err(Error::Chunkavail)` into `Ok(None)`. 55 | fn chunk_avail(self) -> Result, Error>; 56 | } 57 | 58 | impl ChunkAvail for Result { 59 | fn chunk_avail(self) -> Result, Error> { 60 | match self { 61 | Ok(value) => Ok(Some(value)), 62 | Err(Error::Chunkavail) => Ok(None), 63 | Err(error) => Err(error), 64 | } 65 | } 66 | } 67 | 68 | /// The raw decoding context. 69 | /// 70 | /// * 71 | /// * 72 | #[derive(Debug)] 73 | pub struct RawContext { 74 | raw: *mut sys::spng_ctx, 75 | reader: Option>, 76 | } 77 | 78 | impl Drop for RawContext { 79 | fn drop(&mut self) { 80 | if !self.raw.is_null() { 81 | unsafe { 82 | sys::spng_ctx_free(self.raw); 83 | } 84 | } 85 | if let Some(reader) = self.reader { 86 | unsafe { 87 | drop(Box::from_raw(reader.as_ptr())); 88 | } 89 | } 90 | } 91 | } 92 | 93 | impl RawContext { 94 | pub fn new() -> Result, Error> { 95 | RawContext::with_flags(ContextFlags::empty()) 96 | } 97 | 98 | pub fn with_flags(flags: ContextFlags) -> Result, Error> { 99 | unsafe { 100 | let raw = sys::spng_ctx_new(flags.bits() as _); 101 | if raw.is_null() { 102 | Err(Error::Mem) 103 | } else { 104 | Ok(RawContext { raw, reader: None }) 105 | } 106 | } 107 | } 108 | 109 | /// Set how chunk CRC errors should be handled for critical and ancillary chunks. 110 | pub fn set_crc_action( 111 | &mut self, 112 | critical: CrcAction, 113 | ancillary: CrcAction, 114 | ) -> Result<(), Error> { 115 | unsafe { 116 | check_err(sys::spng_set_crc_action( 117 | self.raw, 118 | critical as i32, 119 | ancillary as i32, 120 | )) 121 | } 122 | } 123 | 124 | /// Get image width and height limits. 125 | /// 126 | /// Returns `(width, height)` 127 | pub fn get_image_limits(&self) -> Result<(u32, u32), Error> { 128 | let mut width = 0; 129 | let mut height = 0; 130 | unsafe { 131 | check_err(sys::spng_get_image_limits( 132 | self.raw, 133 | &mut width, 134 | &mut height, 135 | ))?; 136 | Ok((width, height)) 137 | } 138 | } 139 | 140 | /// Set image width and height limits, these may not be larger than `(2^31)-1`. 141 | pub fn set_image_limits(&mut self, max_width: u32, max_height: u32) -> Result<(), Error> { 142 | unsafe { check_err(sys::spng_set_image_limits(self.raw, max_width, max_height)) } 143 | } 144 | 145 | /// Get chunk size and chunk cache limits. 146 | /// 147 | /// Returns `(chunk_size, cache_size)` 148 | pub fn get_chunk_limits(&self) -> Result<(usize, usize), Error> { 149 | let mut chunk_size = 0; 150 | let mut cache_size = 0; 151 | unsafe { 152 | check_err(sys::spng_get_chunk_limits( 153 | self.raw, 154 | &mut chunk_size, 155 | &mut cache_size, 156 | ))?; 157 | Ok((chunk_size, cache_size)) 158 | } 159 | } 160 | 161 | /// Set chunk size and chunk cache limits, the default chunk size limit is `(2^31)-1`, the default 162 | /// chunk cache limit is `SIZE_MAX`. 163 | pub fn set_chunk_limits(&mut self, chunk_size: usize, cache_size: usize) -> Result<(), Error> { 164 | unsafe { check_err(sys::spng_set_chunk_limits(self.raw, chunk_size, cache_size)) } 165 | } 166 | 167 | /// Get the image header. 168 | pub fn get_ihdr(&self) -> Result { 169 | unsafe { 170 | let mut chunk = MaybeUninit::uninit(); 171 | check_err(sys::spng_get_ihdr(self.raw, chunk.as_mut_ptr()))?; 172 | Ok(chunk.assume_init()) 173 | } 174 | } 175 | 176 | /// Get the image palette. 177 | pub fn get_plte(&self) -> Result, Error> { 178 | unsafe { 179 | let mut chunk = MaybeUninit::uninit(); 180 | check_err(sys::spng_get_plte(self.raw, chunk.as_mut_ptr()))?; 181 | Ok(Ref::from(Plte(chunk.assume_init()))) 182 | } 183 | } 184 | 185 | /// Get the image transparency. 186 | pub fn get_trns(&self) -> Result { 187 | unsafe { 188 | let mut chunk = MaybeUninit::uninit(); 189 | check_err(sys::spng_get_trns(self.raw, chunk.as_mut_ptr()))?; 190 | Ok(chunk.assume_init()) 191 | } 192 | } 193 | 194 | /// Get primary chromacities and white point as floating point numbers. 195 | pub fn get_chrm(&self) -> Result { 196 | unsafe { 197 | let mut chunk = MaybeUninit::uninit(); 198 | check_err(sys::spng_get_chrm(self.raw, chunk.as_mut_ptr()))?; 199 | Ok(chunk.assume_init()) 200 | } 201 | } 202 | 203 | /// Get primary chromacities and white point in the PNG's internal representation. 204 | pub fn get_chrm_int(&self) -> Result { 205 | unsafe { 206 | let mut chunk = MaybeUninit::uninit(); 207 | check_err(sys::spng_get_chrm_int(self.raw, chunk.as_mut_ptr()))?; 208 | Ok(chunk.assume_init()) 209 | } 210 | } 211 | 212 | /// Get the image gamma. 213 | pub fn get_gama(&self) -> Result { 214 | unsafe { 215 | let mut chunk = MaybeUninit::uninit(); 216 | check_err(sys::spng_get_gama(self.raw, chunk.as_mut_ptr()))?; 217 | Ok(chunk.assume_init()) 218 | } 219 | } 220 | 221 | /// Get image gamma in PNG's internal representation. 222 | pub fn get_gama_int(&self) -> Result { 223 | let mut gama_int = 0; 224 | unsafe { 225 | check_err(sys::spng_get_gama_int(self.raw, &mut gama_int))?; 226 | } 227 | Ok(gama_int) 228 | } 229 | 230 | /// Get the ICC profile. 231 | /// 232 | /// ### Note 233 | /// ICC profiles are not validated. 234 | pub fn get_iccp(&self) -> Result, Error> { 235 | unsafe { 236 | let mut chunk = MaybeUninit::uninit(); 237 | check_err(sys::spng_get_iccp(self.raw, chunk.as_mut_ptr()))?; 238 | let chunk: Iccp = mem::transmute(chunk.assume_init()); 239 | Ok(Ref::from(chunk)) 240 | } 241 | } 242 | 243 | /// Get the significant bits. 244 | pub fn get_sbit(&self) -> Result { 245 | unsafe { 246 | let mut chunk = MaybeUninit::uninit(); 247 | check_err(sys::spng_get_sbit(self.raw, chunk.as_mut_ptr()))?; 248 | Ok(chunk.assume_init()) 249 | } 250 | } 251 | 252 | /// Get the `sRGB` rendering intent. 253 | pub fn get_srgb(&self) -> Result { 254 | unsafe { 255 | let mut rendering_intent = 0; 256 | check_err(sys::spng_get_srgb(self.raw, &mut rendering_intent))?; 257 | Ok(rendering_intent) 258 | } 259 | } 260 | 261 | /// Get text information. 262 | /// 263 | /// ### Note 264 | /// Due to the structure of PNG files it is recommended to call this function after [`decode_image`]. 265 | /// 266 | /// [`decode_image`]: method@RawContext::decode_image 267 | pub fn get_text(&self) -> Result>, Error> { 268 | unsafe { 269 | use std::ptr; 270 | let mut len = 0; 271 | check_err(sys::spng_get_text(self.raw, ptr::null_mut(), &mut len))?; 272 | let mut vec = Vec::::new(); 273 | vec.reserve_exact(len as usize); 274 | vec.set_len(len as usize); 275 | let text_ptr = vec.as_mut_ptr() as *mut sys::spng_text; 276 | check_err(sys::spng_get_text(self.raw, text_ptr, &mut len))?; 277 | Ok(Ref::from(vec)) 278 | } 279 | } 280 | 281 | /// Get the image background color. 282 | pub fn get_bkgd(&self) -> Result { 283 | unsafe { 284 | let mut chunk = MaybeUninit::uninit(); 285 | check_err(sys::spng_get_bkgd(self.raw, chunk.as_mut_ptr()))?; 286 | Ok(chunk.assume_init()) 287 | } 288 | } 289 | 290 | /// Get the image histogram. 291 | pub fn get_hist(&self) -> Result { 292 | unsafe { 293 | let mut chunk = MaybeUninit::uninit(); 294 | check_err(sys::spng_get_hist(self.raw, chunk.as_mut_ptr()))?; 295 | Ok(chunk.assume_init()) 296 | } 297 | } 298 | 299 | /// Get physical pixel dimensions. 300 | pub fn get_phys(&self) -> Result { 301 | unsafe { 302 | let mut chunk = MaybeUninit::uninit(); 303 | check_err(sys::spng_get_phys(self.raw, chunk.as_mut_ptr()))?; 304 | Ok(chunk.assume_init()) 305 | } 306 | } 307 | 308 | /// Get the suggested palettes. 309 | pub fn get_splt(&self) -> Result>, Error> { 310 | unsafe { 311 | use std::ptr; 312 | let mut len = 0; 313 | check_err(sys::spng_get_splt(self.raw, ptr::null_mut(), &mut len))?; 314 | let mut vec = Vec::::new(); 315 | vec.reserve_exact(len as usize); 316 | vec.set_len(len as usize); 317 | let splt_ptr = vec.as_mut_ptr() as *mut sys::spng_splt; 318 | check_err(sys::spng_get_splt(self.raw, splt_ptr, &mut len))?; 319 | Ok(Ref::from(vec)) 320 | } 321 | } 322 | 323 | /// Get the modification time. 324 | /// 325 | /// ### Note 326 | /// Due to the structure of PNG files it is recommended to call this function after [`decode_image`]. 327 | /// 328 | /// [`decode_image`]: method@RawContext::decode_image 329 | pub fn get_time(&self) -> Result { 330 | unsafe { 331 | let mut chunk = MaybeUninit::uninit(); 332 | check_err(sys::spng_get_time(self.raw, chunk.as_mut_ptr()))?; 333 | Ok(chunk.assume_init()) 334 | } 335 | } 336 | 337 | /// Get the image offset. 338 | pub fn get_offs(&self) -> Result { 339 | unsafe { 340 | let mut chunk = MaybeUninit::uninit(); 341 | check_err(sys::spng_get_offs(self.raw, chunk.as_mut_ptr()))?; 342 | Ok(chunk.assume_init()) 343 | } 344 | } 345 | 346 | /// Get the `EXIF` data. 347 | /// 348 | /// ### Note 349 | /// Due to the structure of PNG files it is recommended to call this function after [`decode_image`]. 350 | /// 351 | /// [`decode_image`]: method@RawContext::decode_image 352 | pub fn get_exif(&self) -> Result, Error> { 353 | unsafe { 354 | let mut chunk = MaybeUninit::uninit(); 355 | check_err(sys::spng_get_exif(self.raw, chunk.as_mut_ptr()))?; 356 | let chunk: Exif = mem::transmute(chunk.assume_init()); 357 | Ok(Ref::from(chunk)) 358 | } 359 | } 360 | 361 | /// Get the current, to-be-decoded row's information. 362 | pub fn get_row_info(&self) -> Result { 363 | unsafe { 364 | let mut chunk = MaybeUninit::uninit(); 365 | check_err(sys::spng_get_row_info(self.raw, chunk.as_mut_ptr()))?; 366 | Ok(chunk.assume_init()) 367 | } 368 | } 369 | 370 | /// Returns unknown chunk information. 371 | /// 372 | /// ### Note 373 | /// Due to the structure of PNG files it is recommended to call this function after [`decode_image`]. 374 | /// 375 | /// [`decode_image`]: method@RawContext::decode_image 376 | pub fn get_unknown_chunks(&self) -> Result>, Error> { 377 | unsafe { 378 | use std::ptr; 379 | let mut len = 0; 380 | check_err(sys::spng_get_unknown_chunks( 381 | self.raw, 382 | ptr::null_mut(), 383 | &mut len, 384 | ))?; 385 | let mut vec = Vec::::new(); 386 | vec.reserve_exact(len as usize); 387 | vec.set_len(len as usize); 388 | let chunk_ptr = vec.as_mut_ptr() as *mut sys::spng_unknown_chunk; 389 | check_err(sys::spng_get_unknown_chunks(self.raw, chunk_ptr, &mut len))?; 390 | Ok(Ref::from(vec)) 391 | } 392 | } 393 | 394 | /// Calculates decoded image buffer size for the given output format. 395 | /// 396 | /// PNG data must have been set prior with [`set_png_stream`] or [`set_png_buffer`]. 397 | /// 398 | /// [`set_png_stream`]: method@RawContext::set_png_stream 399 | /// [`set_png_buffer`]: method@RawContext::set_png_buffer 400 | pub fn decoded_image_size(&self, out_format: Format) -> Result { 401 | let mut len = 0; 402 | unsafe { 403 | check_err(sys::spng_decoded_image_size( 404 | self.raw, 405 | out_format as _, 406 | &mut len, 407 | ))?; 408 | } 409 | Ok(len) 410 | } 411 | 412 | /// Decodes the PNG file and writes the image to `out`. The image is converted from any PNG format to the 413 | /// destination format `out_format`. Interlaced images are deinterlaced and `16-bit` images are converted to 414 | /// host-endian. 415 | /// 416 | /// The `out` buffer must have a length greater or equal to the size returned by [`decoded_image_size`] with 417 | /// the same `out_format`. 418 | /// 419 | /// If the `SPNG_DECODE_PROGRESSIVE` flag is set, the context will be initialized with `out_format` for 420 | /// progressive decoding. The image is not immediately decoded and the `out` buffer is ignored. 421 | /// 422 | /// The `SPNG_DECODE_TRNS` flag is ignored if the PNG has an alpha channel or does not contain a `TRNS` 423 | /// chunk. It is also ignored for gray `1/2/4`-bit images. 424 | /// 425 | /// The function may only be called **once** per context. 426 | /// 427 | /// [`decode_image`]: method@RawContext::decode_image 428 | /// [`decoded_image_size`]: method@RawContext::decoded_image_size 429 | pub fn decode_image( 430 | &mut self, 431 | out: &mut [u8], 432 | out_format: Format, 433 | flags: DecodeFlags, 434 | ) -> Result<(), Error> { 435 | unsafe { 436 | check_err(sys::spng_decode_image( 437 | self.raw, 438 | out.as_mut_ptr() as _, 439 | out.len(), 440 | out_format as _, 441 | flags.bits() as _, 442 | )) 443 | } 444 | } 445 | 446 | /// Decodes and deinterlaces a scanline to `out`. 447 | /// 448 | /// This function requires the decoder to be initialized by calling [`decode_image`] with the 449 | /// `SPNG_DECODE_PROGRESSIVE` flag set. 450 | /// 451 | /// The widest scanline is the decoded image size divided by `ihdr.height`. 452 | /// 453 | /// For the last scanline and subsequent calls the return value is `SPNG_EOI`. 454 | /// 455 | /// If the image is not interlaced this function's behavior is identical to [`decode_scanline`]. 456 | /// 457 | /// [`decode_image`]: method@RawContext::decode_image 458 | /// [`decode_scanline`]: method@RawContext::decode_scanline 459 | pub fn decode_row(&mut self, out: &mut [u8]) -> Result<(), Error> { 460 | unsafe { 461 | check_err(sys::spng_decode_row( 462 | self.raw, 463 | out.as_mut_ptr() as _, 464 | out.len(), 465 | )) 466 | } 467 | } 468 | 469 | /// Decode all chunks before or after the image data (IDAT) stream, 470 | /// depending on the state of the decoder. 471 | /// 472 | /// If the image is decoded this function will read up to the end-of-file (IEND) marker. 473 | /// 474 | /// Calling this function before `decode_image` is optional. 475 | /// 476 | /// [`decode_image`]: method@RawContext::decode_image 477 | pub fn decode_chunks(&mut self) -> Result<(), Error> { 478 | unsafe { check_err(sys::spng_decode_chunks(self.raw)) } 479 | } 480 | 481 | /// Decodes a scanline to `out`. 482 | /// 483 | /// This function requires the decoder to be initialized by calling [`decode_image`] with the 484 | /// `SPNG_DECODE_PROGRESSIVE` flag set. 485 | /// 486 | /// The widest scanline is the decoded image size divided by `ihdr.height`. 487 | /// 488 | /// For the last scanline and subsequent calls the return value is `SPNG_EOI`. 489 | /// 490 | /// [`decode_image`]: method@RawContext::decode_image 491 | pub fn decode_scanline(&mut self, output: &mut [u8]) -> Result<(), Error> { 492 | unsafe { 493 | check_err(sys::spng_decode_scanline( 494 | self.raw, 495 | output.as_mut_ptr() as _, 496 | output.len(), 497 | )) 498 | } 499 | } 500 | 501 | /// Sets `option` to the specified `value`. 502 | pub fn set_option(&mut self, option: SpngOption, value: i32) -> Result<(), Error> { 503 | unsafe { check_err(sys::spng_set_option(self.raw, option as _, value as _)) } 504 | } 505 | 506 | /// Gets the value for the specified `option`. 507 | pub fn get_option(&self, option: SpngOption) -> Result { 508 | let mut value = 0; 509 | unsafe { 510 | check_err(sys::spng_get_option(self.raw, option as _, &mut value))?; 511 | } 512 | Ok(value as _) 513 | } 514 | } 515 | 516 | impl RawContext { 517 | /// Set the input `png` stream reader. The input buffer or stream may only be set once per context. 518 | pub fn set_png_stream(&mut self, reader: R) -> Result<(), Error> { 519 | let boxed = Box::new(reader); 520 | let unboxed = Box::into_raw(boxed); 521 | self.reader = NonNull::new(unboxed); 522 | let rw_fn: sys::spng_rw_fn = Some(read_fn::); 523 | unsafe { check_err(sys::spng_set_png_stream(self.raw, rw_fn, unboxed as *mut _)) } 524 | } 525 | } 526 | 527 | impl<'a> RawContext<&'a [u8]> { 528 | /// Set the input `png` buffer. The input buffer or stream may only be set once per context. 529 | pub fn set_png_buffer(&mut self, buf: &'a [u8]) -> Result<(), Error> { 530 | unsafe { 531 | check_err(sys::spng_set_png_buffer( 532 | self.raw, 533 | buf.as_ptr() as *const _, 534 | buf.len(), 535 | )) 536 | } 537 | } 538 | } 539 | 540 | /// Attaches lifetime `'a` to `T`. 541 | pub struct Ref<'a, T: 'a> { 542 | data: T, 543 | _p: PhantomData<&'a ()>, 544 | } 545 | 546 | impl<'a, T: 'a> std::ops::Deref for Ref<'a, T> { 547 | type Target = T; 548 | fn deref(&self) -> &Self::Target { 549 | &self.data 550 | } 551 | } 552 | 553 | impl<'a, T: 'a> From for Ref<'a, T> { 554 | fn from(t: T) -> Ref<'a, T> { 555 | Ref { 556 | data: t, 557 | _p: PhantomData, 558 | } 559 | } 560 | } 561 | 562 | /// `PNG` chunk data 563 | pub mod chunk { 564 | use spng_sys as sys; 565 | use std::{ffi::CStr, slice}; 566 | 567 | /// Safe wrapper for [`spng_sys::spng_splt`] 568 | #[repr(transparent)] 569 | pub struct Splt(pub(crate) sys::spng_splt); 570 | 571 | impl Splt { 572 | pub fn name(&self) -> Result<&str, std::str::Utf8Error> { 573 | unsafe { CStr::from_ptr(self.0.name.as_ptr() as _).to_str() } 574 | } 575 | 576 | pub fn sample_depth(&self) -> u8 { 577 | self.0.sample_depth 578 | } 579 | 580 | pub fn entries(&self) -> &[sys::spng_splt_entry] { 581 | unsafe { slice::from_raw_parts(self.0.entries, self.0.n_entries as usize) } 582 | } 583 | } 584 | 585 | /// Safe wrapper for [`spng_sys::spng_plte`] 586 | #[repr(transparent)] 587 | pub struct Plte(pub(crate) sys::spng_plte); 588 | 589 | impl Plte { 590 | pub fn entries(&self) -> &[PlteEntry] { 591 | unsafe { slice::from_raw_parts(self.0.entries.as_ptr(), self.0.n_entries as usize) } 592 | } 593 | } 594 | 595 | /// Safe wrapper for [`spng_sys::spng_exif`] 596 | #[repr(transparent)] 597 | pub struct Exif(pub(crate) sys::spng_exif); 598 | 599 | impl Exif { 600 | pub fn data(&self) -> &[u8] { 601 | unsafe { slice::from_raw_parts(self.0.data as _, self.0.length) } 602 | } 603 | } 604 | 605 | /// Safe wrapper for [`spng_sys::spng_text`] 606 | #[repr(transparent)] 607 | pub struct Text(pub(crate) sys::spng_text); 608 | 609 | impl Text { 610 | pub fn keyword(&self) -> Result<&str, std::str::Utf8Error> { 611 | unsafe { CStr::from_ptr(self.0.keyword.as_ptr() as _).to_str() } 612 | } 613 | 614 | pub fn type_(&self) -> i32 { 615 | self.0.type_ 616 | } 617 | 618 | pub fn length(&self) -> usize { 619 | self.0.length 620 | } 621 | 622 | pub fn text(&self) -> Result<&str, std::str::Utf8Error> { 623 | unsafe { CStr::from_ptr(self.0.text).to_str() } 624 | } 625 | 626 | pub fn text_bytes(&self) -> &[u8] { 627 | unsafe { slice::from_raw_parts(self.0.text as _, self.0.length) } 628 | } 629 | 630 | pub fn compression_flag(&self) -> u8 { 631 | self.0.compression_flag 632 | } 633 | 634 | pub fn compression_method(&self) -> u8 { 635 | self.0.compression_method 636 | } 637 | 638 | pub fn language_tag(&self) -> Result<&str, std::str::Utf8Error> { 639 | unsafe { CStr::from_ptr(self.0.language_tag).to_str() } 640 | } 641 | 642 | pub fn translated_keyword(&self) -> Result<&str, std::str::Utf8Error> { 643 | unsafe { CStr::from_ptr(self.0.translated_keyword).to_str() } 644 | } 645 | } 646 | 647 | /// Safe wrapper for [`spng_sys::spng_iccp`] 648 | #[repr(transparent)] 649 | pub struct Iccp(pub(crate) sys::spng_iccp); 650 | 651 | impl Iccp { 652 | pub fn profile_name(&self) -> Result<&str, std::str::Utf8Error> { 653 | unsafe { CStr::from_ptr(self.0.profile_name.as_ptr()).to_str() } 654 | } 655 | 656 | pub fn profile(&self) -> &[u8] { 657 | unsafe { slice::from_raw_parts(self.0.profile as _, self.0.profile_len) } 658 | } 659 | } 660 | 661 | /// Safe wrapper for [`spng_sys::spng_unknown_chunk`] 662 | #[repr(transparent)] 663 | pub struct UnknownChunk(pub(crate) spng_sys::spng_unknown_chunk); 664 | 665 | impl UnknownChunk { 666 | /// Returns the chunk type. 667 | pub fn type_(&self) -> Result<&str, std::str::Utf8Error> { 668 | std::str::from_utf8(&self.0.type_) 669 | } 670 | 671 | /// Returns the chunk data. 672 | pub fn data(&self) -> &[u8] { 673 | unsafe { slice::from_raw_parts(self.0.data as _, self.0.length) } 674 | } 675 | } 676 | 677 | /// Image header 678 | pub type Ihdr = sys::spng_ihdr; 679 | /// Transparency 680 | pub type Trns = sys::spng_trns; 681 | /// Primary chromacities and white point as floating point numbers 682 | pub type Chrm = sys::spng_chrm; 683 | /// Primary chromacities and white point in the PNG's internal representation 684 | pub type ChrmInt = sys::spng_chrm_int; 685 | /// Significant bits 686 | pub type Sbit = sys::spng_sbit; 687 | /// Background color 688 | pub type Bkgd = sys::spng_bkgd; 689 | /// Histogram 690 | pub type Hist = sys::spng_hist; 691 | /// Physical pixel dimensions 692 | pub type Phys = sys::spng_phys; 693 | /// Modification time 694 | pub type Time = sys::spng_time; 695 | /// Offset 696 | pub type Offs = sys::spng_offs; 697 | /// To-be-decoded row information 698 | pub type RowInfo = sys::spng_row_info; 699 | /// Palette entry 700 | pub type PlteEntry = spng_sys::spng_plte_entry; 701 | } 702 | -------------------------------------------------------------------------------- /spng-sys/src/ffi.rs: -------------------------------------------------------------------------------- 1 | /* automatically generated by rust-bindgen 0.69.2 */ 2 | 3 | /* bindgen 0.69.2 */ 4 | 5 | pub const SPNG_VERSION_MAJOR: u32 = 0; 6 | pub const SPNG_VERSION_MINOR: u32 = 7; 7 | pub const SPNG_VERSION_PATCH: u32 = 4; 8 | pub type FILE = [u64; 27usize]; 9 | pub const spng_errno_SPNG_IO_ERROR: spng_errno = -2; 10 | pub const spng_errno_SPNG_IO_EOF: spng_errno = -1; 11 | pub const spng_errno_SPNG_OK: spng_errno = 0; 12 | pub const spng_errno_SPNG_EINVAL: spng_errno = 1; 13 | pub const spng_errno_SPNG_EMEM: spng_errno = 2; 14 | pub const spng_errno_SPNG_EOVERFLOW: spng_errno = 3; 15 | pub const spng_errno_SPNG_ESIGNATURE: spng_errno = 4; 16 | pub const spng_errno_SPNG_EWIDTH: spng_errno = 5; 17 | pub const spng_errno_SPNG_EHEIGHT: spng_errno = 6; 18 | pub const spng_errno_SPNG_EUSER_WIDTH: spng_errno = 7; 19 | pub const spng_errno_SPNG_EUSER_HEIGHT: spng_errno = 8; 20 | pub const spng_errno_SPNG_EBIT_DEPTH: spng_errno = 9; 21 | pub const spng_errno_SPNG_ECOLOR_TYPE: spng_errno = 10; 22 | pub const spng_errno_SPNG_ECOMPRESSION_METHOD: spng_errno = 11; 23 | pub const spng_errno_SPNG_EFILTER_METHOD: spng_errno = 12; 24 | pub const spng_errno_SPNG_EINTERLACE_METHOD: spng_errno = 13; 25 | pub const spng_errno_SPNG_EIHDR_SIZE: spng_errno = 14; 26 | pub const spng_errno_SPNG_ENOIHDR: spng_errno = 15; 27 | pub const spng_errno_SPNG_ECHUNK_POS: spng_errno = 16; 28 | pub const spng_errno_SPNG_ECHUNK_SIZE: spng_errno = 17; 29 | pub const spng_errno_SPNG_ECHUNK_CRC: spng_errno = 18; 30 | pub const spng_errno_SPNG_ECHUNK_TYPE: spng_errno = 19; 31 | pub const spng_errno_SPNG_ECHUNK_UNKNOWN_CRITICAL: spng_errno = 20; 32 | pub const spng_errno_SPNG_EDUP_PLTE: spng_errno = 21; 33 | pub const spng_errno_SPNG_EDUP_CHRM: spng_errno = 22; 34 | pub const spng_errno_SPNG_EDUP_GAMA: spng_errno = 23; 35 | pub const spng_errno_SPNG_EDUP_ICCP: spng_errno = 24; 36 | pub const spng_errno_SPNG_EDUP_SBIT: spng_errno = 25; 37 | pub const spng_errno_SPNG_EDUP_SRGB: spng_errno = 26; 38 | pub const spng_errno_SPNG_EDUP_BKGD: spng_errno = 27; 39 | pub const spng_errno_SPNG_EDUP_HIST: spng_errno = 28; 40 | pub const spng_errno_SPNG_EDUP_TRNS: spng_errno = 29; 41 | pub const spng_errno_SPNG_EDUP_PHYS: spng_errno = 30; 42 | pub const spng_errno_SPNG_EDUP_TIME: spng_errno = 31; 43 | pub const spng_errno_SPNG_EDUP_OFFS: spng_errno = 32; 44 | pub const spng_errno_SPNG_EDUP_EXIF: spng_errno = 33; 45 | pub const spng_errno_SPNG_ECHRM: spng_errno = 34; 46 | pub const spng_errno_SPNG_EPLTE_IDX: spng_errno = 35; 47 | pub const spng_errno_SPNG_ETRNS_COLOR_TYPE: spng_errno = 36; 48 | pub const spng_errno_SPNG_ETRNS_NO_PLTE: spng_errno = 37; 49 | pub const spng_errno_SPNG_EGAMA: spng_errno = 38; 50 | pub const spng_errno_SPNG_EICCP_NAME: spng_errno = 39; 51 | pub const spng_errno_SPNG_EICCP_COMPRESSION_METHOD: spng_errno = 40; 52 | pub const spng_errno_SPNG_ESBIT: spng_errno = 41; 53 | pub const spng_errno_SPNG_ESRGB: spng_errno = 42; 54 | pub const spng_errno_SPNG_ETEXT: spng_errno = 43; 55 | pub const spng_errno_SPNG_ETEXT_KEYWORD: spng_errno = 44; 56 | pub const spng_errno_SPNG_EZTXT: spng_errno = 45; 57 | pub const spng_errno_SPNG_EZTXT_COMPRESSION_METHOD: spng_errno = 46; 58 | pub const spng_errno_SPNG_EITXT: spng_errno = 47; 59 | pub const spng_errno_SPNG_EITXT_COMPRESSION_FLAG: spng_errno = 48; 60 | pub const spng_errno_SPNG_EITXT_COMPRESSION_METHOD: spng_errno = 49; 61 | pub const spng_errno_SPNG_EITXT_LANG_TAG: spng_errno = 50; 62 | pub const spng_errno_SPNG_EITXT_TRANSLATED_KEY: spng_errno = 51; 63 | pub const spng_errno_SPNG_EBKGD_NO_PLTE: spng_errno = 52; 64 | pub const spng_errno_SPNG_EBKGD_PLTE_IDX: spng_errno = 53; 65 | pub const spng_errno_SPNG_EHIST_NO_PLTE: spng_errno = 54; 66 | pub const spng_errno_SPNG_EPHYS: spng_errno = 55; 67 | pub const spng_errno_SPNG_ESPLT_NAME: spng_errno = 56; 68 | pub const spng_errno_SPNG_ESPLT_DUP_NAME: spng_errno = 57; 69 | pub const spng_errno_SPNG_ESPLT_DEPTH: spng_errno = 58; 70 | pub const spng_errno_SPNG_ETIME: spng_errno = 59; 71 | pub const spng_errno_SPNG_EOFFS: spng_errno = 60; 72 | pub const spng_errno_SPNG_EEXIF: spng_errno = 61; 73 | pub const spng_errno_SPNG_EIDAT_TOO_SHORT: spng_errno = 62; 74 | pub const spng_errno_SPNG_EIDAT_STREAM: spng_errno = 63; 75 | pub const spng_errno_SPNG_EZLIB: spng_errno = 64; 76 | pub const spng_errno_SPNG_EFILTER: spng_errno = 65; 77 | pub const spng_errno_SPNG_EBUFSIZ: spng_errno = 66; 78 | pub const spng_errno_SPNG_EIO: spng_errno = 67; 79 | pub const spng_errno_SPNG_EOF: spng_errno = 68; 80 | pub const spng_errno_SPNG_EBUF_SET: spng_errno = 69; 81 | pub const spng_errno_SPNG_EBADSTATE: spng_errno = 70; 82 | pub const spng_errno_SPNG_EFMT: spng_errno = 71; 83 | pub const spng_errno_SPNG_EFLAGS: spng_errno = 72; 84 | pub const spng_errno_SPNG_ECHUNKAVAIL: spng_errno = 73; 85 | pub const spng_errno_SPNG_ENCODE_ONLY: spng_errno = 74; 86 | pub const spng_errno_SPNG_EOI: spng_errno = 75; 87 | pub const spng_errno_SPNG_ENOPLTE: spng_errno = 76; 88 | pub const spng_errno_SPNG_ECHUNK_LIMITS: spng_errno = 77; 89 | pub const spng_errno_SPNG_EZLIB_INIT: spng_errno = 78; 90 | pub const spng_errno_SPNG_ECHUNK_STDLEN: spng_errno = 79; 91 | pub const spng_errno_SPNG_EINTERNAL: spng_errno = 80; 92 | pub const spng_errno_SPNG_ECTXTYPE: spng_errno = 81; 93 | pub const spng_errno_SPNG_ENOSRC: spng_errno = 82; 94 | pub const spng_errno_SPNG_ENODST: spng_errno = 83; 95 | pub const spng_errno_SPNG_EOPSTATE: spng_errno = 84; 96 | pub const spng_errno_SPNG_ENOTFINAL: spng_errno = 85; 97 | pub type spng_errno = libc::c_int; 98 | pub const spng_text_type_SPNG_TEXT: spng_text_type = 1; 99 | pub const spng_text_type_SPNG_ZTXT: spng_text_type = 2; 100 | pub const spng_text_type_SPNG_ITXT: spng_text_type = 3; 101 | pub type spng_text_type = libc::c_uint; 102 | pub const spng_color_type_SPNG_COLOR_TYPE_GRAYSCALE: spng_color_type = 0; 103 | pub const spng_color_type_SPNG_COLOR_TYPE_TRUECOLOR: spng_color_type = 2; 104 | pub const spng_color_type_SPNG_COLOR_TYPE_INDEXED: spng_color_type = 3; 105 | pub const spng_color_type_SPNG_COLOR_TYPE_GRAYSCALE_ALPHA: spng_color_type = 4; 106 | pub const spng_color_type_SPNG_COLOR_TYPE_TRUECOLOR_ALPHA: spng_color_type = 6; 107 | pub type spng_color_type = libc::c_uint; 108 | pub const spng_filter_SPNG_FILTER_NONE: spng_filter = 0; 109 | pub const spng_filter_SPNG_FILTER_SUB: spng_filter = 1; 110 | pub const spng_filter_SPNG_FILTER_UP: spng_filter = 2; 111 | pub const spng_filter_SPNG_FILTER_AVERAGE: spng_filter = 3; 112 | pub const spng_filter_SPNG_FILTER_PAETH: spng_filter = 4; 113 | pub type spng_filter = libc::c_uint; 114 | pub const spng_filter_choice_SPNG_DISABLE_FILTERING: spng_filter_choice = 0; 115 | pub const spng_filter_choice_SPNG_FILTER_CHOICE_NONE: spng_filter_choice = 8; 116 | pub const spng_filter_choice_SPNG_FILTER_CHOICE_SUB: spng_filter_choice = 16; 117 | pub const spng_filter_choice_SPNG_FILTER_CHOICE_UP: spng_filter_choice = 32; 118 | pub const spng_filter_choice_SPNG_FILTER_CHOICE_AVG: spng_filter_choice = 64; 119 | pub const spng_filter_choice_SPNG_FILTER_CHOICE_PAETH: spng_filter_choice = 128; 120 | pub const spng_filter_choice_SPNG_FILTER_CHOICE_ALL: spng_filter_choice = 248; 121 | pub type spng_filter_choice = libc::c_uint; 122 | pub const spng_interlace_method_SPNG_INTERLACE_NONE: spng_interlace_method = 0; 123 | pub const spng_interlace_method_SPNG_INTERLACE_ADAM7: spng_interlace_method = 1; 124 | pub type spng_interlace_method = libc::c_uint; 125 | pub const spng_format_SPNG_FMT_RGBA8: spng_format = 1; 126 | pub const spng_format_SPNG_FMT_RGBA16: spng_format = 2; 127 | pub const spng_format_SPNG_FMT_RGB8: spng_format = 4; 128 | pub const spng_format_SPNG_FMT_GA8: spng_format = 16; 129 | pub const spng_format_SPNG_FMT_GA16: spng_format = 32; 130 | pub const spng_format_SPNG_FMT_G8: spng_format = 64; 131 | pub const spng_format_SPNG_FMT_PNG: spng_format = 256; 132 | pub const spng_format_SPNG_FMT_RAW: spng_format = 512; 133 | pub type spng_format = libc::c_uint; 134 | pub const spng_ctx_flags_SPNG_CTX_IGNORE_ADLER32: spng_ctx_flags = 1; 135 | pub const spng_ctx_flags_SPNG_CTX_ENCODER: spng_ctx_flags = 2; 136 | pub type spng_ctx_flags = libc::c_uint; 137 | pub const spng_decode_flags_SPNG_DECODE_USE_TRNS: spng_decode_flags = 1; 138 | pub const spng_decode_flags_SPNG_DECODE_USE_GAMA: spng_decode_flags = 2; 139 | pub const spng_decode_flags_SPNG_DECODE_USE_SBIT: spng_decode_flags = 8; 140 | pub const spng_decode_flags_SPNG_DECODE_TRNS: spng_decode_flags = 1; 141 | pub const spng_decode_flags_SPNG_DECODE_GAMMA: spng_decode_flags = 2; 142 | pub const spng_decode_flags_SPNG_DECODE_PROGRESSIVE: spng_decode_flags = 256; 143 | pub type spng_decode_flags = libc::c_uint; 144 | pub const spng_crc_action_SPNG_CRC_ERROR: spng_crc_action = 0; 145 | pub const spng_crc_action_SPNG_CRC_DISCARD: spng_crc_action = 1; 146 | pub const spng_crc_action_SPNG_CRC_USE: spng_crc_action = 2; 147 | pub type spng_crc_action = libc::c_uint; 148 | pub const spng_encode_flags_SPNG_ENCODE_PROGRESSIVE: spng_encode_flags = 1; 149 | pub const spng_encode_flags_SPNG_ENCODE_FINALIZE: spng_encode_flags = 2; 150 | pub type spng_encode_flags = libc::c_uint; 151 | #[repr(C)] 152 | #[derive(Debug, Copy, Clone)] 153 | pub struct spng_ihdr { 154 | pub width: u32, 155 | pub height: u32, 156 | pub bit_depth: u8, 157 | pub color_type: u8, 158 | pub compression_method: u8, 159 | pub filter_method: u8, 160 | pub interlace_method: u8, 161 | } 162 | #[test] 163 | fn bindgen_test_layout_spng_ihdr() { 164 | const UNINIT: ::core::mem::MaybeUninit = ::core::mem::MaybeUninit::uninit(); 165 | let ptr = UNINIT.as_ptr(); 166 | assert_eq!( 167 | ::core::mem::size_of::(), 168 | 16usize, 169 | concat!("Size of: ", stringify!(spng_ihdr)) 170 | ); 171 | assert_eq!( 172 | ::core::mem::align_of::(), 173 | 4usize, 174 | concat!("Alignment of ", stringify!(spng_ihdr)) 175 | ); 176 | assert_eq!( 177 | unsafe { ::core::ptr::addr_of!((*ptr).width) as usize - ptr as usize }, 178 | 0usize, 179 | concat!( 180 | "Offset of field: ", 181 | stringify!(spng_ihdr), 182 | "::", 183 | stringify!(width) 184 | ) 185 | ); 186 | assert_eq!( 187 | unsafe { ::core::ptr::addr_of!((*ptr).height) as usize - ptr as usize }, 188 | 4usize, 189 | concat!( 190 | "Offset of field: ", 191 | stringify!(spng_ihdr), 192 | "::", 193 | stringify!(height) 194 | ) 195 | ); 196 | assert_eq!( 197 | unsafe { ::core::ptr::addr_of!((*ptr).bit_depth) as usize - ptr as usize }, 198 | 8usize, 199 | concat!( 200 | "Offset of field: ", 201 | stringify!(spng_ihdr), 202 | "::", 203 | stringify!(bit_depth) 204 | ) 205 | ); 206 | assert_eq!( 207 | unsafe { ::core::ptr::addr_of!((*ptr).color_type) as usize - ptr as usize }, 208 | 9usize, 209 | concat!( 210 | "Offset of field: ", 211 | stringify!(spng_ihdr), 212 | "::", 213 | stringify!(color_type) 214 | ) 215 | ); 216 | assert_eq!( 217 | unsafe { ::core::ptr::addr_of!((*ptr).compression_method) as usize - ptr as usize }, 218 | 10usize, 219 | concat!( 220 | "Offset of field: ", 221 | stringify!(spng_ihdr), 222 | "::", 223 | stringify!(compression_method) 224 | ) 225 | ); 226 | assert_eq!( 227 | unsafe { ::core::ptr::addr_of!((*ptr).filter_method) as usize - ptr as usize }, 228 | 11usize, 229 | concat!( 230 | "Offset of field: ", 231 | stringify!(spng_ihdr), 232 | "::", 233 | stringify!(filter_method) 234 | ) 235 | ); 236 | assert_eq!( 237 | unsafe { ::core::ptr::addr_of!((*ptr).interlace_method) as usize - ptr as usize }, 238 | 12usize, 239 | concat!( 240 | "Offset of field: ", 241 | stringify!(spng_ihdr), 242 | "::", 243 | stringify!(interlace_method) 244 | ) 245 | ); 246 | } 247 | #[repr(C)] 248 | #[derive(Debug, Copy, Clone)] 249 | pub struct spng_plte_entry { 250 | pub red: u8, 251 | pub green: u8, 252 | pub blue: u8, 253 | pub alpha: u8, 254 | } 255 | #[test] 256 | fn bindgen_test_layout_spng_plte_entry() { 257 | const UNINIT: ::core::mem::MaybeUninit = ::core::mem::MaybeUninit::uninit(); 258 | let ptr = UNINIT.as_ptr(); 259 | assert_eq!( 260 | ::core::mem::size_of::(), 261 | 4usize, 262 | concat!("Size of: ", stringify!(spng_plte_entry)) 263 | ); 264 | assert_eq!( 265 | ::core::mem::align_of::(), 266 | 1usize, 267 | concat!("Alignment of ", stringify!(spng_plte_entry)) 268 | ); 269 | assert_eq!( 270 | unsafe { ::core::ptr::addr_of!((*ptr).red) as usize - ptr as usize }, 271 | 0usize, 272 | concat!( 273 | "Offset of field: ", 274 | stringify!(spng_plte_entry), 275 | "::", 276 | stringify!(red) 277 | ) 278 | ); 279 | assert_eq!( 280 | unsafe { ::core::ptr::addr_of!((*ptr).green) as usize - ptr as usize }, 281 | 1usize, 282 | concat!( 283 | "Offset of field: ", 284 | stringify!(spng_plte_entry), 285 | "::", 286 | stringify!(green) 287 | ) 288 | ); 289 | assert_eq!( 290 | unsafe { ::core::ptr::addr_of!((*ptr).blue) as usize - ptr as usize }, 291 | 2usize, 292 | concat!( 293 | "Offset of field: ", 294 | stringify!(spng_plte_entry), 295 | "::", 296 | stringify!(blue) 297 | ) 298 | ); 299 | assert_eq!( 300 | unsafe { ::core::ptr::addr_of!((*ptr).alpha) as usize - ptr as usize }, 301 | 3usize, 302 | concat!( 303 | "Offset of field: ", 304 | stringify!(spng_plte_entry), 305 | "::", 306 | stringify!(alpha) 307 | ) 308 | ); 309 | } 310 | #[repr(C)] 311 | #[derive(Debug, Copy, Clone)] 312 | pub struct spng_plte { 313 | pub n_entries: u32, 314 | pub entries: [spng_plte_entry; 256usize], 315 | } 316 | #[test] 317 | fn bindgen_test_layout_spng_plte() { 318 | const UNINIT: ::core::mem::MaybeUninit = ::core::mem::MaybeUninit::uninit(); 319 | let ptr = UNINIT.as_ptr(); 320 | assert_eq!( 321 | ::core::mem::size_of::(), 322 | 1028usize, 323 | concat!("Size of: ", stringify!(spng_plte)) 324 | ); 325 | assert_eq!( 326 | ::core::mem::align_of::(), 327 | 4usize, 328 | concat!("Alignment of ", stringify!(spng_plte)) 329 | ); 330 | assert_eq!( 331 | unsafe { ::core::ptr::addr_of!((*ptr).n_entries) as usize - ptr as usize }, 332 | 0usize, 333 | concat!( 334 | "Offset of field: ", 335 | stringify!(spng_plte), 336 | "::", 337 | stringify!(n_entries) 338 | ) 339 | ); 340 | assert_eq!( 341 | unsafe { ::core::ptr::addr_of!((*ptr).entries) as usize - ptr as usize }, 342 | 4usize, 343 | concat!( 344 | "Offset of field: ", 345 | stringify!(spng_plte), 346 | "::", 347 | stringify!(entries) 348 | ) 349 | ); 350 | } 351 | #[repr(C)] 352 | #[derive(Debug, Copy, Clone)] 353 | pub struct spng_trns { 354 | pub gray: u16, 355 | pub red: u16, 356 | pub green: u16, 357 | pub blue: u16, 358 | pub n_type3_entries: u32, 359 | pub type3_alpha: [u8; 256usize], 360 | } 361 | #[test] 362 | fn bindgen_test_layout_spng_trns() { 363 | const UNINIT: ::core::mem::MaybeUninit = ::core::mem::MaybeUninit::uninit(); 364 | let ptr = UNINIT.as_ptr(); 365 | assert_eq!( 366 | ::core::mem::size_of::(), 367 | 268usize, 368 | concat!("Size of: ", stringify!(spng_trns)) 369 | ); 370 | assert_eq!( 371 | ::core::mem::align_of::(), 372 | 4usize, 373 | concat!("Alignment of ", stringify!(spng_trns)) 374 | ); 375 | assert_eq!( 376 | unsafe { ::core::ptr::addr_of!((*ptr).gray) as usize - ptr as usize }, 377 | 0usize, 378 | concat!( 379 | "Offset of field: ", 380 | stringify!(spng_trns), 381 | "::", 382 | stringify!(gray) 383 | ) 384 | ); 385 | assert_eq!( 386 | unsafe { ::core::ptr::addr_of!((*ptr).red) as usize - ptr as usize }, 387 | 2usize, 388 | concat!( 389 | "Offset of field: ", 390 | stringify!(spng_trns), 391 | "::", 392 | stringify!(red) 393 | ) 394 | ); 395 | assert_eq!( 396 | unsafe { ::core::ptr::addr_of!((*ptr).green) as usize - ptr as usize }, 397 | 4usize, 398 | concat!( 399 | "Offset of field: ", 400 | stringify!(spng_trns), 401 | "::", 402 | stringify!(green) 403 | ) 404 | ); 405 | assert_eq!( 406 | unsafe { ::core::ptr::addr_of!((*ptr).blue) as usize - ptr as usize }, 407 | 6usize, 408 | concat!( 409 | "Offset of field: ", 410 | stringify!(spng_trns), 411 | "::", 412 | stringify!(blue) 413 | ) 414 | ); 415 | assert_eq!( 416 | unsafe { ::core::ptr::addr_of!((*ptr).n_type3_entries) as usize - ptr as usize }, 417 | 8usize, 418 | concat!( 419 | "Offset of field: ", 420 | stringify!(spng_trns), 421 | "::", 422 | stringify!(n_type3_entries) 423 | ) 424 | ); 425 | assert_eq!( 426 | unsafe { ::core::ptr::addr_of!((*ptr).type3_alpha) as usize - ptr as usize }, 427 | 12usize, 428 | concat!( 429 | "Offset of field: ", 430 | stringify!(spng_trns), 431 | "::", 432 | stringify!(type3_alpha) 433 | ) 434 | ); 435 | } 436 | #[repr(C)] 437 | #[derive(Debug, Copy, Clone)] 438 | pub struct spng_chrm_int { 439 | pub white_point_x: u32, 440 | pub white_point_y: u32, 441 | pub red_x: u32, 442 | pub red_y: u32, 443 | pub green_x: u32, 444 | pub green_y: u32, 445 | pub blue_x: u32, 446 | pub blue_y: u32, 447 | } 448 | #[test] 449 | fn bindgen_test_layout_spng_chrm_int() { 450 | const UNINIT: ::core::mem::MaybeUninit = ::core::mem::MaybeUninit::uninit(); 451 | let ptr = UNINIT.as_ptr(); 452 | assert_eq!( 453 | ::core::mem::size_of::(), 454 | 32usize, 455 | concat!("Size of: ", stringify!(spng_chrm_int)) 456 | ); 457 | assert_eq!( 458 | ::core::mem::align_of::(), 459 | 4usize, 460 | concat!("Alignment of ", stringify!(spng_chrm_int)) 461 | ); 462 | assert_eq!( 463 | unsafe { ::core::ptr::addr_of!((*ptr).white_point_x) as usize - ptr as usize }, 464 | 0usize, 465 | concat!( 466 | "Offset of field: ", 467 | stringify!(spng_chrm_int), 468 | "::", 469 | stringify!(white_point_x) 470 | ) 471 | ); 472 | assert_eq!( 473 | unsafe { ::core::ptr::addr_of!((*ptr).white_point_y) as usize - ptr as usize }, 474 | 4usize, 475 | concat!( 476 | "Offset of field: ", 477 | stringify!(spng_chrm_int), 478 | "::", 479 | stringify!(white_point_y) 480 | ) 481 | ); 482 | assert_eq!( 483 | unsafe { ::core::ptr::addr_of!((*ptr).red_x) as usize - ptr as usize }, 484 | 8usize, 485 | concat!( 486 | "Offset of field: ", 487 | stringify!(spng_chrm_int), 488 | "::", 489 | stringify!(red_x) 490 | ) 491 | ); 492 | assert_eq!( 493 | unsafe { ::core::ptr::addr_of!((*ptr).red_y) as usize - ptr as usize }, 494 | 12usize, 495 | concat!( 496 | "Offset of field: ", 497 | stringify!(spng_chrm_int), 498 | "::", 499 | stringify!(red_y) 500 | ) 501 | ); 502 | assert_eq!( 503 | unsafe { ::core::ptr::addr_of!((*ptr).green_x) as usize - ptr as usize }, 504 | 16usize, 505 | concat!( 506 | "Offset of field: ", 507 | stringify!(spng_chrm_int), 508 | "::", 509 | stringify!(green_x) 510 | ) 511 | ); 512 | assert_eq!( 513 | unsafe { ::core::ptr::addr_of!((*ptr).green_y) as usize - ptr as usize }, 514 | 20usize, 515 | concat!( 516 | "Offset of field: ", 517 | stringify!(spng_chrm_int), 518 | "::", 519 | stringify!(green_y) 520 | ) 521 | ); 522 | assert_eq!( 523 | unsafe { ::core::ptr::addr_of!((*ptr).blue_x) as usize - ptr as usize }, 524 | 24usize, 525 | concat!( 526 | "Offset of field: ", 527 | stringify!(spng_chrm_int), 528 | "::", 529 | stringify!(blue_x) 530 | ) 531 | ); 532 | assert_eq!( 533 | unsafe { ::core::ptr::addr_of!((*ptr).blue_y) as usize - ptr as usize }, 534 | 28usize, 535 | concat!( 536 | "Offset of field: ", 537 | stringify!(spng_chrm_int), 538 | "::", 539 | stringify!(blue_y) 540 | ) 541 | ); 542 | } 543 | #[repr(C)] 544 | #[derive(Debug, Copy, Clone)] 545 | pub struct spng_chrm { 546 | pub white_point_x: f64, 547 | pub white_point_y: f64, 548 | pub red_x: f64, 549 | pub red_y: f64, 550 | pub green_x: f64, 551 | pub green_y: f64, 552 | pub blue_x: f64, 553 | pub blue_y: f64, 554 | } 555 | #[test] 556 | fn bindgen_test_layout_spng_chrm() { 557 | const UNINIT: ::core::mem::MaybeUninit = ::core::mem::MaybeUninit::uninit(); 558 | let ptr = UNINIT.as_ptr(); 559 | assert_eq!( 560 | ::core::mem::size_of::(), 561 | 64usize, 562 | concat!("Size of: ", stringify!(spng_chrm)) 563 | ); 564 | assert_eq!( 565 | ::core::mem::align_of::(), 566 | 8usize, 567 | concat!("Alignment of ", stringify!(spng_chrm)) 568 | ); 569 | assert_eq!( 570 | unsafe { ::core::ptr::addr_of!((*ptr).white_point_x) as usize - ptr as usize }, 571 | 0usize, 572 | concat!( 573 | "Offset of field: ", 574 | stringify!(spng_chrm), 575 | "::", 576 | stringify!(white_point_x) 577 | ) 578 | ); 579 | assert_eq!( 580 | unsafe { ::core::ptr::addr_of!((*ptr).white_point_y) as usize - ptr as usize }, 581 | 8usize, 582 | concat!( 583 | "Offset of field: ", 584 | stringify!(spng_chrm), 585 | "::", 586 | stringify!(white_point_y) 587 | ) 588 | ); 589 | assert_eq!( 590 | unsafe { ::core::ptr::addr_of!((*ptr).red_x) as usize - ptr as usize }, 591 | 16usize, 592 | concat!( 593 | "Offset of field: ", 594 | stringify!(spng_chrm), 595 | "::", 596 | stringify!(red_x) 597 | ) 598 | ); 599 | assert_eq!( 600 | unsafe { ::core::ptr::addr_of!((*ptr).red_y) as usize - ptr as usize }, 601 | 24usize, 602 | concat!( 603 | "Offset of field: ", 604 | stringify!(spng_chrm), 605 | "::", 606 | stringify!(red_y) 607 | ) 608 | ); 609 | assert_eq!( 610 | unsafe { ::core::ptr::addr_of!((*ptr).green_x) as usize - ptr as usize }, 611 | 32usize, 612 | concat!( 613 | "Offset of field: ", 614 | stringify!(spng_chrm), 615 | "::", 616 | stringify!(green_x) 617 | ) 618 | ); 619 | assert_eq!( 620 | unsafe { ::core::ptr::addr_of!((*ptr).green_y) as usize - ptr as usize }, 621 | 40usize, 622 | concat!( 623 | "Offset of field: ", 624 | stringify!(spng_chrm), 625 | "::", 626 | stringify!(green_y) 627 | ) 628 | ); 629 | assert_eq!( 630 | unsafe { ::core::ptr::addr_of!((*ptr).blue_x) as usize - ptr as usize }, 631 | 48usize, 632 | concat!( 633 | "Offset of field: ", 634 | stringify!(spng_chrm), 635 | "::", 636 | stringify!(blue_x) 637 | ) 638 | ); 639 | assert_eq!( 640 | unsafe { ::core::ptr::addr_of!((*ptr).blue_y) as usize - ptr as usize }, 641 | 56usize, 642 | concat!( 643 | "Offset of field: ", 644 | stringify!(spng_chrm), 645 | "::", 646 | stringify!(blue_y) 647 | ) 648 | ); 649 | } 650 | #[repr(C)] 651 | #[derive(Debug, Copy, Clone)] 652 | pub struct spng_iccp { 653 | pub profile_name: [libc::c_char; 80usize], 654 | pub profile_len: usize, 655 | pub profile: *mut libc::c_char, 656 | } 657 | #[test] 658 | fn bindgen_test_layout_spng_iccp() { 659 | const UNINIT: ::core::mem::MaybeUninit = ::core::mem::MaybeUninit::uninit(); 660 | let ptr = UNINIT.as_ptr(); 661 | assert_eq!( 662 | ::core::mem::size_of::(), 663 | 96usize, 664 | concat!("Size of: ", stringify!(spng_iccp)) 665 | ); 666 | assert_eq!( 667 | ::core::mem::align_of::(), 668 | 8usize, 669 | concat!("Alignment of ", stringify!(spng_iccp)) 670 | ); 671 | assert_eq!( 672 | unsafe { ::core::ptr::addr_of!((*ptr).profile_name) as usize - ptr as usize }, 673 | 0usize, 674 | concat!( 675 | "Offset of field: ", 676 | stringify!(spng_iccp), 677 | "::", 678 | stringify!(profile_name) 679 | ) 680 | ); 681 | assert_eq!( 682 | unsafe { ::core::ptr::addr_of!((*ptr).profile_len) as usize - ptr as usize }, 683 | 80usize, 684 | concat!( 685 | "Offset of field: ", 686 | stringify!(spng_iccp), 687 | "::", 688 | stringify!(profile_len) 689 | ) 690 | ); 691 | assert_eq!( 692 | unsafe { ::core::ptr::addr_of!((*ptr).profile) as usize - ptr as usize }, 693 | 88usize, 694 | concat!( 695 | "Offset of field: ", 696 | stringify!(spng_iccp), 697 | "::", 698 | stringify!(profile) 699 | ) 700 | ); 701 | } 702 | #[repr(C)] 703 | #[derive(Debug, Copy, Clone)] 704 | pub struct spng_sbit { 705 | pub grayscale_bits: u8, 706 | pub red_bits: u8, 707 | pub green_bits: u8, 708 | pub blue_bits: u8, 709 | pub alpha_bits: u8, 710 | } 711 | #[test] 712 | fn bindgen_test_layout_spng_sbit() { 713 | const UNINIT: ::core::mem::MaybeUninit = ::core::mem::MaybeUninit::uninit(); 714 | let ptr = UNINIT.as_ptr(); 715 | assert_eq!( 716 | ::core::mem::size_of::(), 717 | 5usize, 718 | concat!("Size of: ", stringify!(spng_sbit)) 719 | ); 720 | assert_eq!( 721 | ::core::mem::align_of::(), 722 | 1usize, 723 | concat!("Alignment of ", stringify!(spng_sbit)) 724 | ); 725 | assert_eq!( 726 | unsafe { ::core::ptr::addr_of!((*ptr).grayscale_bits) as usize - ptr as usize }, 727 | 0usize, 728 | concat!( 729 | "Offset of field: ", 730 | stringify!(spng_sbit), 731 | "::", 732 | stringify!(grayscale_bits) 733 | ) 734 | ); 735 | assert_eq!( 736 | unsafe { ::core::ptr::addr_of!((*ptr).red_bits) as usize - ptr as usize }, 737 | 1usize, 738 | concat!( 739 | "Offset of field: ", 740 | stringify!(spng_sbit), 741 | "::", 742 | stringify!(red_bits) 743 | ) 744 | ); 745 | assert_eq!( 746 | unsafe { ::core::ptr::addr_of!((*ptr).green_bits) as usize - ptr as usize }, 747 | 2usize, 748 | concat!( 749 | "Offset of field: ", 750 | stringify!(spng_sbit), 751 | "::", 752 | stringify!(green_bits) 753 | ) 754 | ); 755 | assert_eq!( 756 | unsafe { ::core::ptr::addr_of!((*ptr).blue_bits) as usize - ptr as usize }, 757 | 3usize, 758 | concat!( 759 | "Offset of field: ", 760 | stringify!(spng_sbit), 761 | "::", 762 | stringify!(blue_bits) 763 | ) 764 | ); 765 | assert_eq!( 766 | unsafe { ::core::ptr::addr_of!((*ptr).alpha_bits) as usize - ptr as usize }, 767 | 4usize, 768 | concat!( 769 | "Offset of field: ", 770 | stringify!(spng_sbit), 771 | "::", 772 | stringify!(alpha_bits) 773 | ) 774 | ); 775 | } 776 | #[repr(C)] 777 | #[derive(Debug, Copy, Clone)] 778 | pub struct spng_text { 779 | pub keyword: [libc::c_char; 80usize], 780 | pub type_: libc::c_int, 781 | pub length: usize, 782 | pub text: *mut libc::c_char, 783 | pub compression_flag: u8, 784 | pub compression_method: u8, 785 | pub language_tag: *mut libc::c_char, 786 | pub translated_keyword: *mut libc::c_char, 787 | } 788 | #[test] 789 | fn bindgen_test_layout_spng_text() { 790 | const UNINIT: ::core::mem::MaybeUninit = ::core::mem::MaybeUninit::uninit(); 791 | let ptr = UNINIT.as_ptr(); 792 | assert_eq!( 793 | ::core::mem::size_of::(), 794 | 128usize, 795 | concat!("Size of: ", stringify!(spng_text)) 796 | ); 797 | assert_eq!( 798 | ::core::mem::align_of::(), 799 | 8usize, 800 | concat!("Alignment of ", stringify!(spng_text)) 801 | ); 802 | assert_eq!( 803 | unsafe { ::core::ptr::addr_of!((*ptr).keyword) as usize - ptr as usize }, 804 | 0usize, 805 | concat!( 806 | "Offset of field: ", 807 | stringify!(spng_text), 808 | "::", 809 | stringify!(keyword) 810 | ) 811 | ); 812 | assert_eq!( 813 | unsafe { ::core::ptr::addr_of!((*ptr).type_) as usize - ptr as usize }, 814 | 80usize, 815 | concat!( 816 | "Offset of field: ", 817 | stringify!(spng_text), 818 | "::", 819 | stringify!(type_) 820 | ) 821 | ); 822 | assert_eq!( 823 | unsafe { ::core::ptr::addr_of!((*ptr).length) as usize - ptr as usize }, 824 | 88usize, 825 | concat!( 826 | "Offset of field: ", 827 | stringify!(spng_text), 828 | "::", 829 | stringify!(length) 830 | ) 831 | ); 832 | assert_eq!( 833 | unsafe { ::core::ptr::addr_of!((*ptr).text) as usize - ptr as usize }, 834 | 96usize, 835 | concat!( 836 | "Offset of field: ", 837 | stringify!(spng_text), 838 | "::", 839 | stringify!(text) 840 | ) 841 | ); 842 | assert_eq!( 843 | unsafe { ::core::ptr::addr_of!((*ptr).compression_flag) as usize - ptr as usize }, 844 | 104usize, 845 | concat!( 846 | "Offset of field: ", 847 | stringify!(spng_text), 848 | "::", 849 | stringify!(compression_flag) 850 | ) 851 | ); 852 | assert_eq!( 853 | unsafe { ::core::ptr::addr_of!((*ptr).compression_method) as usize - ptr as usize }, 854 | 105usize, 855 | concat!( 856 | "Offset of field: ", 857 | stringify!(spng_text), 858 | "::", 859 | stringify!(compression_method) 860 | ) 861 | ); 862 | assert_eq!( 863 | unsafe { ::core::ptr::addr_of!((*ptr).language_tag) as usize - ptr as usize }, 864 | 112usize, 865 | concat!( 866 | "Offset of field: ", 867 | stringify!(spng_text), 868 | "::", 869 | stringify!(language_tag) 870 | ) 871 | ); 872 | assert_eq!( 873 | unsafe { ::core::ptr::addr_of!((*ptr).translated_keyword) as usize - ptr as usize }, 874 | 120usize, 875 | concat!( 876 | "Offset of field: ", 877 | stringify!(spng_text), 878 | "::", 879 | stringify!(translated_keyword) 880 | ) 881 | ); 882 | } 883 | #[repr(C)] 884 | #[derive(Debug, Copy, Clone)] 885 | pub struct spng_bkgd { 886 | pub gray: u16, 887 | pub red: u16, 888 | pub green: u16, 889 | pub blue: u16, 890 | pub plte_index: u16, 891 | } 892 | #[test] 893 | fn bindgen_test_layout_spng_bkgd() { 894 | const UNINIT: ::core::mem::MaybeUninit = ::core::mem::MaybeUninit::uninit(); 895 | let ptr = UNINIT.as_ptr(); 896 | assert_eq!( 897 | ::core::mem::size_of::(), 898 | 10usize, 899 | concat!("Size of: ", stringify!(spng_bkgd)) 900 | ); 901 | assert_eq!( 902 | ::core::mem::align_of::(), 903 | 2usize, 904 | concat!("Alignment of ", stringify!(spng_bkgd)) 905 | ); 906 | assert_eq!( 907 | unsafe { ::core::ptr::addr_of!((*ptr).gray) as usize - ptr as usize }, 908 | 0usize, 909 | concat!( 910 | "Offset of field: ", 911 | stringify!(spng_bkgd), 912 | "::", 913 | stringify!(gray) 914 | ) 915 | ); 916 | assert_eq!( 917 | unsafe { ::core::ptr::addr_of!((*ptr).red) as usize - ptr as usize }, 918 | 2usize, 919 | concat!( 920 | "Offset of field: ", 921 | stringify!(spng_bkgd), 922 | "::", 923 | stringify!(red) 924 | ) 925 | ); 926 | assert_eq!( 927 | unsafe { ::core::ptr::addr_of!((*ptr).green) as usize - ptr as usize }, 928 | 4usize, 929 | concat!( 930 | "Offset of field: ", 931 | stringify!(spng_bkgd), 932 | "::", 933 | stringify!(green) 934 | ) 935 | ); 936 | assert_eq!( 937 | unsafe { ::core::ptr::addr_of!((*ptr).blue) as usize - ptr as usize }, 938 | 6usize, 939 | concat!( 940 | "Offset of field: ", 941 | stringify!(spng_bkgd), 942 | "::", 943 | stringify!(blue) 944 | ) 945 | ); 946 | assert_eq!( 947 | unsafe { ::core::ptr::addr_of!((*ptr).plte_index) as usize - ptr as usize }, 948 | 8usize, 949 | concat!( 950 | "Offset of field: ", 951 | stringify!(spng_bkgd), 952 | "::", 953 | stringify!(plte_index) 954 | ) 955 | ); 956 | } 957 | #[repr(C)] 958 | #[derive(Debug, Copy, Clone)] 959 | pub struct spng_hist { 960 | pub frequency: [u16; 256usize], 961 | } 962 | #[test] 963 | fn bindgen_test_layout_spng_hist() { 964 | const UNINIT: ::core::mem::MaybeUninit = ::core::mem::MaybeUninit::uninit(); 965 | let ptr = UNINIT.as_ptr(); 966 | assert_eq!( 967 | ::core::mem::size_of::(), 968 | 512usize, 969 | concat!("Size of: ", stringify!(spng_hist)) 970 | ); 971 | assert_eq!( 972 | ::core::mem::align_of::(), 973 | 2usize, 974 | concat!("Alignment of ", stringify!(spng_hist)) 975 | ); 976 | assert_eq!( 977 | unsafe { ::core::ptr::addr_of!((*ptr).frequency) as usize - ptr as usize }, 978 | 0usize, 979 | concat!( 980 | "Offset of field: ", 981 | stringify!(spng_hist), 982 | "::", 983 | stringify!(frequency) 984 | ) 985 | ); 986 | } 987 | #[repr(C)] 988 | #[derive(Debug, Copy, Clone)] 989 | pub struct spng_phys { 990 | pub ppu_x: u32, 991 | pub ppu_y: u32, 992 | pub unit_specifier: u8, 993 | } 994 | #[test] 995 | fn bindgen_test_layout_spng_phys() { 996 | const UNINIT: ::core::mem::MaybeUninit = ::core::mem::MaybeUninit::uninit(); 997 | let ptr = UNINIT.as_ptr(); 998 | assert_eq!( 999 | ::core::mem::size_of::(), 1000 | 12usize, 1001 | concat!("Size of: ", stringify!(spng_phys)) 1002 | ); 1003 | assert_eq!( 1004 | ::core::mem::align_of::(), 1005 | 4usize, 1006 | concat!("Alignment of ", stringify!(spng_phys)) 1007 | ); 1008 | assert_eq!( 1009 | unsafe { ::core::ptr::addr_of!((*ptr).ppu_x) as usize - ptr as usize }, 1010 | 0usize, 1011 | concat!( 1012 | "Offset of field: ", 1013 | stringify!(spng_phys), 1014 | "::", 1015 | stringify!(ppu_x) 1016 | ) 1017 | ); 1018 | assert_eq!( 1019 | unsafe { ::core::ptr::addr_of!((*ptr).ppu_y) as usize - ptr as usize }, 1020 | 4usize, 1021 | concat!( 1022 | "Offset of field: ", 1023 | stringify!(spng_phys), 1024 | "::", 1025 | stringify!(ppu_y) 1026 | ) 1027 | ); 1028 | assert_eq!( 1029 | unsafe { ::core::ptr::addr_of!((*ptr).unit_specifier) as usize - ptr as usize }, 1030 | 8usize, 1031 | concat!( 1032 | "Offset of field: ", 1033 | stringify!(spng_phys), 1034 | "::", 1035 | stringify!(unit_specifier) 1036 | ) 1037 | ); 1038 | } 1039 | #[repr(C)] 1040 | #[derive(Debug, Copy, Clone)] 1041 | pub struct spng_splt_entry { 1042 | pub red: u16, 1043 | pub green: u16, 1044 | pub blue: u16, 1045 | pub alpha: u16, 1046 | pub frequency: u16, 1047 | } 1048 | #[test] 1049 | fn bindgen_test_layout_spng_splt_entry() { 1050 | const UNINIT: ::core::mem::MaybeUninit = ::core::mem::MaybeUninit::uninit(); 1051 | let ptr = UNINIT.as_ptr(); 1052 | assert_eq!( 1053 | ::core::mem::size_of::(), 1054 | 10usize, 1055 | concat!("Size of: ", stringify!(spng_splt_entry)) 1056 | ); 1057 | assert_eq!( 1058 | ::core::mem::align_of::(), 1059 | 2usize, 1060 | concat!("Alignment of ", stringify!(spng_splt_entry)) 1061 | ); 1062 | assert_eq!( 1063 | unsafe { ::core::ptr::addr_of!((*ptr).red) as usize - ptr as usize }, 1064 | 0usize, 1065 | concat!( 1066 | "Offset of field: ", 1067 | stringify!(spng_splt_entry), 1068 | "::", 1069 | stringify!(red) 1070 | ) 1071 | ); 1072 | assert_eq!( 1073 | unsafe { ::core::ptr::addr_of!((*ptr).green) as usize - ptr as usize }, 1074 | 2usize, 1075 | concat!( 1076 | "Offset of field: ", 1077 | stringify!(spng_splt_entry), 1078 | "::", 1079 | stringify!(green) 1080 | ) 1081 | ); 1082 | assert_eq!( 1083 | unsafe { ::core::ptr::addr_of!((*ptr).blue) as usize - ptr as usize }, 1084 | 4usize, 1085 | concat!( 1086 | "Offset of field: ", 1087 | stringify!(spng_splt_entry), 1088 | "::", 1089 | stringify!(blue) 1090 | ) 1091 | ); 1092 | assert_eq!( 1093 | unsafe { ::core::ptr::addr_of!((*ptr).alpha) as usize - ptr as usize }, 1094 | 6usize, 1095 | concat!( 1096 | "Offset of field: ", 1097 | stringify!(spng_splt_entry), 1098 | "::", 1099 | stringify!(alpha) 1100 | ) 1101 | ); 1102 | assert_eq!( 1103 | unsafe { ::core::ptr::addr_of!((*ptr).frequency) as usize - ptr as usize }, 1104 | 8usize, 1105 | concat!( 1106 | "Offset of field: ", 1107 | stringify!(spng_splt_entry), 1108 | "::", 1109 | stringify!(frequency) 1110 | ) 1111 | ); 1112 | } 1113 | #[repr(C)] 1114 | #[derive(Debug, Copy, Clone)] 1115 | pub struct spng_splt { 1116 | pub name: [libc::c_char; 80usize], 1117 | pub sample_depth: u8, 1118 | pub n_entries: u32, 1119 | pub entries: *mut spng_splt_entry, 1120 | } 1121 | #[test] 1122 | fn bindgen_test_layout_spng_splt() { 1123 | const UNINIT: ::core::mem::MaybeUninit = ::core::mem::MaybeUninit::uninit(); 1124 | let ptr = UNINIT.as_ptr(); 1125 | assert_eq!( 1126 | ::core::mem::size_of::(), 1127 | 96usize, 1128 | concat!("Size of: ", stringify!(spng_splt)) 1129 | ); 1130 | assert_eq!( 1131 | ::core::mem::align_of::(), 1132 | 8usize, 1133 | concat!("Alignment of ", stringify!(spng_splt)) 1134 | ); 1135 | assert_eq!( 1136 | unsafe { ::core::ptr::addr_of!((*ptr).name) as usize - ptr as usize }, 1137 | 0usize, 1138 | concat!( 1139 | "Offset of field: ", 1140 | stringify!(spng_splt), 1141 | "::", 1142 | stringify!(name) 1143 | ) 1144 | ); 1145 | assert_eq!( 1146 | unsafe { ::core::ptr::addr_of!((*ptr).sample_depth) as usize - ptr as usize }, 1147 | 80usize, 1148 | concat!( 1149 | "Offset of field: ", 1150 | stringify!(spng_splt), 1151 | "::", 1152 | stringify!(sample_depth) 1153 | ) 1154 | ); 1155 | assert_eq!( 1156 | unsafe { ::core::ptr::addr_of!((*ptr).n_entries) as usize - ptr as usize }, 1157 | 84usize, 1158 | concat!( 1159 | "Offset of field: ", 1160 | stringify!(spng_splt), 1161 | "::", 1162 | stringify!(n_entries) 1163 | ) 1164 | ); 1165 | assert_eq!( 1166 | unsafe { ::core::ptr::addr_of!((*ptr).entries) as usize - ptr as usize }, 1167 | 88usize, 1168 | concat!( 1169 | "Offset of field: ", 1170 | stringify!(spng_splt), 1171 | "::", 1172 | stringify!(entries) 1173 | ) 1174 | ); 1175 | } 1176 | #[repr(C)] 1177 | #[derive(Debug, Copy, Clone)] 1178 | pub struct spng_time { 1179 | pub year: u16, 1180 | pub month: u8, 1181 | pub day: u8, 1182 | pub hour: u8, 1183 | pub minute: u8, 1184 | pub second: u8, 1185 | } 1186 | #[test] 1187 | fn bindgen_test_layout_spng_time() { 1188 | const UNINIT: ::core::mem::MaybeUninit = ::core::mem::MaybeUninit::uninit(); 1189 | let ptr = UNINIT.as_ptr(); 1190 | assert_eq!( 1191 | ::core::mem::size_of::(), 1192 | 8usize, 1193 | concat!("Size of: ", stringify!(spng_time)) 1194 | ); 1195 | assert_eq!( 1196 | ::core::mem::align_of::(), 1197 | 2usize, 1198 | concat!("Alignment of ", stringify!(spng_time)) 1199 | ); 1200 | assert_eq!( 1201 | unsafe { ::core::ptr::addr_of!((*ptr).year) as usize - ptr as usize }, 1202 | 0usize, 1203 | concat!( 1204 | "Offset of field: ", 1205 | stringify!(spng_time), 1206 | "::", 1207 | stringify!(year) 1208 | ) 1209 | ); 1210 | assert_eq!( 1211 | unsafe { ::core::ptr::addr_of!((*ptr).month) as usize - ptr as usize }, 1212 | 2usize, 1213 | concat!( 1214 | "Offset of field: ", 1215 | stringify!(spng_time), 1216 | "::", 1217 | stringify!(month) 1218 | ) 1219 | ); 1220 | assert_eq!( 1221 | unsafe { ::core::ptr::addr_of!((*ptr).day) as usize - ptr as usize }, 1222 | 3usize, 1223 | concat!( 1224 | "Offset of field: ", 1225 | stringify!(spng_time), 1226 | "::", 1227 | stringify!(day) 1228 | ) 1229 | ); 1230 | assert_eq!( 1231 | unsafe { ::core::ptr::addr_of!((*ptr).hour) as usize - ptr as usize }, 1232 | 4usize, 1233 | concat!( 1234 | "Offset of field: ", 1235 | stringify!(spng_time), 1236 | "::", 1237 | stringify!(hour) 1238 | ) 1239 | ); 1240 | assert_eq!( 1241 | unsafe { ::core::ptr::addr_of!((*ptr).minute) as usize - ptr as usize }, 1242 | 5usize, 1243 | concat!( 1244 | "Offset of field: ", 1245 | stringify!(spng_time), 1246 | "::", 1247 | stringify!(minute) 1248 | ) 1249 | ); 1250 | assert_eq!( 1251 | unsafe { ::core::ptr::addr_of!((*ptr).second) as usize - ptr as usize }, 1252 | 6usize, 1253 | concat!( 1254 | "Offset of field: ", 1255 | stringify!(spng_time), 1256 | "::", 1257 | stringify!(second) 1258 | ) 1259 | ); 1260 | } 1261 | #[repr(C)] 1262 | #[derive(Debug, Copy, Clone)] 1263 | pub struct spng_offs { 1264 | pub x: i32, 1265 | pub y: i32, 1266 | pub unit_specifier: u8, 1267 | } 1268 | #[test] 1269 | fn bindgen_test_layout_spng_offs() { 1270 | const UNINIT: ::core::mem::MaybeUninit = ::core::mem::MaybeUninit::uninit(); 1271 | let ptr = UNINIT.as_ptr(); 1272 | assert_eq!( 1273 | ::core::mem::size_of::(), 1274 | 12usize, 1275 | concat!("Size of: ", stringify!(spng_offs)) 1276 | ); 1277 | assert_eq!( 1278 | ::core::mem::align_of::(), 1279 | 4usize, 1280 | concat!("Alignment of ", stringify!(spng_offs)) 1281 | ); 1282 | assert_eq!( 1283 | unsafe { ::core::ptr::addr_of!((*ptr).x) as usize - ptr as usize }, 1284 | 0usize, 1285 | concat!( 1286 | "Offset of field: ", 1287 | stringify!(spng_offs), 1288 | "::", 1289 | stringify!(x) 1290 | ) 1291 | ); 1292 | assert_eq!( 1293 | unsafe { ::core::ptr::addr_of!((*ptr).y) as usize - ptr as usize }, 1294 | 4usize, 1295 | concat!( 1296 | "Offset of field: ", 1297 | stringify!(spng_offs), 1298 | "::", 1299 | stringify!(y) 1300 | ) 1301 | ); 1302 | assert_eq!( 1303 | unsafe { ::core::ptr::addr_of!((*ptr).unit_specifier) as usize - ptr as usize }, 1304 | 8usize, 1305 | concat!( 1306 | "Offset of field: ", 1307 | stringify!(spng_offs), 1308 | "::", 1309 | stringify!(unit_specifier) 1310 | ) 1311 | ); 1312 | } 1313 | #[repr(C)] 1314 | #[derive(Debug, Copy, Clone)] 1315 | pub struct spng_exif { 1316 | pub length: usize, 1317 | pub data: *mut libc::c_char, 1318 | } 1319 | #[test] 1320 | fn bindgen_test_layout_spng_exif() { 1321 | const UNINIT: ::core::mem::MaybeUninit = ::core::mem::MaybeUninit::uninit(); 1322 | let ptr = UNINIT.as_ptr(); 1323 | assert_eq!( 1324 | ::core::mem::size_of::(), 1325 | 16usize, 1326 | concat!("Size of: ", stringify!(spng_exif)) 1327 | ); 1328 | assert_eq!( 1329 | ::core::mem::align_of::(), 1330 | 8usize, 1331 | concat!("Alignment of ", stringify!(spng_exif)) 1332 | ); 1333 | assert_eq!( 1334 | unsafe { ::core::ptr::addr_of!((*ptr).length) as usize - ptr as usize }, 1335 | 0usize, 1336 | concat!( 1337 | "Offset of field: ", 1338 | stringify!(spng_exif), 1339 | "::", 1340 | stringify!(length) 1341 | ) 1342 | ); 1343 | assert_eq!( 1344 | unsafe { ::core::ptr::addr_of!((*ptr).data) as usize - ptr as usize }, 1345 | 8usize, 1346 | concat!( 1347 | "Offset of field: ", 1348 | stringify!(spng_exif), 1349 | "::", 1350 | stringify!(data) 1351 | ) 1352 | ); 1353 | } 1354 | #[repr(C)] 1355 | #[derive(Debug, Copy, Clone)] 1356 | pub struct spng_chunk { 1357 | pub offset: usize, 1358 | pub length: u32, 1359 | pub type_: [u8; 4usize], 1360 | pub crc: u32, 1361 | } 1362 | #[test] 1363 | fn bindgen_test_layout_spng_chunk() { 1364 | const UNINIT: ::core::mem::MaybeUninit = ::core::mem::MaybeUninit::uninit(); 1365 | let ptr = UNINIT.as_ptr(); 1366 | assert_eq!( 1367 | ::core::mem::size_of::(), 1368 | 24usize, 1369 | concat!("Size of: ", stringify!(spng_chunk)) 1370 | ); 1371 | assert_eq!( 1372 | ::core::mem::align_of::(), 1373 | 8usize, 1374 | concat!("Alignment of ", stringify!(spng_chunk)) 1375 | ); 1376 | assert_eq!( 1377 | unsafe { ::core::ptr::addr_of!((*ptr).offset) as usize - ptr as usize }, 1378 | 0usize, 1379 | concat!( 1380 | "Offset of field: ", 1381 | stringify!(spng_chunk), 1382 | "::", 1383 | stringify!(offset) 1384 | ) 1385 | ); 1386 | assert_eq!( 1387 | unsafe { ::core::ptr::addr_of!((*ptr).length) as usize - ptr as usize }, 1388 | 8usize, 1389 | concat!( 1390 | "Offset of field: ", 1391 | stringify!(spng_chunk), 1392 | "::", 1393 | stringify!(length) 1394 | ) 1395 | ); 1396 | assert_eq!( 1397 | unsafe { ::core::ptr::addr_of!((*ptr).type_) as usize - ptr as usize }, 1398 | 12usize, 1399 | concat!( 1400 | "Offset of field: ", 1401 | stringify!(spng_chunk), 1402 | "::", 1403 | stringify!(type_) 1404 | ) 1405 | ); 1406 | assert_eq!( 1407 | unsafe { ::core::ptr::addr_of!((*ptr).crc) as usize - ptr as usize }, 1408 | 16usize, 1409 | concat!( 1410 | "Offset of field: ", 1411 | stringify!(spng_chunk), 1412 | "::", 1413 | stringify!(crc) 1414 | ) 1415 | ); 1416 | } 1417 | pub const spng_location_SPNG_AFTER_IHDR: spng_location = 1; 1418 | pub const spng_location_SPNG_AFTER_PLTE: spng_location = 2; 1419 | pub const spng_location_SPNG_AFTER_IDAT: spng_location = 8; 1420 | pub type spng_location = libc::c_uint; 1421 | #[repr(C)] 1422 | #[derive(Debug, Copy, Clone)] 1423 | pub struct spng_unknown_chunk { 1424 | pub type_: [u8; 4usize], 1425 | pub length: usize, 1426 | pub data: *mut libc::c_void, 1427 | pub location: spng_location, 1428 | } 1429 | #[test] 1430 | fn bindgen_test_layout_spng_unknown_chunk() { 1431 | const UNINIT: ::core::mem::MaybeUninit = ::core::mem::MaybeUninit::uninit(); 1432 | let ptr = UNINIT.as_ptr(); 1433 | assert_eq!( 1434 | ::core::mem::size_of::(), 1435 | 32usize, 1436 | concat!("Size of: ", stringify!(spng_unknown_chunk)) 1437 | ); 1438 | assert_eq!( 1439 | ::core::mem::align_of::(), 1440 | 8usize, 1441 | concat!("Alignment of ", stringify!(spng_unknown_chunk)) 1442 | ); 1443 | assert_eq!( 1444 | unsafe { ::core::ptr::addr_of!((*ptr).type_) as usize - ptr as usize }, 1445 | 0usize, 1446 | concat!( 1447 | "Offset of field: ", 1448 | stringify!(spng_unknown_chunk), 1449 | "::", 1450 | stringify!(type_) 1451 | ) 1452 | ); 1453 | assert_eq!( 1454 | unsafe { ::core::ptr::addr_of!((*ptr).length) as usize - ptr as usize }, 1455 | 8usize, 1456 | concat!( 1457 | "Offset of field: ", 1458 | stringify!(spng_unknown_chunk), 1459 | "::", 1460 | stringify!(length) 1461 | ) 1462 | ); 1463 | assert_eq!( 1464 | unsafe { ::core::ptr::addr_of!((*ptr).data) as usize - ptr as usize }, 1465 | 16usize, 1466 | concat!( 1467 | "Offset of field: ", 1468 | stringify!(spng_unknown_chunk), 1469 | "::", 1470 | stringify!(data) 1471 | ) 1472 | ); 1473 | assert_eq!( 1474 | unsafe { ::core::ptr::addr_of!((*ptr).location) as usize - ptr as usize }, 1475 | 24usize, 1476 | concat!( 1477 | "Offset of field: ", 1478 | stringify!(spng_unknown_chunk), 1479 | "::", 1480 | stringify!(location) 1481 | ) 1482 | ); 1483 | } 1484 | pub const spng_option_SPNG_KEEP_UNKNOWN_CHUNKS: spng_option = 1; 1485 | pub const spng_option_SPNG_IMG_COMPRESSION_LEVEL: spng_option = 2; 1486 | pub const spng_option_SPNG_IMG_WINDOW_BITS: spng_option = 3; 1487 | pub const spng_option_SPNG_IMG_MEM_LEVEL: spng_option = 4; 1488 | pub const spng_option_SPNG_IMG_COMPRESSION_STRATEGY: spng_option = 5; 1489 | pub const spng_option_SPNG_TEXT_COMPRESSION_LEVEL: spng_option = 6; 1490 | pub const spng_option_SPNG_TEXT_WINDOW_BITS: spng_option = 7; 1491 | pub const spng_option_SPNG_TEXT_MEM_LEVEL: spng_option = 8; 1492 | pub const spng_option_SPNG_TEXT_COMPRESSION_STRATEGY: spng_option = 9; 1493 | pub const spng_option_SPNG_FILTER_CHOICE: spng_option = 10; 1494 | pub const spng_option_SPNG_CHUNK_COUNT_LIMIT: spng_option = 11; 1495 | pub const spng_option_SPNG_ENCODE_TO_BUFFER: spng_option = 12; 1496 | pub type spng_option = libc::c_uint; 1497 | pub type spng_malloc_fn = 1498 | ::core::option::Option *mut libc::c_void>; 1499 | pub type spng_realloc_fn = ::core::option::Option< 1500 | unsafe extern "C" fn(ptr: *mut libc::c_void, size: usize) -> *mut libc::c_void, 1501 | >; 1502 | pub type spng_calloc_fn = 1503 | ::core::option::Option *mut libc::c_void>; 1504 | pub type spng_free_fn = ::core::option::Option; 1505 | #[repr(C)] 1506 | #[derive(Debug, Copy, Clone)] 1507 | pub struct spng_alloc { 1508 | pub malloc_fn: spng_malloc_fn, 1509 | pub realloc_fn: spng_realloc_fn, 1510 | pub calloc_fn: spng_calloc_fn, 1511 | pub free_fn: spng_free_fn, 1512 | } 1513 | #[test] 1514 | fn bindgen_test_layout_spng_alloc() { 1515 | const UNINIT: ::core::mem::MaybeUninit = ::core::mem::MaybeUninit::uninit(); 1516 | let ptr = UNINIT.as_ptr(); 1517 | assert_eq!( 1518 | ::core::mem::size_of::(), 1519 | 32usize, 1520 | concat!("Size of: ", stringify!(spng_alloc)) 1521 | ); 1522 | assert_eq!( 1523 | ::core::mem::align_of::(), 1524 | 8usize, 1525 | concat!("Alignment of ", stringify!(spng_alloc)) 1526 | ); 1527 | assert_eq!( 1528 | unsafe { ::core::ptr::addr_of!((*ptr).malloc_fn) as usize - ptr as usize }, 1529 | 0usize, 1530 | concat!( 1531 | "Offset of field: ", 1532 | stringify!(spng_alloc), 1533 | "::", 1534 | stringify!(malloc_fn) 1535 | ) 1536 | ); 1537 | assert_eq!( 1538 | unsafe { ::core::ptr::addr_of!((*ptr).realloc_fn) as usize - ptr as usize }, 1539 | 8usize, 1540 | concat!( 1541 | "Offset of field: ", 1542 | stringify!(spng_alloc), 1543 | "::", 1544 | stringify!(realloc_fn) 1545 | ) 1546 | ); 1547 | assert_eq!( 1548 | unsafe { ::core::ptr::addr_of!((*ptr).calloc_fn) as usize - ptr as usize }, 1549 | 16usize, 1550 | concat!( 1551 | "Offset of field: ", 1552 | stringify!(spng_alloc), 1553 | "::", 1554 | stringify!(calloc_fn) 1555 | ) 1556 | ); 1557 | assert_eq!( 1558 | unsafe { ::core::ptr::addr_of!((*ptr).free_fn) as usize - ptr as usize }, 1559 | 24usize, 1560 | concat!( 1561 | "Offset of field: ", 1562 | stringify!(spng_alloc), 1563 | "::", 1564 | stringify!(free_fn) 1565 | ) 1566 | ); 1567 | } 1568 | #[repr(C)] 1569 | #[derive(Debug, Copy, Clone)] 1570 | pub struct spng_row_info { 1571 | pub scanline_idx: u32, 1572 | pub row_num: u32, 1573 | pub pass: libc::c_int, 1574 | pub filter: u8, 1575 | } 1576 | #[test] 1577 | fn bindgen_test_layout_spng_row_info() { 1578 | const UNINIT: ::core::mem::MaybeUninit = ::core::mem::MaybeUninit::uninit(); 1579 | let ptr = UNINIT.as_ptr(); 1580 | assert_eq!( 1581 | ::core::mem::size_of::(), 1582 | 16usize, 1583 | concat!("Size of: ", stringify!(spng_row_info)) 1584 | ); 1585 | assert_eq!( 1586 | ::core::mem::align_of::(), 1587 | 4usize, 1588 | concat!("Alignment of ", stringify!(spng_row_info)) 1589 | ); 1590 | assert_eq!( 1591 | unsafe { ::core::ptr::addr_of!((*ptr).scanline_idx) as usize - ptr as usize }, 1592 | 0usize, 1593 | concat!( 1594 | "Offset of field: ", 1595 | stringify!(spng_row_info), 1596 | "::", 1597 | stringify!(scanline_idx) 1598 | ) 1599 | ); 1600 | assert_eq!( 1601 | unsafe { ::core::ptr::addr_of!((*ptr).row_num) as usize - ptr as usize }, 1602 | 4usize, 1603 | concat!( 1604 | "Offset of field: ", 1605 | stringify!(spng_row_info), 1606 | "::", 1607 | stringify!(row_num) 1608 | ) 1609 | ); 1610 | assert_eq!( 1611 | unsafe { ::core::ptr::addr_of!((*ptr).pass) as usize - ptr as usize }, 1612 | 8usize, 1613 | concat!( 1614 | "Offset of field: ", 1615 | stringify!(spng_row_info), 1616 | "::", 1617 | stringify!(pass) 1618 | ) 1619 | ); 1620 | assert_eq!( 1621 | unsafe { ::core::ptr::addr_of!((*ptr).filter) as usize - ptr as usize }, 1622 | 12usize, 1623 | concat!( 1624 | "Offset of field: ", 1625 | stringify!(spng_row_info), 1626 | "::", 1627 | stringify!(filter) 1628 | ) 1629 | ); 1630 | } 1631 | #[repr(C)] 1632 | #[derive(Debug, Copy, Clone)] 1633 | pub struct spng_ctx { 1634 | _unused: [u8; 0], 1635 | } 1636 | pub type spng_read_fn = ::core::option::Option< 1637 | unsafe extern "C" fn( 1638 | ctx: *mut spng_ctx, 1639 | user: *mut libc::c_void, 1640 | dest: *mut libc::c_void, 1641 | length: usize, 1642 | ) -> libc::c_int, 1643 | >; 1644 | pub type spng_write_fn = ::core::option::Option< 1645 | unsafe extern "C" fn( 1646 | ctx: *mut spng_ctx, 1647 | user: *mut libc::c_void, 1648 | src: *mut libc::c_void, 1649 | length: usize, 1650 | ) -> libc::c_int, 1651 | >; 1652 | pub type spng_rw_fn = ::core::option::Option< 1653 | unsafe extern "C" fn( 1654 | ctx: *mut spng_ctx, 1655 | user: *mut libc::c_void, 1656 | dst_src: *mut libc::c_void, 1657 | length: usize, 1658 | ) -> libc::c_int, 1659 | >; 1660 | extern "C" { 1661 | pub fn spng_ctx_new(flags: libc::c_int) -> *mut spng_ctx; 1662 | } 1663 | extern "C" { 1664 | pub fn spng_ctx_new2(alloc: *mut spng_alloc, flags: libc::c_int) -> *mut spng_ctx; 1665 | } 1666 | extern "C" { 1667 | pub fn spng_ctx_free(ctx: *mut spng_ctx); 1668 | } 1669 | extern "C" { 1670 | pub fn spng_set_png_buffer( 1671 | ctx: *mut spng_ctx, 1672 | buf: *const libc::c_void, 1673 | size: usize, 1674 | ) -> libc::c_int; 1675 | } 1676 | extern "C" { 1677 | pub fn spng_set_png_stream( 1678 | ctx: *mut spng_ctx, 1679 | rw_func: spng_rw_fn, 1680 | user: *mut libc::c_void, 1681 | ) -> libc::c_int; 1682 | } 1683 | extern "C" { 1684 | pub fn spng_set_png_file(ctx: *mut spng_ctx, file: *mut FILE) -> libc::c_int; 1685 | } 1686 | extern "C" { 1687 | pub fn spng_get_png_buffer( 1688 | ctx: *mut spng_ctx, 1689 | len: *mut usize, 1690 | error: *mut libc::c_int, 1691 | ) -> *mut libc::c_void; 1692 | } 1693 | extern "C" { 1694 | pub fn spng_set_image_limits(ctx: *mut spng_ctx, width: u32, height: u32) -> libc::c_int; 1695 | } 1696 | extern "C" { 1697 | pub fn spng_get_image_limits( 1698 | ctx: *mut spng_ctx, 1699 | width: *mut u32, 1700 | height: *mut u32, 1701 | ) -> libc::c_int; 1702 | } 1703 | extern "C" { 1704 | pub fn spng_set_chunk_limits( 1705 | ctx: *mut spng_ctx, 1706 | chunk_size: usize, 1707 | cache_size: usize, 1708 | ) -> libc::c_int; 1709 | } 1710 | extern "C" { 1711 | pub fn spng_get_chunk_limits( 1712 | ctx: *mut spng_ctx, 1713 | chunk_size: *mut usize, 1714 | cache_size: *mut usize, 1715 | ) -> libc::c_int; 1716 | } 1717 | extern "C" { 1718 | pub fn spng_set_crc_action( 1719 | ctx: *mut spng_ctx, 1720 | critical: libc::c_int, 1721 | ancillary: libc::c_int, 1722 | ) -> libc::c_int; 1723 | } 1724 | extern "C" { 1725 | pub fn spng_set_option( 1726 | ctx: *mut spng_ctx, 1727 | option: spng_option, 1728 | value: libc::c_int, 1729 | ) -> libc::c_int; 1730 | } 1731 | extern "C" { 1732 | pub fn spng_get_option( 1733 | ctx: *mut spng_ctx, 1734 | option: spng_option, 1735 | value: *mut libc::c_int, 1736 | ) -> libc::c_int; 1737 | } 1738 | extern "C" { 1739 | pub fn spng_decoded_image_size( 1740 | ctx: *mut spng_ctx, 1741 | fmt: libc::c_int, 1742 | len: *mut usize, 1743 | ) -> libc::c_int; 1744 | } 1745 | extern "C" { 1746 | pub fn spng_decode_image( 1747 | ctx: *mut spng_ctx, 1748 | out: *mut libc::c_void, 1749 | len: usize, 1750 | fmt: libc::c_int, 1751 | flags: libc::c_int, 1752 | ) -> libc::c_int; 1753 | } 1754 | extern "C" { 1755 | pub fn spng_decode_scanline( 1756 | ctx: *mut spng_ctx, 1757 | out: *mut libc::c_void, 1758 | len: usize, 1759 | ) -> libc::c_int; 1760 | } 1761 | extern "C" { 1762 | pub fn spng_decode_row(ctx: *mut spng_ctx, out: *mut libc::c_void, len: usize) -> libc::c_int; 1763 | } 1764 | extern "C" { 1765 | pub fn spng_decode_chunks(ctx: *mut spng_ctx) -> libc::c_int; 1766 | } 1767 | extern "C" { 1768 | pub fn spng_get_row_info(ctx: *mut spng_ctx, row_info: *mut spng_row_info) -> libc::c_int; 1769 | } 1770 | extern "C" { 1771 | pub fn spng_encode_image( 1772 | ctx: *mut spng_ctx, 1773 | img: *const libc::c_void, 1774 | len: usize, 1775 | fmt: libc::c_int, 1776 | flags: libc::c_int, 1777 | ) -> libc::c_int; 1778 | } 1779 | extern "C" { 1780 | pub fn spng_encode_scanline( 1781 | ctx: *mut spng_ctx, 1782 | scanline: *const libc::c_void, 1783 | len: usize, 1784 | ) -> libc::c_int; 1785 | } 1786 | extern "C" { 1787 | pub fn spng_encode_row(ctx: *mut spng_ctx, row: *const libc::c_void, len: usize) 1788 | -> libc::c_int; 1789 | } 1790 | extern "C" { 1791 | pub fn spng_encode_chunks(ctx: *mut spng_ctx) -> libc::c_int; 1792 | } 1793 | extern "C" { 1794 | pub fn spng_get_ihdr(ctx: *mut spng_ctx, ihdr: *mut spng_ihdr) -> libc::c_int; 1795 | } 1796 | extern "C" { 1797 | pub fn spng_get_plte(ctx: *mut spng_ctx, plte: *mut spng_plte) -> libc::c_int; 1798 | } 1799 | extern "C" { 1800 | pub fn spng_get_trns(ctx: *mut spng_ctx, trns: *mut spng_trns) -> libc::c_int; 1801 | } 1802 | extern "C" { 1803 | pub fn spng_get_chrm(ctx: *mut spng_ctx, chrm: *mut spng_chrm) -> libc::c_int; 1804 | } 1805 | extern "C" { 1806 | pub fn spng_get_chrm_int(ctx: *mut spng_ctx, chrm_int: *mut spng_chrm_int) -> libc::c_int; 1807 | } 1808 | extern "C" { 1809 | pub fn spng_get_gama(ctx: *mut spng_ctx, gamma: *mut f64) -> libc::c_int; 1810 | } 1811 | extern "C" { 1812 | pub fn spng_get_gama_int(ctx: *mut spng_ctx, gama_int: *mut u32) -> libc::c_int; 1813 | } 1814 | extern "C" { 1815 | pub fn spng_get_iccp(ctx: *mut spng_ctx, iccp: *mut spng_iccp) -> libc::c_int; 1816 | } 1817 | extern "C" { 1818 | pub fn spng_get_sbit(ctx: *mut spng_ctx, sbit: *mut spng_sbit) -> libc::c_int; 1819 | } 1820 | extern "C" { 1821 | pub fn spng_get_srgb(ctx: *mut spng_ctx, rendering_intent: *mut u8) -> libc::c_int; 1822 | } 1823 | extern "C" { 1824 | pub fn spng_get_text(ctx: *mut spng_ctx, text: *mut spng_text, n_text: *mut u32) 1825 | -> libc::c_int; 1826 | } 1827 | extern "C" { 1828 | pub fn spng_get_bkgd(ctx: *mut spng_ctx, bkgd: *mut spng_bkgd) -> libc::c_int; 1829 | } 1830 | extern "C" { 1831 | pub fn spng_get_hist(ctx: *mut spng_ctx, hist: *mut spng_hist) -> libc::c_int; 1832 | } 1833 | extern "C" { 1834 | pub fn spng_get_phys(ctx: *mut spng_ctx, phys: *mut spng_phys) -> libc::c_int; 1835 | } 1836 | extern "C" { 1837 | pub fn spng_get_splt(ctx: *mut spng_ctx, splt: *mut spng_splt, n_splt: *mut u32) 1838 | -> libc::c_int; 1839 | } 1840 | extern "C" { 1841 | pub fn spng_get_time(ctx: *mut spng_ctx, time: *mut spng_time) -> libc::c_int; 1842 | } 1843 | extern "C" { 1844 | pub fn spng_get_unknown_chunks( 1845 | ctx: *mut spng_ctx, 1846 | chunks: *mut spng_unknown_chunk, 1847 | n_chunks: *mut u32, 1848 | ) -> libc::c_int; 1849 | } 1850 | extern "C" { 1851 | pub fn spng_get_offs(ctx: *mut spng_ctx, offs: *mut spng_offs) -> libc::c_int; 1852 | } 1853 | extern "C" { 1854 | pub fn spng_get_exif(ctx: *mut spng_ctx, exif: *mut spng_exif) -> libc::c_int; 1855 | } 1856 | extern "C" { 1857 | pub fn spng_set_ihdr(ctx: *mut spng_ctx, ihdr: *mut spng_ihdr) -> libc::c_int; 1858 | } 1859 | extern "C" { 1860 | pub fn spng_set_plte(ctx: *mut spng_ctx, plte: *mut spng_plte) -> libc::c_int; 1861 | } 1862 | extern "C" { 1863 | pub fn spng_set_trns(ctx: *mut spng_ctx, trns: *mut spng_trns) -> libc::c_int; 1864 | } 1865 | extern "C" { 1866 | pub fn spng_set_chrm(ctx: *mut spng_ctx, chrm: *mut spng_chrm) -> libc::c_int; 1867 | } 1868 | extern "C" { 1869 | pub fn spng_set_chrm_int(ctx: *mut spng_ctx, chrm_int: *mut spng_chrm_int) -> libc::c_int; 1870 | } 1871 | extern "C" { 1872 | pub fn spng_set_gama(ctx: *mut spng_ctx, gamma: f64) -> libc::c_int; 1873 | } 1874 | extern "C" { 1875 | pub fn spng_set_gama_int(ctx: *mut spng_ctx, gamma: u32) -> libc::c_int; 1876 | } 1877 | extern "C" { 1878 | pub fn spng_set_iccp(ctx: *mut spng_ctx, iccp: *mut spng_iccp) -> libc::c_int; 1879 | } 1880 | extern "C" { 1881 | pub fn spng_set_sbit(ctx: *mut spng_ctx, sbit: *mut spng_sbit) -> libc::c_int; 1882 | } 1883 | extern "C" { 1884 | pub fn spng_set_srgb(ctx: *mut spng_ctx, rendering_intent: u8) -> libc::c_int; 1885 | } 1886 | extern "C" { 1887 | pub fn spng_set_text(ctx: *mut spng_ctx, text: *mut spng_text, n_text: u32) -> libc::c_int; 1888 | } 1889 | extern "C" { 1890 | pub fn spng_set_bkgd(ctx: *mut spng_ctx, bkgd: *mut spng_bkgd) -> libc::c_int; 1891 | } 1892 | extern "C" { 1893 | pub fn spng_set_hist(ctx: *mut spng_ctx, hist: *mut spng_hist) -> libc::c_int; 1894 | } 1895 | extern "C" { 1896 | pub fn spng_set_phys(ctx: *mut spng_ctx, phys: *mut spng_phys) -> libc::c_int; 1897 | } 1898 | extern "C" { 1899 | pub fn spng_set_splt(ctx: *mut spng_ctx, splt: *mut spng_splt, n_splt: u32) -> libc::c_int; 1900 | } 1901 | extern "C" { 1902 | pub fn spng_set_time(ctx: *mut spng_ctx, time: *mut spng_time) -> libc::c_int; 1903 | } 1904 | extern "C" { 1905 | pub fn spng_set_unknown_chunks( 1906 | ctx: *mut spng_ctx, 1907 | chunks: *mut spng_unknown_chunk, 1908 | n_chunks: u32, 1909 | ) -> libc::c_int; 1910 | } 1911 | extern "C" { 1912 | pub fn spng_set_offs(ctx: *mut spng_ctx, offs: *mut spng_offs) -> libc::c_int; 1913 | } 1914 | extern "C" { 1915 | pub fn spng_set_exif(ctx: *mut spng_ctx, exif: *mut spng_exif) -> libc::c_int; 1916 | } 1917 | extern "C" { 1918 | pub fn spng_strerror(err: libc::c_int) -> *const libc::c_char; 1919 | } 1920 | extern "C" { 1921 | pub fn spng_version_string() -> *const libc::c_char; 1922 | } 1923 | --------------------------------------------------------------------------------