rgb-0.8.36/.cargo_vcs_info.json0000644000000001360000000000100117040ustar { "git": { "sha1": "789553fdf3e9679ca82207c079cdfbd138fb886c" }, "path_in_vcs": "" }rgb-0.8.36/Cargo.lock0000644000000045270000000000100076670ustar # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 3 [[package]] name = "bytemuck" version = "1.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72957246c41db82b8ef88a5486143830adeb8227ef9837740bdec67724cf2c5b" [[package]] name = "itoa" version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" [[package]] name = "proc-macro2" version = "1.0.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba508cc11742c0dc5c1659771673afbab7a0efab23aa17e854cbab0837ed0b43" dependencies = [ "unicode-xid", ] [[package]] name = "quote" version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05" dependencies = [ "proc-macro2", ] [[package]] name = "rgb" version = "0.8.36" dependencies = [ "bytemuck", "serde", "serde_json", ] [[package]] name = "ryu" version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c9613b5a66ab9ba26415184cfc41156594925a9cf3a2057e57f31ff145f6568" [[package]] name = "serde" version = "1.0.130" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" version = "1.0.130" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d7bc1a1ab1961464eae040d96713baa5a724a8152c1222492465b54322ec508b" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "serde_json" version = "1.0.72" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0ffa0837f2dfa6fb90868c2b5468cad482e175f7dad97e7421951e663f2b527" dependencies = [ "itoa", "ryu", "serde", ] [[package]] name = "syn" version = "1.0.82" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8daf5dd0bb60cbd4137b1b587d2fc0ae729bc07cf01cd70b36a1ed5ade3b9d59" dependencies = [ "proc-macro2", "quote", "unicode-xid", ] [[package]] name = "unicode-xid" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" rgb-0.8.36/Cargo.toml0000644000000036370000000000100077130ustar # 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 = "2018" name = "rgb" version = "0.8.36" authors = ["Kornel Lesiński "] include = [ "src/**/*", "Cargo.toml", "README.md", "examples/*.rs", "LICENSE", ] 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] targets = ["x86_64-unknown-linux-gnu"] features = [ "argb", "serde", "as-bytes", ] [[example]] name = "serde" required-features = ["serde"] [[example]] name = "example" required-features = ["as-bytes"] [dependencies.bytemuck] version = "1.7.2" optional = true [dependencies.serde] version = "1.0.130" features = ["derive"] optional = true default-features = false [dev-dependencies.serde_json] version = "1.0.68" [features] argb = [] as-bytes = ["bytemuck"] default = ["as-bytes"] grb = [] [badges.maintenance] status = "actively-developed" [badges.travis-ci] repository = "kornelski/rust-rgb" rgb-0.8.36/Cargo.toml.orig000064400000000000000000000027131046102023000133660ustar 00000000000000[package] name = "rgb" version = "0.8.36" authors = ["Kornel Lesiński "] 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 = "2018" [features] default = ["as-bytes"] # safe as_bytes() casts require a marker trait for non-padded, non-pointery types. as-bytes = ["bytemuck"] argb = [] grb = [] [badges] travis-ci = { repository = "kornelski/rust-rgb" } maintenance = { status = "actively-developed" } [dependencies] serde = { version = "1.0.130", optional = true, default-features = false, features = ["derive"] } bytemuck = { version = "1.7.2", optional = true } [dev-dependencies] serde_json = "1.0.68" [[example]] name = "serde" required-features = ["serde"] [[example]] name = "example" required-features = ["as-bytes"] [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] features = [ "argb", "serde", "as-bytes" ] rgb-0.8.36/LICENSE000064400000000000000000000020471046102023000115040ustar 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.36/README.md000064400000000000000000000044161046102023000117600ustar 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 standards](https://imgs.xkcd.com/comics/standards.png)](https://xkcd.com/927/) ## Installation Add this to your `Cargo.toml`: ```toml [dependencies] rgb = "0.8" ``` ## 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`](//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::*`. To enable `ARGB` and `ABGR`, use the "argb" feature: ```toml rgb = { version = "0.8", features = ["argb"] } ``` There's also an optional `serde` feature that makes all types (de)serializable. rgb-0.8.36/examples/example.rs000064400000000000000000000005111046102023000143100ustar 00000000000000use rgb::*; fn main() { let px = RGB{r:255_u8,g:0,b:100}; assert_eq!([px].as_bytes()[0], 255); let bigpx = RGB16{r:65535_u16,g:0,b:0}; assert_eq!(bigpx.as_slice()[0], 65535); let px = RGB8::new(255, 0, 255); let inverted: RGB8 = px.map(|ch| 255 - ch); println!("{}", inverted); // rgb(0,255,0) } rgb-0.8.36/examples/serde.rs000064400000000000000000000005341046102023000137640ustar 00000000000000extern crate rgb; extern crate serde_json; use 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: RGB8 = serde_json::from_str("{\"r\":10,\"g\":20,\"b\":30}").unwrap(); println!("{}", color); } rgb-0.8.36/src/alt.rs000064400000000000000000000237511046102023000124210ustar 00000000000000use crate::internal::pixel::*; use core::ops; use core::slice; #[repr(C)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Ord, PartialOrd, Hash)] /// RGB in reverse byte order pub struct BGR { /// Blue first pub b: ComponentType, /// Green pub g: ComponentType, /// Red last pub r: ComponentType, } #[repr(C)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Ord, PartialOrd, Hash)] /// BGR+A pub struct BGRA { /// Blue first pub b: ComponentType, /// Green pub g: ComponentType, /// Red pub r: ComponentType, /// Alpha last pub a: AlphaComponentType, } #[cfg(feature = "argb")] #[repr(C)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Ord, PartialOrd, Hash)] /// A+BGR pub struct ABGR { /// Alpha first pub a: AlphaComponentType, /// Blue pub b: ComponentType, /// Green pub g: ComponentType, /// Red last pub r: ComponentType, } #[cfg(feature = "argb")] #[repr(C)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Ord, PartialOrd, Hash)] /// A+RGB pub struct ARGB { /// Alpha first pub a: AlphaComponentType, /// Red pub r: ComponentType, /// Green pub g: ComponentType, /// Blue last pub b: ComponentType, } /// 8-bit BGR pub type BGR8 = BGR; /// 16-bit BGR in machine's native endian pub type BGR16 = BGR; /// 8-bit BGRA pub type BGRA8 = BGRA; /// 8-bit ABGR, alpha is first. 0 = transparent, 255 = opaque. #[cfg(feature = "argb")] pub type ABGR8 = ABGR; /// 8-bit ARGB, alpha is first. 0 = transparent, 255 = opaque. #[cfg(feature = "argb")] pub type ARGB8 = ARGB; /// 16-bit BGR in machine's native endian pub type BGRA16 = BGRA; /// 16-bit ABGR in machine's native endian. 0 = transparent, 65535 = opaque. #[cfg(feature = "argb")] pub type ABGR16 = ABGR; /// 16-bit ARGB in machine's native endian. 0 = transparent, 65535 = opaque. #[cfg(feature = "argb")] pub type ARGB16 = ARGB; #[cfg(feature = "grb")] #[repr(C)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Ord, PartialOrd, Hash)] /// RGB with red-green swapped (may be useful for LEDs) pub struct GRB { /// Green first pub g: ComponentType, /// Red pub r: ComponentType, /// Blue last pub b: ComponentType, } /// 8-bit GRB #[cfg(feature = "grb")] pub type GRB8 = GRB; //////////////////////////////////////// #[repr(C)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Ord, PartialOrd, Hash)] /// Grayscale. Use `.0` or `*` (deref) to access the value. pub struct Gray( /// brightness level pub ComponentType, ); #[repr(C)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Ord, PartialOrd, Hash)] /// Grayscale with alpha. Use `.0`/`.1` to access. pub struct GrayAlpha( /// brightness level pub ComponentType, /// alpha pub AlphaComponentType, ); #[cfg(feature = "as-bytes")] unsafe impl crate::Pod for Gray where T: crate::Pod {} #[cfg(feature = "as-bytes")] 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")] unsafe impl crate::Zeroable for GrayAlpha where T: crate::Zeroable, A: crate::Zeroable {} /// 8-bit gray pub type GRAY8 = Gray; /// 16-bit gray in machine's native endian pub type GRAY16 = Gray; /// 8-bit gray with alpha in machine's native endian pub type GRAYA8 = GrayAlpha; /// 16-bit gray with alpha in machine's native endian pub type GRAYA16 = GrayAlpha; impl Gray { /// New grayscale pixel #[inline(always)] pub const fn new(brightness: T) -> Self { Self(brightness) } } impl 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 { /// New grayscale+alpha pixel #[inline(always)] pub const fn new(brightness: T, alpha: A) -> Self { Self(brightness, alpha) } /// 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 #[inline(always)] pub fn 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_c(&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_c(&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() as *const _, 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) } } } #[cfg(feature = "as-bytes")] impl ComponentBytes for [GrayAlpha] {} 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() as *const _, self.len()) } } #[inline] fn as_mut_slice(&mut self) -> &mut [T] { unsafe { slice::from_raw_parts_mut(self.as_ptr() as *mut _, self.len()) } } } #[cfg(feature = "as-bytes")] impl ComponentBytes for [Gray] {} /// 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] 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); assert_eq!(110, *g + 10); 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.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.36/src/internal/convert/array.rs000064400000000000000000000050521046102023000162450ustar 00000000000000#[cfg(feature = "argb")] use 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 Into<[T; 3]> for RGB { #[inline(always)] fn into(self) -> [T; 3] { [self.r, self.g, self.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 Into<[T; 4]> for RGBA { #[inline(always)] fn into(self) -> [T; 4] { [self.r, self.g, self.b, self.a] } } #[cfg(feature = "argb")] 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], } } } #[cfg(feature = "argb")] 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 Into<[T; 3]> for BGR { #[inline(always)] fn into(self) -> [T; 3] { [self.b, self.g, self.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 Into<[T; 4]> for BGRA { #[inline(always)] fn into(self) -> [T; 4] { [self.b, self.g, self.r, self.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.36/src/internal/convert/mod.rs000064400000000000000000000300571046102023000157110ustar 00000000000000use super::pixel::*; use crate::alt::*; use crate::RGB; use crate::RGBA; use core::convert::*; use core::mem; use core::slice; mod array; mod tuple; /// Casts a slice of bytes into a slice of pixels, e.g. `[u8]` to `[RGB8]`. /// /// See also `FromSlice` pub trait AsPixels { /// 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]; /// 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} #[cfg(feature = "grb")] as_pixels_impl!{GRB, 3} as_pixels_impl!{Gray, 1} as_pixels_impl!{GrayAlpha, 2} #[cfg(feature = "argb")] as_pixels_impl!{ARGB, 4} #[cfg(feature = "argb")] as_pixels_impl!{ABGR, 4} /// 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 #[cfg(feature = "argb")] 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 #[cfg(feature = "argb")] 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 #[cfg(feature = "argb")] 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 #[cfg(feature = "argb")] 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] #[cfg(feature = "argb")] 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] #[cfg(feature = "argb")] 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] #[cfg(feature = "argb")] 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] #[cfg(feature = "argb")] 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() as *const T, 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() as *mut T, 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,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),+ } } } } } #[cfg(feature = "argb")] reorder_impl_from!(@rgba RGBA, ARGB); #[cfg(feature = "argb")] reorder_impl_from!(@rgba ABGR, ARGB); #[cfg(feature = "argb")] reorder_impl_from!(@rgba BGRA, ARGB); #[cfg(feature = "argb")] reorder_impl_from!(@rgba BGRA, ABGR); reorder_impl_from!(@rgb RGB, BGR); reorder_impl_from!(@rgba BGRA, RGBA); #[cfg(feature = "argb")] reorder_impl_from!(@rgba ABGR, RGBA); #[cfg(feature = "grb")] 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, } } } impl AsRef for Gray { #[inline(always)] fn as_ref(&self) -> &T { &self.0 } } impl AsRef<[T]> for RGB { #[inline(always)] fn as_ref(&self) -> &[T] { self.as_slice() } } impl AsRef<[T]> for RGBA { #[inline(always)] fn as_ref(&self) -> &[T] { self.as_slice() } } impl AsRef for GrayAlpha { #[inline(always)] fn as_ref(&self) -> &T { &self.0 } } impl AsMut for Gray { #[inline(always)] fn as_mut(&mut self) -> &mut T { &mut self.0 } } impl AsMut<[T]> for RGB { #[inline(always)] fn as_mut(&mut self) -> &mut [T] { self.as_mut_slice() } } impl AsMut<[T]> for RGBA { #[inline(always)] fn as_mut(&mut self) -> &mut [T] { self.as_mut_slice() } } impl AsMut for GrayAlpha { #[inline(always)] fn as_mut(&mut self) -> &mut T { &mut self.0 } } #[cfg(feature = "argb")] #[test] fn argb_converts() { let argb = ARGB {a: 0xffu8, r: 0xff, g: 0xff, b: 0xff}; let rgba = RGBA {a: 0xffu8, r: 0xff, g: 0xff, b: 0xff}; assert_eq!(RGBA::from(argb), rgba); assert_eq!(ARGB::from(rgba), argb); let bgra = BGRA {a: 0xffu8, r: 0xff, g: 0xff, b: 0xff}; let abgr = ABGR {a: 0xffu8, r: 0xff, g: 0xff, b: 0xff}; 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()); } rgb-0.8.36/src/internal/convert/tuple.rs000064400000000000000000000034761046102023000162700ustar 00000000000000use crate::alt::BGR; use crate::alt::BGRA; use crate::RGB; use crate::RGBA; use core::convert::*; impl From<(T,T,T)> for RGB { #[inline] fn from(other: (T,T,T)) -> Self { Self { r: other.0, g: other.1, b: other.2, } } } impl Into<(T,T,T)> for RGB { #[inline] fn into(self) -> (T,T,T) { (self.r, self.g, self.b) } } impl From<(T,T,T,A)> for RGBA { #[inline] fn from(other: (T,T,T,A)) -> Self { Self { r: other.0, g: other.1, b: other.2, a: other.3, } } } impl Into<(T,T,T,A)> for RGBA { #[inline] fn into(self) -> (T,T,T,A) { (self.r, self.g, self.b, self.a) } } impl From<(T,T,T)> for BGR { #[inline(always)] fn from(other: (T,T,T)) -> Self { Self { b: other.0, g: other.1, r: other.2, } } } impl Into<(T,T,T)> for BGR { #[inline(always)] fn into(self) -> (T,T,T) { (self.b, self.g, self.r) } } impl From<(T,T,T,A)> for BGRA { #[inline(always)] fn from(other: (T,T,T,A)) -> Self { Self { b: other.0, g: other.1, r: other.2, a: other.3, } } } impl Into<(T,T,T,A)> for BGRA { #[inline(always)] fn into(self) -> (T,T,T,A) { (self.b, self.g, self.r, self.a) } } #[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.36/src/internal/ops.rs000064400000000000000000000272511046102023000142550ustar 00000000000000use crate::alt::Gray; use crate::alt::GrayAlpha; use super::pixel::*; use crate::RGB; use crate::RGBA; use core::ops::*; use core::iter::Sum; #[cfg(feature = "argb")] use crate::alt::ARGB; #[cfg(feature = "grb")] use crate::alt::GRB; 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) } } }; } 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) } } }; } 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} #[cfg(feature = "argb")] impl_scalar!{ARGB} #[cfg(feature = "grb")] impl_scalar!{GRB} impl_scalar!{Gray} impl_scalar!{GrayAlpha} impl_struct_ops_opaque! {RGB => r g b} #[cfg(feature = "grb")] impl_struct_ops_opaque! {GRB => g r b} impl_struct_ops_opaque! {Gray => 0} impl_struct_ops_alpha! {RGBA => r g b a} #[cfg(feature = "argb")] impl_struct_ops_alpha! {ARGB => a r g b} impl_struct_ops_alpha! {GrayAlpha => 0 1} #[cfg(test)] mod test { use super::*; 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(2u8,4,6,8u16), RGBA::new_alpha(1u8,2,3,4u16) + RGBA{r:1u8,g:2,b:3,a:4u16}); 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] #[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] 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(1u8,1,1,1u16), RGBA::new_alpha(2,3,4,5)].iter().copied().sum::>(); let s4 = [RGBA::new_alpha(1u16,1,1,1u8), 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, 6)); assert_eq!(s4, RGBA::new_alpha(3, 4, 5, 6)); } } rgb-0.8.36/src/internal/pixel.rs000064400000000000000000000063641046102023000145770ustar 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]; } /// 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() as *const _, slice.len() * core::mem::size_of::()) } } /// 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() as *mut _, slice.len() * core::mem::size_of::()) } } } /// 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. fn map_c(&self, f: Callback) -> DestPixel where Callback: FnMut(SrcComponent) -> DestComponent; } rgb-0.8.36/src/internal/rgb.rs000064400000000000000000000165631046102023000142320ustar 00000000000000use super::pixel::*; use crate::alt::BGR; use crate::alt::BGRA; use crate::RGB; use crate::RGBA; use core::fmt; #[cfg(feature = "grb")] use crate::alt::GRB; impl RGB { /// Convenience function for creating a new pixel /// The order of arguments is R,G,B #[inline(always)] pub const fn new(r: T, g: T, b: T) -> Self { Self { r, g, b } } } impl BGR { /// Convenience function for creating a new pixel /// Wargning: The order of arguments is R,G,B #[deprecated(note="This function has a misleading order of arguments. Use BGR{} literal instead")] #[inline(always)] pub const fn new(r: T, g: T, b: T) -> Self { Self { b, g, r } } } #[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 {} 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_c(&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 #[inline(always)] pub fn 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(always)] 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} #[cfg(feature = "grb")] 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::*; use std; #[test] #[cfg(feature = "grb")] 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).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.36/src/internal/rgba.rs000064400000000000000000000330721046102023000143650ustar 00000000000000use core::fmt; use crate::alt::*; use crate::RGB; use crate::RGBA; use super::pixel::*; impl RGBA { #[inline(always)] /// Convenience function for creating a new pixel /// The order of arguments is R,G,B,A pub const fn new(r: T, g: T, b: T, a: T) -> Self { Self {r,g,b,a} } } 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 {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_alpha(r: T, g: T, b: T, a: A) -> Self { Self {r,g,b,a} } } #[cfg(feature = "as-bytes")] unsafe impl crate::Pod for RGBA where T: crate::Pod, A: crate::Pod {} #[cfg(feature = "as-bytes")] unsafe impl crate::Pod for BGRA where T: crate::Pod, A: crate::Pod {} #[cfg(feature = "as-bytes")] unsafe impl crate::Zeroable for RGBA where T: crate::Zeroable, A: crate::Zeroable {} #[cfg(feature = "as-bytes")] unsafe impl crate::Zeroable for BGRA where T: crate::Zeroable, A: crate::Zeroable {} #[cfg(feature = "argb")] 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} } } #[cfg(feature = "argb")] 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} } } #[cfg(feature = "argb")] 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} } } #[cfg(feature = "argb")] 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} } } #[cfg(all(feature = "as-bytes", feature = "argb"))] unsafe impl crate::Pod for ARGB where T: crate::Pod, A: crate::Pod {} #[cfg(all(feature = "as-bytes", feature = "argb"))] unsafe impl crate::Pod for ABGR where T: crate::Pod, A: crate::Pod {} #[cfg(all(feature = "as-bytes", feature = "argb"))] unsafe impl crate::Zeroable for ARGB where T: crate::Zeroable, A: crate::Zeroable {} #[cfg(all(feature = "as-bytes", feature = "argb"))] unsafe impl crate::Zeroable for ABGR where T: crate::Zeroable, A: crate::Zeroable {} 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 #[inline(always)] 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(), } } #[inline(always)] /// Create a new RGBA with the new alpha value, but same RGB values pub fn 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_c(&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. #[inline(always)] #[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 BGRA { /// Copy RGB components out of the RGBA struct /// /// Note: you can use `.into()` to convert between other types #[inline(always)] #[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} #[cfg(feature = "argb")] impl_rgba! {ARGB} #[cfg(feature = "argb")] impl_rgba! {ABGR} impl_alpha_conv! {BGR, BGRA} impl_alpha_conv! {RGB, BGRA} impl_alpha_conv! {BGR, RGBA} impl_alpha_conv! {RGB, RGBA} #[cfg(feature = "argb")] impl_alpha_conv! {BGR, ABGR} #[cfg(feature = "argb")] impl_alpha_conv! {RGB, ABGR} #[cfg(feature = "argb")] impl_alpha_conv! {BGR, ARGB} #[cfg(feature = "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().cloned().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_c(|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 = "argb")] 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); 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.36/src/lib.rs000064400000000000000000000153021046102023000124000ustar 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. //! //! ```rust //! # 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")] #![no_std] #![warn(missing_docs)] // std is required to run unit tests #[cfg(test)] #[macro_use] extern crate std; #[cfg(feature = "serde")] #[macro_use] extern crate serde; 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; /// 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::internal::convert::*; pub use crate::internal::ops::*; pub use crate::internal::pixel::*; pub use crate::internal::rgb::*; pub use crate::internal::rgba::*; #[repr(C)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Ord, PartialOrd, Hash)] /// The RGB pixel /// /// The component type can be `u8` (aliased as `RGB8`), `u16` (aliased as `RGB16`), /// or any other type (but simple copyable types are recommended.) pub struct RGB { /// Red pub r: ComponentType, /// Green pub g: ComponentType, /// Blue pub b: ComponentType, } #[repr(C)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Ord, PartialOrd, Hash)] /// The RGBA pixel /// /// The component type can be `u8` (aliased as `RGBA8`), `u16` (aliased as `RGBA16`), /// or any other type (but simple copyable types are recommended.) /// /// You can specify a different type for alpha, but it's only for special cases /// (e.g. if you use a newtype like `RGBA, u16>`). pub struct RGBA { /// Red pub r: ComponentType, /// Green pub g: ComponentType, /// Blue pub b: ComponentType, /// Alpha pub a: AlphaComponentType, } /// 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.into_iter().cloned().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[..]); }