--- /dev/null
+{
+ "git": {
+ "sha1": "789553fdf3e9679ca82207c079cdfbd138fb886c"
+ },
+ "path_in_vcs": ""
+}
\ No newline at end of file
--- /dev/null
+# 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"
--- /dev/null
+# 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 <kornel@geekhood.net>"]
+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"
--- /dev/null
+[package]
+name = "rgb"
+version = "0.8.36"
+authors = ["Kornel Lesiński <kornel@geekhood.net>"]
+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" ]
--- /dev/null
+MIT 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.
--- /dev/null
+# `struct RGB` for [Rust](https://www.rust-lang.org) [](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
+
+[](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<CustomType>`), 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<T>`, and `RGBA<RGBType, AlphaType>`, so you can use them with a newtype, e.g.:
+
+```rust
+struct LinearLight(u16);
+type LinearRGB = RGB<LinearLight>;
+```
+
+
+### `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.
--- /dev/null
+use 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)
+}
--- /dev/null
+extern 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);
+}
--- /dev/null
+use 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<ComponentType> {
+ /// 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<ComponentType, AlphaComponentType = ComponentType> {
+ /// 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<ComponentType, AlphaComponentType = ComponentType> {
+ /// 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<ComponentType, AlphaComponentType = ComponentType> {
+ /// 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<u8>;
+
+/// 16-bit BGR in machine's native endian
+pub type BGR16 = BGR<u16>;
+
+/// 8-bit BGRA
+pub type BGRA8 = BGRA<u8>;
+
+/// 8-bit ABGR, alpha is first. 0 = transparent, 255 = opaque.
+#[cfg(feature = "argb")]
+pub type ABGR8 = ABGR<u8>;
+
+/// 8-bit ARGB, alpha is first. 0 = transparent, 255 = opaque.
+#[cfg(feature = "argb")]
+pub type ARGB8 = ARGB<u8>;
+
+/// 16-bit BGR in machine's native endian
+pub type BGRA16 = BGRA<u16>;
+
+/// 16-bit ABGR in machine's native endian. 0 = transparent, 65535 = opaque.
+#[cfg(feature = "argb")]
+pub type ABGR16 = ABGR<u16>;
+
+/// 16-bit ARGB in machine's native endian. 0 = transparent, 65535 = opaque.
+#[cfg(feature = "argb")]
+pub type ARGB16 = ARGB<u16>;
+
+#[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<ComponentType> {
+ /// Green first
+ pub g: ComponentType,
+ /// Red
+ pub r: ComponentType,
+ /// Blue last
+ pub b: ComponentType,
+}
+
+/// 8-bit GRB
+#[cfg(feature = "grb")]
+pub type GRB8 = GRB<u8>;
+
+////////////////////////////////////////
+
+#[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<ComponentType>(
+ /// 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<ComponentType, AlphaComponentType = ComponentType>(
+ /// brightness level
+ pub ComponentType,
+ /// alpha
+ pub AlphaComponentType,
+);
+
+#[cfg(feature = "as-bytes")]
+unsafe impl<T> crate::Pod for Gray<T> where T: crate::Pod {}
+#[cfg(feature = "as-bytes")]
+unsafe impl<T, A> crate::Pod for GrayAlpha<T, A> where T: crate::Pod, A: crate::Pod {}
+#[cfg(feature = "as-bytes")]
+unsafe impl<T> crate::Zeroable for Gray<T> where T: crate::Zeroable {}
+#[cfg(feature = "as-bytes")]
+unsafe impl<T, A> crate::Zeroable for GrayAlpha<T, A> where T: crate::Zeroable, A: crate::Zeroable {}
+
+/// 8-bit gray
+pub type GRAY8 = Gray<u8>;
+
+/// 16-bit gray in machine's native endian
+pub type GRAY16 = Gray<u16>;
+
+/// 8-bit gray with alpha in machine's native endian
+pub type GRAYA8 = GrayAlpha<u8>;
+
+/// 16-bit gray with alpha in machine's native endian
+pub type GRAYA16 = GrayAlpha<u16>;
+
+impl<T> Gray<T> {
+ /// New grayscale pixel
+ #[inline(always)]
+ pub const fn new(brightness: T) -> Self {
+ Self(brightness)
+ }
+}
+
+impl<T> ops::Deref for Gray<T> {
+ type Target = T;
+ #[inline(always)]
+ fn deref(&self) -> &T {
+ &self.0
+ }
+}
+
+impl<T: Copy> From<T> for Gray<T> {
+ #[inline(always)]
+ fn from(component: T) -> Self {
+ Gray(component)
+ }
+}
+
+impl<T: Clone, A> GrayAlpha<T, A> {
+ /// Copy `Gray` component out of the `GrayAlpha` struct
+ #[inline(always)]
+ pub fn gray(&self) -> Gray<T> {
+ Gray(self.0.clone())
+ }
+}
+
+impl<T, A> GrayAlpha<T, A> {
+ /// 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<T> {
+ unsafe {
+ &mut *(self as *mut _ as *mut _)
+ }
+ }
+}
+
+impl<T: Copy, A: Clone> GrayAlpha<T, A> {
+ /// 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<F, B>(&self, f: F) -> GrayAlpha<T, B>
+ 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<F, U, B>(&self, f: F) -> GrayAlpha<U, B>
+ where F: FnOnce(T) -> U, U: Clone, B: From<A> + Clone {
+ GrayAlpha(f(self.0), self.1.clone().into())
+ }
+}
+
+impl<T: Copy, B> ComponentMap<Gray<B>, T, B> for Gray<T> {
+ #[inline(always)]
+ fn map<F>(&self, mut f: F) -> Gray<B> where F: FnMut(T) -> B {
+ Gray(f(self.0))
+ }
+}
+
+impl<T: Copy, B> ColorComponentMap<Gray<B>, T, B> for Gray<T> {
+ #[inline(always)]
+ fn map_c<F>(&self, mut f: F) -> Gray<B> where F: FnMut(T) -> B {
+ Gray(f(self.0))
+ }
+}
+
+impl<T: Copy, B> ComponentMap<GrayAlpha<B>, T, B> for GrayAlpha<T> {
+ #[inline(always)]
+ fn map<F>(&self, mut f: F) -> GrayAlpha<B>
+ where
+ F: FnMut(T) -> B,
+ {
+ GrayAlpha(f(self.0), f(self.1))
+ }
+}
+
+impl<T: Copy, A: Copy, B> ColorComponentMap<GrayAlpha<B, A>, T, B> for GrayAlpha<T, A> {
+ #[inline(always)]
+ fn map_c<F>(&self, mut f: F) -> GrayAlpha<B, A>
+ where
+ F: FnMut(T) -> B,
+ {
+ GrayAlpha(f(self.0), self.1)
+ }
+}
+
+impl<T> ComponentSlice<T> for GrayAlpha<T> {
+ #[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<T> ComponentSlice<T> for [GrayAlpha<T>] {
+ #[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<T: crate::Pod> ComponentBytes<T> for [GrayAlpha<T>] {}
+
+impl<T> ComponentSlice<T> for Gray<T> {
+ #[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<T> ComponentSlice<T> for [Gray<T>] {
+ #[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<T: crate::Pod> ComponentBytes<T> for [Gray<T>] {}
+
+/// Assumes 255 is opaque
+impl<T: Copy> From<Gray<T>> for GrayAlpha<T, u8> {
+ #[inline(always)]
+ fn from(other: Gray<T>) -> Self {
+ GrayAlpha(other.0, 0xFF)
+ }
+}
+
+/// Assumes 65535 is opaque
+impl<T: Copy> From<Gray<T>> for GrayAlpha<T, u16> {
+ #[inline(always)]
+ fn from(other: Gray<T>) -> 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<u16, u16> = ga.into();
+ assert_eq!(rgba.r, 1);
+ assert_eq!(rgba.g, 1);
+ assert_eq!(rgba.b, 1);
+ assert_eq!(rgba.a, 2);
+}
+
--- /dev/null
+#[cfg(feature = "argb")]
+use crate::alt::{ARGB};
+use crate::alt::{BGR, BGRA};
+use crate::{RGB, RGBA};
+
+impl<T: Copy> From<[T; 3]> for RGB<T> {
+ #[inline(always)]
+ fn from(other: [T; 3]) -> Self {
+ Self {
+ r: other[0],
+ g: other[1],
+ b: other[2],
+ }
+ }
+}
+
+impl<T> Into<[T; 3]> for RGB<T> {
+ #[inline(always)]
+ fn into(self) -> [T; 3] {
+ [self.r, self.g, self.b]
+ }
+}
+
+impl<T: Copy> From<[T; 4]> for RGBA<T> {
+ #[inline(always)]
+ fn from(other: [T; 4]) -> Self {
+ Self {
+ r: other[0],
+ g: other[1],
+ b: other[2],
+ a: other[3],
+ }
+ }
+}
+
+impl<T> Into<[T; 4]> for RGBA<T> {
+ #[inline(always)]
+ fn into(self) -> [T; 4] {
+ [self.r, self.g, self.b, self.a]
+ }
+}
+
+#[cfg(feature = "argb")]
+impl<T: Copy> From<[T; 4]> for ARGB<T> {
+ #[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<T> Into<[T; 4]> for ARGB<T> {
+ #[inline(always)]
+ fn into(self) -> [T; 4] {
+ [self.a, self.r, self.g, self.b]
+ }
+}
+
+impl<T: Copy> From<[T; 3]> for BGR<T> {
+ #[inline(always)]
+ fn from(other: [T; 3]) -> Self {
+ Self {
+ b: other[0],
+ g: other[1],
+ r: other[2],
+ }
+ }
+}
+
+impl<T> Into<[T; 3]> for BGR<T> {
+ #[inline(always)]
+ fn into(self) -> [T; 3] {
+ [self.b, self.g, self.r]
+ }
+}
+
+impl<T: Copy> From<[T; 4]> for BGRA<T> {
+ #[inline(always)]
+ fn from(other: [T; 4]) -> Self {
+ Self {
+ b: other[0],
+ g: other[1],
+ r: other[2],
+ a: other[3],
+ }
+ }
+}
+
+impl<T> Into<[T; 4]> for BGRA<T> {
+ #[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]);
+}
--- /dev/null
+use 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<PixelType> {
+ /// 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<T> AsPixels<$typ<T>> for [T] {
+ fn as_pixels(&self) -> &[$typ<T>] {
+ unsafe {
+ slice::from_raw_parts(self.as_ptr() as *const _, self.len() / $elems)
+ }
+ }
+ fn as_pixels_mut(&mut self) -> &mut [$typ<T>] {
+ 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<T: Copy> {
+ /// Reinterpert slice as RGB pixels
+ fn as_rgb(&self) -> &[RGB<T>];
+ /// Reinterpert slice as RGBA pixels
+ fn as_rgba(&self) -> &[RGBA<T>];
+ /// Reinterpert slice as alpha-first ARGB pixels
+ #[cfg(feature = "argb")]
+ fn as_argb(&self) -> &[ARGB<T>];
+ /// Reinterpert mutable slice as RGB pixels
+ fn as_rgb_mut(&mut self) -> &mut [RGB<T>];
+ /// Reinterpert mutable slice as RGBA pixels
+ fn as_rgba_mut(&mut self) -> &mut [RGBA<T>];
+ /// Reinterpert mutable slice as alpha-first ARGB pixels
+ #[cfg(feature = "argb")]
+ fn as_argb_mut(&mut self) -> &mut [ARGB<T>];
+
+ /// Reinterpert mutable slice as grayscale pixels
+ fn as_gray(&self) -> &[Gray<T>];
+ /// Reinterpert mutable slice as grayscale pixels with alpha
+ fn as_gray_alpha(&self) -> &[GrayAlpha<T>];
+ /// Reinterpert mutable slice as grayscale pixels
+ fn as_gray_mut(&mut self) -> &mut [Gray<T>];
+ /// Reinterpert mutable slice as grayscale pixels with alpha
+ fn as_gray_alpha_mut(&mut self) -> &mut [GrayAlpha<T>];
+
+ /// Reinterpert slice as reverse-order BGR pixels
+ fn as_bgr(&self) -> &[BGR<T>];
+ /// Reinterpert slice as reverse-order BGRA pixels
+ fn as_bgra(&self) -> &[BGRA<T>];
+ /// Reinterpert slice as reverse-order ABGR pixels
+ #[cfg(feature = "argb")]
+ fn as_abgr(&self) -> &[ABGR<T>];
+ /// Reinterpert ntable slice as reverse-order BGR pixels
+ fn as_bgr_mut(&mut self) -> &mut [BGR<T>];
+ /// Reinterpert mutable slice as reverse-order alpha-last BGRA pixels
+ fn as_bgra_mut(&mut self) -> &mut [BGRA<T>];
+ /// Reinterpert mutable slice as reverse-order alpha-first ABGR pixels
+ #[cfg(feature = "argb")]
+ fn as_abgr_mut(&mut self) -> &mut [ABGR<T>];
+}
+
+impl<T: Copy> FromSlice<T> for [T] {
+ #[inline]
+ fn as_rgb(&self) -> &[RGB<T>] {
+ unsafe { from_items_to_struct(self) }
+ }
+
+ #[inline]
+ fn as_rgba(&self) -> &[RGBA<T>] {
+ unsafe { from_items_to_struct(self) }
+ }
+
+ #[inline]
+ #[cfg(feature = "argb")]
+ fn as_argb(&self) -> &[ARGB<T>] {
+ unsafe { from_items_to_struct(self) }
+ }
+
+ #[inline]
+ fn as_rgb_mut(&mut self) -> &mut [RGB<T>] {
+ unsafe { from_items_to_struct_mut(self) }
+ }
+
+ #[inline]
+ fn as_rgba_mut(&mut self) -> &mut [RGBA<T>] {
+ unsafe { from_items_to_struct_mut(self) }
+ }
+
+ #[inline]
+ #[cfg(feature = "argb")]
+ fn as_argb_mut(&mut self) -> &mut [ARGB<T>] {
+ unsafe { from_items_to_struct_mut(self) }
+ }
+
+ #[inline]
+ fn as_gray(&self) -> &[Gray<T>] {
+ unsafe { from_items_to_struct(self) }
+ }
+
+ #[inline]
+ fn as_gray_alpha(&self) -> &[GrayAlpha<T>] {
+ unsafe { from_items_to_struct(self) }
+ }
+
+ #[inline]
+ fn as_gray_mut(&mut self) -> &mut [Gray<T>] {
+ unsafe { from_items_to_struct_mut(self) }
+ }
+
+ #[inline]
+ fn as_gray_alpha_mut(&mut self) -> &mut [GrayAlpha<T>] {
+ unsafe { from_items_to_struct_mut(self) }
+ }
+
+
+ #[inline]
+ fn as_bgr(&self) -> &[BGR<T>] {
+ unsafe { from_items_to_struct(self) }
+ }
+
+ #[inline]
+ #[cfg(feature = "argb")]
+ fn as_abgr(&self) -> &[ABGR<T>] {
+ unsafe { from_items_to_struct(self) }
+ }
+
+ #[inline]
+ fn as_bgra(&self) -> &[BGRA<T>] {
+ unsafe { from_items_to_struct(self) }
+ }
+
+ #[inline]
+ fn as_bgr_mut(&mut self) -> &mut [BGR<T>] {
+ unsafe { from_items_to_struct_mut(self) }
+ }
+
+ #[inline]
+ fn as_bgra_mut(&mut self) -> &mut [BGRA<T>] {
+ unsafe { from_items_to_struct_mut(self) }
+ }
+
+ #[inline]
+ #[cfg(feature = "argb")]
+ fn as_abgr_mut(&mut self) -> &mut [ABGR<T>] {
+ unsafe { from_items_to_struct_mut(self) }
+ }
+}
+
+#[inline(always)]
+unsafe fn from_items_to_struct<F, T>(from: &[F]) -> &[T] {
+ debug_assert_eq!(0, mem::size_of::<T>() % mem::size_of::<F>());
+ let len = from.len() / (mem::size_of::<T>() / mem::size_of::<F>());
+ slice::from_raw_parts(from.as_ptr() as *const T, len)
+}
+
+#[inline(always)]
+unsafe fn from_items_to_struct_mut<F, T>(from: &mut [F]) -> &mut [T] {
+ debug_assert_eq!(0, mem::size_of::<T>() % mem::size_of::<F>());
+ let len = from.len() / (mem::size_of::<T>() / mem::size_of::<F>());
+ 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<T> From<$t1<T>> for $t2<T> where T: ::core::clone::Clone {
+ fn from(other: $t1<T>) -> 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<T: Clone> From<Gray<T>> for RGB<T> {
+ #[inline(always)]
+ fn from(other: Gray<T>) -> Self {
+ Self {
+ r: other.0.clone(),
+ g: other.0.clone(),
+ b: other.0,
+ }
+ }
+}
+
+impl<T: Clone> From<Gray<T>> for RGBA<T, u8> {
+ #[inline(always)]
+ fn from(other: Gray<T>) -> Self {
+ Self {
+ r: other.0.clone(),
+ g: other.0.clone(),
+ b: other.0,
+ a: 255,
+ }
+ }
+}
+
+impl<T: Clone,A> From<GrayAlpha<T,A>> for RGBA<T,A> {
+ #[inline(always)]
+ fn from(other: GrayAlpha<T,A>) -> Self {
+ Self {
+ r: other.0.clone(),
+ g: other.0.clone(),
+ b: other.0,
+ a: other.1,
+ }
+ }
+}
+
+impl<T> AsRef<T> for Gray<T> {
+ #[inline(always)]
+ fn as_ref(&self) -> &T {
+ &self.0
+ }
+}
+
+impl<T> AsRef<[T]> for RGB<T> {
+ #[inline(always)]
+ fn as_ref(&self) -> &[T] {
+ self.as_slice()
+ }
+}
+
+impl<T> AsRef<[T]> for RGBA<T> {
+ #[inline(always)]
+ fn as_ref(&self) -> &[T] {
+ self.as_slice()
+ }
+}
+
+impl<T> AsRef<T> for GrayAlpha<T> {
+ #[inline(always)]
+ fn as_ref(&self) -> &T {
+ &self.0
+ }
+}
+
+
+impl<T> AsMut<T> for Gray<T> {
+ #[inline(always)]
+ fn as_mut(&mut self) -> &mut T {
+ &mut self.0
+ }
+}
+
+impl<T> AsMut<[T]> for RGB<T> {
+ #[inline(always)]
+ fn as_mut(&mut self) -> &mut [T] {
+ self.as_mut_slice()
+ }
+}
+
+impl<T> AsMut<[T]> for RGBA<T> {
+ #[inline(always)]
+ fn as_mut(&mut self) -> &mut [T] {
+ self.as_mut_slice()
+ }
+}
+
+impl<T> AsMut<T> for GrayAlpha<T> {
+ #[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());
+}
+
--- /dev/null
+use crate::alt::BGR;
+use crate::alt::BGRA;
+use crate::RGB;
+use crate::RGBA;
+use core::convert::*;
+
+impl<T> From<(T,T,T)> for RGB<T> {
+ #[inline]
+ fn from(other: (T,T,T)) -> Self {
+ Self {
+ r: other.0,
+ g: other.1,
+ b: other.2,
+ }
+ }
+}
+
+impl<T> Into<(T,T,T)> for RGB<T> {
+ #[inline]
+ fn into(self) -> (T,T,T) {
+ (self.r, self.g, self.b)
+ }
+}
+
+impl<T,A> From<(T,T,T,A)> for RGBA<T,A> {
+ #[inline]
+ fn from(other: (T,T,T,A)) -> Self {
+ Self {
+ r: other.0,
+ g: other.1,
+ b: other.2,
+ a: other.3,
+ }
+ }
+}
+
+impl<T,A> Into<(T,T,T,A)> for RGBA<T,A> {
+ #[inline]
+ fn into(self) -> (T,T,T,A) {
+ (self.r, self.g, self.b, self.a)
+ }
+}
+
+impl<T> From<(T,T,T)> for BGR<T> {
+ #[inline(always)]
+ fn from(other: (T,T,T)) -> Self {
+ Self {
+ b: other.0,
+ g: other.1,
+ r: other.2,
+ }
+ }
+}
+
+impl<T> Into<(T,T,T)> for BGR<T> {
+ #[inline(always)]
+ fn into(self) -> (T,T,T) {
+ (self.b, self.g, self.r)
+ }
+}
+
+impl<T,A> From<(T,T,T,A)> for BGRA<T,A> {
+ #[inline(always)]
+ fn from(other: (T,T,T,A)) -> Self {
+ Self {
+ b: other.0,
+ g: other.1,
+ r: other.2,
+ a: other.3,
+ }
+ }
+}
+
+impl<T,A> Into<(T,T,T,A)> for BGRA<T,A> {
+ #[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());
+}
--- /dev/null
+use 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<T: Add> Add for $ty<T> {
+ type Output = $ty<<T as Add>::Output>;
+
+ #[inline(always)]
+ fn add(self, other: $ty<T>) -> Self::Output {
+ $ty {
+ $(
+ $field: self.$field + other.$field,
+ )+
+ }
+ }
+ }
+
+ /// `px + px`
+ impl<T> AddAssign for $ty<T> where
+ T: Add<Output = T> + Copy
+ {
+ #[inline(always)]
+ fn add_assign(&mut self, other: $ty<T>) {
+ *self = Self {
+ $(
+ $field: self.$field + other.$field,
+ )+
+ };
+ }
+ }
+
+ /// `px * px`
+ impl<T: Mul> Mul for $ty<T> {
+ type Output = $ty<<T as Mul>::Output>;
+
+ #[inline(always)]
+ fn mul(self, other: $ty<T>) -> Self::Output {
+ $ty {
+ $(
+ $field: self.$field * other.$field,
+ )+
+ }
+ }
+ }
+
+ /// `px * px`
+ impl<T> MulAssign for $ty<T> where
+ T: Mul<Output = T> + Copy
+ {
+ #[inline(always)]
+ fn mul_assign(&mut self, other: $ty<T>) {
+ *self = Self {
+ $(
+ $field: self.$field * other.$field,
+ )+
+ };
+ }
+ }
+
+ /// `px - px`
+ impl<T: Sub> Sub for $ty<T> {
+ type Output = $ty<<T as Sub>::Output>;
+
+ #[inline(always)]
+ fn sub(self, other: $ty<T>) -> Self::Output {
+ $ty {
+ $(
+ $field: self.$field - other.$field,
+ )+
+ }
+ }
+ }
+
+ /// `px - px`
+ impl<T> SubAssign for $ty<T> where
+ T: Sub<Output = T> + Copy
+ {
+ #[inline(always)]
+ fn sub_assign(&mut self, other: $ty<T>) {
+ *self = Self {
+ $(
+ $field: self.$field - other.$field,
+ )+
+ };
+ }
+ }
+
+ impl<T> Sum<$ty<T>> for $ty<T> where T: Default + Add<Output=T> {
+ #[inline(always)]
+ fn sum<I: Iterator<Item=Self>>(iter: I) -> Self {
+ iter.fold($ty::default(), Add::add)
+ }
+ }
+ };
+}
+
+macro_rules! impl_struct_ops_alpha {
+ ($ty:ident => $($field:tt)+) => {
+ /// `px + px`
+ impl<T: Add, A: Add> Add for $ty<T, A> {
+ type Output = $ty<<T as Add>::Output, <A as Add>::Output>;
+
+ #[inline(always)]
+ fn add(self, other: $ty<T, A>) -> Self::Output {
+ $ty {
+ $(
+ $field: self.$field + other.$field,
+ )+
+ }
+ }
+ }
+
+ /// `px + px`
+ impl<T, A> AddAssign for $ty<T, A> where
+ T: Add<Output = T> + Copy,
+ A: Add<Output = A> + Copy
+ {
+ #[inline(always)]
+ fn add_assign(&mut self, other: $ty<T, A>) {
+ *self = Self {
+ $(
+ $field: self.$field + other.$field,
+ )+
+ };
+ }
+ }
+
+ /// `px - px`
+ impl<T: Sub, A: Sub> Sub for $ty<T, A> {
+ type Output = $ty<<T as Sub>::Output, <A as Sub>::Output>;
+
+ #[inline(always)]
+ fn sub(self, other: $ty<T, A>) -> Self::Output {
+ $ty {
+ $(
+ $field: self.$field - other.$field,
+ )+
+ }
+ }
+ }
+
+ /// `px - px`
+ impl<T, A> SubAssign for $ty<T, A> where
+ T: Sub<Output = T> + Copy,
+ A: Sub<Output = A> + Copy
+ {
+ #[inline(always)]
+ fn sub_assign(&mut self, other: $ty<T, A>) {
+ *self = Self {
+ $(
+ $field: self.$field - other.$field,
+ )+
+ };
+ }
+ }
+
+ impl<T, A> Sum<$ty<T, A>> for $ty<T, A> where T: Default + Add<Output=T>, A: Default + Add<Output=A> {
+ #[inline(always)]
+ fn sum<I: Iterator<Item=Self>>(iter: I) -> Self {
+ iter.fold($ty::default(), Add::add)
+ }
+ }
+ };
+}
+
+macro_rules! impl_scalar {
+ ($ty:ident) => {
+ /// `px - 1`
+ impl<T> Sub<T> for $ty<T> where
+ T: Copy + Sub<Output=T>
+ {
+ type Output = $ty<<T as Sub>::Output>;
+
+ #[inline(always)]
+ fn sub(self, r: T) -> Self::Output {
+ self.map(|l| l-r)
+ }
+ }
+
+ /// `px - 1`
+ impl<T> SubAssign<T> for $ty<T> where
+ T: Copy + Sub<Output=T>
+ {
+ #[inline(always)]
+ fn sub_assign(&mut self, r: T) {
+ *self = self.map(|l| l-r);
+ }
+ }
+
+ /// `px + 1`
+ impl<T> Add<T> for $ty<T> where
+ T: Copy + Add<Output=T>
+ {
+ type Output = $ty<T>;
+
+ #[inline(always)]
+ fn add(self, r: T) -> Self::Output {
+ self.map(|l|l+r)
+ }
+ }
+
+ /// `px + 1`
+ impl<T> AddAssign<T> for $ty<T> where
+ T: Copy + Add<Output=T>
+ {
+ #[inline(always)]
+ fn add_assign(&mut self, r: T) {
+ *self = self.map(|l| l+r);
+ }
+ }
+
+ /// `px * 1`
+ impl<T> Mul<T> for $ty<T> where
+ T: Copy + Mul<Output=T>
+ {
+ type Output = $ty<T>;
+
+ #[inline(always)]
+ fn mul(self, r: T) -> Self::Output {
+ self.map(|l|l*r)
+ }
+ }
+
+ /// `px * 1`
+ impl<T> MulAssign<T> for $ty<T> where
+ T: Copy + Mul<Output=T>
+ {
+ #[inline(always)]
+ fn mul_assign(&mut self, r: T) {
+ *self = self.map(|l| l*r);
+ }
+ }
+
+ /// `px / 1`
+ impl<T> Div<T> for $ty<T> where
+ T: Copy + Div<Output=T>
+ {
+ type Output = $ty<T>;
+
+ #[inline(always)]
+ fn div(self, r: T) -> Self::Output {
+ self.map(|l| l / r)
+ }
+ }
+
+ /// `px * 1`
+ impl<T> DivAssign<T> for $ty<T> where
+ T: Copy + Div<Output=T>
+ {
+ #[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<u8> = RGB::new(255, 255, 255);
+ const BLACK_RGB: RGB<u8> = RGB::new(0, 0, 0);
+ const RED_RGB: RGB<u8> = RGB::new(255, 0, 0);
+ const GREEN_RGB: RGB<u8> = RGB::new(0, 255, 0);
+ const BLUE_RGB: RGB<u8> = RGB::new(0, 0, 255);
+
+ const WHITE_RGBA: RGBA<u8> = RGBA::new(255, 255, 255, 255);
+ const BLACK_RGBA: RGBA<u8> = RGBA::new(0, 0, 0, 0);
+ const RED_RGBA: RGBA<u8> = RGBA::new(255, 0, 0, 255);
+ const GREEN_RGBA: RGBA<u8> = RGBA::new(0, 255, 0, 0);
+ const BLUE_RGBA: RGBA<u8> = 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::<RGB<u8>>();
+ let s2 = [RGB::new(1u16,1,1), RGB::new(2,3,4)].iter().copied().sum::<RGB<u16>>();
+ let s3 = [RGBA::new_alpha(1u8,1,1,1u16), RGBA::new_alpha(2,3,4,5)].iter().copied().sum::<RGBA<u8, u16>>();
+ let s4 = [RGBA::new_alpha(1u16,1,1,1u8), RGBA::new_alpha(2,3,4,5)].iter().copied().sum::<RGBA<u16, u8>>();
+ 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));
+ }
+}
--- /dev/null
+
+/// Casting the struct to slices of its components
+pub trait ComponentSlice<T> {
+ /// 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<MyCustomType>`, 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<T: crate::Pod> where Self: ComponentSlice<T> {
+ /// 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::<T>());
+ let slice = self.as_slice();
+ unsafe {
+ core::slice::from_raw_parts(slice.as_ptr() as *const _, slice.len() * core::mem::size_of::<T>())
+ }
+ }
+
+ /// 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::<T>());
+ 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::<T>())
+ }
+ }
+}
+
+/// 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<DestPixel, SrcComponent, DestComponent> {
+ /// 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<Callback>(&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<DestPixel, SrcComponent, DestComponent> {
+ /// 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<Callback>(&self, f: Callback) -> DestPixel
+ where Callback: FnMut(SrcComponent) -> DestComponent;
+}
--- /dev/null
+use 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<T> RGB<T> {
+ /// 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<T> BGR<T> {
+ /// 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<T> crate::Pod for RGB<T> where T: crate::Pod {}
+#[cfg(feature = "as-bytes")]
+unsafe impl<T> crate::Pod for BGR<T> where T: crate::Pod {}
+#[cfg(feature = "as-bytes")]
+unsafe impl<T> crate::Zeroable for RGB<T> where T: crate::Zeroable {}
+#[cfg(feature = "as-bytes")]
+unsafe impl<T> crate::Zeroable for BGR<T> where T: crate::Zeroable {}
+
+macro_rules! impl_rgb {
+ ($RGB:ident) => {
+ impl<T: Clone> $RGB<T> {
+ /// Iterate over color components (R, G, and B)
+ #[inline(always)]
+ pub fn iter(&self) -> core::iter::Cloned<core::slice::Iter<'_, T>> {
+ self.as_slice().iter().cloned()
+ }
+ }
+
+ impl<T: Copy, B> ComponentMap<$RGB<B>, T, B> for $RGB<T> {
+ #[inline(always)]
+ fn map<F>(&self, mut f: F) -> $RGB<B>
+ where F: FnMut(T) -> B {
+ $RGB {
+ r:f(self.r),
+ g:f(self.g),
+ b:f(self.b),
+ }
+ }
+ }
+
+ impl<T: Copy, B> ColorComponentMap<$RGB<B>, T, B> for $RGB<T> {
+ #[inline(always)]
+ fn map_c<F>(&self, mut f: F) -> $RGB<B>
+ where F: FnMut(T) -> B {
+ $RGB {
+ r:f(self.r),
+ g:f(self.g),
+ b:f(self.b),
+ }
+ }
+ }
+
+ impl<T> ComponentSlice<T> for $RGB<T> {
+ #[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<T> ComponentSlice<T> for [$RGB<T>] {
+ #[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<T: crate::Pod> ComponentBytes<T> for [$RGB<T>] {}
+ }
+}
+
+macro_rules! impl_rgb_to_alpha {
+ ($RGB:ident, $RGBA:ident) => {
+ impl<T: Clone> $RGB<T> {
+ /// Convenience function for converting to RGBA
+ #[inline(always)]
+ pub fn alpha(&self, a: T) -> $RGBA<T> {
+ $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<A>(&self, a: A) -> $RGBA<T, A> {
+ $RGBA {
+ r: self.r.clone(),
+ g: self.g.clone(),
+ b: self.b.clone(),
+ a,
+ }
+ }
+ }
+ }
+}
+
+
+impl<T> core::iter::FromIterator<T> for RGB<T> {
+ /// 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<I: IntoIterator<Item = T>>(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<T: fmt::Display> fmt::Display for RGB<T> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f,"rgb({},{},{})", self.r,self.g,self.b)
+ }
+}
+
+impl<T: fmt::UpperHex> fmt::UpperHex for RGB<T> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f,"RGB {{ #{:02X}{:02X}{:02X} }}", self.r, self.g, self.b)
+ }
+}
+
+impl<T: fmt::LowerHex> fmt::LowerHex for RGB<T> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f,"RGB {{ #{:02x}{:02x}{:02x} }}", self.r, self.g, self.b)
+ }
+}
+
+impl<T: fmt::Display> fmt::Display for BGR<T> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f,"bgr({},{},{})", self.b, self.g, self.r)
+ }
+}
+
+impl<T: fmt::UpperHex> fmt::UpperHex for BGR<T> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f,"BGR {{ #{:02X}{:02X}{:02X} }}", self.b, self.g, self.r)
+ }
+}
+
+impl<T: fmt::LowerHex> fmt::LowerHex for BGR<T> {
+ 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));
+ }
+}
--- /dev/null
+use core::fmt;
+use crate::alt::*;
+use crate::RGB;
+use crate::RGBA;
+use super::pixel::*;
+
+impl<T> RGBA<T> {
+ #[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<T, A> RGBA<T,A> {
+ #[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<T> BGRA<T> {
+ #[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<T, A> BGRA<T,A> {
+ #[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<T, A> crate::Pod for RGBA<T, A> where T: crate::Pod, A: crate::Pod {}
+#[cfg(feature = "as-bytes")]
+unsafe impl<T, A> crate::Pod for BGRA<T, A> where T: crate::Pod, A: crate::Pod {}
+#[cfg(feature = "as-bytes")]
+unsafe impl<T, A> crate::Zeroable for RGBA<T, A> where T: crate::Zeroable, A: crate::Zeroable {}
+#[cfg(feature = "as-bytes")]
+unsafe impl<T, A> crate::Zeroable for BGRA<T, A> where T: crate::Zeroable, A: crate::Zeroable {}
+
+#[cfg(feature = "argb")]
+impl<T> ARGB<T> {
+ #[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<T, A> ARGB<T,A> {
+ #[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<T> ABGR<T> {
+ #[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<T, A> ABGR<T,A> {
+ #[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<T, A> crate::Pod for ARGB<T, A> where T: crate::Pod, A: crate::Pod {}
+#[cfg(all(feature = "as-bytes", feature = "argb"))]
+unsafe impl<T, A> crate::Pod for ABGR<T, A> where T: crate::Pod, A: crate::Pod {}
+#[cfg(all(feature = "as-bytes", feature = "argb"))]
+unsafe impl<T, A> crate::Zeroable for ARGB<T, A> where T: crate::Zeroable, A: crate::Zeroable {}
+#[cfg(all(feature = "as-bytes", feature = "argb"))]
+unsafe impl<T, A> crate::Zeroable for ABGR<T, A> where T: crate::Zeroable, A: crate::Zeroable {}
+
+macro_rules! impl_rgba {
+ ($RGBA:ident) => {
+ impl<T: Clone> $RGBA<T> {
+ /// Iterate over all components (length=4)
+ #[inline(always)]
+ pub fn iter(&self) -> core::iter::Cloned<core::slice::Iter<'_, T>> {
+ self.as_slice().iter().cloned()
+ }
+ }
+
+ impl<T: Clone, A> $RGBA<T, A> {
+ /// 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<T> {
+ BGR {r:self.r.clone(), g:self.g.clone(), b:self.b.clone()}
+ }
+ }
+
+ impl<T: Copy, A: Clone> $RGBA<T, A> {
+ /// Create new RGBA with the same alpha value, but different RGB values
+ #[inline(always)]
+ pub fn map_rgb<F, U, B>(&self, mut f: F) -> $RGBA<U, B>
+ where F: FnMut(T) -> U, U: Clone, B: From<A> + 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<F, B>(&self, f: F) -> $RGBA<T, B>
+ where F: FnOnce(A) -> B {
+ $RGBA {
+ r: self.r,
+ g: self.g,
+ b: self.b,
+ a: f(self.a.clone()),
+ }
+ }
+ }
+
+ impl<T: Copy, B> ComponentMap<$RGBA<B>, T, B> for $RGBA<T> {
+ #[inline(always)]
+ fn map<F>(&self, mut f: F) -> $RGBA<B>
+ where
+ F: FnMut(T) -> B,
+ {
+ $RGBA {
+ r: f(self.r),
+ g: f(self.g),
+ b: f(self.b),
+ a: f(self.a),
+ }
+ }
+ }
+
+ impl<T: Copy, A: Copy, B> ColorComponentMap<$RGBA<B, A>, T, B> for $RGBA<T, A> {
+ #[inline(always)]
+ fn map_c<F>(&self, mut f: F) -> $RGBA<B, A>
+ where
+ F: FnMut(T) -> B,
+ {
+ $RGBA {
+ r: f(self.r),
+ g: f(self.g),
+ b: f(self.b),
+ a: self.a,
+ }
+ }
+ }
+
+ impl<T> ComponentSlice<T> for $RGBA<T> {
+ #[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<T> ComponentSlice<T> for [$RGBA<T>] {
+ #[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<T: crate::Pod> ComponentBytes<T> for [$RGBA<T>] {}
+ }
+}
+
+macro_rules! impl_alpha_conv {
+ ($RGB:ident, $RGBA:ident) => {
+ /// Assumes 255 is opaque
+ impl<T: Copy> From<$RGB<T>> for $RGBA<T, u8> {
+ #[inline(always)]
+ fn from(other: $RGB<T>) -> Self {
+ Self {
+ r: other.r,
+ g: other.g,
+ b: other.b,
+ a: 0xFF,
+ }
+ }
+ }
+
+ /// Assumes 65535 is opaque
+ impl<T: Copy> From<$RGB<T>> for $RGBA<T, u16> {
+ #[inline(always)]
+ fn from(other: $RGB<T>) -> Self {
+ Self {
+ r: other.r,
+ g: other.g,
+ b: other.b,
+ a: 0xFFFF,
+ }
+ }
+ }
+ }
+}
+
+impl<T, A> RGBA<T, A> {
+ /// 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<T> {
+ unsafe {
+ &mut *(self as *mut _ as *mut RGB<T>)
+ }
+ }
+}
+
+impl<T, A> BGRA<T, A> {
+ /// 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<T> {
+ unsafe {
+ &mut *(self as *mut _ as *mut BGR<T>)
+ }
+ }
+
+ /// 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<T> {
+ unsafe {
+ &mut *(self as *mut _ as *mut BGR<T>)
+ }
+ }
+}
+
+impl<T> core::iter::FromIterator<T> for RGBA<T> {
+ #[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<I: IntoIterator<Item = T>>(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<T: Clone, A> RGBA<T, A> {
+ /// 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<T> {
+ RGB {r:self.r.clone(), g:self.g.clone(), b:self.b.clone()}
+ }
+}
+
+impl<T: Clone, A> BGRA<T, A> {
+ /// 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<T> {
+ 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<T: fmt::Display, A: fmt::Display> fmt::Display for RGBA<T, A> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "rgba({},{},{},{})", self.r, self.g, self.b, self.a)
+ }
+}
+
+impl<T: fmt::Display, A: fmt::Display> fmt::Display for BGRA<T, A> {
+ 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());
+ }
+}
--- /dev/null
+//! 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<ComponentType> {
+ /// 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<LinearLight<u16>, u16>`).
+pub struct RGBA<ComponentType, AlphaComponentType = ComponentType> {
+ /// 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<u8>;
+
+/// 16-bit RGB in machine's native endian
+///
+/// Be careful to perform byte-swapping when reading from files.
+pub type RGB16 = RGB<u16>;
+
+/// 8-bit RGBA, alpha is last. 0 = transparent, 255 = opaque.
+pub type RGBA8 = RGBA<u8>;
+
+/// 16-bit RGB in machine's native endian. 0 = transparent, 65535 = opaque.
+///
+/// Alpha is last.
+pub type RGBA16 = RGBA<u16>;
+
+#[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<i16> = a.into();
+ let c:RGB<f32> = b.into();
+ let d:RGB<f32> = 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[..]);
+}