rgb-0.8.11/Cargo.toml.orig010064400007650000024000000017251332414446400134730ustar0000000000000000[package] name = "rgb" version = "0.8.11" authors = ["Kornel Lesiński "] include = ["src/**/*", "Cargo.toml", "README.md", "examples/*.rs"] description = "`struct RGB` (etc.) for sharing pixels between crates.\nAllows no-copy high-level interoperability. Also adds common convenience methods and implements standard Rust traits to make RGB/RGBA pixels first-class Rust objects." documentation = "https://kornelski.github.io/rust-rgb/rgb/" repository = "https://github.com/kornelski/rust-rgb" homepage = "https://crates.rs/crates/rgb" readme = "README.md" keywords = ["rgb", "rgba", "bgra", "pixel", "interoperability"] license = "MIT" categories = ["rust-patterns", "multimedia::images"] [badges] travis-ci = { repository = "kornelski/rust-rgb" } [dependencies] serde = { version = "1.0", optional = true, features = ["derive"] } [dev-dependencies] serde_json = "1.0" [[example]] name = "serde" required-features = ["serde"] [[example]] name = "example" rgb-0.8.11/Cargo.toml0000644000000027300000000000000077340ustar00# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g. crates.io) dependencies # # If you believe there's an error in this file please file an # issue against the rust-lang/cargo repository. If you're # editing this file be aware that the upstream Cargo.toml # will likely look very different (and much more reasonable) [package] name = "rgb" version = "0.8.11" authors = ["Kornel Lesiński "] include = ["src/**/*", "Cargo.toml", "README.md", "examples/*.rs"] description = "`struct RGB` (etc.) for sharing pixels between crates.\nAllows no-copy high-level interoperability. Also adds common convenience methods and implements standard Rust traits to make RGB/RGBA pixels first-class Rust objects." homepage = "https://crates.rs/crates/rgb" documentation = "https://kornelski.github.io/rust-rgb/rgb/" readme = "README.md" keywords = ["rgb", "rgba", "bgra", "pixel", "interoperability"] categories = ["rust-patterns", "multimedia::images"] license = "MIT" repository = "https://github.com/kornelski/rust-rgb" [[example]] name = "serde" required-features = ["serde"] [[example]] name = "example" [dependencies.serde] version = "1.0" features = ["derive"] optional = true [dev-dependencies.serde_json] version = "1.0" [badges.travis-ci] repository = "kornelski/rust-rgb" rgb-0.8.11/README.md010064400007650000024000000033601332414120700120500ustar0000000000000000# `struct RGB` for [Rust](https://www.rust-lang.org) [![v](https://img.shields.io/crates/v/rgb.svg)](https://crates.io/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 extern crate rgb; 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 functinos 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(); ``` ---- ## About colorspaces This crate is intentionally ignorant about flavors of RGB color spaces. *Correct* color management is a complex problem, and this crate aims to be the lowest common denominator. However, it 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; ``` rgb-0.8.11/examples/example.rs010064400007650000024000000005301332414120700144040ustar0000000000000000extern crate rgb; 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) } rgb-0.8.11/examples/serde.rs010064400007650000024000000005341332414120700140570ustar0000000000000000extern 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.11/src/alt.rs010064400007650000024000000141021332414437100125070ustar0000000000000000use core::ops; use core::mem; use core::slice; use internal::pixel::*; #[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, } pub type BGR8 = BGR; /// 16-bit BGR in machine's native endian pub type BGR16 = BGR; pub type BGRA8 = BGRA; /// 16-bit BGR in machine's native endian pub type BGRA16 = BGRA; //////////////////////////////////////// #[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); pub type GRAY8 = Gray; /// 16-bit gray in machine's native endian pub type GRAY16 = Gray; pub type GRAYA8 = GrayAlpha; /// 16-bit gray in machine's native endian pub type GRAYA16 = GrayAlpha; impl ops::Deref for Gray { type Target = T; fn deref(&self) -> &T { &self.0 } } impl From for Gray { fn from(component: T) -> Self { Gray(component) } } impl GrayAlpha { /// Copy `Gray` component out of the `GrayAlpha` struct #[inline(always)] pub fn gray(&self) -> Gray { Gray(self.0.clone()) } } impl GrayAlpha { /// Provide a mutable view of only `Gray` component (leaving out alpha). #[inline(always)] pub fn gray_mut(&mut self) -> &mut Gray { unsafe { mem::transmute(self) } } } impl GrayAlpha { /// 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.clone()), self.1.clone().into()) } } 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 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) } } } impl ComponentBytes for [GrayAlpha] {} impl ComponentSlice for Gray { #[inline(always)] fn as_slice(&self) -> &[T] { unsafe { slice::from_raw_parts(self as *const Self as *const T, 1) } } #[inline(always)] fn as_mut_slice(&mut self) -> &mut [T] { unsafe { slice::from_raw_parts_mut(self as *mut Self as *mut T, 1) } } } 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()) } } } impl ComponentBytes for [Gray] {} /// Assumes 255 is opaque impl From> for GrayAlpha { fn from(other: Gray) -> Self { GrayAlpha(other.0, 0xFF) } } /// Assumes 65535 is opaque impl From> for GrayAlpha { fn from(other: Gray) -> Self { GrayAlpha(other.0, 0xFFFF) } } #[test] fn gray() { let rgb: ::RGB<_> = Gray(1).into(); assert_eq!(rgb.r, 1); assert_eq!(rgb.g, 1); assert_eq!(rgb.b, 1); let g: GRAY8 = 100.into(); assert_eq!(110, *g + 10); assert_eq!(110, 10 + Gray(100).as_ref()); let ga: GRAYA8 = GrayAlpha(1, 2); assert_eq!(ga.gray(), Gray(1)); let mut g2 = ga.clone(); *g2.gray_mut() = Gray(3); assert_eq!(g2.map_gray(|g| g+1), GrayAlpha(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!((&[Gray(1u16), Gray(2)][..]).as_slice(), &[1, 2]); assert_eq!((&[GrayAlpha(1u16, 2), GrayAlpha(3, 4)][..]).as_slice(), &[1, 2, 3, 4]); let rgba: ::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: ::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.11/src/internal/convert/mod.rs010064400007650000024000000153421332414120700160040ustar0000000000000000use core::convert::*; use super::pixel::*; use core::slice; use core::mem; use RGB; use RGBA; use alt::BGR; use alt::BGRA; use alt::Gray; use alt::GrayAlpha; mod tuple; /// 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 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 slice as reverse-order BGR pixels fn as_bgr(&self) -> &[BGR]; /// Reinterpert slice as reverse-order BGRA pixels fn as_bgra(&self) -> &[BGRA]; /// Reinterpert ntable slice as reverse-order BGR pixels fn as_bgr_mut(&mut self) -> &mut [BGR]; /// Reinterpert mutable slice as reverse-order BGRA pixels fn as_bgra_mut(&mut self) -> &mut [BGRA]; } impl FromSlice for [T] { fn as_rgb(&self) -> &[RGB] { debug_assert_eq!(3, mem::size_of::>() / mem::size_of::()); unsafe { slice::from_raw_parts(self.as_ptr() as *const _, self.len() / 3) } } fn as_rgba(&self) -> &[RGBA] { debug_assert_eq!(4, mem::size_of::>() / mem::size_of::()); unsafe { slice::from_raw_parts(self.as_ptr() as *const _, self.len() / 4) } } fn as_rgb_mut(&mut self) -> &mut [RGB] { debug_assert_eq!(3, mem::size_of::>() / mem::size_of::()); unsafe { slice::from_raw_parts_mut(self.as_ptr() as *mut _, self.len() / 3) } } fn as_rgba_mut(&mut self) -> &mut [RGBA] { debug_assert_eq!(4, mem::size_of::>() / mem::size_of::()); unsafe { slice::from_raw_parts_mut(self.as_ptr() as *mut _, self.len() / 4) } } fn as_bgr(&self) -> &[BGR] { debug_assert_eq!(3, mem::size_of::>() / mem::size_of::()); unsafe { slice::from_raw_parts(self.as_ptr() as *const _, self.len() / 3) } } fn as_bgra(&self) -> &[BGRA] { debug_assert_eq!(4, mem::size_of::>() / mem::size_of::()); unsafe { slice::from_raw_parts(self.as_ptr() as *const _, self.len() / 4) } } fn as_bgr_mut(&mut self) -> &mut [BGR] { debug_assert_eq!(3, mem::size_of::>() / mem::size_of::()); unsafe { slice::from_raw_parts_mut(self.as_ptr() as *mut _, self.len() / 3) } } fn as_bgra_mut(&mut self) -> &mut [BGRA] { debug_assert_eq!(4, mem::size_of::>() / mem::size_of::()); unsafe { slice::from_raw_parts_mut(self.as_ptr() as *mut _, self.len() / 4) } } } 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(|c|c.into()) } } } } rgb_impl_from!{RGB, u8,i16} rgb_impl_from!{RGB, u16,i32} 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, 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} impl From> for RGB { fn from(other: Gray) -> Self { Self { r: other.0.clone(), g: other.0.clone(), b: other.0, } } } impl From> for RGBA { fn from(other: GrayAlpha) -> Self { Self { r: other.0.clone(), g: other.0.clone(), b: other.0, a: other.1, } } } impl From> for BGR { fn from(other: RGB) -> Self { Self { r: other.r, g: other.g, b: other.b, } } } impl From> for BGRA { fn from(other: RGBA) -> Self { Self { r: other.r, g: other.g, b: other.b, a: other.a, } } } impl From> for RGB { fn from(other: BGR) -> Self { Self { r: other.r, g: other.g, b: other.b, } } } impl From> for RGBA { fn from(other: BGRA) -> Self { Self { r: other.r, g: other.g, b: other.b, a: other.a, } } } impl AsRef for Gray { fn as_ref(&self) -> &T { &self.0 } } impl AsRef<[T]> for RGB { fn as_ref(&self) -> &[T] { self.as_slice() } } impl AsRef<[T]> for RGBA { fn as_ref(&self) -> &[T] { self.as_slice() } } impl AsRef for GrayAlpha { fn as_ref(&self) -> &T { &self.0 } } impl AsMut for Gray { fn as_mut(&mut self) -> &mut T { &mut self.0 } } impl AsMut<[T]> for RGB { fn as_mut(&mut self) -> &mut [T] { self.as_mut_slice() } } impl AsMut<[T]> for RGBA { fn as_mut(&mut self) -> &mut [T] { self.as_mut_slice() } } impl AsMut for GrayAlpha { fn as_mut(&mut self) -> &mut T { &mut self.0 } } #[test] fn converts() { 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.11/src/internal/convert/tuple.rs010064400007650000024000000033121332414120700163500ustar0000000000000000use core::convert::*; use RGB; use RGBA; use alt::BGR; use alt::BGRA; 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 { fn from(other: (T,T,T)) -> Self { Self { b: other.0, g: other.1, r: other.2, } } } impl Into<(T,T,T)> for BGR { fn into(self) -> (T,T,T) { (self.b, self.g, self.r) } } impl From<(T,T,T,A)> for BGRA { 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 { 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.11/src/internal/ops.rs010064400007650000024000000052121332414120700143410ustar0000000000000000use core::ops::*; use super::pixel::*; use RGB; use RGBA; /// `px + px` impl Add for RGB { type Output = RGB<::Output>; #[inline(always)] fn add(self, other: RGB) -> Self::Output { RGB { r: self.r + other.r, g: self.g + other.g, b: self.b + other.b, } } } /// `px + px` impl Add> for RGBA { type Output = RGBA<::Output, ::Output>; #[inline(always)] fn add(self, other: RGBA) -> Self::Output { RGBA { r: self.r + other.r, g: self.g + other.g, b: self.b + other.b, a: self.a + other.a, } } } /// `px - px` impl Sub for RGB { type Output = RGB<::Output>; #[inline(always)] fn sub(self, other: RGB) -> Self::Output { RGB { r: self.r - other.r, g: self.g - other.g, b: self.b - other.b, } } } /// `px - px` impl Sub> for RGBA { type Output = RGBA<::Output, ::Output>; #[inline(always)] fn sub(self, other: RGBA) -> Self::Output { RGBA { r: self.r - other.r, g: self.g - other.g, b: self.b - other.b, a: self.a - other.a, } } } /// `px + 1` impl Add for RGB where T: Add { type Output = RGB; #[inline(always)] fn add(self, r: T) -> Self::Output { self.map(|l|l+r) } } /// `px + 1` impl Add for RGBA where T: Add { type Output = RGBA; #[inline(always)] fn add(self, r: T) -> Self::Output { self.map(|l|l+r) } } /// `px * 1` impl Mul for RGB where T: Mul { type Output = RGB; #[inline(always)] fn mul(self, r: T) -> Self::Output { self.map(|l|l*r) } } /// `px * 1` impl Mul for RGBA where T: Mul { type Output = RGBA; #[inline(always)] fn mul(self, r: T) -> Self::Output { self.map(|l|l*r) } } #[test] fn test_math() { 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!(RGB::new(0.5,1.5,2.5), RGB::new(1.,3.,5.) * 0.5); 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!(RGBA::new(2,4,6,8), RGBA::new(1,2,3,4) * 2); } rgb-0.8.11/src/internal/pixel.rs010064400007650000024000000034651332414120700146710ustar0000000000000000use core; /// 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]; fn as_mut_slice(&mut self) -> &mut [T]; } /// Casting a slice of `RGB/A` values to a slice of `u8` 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] { let slice = self.as_slice(); unsafe { core::slice::from_raw_parts(slice.as_ptr() as *const _, slice.len() * core::mem::size_of::()) } } #[inline] /// The components interpreted as raw bytes, in machine's native endian. In `RGB` bytes of the red component are first. fn as_bytes_mut(&mut self) -> &mut [u8] { 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,ignore /// let inverted = pixel.map(|c| 255 - c); /// /// For simple math there are Add/Sub/Mul implementations: /// let halved = pixel.map(|c| c / 2); /// let halved = 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; } rgb-0.8.11/src/internal/rgb.rs010064400007650000024000000107111332414120700143120ustar0000000000000000use core; use core::fmt; use super::pixel::*; use RGB; use RGBA; use alt::BGR; use alt::BGRA; macro_rules! impl_rgb { ($RGB:ident, $RGBA:ident) => { impl $RGB { /// Convenience function for creating a new pixel #[inline(always)] pub fn new(r: T, g: T, b: T) -> Self { Self {r,g,b} } /// Iterate over color components (R, G, and B) #[inline(always)] pub fn iter(&self) -> core::iter::Cloned> { self.as_slice().iter().cloned() } // 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 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 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_ptr() as *mut _, self.len() * 3) } } } impl ComponentBytes for [$RGB] {} } } 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, RGBA} impl_rgb!{BGR, BGRA} 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::Display for BGR { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f,"bgr({},{},{})", self.b, self.g, self.r) } } #[cfg(test)] mod rgb_test { use super::*; use std; #[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))); 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()); } } rgb-0.8.11/src/internal/rgba.rs010064400007650000024000000160751332414120700144640ustar0000000000000000use core; use core::fmt; use super::pixel::*; use RGB; use RGBA; use alt::BGR; use alt::BGRA; impl RGBA { #[inline(always)] pub fn new(r: T, g: T, b: T, a: T) -> Self { Self {r,g,b,a} } } impl RGBA { #[inline(always)] pub fn new_alpha(r: T, g: T, b: T, a: A) -> Self { Self {r,g,b,a} } } macro_rules! impl_rgba { ($RGBA:ident, $RGB:ident, $BGRA: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 #[inline(always)] pub fn rgb(&self) -> $RGB { $RGB {r:self.r.clone(), g:self.g.clone(), b:self.b.clone()} } } 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 { core::mem::transmute(self) } } } impl $RGBA { /// Create new RGBA with the same alpha value, but different RGB values #[inline(always)] pub fn map_rgb(&self, f: F) -> $RGBA where F: FnMut(T) -> U, U: Clone, B: From + Clone { self.rgb().map(f).new_alpha(self.a.clone().into()) } } 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 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_ptr() as *mut _, self.len() * 4) } } } impl ComponentBytes for [$RGBA] {} /// Assumes 255 is opaque impl From<$RGB> for $RGBA { fn from(other: $RGB) -> Self { Self { r: other.r, g: other.g, b: other.b, a: 0xFF, } } } /// Assumes 255 is opaque impl From<$RGB> for $BGRA { 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 { fn from(other: $RGB) -> Self { Self { r: other.r, g: other.g, b: other.b, a: 0xFFFF, } } } /// Assumes 255 is opaque impl From<$RGB> for $BGRA { fn from(other: $RGB) -> Self { Self { r: other.r, g: other.g, b: other.b, a: 0xFFFF, } } } } } 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! {RGBA, RGB, BGRA} impl_rgba! {BGRA, BGR, RGBA} 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, 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 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); 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] fn bgra_test() { let neg = BGRA{r:1,g:2,b:3i32,a: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!(&[-3,-2,-1,-1000], neg.as_slice()); assert!(neg < BGRA{r:0,g:0,b:0,a:0}); let neg = BGRA{r:1u8,g:2u8,b:3u8,a:4u8}.map_rgb(|c| -(c as i16)); assert_eq!(-1i16, neg.r); assert_eq!(4i16, neg.a); let mut px = BGRA{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); let v = vec![BGRA{b:1u8,g:2,r:3,a:4}, BGRA{b:5,g:6,r:7,a:8}]; assert_eq!(&[1,2,3,4,5,6,7,8], v.as_bytes()); } rgb-0.8.11/src/lib.rs010064400007650000024000000136411332414120700124770ustar0000000000000000//! 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]; //! let bytes = pixels.as_bytes(); //! //! 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] // 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 rgb; pub mod rgba; pub mod pixel; pub mod ops; pub mod convert; } /// BGR/BGRA alernative layouts & grayscale /// /// BGR might be seful for some Windows or OpenGL APIs. pub mod alt; pub use internal::rgb::*; pub use internal::rgba::*; pub use internal::pixel::*; pub use internal::ops::*; pub use internal::convert::*; #[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 techincally 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()); 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); 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); 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!(rgb, rgb_bytes.into_iter().cloned().collect()); assert_eq!(&[rgb], rgb_bytes.as_rgb()); let mut rgb2 = [rgb]; assert_eq!(rgb2.as_mut_slice().as_rgb_mut(), &mut [rgb]); 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[..]); }