rgb-0.8.50/.cargo_vcs_info.json0000644000000001360000000000100117000ustar { "git": { "sha1": "b2e65a23fa8218149aae0edeec167eaef625a8c5" }, "path_in_vcs": "" }rgb-0.8.50/Cargo.lock0000644000000117240000000000100076600ustar # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 3 [[package]] name = "bitflags" version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bytemuck" version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6fd4c6dcc3b0aea2f5c0b4b82c2b15fe39ddbc76041a310848f4706edf76bb31" [[package]] name = "defmt" version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a99dd22262668b887121d4672af5a64b238f026099f1a2a1b322066c9ecfe9e0" dependencies = [ "bitflags", "defmt-macros", ] [[package]] name = "defmt-macros" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3a9f309eff1f79b3ebdf252954d90ae440599c26c2c553fe87a2d17195f2dcb" dependencies = [ "defmt-parser", "proc-macro-error", "proc-macro2", "quote", "syn 2.0.72", ] [[package]] name = "defmt-parser" version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff4a5fefe330e8d7f31b16a318f9ce81000d8e35e69b93eae154d16d2278f70f" dependencies = [ "thiserror", ] [[package]] name = "itoa" version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "memchr" version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "proc-macro-error" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" dependencies = [ "proc-macro-error-attr", "proc-macro2", "quote", "syn 1.0.109", "version_check", ] [[package]] name = "proc-macro-error-attr" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" dependencies = [ "proc-macro2", "quote", "version_check", ] [[package]] name = "proc-macro2" version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" dependencies = [ "unicode-ident", ] [[package]] name = "quote" version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" dependencies = [ "proc-macro2", ] [[package]] name = "rgb" version = "0.8.50" dependencies = [ "bytemuck", "defmt", "serde", "serde_json", ] [[package]] name = "ryu" version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" [[package]] name = "serde" version = "1.0.204" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" version = "1.0.204" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" dependencies = [ "proc-macro2", "quote", "syn 2.0.72", ] [[package]] name = "serde_json" version = "1.0.122" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "784b6203951c57ff748476b126ccb5e8e2959a5c19e5c617ab1956be3dbc68da" dependencies = [ "itoa", "memchr", "ryu", "serde", ] [[package]] name = "syn" version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ "proc-macro2", "unicode-ident", ] [[package]] name = "syn" version = "2.0.72" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] [[package]] name = "thiserror" version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" dependencies = [ "proc-macro2", "quote", "syn 2.0.72", ] [[package]] name = "unicode-ident" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "version_check" version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" rgb-0.8.50/Cargo.toml0000644000000045430000000000100077040ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2021" rust-version = "1.63" name = "rgb" version = "0.8.50" authors = [ "Kornel Lesiński ", "James Forster ", ] build = false include = [ "src/**/*", "Cargo.toml", "README.md", "examples/*.rs", "LICENSE", ] autobins = false autoexamples = false autotests = false autobenches = false description = """ `struct RGB/RGBA/etc.` for sharing pixels between crates + convenience methods for color manipulation. Allows no-copy high-level interoperability. Also adds common convenience methods and implements standard Rust traits to make `RGB`/`RGBA` pixels and slices first-class Rust objects.""" homepage = "https://lib.rs/crates/rgb" documentation = "https://docs.rs/rgb" readme = "README.md" keywords = [ "rgb", "rgba", "bgra", "pixel", "color", ] categories = [ "graphics", "rust-patterns", "multimedia::images", ] license = "MIT" repository = "https://github.com/kornelski/rust-rgb" [package.metadata.docs.rs] features = [ "as-bytes", "serde", ] rustdoc-args = ["--generate-link-to-definition"] targets = ["x86_64-unknown-linux-gnu"] [lib] name = "rgb" path = "src/lib.rs" [[example]] name = "example" path = "examples/example.rs" required-features = ["as-bytes"] [[example]] name = "serde" path = "examples/serde.rs" required-features = ["serde"] [dependencies.bytemuck] version = "1.16" optional = true [dependencies.defmt] version = "0.3.8" optional = true [dependencies.serde] version = "1.0.200" features = ["derive"] optional = true default-features = false [dev-dependencies.serde_json] version = "1.0.100" [features] argb = [] as-bytes = ["bytemuck"] bytemuck = ["dep:bytemuck"] checked_fns = [] default = [ "as-bytes", "argb", "grb", ] defmt-03 = ["dep:defmt"] grb = [] serde = ["dep:serde"] unstable-experimental = [] [badges.maintenance] status = "actively-developed" rgb-0.8.50/Cargo.toml.orig000064400000000000000000000040121046102023000133540ustar 00000000000000[package] name = "rgb" version = "0.8.50" authors = ["Kornel Lesiński ", "James Forster "] include = ["src/**/*", "Cargo.toml", "README.md", "examples/*.rs", "LICENSE"] description = "`struct RGB/RGBA/etc.` for sharing pixels between crates + convenience methods for color manipulation.\nAllows no-copy high-level interoperability. Also adds common convenience methods and implements standard Rust traits to make `RGB`/`RGBA` pixels and slices first-class Rust objects." documentation = "https://docs.rs/rgb" repository = "https://github.com/kornelski/rust-rgb" homepage = "https://lib.rs/crates/rgb" readme = "README.md" keywords = ["rgb", "rgba", "bgra", "pixel", "color"] license = "MIT" categories = ["graphics", "rust-patterns", "multimedia::images"] edition = "2021" rust-version = "1.63" [features] default = ["as-bytes", "argb", "grb"] # safe as_bytes() casts require a marker trait for non-padded, non-pointery types. as-bytes = ["bytemuck"] # Preferred over as-bytes bytemuck = ["dep:bytemuck"] # Deprecated: all pixel types are enabled by default. No-op. argb = [] # Deprecated: all pixel types are enabled by default. No-op. grb = [] # Enable `checked_add` and `checked_sub` methods on `RGB` checked_fns = [] # Make pixels serializable serde = ["dep:serde"] # support for the `defmt` crate defmt-03 = ["dep:defmt"] # Preview of changes for v0.9. May cause semver breakage if enabled. unstable-experimental = [] [badges] maintenance = { status = "actively-developed" } [dependencies] serde = { version = "1.0.200", optional = true, default-features = false, features = ["derive"] } bytemuck = { version = "1.16", optional = true } defmt = { version = "0.3.8", optional = true } [dev-dependencies] serde_json = "1.0.100" [[example]] name = "serde" required-features = ["serde"] [[example]] name = "example" required-features = ["as-bytes"] [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] features = ["as-bytes", "serde"] rustdoc-args = ["--generate-link-to-definition"] rgb-0.8.50/LICENSE000064400000000000000000000020471046102023000115000ustar 00000000000000MIT License Copyright (c) 2019 Kornel Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. rgb-0.8.50/README.md000064400000000000000000000100501046102023000117430ustar 00000000000000# `struct RGB` for [Rust](https://www.rust-lang.org) [![crate](https://img.shields.io/crates/v/rgb.svg)](https://lib.rs/crates/rgb) Operating on pixels as weakly-typed vectors of `u8` is error-prone and inconvenient. It's better to use vectors of pixel structs. However, Rust is so strongly typed that *your* RGB pixel struct is not compatible with *my* RGB pixel struct. So let's all use mine :P [xkcd: …there are 15 competing standards](https://xkcd.com/927/) ## Installation Add this to your `Cargo.toml`: ```toml [dependencies] rgb = "0.8.43" ``` ## Usage ### `RGB` and `RGBA` structs The structs implement common Rust traits and a few convenience functions, e.g. `map` that repeats an operation on every subpixel: ```rust use rgb::*; // Laziest way to use traits which add extra methods to the structs let px = RGB { r:255_u8, g:0, b:255, }; let inverted = px.map(|ch| 255 - ch); println!("{}", inverted); // Display: rgb(0,255,0) assert_eq!(RGB8::new(0, 255, 0), inverted); ``` ### Byte slices to pixel slices For interoperability with functions operating on generic arrays of bytes there are functions for safe casting to and from pixel slices. ```rust let raw = vec![0u8; width*height*3]; let pixels: &[RGB8] = raw.as_rgb(); /// Safe casts without copying let raw_again = pixels.as_bytes(); ``` Note: if you get an error about "no method named `as_bytes` found", add `use rgb::ComponentBytes`. If you're using a custom component type (`RGB`), implement `rgb::Pod` (plain old data) and `rgb::Zeroable` trait for the component (these traits are from [`bytemuck`](https://lib.rs/bytemuck) crate). ---- ## About colorspaces *Correct* color management is a complex problem, and this crate aims to be the lowest common denominator, so it's intentionally agnostic about it. However, this library supports any subpixel type for `RGB`, and `RGBA`, so you can use them with a newtype, e.g.: ```rust struct LinearLight(u16); type LinearRGB = RGB; ``` ### `BGRA`, `ARGB`, `Gray`, etc. There are other color types in `rgb::alt::*`. There's also an optional `serde` feature that makes all types (de)serializable. ## Roadmap to 1.0 The plan is to provide easy migration to v1.0. There will be a transitional v0.9 version released that will be mostly backwards-compatible with 0.8, and forwards-compatible with 1.0. Planned changes: * Types will be renamed to follow Rust's naming convention: `RGBA` → `Rgba`. The old names will continue to work as hidden aliases. * The `Gray` and `GrayAlpha` types will change from tuple structs with `.0` to structs with named fields `.v` (value) and `.a` (alpha). Through a `Deref` trick both field names will work, but `.0` is going to be deprecated. * `bytemuck::Pod` (conversions from/to raw bytes) will require color and alpha components to be the same type (i.e. it will work with `Rgba`, but not `Rgba`). Currently it's unsound if the alpha has a different size than color components. * Many inherent methods will be moved to a new `Pixel` trait. ## Migration from 0.8 to 0.9 1. Update to the latest version of 0.8, and fix all deprecation warnings. - rename `.alpha()` to `.with_alpha()` - rename `.map_c()` to `.map_colors()` 2. Change field access on `GrayAlpha` from `.0` and `.1` to `.v` and `.a` where possible. 3. Use the `bytemuck` crate for conversions from/to bytes instead of `ComponentBytes` trait. Disable the `as-bytes` feature if possible. 4. Don't enable `gbr` and `argb` features. All pixel types are enabled by default. 5. In generic code operating on pixels, add `Copy + 'static` bounds to the pixel types and/or their components. 6. Test your code with `rgb = { version = "0.8.46", features = ["unstable-experimental"] }`, which enables some of the future breaking changes on the older version. This feature flag is only for testing, and will be changed/removed in the future. 7. Avoid wildcard imports from `rgb::alt::*`, and avoid using `GRAY8`-`GRAYA16` type aliases. rgb-0.8.50/examples/example.rs000064400000000000000000000010551046102023000143100ustar 00000000000000#[cfg(feature = "as-bytes")] fn main() { use rgb::{ComponentBytes, ComponentSlice, ComponentMap}; use rgb::Rgb; let px = Rgb { r: 255_u8, g: 0, b: 100, }; assert_eq!([px].as_bytes()[0], 255); let bigpx = Rgb:: { r: 65535_u16, g: 0, b: 0, }; assert_eq!(bigpx.as_slice()[0], 65535); let px = Rgb::::new(255, 0, 255); let inverted: Rgb = px.map(|ch| 255 - ch); println!("{inverted}"); // rgb(0,255,0) } #[cfg(not(feature = "as-bytes"))] fn main() {} rgb-0.8.50/examples/serde.rs000064400000000000000000000004631046102023000137610ustar 00000000000000use rgb::*; // Run using: cargo run --features=serde --example serde fn main() { let color = Rgb { r:255_u8, g:0, b:100 }; println!("{}", serde_json::to_string(&color).unwrap()); let color: Rgb = serde_json::from_str("{\"r\":10,\"g\":20,\"b\":30}").unwrap(); println!("{}", color); } rgb-0.8.50/src/as_bytes.rs000064400000000000000000000115301046102023000134360ustar 00000000000000use crate::{RGB, RGBA}; use crate::alt::{Gray, GrayAlpha, BGR, BGRA}; use crate::alt::{ARGB, ABGR}; use crate::ComponentBytes; #[cfg(feature = "as-bytes")] unsafe impl crate::Pod for RGB where T: crate::Pod {} #[cfg(feature = "as-bytes")] unsafe impl crate::Pod for BGR where T: crate::Pod {} #[cfg(feature = "as-bytes")] unsafe impl crate::Zeroable for RGB where T: crate::Zeroable {} #[cfg(feature = "as-bytes")] unsafe impl crate::Zeroable for BGR where T: crate::Zeroable {} #[cfg(feature = "as-bytes")] /// This is unsound. You can disable `as-bytes` feature, enable `bytemuck`, and use `bytemuck::cast_slice()` instead. unsafe impl crate::Zeroable for ABGR where T: crate::Zeroable, A: crate::Zeroable { #[track_caller] #[inline(always)] fn zeroed() -> Self { unsafe { let _ = assert_no_padding::(); core::mem::zeroed() } } } #[track_caller] const fn assert_no_padding() { if core::mem::size_of::() + 3 * core::mem::size_of::() != core::mem::size_of::() { panic!("type has padding"); } } #[cfg(feature = "as-bytes")] /// This is unsound. You can disable `as-bytes` feature, enable `bytemuck`, and use `bytemuck::cast_slice()` instead. unsafe impl crate::Pod for RGBA where T: crate::Pod, A: crate::Pod {} #[cfg(feature = "as-bytes")] /// This is unsound. You can disable `as-bytes` feature, enable `bytemuck`, and use `bytemuck::cast_slice()` instead. unsafe impl crate::Pod for BGRA where T: crate::Pod, A: crate::Pod {} #[cfg(feature = "as-bytes")] /// This is unsound. You can disable `as-bytes` feature, enable `bytemuck`, and use `bytemuck::cast_slice()` instead. unsafe impl crate::Zeroable for RGBA where T: crate::Zeroable, A: crate::Zeroable { #[track_caller] #[inline(always)] fn zeroed() -> Self { unsafe { let _ = assert_no_padding::(); core::mem::zeroed() } } } #[cfg(feature = "as-bytes")] /// This is unsound. You can disable `as-bytes` feature, enable `bytemuck`, and use `bytemuck::cast_slice()` instead. unsafe impl crate::Pod for ARGB where T: crate::Pod, A: crate::Pod {} #[cfg(feature = "as-bytes")] /// This is unsound. You can disable `as-bytes` feature, enable `bytemuck`, and use `bytemuck::cast_slice()` instead. unsafe impl crate::Pod for ABGR where T: crate::Pod, A: crate::Pod {} #[cfg(feature = "as-bytes")] /// This is unsound. You can disable `as-bytes` feature, enable `bytemuck`, and use `bytemuck::cast_slice()` instead. unsafe impl crate::Zeroable for ARGB where T: crate::Zeroable, A: crate::Zeroable { #[track_caller] #[inline(always)] fn zeroed() -> Self { unsafe { let _ = assert_no_padding::(); core::mem::zeroed() } } } #[cfg(feature = "as-bytes")] /// This is unsound. You can disable `as-bytes` feature, enable `bytemuck`, and use `bytemuck::cast_slice()` instead. unsafe impl crate::Zeroable for BGRA where T: crate::Zeroable, A: crate::Zeroable { #[track_caller] #[inline(always)] fn zeroed() -> Self { unsafe { let _ = assert_no_padding::(); core::mem::zeroed() } } } #[cfg(feature = "as-bytes")] unsafe impl crate::Pod for Gray where T: crate::Pod {} #[cfg(feature = "as-bytes")] /// This is unsound. You can disable `as-bytes` feature, enable `bytemuck`, and use `bytemuck::cast_slice()` instead. unsafe impl crate::Pod for GrayAlpha where T: crate::Pod, A: crate::Pod {} #[cfg(feature = "as-bytes")] unsafe impl crate::Zeroable for Gray where T: crate::Zeroable {} #[cfg(feature = "as-bytes")] /// This is unsound. You can disable `as-bytes` feature, enable `bytemuck`, and use `bytemuck::cast_slice()` instead. unsafe impl crate::Zeroable for GrayAlpha where T: crate::Zeroable, A: crate::Zeroable { #[track_caller] #[inline(always)] fn zeroed() -> Self { unsafe { if core::mem::size_of::() + core::mem::size_of::() != core::mem::size_of::() { panic!("type has padding"); } core::mem::zeroed() } } } #[cfg(feature = "as-bytes")] impl ComponentBytes for [Gray] {} #[cfg(feature = "as-bytes")] impl ComponentBytes for [GrayAlpha] {} #[test] #[allow(dead_code)] fn shared_impl() { struct SharedPixelBuffer { data: [Pixel; 1], } impl SharedPixelBuffer where [Pixel]: crate::ComponentBytes, { pub fn as_bytes(&self) -> &[u8] { self.data.as_slice().as_bytes() } } let b = SharedPixelBuffer { data: [crate::RGB8::new(0,0,0)], }; let _ = b.as_bytes(); } rgb-0.8.50/src/bytemuck_impl.rs000064400000000000000000000013031046102023000144660ustar 00000000000000use crate::{Abgr, Argb, Bgr, Bgra, Grb, Rgb, Rgba}; use crate::formats::gray_a::GrayA; use crate::formats::gray_alpha::GrayAlpha_v08; use crate::formats::gray::Gray_v08; #[cfg(feature = "unstable-experimental")] use crate::formats::gray::Gray_v09; macro_rules! bytemuck { ($name:ident) => { unsafe impl ::bytemuck::Zeroable for $name {} unsafe impl ::bytemuck::Pod for $name {} }; } bytemuck!(Rgb); bytemuck!(Bgr); bytemuck!(Grb); bytemuck!(Rgba); bytemuck!(Argb); bytemuck!(Bgra); bytemuck!(Abgr); bytemuck!(GrayA); bytemuck!(GrayAlpha_v08); bytemuck!(Gray_v08); #[cfg(feature = "unstable-experimental")] bytemuck!(Gray_v09); rgb-0.8.50/src/formats/abgr.rs000064400000000000000000000010671046102023000142170ustar 00000000000000#[repr(C)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "defmt-03", derive(defmt::Format))] #[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Ord, PartialOrd, Hash)] /// An `Alpha + Blue + Green + Red` pixel. /// /// # Examples /// /// ``` /// use rgb::Abgr; /// /// let pixel: Abgr = Abgr { a: 255, b: 0, g: 0, r: 0 }; /// ``` pub struct Abgr { /// Alpha Component pub a: A, /// Blue Component pub b: T, /// Green Component pub g: T, /// Red Component pub r: T, } rgb-0.8.50/src/formats/argb.rs000064400000000000000000000010671046102023000142170ustar 00000000000000#[repr(C)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "defmt-03", derive(defmt::Format))] #[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Ord, PartialOrd, Hash)] /// An `Alpha + Red + Green + Blue` pixel. /// /// # Examples /// /// ``` /// use rgb::Argb; /// /// let pixel: Argb = Argb { a: 255, r: 0, g: 0, b: 0 }; /// ``` pub struct Argb { /// Alpha Component pub a: A, /// Red Component pub r: T, /// Green Component pub g: T, /// Blue Component pub b: T, } rgb-0.8.50/src/formats/bgr.rs000064400000000000000000000007651046102023000140620ustar 00000000000000#[repr(C)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "defmt-03", derive(defmt::Format))] #[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Ord, PartialOrd, Hash)] /// A `Blue + Green + Red` pixel. /// /// # Examples /// /// ``` /// use rgb::Bgr; /// /// let pixel: Bgr = Bgr { b: 0, g: 0, r: 0 }; /// ``` pub struct Bgr { /// Blue Component pub b: T, /// Green Component pub g: T, /// Red Component pub r: T, } rgb-0.8.50/src/formats/bgra.rs000064400000000000000000000010661046102023000142160ustar 00000000000000#[repr(C)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "defmt-03", derive(defmt::Format))] #[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Ord, PartialOrd, Hash)] /// A `Blue + Green + Red + Alpha` pixel. /// /// # Examples /// /// ``` /// use rgb::Bgra; /// /// let pixel: Bgra = Bgra { b: 0, g: 0, r: 0, a: 255 }; /// ``` pub struct Bgra { /// Blue Component pub b: T, /// Green Component pub g: T, /// Red Component pub r: T, /// Alpha Component pub a: A, } rgb-0.8.50/src/formats/gray.rs000064400000000000000000000055231046102023000142470ustar 00000000000000#[repr(C)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "defmt-03", derive(defmt::Format))] #[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Ord, PartialOrd, Hash)] /// A `Grayscale` pixel (rgb crate v0.8) #[allow(non_camel_case_types)] pub struct Gray_v08( /// Grayscale Component. This field will be renamed to `v`. pub T, ); impl Gray_v08 { /// Reads the `.0` field /// /// This function isn't necessary, but it is forwards-compatible with the next major version of the RGB crate. pub fn value(self) -> T { self.0 } /// Exposes the `.0` field for writing /// /// This function isn't necessary, but it is forwards-compatible with the next major version of the RGB crate. pub fn value_mut(&mut self) -> &mut T { &mut self.0 } /// Add alpha component to this pixel #[allow(deprecated)] pub fn with_alpha(self, add_alpha_value: T) -> crate::formats::gray_alpha::GrayAlpha_v08 { crate::formats::gray_alpha::GrayAlpha_v08(self.0, add_alpha_value) } } #[cfg(feature = "unstable-experimental")] /// A `Grayscale` pixel (rgb crate v0.9) /// /// This is the new gray pixel type as opposed to the legacy gray type /// (`rgb::Gray`) which is kept for backwards-compatibility. /// /// # Examples /// /// ``` /// use rgb::Gray; /// /// let pixel: Gray = Gray { v: 0 }; /// ``` #[allow(non_camel_case_types)] #[repr(C)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "defmt-03", derive(defmt::Format))] #[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Ord, PartialOrd, Hash)] #[doc(alias = "Luma")] pub struct Gray_v09 { /// Grayscale Component pub v: T, } #[cfg(feature = "unstable-experimental")] impl core::ops::Deref for Gray_v08 { type Target = Gray_v09; fn deref(&self) -> &Gray_v09 { unsafe { &*(self as *const Self as *const Gray_v09::) } } } #[cfg(feature = "unstable-experimental")] impl Gray_v09 { /// Reads the `.v` field /// /// This function isn't necessary, but it is forwards-compatible with the next major version of the RGB crate. pub fn value(self) -> T { self.v } /// Exposes the `.v` field for writing /// /// This function isn't necessary, but it is forwards-compatible with the next major version of the RGB crate. pub fn value_mut(&mut self) -> &mut T { &mut self.v } /// Add alpha component to this pixel pub fn with_alpha(self, add_alpha_value: T) -> crate::formats::gray_a::GrayA { crate::formats::gray_a::GrayA { v: self.v, a: add_alpha_value } } } #[test] #[cfg(feature = "unstable-experimental")] fn swizzle() { let g = Gray_v08(10u8); assert_eq!(10, g.v); assert_eq!(10, g.0); } rgb-0.8.50/src/formats/gray_a.rs000064400000000000000000000016751046102023000145530ustar 00000000000000#[repr(C)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "defmt-03", derive(defmt::Format))] #[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Ord, PartialOrd, Hash)] /// A `Value (brightness) + Alpha` pixel (rgb crate v0.9) /// /// This pixel is commonly used for grayscale images. pub struct GrayA { /// Value - the brightness component. May be luma or luminance. pub v: T, /// Alpha Component pub a: A, } impl GrayA { /// Reads the `.v` field /// /// This function isn't necessary, but it is forwards-compatible with the next major version of the RGB crate. pub fn value(self) -> T { self.v } /// Exposes the `.v` field for writing /// /// This function isn't necessary, but it is forwards-compatible with the next major version of the RGB crate. pub fn value_mut(&mut self) -> &mut T { &mut self.v } } rgb-0.8.50/src/formats/gray_alpha.rs000064400000000000000000000031661046102023000154150ustar 00000000000000use crate::formats::gray_a::GrayA; use core::ops::Deref; #[repr(C)] #[cfg_attr(feature = "unstable-experimental", deprecated(note = "renamed to GrayA"))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "defmt-03", derive(defmt::Format))] #[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Ord, PartialOrd, Hash)] /// A pixel for grayscale value + alpha components (rgb crate v0.8) /// /// Through a `Deref` hack it renames the fields from `.0` and `.1` /// to `.v` (value) and `.a` (alpha) #[allow(non_camel_case_types)] pub struct GrayAlpha_v08( /// Grayscale Component /// /// This field has been renamed to `.v` pub T, /// Alpha Component. This field has been renamed to `.a`. pub A, ); impl GrayAlpha_v08 { /// Reads the `.0` field /// /// This function isn't necessary, but it is forwards-compatible with the next major version of the RGB crate. pub fn value(self) -> T { self.0 } /// Exposes the `.0` field for writing /// /// This function isn't necessary, but it is forwards-compatible with the next major version of the RGB crate. pub fn value_mut(&mut self) -> &mut T { &mut self.0 } } impl Deref for GrayAlpha_v08 { type Target = GrayA; /// A trick that allows using `.v` and `.a` on the old `GrayAlpha` type. fn deref(&self) -> &GrayA { unsafe { &*(self as *const Self as *const GrayA::) } } } #[test] fn swizzle() { let g = GrayAlpha_v08(10u8, 20u8); assert_eq!(10, g.v); assert_eq!(20, g.a); } rgb-0.8.50/src/formats/grb.rs000064400000000000000000000007651046102023000140620ustar 00000000000000#[repr(C)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "defmt-03", derive(defmt::Format))] #[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Ord, PartialOrd, Hash)] /// A `Green + Red + Blue` pixel. /// /// # Examples /// /// ``` /// use rgb::Grb; /// /// let pixel: Grb = Grb { g: 0, r: 0, b: 0 }; /// ``` pub struct Grb { /// Green Component pub g: T, /// Red Component pub r: T, /// Blue Component pub b: T, } rgb-0.8.50/src/formats/rgb.rs000064400000000000000000000007651046102023000140620ustar 00000000000000#[repr(C)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "defmt-03", derive(defmt::Format))] #[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Ord, PartialOrd, Hash)] /// A `Red + Green + Blue` pixel. /// /// # Examples /// /// ``` /// use rgb::Rgb; /// /// let pixel: Rgb = Rgb { r: 0, g: 0, b: 0 }; /// ``` pub struct Rgb { /// Red Component pub r: T, /// Green Component pub g: T, /// Blue Component pub b: T, } rgb-0.8.50/src/formats/rgba.rs000064400000000000000000000010661046102023000142160ustar 00000000000000#[repr(C)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "defmt-03", derive(defmt::Format))] #[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Ord, PartialOrd, Hash)] /// A `Red + Green + Blue + Alpha` pixel. /// /// # Examples /// /// ``` /// use rgb::Rgba; /// /// let pixel: Rgba = Rgba { r: 0, g: 0, b: 0, a: 255 }; /// ``` pub struct Rgba { /// Red Component pub r: T, /// Green Component pub g: T, /// Blue Component pub b: T, /// Alpha Component pub a: A, } rgb-0.8.50/src/inherent_impls.rs000064400000000000000000000031531046102023000146470ustar 00000000000000use crate::{Abgr, Argb, Bgr, Bgra, Grb, Rgb, Rgba}; use crate::formats::gray_a::GrayA; use crate::formats::gray::Gray_v08; #[cfg(feature = "unstable-experimental")] use crate::formats::gray::Gray_v09; use crate::formats::gray_alpha::GrayAlpha_v08; macro_rules! inherent_impls { ($name:ident, $new_fn:ident, [$($field:tt $var:ident),*]) => { impl $name { #[doc=concat!("Creates a new [`", stringify!($name), "`] pixel type from its components.")] /// /// Alternatively, you can use struct literal syntax to /// create the new pixel type: ///```not_rust #[doc=concat!("use rgb::", stringify!($name), ";")] /// #[doc=concat!("let pixel = ", stringify!($name), " {", stringify!($($field: $var),*), "};")] ///``` pub const fn $new_fn($($var: T),*) -> Self { Self {$($field: $var),*} } } } } inherent_impls!(Rgb, new, [r red, g green, b blue]); inherent_impls!(Bgr, new_bgr, [b blue, g green, r red]); inherent_impls!(Grb, new_grb, [g green, r red, b blue]); inherent_impls!(Gray_v08, new, [0 value]); #[cfg(feature = "unstable-experimental")] inherent_impls!(Gray_v09, new, [v value]); inherent_impls!(Rgba, new, [r red, g green, b blue, a alpha]); inherent_impls!(Argb, new_argb, [a alpha, r red, g green, b blue]); inherent_impls!(Bgra, new_bgra, [b blue, g green, r red, a alpha]); inherent_impls!(Abgr, new_abgr, [a alpha, b blue, g green, r red]); inherent_impls!(GrayA, new, [v value, a alpha]); inherent_impls!(GrayAlpha_v08, new, [0 value, 1 alpha]); rgb-0.8.50/src/legacy/alt.rs000064400000000000000000000175571046102023000136700ustar 00000000000000use crate::legacy::internal::pixel::*; use core::slice; pub use crate::formats::gray::Gray_v08 as Gray; pub use crate::formats::gray_alpha::GrayAlpha_v08 as GrayAlpha; /// Renamed to `Bgra` #[doc(hidden)] pub use crate::formats::bgra::Bgra as BGRA; /// Renamed to `Bgr` #[doc(hidden)] pub use crate::formats::bgr::Bgr as BGR; /// Renamed to `Abgr` #[doc(hidden)] pub use crate::formats::abgr::Abgr as ABGR; /// Renamed to `Argb` #[doc(hidden)] pub use crate::formats::argb::Argb as ARGB; /// Renamed to `Grb` #[doc(hidden)] pub use crate::formats::grb::Grb as GRB; /// 8-bit BGR pub type BGR8 = crate::formats::bgr::Bgr; /// 16-bit BGR in machine's native endian pub type BGR16 = crate::formats::bgr::Bgr; /// 8-bit BGRA pub type BGRA8 = crate::formats::bgra::Bgra; /// 8-bit ABGR, alpha is first. 0 = transparent, 255 = opaque. pub type ABGR8 = crate::formats::abgr::Abgr; /// 8-bit ARGB, alpha is first. 0 = transparent, 255 = opaque. pub type ARGB8 = crate::Argb; /// 16-bit BGR in machine's native endian pub type BGRA16 = crate::formats::bgra::Bgra; /// 16-bit ABGR in machine's native endian. 0 = transparent, 65535 = opaque. pub type ABGR16 = crate::formats::abgr::Abgr; /// 16-bit ARGB in machine's native endian. 0 = transparent, 65535 = opaque. pub type ARGB16 = crate::Argb; /// 8-bit GRB pub type GRB8 = crate::formats::grb::Grb; /// 8-bit gray #[deprecated(note = "Refer to ::rgb::alt::Gray directly (this type alias will change in the next major version)")] pub type GRAY8 = Gray; /// 16-bit gray in machine's native endian #[deprecated(note = "Refer to ::rgb::alt::Gray directly (this type alias will change in the next major version)")] pub type GRAY16 = Gray; /// 8-bit gray with alpha in machine's native endian #[deprecated(note = "Refer to ::rgb::alt::GrayAlpha directly (this type alias will change in the next major version)")] pub type GRAYA8 = GrayAlpha; /// 16-bit gray with alpha in machine's native endian #[deprecated(note = "Refer to ::rgb::alt::GrayAlpha directly (this type alias will change in the next major version)")] pub type GRAYA16 = GrayAlpha; #[cfg(not(feature = "unstable-experimental"))] impl core::ops::Deref for Gray { type Target = T; #[inline(always)] fn deref(&self) -> &T { &self.0 } } impl From for Gray { #[inline(always)] fn from(component: T) -> Self { Gray(component) } } impl GrayAlpha { /// Copy `Gray` component out of the `GrayAlpha` struct #[inline(always)] pub fn gray(&self) -> Gray { Gray(self.0.clone()) } } impl GrayAlpha { /// Provide a mutable view of only `Gray` component (leaving out alpha). #[inline(always)] pub fn gray_mut(&mut self) -> &mut Gray { unsafe { &mut *(self as *mut _ as *mut _) } } } impl GrayAlpha { /// Create a new `GrayAlpha` with the new alpha value, but same gray value #[doc(hidden)] #[deprecated(note = "use .with_alpha(a) instead; this will become a getter in the future")] pub fn alpha(&self, a: A) -> Self { self.with_alpha(a) } /// Create a new `GrayAlpha` with the new alpha value, but same gray value #[inline(always)] pub fn with_alpha(&self, a: A) -> Self { Self(self.0, a) } /// Create a new `GrayAlpha` with a new alpha value created by the callback. #[inline(always)] pub fn map_alpha(&self, f: F) -> GrayAlpha where F: FnOnce(A) -> B { GrayAlpha(self.0, f(self.1.clone())) } /// Create new `GrayAlpha` with the same alpha value, but different `Gray` value #[inline(always)] pub fn map_gray(&self, f: F) -> GrayAlpha where F: FnOnce(T) -> U, U: Clone, B: From + Clone { GrayAlpha(f(self.0), self.1.clone().into()) } } impl ComponentMap, T, B> for Gray { #[inline(always)] fn map(&self, mut f: F) -> Gray where F: FnMut(T) -> B { Gray(f(self.0)) } } impl ColorComponentMap, T, B> for Gray { #[inline(always)] fn map_colors(&self, mut f: F) -> Gray where F: FnMut(T) -> B { Gray(f(self.0)) } } impl ComponentMap, T, B> for GrayAlpha { #[inline(always)] fn map(&self, mut f: F) -> GrayAlpha where F: FnMut(T) -> B { GrayAlpha(f(self.0), f(self.1)) } } impl ColorComponentMap, T, B> for GrayAlpha { #[inline(always)] fn map_colors(&self, mut f: F) -> GrayAlpha where F: FnMut(T) -> B { GrayAlpha(f(self.0), self.1) } } impl ComponentSlice for GrayAlpha { #[inline(always)] fn as_slice(&self) -> &[T] { unsafe { slice::from_raw_parts(self as *const Self as *const T, 2) } } #[inline(always)] fn as_mut_slice(&mut self) -> &mut [T] { unsafe { slice::from_raw_parts_mut(self as *mut Self as *mut T, 2) } } } impl ComponentSlice for [GrayAlpha] { #[inline] fn as_slice(&self) -> &[T] { unsafe { slice::from_raw_parts(self.as_ptr().cast(), self.len() * 2) } } #[inline] fn as_mut_slice(&mut self) -> &mut [T] { unsafe { slice::from_raw_parts_mut(self.as_ptr() as *mut _, self.len() * 2) } } } impl ComponentSlice for Gray { #[inline(always)] fn as_slice(&self) -> &[T] { slice::from_ref(&self.0) } #[inline(always)] fn as_mut_slice(&mut self) -> &mut [T] { slice::from_mut(&mut self.0) } } impl ComponentSlice for [Gray] { #[inline] fn as_slice(&self) -> &[T] { unsafe { slice::from_raw_parts(self.as_ptr().cast(), self.len()) } } #[inline] fn as_mut_slice(&mut self) -> &mut [T] { unsafe { slice::from_raw_parts_mut(self.as_ptr() as *mut _, self.len()) } } } /// Assumes 255 is opaque impl From> for GrayAlpha { #[inline(always)] fn from(other: Gray) -> Self { GrayAlpha(other.0, 0xFF) } } /// Assumes 65535 is opaque impl From> for GrayAlpha { #[inline(always)] fn from(other: Gray) -> Self { GrayAlpha(other.0, 0xFFFF) } } #[test] #[allow(deprecated)] fn gray() { let rgb: crate::RGB<_> = Gray(1).into(); assert_eq!(rgb.r, 1); assert_eq!(rgb.g, 1); assert_eq!(rgb.b, 1); let rgba: crate::RGBA<_> = Gray(1u8).into(); assert_eq!(rgba.r, 1); assert_eq!(rgba.g, 1); assert_eq!(rgba.b, 1); assert_eq!(rgba.a, 255); let g: GRAY8 = 200.into(); let g = g.map(|c| c / 2); #[cfg(not(feature = "unstable-experimental"))] assert_eq!(110, *g + 10); #[cfg(not(feature = "unstable-experimental"))] assert_eq!(110, 10 + Gray(100).as_ref()); let ga: GRAYA8 = GrayAlpha(1, 2); assert_eq!(ga.gray(), Gray::new(1)); let mut g2 = ga.clone(); *g2.gray_mut() = Gray(3); assert_eq!(g2.map_gray(|g| g + 1), GRAYA8::new(4, 2)); assert_eq!(g2.map(|g| g + 1), GrayAlpha(4, 3)); assert_eq!(g2.0, 3); assert_eq!(g2.as_slice(), &[3, 2]); assert_eq!(g2.as_mut_slice(), &[3, 2]); assert_eq!(g2.with_alpha(13), GrayAlpha(3, 13)); assert_eq!(g2.map_alpha(|x| x + 3), GrayAlpha(3, 5)); assert_eq!((&[Gray(1u16), Gray(2)][..]).as_slice(), &[1, 2]); assert_eq!((&[GrayAlpha(1u16, 2), GrayAlpha(3, 4)][..]).as_slice(), &[1, 2, 3, 4]); let rgba: crate::RGBA<_> = ga.into(); assert_eq!(rgba.r, 1); assert_eq!(rgba.g, 1); assert_eq!(rgba.b, 1); assert_eq!(rgba.a, 2); let ga: GRAYA16 = GrayAlpha(1, 2); let rgba: crate::RGBA = ga.into(); assert_eq!(rgba.r, 1); assert_eq!(rgba.g, 1); assert_eq!(rgba.b, 1); assert_eq!(rgba.a, 2); } rgb-0.8.50/src/legacy/internal/convert/array.rs000064400000000000000000000050111046102023000175000ustar 00000000000000use crate::alt::ARGB; use crate::alt::{BGR, BGRA}; use crate::{RGB, RGBA}; impl From<[T; 3]> for RGB { #[inline(always)] fn from(other: [T; 3]) -> Self { Self { r: other[0], g: other[1], b: other[2], } } } impl From> for [T; 3] { #[inline(always)] fn from(value: RGB) -> Self { [value.r, value.g, value.b] } } impl From<[T; 4]> for RGBA { #[inline(always)] fn from(other: [T; 4]) -> Self { Self { r: other[0], g: other[1], b: other[2], a: other[3], } } } impl From> for [T; 4] { #[inline(always)] fn from(value: RGBA) -> Self { [value.r, value.g, value.b, value.a] } } impl From<[T; 4]> for ARGB { #[inline(always)] fn from(other: [T; 4]) -> Self { Self { a: other[0], r: other[1], g: other[2], b: other[3], } } } impl Into<[T; 4]> for ARGB { #[inline(always)] fn into(self) -> [T; 4] { [self.a, self.r, self.g, self.b] } } impl From<[T; 3]> for BGR { #[inline(always)] fn from(other: [T; 3]) -> Self { Self { b: other[0], g: other[1], r: other[2], } } } impl From> for [T; 3] { #[inline(always)] fn from(value: BGR) -> Self { [value.b, value.g, value.r] } } impl From<[T; 4]> for BGRA { #[inline(always)] fn from(other: [T; 4]) -> Self { Self { b: other[0], g: other[1], r: other[2], a: other[3], } } } impl From> for [T; 4] { #[inline(always)] fn from(value: BGRA) -> Self { [value.b, value.g, value.r, value.a] } } #[test] #[allow(deprecated)] fn convert_array() { use crate::alt::{BGR8, BGRA8}; use crate::{RGB8, RGBA8}; assert_eq!(RGB8::from([1, 2, 3]), RGB8::new(1, 2, 3)); assert_eq!(Into::<[u8; 3]>::into(RGB8::new(1, 2, 3)), [1, 2, 3]); assert_eq!(RGBA8::from([1, 2, 3, 4]), RGBA8::new(1, 2, 3, 4)); assert_eq!(Into::<[u8; 4]>::into(RGBA8::new(1, 2, 3, 4)), [1, 2, 3, 4]); assert_eq!(BGR8::from([3, 2, 1]), BGR8::new(1, 2, 3)); assert_eq!(Into::<[u8; 3]>::into(BGR8::new(1, 2, 3)), [3, 2, 1]); assert_eq!(BGRA8::from([3, 2, 1, 4]), BGRA8::new(1, 2, 3, 4)); assert_eq!(Into::<[u8; 4]>::into(BGRA8::new(1, 2, 3, 4)), [3, 2, 1, 4]); } rgb-0.8.50/src/legacy/internal/convert/mod.rs000064400000000000000000000340761046102023000171560ustar 00000000000000use super::pixel::*; use crate::alt::*; use crate::{RGB, RGBA}; use core::{mem, slice}; mod array; mod tuple; /// Use [`::bytemuck::cast_slice()`] instead. /// /// Casts a slice of bytes into a slice of pixels, e.g. `[u8]` to `[RGB8]`. /// /// See also `FromSlice` pub trait AsPixels { /// Use [`::bytemuck::cast_slice()`] instead. /// /// Reinterpret the slice as a read-only/shared slice of pixels. /// Multiple consecutive elements in the slice are intepreted as a single pixel /// (depending on format, e.g. 3 for RGB, 4 for RGBA). /// /// Leftover elements are ignored if the slice isn't evenly divisible into pixels. /// /// Use this method only when the type is known from context. /// See also `FromSlice`. fn as_pixels(&self) -> &[PixelType]; /// Use [`::bytemuck::cast_slice_mut()`] instead. /// /// Reinterpret the slice as a mutable/exclusive slice of pixels. /// Multiple consecutive elements in the slice are intepreted as a single pixel /// (depending on format, e.g. 3 for RGB, 4 for RGBA). /// /// Leftover elements are ignored if the slice isn't evenly divisible into pixels. /// /// Use this method only when the type is known from context. /// See also `FromSlice`. fn as_pixels_mut(&mut self) -> &mut [PixelType]; } macro_rules! as_pixels_impl { ($typ:ident, $elems:expr) => { impl AsPixels<$typ> for [T] { fn as_pixels(&self) -> &[$typ] { unsafe { slice::from_raw_parts(self.as_ptr() as *const _, self.len() / $elems) } } fn as_pixels_mut(&mut self) -> &mut [$typ] { unsafe { slice::from_raw_parts_mut(self.as_mut_ptr() as *mut _, self.len() / $elems) } } } }; } as_pixels_impl! {RGB, 3} as_pixels_impl! {RGBA, 4} as_pixels_impl! {BGR, 3} as_pixels_impl! {BGRA, 4} as_pixels_impl! {GRB, 3} as_pixels_impl! {Gray, 1} as_pixels_impl! {GrayAlpha, 2} as_pixels_impl! {ARGB, 4} as_pixels_impl! {ABGR, 4} /// Use [`::bytemuck::cast_slice()`] or [`::bytemuck::from_bytes()`] to convert /// /// Cast a slice of component values (bytes) as a slice of RGB/RGBA pixels /// /// If there's any incomplete pixel at the end of the slice it is ignored. pub trait FromSlice { /// Reinterpert slice as RGB pixels fn as_rgb(&self) -> &[RGB]; /// Reinterpert slice as RGBA pixels fn as_rgba(&self) -> &[RGBA]; /// Reinterpert slice as alpha-first ARGB pixels fn as_argb(&self) -> &[ARGB]; /// Reinterpert mutable slice as RGB pixels fn as_rgb_mut(&mut self) -> &mut [RGB]; /// Reinterpert mutable slice as RGBA pixels fn as_rgba_mut(&mut self) -> &mut [RGBA]; /// Reinterpert mutable slice as alpha-first ARGB pixels fn as_argb_mut(&mut self) -> &mut [ARGB]; /// Reinterpert mutable slice as grayscale pixels fn as_gray(&self) -> &[Gray]; /// Reinterpert mutable slice as grayscale pixels with alpha fn as_gray_alpha(&self) -> &[GrayAlpha]; /// Reinterpert mutable slice as grayscale pixels fn as_gray_mut(&mut self) -> &mut [Gray]; /// Reinterpert mutable slice as grayscale pixels with alpha fn as_gray_alpha_mut(&mut self) -> &mut [GrayAlpha]; /// Reinterpert slice as reverse-order BGR pixels fn as_bgr(&self) -> &[BGR]; /// Reinterpert slice as reverse-order BGRA pixels fn as_bgra(&self) -> &[BGRA]; /// Reinterpert slice as reverse-order ABGR pixels fn as_abgr(&self) -> &[ABGR]; /// Reinterpert ntable slice as reverse-order BGR pixels fn as_bgr_mut(&mut self) -> &mut [BGR]; /// Reinterpert mutable slice as reverse-order alpha-last BGRA pixels fn as_bgra_mut(&mut self) -> &mut [BGRA]; /// Reinterpert mutable slice as reverse-order alpha-first ABGR pixels fn as_abgr_mut(&mut self) -> &mut [ABGR]; } impl FromSlice for [T] { #[inline] fn as_rgb(&self) -> &[RGB] { unsafe { from_items_to_struct(self) } } #[inline] fn as_rgba(&self) -> &[RGBA] { unsafe { from_items_to_struct(self) } } #[inline] fn as_argb(&self) -> &[ARGB] { unsafe { from_items_to_struct(self) } } #[inline] fn as_rgb_mut(&mut self) -> &mut [RGB] { unsafe { from_items_to_struct_mut(self) } } #[inline] fn as_rgba_mut(&mut self) -> &mut [RGBA] { unsafe { from_items_to_struct_mut(self) } } #[inline] fn as_argb_mut(&mut self) -> &mut [ARGB] { unsafe { from_items_to_struct_mut(self) } } #[inline] fn as_gray(&self) -> &[Gray] { unsafe { from_items_to_struct(self) } } #[inline] fn as_gray_alpha(&self) -> &[GrayAlpha] { unsafe { from_items_to_struct(self) } } #[inline] fn as_gray_mut(&mut self) -> &mut [Gray] { unsafe { from_items_to_struct_mut(self) } } #[inline] fn as_gray_alpha_mut(&mut self) -> &mut [GrayAlpha] { unsafe { from_items_to_struct_mut(self) } } #[inline] fn as_bgr(&self) -> &[BGR] { unsafe { from_items_to_struct(self) } } #[inline] fn as_abgr(&self) -> &[ABGR] { unsafe { from_items_to_struct(self) } } #[inline] fn as_bgra(&self) -> &[BGRA] { unsafe { from_items_to_struct(self) } } #[inline] fn as_bgr_mut(&mut self) -> &mut [BGR] { unsafe { from_items_to_struct_mut(self) } } #[inline] fn as_bgra_mut(&mut self) -> &mut [BGRA] { unsafe { from_items_to_struct_mut(self) } } #[inline] fn as_abgr_mut(&mut self) -> &mut [ABGR] { unsafe { from_items_to_struct_mut(self) } } } #[inline(always)] unsafe fn from_items_to_struct(from: &[F]) -> &[T] { debug_assert_eq!(0, mem::size_of::() % mem::size_of::()); let len = from.len() / (mem::size_of::() / mem::size_of::()); slice::from_raw_parts(from.as_ptr().cast::(), len) } #[inline(always)] unsafe fn from_items_to_struct_mut(from: &mut [F]) -> &mut [T] { debug_assert_eq!(0, mem::size_of::() % mem::size_of::()); let len = from.len() / (mem::size_of::() / mem::size_of::()); slice::from_raw_parts_mut(from.as_mut_ptr().cast::(), len) } macro_rules! rgb_impl_from { ($typename:ident, $from:ty, $to:ty) => { impl From<$typename<$from>> for $typename<$to> { #[inline(always)] fn from(other: $typename<$from>) -> Self { other.map(core::convert::Into::into) } } }; } rgb_impl_from! {RGB, u8,i16} rgb_impl_from! {RGB, u8,i32} rgb_impl_from! {RGB, u8,u16} rgb_impl_from! {RGB, u8,u32} rgb_impl_from! {RGB, u16,i32} rgb_impl_from! {RGB, u16,u32} rgb_impl_from! {RGB, u16,u64} rgb_impl_from! {RGB, u8,f32} rgb_impl_from! {RGB, u8,f64} rgb_impl_from! {RGB, u16,f32} rgb_impl_from! {RGB, u16,f64} rgb_impl_from! {RGB, i16,f32} rgb_impl_from! {RGB, i16,f64} rgb_impl_from! {RGB, i32,f64} rgb_impl_from! {RGB, f32,f64} rgb_impl_from! {RGBA, u16,i32} rgb_impl_from! {RGBA, u16,u32} rgb_impl_from! {RGBA, u16,u64} rgb_impl_from! {RGBA, u8,i16} rgb_impl_from! {RGBA, u8,u16} rgb_impl_from! {RGBA, u8,u32} rgb_impl_from! {RGBA, u8,f32} rgb_impl_from! {RGBA, u8,f64} rgb_impl_from! {RGBA, u16,f32} rgb_impl_from! {RGBA, u16,f64} rgb_impl_from! {RGBA, i16,f32} rgb_impl_from! {RGBA, i16,f64} rgb_impl_from! {RGBA, i32,f64} rgb_impl_from! {RGBA, f32,f64} macro_rules! reorder_impl_from { (@rgb $t1:ident, $t2:ident) => { reorder_impl_from!(@once $t1, $t2, r, g, b); reorder_impl_from!(@once $t2, $t1, r, g, b); }; (@rgba $t1:ident, $t2:ident) => { reorder_impl_from!(@once $t1, $t2, r, g, b, a); reorder_impl_from!(@once $t2, $t1, r, g, b, a); }; (@once $t1:ident, $t2:ident, $($component:ident),+) => { impl From<$t1> for $t2 where T: ::core::clone::Clone { fn from(other: $t1) -> Self { let $t1 { $($component),+ } = other; Self { $($component),+ } } } } } reorder_impl_from!(@rgba RGBA, ARGB); reorder_impl_from!(@rgba ABGR, ARGB); reorder_impl_from!(@rgba BGRA, ARGB); reorder_impl_from!(@rgba BGRA, ABGR); reorder_impl_from!(@rgb RGB, BGR); reorder_impl_from!(@rgba BGRA, RGBA); reorder_impl_from!(@rgba ABGR, RGBA); reorder_impl_from!(@rgb RGB, GRB); impl From> for RGB { #[inline(always)] fn from(other: Gray) -> Self { Self { r: other.0.clone(), g: other.0.clone(), b: other.0, } } } impl From> for RGBA { #[inline(always)] fn from(other: Gray) -> Self { Self { r: other.0.clone(), g: other.0.clone(), b: other.0, a: 255, } } } impl From> for RGBA { #[inline(always)] fn from(other: GrayAlpha) -> Self { Self { r: other.0.clone(), g: other.0.clone(), b: other.0, a: other.1, } } } #[cfg(not(feature = "unstable-experimental"))] impl AsRef for Gray { #[inline(always)] fn as_ref(&self) -> &T { &self.0 } } #[cfg(not(feature = "unstable-experimental"))] impl AsRef<[T]> for RGB { #[inline(always)] fn as_ref(&self) -> &[T] { self.as_slice() } } #[cfg(feature = "unstable-experimental")] impl AsRef<[T; 3]> for RGB { fn as_ref(&self) -> &[T; 3] { unsafe { &*(self as *const Self).cast() } } } #[cfg(not(feature = "unstable-experimental"))] impl AsRef<[T]> for RGBA { #[inline(always)] fn as_ref(&self) -> &[T] { self.as_slice() } } #[cfg(feature = "unstable-experimental")] impl AsRef<[T; 4]> for RGBA { fn as_ref(&self) -> &[T; 4] { unsafe { &*(self as *const Self).cast() } } } impl AsRef<[T; 4]> for ARGB { fn as_ref(&self) -> &[T; 4] { unsafe { &*(self as *const Self).cast() } } } impl AsRef<[T; 4]> for BGRA { fn as_ref(&self) -> &[T; 4] { unsafe { &*(self as *const Self).cast() } } } impl AsRef<[T; 4]> for ABGR { fn as_ref(&self) -> &[T; 4] { unsafe { &*(self as *const Self).cast() } } } #[cfg(not(feature = "unstable-experimental"))] impl AsRef for GrayAlpha { #[inline(always)] fn as_ref(&self) -> &T { &self.0 } } #[cfg(feature = "unstable-experimental")] impl AsRef<[T; 2]> for GrayAlpha { fn as_ref(&self) -> &[T; 2] { unsafe { &*(self as *const Self).cast() } } } #[cfg(not(feature = "unstable-experimental"))] impl AsMut for Gray { #[inline(always)] fn as_mut(&mut self) -> &mut T { &mut self.0 } } #[cfg(not(feature = "unstable-experimental"))] impl AsMut<[T]> for RGB { #[inline(always)] fn as_mut(&mut self) -> &mut [T] { self.as_mut_slice() } } #[cfg(feature = "unstable-experimental")] impl AsMut<[T; 3]> for RGB { fn as_mut(&mut self) -> &mut [T; 3] { unsafe { &mut *(self as *mut Self).cast() } } } #[cfg(not(feature = "unstable-experimental"))] impl AsMut<[T]> for RGBA { #[inline(always)] fn as_mut(&mut self) -> &mut [T] { self.as_mut_slice() } } #[cfg(feature = "unstable-experimental")] impl AsMut<[T; 4]> for RGBA { fn as_mut(&mut self) -> &mut [T; 4] { unsafe { &mut *(self as *mut Self).cast() } } } #[cfg(not(feature = "unstable-experimental"))] impl AsMut for GrayAlpha { #[inline(always)] fn as_mut(&mut self) -> &mut T { &mut self.0 } } #[cfg(feature = "unstable-experimental")] impl AsMut<[T; 2]> for GrayAlpha { fn as_mut(&mut self) -> &mut [T; 2] { unsafe { &mut *(self as *mut Self).cast() } } } #[test] fn argb_converts() { let argb = ARGB { a: 0xffu8, r: 0xfa, g: 0xfb, b: 0xfc }; let rgba = RGBA { a: 0xffu8, r: 0xfa, g: 0xfb, b: 0xfc }; assert_eq!(RGBA::from(argb), rgba); assert_eq!(ARGB::from(rgba), argb); assert_eq!(rgba.rgb(), argb.rgb()); let bgra = BGRA { a: 0xffu8, r: 0x1f, g: 0x2f, b: 0x3f }; let abgr = ABGR { a: 0xffu8, r: 0x1f, g: 0x2f, b: 0x3f }; assert_eq!(BGRA::from(abgr), bgra); assert_eq!(ABGR::from(bgra), abgr); } #[test] fn converts() { assert_eq!([1,2].as_gray(), [Gray::new(1), Gray::new(2)]); assert_eq!([3].as_gray_mut(), [Gray::new(3)]); assert_eq!([1,2].as_gray_alpha(), [GrayAlpha::new(1, 2)]); // excess bytes are ignored assert_eq!([1,2,3].as_gray_alpha_mut(), [GrayAlpha::new(1, 2)]); assert_eq!([1,2,3,4].as_gray_alpha_mut(), [GrayAlpha::new(1, 2), GrayAlpha::new(3, 4)]); assert_eq!(RGBA::new(1u8,2,3,255), RGB::new(1u8,2,3).into()); assert_eq!(RGBA::new(1u16,2,3,65535), RGB::new(1u16,2,3).into()); assert_eq!(BGRA{r:1u8,g:2u8,b:3u8,a:255u8}, BGR{r:1u8,g:2u8,b:3u8}.into()); assert_eq!(BGRA{r:1u8,g:2u8,b:3u8,a:255u8}, RGB{r:1u8,g:2u8,b:3u8}.into()); assert_eq!(RGBA {r:1u8,g:2,b:3,a:4u8}, BGRA{r:1u8,g:2u8,b:3u8,a:4u8}.into()); assert_eq!(BGR {r:1u8,g:2,b:3u8}, RGB {r:1u8,g:2,b:3u8}.into()); assert_eq!(RGB {r:1u16,g:0x5678,b:0xABCDu16}, BGR {r:1u16,g:0x5678,b:0xABCDu16}.into()); assert_eq!(BGR {r:0x1234567u32,g:2,b:3u32}, RGB {r:0x1234567u32,g:2,b:3u32}.into()); assert_eq!(&[1u8,2,3,4], RGBA {r:1u8,g:2,b:3,a:4u8}.as_slice()); assert_eq!(&[1u8,2,3,4], RGBA {r:1u8,g:2,b:3,a:4u8}.as_ref()); assert_eq!(&[1u8,2,3], RGB {r:1u8,g:2,b:3}.as_slice()); assert_eq!(&[1u8,2,3], RGB {r:1u8,g:2,b:3}.as_ref()); assert_eq!(&[1u8,2,3], RGB {r:1u8,g:2,b:3}.as_mut_slice()); assert_eq!(&[1u8,2,3], RGB {r:1u8,g:2,b:3}.as_mut()); } #[test] #[cfg(feature = "unstable-experimental")] fn as_refs() { let mut r = RGBA::new(1u8,2,3,4u8); assert_eq!(&[1,2,3,4], AsRef::<[u8; 4]>::as_ref(&r)); assert_eq!([1,2,3,4], *AsMut::<[u8; 4]>::as_mut(&mut r)); let mut r = GrayAlpha::new(1u8,4u8); assert_eq!(&[1,4], AsRef::<[u8; 2]>::as_ref(&r)); assert_eq!([1,4], *AsMut::<[u8; 2]>::as_mut(&mut r)); } rgb-0.8.50/src/legacy/internal/convert/tuple.rs000064400000000000000000000052621046102023000175230ustar 00000000000000 use crate::formats::gray::Gray_v08; use crate::{Abgr, Argb, Bgr, Bgra, Grb, Rgb, Rgba, alt::GrayAlpha}; #[cfg(feature = "unstable-experimental")] use crate::GrayA; #[cfg(feature = "unstable-experimental")] use crate::formats::gray::Gray_v09; macro_rules! tuple_conversion { ($name:ident, 1, [$($bit:tt:$num:tt),*]) => { impl From<$name> for (S,) where R: Into { fn from(value: $name) -> Self { ($(value.$bit.into()),*,) } } }; ($name:ident, 2, [$($bit:tt:$num:tt),*]) => { impl From<$name> for (S, S) where R: Into { fn from(value: $name) -> Self { ($(value.$bit.into()),*) } } impl From<(R, R)> for $name where R: Into { fn from(value: (R, R)) -> Self { Self{$($bit: value.$num.into()),*} } } }; ($name:ident, 3, [$($bit:tt:$num:tt),*]) => { impl From<$name> for (S, S, S) where R: Into { fn from(value: $name) -> Self { ($(value.$bit.into()),*) } } impl From<(R, R, R)> for $name where R: Into { fn from(value: (R, R, R)) -> Self { Self{$($bit: value.$num.into()),*} } } }; ($name:ident, 4, [$($bit:tt:$num:tt),*]) => { impl From<$name> for (S, S, S, S) where R: Into { fn from(value: $name) -> Self { ($(value.$bit.into()),*) } } impl From<(R, R, R, R)> for $name where R: Into { fn from(value: (R, R, R, R)) -> Self { Self{$($bit: value.$num.into()),*} } } }; } tuple_conversion!(Rgb, 3, [r:0, g:1, b:2]); tuple_conversion!(Bgr, 3, [b:0, g:1, r:2]); tuple_conversion!(Grb, 3, [g:0, r:1, b:2]); #[cfg(feature = "unstable-experimental")] tuple_conversion!(Gray_v09, 1, [v:0]); tuple_conversion!(Rgba, 4, [r:0, g:1, b:2, a:3]); tuple_conversion!(Argb, 4, [a:0, r:1, g:2, b:3]); tuple_conversion!(Bgra, 4, [b:0, g:1, r:2, a:3]); tuple_conversion!(Abgr, 4, [a:0, b:1, g:2, r:3]); #[cfg(feature = "unstable-experimental")] tuple_conversion!(GrayA, 2, [v:0, a:1]); tuple_conversion!(Gray_v08, 1, [0:0]); tuple_conversion!(GrayAlpha, 2, [0:0, 1:1]); #[test] fn converts() { assert_eq!((1,2,3), Rgb {r:1u8,g:2,b:3}.into()); assert_eq!(Rgb {r:1u8,g:2,b:3}, (1,2,3).into()); assert_eq!((1,2,3,4), Rgba {r:1,g:2,b:3,a:4}.into()); assert_eq!(Rgba {r:1u8,g:2,b:3,a:4}, (1,2,3,4).into()); assert_eq!(Bgra {r:1u8,g:2,b:3,a:4}, (3,2,1,4).into()); assert_eq!(Bgr {r:1u8,g:2,b:3}, (3,2,1).into()); } rgb-0.8.50/src/legacy/internal/ops.rs000064400000000000000000000361341046102023000155150ustar 00000000000000use crate::formats::gray::Gray_v08 as Gray; use super::pixel::ComponentMap; use crate::alt::GrayAlpha; use crate::alt::ARGB; use crate::alt::GRB; use crate::{RGB, RGBA}; use core::iter::Sum; use core::ops::*; #[cfg(feature = "checked_fns")] macro_rules! impl_struct_checked { ($ty:ident, $field_ty:ident, => $($field:tt)+) => { impl $ty<$field_ty> { /// `px.checked_add(px)` #[inline(always)] pub fn checked_add(self, rhs: $ty<$field_ty>) -> Option { Some($ty { $( $field: self.$field.checked_add(rhs.$field)?, )+ }) } /// `px.checked_sub(px)` #[inline(always)] pub fn checked_sub(self, rhs: $ty<$field_ty>) -> Option { Some($ty { $( $field: self.$field.checked_sub(rhs.$field)?, )+ }) } } } } #[cfg(not(feature = "checked_fns"))] macro_rules! impl_struct_checked { ($ty:ident, $field_ty:ident, => $($field:tt)+) => {}; } macro_rules! impl_struct_ops_opaque { ($ty:ident => $($field:tt)+) => { /// `px + px` impl Add for $ty { type Output = $ty<::Output>; #[inline(always)] fn add(self, other: $ty) -> Self::Output { $ty { $( $field: self.$field + other.$field, )+ } } } /// `px + px` impl AddAssign for $ty where T: Add + Copy { #[inline(always)] fn add_assign(&mut self, other: $ty) { *self = Self { $( $field: self.$field + other.$field, )+ }; } } /// `px * px` impl Mul for $ty { type Output = $ty<::Output>; #[inline(always)] fn mul(self, other: $ty) -> Self::Output { $ty { $( $field: self.$field * other.$field, )+ } } } /// `px * px` impl MulAssign for $ty where T: Mul + Copy { #[inline(always)] fn mul_assign(&mut self, other: $ty) { *self = Self { $( $field: self.$field * other.$field, )+ }; } } /// `px - px` impl Sub for $ty { type Output = $ty<::Output>; #[inline(always)] fn sub(self, other: $ty) -> Self::Output { $ty { $( $field: self.$field - other.$field, )+ } } } /// `px - px` impl SubAssign for $ty where T: Sub + Copy { #[inline(always)] fn sub_assign(&mut self, other: $ty) { *self = Self { $( $field: self.$field - other.$field, )+ }; } } impl Sum<$ty> for $ty where T: Default + Add { #[inline(always)] fn sum>(iter: I) -> Self { iter.fold($ty::default(), Add::add) } } impl_struct_checked!($ty, u8, => $($field)+); impl_struct_checked!($ty, u16, => $($field)+); impl_struct_checked!($ty, u32, => $($field)+); impl_struct_checked!($ty, u64, => $($field)+); impl_struct_checked!($ty, i8, => $($field)+); impl_struct_checked!($ty, i16, => $($field)+); impl_struct_checked!($ty, i32, => $($field)+); impl_struct_checked!($ty, i64, => $($field)+); }; } macro_rules! impl_struct_ops_alpha { ($ty:ident => $($field:tt)+) => { /// `px + px` impl Add for $ty { type Output = $ty<::Output, ::Output>; #[inline(always)] fn add(self, other: $ty) -> Self::Output { $ty { $( $field: self.$field + other.$field, )+ } } } /// `px + px` impl AddAssign for $ty where T: Add + Copy, A: Add + Copy { #[inline(always)] fn add_assign(&mut self, other: $ty) { *self = Self { $( $field: self.$field + other.$field, )+ }; } } /// `px - px` impl Sub for $ty { type Output = $ty<::Output, ::Output>; #[inline(always)] fn sub(self, other: $ty) -> Self::Output { $ty { $( $field: self.$field - other.$field, )+ } } } /// `px - px` impl SubAssign for $ty where T: Sub + Copy, A: Sub + Copy { #[inline(always)] fn sub_assign(&mut self, other: $ty) { *self = Self { $( $field: self.$field - other.$field, )+ }; } } impl Sum<$ty> for $ty where T: Default + Add, A: Default + Add { #[inline(always)] fn sum>(iter: I) -> Self { iter.fold($ty::default(), Add::add) } } impl_struct_checked!($ty, u8, => $($field)+); impl_struct_checked!($ty, u16, => $($field)+); impl_struct_checked!($ty, u32, => $($field)+); impl_struct_checked!($ty, u64, => $($field)+); impl_struct_checked!($ty, i8, => $($field)+); impl_struct_checked!($ty, i16, => $($field)+); impl_struct_checked!($ty, i32, => $($field)+); impl_struct_checked!($ty, i64, => $($field)+); }; } macro_rules! impl_scalar { ($ty:ident) => { /// `px - 1` impl Sub for $ty where T: Copy + Sub { type Output = $ty<::Output>; #[inline(always)] fn sub(self, r: T) -> Self::Output { self.map(|l| l - r) } } /// `px - 1` impl SubAssign for $ty where T: Copy + Sub { #[inline(always)] fn sub_assign(&mut self, r: T) { *self = self.map(|l| l - r); } } /// `px + 1` impl Add for $ty where T: Copy + Add { type Output = $ty; #[inline(always)] fn add(self, r: T) -> Self::Output { self.map(|l| l + r) } } /// `px + 1` impl AddAssign for $ty where T: Copy + Add { #[inline(always)] fn add_assign(&mut self, r: T) { *self = self.map(|l| l + r); } } /// `px * 1` impl Mul for $ty where T: Copy + Mul { type Output = $ty; #[inline(always)] fn mul(self, r: T) -> Self::Output { self.map(|l| l * r) } } /// `px * 1` impl MulAssign for $ty where T: Copy + Mul { #[inline(always)] fn mul_assign(&mut self, r: T) { *self = self.map(|l| l * r); } } /// `px / 1` impl Div for $ty where T: Copy + Div { type Output = $ty; #[inline(always)] fn div(self, r: T) -> Self::Output { self.map(|l| l / r) } } /// `px * 1` impl DivAssign for $ty where T: Copy + Div { #[inline(always)] fn div_assign(&mut self, r: T) { *self = self.map(|l| l / r); } } }; } impl_scalar! {RGB} impl_scalar! {RGBA} impl_scalar! {ARGB} impl_scalar! {GRB} impl_scalar! {Gray} impl_scalar! {GrayAlpha} impl_struct_ops_opaque! {RGB => r g b} impl_struct_ops_opaque! {GRB => g r b} impl_struct_ops_opaque! {Gray => 0} impl_struct_ops_alpha! {RGBA => r g b a} impl_struct_ops_alpha! {ARGB => a r g b} impl_struct_ops_alpha! {GrayAlpha => 0 1} #[cfg(test)] mod test { use super::*; use core::num::Wrapping; const WHITE_RGB: RGB = RGB::new(255, 255, 255); const BLACK_RGB: RGB = RGB::new(0, 0, 0); const RED_RGB: RGB = RGB::new(255, 0, 0); const GREEN_RGB: RGB = RGB::new(0, 255, 0); const BLUE_RGB: RGB = RGB::new(0, 0, 255); const WHITE_RGBA: RGBA = RGBA::new(255, 255, 255, 255); const BLACK_RGBA: RGBA = RGBA::new(0, 0, 0, 0); const RED_RGBA: RGBA = RGBA::new(255, 0, 0, 255); const GREEN_RGBA: RGBA = RGBA::new(0, 255, 0, 0); const BLUE_RGBA: RGBA = RGBA::new(0, 0, 255, 255); #[test] fn test_add() { assert_eq!(RGB::new(2,4,6), RGB::new(1,2,3) + RGB{r:1,g:2,b:3}); assert_eq!(RGB::new(2.,4.,6.), RGB::new(1.,3.,5.) + 1.); assert_eq!(RGBA::new_alpha(2f32,4.,6.,8u32), RGBA::new_alpha(1f32,2.,3.,4u32) + RGBA{r:1f32,g:2.0,b:3.0,a:4u32}); assert_eq!(RGBA::new(2i16,4,6,8), RGBA::new(1,3,5,7) + 1); assert_eq!(RGB::new(255, 255, 0), RED_RGB+GREEN_RGB); assert_eq!(RGB::new(255, 0, 0), RED_RGB+RGB::new(0, 0, 0)); assert_eq!(WHITE_RGB, BLACK_RGB + 255); assert_eq!(RGBA::new(255, 255, 0, 255), RED_RGBA+GREEN_RGBA); assert_eq!(RGBA::new(255, 0, 0, 255), RED_RGBA+RGBA::new(0, 0, 0, 0)); assert_eq!(WHITE_RGBA, BLACK_RGBA + 255); } #[test] #[cfg(feature = "checked_fns")] fn test_checked_add() { assert_eq!(WHITE_RGB.checked_add(WHITE_RGB), None); assert_eq!(RGB::::new(255, 255, 255).checked_add(RGB::::new(255, 0, 0)), None); assert_eq!(RGB::::new(255, 255, 255).checked_add(RGB::::new(0, 255, 0)), None); assert_eq!(RGB::::new(255, 255, 255).checked_add(RGB::::new(0, 0, 255)), None); assert_eq!(WHITE_RGBA.checked_add(BLACK_RGBA), Some(WHITE_RGBA)); assert_eq!(RGB::::new(-128, 2, 3).checked_add(RGB::::new(-1, 0, 0)), None); assert_eq!(RGB::::new(2, -128, 3).checked_add(RGB::::new(0, -1, 0)), None); assert_eq!(RGB::::new(2, 2, -128).checked_add(RGB::::new(0, 0, -1)), None); assert_eq!(RGB::::new(2, 2, -128).checked_add(RGB::::new(0, 0, 1)), Some(RGB::::new(2, 2, -127))); } #[test] #[should_panic] #[cfg(debug_assertions)] fn test_add_overflow() { assert_ne!(RGBA::new(255u8, 255, 0, 0), RED_RGBA + BLUE_RGBA); } #[test] fn test_sub() { assert_eq!(RED_RGB, (WHITE_RGB - GREEN_RGB) - BLUE_RGB); assert_eq!(BLACK_RGB, WHITE_RGB - 255); assert_eq!(RGBA::new(255, 255, 0, 0), WHITE_RGBA - BLUE_RGBA); assert_eq!(BLACK_RGBA, WHITE_RGBA - 255); } #[test] #[cfg(feature = "checked_fns")] fn test_checked_sub() { assert_eq!(RGBA::::new(2,4,6,111).checked_sub(RGBA::::new(3,4,6,0)), None); assert_eq!(RGB::::new(2,4,6).checked_sub(RGB::::new(2,5,6)), None); assert_eq!(RGB::::new(2,4,6).checked_sub(RGB::::new(2,4,7)), None); assert_eq!(RGB::::new(2,4,6).checked_sub(RGB::::new(2,4,6)), Some(BLACK_RGB)); assert_eq!(RGB::::new(-128,4,6).checked_sub(RGB::::new(1,4,7)), None); assert_eq!(RGB::::new(2,-128,6).checked_sub(RGB::::new(2,1,7)), None); assert_eq!(RGB::::new(2,4,-128).checked_sub(RGB::::new(2,4,1)), None); assert_eq!(RGB::::new(2,4,6).checked_sub(RGB::::new(-2,4,6)), Some(RGB::::new(4,0,0))); } #[test] fn test_add_assign() { let mut green_rgb = RGB::new(0, 255, 0); green_rgb += RGB::new(255, 0, 255); assert_eq!(WHITE_RGB, green_rgb); let mut black_rgb = RGB::new(0, 0, 0); black_rgb += 255; assert_eq!(WHITE_RGB, black_rgb); let mut green_rgba = RGBA::new(0, 255, 0, 0); green_rgba += RGBA::new(255, 0, 255, 255); assert_eq!(WHITE_RGBA, green_rgba); let mut black_rgba = RGBA::new(0, 0, 0, 0); black_rgba += 255; assert_eq!(WHITE_RGBA, black_rgba); } #[test] fn test_sub_assign() { let mut green_rgb = RGB::new(0, 255, 0); green_rgb -= RGB::new(0, 255, 0); assert_eq!(BLACK_RGB, green_rgb); let mut white_rgb = RGB::new(255, 255, 255); white_rgb -= 255; assert_eq!(BLACK_RGB, white_rgb); let mut green_rgba = RGBA::new(0, 255, 0, 0); green_rgba -= RGBA::new(0, 255, 0, 0); assert_eq!(BLACK_RGBA, green_rgba); let mut white_rgba = RGBA::new(255, 255, 255, 255); white_rgba -= 255; assert_eq!(BLACK_RGBA, white_rgba); } #[test] fn test_mult() { assert_eq!(RGB::new(0.5,1.5,2.5), RGB::new(1.,3.,5.) * 0.5); assert_eq!(RGBA::new(2,4,6,8), RGBA::new(1,2,3,4) * 2); assert_eq!(RGB::new(0.5,1.5,2.5) * RGB::new(1.,3.,5.), RGB::new(0.5,4.5,12.5)); } #[test] fn test_mult_assign() { let mut green_rgb = RGB::new(0u16, 255, 0); green_rgb *= 1; assert_eq!(RGB::new(0, 255, 0), green_rgb); green_rgb *= 2; assert_eq!(RGB::new(0, 255*2, 0), green_rgb); let mut rgb = RGB::new(0.5,1.5,2.5); rgb *= RGB::new(1.,3.,5.); assert_eq!(rgb, RGB::new(0.5,4.5,12.5)); let mut green_rgba = RGBA::new(0u16, 255, 0, 0); green_rgba *= 1; assert_eq!(RGBA::new(0, 255, 0, 0), green_rgba); green_rgba *= 2; assert_eq!(RGBA::new(0, 255*2, 0, 0), green_rgba); } #[test] fn sum() { let s1 = [RGB::new(1u8,1,1), RGB::new(2,3,4)].iter().copied().sum::>(); let s2 = [RGB::new(1u16,1,1), RGB::new(2,3,4)].iter().copied().sum::>(); let s3 = [RGBA::new_alpha(1u16,1,1,Wrapping(1u16)), RGBA::new_alpha(2,3,4,Wrapping(5))].iter().copied().sum::>>(); let s4 = [RGBA::new_alpha(1u16,1,1,1u16), RGBA::new_alpha(2,3,4,5)].iter().copied().sum::>(); assert_eq!(s1, RGB::new(3, 4, 5)); assert_eq!(s2, RGB::new(3, 4, 5)); assert_eq!(s3, RGBA::new_alpha(3, 4, 5, Wrapping(6))); assert_eq!(s4, RGBA::new_alpha(3, 4, 5, 6)); } } rgb-0.8.50/src/legacy/internal/pixel.rs000064400000000000000000000071471046102023000160370ustar 00000000000000/// Casting the struct to slices of its components pub trait ComponentSlice { /// The components interpreted as an array, e.g. one `RGB` expands to 3 elements. /// /// It's implemented for individual pixels as well as slices of pixels. fn as_slice(&self) -> &[T]; /// The components interpreted as a mutable array, e.g. one `RGB` expands to 3 elements. /// /// It's implemented for individual pixels as well as slices of pixels. /// /// If you get an error when calling this on an array, add `[..]` /// /// > use of unstable library feature 'array_methods' /// /// ```rust,ignore /// arr[..].as_mut_slice() /// ``` fn as_mut_slice(&mut self) -> &mut [T]; } /// Use [`::bytemuck::cast_slice()`] instead. /// /// Casting a slice of `RGB/A` values to a slice of `u8` /// /// If instead of `RGB8` you use `RGB`, and you want to cast from/to that custom type, /// implement the `Plain` trait for it: /// /// ```rust /// # #[derive(Copy, Clone)] /// # struct MyCustomType; /// unsafe impl rgb::Pod for MyCustomType {} /// unsafe impl rgb::Zeroable for MyCustomType {} /// ``` /// /// Plain types are not allowed to contain struct padding, booleans, chars, enums, references or pointers. #[cfg(feature = "as-bytes")] pub trait ComponentBytes where Self: ComponentSlice { /// The components interpreted as raw bytes, in machine's native endian. In `RGB` bytes of the red component are first. #[inline] fn as_bytes(&self) -> &[u8] { assert_ne!(0, core::mem::size_of::()); let slice = self.as_slice(); unsafe { core::slice::from_raw_parts(slice.as_ptr().cast(), core::mem::size_of_val(slice)) } } /// The components interpreted as raw bytes, in machine's native endian. In `RGB` bytes of the red component are first. #[inline] fn as_bytes_mut(&mut self) -> &mut [u8] { assert_ne!(0, core::mem::size_of::()); let slice = self.as_mut_slice(); unsafe { core::slice::from_raw_parts_mut(slice.as_mut_ptr().cast(), core::mem::size_of_val(slice)) } } } /// Applying operation to every component /// /// ```rust /// use rgb::ComponentMap; /// # let pixel = rgb::RGB::new(0u8,0,0); /// let inverted = pixel.map(|c| 255 - c); /// /// // For simple math there are Add/Sub/Mul implementations: /// let halved = pixel.map(|c| c / 2); /// let doubled = pixel * 2; /// ``` pub trait ComponentMap { /// Convenience function (equivalent of `self.iter().map().collect()`) for applying the same formula to every component. /// /// Note that it returns the pixel directly, not an Interator. fn map(&self, f: Callback) -> DestPixel where Callback: FnMut(SrcComponent) -> DestComponent; } /// Same as `ComponentMap`, but doesn't change the alpha channel (if there's any alpha). pub trait ColorComponentMap { /// Convenience function for applying the same formula to every rgb/gray component, but skipping the alpha component. /// /// Note that it returns the pixel directly, not an Interator. #[doc(alias = "map_colors_same")] fn map_colors(&self, f: Callback) -> DestPixel where Callback: FnMut(SrcComponent) -> DestComponent { #[allow(deprecated)] self.map_c(f) } /// Alias of `map_colors` #[deprecated(note = "renamed to map_colors")] fn map_c(&self, f: Callback) -> DestPixel where Callback: FnMut(SrcComponent) -> DestComponent { self.map_colors(f) } } rgb-0.8.50/src/legacy/internal/rgb.rs000064400000000000000000000161011046102023000154560ustar 00000000000000use super::pixel::*; use crate::alt::GRB; use crate::alt::{BGR, BGRA}; use crate::{RGB, RGBA}; use core::fmt; impl BGR { /// Convenience function for creating a new pixel /// Warning: The order of arguments is R,G,B #[deprecated(note = "This function has a misleading order of arguments. Use BGR{} literal instead")] pub const fn new(r: T, g: T, b: T) -> Self { Self { b, g, r } } } macro_rules! impl_rgb { ($RGB:ident) => { impl $RGB { /// Iterate over color components (R, G, and B) #[inline(always)] pub fn iter(&self) -> core::iter::Cloned> { self.as_slice().iter().cloned() } } impl ComponentMap<$RGB, T, B> for $RGB { #[inline(always)] fn map(&self, mut f: F) -> $RGB where F: FnMut(T) -> B { $RGB { r:f(self.r), g:f(self.g), b:f(self.b), } } } impl ColorComponentMap<$RGB, T, B> for $RGB { #[inline(always)] fn map_colors(&self, mut f: F) -> $RGB where F: FnMut(T) -> B { $RGB { r:f(self.r), g:f(self.g), b:f(self.b), } } } impl ComponentSlice for $RGB { #[inline(always)] fn as_slice(&self) -> &[T] { unsafe { core::slice::from_raw_parts(self as *const Self as *const T, 3) } } #[inline(always)] fn as_mut_slice(&mut self) -> &mut [T] { unsafe { core::slice::from_raw_parts_mut(self as *mut Self as *mut T, 3) } } } impl ComponentSlice for [$RGB] { #[inline] fn as_slice(&self) -> &[T] { unsafe { core::slice::from_raw_parts(self.as_ptr() as *const _, self.len() * 3) } } #[inline] fn as_mut_slice(&mut self) -> &mut [T] { unsafe { core::slice::from_raw_parts_mut(self.as_mut_ptr() as *mut _, self.len() * 3) } } } #[cfg(feature = "as-bytes")] impl ComponentBytes for [$RGB] {} }; } macro_rules! impl_rgb_to_alpha { ($RGB:ident, $RGBA:ident) => { impl $RGB { /// Convenience function for converting to RGBA #[doc(hidden)] #[deprecated(note = "use .with_alpha(a) instead; this will become a getter in the future")] pub fn alpha(&self, a: T) -> $RGBA { self.with_alpha(a) } /// Convenience function for converting to RGBA #[inline(always)] #[doc(alias = "alpha")] pub fn with_alpha(&self, a: T) -> $RGBA { $RGBA { r: self.r.clone(), g: self.g.clone(), b: self.b.clone(), a, } } /// Convenience function for converting to RGBA with alpha channel of a different type than type of the pixels #[inline(never)] #[deprecated(note = "use .with_alpha(a) instead")] pub fn new_alpha(&self, a: A) -> $RGBA { $RGBA { r: self.r.clone(), g: self.g.clone(), b: self.b.clone(), a, } } } }; } impl core::iter::FromIterator for RGB { /// Takes exactly 3 elements from the iterator and creates a new instance. /// Panics if there are fewer elements in the iterator. #[inline(always)] fn from_iter>(into_iter: I) -> Self { let mut iter = into_iter.into_iter(); Self { r: iter.next().unwrap(), g: iter.next().unwrap(), b: iter.next().unwrap(), } } } impl_rgb! {RGB} impl_rgb_to_alpha! {RGB, RGBA} impl_rgb! {BGR} impl_rgb_to_alpha! {BGR, BGRA} impl_rgb! {GRB} impl fmt::Display for RGB { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "rgb({},{},{})", self.r, self.g, self.b) } } impl fmt::UpperHex for RGB { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "RGB {{ #{:02X}{:02X}{:02X} }}", self.r, self.g, self.b) } } impl fmt::LowerHex for RGB { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "RGB {{ #{:02x}{:02x}{:02x} }}", self.r, self.g, self.b) } } impl fmt::Display for BGR { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "bgr({},{},{})", self.b, self.g, self.r) } } impl fmt::UpperHex for BGR { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "BGR {{ #{:02X}{:02X}{:02X} }}", self.b, self.g, self.r) } } impl fmt::LowerHex for BGR { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "BGR {{ #{:02x}{:02x}{:02x} }}", self.b, self.g, self.r) } } #[cfg(test)] mod rgb_test { use super::*; #[test] fn grb_test() { let grb = GRB {g:1,r:2,b:3}.map(|c| c * 2) + 1; let rgb: crate::RGB8 = grb.into(); assert_eq!(rgb, RGB::new(5,3,7)); } #[test] fn sanity_check() { let neg = RGB::new(1,2,3i32).map(|x| -x); assert_eq!(neg.r, -1); assert_eq!(neg.g, -2); assert_eq!(neg.b, -3); let mut px = RGB::new(3,4,5); px.as_mut_slice()[1] = 111; assert_eq!(111, px.g); assert_eq!(RGBA::new(250,251,252,253), RGB::new(250,251,252).with_alpha(253)); assert_eq!(RGB{r:1u8,g:2,b:3}, RGB::new(1u8,2,3)); assert!(RGB{r:1u8,g:1,b:2} < RGB::new(2,1,1)); let mut h = std::collections::HashSet::new(); h.insert(px); assert!(h.contains(&RGB::new(3,111,5))); assert!(!h.contains(&RGB::new(111,5,3))); #[cfg(feature = "as-bytes")] { let v = vec![RGB::new(1u8,2,3), RGB::new(4,5,6)]; assert_eq!(&[1,2,3,4,5,6], v.as_bytes()); } assert_eq!(RGB::new(0u8,0,0), Default::default()); } #[test] #[allow(deprecated)] fn test_fmt() { let red_rgb = RGB::new(255, 0, 0); let red_bgr = BGR::new(255, 0, 0); assert_eq!("RGB { #FF0000 }", &format!("{:X}", red_rgb)); assert_eq!("BGR { #0000FF }", &format!("{:X}", red_bgr)); assert_eq!("RGB { #ff0000 }", &format!("{:x}", red_rgb)); assert_eq!("BGR { #0000ff }", &format!("{:x}", red_bgr)); assert_eq!("rgb(255,0,0)", &format!("{}", red_rgb)); assert_eq!("bgr(0,0,255)", &format!("{}", red_bgr)); } } rgb-0.8.50/src/legacy/internal/rgba.rs000064400000000000000000000315401046102023000156230ustar 00000000000000use super::pixel::*; use crate::alt::*; use crate::{RGB, RGBA}; use core::fmt; impl RGBA { #[inline(always)] /// Convenience function for creating a new pixel /// The order of arguments is R,G,B,A pub const fn new_alpha(r: T, g: T, b: T, a: A) -> Self { Self { r, g, b, a } } } impl BGRA { #[inline(always)] /// Convenience function for creating a new pixel /// Warning: The order of arguments is R,G,B,A #[deprecated(note = "This function has a misleading order of arguments. Use BGRA{} literal instead")] pub const fn new(r: T, g: T, b: T, a: T) -> Self { Self { b, g, r, a } } } /// ```rust,compile_fail /// let r = rgb::BGRA::::zeroed(); /// ``` impl BGRA { #[inline(always)] /// Convenience function for creating a new pixel /// Warning: The order of arguments is R,G,B,A #[deprecated(note = "This function has a misleading order of arguments. Use BGRA{} literal instead")] pub const fn new_alpha(r: T, g: T, b: T, a: A) -> Self { Self { b, g, r, a } } } impl ARGB { #[inline(always)] /// Convenience function for creating a new pixel /// The order of arguments is R,G,B,A #[deprecated(note = "This function has a misleading order of arguments. Use ARGB{} literal instead")] pub const fn new(r: T, g: T, b: T, a: T) -> Self { Self { r, g, b, a } } } impl ARGB { #[inline(always)] /// Convenience function for creating a new pixel /// The order of arguments is R,G,B,A #[deprecated(note = "This function has a misleading order of arguments. Use ARGB{} literal instead")] pub const fn new_alpha(r: T, g: T, b: T, a: A) -> Self { Self { r, g, b, a } } } impl ABGR { #[inline(always)] /// Convenience function for creating a new pixel /// The order of arguments is R,G,B,A #[deprecated(note = "This function has a misleading order of arguments. Use ABGR{} literal instead")] pub const fn new(r: T, g: T, b: T, a: T) -> Self { Self { r, g, b, a } } } impl ABGR { #[inline(always)] /// Convenience function for creating a new pixel /// The order of arguments is R,G,B,A #[deprecated(note = "This function has a misleading order of arguments. Use ABGR{} literal instead")] pub const fn new_alpha(r: T, g: T, b: T, a: A) -> Self { Self { r, g, b, a } } } macro_rules! impl_rgba { ($RGBA:ident) => { impl $RGBA { /// Iterate over all components (length=4) #[inline(always)] pub fn iter(&self) -> core::iter::Cloned> { self.as_slice().iter().cloned() } } impl $RGBA { /// Copy RGB components out of the RGBA struct /// /// Note: you can use `.into()` to convert between other types #[inline(always)] pub fn bgr(&self) -> BGR { BGR { r: self.r.clone(), g: self.g.clone(), b: self.b.clone(), } } } impl $RGBA { /// Create new RGBA with the same alpha value, but different RGB values #[deprecated(note = "Renamed to map_colors()")] pub fn map_rgb(&self, mut f: F) -> $RGBA where F: FnMut(T) -> U, U: Clone, B: From + Clone { $RGBA { r: f(self.r), g: f(self.g), b: f(self.b), a: self.a.clone().into(), } } #[doc(hidden)] #[deprecated(note = "use .with_alpha(a) instead")] /// Create a new RGBA with the new alpha value, but same RGB values pub fn alpha(&self, a: A) -> Self { self.with_alpha(a) } #[inline(always)] /// Create a new RGBA with the new alpha value, but same RGB values pub fn with_alpha(&self, a: A) -> Self { Self { r: self.r, g: self.g, b: self.b, a } } /// Create a new RGBA with a new alpha value created by the callback. /// Allows changing of the type used for the alpha channel. #[inline] pub fn map_alpha(&self, f: F) -> $RGBA where F: FnOnce(A) -> B { $RGBA { r: self.r, g: self.g, b: self.b, a: f(self.a.clone()), } } } impl ComponentMap<$RGBA, T, B> for $RGBA { #[inline(always)] fn map(&self, mut f: F) -> $RGBA where F: FnMut(T) -> B { $RGBA { r: f(self.r), g: f(self.g), b: f(self.b), a: f(self.a), } } } impl ColorComponentMap<$RGBA, T, B> for $RGBA { #[inline(always)] fn map_colors(&self, mut f: F) -> $RGBA where F: FnMut(T) -> B { $RGBA { r: f(self.r), g: f(self.g), b: f(self.b), a: self.a, } } } impl ComponentSlice for $RGBA { #[inline(always)] fn as_slice(&self) -> &[T] { unsafe { core::slice::from_raw_parts(self as *const Self as *const T, 4) } } #[inline(always)] fn as_mut_slice(&mut self) -> &mut [T] { unsafe { core::slice::from_raw_parts_mut(self as *mut Self as *mut T, 4) } } } impl ComponentSlice for [$RGBA] { #[inline] fn as_slice(&self) -> &[T] { unsafe { core::slice::from_raw_parts(self.as_ptr() as *const _, self.len() * 4) } } #[inline] fn as_mut_slice(&mut self) -> &mut [T] { unsafe { core::slice::from_raw_parts_mut(self.as_mut_ptr() as *mut _, self.len() * 4) } } } #[cfg(feature = "as-bytes")] impl ComponentBytes for [$RGBA] {} }; } macro_rules! impl_alpha_conv { ($RGB:ident, $RGBA:ident) => { /// Assumes 255 is opaque impl From<$RGB> for $RGBA { #[inline(always)] fn from(other: $RGB) -> Self { Self { r: other.r, g: other.g, b: other.b, a: 0xFF, } } } /// Assumes 65535 is opaque impl From<$RGB> for $RGBA { #[inline(always)] fn from(other: $RGB) -> Self { Self { r: other.r, g: other.g, b: other.b, a: 0xFFFF, } } } }; } impl RGBA { /// Provide a mutable view of only RGB components (leaving out alpha). /// Useful to change color without changing opacity. #[inline(always)] pub fn rgb_mut(&mut self) -> &mut RGB { unsafe { &mut *(self as *mut _ as *mut RGB) } } } impl BGRA { /// Provide a mutable view of only RGB components (leaving out alpha). /// Useful to change color without changing opacity. #[deprecated(note = "This function will change. Use bgr_mut()")] pub fn rgb_mut(&mut self) -> &mut BGR { unsafe { &mut *(self as *mut _ as *mut BGR) } } /// Provide a mutable view of only RGB components (leaving out alpha). /// Useful to change color without changing opacity. #[inline(always)] pub fn bgr_mut(&mut self) -> &mut BGR { unsafe { &mut *(self as *mut _ as *mut BGR) } } } impl core::iter::FromIterator for RGBA { #[inline(always)] /// Takes exactly 4 elements from the iterator and creates a new instance. /// Panics if there are fewer elements in the iterator. fn from_iter>(into_iter: I) -> Self { let mut iter = into_iter.into_iter(); Self { r: iter.next().unwrap(), g: iter.next().unwrap(), b: iter.next().unwrap(), a: iter.next().unwrap(), } } } impl RGBA { /// Copy RGB components out of the RGBA struct /// /// Note: you can use `.into()` to convert between other types #[inline(always)] pub fn rgb(&self) -> RGB { RGB { r: self.r.clone(), g: self.g.clone(), b: self.b.clone(), } } } impl ARGB { /// Copy RGB components out of the ARGB struct /// /// Note: you can use `.into()` to convert between other types #[inline(always)] pub fn rgb(&self) -> RGB { RGB { r: self.r.clone(), g: self.g.clone(), b: self.b.clone(), } } } impl BGRA { /// Copy RGB components out of the RGBA struct /// /// Note: you can use `.into()` to convert between other types #[deprecated(note = "This function will change. Use bgr()")] pub fn rgb(&self) -> BGR { BGR { r: self.r.clone(), g: self.g.clone(), b: self.b.clone(), } } } impl_rgba! {RGBA} impl_rgba! {BGRA} impl_rgba! {ARGB} impl_rgba! {ABGR} impl_alpha_conv! {BGR, BGRA} impl_alpha_conv! {RGB, BGRA} impl_alpha_conv! {BGR, RGBA} impl_alpha_conv! {RGB, RGBA} impl_alpha_conv! {BGR, ABGR} impl_alpha_conv! {RGB, ABGR} impl_alpha_conv! {BGR, ARGB} impl_alpha_conv! {RGB, ARGB} impl fmt::Display for RGBA { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "rgba({},{},{},{})", self.r, self.g, self.b, self.a) } } impl fmt::Display for BGRA { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "bgra({},{},{},{})", self.r, self.g, self.b, self.a) } } #[test] fn rgba_test() { let neg = RGBA::new(1,2,3i32,1000).map(|x| -x); assert_eq!(neg.r, -1); assert_eq!(neg.rgb().r, -1); assert_eq!(neg.g, -2); assert_eq!(neg.rgb().g, -2); assert_eq!(neg.b, -3); assert_eq!(neg.rgb().b, -3); assert_eq!(neg.a, -1000); assert_eq!(neg.map_alpha(|x| x+1).a, -999); assert_eq!(neg, neg.as_slice().iter().copied().collect()); assert!(neg < RGBA::new(0,0,0,0)); let neg = RGBA::new(1u8,2,3,4).map_rgb(|c| -(c as i16)); assert_eq!(-1i16, neg.r); assert_eq!(4i16, neg.a); let neg = RGBA::new(1u8,2,3,4).map_colors(|c| -(c as i16)); assert_eq!(-1i16, neg.r); assert_eq!(4u8, neg.a); let mut px = RGBA{r:1,g:2,b:3,a:4}; px.as_mut_slice()[3] = 100; assert_eq!(1, px.rgb_mut().r); assert_eq!(2, px.rgb_mut().g); px.rgb_mut().b = 4; assert_eq!(4, px.rgb_mut().b); assert_eq!(100, px.a); #[cfg(feature = "as-bytes")] { let v = vec![RGBA::new(1u8,2,3,4), RGBA::new(5,6,7,8)]; assert_eq!(&[1,2,3,4,5,6,7,8], v.as_bytes()); } } #[test] #[cfg(feature = "as-bytes")] fn abgr_test() { let abgr = ABGR {r:1,g:2,b:3,a:4}; assert_eq!(4, abgr.as_slice()[0]); use crate::AsPixels; assert_eq!(abgr, [abgr].as_bytes().as_pixels()[0]); } #[test] #[allow(deprecated)] fn bgra_test() { let neg = BGRA::new(1, 2, 3i32, 1000).map(|x| -x); let _ = neg.as_slice(); #[cfg(feature = "as-bytes")] { let _ = [neg].as_bytes(); } assert_eq!(neg.r, -1); assert_eq!(neg.bgr().r, -1); assert_eq!(neg.g, -2); assert_eq!(neg.bgr().g, -2); assert_eq!(neg.b, -3); assert_eq!(neg.bgr().b, -3); assert_eq!(neg.a, -1000); assert_eq!(&[-3,-2,-1,-1000], neg.as_slice()); assert!(neg < BGRA::new(0, 0, 0, 0)); let neg = BGRA::new(1u8, 2u8, 3u8, 4u8).map_rgb(|c| -(c as i16)); assert_eq!(-1i16, neg.r); assert_eq!(4i16, neg.a); #[allow(deprecated)] let neg = BGRA::new(1u8, 2u8, 3u8, 4u8).map_c(|c| -(c as i16)); assert_eq!(-1i16, neg.r); assert_eq!(4u8, neg.a); let mut px = BGRA{r:1,g:2,b:3,a:-9}.alpha(4); px.as_mut_slice()[3] = 100; assert_eq!(1, px.bgr_mut().r); assert_eq!(2, px.bgr_mut().g); px.bgr_mut().b = 4; assert_eq!(4, px.bgr_mut().b); assert_eq!(100, px.a); #[cfg(feature = "as-bytes")] { let v = vec![BGRA::new(3u8, 2, 1, 4), BGRA::new(7, 6, 5, 8)]; assert_eq!(&[1,2,3,4,5,6,7,8], v.as_bytes()); } } rgb-0.8.50/src/lib.rs000064400000000000000000000163551046102023000124050ustar 00000000000000//! Basic struct for `RGB` and `RGBA` pixels. Packed, with red first, alpha last. //! //! This crate is intended to be the lowest common denominator for sharing `RGB`/`RGBA` bitmaps between other crates. //! //! The crate includes convenience functions for converting between the struct and bytes, //! and overloaded operators that work on all channels at once. //! //! This crate intentionally doesn't implement color management (due to complexity of the problem), //! but the structs can be parametrized to implement this if necessary. Other colorspaces are out of scope. //! #![cfg_attr(feature = "as-bytes", doc = "```rust")] #![cfg_attr(not(feature = "as-bytes"), doc = "```ignore")] //! # use rgb::*; //! let pixel = RGB8 {r:0, g:100, b:255}; //! //! let pixel_rgba = pixel.alpha(255); //! let pixel = pixel_rgba.rgb(); //! //! let pixels = vec![pixel; 100]; //! use rgb::ComponentBytes; // Import byte conversion trait //! let bytes = pixels.as_bytes(); //! //! use rgb::ComponentMap; // Import pixel map trait //! let half_bright = pixel.map(|channel| channel / 2); //! let doubled = half_bright * 2; //! # let _ = doubled; //! ``` #![doc(html_logo_url = "https://kornel.ski/rgb-logo.png")] #![warn(missing_docs)] #![cfg_attr(docsrs, feature(doc_auto_cfg))] #![no_std] // std is required to run unit tests #[cfg(test)] #[macro_use] extern crate std; /// Re-export of the [`bytemuck` crate](https://lib.rs/bytemuck). [See docs](https://docs.rs/bytemuck). /// /// Use [`::bytemuck::cast_slice()`] or [`::bytemuck::from_bytes()`] to convert /// pixels to/from `&[u8]`. #[cfg(feature = "bytemuck")] #[doc(alias = "ComponentSlice")] #[doc(alias = "as_bytes")] #[doc(alias = "Pod")] pub use ::bytemuck; pub(crate) mod formats { pub mod abgr; pub mod argb; pub mod bgr; pub mod bgra; pub mod gray; pub mod gray_a; pub mod gray_alpha; pub mod grb; pub mod rgb; pub mod rgba; } /// traits for forward compatibility with the next major version of the crate pub mod prelude { pub use crate::legacy::internal::pixel::ComponentMap; pub use crate::legacy::internal::pixel::ColorComponentMap; } pub use formats::abgr::Abgr; pub use formats::argb::Argb; pub use formats::bgr::Bgr; pub use formats::bgra::Bgra; #[cfg(not(feature = "unstable-experimental"))] pub use formats::gray_alpha::GrayAlpha_v08 as GrayAlpha; #[cfg(not(feature = "unstable-experimental"))] pub use formats::gray::Gray_v08 as Gray; pub use formats::grb::Grb; pub use formats::rgb::Rgb; pub use formats::rgba::Rgba; mod inherent_impls; pub(crate) mod legacy { pub(crate) mod internal { pub mod convert; pub mod ops; pub mod pixel; pub mod rgb; pub mod rgba; } /// BGR/BGRA alernative layouts & grayscale /// /// BGR might be useful for some Windows or OpenGL APIs. pub mod alt; } pub use legacy::alt; #[cfg(all(feature = "bytemuck", not(feature = "as-bytes")))] mod bytemuck_impl; #[cfg(feature = "as-bytes")] mod as_bytes; /// Re-export from `bytemuck` crate #[cfg(feature = "as-bytes")] pub use ::bytemuck::Pod; /// Re-export from `bytemuck` crate #[cfg(feature = "as-bytes")] pub use ::bytemuck::Zeroable; pub use crate::legacy::internal::convert::*; pub use crate::legacy::internal::pixel::*; #[doc(hidden)] /// Renamed to `Rgb` pub use formats::rgb::Rgb as RGB; #[doc(hidden)] /// Renamed to `Rgba` pub use formats::rgba::Rgba as RGBA; #[doc(hidden)] /// Incompatible replacement for the `GrayAlpha` type pub use formats::gray_a::GrayA; #[cfg(feature = "unstable-experimental")] pub use formats::gray::Gray_v09 as Gray; /// 8-bit RGB /// /// The colorspace is technically undefined, but generally sRGB is assumed. pub type RGB8 = RGB; /// 16-bit RGB in machine's native endian /// /// Be careful to perform byte-swapping when reading from files. pub type RGB16 = RGB; /// 8-bit RGBA, alpha is last. 0 = transparent, 255 = opaque. pub type RGBA8 = RGBA; /// 16-bit RGB in machine's native endian. 0 = transparent, 65535 = opaque. /// /// Alpha is last. pub type RGBA16 = RGBA; #[test] fn rgb_works() { let rgb = RGB{r:0u8,g:128,b:255}.clone(); assert_eq!(rgb.b, 255); assert_eq!(rgb, rgb.iter().map(|ch| ch).collect()); #[cfg(feature = "as-bytes")] { assert_eq!(0, [rgb].as_bytes()[0]); assert_eq!(128, [rgb].as_bytes()[1]); assert_eq!(255, [rgb].as_bytes()[2]); } let rgb = RGB16{r:0u16,g:0x7F7F,b:65535}; assert_eq!(rgb.b, 65535); assert_eq!(rgb.as_slice()[1], 0x7F7F); #[cfg(feature = "as-bytes")] { assert_eq!(0, [rgb].as_bytes()[0]); assert_eq!(0, [rgb].as_bytes()[1]); assert_eq!(0x7F, [rgb].as_bytes()[2]); assert_eq!(0x7F, [rgb].as_bytes()[3]); assert_eq!(0xFF, [rgb].as_bytes()[4]); assert_eq!(0xFF, [rgb].as_bytes()[5]); } assert_eq!("rgb(1,2,3)", format!("{}", RGB::new(1,2,3))); } #[test] fn sub_floats() { assert_eq!(RGBA{r:2.5_f64, g:-1.5, b:0., a:5.}, RGBA{r:3.5_f64, g:-0.5, b:-2., a:0.} - RGBA{r:1.0_f64, g:1., b:-2., a:-5.}); } #[test] fn into() { let a:RGB8 = RGB{r:0,g:1,b:2}; let b:RGB = a.into(); let c:RGB = b.into(); let d:RGB = a.into(); assert_eq!(c, d); } #[test] fn rgba_works() { let rgba = RGBA{r:0u8,g:128,b:255,a:33}.clone(); assert_eq!(rgba.b, 255); assert_eq!(rgba.a, 33); assert_eq!(rgba, rgba.iter().map(|ch| ch).collect()); assert_eq!("rgba(1,2,3,4)", format!("{}", RGBA::new(1,2,3,4))); assert_eq!(rgba - rgba, RGBA::new(0,0,0,0)); } #[test] fn bytes() { let rgb = RGB8::new(1,2,3); #[cfg(feature = "as-bytes")] { let rgb_arr = [rgb]; let rgb_bytes = rgb_arr.as_bytes(); assert_eq!(&[1,2,3], rgb_bytes); assert_eq!(rgb_bytes.as_rgba().len(), 0); assert_eq!({let t: &[RGBA8] = rgb_bytes.as_pixels(); t}.len(), 0); assert_eq!(rgb, rgb_bytes.into_iter().cloned().collect()); assert_eq!(&[rgb], rgb_bytes.as_rgb()); assert_eq!(&[rgb], rgb_bytes.as_pixels()); } let mut rgb2 = [rgb]; assert_eq!(rgb2[..].as_mut_slice().as_rgb_mut(), &mut [rgb]); assert_eq!(&mut [rgb], rgb2[..].as_mut_slice().as_pixels_mut()); #[cfg(feature = "as-bytes")] { let rgba = RGBA8::new(1,2,3,4); let mut rgba_arr = [rgba]; let rgba_bytes = rgba_arr.as_bytes_mut(); assert_eq!(&[1,2,3,4], rgba_bytes); assert_eq!(&[rgba], rgba_bytes.as_rgba()); rgba_bytes[3] = 99; assert_eq!(RGBA8::new(1,2,3,99), rgba_arr.as_bytes().into_iter().cloned().collect()); } let rgb = RGB16::new(1,2,3); let rgb_slice = rgb.as_slice(); assert_eq!(&[1,2,3], rgb_slice); assert_eq!(rgb_slice.as_rgba(), &[]); assert_eq!(&[rgb], rgb_slice.as_rgb()); assert_eq!(rgb, rgb_slice.into_iter().cloned().collect()); let rgba = RGBA16::new(1,2,3,4); let rgba_slice = rgba.as_slice(); assert_eq!(&[1,2,3,4], rgba_slice); assert_eq!(&[1,2,3], rgba_slice.as_rgb()[0].as_slice()); assert_eq!(&[rgba], rgba_slice.as_rgba()); assert_eq!(rgba, rgba_slice.iter().copied().collect()); let mut rgba2 = [rgba]; assert_eq!(rgba2[..].as_mut_slice().as_rgba_mut(), &mut [rgba]); let mut foo = vec![0u8; 8]; foo.as_rgba_mut()[1] = RGBA::new(1,2,3,4); assert_eq!(&[0u8,0,0,0,1,2,3,4], &foo[..]); }