├── .github └── workflows │ └── ci.yml ├── .gitignore ├── .travis.yml ├── CHANGELOG.md ├── Cargo.toml ├── LICENSE ├── README.md ├── examples ├── example.rs └── serde.rs └── src ├── bytemuck_impl.rs ├── core_traits.rs ├── formats ├── abgr.rs ├── argb.rs ├── bgr.rs ├── bgra.rs ├── gray.rs ├── gray_a.rs ├── gray_a44.rs ├── gray_alpha.rs ├── grb.rs ├── rgb.rs ├── rgba.rs └── rgbw.rs ├── from.rs ├── inherent_impls.rs ├── legacy ├── alt.rs ├── internal │ ├── convert │ │ └── mod.rs │ ├── ops.rs │ ├── pixel.rs │ ├── rgb.rs │ └── rgba.rs └── mod.rs ├── lib.rs ├── num_traits.rs ├── pixel_traits ├── arraylike.rs ├── gain_alpha.rs ├── has_alpha.rs ├── het_pixel.rs └── pixel.rs └── tuples.rs /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | test: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - uses: actions/checkout@v4 10 | - name: Install latest stable Rust 11 | uses: dtolnay/rust-toolchain@stable 12 | - name: Test no default features 13 | run: cargo test --no-default-features 14 | - name: Test all features 15 | run: cargo test --all --all-features 16 | - uses: taiki-e/install-action@cargo-hack 17 | - name: Check all feature combinations 18 | run: cargo hack check --feature-powerset --no-dev-deps --exclude-features unstable-experimental,defmt-03,grb,argb --exclude-all-features --exclude-no-default-features 19 | - name: Test individual features 20 | run: cargo hack test --each-feature --exclude-features unstable-experimental --exclude-all-features --exclude-no-default-features 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | Cargo.lock 3 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: rust 2 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | 2 | # 0.8.41 3 | 4 | * Renamed `.alpha(new_val)` method to `.with_alpha(new_val)`. 5 | * Added Rust-idiomatic name aliases `Rgb`/`Rgba` for the `RGB`/`RGBA` structs. 6 | 7 | # 0.8.40 8 | 9 | * Added `.checked_add`/`sub` methods. 10 | 11 | * Added a `Deref` trick that makes `GrayAlpha` tuple type have `.v` (value) and `.a` (alpha) fields. You should migrate to the new field names wherever possible. 12 | Unfortunately, `Gray` can't have that in a backward-compatible way, since it already derefs to the only field it has. 13 | 14 | * The `Pod` trait is implemented for `RGBA` types where `T != A`, but this is unsound if the fields have a different size or alignment that causes padding. In the future only `RGBA` will support casting from/to raw bytes. 15 | 16 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rgb" 3 | version = "0.8.90" # this must be set to stable, because Cargo won't unify 0.8.90-alpha with 0.8.0 4 | authors = ["Kornel Lesiński ", "James Forster "] 5 | include = ["src/**/*", "Cargo.toml", "README.md", "examples/*.rs", "LICENSE"] 6 | 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." 7 | documentation = "https://docs.rs/rgb" 8 | repository = "https://github.com/kornelski/rust-rgb" 9 | homepage = "https://lib.rs/crates/rgb" 10 | readme = "README.md" 11 | keywords = ["rgb", "rgba", "bgra", "pixel", "color"] 12 | license = "MIT" 13 | categories = ["graphics", "rust-patterns", "multimedia::images"] 14 | edition = "2021" 15 | rust-version = "1.63" 16 | 17 | [features] 18 | # Since all pixel formats are enabled by default, because it has negligible impact on compilation time 19 | default = ["grb", "argb", "as-bytes"] 20 | 21 | # Implements some of the traits, see `rgb::num_traits` module for details. 22 | num-traits = ["dep:num-traits"] 23 | # Support for the `defmt` crate 24 | defmt-03 = ["dep:defmt"] 25 | serde = ["dep:serde"] 26 | bytemuck = ["dep:bytemuck"] 27 | 28 | # Deprecated: it's always enabled anyway 29 | argb = [] 30 | # Deprecated: it's always enabled anyway 31 | grb = [] 32 | # Deprecated: use `num-traits` feature instead, and import `rgb::num_traits::*` 33 | checked_fns = [] 34 | # Deprecated: use `bytemuck` feature instead, and use `rgb::bytemuck::*` 35 | as-bytes = ["bytemuck"] 36 | 37 | # Enable for `cast_vec()`. Disable for no-std support. 38 | std = ["bytemuck?/extern_crate_alloc"] 39 | 40 | [badges] 41 | maintenance = { status = "actively-developed" } 42 | 43 | [dependencies] 44 | serde = { version = "1.0.200", optional = true, default-features = false, features = ["derive"] } 45 | bytemuck = { version = "1.17", optional = true, features = ["min_const_generics", "align_offset"] } # these give better code 46 | defmt = { version = "0.3.8", optional = true, default-features = false } 47 | num-traits = { version = "0.2.19", optional = true, default-features = false } 48 | 49 | [dev-dependencies] 50 | serde_json = "1.0.100" 51 | 52 | [[example]] 53 | name = "serde" 54 | required-features = ["serde"] 55 | 56 | [[example]] 57 | name = "example" 58 | required-features = [] 59 | 60 | [package.metadata.docs.rs] 61 | targets = ["x86_64-unknown-linux-gnu"] 62 | features = ["bytemuck", "serde", "num-traits"] 63 | rustdoc-args = ["--generate-link-to-definition"] 64 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Kornel 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Pixel types for [Rust](https://www.rust-lang.org) [![crate](https://img.shields.io/crates/v/rgb.svg)](https://lib.rs/crates/rgb) 2 | 3 | Operating on pixels as weakly-typed vectors of `u8` is error-prone and inconvenient. It's better to use vectors and slices of pixel structs, like `&[Rgb]`. 4 | 5 | However, Rust is so strongly typed that _your_ `Rgb` struct is not compatible with _my_ `Rgb` struct. This crate provides common structs to share between crates. 6 | 7 | ## Features 8 | 9 | * It's a shared type [used in many crates](https://lib.rs/crates/rgb/rev), which allows you to seamlessly and reliably share pixel data between them. 10 | 11 | * Compiles quickly and has low overhead. The dependencies are only for interoperability with the broader ecosystem, and are all optional. 12 | 13 | * Implements standard Rust traits, and has convenience methods for operating on all channels of the pixels. Saves you from having to copy-paste the same lines for `r`, `g`, and `b`. 14 | 15 | * It's unopinionated about color management, which lets it prepresent most RGB-related pixels without interfering. If you need more advanced conversions and non-RGB color spaces, use the [`palette` crate](https://lib.rs/crates/palette) instead. 16 | 17 | ## Basic Usage 18 | 19 | ```rust 20 | use rgb::{Rgb, Rgba, Argb, Bgr, Bgra, Abgr, Grb}; // and more 21 | use rgb::prelude::*; // traits with convenience methods 22 | 23 | let rgb_pixel = Rgb { r: 0u8, g: 100, b: 255 }; 24 | let wider_pixel = rgb_pixel.map(u16::from); 25 | 26 | println!("{rgb_pixel}"); // prints rgb(0, 100, 255) 27 | println!("{rgb_pixel:X}"); // prints #0064FF 28 | 29 | assert_eq!(rgb_pixel.to_color_array(), [0, 100, 255]); 30 | assert_eq!(rgb_pixel.with_alpha(128), Rgba::new(0, 100, 255, 128)); 31 | ``` 32 | 33 | ### Conversions from/to other types 34 | 35 | We defer to the `bytemuck` crate to have safe zero-cost conversions between types. See [`bytemuck::cast_slice()`][bslice] and [`cast_vec()`][bvec]. 36 | 37 | [bslice]: https://docs.rs/bytemuck/latest/bytemuck/fn.cast_slice.html 38 | [bvec]: https://docs.rs/bytemuck/latest/bytemuck/allocation/fn.cast_vec.html 39 | 40 | ```rust,ignore 41 | let pixels: Vec = vec![0u8; 3 * size]; 42 | let rgb_pixels: Vec> = rgb::bytemuck::allocation::cast_vec(pixels); 43 | 44 | for rgb_pixel in &rgb_pixels { 45 | } 46 | ``` 47 | 48 | If you'd like to work with 2D slices of pixels, see [the `imgvec` crate](https://lib.rs/crates/imgvec). 49 | 50 | # Stable and testing versions 51 | 52 | The version 0.8 is stable, and we plan to support it for a long time. You can use it, and rely on it. 53 | 54 | ```toml 55 | [dependencies] 56 | rgb = "0.8.50" 57 | ``` 58 | 59 | We want to release a proper v1.0.0 eventually. We plan to have it backwards-compatible with crates using v0.8, except some deprecated cruft removed/fixed. We hope the migration will be seamless for most users. Please help us test it! 60 | 61 | ```toml 62 | # This is required due to how version unification works in Cargo 63 | [patch.crates-io] 64 | rgb.git = "https://github.com/kornelski/rust-rgb" 65 | 66 | [dependencies] 67 | rgb = "0.8.90" 68 | ``` 69 | 70 | - Are the names of the traits and their methods good? 71 | - Are there any standard library traits you'd like implemented on the pixel types? 72 | - Is the split between `Pixel`, `HetPixel`, `HasAlpha` sensible? 73 | (pixels support a different type for the alpha channel, and there's `Rgbw` without alpha). 74 | 75 | [Please open issues in the repo with the feedback](https://github.com/kornelski/rust-rgb/issues) 76 | or message [@kornel@mastodon.social](https://mastodon.social/@kornel). 77 | 78 | ## Usage 79 | 80 | ```rust 81 | use rgb::{Rgb, Rgba, Argb, Bgr, Bgra, Abgr, Grb, Gray_v09 as Gray, GrayA}; 82 | 83 | let rgb = Rgb {r: 0, g: 0, b: 0}; 84 | let rbga = Rgba {r: 0, g: 0, b: 0, a: 0}; 85 | let argb = Argb {a: 0, r: 0, g: 0, b: 0}; 86 | 87 | let bgr = Bgr {b: 0, g: 0, r: 0}; 88 | let bgra = Bgra {b: 0, g: 0, r: 0, a: 0}; 89 | let abgr = Abgr {r: 0, g: 0, b: 0, a: 0}; 90 | 91 | let grb = Grb {g: 0, b: 0, r: 0}; 92 | 93 | let gray = Gray {v: 0}; 94 | let gray_a = GrayA {v: 0, a: 0}; 95 | ``` 96 | 97 | If you have a pixel type you would like to use that is not currently 98 | implemented, please open an issue to request your pixel type. 99 | 100 | The pixel types with an alpha component such as `Rgba` have two 101 | generic type parameters: 102 | 103 | ```rust 104 | struct Rgba { 105 | r: T, 106 | g: T, 107 | b: T, 108 | a: A, 109 | } 110 | ``` 111 | 112 | This makes them more flexible for more use-cases, for example if you 113 | needed more precision for you color components than your alpha 114 | component you could create an `Rgba`. However, in most 115 | use-cases the alpha component type will be the same as the color 116 | component type. 117 | 118 | A pixel with separate types for the color and alpha 119 | components is called a heterogeneous pixel (`HetPixel`), whereas a pixel with a 120 | single type for both color and alpha components is called a 121 | homogeneous pixel (`Pixel`). 122 | 123 | ## Pixel Traits 124 | 125 | All functionality for the pixel types is implemented via traits. This 126 | means that none of the pixel types, like `Rgb`, have any inherent 127 | methods. This makes it easy to choose which methods you'd like to be 128 | in scope at any given time unlike inherent methods which are always 129 | within scope. 130 | 131 | This crate offers the following traits: 132 | 133 | ### `HetPixel` 134 | 135 | The most foundational pixel trait implemented by every pixel type. 136 | 137 | ```rust 138 | use rgb::{Rgba, HetPixel}; 139 | 140 | let mut rgba: Rgba = Rgba::try_from_colors_alpha([0, 0, 0], 0).unwrap(); 141 | 142 | *rgba.each_color_mut()[2] = u8::MAX; 143 | assert_eq!(rgba.to_color_array(), [0, 0, 255]); 144 | 145 | *rgba.alpha_opt_mut().unwrap() = 50; 146 | assert_eq!(rgba.alpha_opt(), Some(50)); 147 | 148 | let rgba = rgba.map_colors(u16::from); 149 | let rgba = rgba.map_colors_same(|c| c * 2); 150 | let rgba = rgba.map_alpha(f32::from); 151 | let rgba = rgba.map_alpha_same(|a| a * 2.0); 152 | 153 | assert_eq!(rgba, Rgba:: {r: 0, g: 0, b: 510, a: 100.0}); 154 | ``` 155 | 156 | ### Pixel 157 | 158 | A stricter form of `HetPixel` where the two component types, color and 159 | alpha, are the same. 160 | 161 | ```rust 162 | use rgb::{Rgba, Pixel}; 163 | 164 | let mut rgba: Rgba = Rgba::try_from_components([0, 0, 0, 0]).unwrap(); 165 | 166 | *rgba.each_mut()[2] = u8::MAX; 167 | assert_eq!(rgba.to_array(), [0, 0, 255, 0]); 168 | 169 | let rgba = rgba.map(u16::from); 170 | let rgba = rgba.map_same(|c| c * 2); 171 | 172 | assert_eq!(rgba, Rgba:: {r: 0, g: 0, b: 510, a: 0}); 173 | ``` 174 | 175 | ### `GainAlpha` 176 | 177 | A way to add alpha to a pixel type in various ways. 178 | 179 | ```rust 180 | use rgb::{Rgb, Rgba, GainAlpha}; 181 | 182 | let expected: Rgba = Rgba {r: 0, g: 0, b: 0, a: 255}; 183 | 184 | assert_eq!(Rgb {r: 0, g: 0, b: 0}.with_default_alpha(255), expected); 185 | assert_eq!(Rgb {r: 0, g: 0, b: 0}.with_alpha(255), expected); 186 | assert_eq!(Rgba {r: 0, g: 0, b: 0, a: 0}.with_alpha(255), expected); 187 | ``` 188 | 189 | ### `HasAlpha` 190 | 191 | A trait only implemented on pixels that have an alpha 192 | component. 193 | 194 | Due to a naming conflict with several now-deprecated inherent 195 | functions with the same name (such as `Rgb::alpha()`) the 196 | `HasAlpha::alpha()` method requires fully qualified syntax for 197 | disambiguation. The deprecated functions are due to be removed in a 198 | future release which will solve this issue. 199 | 200 | ```rust 201 | use rgb::{Rgba, HasAlpha}; 202 | 203 | let mut rgba: Rgba = Rgba {r: 0, g: 0, b: 0, a: 255}; 204 | 205 | *rgba.alpha_mut() -= 50; 206 | 207 | assert_eq!(HasAlpha::alpha(&rgba), 205); 208 | ``` 209 | 210 | ## Crate Features 211 | 212 | - `num-traits`: Enables various 213 | [`num_traits`](https://docs.rs/num-traits) traits impls for the 214 | pixel types such as `CheckedAdd`. 215 | - `defmt-03` = Enables the `Format` trait impls from 216 | [`defmt`](https://docs.rs/defmt) `v0.3` for the pixel types 217 | - `serde` = Enables `Serializable` and `Deserializable` trait impls 218 | from [`serde`](https://docs.rs/serde) for the pixel types 219 | - `bytemuck` = Enables `Pod` and `Zeroable` trait impls from 220 | [`bytemuck`](https://docs.rs/serde) for the pixel types 221 | 222 | The following crate features are only kept for backwards compatibility, and will be removed in the next major version: 223 | 224 | ```toml 225 | # These are no longer used 226 | argb = [] 227 | grb = [] 228 | checked_fns = [] 229 | as-bytes = ["bytemuck"] 230 | ``` 231 | 232 | ## Color-Space Agnostic 233 | 234 | This crate is purposefully a basic lowest-common-denominator, and it does not dictate what color spaces the pixel types are supposed to use. 235 | For example, `Gray` could be either linear lightness or gamma-corrected luma, however you wish to use it. 236 | _Correct_ color management is a complex problem, and this crate doesn't want to impose any specific solutions. 237 | 238 | If you need strongly-typed color spaces, you can use newtypes as component types for `Rgb` and `Rgba`, e.g.: 239 | 240 | ```rust 241 | # use rgb::Rgb; 242 | struct LinearLight(u16); 243 | type LinearRGB = Rgb; 244 | ``` 245 | 246 | ## Roadmap to 1.0 247 | 248 | The plan is to provide easy migration to v1.0. There will be a 249 | transitional v0.9 version released that will be mostly 250 | backwards-compatible with 0.8, and forwards-compatible with 1.0. 251 | 252 | The changes: 253 | 254 | - Types were renamed to follow Rust's naming convention: `RGBA` → `Rgba`. 255 | Type aliases with an `8` or `16` suffix (`RGBA8`) were kept as-is. 256 | - The grayscale types have changed from being tuple structs with 257 | `.0`/`.1` to structs with named fields `.v` (value) and `.a` (alpha). 258 | - `GrayAlpha` has been renamed to `GrayA`. 259 | - `bytemuck::Pod` (conversions from/to raw bytes) require color and alpha components to be the same type 260 | (i.e. it works with `Rgba`, but not `Rgba`). 261 | - Most inherent methods were moved to a new `Pixel` trait. 262 | 263 | ### Migrating away from deprecated items 264 | 265 | Some items in this crate have become deprecated in preparation for a 266 | future release which removes them. Here is a checklist of things you may need to do. 267 | 268 | 1. Update to the latest version of 0.8, and fix all deprecation warnings. 269 | - rename `.alpha()` to `.with_alpha()` 270 | - rename `.map_c()` to `.map_colors()` 271 | 1. Change field access on `GrayAlpha` from `.0` and `.1` to `.v` and `.a` where possible. 272 | 1. Use the `bytemuck` crate for conversions from/to bytes instead of `ComponentBytes` trait. Disable the `as-bytes` feature if possible. 273 | 1. Use the `num-traits` crate for `.checked_add()`, don't enable `checked_fns` feature. 274 | 1. Don't enable `gbr` and `argb` features. All pixel types are enabled by default. 275 | 1. `AsRef<[T]>` implementations have changed to `AsRef<[T; N]>`. In most cases `.as_ref()`/`.as_mut()` calls should coerce to a slice anyway. 276 | 1. Instead of `pixel.as_slice()` use `pixel.as_ref()`. 277 | 1. Stop using the `rgb::Gray`/`rgb::GrayAlpha` types and switch to `rgb::Gray_v09 as Gray`/`rgb::GrayA` instead respectively. 278 | 1. In generic code operating on pixels, add `Copy + 'static` bounds to the pixel types and their components. 279 | -------------------------------------------------------------------------------- /examples/example.rs: -------------------------------------------------------------------------------- 1 | #[cfg(feature = "as-bytes")] 2 | fn main() { 3 | use rgb::{ComponentBytes, ComponentSlice}; 4 | use rgb::{Pixel, Rgb}; 5 | 6 | let px = Rgb { 7 | r: 255_u8, 8 | g: 0, 9 | b: 100, 10 | }; 11 | assert_eq!([px].as_bytes()[0], 255); 12 | 13 | let bigpx = Rgb:: { 14 | r: 65535_u16, 15 | g: 0, 16 | b: 0, 17 | }; 18 | assert_eq!(bigpx.as_slice()[0], 65535); 19 | 20 | let px = Rgb::::new(255, 0, 255); 21 | let inverted: Rgb = px.map(|ch| 255 - ch); 22 | 23 | println!("{inverted}"); // rgb(0,255,0) 24 | } 25 | 26 | #[cfg(not(feature = "as-bytes"))] 27 | fn main() {} 28 | -------------------------------------------------------------------------------- /examples/serde.rs: -------------------------------------------------------------------------------- 1 | use rgb::*; 2 | 3 | // Run using: cargo run --features=serde --example serde 4 | 5 | fn main() { 6 | let color = Rgb { r: 255_u8, g: 0, b: 100 }; 7 | println!("{}", serde_json::to_string(&color).unwrap()); 8 | 9 | let color: Rgb = serde_json::from_str("{\"r\":10,\"g\":20,\"b\":30}").unwrap(); 10 | println!("{color}"); 11 | } 12 | -------------------------------------------------------------------------------- /src/bytemuck_impl.rs: -------------------------------------------------------------------------------- 1 | use crate::{Abgr, Argb, Bgr, Bgra, GrayA, GrayA44, Gray_v09, Grb, Rgb, Rgba, Rgbw}; 2 | 3 | macro_rules! bytemuck { 4 | ($name:ident) => { 5 | unsafe impl ::bytemuck::Zeroable for $name {} 6 | unsafe impl ::bytemuck::Pod for $name {} 7 | }; 8 | } 9 | 10 | macro_rules! bytemuck_no_generic { 11 | ($name:ident) => { 12 | unsafe impl ::bytemuck::Zeroable for $name {} 13 | unsafe impl ::bytemuck::Pod for $name {} 14 | }; 15 | } 16 | 17 | bytemuck!(Rgb); 18 | bytemuck!(Bgr); 19 | bytemuck!(Grb); 20 | bytemuck!(Gray_v09); 21 | bytemuck!(Rgbw); 22 | bytemuck!(Rgba); 23 | bytemuck!(Argb); 24 | bytemuck!(Bgra); 25 | bytemuck!(Abgr); 26 | bytemuck!(GrayA); 27 | bytemuck_no_generic!(GrayA44); 28 | 29 | use crate::formats::gray_alpha::GrayAlpha_v08; 30 | bytemuck!(GrayAlpha_v08); 31 | 32 | use crate::formats::gray::Gray_v08; 33 | bytemuck!(Gray_v08); 34 | 35 | #[cfg(feature = "as-bytes")] 36 | impl crate::ComponentBytes for [Gray_v08] { 37 | #[inline] 38 | fn as_bytes(&self) -> &[u8] { 39 | assert_ne!(0, core::mem::size_of::()); 40 | ::bytemuck::cast_slice(self) 41 | } 42 | 43 | #[inline] 44 | fn as_bytes_mut(&mut self) -> &mut [u8] { 45 | assert_ne!(0, core::mem::size_of::()); 46 | ::bytemuck::cast_slice_mut(self) 47 | } 48 | } 49 | 50 | #[cfg(feature = "as-bytes")] 51 | impl crate::ComponentBytes for [Gray_v09] { 52 | #[inline] 53 | fn as_bytes(&self) -> &[u8] { 54 | assert_ne!(0, core::mem::size_of::()); 55 | ::bytemuck::cast_slice(self) 56 | } 57 | 58 | #[inline] 59 | fn as_bytes_mut(&mut self) -> &mut [u8] { 60 | assert_ne!(0, core::mem::size_of::()); 61 | ::bytemuck::cast_slice_mut(self) 62 | } 63 | } 64 | 65 | #[cfg(feature = "as-bytes")] 66 | impl crate::ComponentBytes for [GrayAlpha_v08] { 67 | #[inline] 68 | fn as_bytes(&self) -> &[u8] { 69 | assert_ne!(0, core::mem::size_of::()); 70 | ::bytemuck::cast_slice(self) 71 | } 72 | 73 | #[inline] 74 | fn as_bytes_mut(&mut self) -> &mut [u8] { 75 | assert_ne!(0, core::mem::size_of::()); 76 | ::bytemuck::cast_slice_mut(self) 77 | } 78 | } 79 | 80 | #[cfg(feature = "as-bytes")] 81 | impl crate::ComponentBytes for [GrayA44] { 82 | #[inline] 83 | fn as_bytes(&self) -> &[u8] { 84 | ::bytemuck::cast_slice(self) 85 | } 86 | 87 | #[inline] 88 | fn as_bytes_mut(&mut self) -> &mut [u8] { 89 | ::bytemuck::cast_slice_mut(self) 90 | } 91 | } 92 | 93 | #[test] 94 | fn test_component_bytes_capable() { 95 | assert_eq!( 96 | core::mem::size_of::(), 97 | core::mem::size_of::() 98 | ); 99 | } 100 | -------------------------------------------------------------------------------- /src/core_traits.rs: -------------------------------------------------------------------------------- 1 | use crate::{Abgr, Argb, Bgr, Bgra, GrayA, Gray_v09, Grb, Rgb, Rgba, Rgbw}; 2 | use core::array::TryFromSliceError; 3 | use core::fmt; 4 | use core::iter::Sum; 5 | use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign}; 6 | 7 | macro_rules! trait_impls_common { 8 | ($name:ident, $length:literal, [$($bit:tt),*]) => { 9 | impl From<$name> for [S; $length] where R: Into { 10 | #[inline] 11 | fn from(value: $name) -> Self { 12 | [$(value.$bit.into()),*] 13 | } 14 | } 15 | 16 | impl From<[R; $length]> for $name where R: Into { 17 | #[inline] 18 | fn from(value: [R; $length]) -> Self { 19 | let mut iter = value.into_iter(); 20 | Self { $($bit: iter.next().unwrap().into()),* } 21 | } 22 | } 23 | 24 | impl TryFrom<&[T]> for $name where T: Copy + 'static { 25 | type Error = TryFromSliceError; 26 | 27 | #[inline] 28 | fn try_from(slice: &[T]) -> Result { 29 | let array: [T; $length] = slice.try_into()?; 30 | Ok(Self::from(array)) 31 | } 32 | } 33 | 34 | impl IntoIterator for $name { 35 | type Item = T; 36 | type IntoIter = core::array::IntoIter; 37 | 38 | #[inline] 39 | fn into_iter(self) -> Self::IntoIter { 40 | [$(self.$bit.into()),*].into_iter() 41 | } 42 | } 43 | 44 | /// Allows writing `pixel + 1` 45 | impl Add for $name where T: Copy + Add { 46 | type Output = $name; 47 | 48 | #[inline(always)] 49 | fn add(self, r: T) -> Self::Output { 50 | Self::Output { 51 | $( 52 | $bit: self.$bit + r, 53 | )+ 54 | } 55 | } 56 | } 57 | 58 | /// Allows writing `pixel += 1` 59 | impl AddAssign for $name where T: Copy + Add { 60 | #[inline(always)] 61 | fn add_assign(&mut self, r: T) { 62 | *self = Self { 63 | $( 64 | $bit: self.$bit + r, 65 | )+ 66 | }; 67 | } 68 | } 69 | 70 | /// Allows writing `pixel - 1` 71 | impl Sub for $name where T: Copy + Sub { 72 | type Output = $name; 73 | 74 | #[inline(always)] 75 | fn sub(self, r: T) -> Self::Output { 76 | Self::Output { 77 | $( 78 | $bit: self.$bit - r, 79 | )+ 80 | } 81 | } 82 | } 83 | 84 | /// Allows writing `pixel -= 1` 85 | impl SubAssign for $name where T: Copy + Sub { 86 | #[inline(always)] 87 | fn sub_assign(&mut self, r: T) { 88 | *self = Self { 89 | $( 90 | $bit: self.$bit - r, 91 | )+ 92 | }; 93 | } 94 | } 95 | 96 | /// Allows writing `pixel * 2` 97 | impl Mul for $name where T: Copy + Mul { 98 | type Output = $name; 99 | 100 | #[inline(always)] 101 | fn mul(self, r: T) -> Self::Output { 102 | Self::Output { 103 | $( 104 | $bit: self.$bit * r, 105 | )+ 106 | } 107 | } 108 | } 109 | 110 | /// Allows writing `pixel *= 2` 111 | impl MulAssign for $name where T: Copy + Mul { 112 | #[inline(always)] 113 | fn mul_assign(&mut self, r: T) { 114 | *self = Self { 115 | $( 116 | $bit: self.$bit * r, 117 | )+ 118 | }; 119 | } 120 | } 121 | 122 | /// Allows writing `pixel / 2` 123 | impl Div for $name where T: Copy + Div { 124 | type Output = $name; 125 | 126 | #[inline(always)] 127 | fn div(self, r: T) -> Self::Output { 128 | Self::Output { 129 | $( 130 | $bit: self.$bit / r, 131 | )+ 132 | } 133 | } 134 | } 135 | 136 | /// Allows writing `pixel /= 2` 137 | impl DivAssign for $name where T: Copy + Div { 138 | #[inline(always)] 139 | fn div_assign(&mut self, r: T) { 140 | *self = $name { 141 | $( 142 | $bit: self.$bit / r, 143 | )+ 144 | }; 145 | } 146 | } 147 | 148 | impl AsRef<[T; $length]> for $name where T: Copy + 'static { 149 | #[inline] 150 | fn as_ref(&self) -> &[T; $length] { 151 | crate::Pixel::as_array(self) 152 | } 153 | } 154 | 155 | impl AsMut<[T; $length]> for $name where T: Copy + 'static { 156 | #[inline] 157 | fn as_mut(&mut self) -> &mut [T; $length] { 158 | crate::Pixel::as_array_mut(self) 159 | } 160 | } 161 | }; 162 | } 163 | 164 | macro_rules! trait_impls_with_alpha { 165 | ($name:ident, $length:literal, [$($printas:ident => $bit:tt),*], $display:literal, $upperhex:literal, $lowerhex:literal) => { 166 | trait_impls_common!($name, $length, [$($bit),*]); 167 | 168 | impl fmt::Display for $name { 169 | #[cold] 170 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 171 | write!(f, $display, $($printas = self.$bit),*) 172 | } 173 | } 174 | 175 | impl fmt::UpperHex for $name { 176 | #[cold] 177 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 178 | let width = 2 * core::mem::size_of::(); 179 | write!(f, $upperhex, $($printas = self.$bit),* , w = width) 180 | } 181 | } 182 | 183 | impl fmt::LowerHex for $name { 184 | #[cold] 185 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 186 | let width = 2 * core::mem::size_of::(); 187 | write!(f, $lowerhex, $($printas = self.$bit),* , w = width) 188 | } 189 | } 190 | 191 | impl Sum<$name> for $name where T: Default + Add, A: Default + Add { 192 | #[inline(always)] 193 | fn sum>(iter: I) -> Self { 194 | iter.fold($name::default(), Add::add) 195 | } 196 | } 197 | 198 | /// Allows writing `pixel + pixel` 199 | impl Add for $name { 200 | type Output = $name; 201 | 202 | #[inline(always)] 203 | fn add(self, other: Self) -> Self::Output { 204 | Self::Output { 205 | $( 206 | $bit: self.$bit + other.$bit, 207 | )+ 208 | } 209 | } 210 | } 211 | 212 | /// Allows writing `pixel += pixel` 213 | impl AddAssign for $name where 214 | T: Add + Copy, 215 | A: Add + Copy, 216 | { 217 | #[inline(always)] 218 | fn add_assign(&mut self, other: Self) { 219 | *self = Self { 220 | $( 221 | $bit: self.$bit + other.$bit, 222 | )+ 223 | }; 224 | } 225 | } 226 | 227 | /// Allows writing `pixel - pixel` 228 | impl Sub for $name { 229 | type Output = $name; 230 | 231 | #[inline(always)] 232 | fn sub(self, other: Self) -> Self::Output { 233 | Self::Output { 234 | $( 235 | $bit: self.$bit - other.$bit, 236 | )+ 237 | } 238 | } 239 | } 240 | 241 | /// Allows writing `pixel -= pixel` 242 | impl SubAssign for $name where 243 | T: Sub + Copy, 244 | A: Sub + Copy, 245 | { 246 | #[inline(always)] 247 | fn sub_assign(&mut self, other: Self) { 248 | *self = Self { 249 | $( 250 | $bit: self.$bit - other.$bit, 251 | )+ 252 | }; 253 | } 254 | } 255 | 256 | /// Allows writing `pixel * pixel` 257 | impl Mul for $name { 258 | type Output = $name; 259 | 260 | #[inline(always)] 261 | fn mul(self, other: Self) -> Self::Output { 262 | Self::Output { 263 | $( 264 | $bit: self.$bit * other.$bit, 265 | )+ 266 | } 267 | } 268 | } 269 | 270 | /// Allows writing `pixel *= pixel` 271 | impl MulAssign for $name where 272 | T: Mul + Copy, 273 | A: Mul + Copy, 274 | { 275 | #[inline(always)] 276 | fn mul_assign(&mut self, other: Self) { 277 | *self = Self { 278 | $( 279 | $bit: self.$bit * other.$bit, 280 | )+ 281 | }; 282 | } 283 | } 284 | 285 | /// Allows writing `pixel / pixel` 286 | impl Div for $name { 287 | type Output = $name; 288 | 289 | #[inline(always)] 290 | fn div(self, other: Self) -> Self::Output { 291 | Self::Output { 292 | $( 293 | $bit: self.$bit / other.$bit, 294 | )+ 295 | } 296 | } 297 | } 298 | 299 | /// Allows writing `pixel /= pixel` 300 | impl DivAssign for $name where 301 | T: Div + Copy, 302 | A: Div + Copy, 303 | { 304 | #[inline(always)] 305 | fn div_assign(&mut self, other: Self) { 306 | *self = Self { 307 | $( 308 | $bit: self.$bit / other.$bit, 309 | )+ 310 | }; 311 | } 312 | } 313 | }; 314 | } 315 | 316 | macro_rules! trait_impls_without_alpha { 317 | ($name:ident, $length:literal, [$($printas:ident => $bit:tt),*], $display:literal, $upperhex:literal, $lowerhex:literal) => { 318 | trait_impls_common!($name, $length, [$($bit),*]); 319 | 320 | impl fmt::Display for $name { 321 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 322 | write!(f, $display, $($printas = self.$bit),*) 323 | } 324 | } 325 | 326 | impl fmt::UpperHex for $name { 327 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 328 | let width = 2 * core::mem::size_of::(); 329 | write!(f, $upperhex, $($printas = self.$bit),*, w = width) 330 | } 331 | } 332 | 333 | impl fmt::LowerHex for $name { 334 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 335 | let width = 2 * core::mem::size_of::(); 336 | write!(f, $lowerhex, $($printas = self.$bit),*, w = width) 337 | } 338 | } 339 | 340 | impl Sum<$name> for $name where T: Default + Add { 341 | #[inline(always)] 342 | fn sum>(iter: I) -> Self { 343 | iter.fold($name::default(), Add::add) 344 | } 345 | } 346 | 347 | /// Allows writing `pixel + pixel` 348 | impl Add for $name { 349 | type Output = $name; 350 | 351 | #[inline(always)] 352 | fn add(self, other: Self) -> Self::Output { 353 | Self::Output { 354 | $( 355 | $bit: self.$bit + other.$bit, 356 | )+ 357 | } 358 | } 359 | } 360 | 361 | /// Allows writing `pixel += pixel` 362 | impl AddAssign for $name where T: Add + Copy { 363 | #[inline(always)] 364 | fn add_assign(&mut self, other: Self) { 365 | *self = Self { 366 | $( 367 | $bit: self.$bit + other.$bit, 368 | )+ 369 | }; 370 | } 371 | } 372 | 373 | /// Allows writing `pixel - pixel` 374 | impl Sub for $name { 375 | type Output = $name; 376 | 377 | #[inline(always)] 378 | fn sub(self, other: Self) -> Self::Output { 379 | Self::Output { 380 | $( 381 | $bit: self.$bit - other.$bit, 382 | )+ 383 | } 384 | } 385 | } 386 | 387 | /// Allows writing `pixel -= pixel` 388 | impl SubAssign for $name where T: Sub + Copy { 389 | #[inline(always)] 390 | fn sub_assign(&mut self, other: Self) { 391 | *self = Self { 392 | $( 393 | $bit: self.$bit - other.$bit, 394 | )+ 395 | }; 396 | } 397 | } 398 | 399 | /// Allows writing `pixel * pixel` 400 | impl Mul for $name { 401 | type Output = $name; 402 | 403 | #[inline(always)] 404 | fn mul(self, other: Self) -> Self::Output { 405 | Self::Output { 406 | $( 407 | $bit: self.$bit * other.$bit, 408 | )+ 409 | } 410 | } 411 | } 412 | 413 | /// Allows writing `pixel *= pixel` 414 | impl MulAssign for $name where T: Mul + Copy { 415 | #[inline(always)] 416 | fn mul_assign(&mut self, other: Self) { 417 | *self = Self { 418 | $( 419 | $bit: self.$bit * other.$bit, 420 | )+ 421 | }; 422 | } 423 | } 424 | 425 | /// Allows writing `pixel / pixel` 426 | impl Div for $name { 427 | type Output = $name; 428 | 429 | #[inline(always)] 430 | fn div(self, other: Self) -> Self::Output { 431 | Self::Output { 432 | $( 433 | $bit: self.$bit / other.$bit, 434 | )+ 435 | } 436 | } 437 | } 438 | 439 | /// Allows writing `pixel /= pixel` 440 | impl DivAssign for $name where T: Div + Copy { 441 | #[inline(always)] 442 | fn div_assign(&mut self, other: Self) { 443 | *self = Self { 444 | $( 445 | $bit: self.$bit / other.$bit, 446 | )+ 447 | }; 448 | } 449 | } 450 | }; 451 | } 452 | 453 | trait_impls_without_alpha!(Rgb, 3, [r => r, g => g, b => b], "rgb({r},{g},{b})", "#{r:0w$X}{g:0w$X}{b:0w$X}", "#{r:0w$x}{g:0w$x}{b:0w$x}"); 454 | trait_impls_without_alpha!(Bgr, 3, [b => b, g => g, r => r], "bgr({b},{g},{r})", "#{r:0w$X}{g:0w$X}{b:0w$X}", "#{r:0w$x}{g:0w$x}{b:0w$x}"); 455 | trait_impls_without_alpha!(Grb, 3, [g => g, r => r, b => b], "grb({g},{r},{b})", "#{r:0w$X}{g:0w$X}{b:0w$X}", "#{r:0w$x}{g:0w$x}{b:0w$x}"); 456 | trait_impls_without_alpha!(Gray_v09, 1, [v => v], "gray({v})", "gray(#{v:0w$X})", "gray(#{v:0w$x})"); 457 | trait_impls_without_alpha!(Rgbw, 4, [r => r, g => g, b => b, white => w], "rgbw({r},{g},{b},{white})", "#{r:0w$X}{g:0w$X}{b:0w$X}{white:0w$X}", "#{r:0w$x}{g:0w$x}{b:0w$x}{white:0w$x}"); 458 | 459 | use crate::formats::gray::Gray_v08; 460 | trait_impls_without_alpha!(Gray_v08, 1, [v => 0], "gray_v0.8({v})", "gray_v0.8(#{v:0w$X})", "gray_v0.8(#{v:0w$x})"); 461 | 462 | trait_impls_with_alpha!(Rgba, 4, [r => r, g => g, b => b, a => a], "rgba({r},{g},{b},{a})", "#{r:0w$X}{g:0w$X}{b:0w$X}{a:0w$X}", "#{r:0w$x}{g:0w$x}{b:0w$x}{a:0w$x}"); 463 | trait_impls_with_alpha!(Argb, 4, [a => a, r => r, g => g, b => b], "argb({a},{r},{g},{b})", "#{r:0w$X}{g:0w$X}{b:0w$X}{a:0w$X}", "#{r:0w$x}{g:0w$x}{b:0w$x}{a:0w$x}"); 464 | trait_impls_with_alpha!(Bgra, 4, [b => b, g => g, r => r, a => a], "bgra({b},{g},{r},{a})", "#{r:0w$X}{g:0w$X}{b:0w$X}{a:0w$X}", "#{r:0w$x}{g:0w$x}{b:0w$x}{a:0w$x}"); 465 | trait_impls_with_alpha!(Abgr, 4, [a => a, b => b, g => g, r => r], "abgr({a},{b},{g},{r})", "#{r:0w$X}{g:0w$X}{b:0w$X}{a:0w$X}", "#{r:0w$x}{g:0w$x}{b:0w$x}{a:0w$x}"); 466 | trait_impls_with_alpha!(GrayA, 2, [v => v, a => a], "graya({v},{a})", "graya(#{v:0w$X}{a:0w$X})", "graya(#{v:0w$x}{a:0w$x})"); 467 | 468 | use crate::formats::gray_alpha::GrayAlpha_v08; 469 | trait_impls_with_alpha!(GrayAlpha_v08, 2, [v => 0, a => 1], "graya_v0.8({v},{a})", "graya_v0.8(#{v:0w$X}{a:0w$X})", "graya_v0.8(#{v:0w$x}{a:0w$x})"); 470 | 471 | #[cfg(test)] 472 | #[test] 473 | fn test_16_fmt() { 474 | extern crate std; 475 | 476 | let a = Argb::::new_argb(1, 0x1234, 3, 65535); 477 | assert_eq!("#12340003FFFF0001", &std::format!("{a:X}")); 478 | } 479 | 480 | #[test] 481 | #[allow(deprecated)] 482 | fn convert_array() { 483 | use crate::{BGR8, BGRA8, RGB8, RGBA8}; 484 | 485 | assert_eq!(RGB8::from([1, 2, 3]), RGB8::new(1, 2, 3)); 486 | assert_eq!(Into::<[u8; 3]>::into(RGB8::new(1, 2, 3)), [1, 2, 3]); 487 | assert_eq!(RGBA8::from([1, 2, 3, 4]), RGBA8::new(1, 2, 3, 4)); 488 | assert_eq!(Into::<[u8; 4]>::into(RGBA8::new(1, 2, 3, 4)), [1, 2, 3, 4]); 489 | assert_eq!(BGR8::from([3, 2, 1]), BGR8::new_bgr(3, 2, 1)); 490 | assert_eq!(Into::<[u8; 3]>::into(BGR8::new_bgr(3, 2, 1)), [3, 2, 1]); 491 | assert_eq!(BGRA8::from([4, 3, 2, 1]), BGRA8::new_bgra(4, 3, 2, 1)); 492 | assert_eq!(Into::<[u8; 4]>::into(BGRA8::new_bgra(4, 3, 2, 1)), [4, 3, 2, 1]); 493 | } 494 | -------------------------------------------------------------------------------- /src/formats/abgr.rs: -------------------------------------------------------------------------------- 1 | #[repr(C)] 2 | #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] 3 | #[cfg_attr(feature = "defmt-03", derive(defmt::Format))] 4 | #[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Ord, PartialOrd, Hash)] 5 | /// An `Alpha + Blue + Green + Red` pixel. 6 | /// 7 | /// # Examples 8 | /// 9 | /// ``` 10 | /// use rgb::Abgr; 11 | /// 12 | /// let pixel: Abgr = Abgr { a: 255, b: 0, g: 0, r: 0 }; 13 | /// ``` 14 | #[doc(alias = "ABGR8")] 15 | #[doc(alias = "ABGR16")] 16 | pub struct Abgr { 17 | /// Alpha Component 18 | pub a: A, 19 | /// Blue Component 20 | pub b: T, 21 | /// Green Component 22 | pub g: T, 23 | /// Red Component 24 | pub r: T, 25 | } 26 | -------------------------------------------------------------------------------- /src/formats/argb.rs: -------------------------------------------------------------------------------- 1 | #[repr(C)] 2 | #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] 3 | #[cfg_attr(feature = "defmt-03", derive(defmt::Format))] 4 | #[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Ord, PartialOrd, Hash)] 5 | /// An `Alpha + Red + Green + Blue` pixel. 6 | /// 7 | /// # Examples 8 | /// 9 | /// ``` 10 | /// use rgb::Argb; 11 | /// 12 | /// let pixel: Argb = Argb { a: 255, r: 0, g: 0, b: 0 }; 13 | /// ``` 14 | #[doc(alias = "ARGB8")] 15 | #[doc(alias = "ARGB16")] 16 | pub struct Argb { 17 | /// Alpha Component 18 | pub a: A, 19 | /// Red Component 20 | pub r: T, 21 | /// Green Component 22 | pub g: T, 23 | /// Blue Component 24 | pub b: T, 25 | } 26 | -------------------------------------------------------------------------------- /src/formats/bgr.rs: -------------------------------------------------------------------------------- 1 | #[repr(C)] 2 | #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] 3 | #[cfg_attr(feature = "defmt-03", derive(defmt::Format))] 4 | #[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Ord, PartialOrd, Hash)] 5 | /// A `Blue + Green + Red` pixel. 6 | /// 7 | /// # Examples 8 | /// 9 | /// ``` 10 | /// use rgb::Bgr; 11 | /// 12 | /// let pixel: Bgr = Bgr { b: 0, g: 0, r: 0 }; 13 | /// ``` 14 | #[doc(alias = "BGR8")] 15 | #[doc(alias = "BGR16")] 16 | pub struct Bgr { 17 | /// Blue Component 18 | pub b: T, 19 | /// Green Component 20 | pub g: T, 21 | /// Red Component 22 | pub r: T, 23 | } 24 | -------------------------------------------------------------------------------- /src/formats/bgra.rs: -------------------------------------------------------------------------------- 1 | #[repr(C)] 2 | #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] 3 | #[cfg_attr(feature = "defmt-03", derive(defmt::Format))] 4 | #[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Ord, PartialOrd, Hash)] 5 | /// A `Blue + Green + Red + Alpha` pixel. 6 | /// 7 | /// # Examples 8 | /// 9 | /// ``` 10 | /// use rgb::Bgra; 11 | /// 12 | /// let pixel: Bgra = Bgra { b: 0, g: 0, r: 0, a: 255 }; 13 | /// ``` 14 | #[doc(alias = "BGRA8")] 15 | #[doc(alias = "BGRA16")] 16 | pub struct Bgra { 17 | /// Blue Component 18 | pub b: T, 19 | /// Green Component 20 | pub g: T, 21 | /// Red Component 22 | pub r: T, 23 | /// Alpha Component 24 | pub a: A, 25 | } 26 | -------------------------------------------------------------------------------- /src/formats/gray.rs: -------------------------------------------------------------------------------- 1 | #[repr(C)] 2 | #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] 3 | #[cfg_attr(feature = "defmt-03", derive(defmt::Format))] 4 | #[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Ord, PartialOrd, Hash)] 5 | /// A `Grayscale` pixel 6 | /// 7 | /// This is the legacy gray pixel type as opposed to the new gray type 8 | /// (`rgb::Gray_v09`). This type is kept for backwards-compatibility. 9 | /// 10 | /// You should transition to the new gray pixel type as this type is 11 | /// due to be removed in a future release. 12 | #[allow(non_camel_case_types)] 13 | pub struct Gray_v08( 14 | /// Grayscale Component. This field will be renamed to `v`. 15 | pub T, 16 | ); 17 | 18 | /// A `Grayscale` pixel. 19 | /// 20 | /// This is the new gray pixel type as opposed to the legacy gray type 21 | /// (`rgb::Gray`) which is kept for backwards-compatibility. 22 | /// 23 | /// # Examples 24 | /// 25 | /// ``` 26 | /// use rgb::Gray_v09 as Gray; 27 | /// 28 | /// let pixel: Gray = Gray { v: 0 }; 29 | /// ``` 30 | #[allow(non_camel_case_types)] 31 | #[repr(C)] 32 | #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] 33 | #[cfg_attr(feature = "defmt-03", derive(defmt::Format))] 34 | #[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Ord, PartialOrd, Hash)] 35 | #[doc(alias = "Luma")] 36 | #[doc(alias = "Mono")] 37 | #[doc(alias = "GRAY8")] 38 | #[doc(alias = "GRAY16")] 39 | pub struct Gray_v09 { 40 | /// Grayscale Component 41 | pub v: T, 42 | } 43 | 44 | impl core::ops::Deref for Gray_v08 { 45 | type Target = T; 46 | 47 | fn deref(&self) -> &T { 48 | &self.0 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/formats/gray_a.rs: -------------------------------------------------------------------------------- 1 | #[repr(C)] 2 | #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] 3 | #[cfg_attr(feature = "defmt-03", derive(defmt::Format))] 4 | #[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Ord, PartialOrd, Hash)] 5 | /// A `Grayscale + Alpha` pixel (rgb crate v0.9) 6 | /// 7 | /// This pixel is commonly used for grayscale images. A binary 8 | /// grayscale images can also be represented using `GrayA`, 9 | /// but this won't reduce the storage size. 10 | /// 11 | /// This is the new gray+alpha pixel type as opposed to the legacy gray+alpha type 12 | /// (`rgb::GrayAlpha`) which is kept for backwards-compatibility. 13 | /// 14 | /// # Examples 15 | /// 16 | /// ``` 17 | /// use rgb::GrayA; 18 | /// 19 | /// let pixel: GrayA = GrayA { v: 0, a: 255 }; 20 | /// ``` 21 | #[doc(alias = "GrayAlpha")] 22 | #[doc(alias = "GRAYA8")] 23 | #[doc(alias = "GRAYA16")] 24 | pub struct GrayA { 25 | /// Value - the brightness component. May be luma or luminance. 26 | pub v: T, 27 | /// Alpha Component 28 | pub a: A, 29 | } 30 | -------------------------------------------------------------------------------- /src/formats/gray_a44.rs: -------------------------------------------------------------------------------- 1 | use core::fmt::Display; 2 | 3 | #[repr(C)] 4 | #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] 5 | #[cfg_attr(feature = "defmt-03", derive(defmt::Format))] 6 | #[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Ord, PartialOrd, Hash)] 7 | /// A `Grayscale + Alpha` 8-bit pixel with the first 4 bits used for the value 8 | /// component the last 4 bits used for the alpha component. 9 | /// 10 | /// # Examples 11 | /// 12 | /// ``` 13 | /// use rgb::GrayA44; 14 | /// 15 | /// let pixel = GrayA44::new(0, 15).unwrap(); 16 | /// ``` 17 | pub struct GrayA44(pub(crate) u8); 18 | 19 | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] 20 | /// Error returned from the [`GrayA44::new()`] function if the given 21 | /// components are out of range. 22 | pub struct OutOfRangeError; 23 | impl Display for OutOfRangeError { 24 | #[cold] 25 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 26 | f.write_str("the components are outside of the valid range") 27 | } 28 | } 29 | 30 | impl GrayA44 { 31 | /// Tries to create new [`GrayA44`] given both components. 32 | /// 33 | /// Returns an error if either component is out of the 4-bit range (`0..=15`). 34 | /// 35 | /// # Examples 36 | /// 37 | /// ``` 38 | /// use rgb::GrayA44; 39 | /// use rgb::error::OutOfRangeError; 40 | /// 41 | /// let pixel = GrayA44::new(0, 15).unwrap(); 42 | /// assert_eq!(pixel.v(), 0); 43 | /// assert_eq!(pixel.a(), 15); 44 | /// 45 | /// assert_eq!(GrayA44::new(120, 20), Err(OutOfRangeError)); 46 | /// ``` 47 | #[inline] 48 | pub fn new(v: u8, a: u8) -> Result { 49 | if v > 15 || a > 15 { 50 | return Err(OutOfRangeError); 51 | } 52 | 53 | Ok(Self((v << 4) | a)) 54 | } 55 | 56 | /// Returns a copy of the pixel's 4-bit grayscale component as a `u8`. 57 | /// 58 | /// # Examples 59 | /// 60 | /// ``` 61 | /// use rgb::GrayA44; 62 | /// 63 | /// let pixel = GrayA44::new(0, 15).unwrap(); 64 | /// 65 | /// assert_eq!(pixel.v(), 0); 66 | /// ``` 67 | #[inline] 68 | pub fn v(self) -> u8 { 69 | self.0 >> 4 70 | } 71 | 72 | #[inline] 73 | /// Returns a copy of the pixel's 4-bit alpha component as a `u8`. 74 | /// 75 | /// # Examples 76 | /// 77 | /// ``` 78 | /// use rgb::GrayA44; 79 | /// 80 | /// let pixel = GrayA44::new(0, 15).unwrap(); 81 | /// 82 | /// assert_eq!(pixel.a(), 15); 83 | /// ``` 84 | pub fn a(self) -> u8 { 85 | self.0 & 0xF 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/formats/gray_alpha.rs: -------------------------------------------------------------------------------- 1 | use crate::formats::gray_a::GrayA; 2 | use core::ops::Deref; 3 | 4 | #[repr(C)] 5 | #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] 6 | #[cfg_attr(feature = "defmt-03", derive(defmt::Format))] 7 | #[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Ord, PartialOrd, Hash)] 8 | /// A pixel for grayscale value + alpha components (rgb crate v0.8) 9 | /// 10 | /// This is the legacy gray+alpha pixel type as opposed to the new gray+alpha type 11 | /// (`rgb::GrayA`). This type is kept for backwards-compatibility. 12 | /// 13 | /// You should transition to the new gray+alpha pixel type as this type is 14 | /// due to be removed in a future release. 15 | /// 16 | /// Through a `Deref` hack it renames the fields from `.0` and `.1` 17 | /// to `.v` (value) and `.a` (alpha) 18 | #[allow(non_camel_case_types)] 19 | pub struct GrayAlpha_v08( 20 | /// Grayscale Component 21 | /// 22 | /// This field has been renamed to `.v` 23 | pub T, 24 | /// Alpha Component. This field has been renamed to `.a`. 25 | pub A, 26 | ); 27 | 28 | impl Deref for GrayAlpha_v08 { 29 | type Target = GrayA; 30 | 31 | /// A trick that allows using `.v` and `.a` on the old `GrayAlpha` type. 32 | fn deref(&self) -> &GrayA { 33 | unsafe { &*(self as *const Self).cast::>() } 34 | } 35 | } 36 | 37 | #[test] 38 | fn swizzle() { 39 | let g = GrayAlpha_v08(10u8, 20u8); 40 | assert_eq!(10, g.v); 41 | assert_eq!(20, g.a); 42 | } 43 | -------------------------------------------------------------------------------- /src/formats/grb.rs: -------------------------------------------------------------------------------- 1 | #[repr(C)] 2 | #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] 3 | #[cfg_attr(feature = "defmt-03", derive(defmt::Format))] 4 | #[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Ord, PartialOrd, Hash)] 5 | /// A `Green + Red + Blue` pixel. 6 | /// 7 | /// # Examples 8 | /// 9 | /// ``` 10 | /// use rgb::Grb; 11 | /// 12 | /// let pixel: Grb = Grb { g: 0, r: 0, b: 0 }; 13 | /// ``` 14 | pub struct Grb { 15 | /// Green Component 16 | pub g: T, 17 | /// Red Component 18 | pub r: T, 19 | /// Blue Component 20 | pub b: T, 21 | } 22 | -------------------------------------------------------------------------------- /src/formats/rgb.rs: -------------------------------------------------------------------------------- 1 | #[repr(C)] 2 | #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] 3 | #[cfg_attr(feature = "defmt-03", derive(defmt::Format))] 4 | #[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Ord, PartialOrd, Hash)] 5 | /// A `Red + Green + Blue` pixel. 6 | /// 7 | /// # Examples 8 | /// 9 | /// ``` 10 | /// use rgb::Rgb; 11 | /// 12 | /// let pixel: Rgb = Rgb { r: 0, g: 0, b: 0 }; 13 | /// ``` 14 | #[doc(alias = "RGB8")] 15 | #[doc(alias = "RGB16")] 16 | pub struct Rgb { 17 | /// Red Component 18 | pub r: T, 19 | /// Green Component 20 | pub g: T, 21 | /// Blue Component 22 | pub b: T, 23 | } 24 | -------------------------------------------------------------------------------- /src/formats/rgba.rs: -------------------------------------------------------------------------------- 1 | #[repr(C)] 2 | #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] 3 | #[cfg_attr(feature = "defmt-03", derive(defmt::Format))] 4 | #[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Ord, PartialOrd, Hash)] 5 | /// A `Red + Green + Blue + Alpha` pixel. 6 | /// 7 | /// # Examples 8 | /// 9 | /// ``` 10 | /// use rgb::Rgba; 11 | /// 12 | /// let pixel: Rgba = Rgba { r: 0, g: 0, b: 0, a: 255 }; 13 | /// ``` 14 | #[doc(alias = "RGBA8")] 15 | #[doc(alias = "RGBA16")] 16 | pub struct Rgba { 17 | /// Red Component 18 | pub r: T, 19 | /// Green Component 20 | pub g: T, 21 | /// Blue Component 22 | pub b: T, 23 | /// Alpha Component 24 | pub a: A, 25 | } 26 | -------------------------------------------------------------------------------- /src/formats/rgbw.rs: -------------------------------------------------------------------------------- 1 | #[repr(C)] 2 | #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] 3 | #[cfg_attr(feature = "defmt-03", derive(defmt::Format))] 4 | #[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Ord, PartialOrd, Hash)] 5 | /// A `Red + Green + Blue + White` pixel. 6 | /// 7 | /// # Examples 8 | /// 9 | /// ``` 10 | /// use rgb::Rgbw; 11 | /// 12 | /// let pixel: Rgbw = Rgbw { r: 0, g: 0, b: 0, w: 0 }; 13 | /// ``` 14 | pub struct Rgbw { 15 | /// Red Component 16 | pub r: T, 17 | /// Green Component 18 | pub g: T, 19 | /// Blue Component 20 | pub b: T, 21 | /// White Component 22 | pub w: T, 23 | } 24 | -------------------------------------------------------------------------------- /src/from.rs: -------------------------------------------------------------------------------- 1 | use crate::{Abgr, Argb, Bgr, Bgra, GrayA, Gray_v09, Grb, Rgb, Rgba}; 2 | 3 | macro_rules! without_alpha { 4 | ($from_type:ident, $self_type:ident, {$($bit:tt),*}) => { 5 | impl From<$from_type> for $self_type { 6 | #[inline] 7 | fn from(value: $from_type) -> Self { 8 | Self { $($bit: value.$bit.into()),* } 9 | } 10 | } 11 | }; 12 | } 13 | macro_rules! with_alpha { 14 | ($from_type:ident, $self_type:ident, {$($bit:tt),*}) => { 15 | impl From<$from_type> for $self_type { 16 | #[inline] 17 | fn from(value: $from_type) -> Self { 18 | Self { $($bit: value.$bit.into()),* } 19 | } 20 | } 21 | }; 22 | } 23 | macro_rules! alpha_to_no_alpha { 24 | ($from_type:ident, $self_type:ident, {$($bit:tt),*}) => { 25 | impl From<$from_type> for $self_type { 26 | #[inline] 27 | fn from(value: $from_type) -> Self { 28 | Self { $($bit: value.$bit.into()),* } 29 | } 30 | } 31 | }; 32 | } 33 | 34 | alpha_to_no_alpha!(Rgba, Rgb, {r, g, b}); 35 | alpha_to_no_alpha!(Argb, Rgb, {r, g, b}); 36 | alpha_to_no_alpha!(Bgra, Rgb, {r, g, b}); 37 | alpha_to_no_alpha!(Abgr, Rgb, {r, g, b}); 38 | without_alpha!(Bgr, Rgb, {r, g, b}); 39 | without_alpha!(Grb, Rgb, {r, g, b}); 40 | 41 | alpha_to_no_alpha!(Rgba, Bgr, {r, g, b}); 42 | alpha_to_no_alpha!(Argb, Bgr, {r, g, b}); 43 | alpha_to_no_alpha!(Bgra, Bgr, {r, g, b}); 44 | alpha_to_no_alpha!(Abgr, Bgr, {r, g, b}); 45 | without_alpha!(Rgb, Bgr, {r, g, b}); 46 | without_alpha!(Grb, Bgr, {r, g, b}); 47 | 48 | alpha_to_no_alpha!(Rgba, Grb, {r, g, b}); 49 | alpha_to_no_alpha!(Argb, Grb, {r, g, b}); 50 | alpha_to_no_alpha!(Bgra, Grb, {r, g, b}); 51 | alpha_to_no_alpha!(Abgr, Grb, {r, g, b}); 52 | without_alpha!(Rgb, Grb, {r, g, b}); 53 | without_alpha!(Bgr, Grb, {r, g, b}); 54 | 55 | with_alpha!(Argb, Rgba, {r, g, b, a}); 56 | with_alpha!(Bgra, Rgba, {r, g, b, a}); 57 | with_alpha!(Abgr, Rgba, {r, g, b, a}); 58 | 59 | with_alpha!(Rgba, Argb, {r, g, b, a}); 60 | with_alpha!(Bgra, Argb, {r, g, b, a}); 61 | with_alpha!(Abgr, Argb, {r, g, b, a}); 62 | 63 | with_alpha!(Rgba, Bgra, {r, g, b, a}); 64 | with_alpha!(Argb, Bgra, {r, g, b, a}); 65 | with_alpha!(Abgr, Bgra, {r, g, b, a}); 66 | 67 | with_alpha!(Rgba, Abgr, {r, g, b, a}); 68 | with_alpha!(Argb, Abgr, {r, g, b, a}); 69 | with_alpha!(Bgra, Abgr, {r, g, b, a}); 70 | 71 | alpha_to_no_alpha!(GrayA, Gray_v09, { v }); 72 | -------------------------------------------------------------------------------- /src/inherent_impls.rs: -------------------------------------------------------------------------------- 1 | use crate::{Abgr, Argb, Bgr, Bgra, GrayA, Gray_v09, Grb, Rgb, Rgba, Rgbw}; 2 | 3 | macro_rules! inherent_impls { 4 | ($name:ident, $new_fn:ident, [$($field:tt $var:ident),*]) => { 5 | impl $name { 6 | #[doc=concat!("Creates a new [`", stringify!($name), "`] pixel type from its components.")] 7 | /// 8 | /// Alternatively, you can use struct literal syntax to 9 | /// create the new pixel type: 10 | ///```not_rust 11 | #[doc=concat!("use rgb::", stringify!($name), ";")] 12 | /// 13 | #[doc=concat!("let pixel = ", stringify!($name), " {", stringify!($($field: $var),*), "};")] 14 | ///``` 15 | pub const fn $new_fn($($var: T),*) -> Self { 16 | Self {$($field: $var),*} 17 | } 18 | } 19 | } 20 | } 21 | 22 | inherent_impls!(Rgb, new, [r red, g green, b blue]); 23 | inherent_impls!(Bgr, new_bgr, [b blue, g green, r red]); 24 | inherent_impls!(Grb, new_grb, [g green, r red, b blue]); 25 | inherent_impls!(Gray_v09, new, [v value]); 26 | inherent_impls!(Rgbw, new, [r red, g green, b blue, w white]); 27 | 28 | use crate::formats::gray::Gray_v08; 29 | inherent_impls!(Gray_v08, new, [0 value]); 30 | 31 | inherent_impls!(Rgba, new, [r red, g green, b blue, a alpha]); 32 | inherent_impls!(Argb, new_argb, [a alpha, r red, g green, b blue]); 33 | inherent_impls!(Bgra, new_bgra, [b blue, g green, r red, a alpha]); 34 | inherent_impls!(Abgr, new_abgr, [a alpha, b blue, g green, r red]); 35 | inherent_impls!(GrayA, new, [v value, a alpha]); 36 | 37 | use crate::formats::gray_alpha::GrayAlpha_v08; 38 | inherent_impls!(GrayAlpha_v08, new, [0 value, 1 alpha]); 39 | -------------------------------------------------------------------------------- /src/legacy/alt.rs: -------------------------------------------------------------------------------- 1 | use crate::legacy::internal::pixel::{ColorComponentMap, ComponentSlice}; 2 | use core::slice; 3 | 4 | pub use crate::formats::gray::Gray_v08 as Gray; 5 | pub use crate::formats::gray_alpha::GrayAlpha_v08 as GrayAlpha; 6 | 7 | /// Renamed to `Bgra` 8 | #[doc(hidden)] 9 | pub use crate::formats::bgra::Bgra as BGRA; 10 | 11 | /// Renamed to `Bgr` 12 | #[doc(hidden)] 13 | pub use crate::formats::bgr::Bgr as BGR; 14 | 15 | /// Renamed to `Abgr` 16 | #[doc(hidden)] 17 | pub use crate::formats::abgr::Abgr as ABGR; 18 | 19 | /// Renamed to `Argb` 20 | #[doc(hidden)] 21 | pub use crate::formats::argb::Argb as ARGB; 22 | 23 | /// Renamed to `Grb` 24 | #[doc(hidden)] 25 | pub use crate::formats::grb::Grb as GRB; 26 | 27 | /// 8-bit BGR 28 | pub type BGR8 = crate::formats::bgr::Bgr; 29 | 30 | /// 16-bit BGR in machine's native endian 31 | pub type BGR16 = crate::formats::bgr::Bgr; 32 | 33 | /// 8-bit BGRA 34 | pub type BGRA8 = crate::formats::bgra::Bgra; 35 | 36 | /// 8-bit ABGR, alpha is first. 0 = transparent, 255 = opaque. 37 | pub type ABGR8 = crate::formats::abgr::Abgr; 38 | 39 | /// 8-bit ARGB, alpha is first. 0 = transparent, 255 = opaque. 40 | pub type ARGB8 = crate::Argb; 41 | 42 | /// 16-bit BGR in machine's native endian 43 | pub type BGRA16 = crate::formats::bgra::Bgra; 44 | 45 | /// 16-bit ABGR in machine's native endian. 0 = transparent, 65535 = opaque. 46 | pub type ABGR16 = crate::formats::abgr::Abgr; 47 | 48 | /// 16-bit ARGB in machine's native endian. 0 = transparent, 65535 = opaque. 49 | pub type ARGB16 = crate::Argb; 50 | 51 | /// 8-bit GRB 52 | pub type GRB8 = crate::formats::grb::Grb; 53 | 54 | /// 8-bit gray 55 | pub type GRAY8 = Gray; 56 | 57 | /// 16-bit gray in machine's native endian 58 | pub type GRAY16 = Gray; 59 | 60 | /// 8-bit gray with alpha in machine's native endian 61 | pub type GRAYA8 = GrayAlpha; 62 | 63 | /// 16-bit gray with alpha in machine's native endian 64 | pub type GRAYA16 = GrayAlpha; 65 | 66 | 67 | /// These are deprecated, use `[val; 1]` as the source if you must 68 | impl From for Gray { fn from(v: u8) -> Self { Self(v) } } 69 | impl From for Gray { fn from(v: u16) -> Self { Self(v) } } 70 | impl From for Gray { fn from(v: u32) -> Self { Self(v) } } 71 | impl From for Gray { fn from(v: i32) -> Self { Self(v) } } 72 | impl From for Gray { fn from(v: f32) -> Self { Self(v) } } 73 | 74 | impl GrayAlpha { 75 | /// Copy `Gray` component out of the `GrayAlpha` struct 76 | #[inline(always)] 77 | pub fn gray(&self) -> Gray { 78 | Gray(self.0.clone()) 79 | } 80 | } 81 | 82 | impl GrayAlpha { 83 | /// Provide a mutable view of only `Gray` component (leaving out alpha). 84 | #[inline(always)] 85 | pub fn gray_mut(&mut self) -> &mut Gray { 86 | unsafe { &mut *(self as *mut Self).cast() } 87 | } 88 | } 89 | 90 | impl GrayAlpha { 91 | /// Create a new `GrayAlpha` with the new alpha value, but same gray value 92 | #[doc(hidden)] 93 | #[deprecated(note = "use .with_alpha(a) instead")] 94 | pub fn alpha(&self, a: A) -> Self { 95 | self.with_alpha(a) 96 | } 97 | 98 | /// Create a new `GrayAlpha` with the new alpha value, but same gray value 99 | #[inline(always)] 100 | pub const fn with_alpha(&self, a: A) -> Self { 101 | Self(self.0, a) 102 | } 103 | 104 | /// Create a new `GrayAlpha` with a new alpha value created by the callback. 105 | #[inline(always)] 106 | pub fn map_alpha(&self, f: F) -> GrayAlpha 107 | where F: FnOnce(A) -> B 108 | { 109 | GrayAlpha(self.0, f(self.1.clone())) 110 | } 111 | 112 | /// Create new `GrayAlpha` with the same alpha value, but different `Gray` value 113 | #[inline(always)] 114 | pub fn map_gray(&self, f: F) -> GrayAlpha 115 | where F: FnOnce(T) -> U, U: Clone, B: From + Clone { 116 | GrayAlpha(f(self.0), self.1.clone().into()) 117 | } 118 | } 119 | 120 | impl ColorComponentMap, T, B> for Gray { 121 | #[inline(always)] 122 | fn map_c(&self, mut f: F) -> Gray where F: FnMut(T) -> B { 123 | Gray(f(self.0)) 124 | } 125 | } 126 | 127 | impl ColorComponentMap, T, B> for GrayAlpha { 128 | #[inline(always)] 129 | fn map_c(&self, mut f: F) -> GrayAlpha 130 | where F: FnMut(T) -> B { 131 | GrayAlpha(f(self.0), self.1) 132 | } 133 | } 134 | 135 | impl ComponentSlice for GrayAlpha { 136 | #[inline(always)] 137 | fn as_slice(&self) -> &[T] { 138 | unsafe { 139 | slice::from_raw_parts((self as *const Self).cast::(), 2) 140 | } 141 | } 142 | 143 | #[inline(always)] 144 | fn as_mut_slice(&mut self) -> &mut [T] { 145 | unsafe { 146 | slice::from_raw_parts_mut((self as *mut Self).cast::(), 2) 147 | } 148 | } 149 | } 150 | 151 | impl ComponentSlice for [GrayAlpha] { 152 | #[inline] 153 | fn as_slice(&self) -> &[T] { 154 | unsafe { 155 | slice::from_raw_parts(self.as_ptr().cast(), self.len() * 2) 156 | } 157 | } 158 | 159 | #[inline] 160 | fn as_mut_slice(&mut self) -> &mut [T] { 161 | unsafe { 162 | slice::from_raw_parts_mut(self.as_ptr() as *mut _, self.len() * 2) 163 | } 164 | } 165 | } 166 | 167 | impl ComponentSlice for Gray { 168 | #[inline(always)] 169 | fn as_slice(&self) -> &[T] { 170 | slice::from_ref(&self.0) 171 | } 172 | 173 | #[inline(always)] 174 | fn as_mut_slice(&mut self) -> &mut [T] { 175 | slice::from_mut(&mut self.0) 176 | } 177 | } 178 | 179 | impl ComponentSlice for [Gray] { 180 | #[inline] 181 | fn as_slice(&self) -> &[T] { 182 | unsafe { 183 | slice::from_raw_parts(self.as_ptr().cast(), self.len()) 184 | } 185 | } 186 | 187 | #[inline] 188 | fn as_mut_slice(&mut self) -> &mut [T] { 189 | unsafe { 190 | slice::from_raw_parts_mut(self.as_ptr() as *mut _, self.len()) 191 | } 192 | } 193 | } 194 | 195 | /// Assumes 255 is opaque 196 | impl From> for GrayAlpha { 197 | #[inline(always)] 198 | fn from(other: Gray) -> Self { 199 | Self(other.0, 0xFF) 200 | } 201 | } 202 | 203 | /// Assumes 65535 is opaque 204 | impl From> for GrayAlpha { 205 | #[inline(always)] 206 | fn from(other: Gray) -> Self { 207 | Self(other.0, 0xFFFF) 208 | } 209 | } 210 | 211 | #[test] 212 | #[allow(deprecated)] 213 | fn gray() { 214 | use crate::Pixel; 215 | 216 | let rgb: crate::RGB<_> = Gray(1).into(); 217 | assert_eq!(rgb.r, 1); 218 | assert_eq!(rgb.g, 1); 219 | assert_eq!(rgb.b, 1); 220 | 221 | let rgba: crate::RGBA<_> = Gray(1u8).into(); 222 | assert_eq!(rgba.r, 1); 223 | assert_eq!(rgba.g, 1); 224 | assert_eq!(rgba.b, 1); 225 | assert_eq!(rgba.a, 255); 226 | 227 | let g: GRAY8 = 200.into(); 228 | let g = g.map(|c| c / 2); 229 | assert_eq!(110, g.0 + 10); 230 | assert_eq!(110, 10 + Gray(100).as_ref()); 231 | 232 | let ga: GRAYA8 = GrayAlpha(1, 2); 233 | assert_eq!(ga.gray(), Gray::new(1)); 234 | let mut g2 = ga.clone(); 235 | *g2.gray_mut() = Gray(3); 236 | assert_eq!(g2.map_gray(|g| g + 1), GRAYA8::new(4, 2)); 237 | assert_eq!(g2.map(|g| g + 1), GrayAlpha(4, 3)); 238 | assert_eq!(g2.0, 3); 239 | assert_eq!(g2.as_slice(), &[3, 2]); 240 | assert_eq!(g2.as_mut_slice(), &[3, 2]); 241 | assert_eq!(g2.with_alpha(13), GrayAlpha(3, 13)); 242 | assert_eq!(g2.map_alpha(|x| x + 3), GrayAlpha(3, 5)); 243 | 244 | assert_eq!((&[Gray(1u16), Gray(2)][..]).as_slice(), &[1, 2]); 245 | assert_eq!((&[GrayAlpha(1u16, 2), GrayAlpha(3, 4)][..]).as_slice(), &[1, 2, 3, 4]); 246 | 247 | let rgba: crate::RGBA<_> = ga.into(); 248 | assert_eq!(rgba.r, 1); 249 | assert_eq!(rgba.g, 1); 250 | assert_eq!(rgba.b, 1); 251 | assert_eq!(rgba.a, 2); 252 | 253 | let ga: GRAYA16 = GrayAlpha(1, 2); 254 | let rgba: crate::RGBA = ga.into(); 255 | assert_eq!(rgba.r, 1); 256 | assert_eq!(rgba.g, 1); 257 | assert_eq!(rgba.b, 1); 258 | assert_eq!(rgba.a, 2); 259 | } 260 | -------------------------------------------------------------------------------- /src/legacy/internal/convert/mod.rs: -------------------------------------------------------------------------------- 1 | use crate::alt::*; 2 | use crate::formats::gray::Gray_v08; 3 | use crate::pixel_traits::pixel::Pixel; 4 | use crate::*; 5 | use core::{mem, slice}; 6 | 7 | /// Casts a slice of bytes into a slice of pixels, e.g. `[u8]` to `[RGB8]`. 8 | /// 9 | /// See also `FromSlice` 10 | pub trait AsPixels { 11 | /// Reinterpret the slice as a read-only/shared slice of pixels. 12 | /// Multiple consecutive elements in the slice are interpreted as a single pixel 13 | /// (depending on format, e.g. 3 for RGB, 4 for RGBA). 14 | /// 15 | /// Leftover elements are ignored if the slice isn't evenly divisible into pixels. 16 | /// 17 | /// Use this method only when the type is known from context. 18 | /// See also `FromSlice`. 19 | fn as_pixels(&self) -> &[PixelType]; 20 | /// Reinterpret the slice as a mutable/exclusive slice of pixels. 21 | /// Multiple consecutive elements in the slice are interpreted as a single pixel 22 | /// (depending on format, e.g. 3 for RGB, 4 for RGBA). 23 | /// 24 | /// Leftover elements are ignored if the slice isn't evenly divisible into pixels. 25 | /// 26 | /// Use this method only when the type is known from context. 27 | /// See also `FromSlice`. 28 | fn as_pixels_mut(&mut self) -> &mut [PixelType]; 29 | } 30 | 31 | macro_rules! as_pixels_impl { 32 | ($typ:ident, $elems:expr) => { 33 | impl AsPixels<$typ> for [T] { 34 | fn as_pixels(&self) -> &[$typ] { 35 | unsafe { 36 | slice::from_raw_parts(self.as_ptr() as *const _, self.len() / $elems) 37 | } 38 | } 39 | 40 | fn as_pixels_mut(&mut self) -> &mut [$typ] { 41 | unsafe { 42 | slice::from_raw_parts_mut(self.as_mut_ptr() as *mut _, self.len() / $elems) 43 | } 44 | } 45 | } 46 | }; 47 | } 48 | 49 | as_pixels_impl! {Rgb, 3} 50 | as_pixels_impl! {Rgba, 4} 51 | as_pixels_impl! {Bgr, 3} 52 | as_pixels_impl! {Bgra, 4} 53 | as_pixels_impl! {Grb, 3} 54 | as_pixels_impl! {Gray_v08, 1} 55 | as_pixels_impl! {GrayAlpha, 2} 56 | as_pixels_impl! {Argb, 4} 57 | as_pixels_impl! {Abgr, 4} 58 | 59 | /// Cast a slice of component values (bytes) as a slice of RGB/RGBA pixels 60 | /// 61 | /// If there's any incomplete pixel at the end of the slice it is ignored. 62 | pub trait FromSlice { 63 | /// Reinterpert slice as RGB pixels 64 | fn as_rgb(&self) -> &[Rgb]; 65 | /// Reinterpert slice as RGBA pixels 66 | fn as_rgba(&self) -> &[Rgba]; 67 | /// Reinterpert slice as alpha-first ARGB pixels 68 | fn as_argb(&self) -> &[ARGB]; 69 | /// Reinterpert mutable slice as RGB pixels 70 | fn as_rgb_mut(&mut self) -> &mut [Rgb]; 71 | /// Reinterpert mutable slice as RGBA pixels 72 | fn as_rgba_mut(&mut self) -> &mut [Rgba]; 73 | /// Reinterpert mutable slice as alpha-first ARGB pixels 74 | fn as_argb_mut(&mut self) -> &mut [ARGB]; 75 | 76 | /// Reinterpert mutable slice as grayscale pixels 77 | #[deprecated(note = "use bytemuck::cast_slice()")] 78 | fn as_gray(&self) -> &[Gray_v08]; 79 | /// Reinterpert mutable slice as grayscale pixels with alpha 80 | #[deprecated(note = "use bytemuck::cast_slice()")] 81 | fn as_gray_alpha(&self) -> &[GrayAlpha]; 82 | /// Reinterpert mutable slice as grayscale pixels 83 | #[deprecated(note = "use bytemuck::cast_slice()")] 84 | fn as_gray_mut(&mut self) -> &mut [Gray_v08]; 85 | /// Reinterpert mutable slice as grayscale pixels with alpha 86 | #[deprecated(note = "use bytemuck::cast_slice()")] 87 | fn as_gray_alpha_mut(&mut self) -> &mut [GrayAlpha]; 88 | 89 | /// Reinterpert slice as reverse-order BGR pixels 90 | fn as_bgr(&self) -> &[Bgr]; 91 | /// Reinterpert slice as reverse-order BGRA pixels 92 | fn as_bgra(&self) -> &[Bgra]; 93 | /// Reinterpert slice as reverse-order ABGR pixels 94 | fn as_abgr(&self) -> &[Abgr]; 95 | /// Reinterpert ntable slice as reverse-order BGR pixels 96 | fn as_bgr_mut(&mut self) -> &mut [Bgr]; 97 | /// Reinterpert mutable slice as reverse-order alpha-last BGRA pixels 98 | fn as_bgra_mut(&mut self) -> &mut [Bgra]; 99 | /// Reinterpert mutable slice as reverse-order alpha-first ABGR pixels 100 | fn as_abgr_mut(&mut self) -> &mut [Abgr]; 101 | } 102 | 103 | impl FromSlice for [T] { 104 | #[inline] 105 | fn as_rgb(&self) -> &[Rgb] { 106 | unsafe { from_items_to_struct(self) } 107 | } 108 | 109 | #[inline] 110 | fn as_rgba(&self) -> &[Rgba] { 111 | unsafe { from_items_to_struct(self) } 112 | } 113 | 114 | #[inline] 115 | fn as_argb(&self) -> &[ARGB] { 116 | unsafe { from_items_to_struct(self) } 117 | } 118 | 119 | #[inline] 120 | fn as_rgb_mut(&mut self) -> &mut [Rgb] { 121 | unsafe { from_items_to_struct_mut(self) } 122 | } 123 | 124 | #[inline] 125 | fn as_rgba_mut(&mut self) -> &mut [Rgba] { 126 | unsafe { from_items_to_struct_mut(self) } 127 | } 128 | 129 | #[inline] 130 | fn as_argb_mut(&mut self) -> &mut [ARGB] { 131 | unsafe { from_items_to_struct_mut(self) } 132 | } 133 | 134 | #[inline] 135 | fn as_gray(&self) -> &[Gray_v08] { 136 | unsafe { from_items_to_struct(self) } 137 | } 138 | 139 | #[inline] 140 | fn as_gray_alpha(&self) -> &[GrayAlpha] { 141 | unsafe { from_items_to_struct(self) } 142 | } 143 | 144 | #[inline] 145 | fn as_gray_mut(&mut self) -> &mut [Gray_v08] { 146 | unsafe { from_items_to_struct_mut(self) } 147 | } 148 | 149 | #[inline] 150 | fn as_gray_alpha_mut(&mut self) -> &mut [GrayAlpha] { 151 | unsafe { from_items_to_struct_mut(self) } 152 | } 153 | 154 | #[inline] 155 | fn as_bgr(&self) -> &[Bgr] { 156 | unsafe { from_items_to_struct(self) } 157 | } 158 | 159 | #[inline] 160 | fn as_abgr(&self) -> &[Abgr] { 161 | unsafe { from_items_to_struct(self) } 162 | } 163 | 164 | #[inline] 165 | fn as_bgra(&self) -> &[Bgra] { 166 | unsafe { from_items_to_struct(self) } 167 | } 168 | 169 | #[inline] 170 | fn as_bgr_mut(&mut self) -> &mut [Bgr] { 171 | unsafe { from_items_to_struct_mut(self) } 172 | } 173 | 174 | #[inline] 175 | fn as_bgra_mut(&mut self) -> &mut [Bgra] { 176 | unsafe { from_items_to_struct_mut(self) } 177 | } 178 | 179 | #[inline] 180 | fn as_abgr_mut(&mut self) -> &mut [Abgr] { 181 | unsafe { from_items_to_struct_mut(self) } 182 | } 183 | } 184 | 185 | #[inline(always)] 186 | unsafe fn from_items_to_struct(from: &[F]) -> &[T] { 187 | debug_assert_eq!(0, mem::size_of::() % mem::size_of::()); 188 | let len = from.len() / (mem::size_of::() / mem::size_of::()); 189 | slice::from_raw_parts(from.as_ptr().cast::(), len) 190 | } 191 | 192 | #[inline(always)] 193 | unsafe fn from_items_to_struct_mut(from: &mut [F]) -> &mut [T] { 194 | debug_assert_eq!(0, mem::size_of::() % mem::size_of::()); 195 | let len = from.len() / (mem::size_of::() / mem::size_of::()); 196 | slice::from_raw_parts_mut(from.as_mut_ptr().cast::(), len) 197 | } 198 | 199 | macro_rules! rgb_impl_from { 200 | ($typename:ident, $from:ty, $to:ty) => { 201 | impl From<$typename<$from>> for $typename<$to> { 202 | #[inline(always)] 203 | fn from(other: $typename<$from>) -> Self { 204 | other.map(core::convert::Into::into) 205 | } 206 | } 207 | }; 208 | } 209 | 210 | rgb_impl_from! {Rgb, u8,i16} 211 | rgb_impl_from! {Rgb, u8,i32} 212 | rgb_impl_from! {Rgb, u8,u16} 213 | rgb_impl_from! {Rgb, u8,u32} 214 | rgb_impl_from! {Rgb, u16,i32} 215 | rgb_impl_from! {Rgb, u16,u32} 216 | rgb_impl_from! {Rgb, u16,u64} 217 | 218 | rgb_impl_from! {Rgb, u8,f32} 219 | rgb_impl_from! {Rgb, u8,f64} 220 | rgb_impl_from! {Rgb, u16,f32} 221 | rgb_impl_from! {Rgb, u16,f64} 222 | 223 | rgb_impl_from! {Rgb, i16,f32} 224 | rgb_impl_from! {Rgb, i16,f64} 225 | 226 | rgb_impl_from! {Rgb, i32,f64} 227 | rgb_impl_from! {Rgb, f32,f64} 228 | 229 | rgb_impl_from! {Rgba, u16,i32} 230 | rgb_impl_from! {Rgba, u16,u32} 231 | rgb_impl_from! {Rgba, u16,u64} 232 | 233 | rgb_impl_from! {Rgba, u8,i16} 234 | rgb_impl_from! {Rgba, u8,u16} 235 | rgb_impl_from! {Rgba, u8,u32} 236 | rgb_impl_from! {Rgba, u8,f32} 237 | rgb_impl_from! {Rgba, u8,f64} 238 | rgb_impl_from! {Rgba, u16,f32} 239 | rgb_impl_from! {Rgba, u16,f64} 240 | 241 | rgb_impl_from! {Rgba, i16,f32} 242 | rgb_impl_from! {Rgba, i16,f64} 243 | 244 | rgb_impl_from! {Rgba, i32,f64} 245 | rgb_impl_from! {Rgba, f32,f64} 246 | 247 | impl From> for Rgb { 248 | #[inline(always)] 249 | fn from(other: Gray_v08) -> Self { 250 | Self { 251 | r: other.0.clone(), 252 | g: other.0.clone(), 253 | b: other.0, 254 | } 255 | } 256 | } 257 | 258 | impl From> for Rgba { 259 | #[inline(always)] 260 | fn from(other: Gray_v08) -> Self { 261 | Self { 262 | r: other.0.clone(), 263 | g: other.0.clone(), 264 | b: other.0, 265 | a: 255, 266 | } 267 | } 268 | } 269 | 270 | impl From> for Rgba { 271 | #[inline(always)] 272 | fn from(other: GrayAlpha) -> Self { 273 | Self { 274 | r: other.0.clone(), 275 | g: other.0.clone(), 276 | b: other.0, 277 | a: other.1, 278 | } 279 | } 280 | } 281 | 282 | impl AsRef for Gray_v08 { 283 | #[inline(always)] 284 | fn as_ref(&self) -> &T { 285 | &self.0 286 | } 287 | } 288 | 289 | impl AsRef for GrayAlpha { 290 | #[inline(always)] 291 | fn as_ref(&self) -> &T { 292 | &self.0 293 | } 294 | } 295 | 296 | impl AsMut for Gray_v08 { 297 | #[inline(always)] 298 | fn as_mut(&mut self) -> &mut T { 299 | &mut self.0 300 | } 301 | } 302 | 303 | impl AsMut for GrayAlpha { 304 | #[inline(always)] 305 | fn as_mut(&mut self) -> &mut T { 306 | &mut self.0 307 | } 308 | } 309 | 310 | #[test] 311 | fn argb_converts() { 312 | let argb = Argb { a: 0xffu8, r: 0xfa, g: 0xfb, b: 0xfc }; 313 | let rgba = Rgba { a: 0xffu8, r: 0xfa, g: 0xfb, b: 0xfc }; 314 | 315 | assert_eq!(Rgba::from(argb), rgba); 316 | assert_eq!(Argb::from(rgba), argb); 317 | assert_eq!(rgba.rgb(), argb.rgb()); 318 | 319 | let bgra = Bgra { a: 0xffu8, r: 0x1f, g: 0x2f, b: 0x3f }; 320 | let abgr = Abgr { a: 0xffu8, r: 0x1f, g: 0x2f, b: 0x3f }; 321 | 322 | assert_eq!(Bgra::from(abgr), bgra); 323 | assert_eq!(Abgr::from(bgra), abgr); 324 | } 325 | 326 | #[test] 327 | fn converts() { 328 | #![allow(deprecated)] 329 | use super::pixel::ComponentSlice; 330 | 331 | assert_eq!([1,2].as_gray(), [Gray_v08::new(1), Gray_v08::new(2)]); 332 | assert_eq!([3].as_gray_mut(), [Gray_v08::new(3)]); 333 | assert_eq!([1,2].as_gray_alpha(), [GrayAlpha::new(1, 2)]); 334 | // excess bytes are ignored 335 | assert_eq!([1,2,3].as_gray_alpha_mut(), [GrayAlpha::new(1, 2)]); 336 | assert_eq!([1,2,3,4].as_gray_alpha_mut(), [GrayAlpha::new(1, 2), GrayAlpha::new(3, 4)]); 337 | 338 | assert_eq!(RGBA::new(1u8,2,3,255), RGB::new(1u8,2,3).into()); 339 | assert_eq!(RGBA::new(1u16,2,3,65535), RGB::new(1u16,2,3).into()); 340 | assert_eq!(BGRA{r:1u8,g:2u8,b:3u8,a:255u8}, BGR{r:1u8,g:2u8,b:3u8}.into()); 341 | assert_eq!(BGRA{r:1u8,g:2u8,b:3u8,a:255u8}, RGB{r:1u8,g:2u8,b:3u8}.into()); 342 | assert_eq!(RGBA {r:1u8,g:2,b:3,a:4u8}, BGRA{r:1u8,g:2u8,b:3u8,a:4u8}.into()); 343 | assert_eq!(BGR {r:1u8,g:2,b:3u8}, RGB {r:1u8,g:2,b:3u8}.into()); 344 | assert_eq!(RGB {r:1u16,g:0x5678,b:0xABCDu16}, BGR {r:1u16,g:0x5678,b:0xABCDu16}.into()); 345 | assert_eq!(BGR {r:0x1234567u32,g:2,b:3u32}, RGB {r:0x1234567u32,g:2,b:3u32}.into()); 346 | 347 | assert_eq!(&[1u8,2,3,4], RGBA {r:1u8,g:2,b:3,a:4u8}.as_slice()); 348 | assert_eq!(&[1u8,2,3,4], RGBA {r:1u8,g:2,b:3,a:4u8}.as_ref()); 349 | assert_eq!(&[1u8,2,3], RGB {r:1u8,g:2,b:3}.as_slice()); 350 | assert_eq!(&[1u8,2,3], RGB {r:1u8,g:2,b:3}.as_ref()); 351 | 352 | assert_eq!(&[1u8,2,3], RGB {r:1u8,g:2,b:3}.as_mut_slice()); 353 | assert_eq!(&[1u8,2,3], RGB {r:1u8,g:2,b:3}.as_mut()); 354 | } 355 | 356 | -------------------------------------------------------------------------------- /src/legacy/internal/ops.rs: -------------------------------------------------------------------------------- 1 | #[allow(unused_imports)] 2 | use crate::formats::gray::Gray_v08; 3 | #[allow(unused_imports)] 4 | use crate::formats::gray_alpha::GrayAlpha_v08; 5 | #[allow(unused_imports)] 6 | use crate::{Abgr, Argb, Bgr, Bgra, Grb, Rgb, Rgba}; 7 | 8 | #[allow(unused_macros)] 9 | macro_rules! impl_struct_checked { 10 | ($ty:ident, $field_ty:ident, => $($field:tt)+) => { 11 | impl $ty<$field_ty> 12 | { 13 | /// `px.checked_add(px)` 14 | #[inline(always)] 15 | #[cfg_attr(feature = "num-traits", deprecated(note = "import `num_traits::CheckedAdd` instead, disable rgb's checked_fns feature"))] 16 | #[must_use] pub fn checked_add(self, rhs: $ty<$field_ty>) -> Option { 17 | Some($ty { 18 | $( 19 | $field: self.$field.checked_add(rhs.$field)?, 20 | )+ 21 | }) 22 | } 23 | 24 | /// `px.checked_sub(px)` 25 | #[inline(always)] 26 | #[cfg_attr(feature = "num-traits", deprecated(note = "import `num_traits::CheckedSub` instead, disable rgb's checked_fns feature"))] 27 | #[must_use] pub fn checked_sub(self, rhs: $ty<$field_ty>) -> Option { 28 | Some($ty { 29 | $( 30 | $field: self.$field.checked_sub(rhs.$field)?, 31 | )+ 32 | }) 33 | } 34 | } 35 | } 36 | } 37 | 38 | #[allow(unused_macros)] 39 | macro_rules! impl_legacy_checked { 40 | ($ty:ident => $($field:tt)+) => { 41 | impl_struct_checked!($ty, u8, => $($field)+); 42 | impl_struct_checked!($ty, u16, => $($field)+); 43 | impl_struct_checked!($ty, u32, => $($field)+); 44 | impl_struct_checked!($ty, u64, => $($field)+); 45 | impl_struct_checked!($ty, i8, => $($field)+); 46 | impl_struct_checked!($ty, i16, => $($field)+); 47 | impl_struct_checked!($ty, i32, => $($field)+); 48 | impl_struct_checked!($ty, i64, => $($field)+); 49 | }; 50 | } 51 | 52 | #[cfg(feature = "checked_fns")] 53 | impl_legacy_checked! {Rgba => r g b a} 54 | #[cfg(feature = "checked_fns")] 55 | impl_legacy_checked! {Abgr => a b g r} 56 | #[cfg(feature = "checked_fns")] 57 | impl_legacy_checked! {Argb => a r g b} 58 | #[cfg(feature = "checked_fns")] 59 | impl_legacy_checked! {Bgra => b g r a} 60 | 61 | #[cfg(feature = "checked_fns")] 62 | impl_legacy_checked! {Bgr => b g r} 63 | #[cfg(feature = "checked_fns")] 64 | impl_legacy_checked! {Rgb => r g b} 65 | #[cfg(feature = "checked_fns")] 66 | impl_legacy_checked! {Grb => r g b} 67 | 68 | #[cfg(feature = "checked_fns")] 69 | impl_legacy_checked! {Gray_v08 => 0} 70 | #[cfg(feature = "checked_fns")] 71 | impl_legacy_checked! {GrayAlpha_v08 => 0 1} 72 | 73 | #[cfg(test)] 74 | #[allow(deprecated)] 75 | mod test { 76 | use crate::*; 77 | use core::num::Wrapping; 78 | 79 | const WHITE_RGB: RGB = RGB::new(255, 255, 255); 80 | const BLACK_RGB: RGB = RGB::new(0, 0, 0); 81 | const RED_RGB: RGB = RGB::new(255, 0, 0); 82 | const GREEN_RGB: RGB = RGB::new(0, 255, 0); 83 | const BLUE_RGB: RGB = RGB::new(0, 0, 255); 84 | 85 | const WHITE_RGBA: RGBA = RGBA::new(255, 255, 255, 255); 86 | const BLACK_RGBA: RGBA = RGBA::new(0, 0, 0, 0); 87 | const RED_RGBA: RGBA = RGBA::new(255, 0, 0, 255); 88 | const GREEN_RGBA: RGBA = RGBA::new(0, 255, 0, 0); 89 | const BLUE_RGBA: RGBA = RGBA::new(0, 0, 255, 255); 90 | 91 | #[test] 92 | fn test_add() { 93 | use crate::*; 94 | 95 | assert_eq!(RGB::new(2,4,6), RGB::new(1,2,3) + RGB{r:1,g:2,b:3}); 96 | assert_eq!(RGB::new(2.,4.,6.), RGB::new(1.,3.,5.) + 1.); 97 | 98 | assert_eq!(RGBA::new_alpha(2f32,4.,6.,8u32), RGBA::new_alpha(1f32,2.,3.,4u32) + RGBA{r:1f32,g:2.0,b:3.0,a:4u32}); 99 | assert_eq!(RGBA::new(2i16,4,6,8), RGBA::new(1,3,5,7) + 1); 100 | 101 | assert_eq!(RGB::new(255, 255, 0), RED_RGB + GREEN_RGB); 102 | assert_eq!(RGB::new(255, 0, 0), RED_RGB + RGB::new(0, 0, 0)); 103 | assert_eq!(WHITE_RGB, BLACK_RGB + 255); 104 | 105 | assert_eq!(RGBA::new(255, 255, 0, 255), RED_RGBA + GREEN_RGBA); 106 | assert_eq!(RGBA::new(255, 0, 0, 255), RED_RGBA + RGBA::new(0, 0, 0, 0)); 107 | assert_eq!(WHITE_RGBA, BLACK_RGBA + 255); 108 | } 109 | 110 | #[test] 111 | #[cfg(feature = "checked_fns")] 112 | #[allow(deprecated)] 113 | fn test_checked_add() { 114 | assert_eq!(WHITE_RGB.checked_add(WHITE_RGB), None); 115 | assert_eq!(RGB::::new(255, 255, 255).checked_add(RGB::::new(255, 0, 0)), None); 116 | assert_eq!(RGB::::new(255, 255, 255).checked_add(RGB::::new(0, 255, 0)), None); 117 | assert_eq!(RGB::::new(255, 255, 255).checked_add(RGB::::new(0, 0, 255)), None); 118 | assert_eq!(WHITE_RGBA.checked_add(BLACK_RGBA), Some(WHITE_RGBA)); 119 | 120 | assert_eq!(RGB::::new(-128, 2, 3).checked_add(RGB::::new(-1, 0, 0)), None); 121 | assert_eq!(RGB::::new(2, -128, 3).checked_add(RGB::::new(0, -1, 0)), None); 122 | assert_eq!(RGB::::new(2, 2, -128).checked_add(RGB::::new(0, 0, -1)), None); 123 | assert_eq!(RGB::::new(2, 2, -128).checked_add(RGB::::new(0, 0, 1)), Some(RGB::::new(2, 2, -127))); 124 | } 125 | 126 | #[test] 127 | #[should_panic] 128 | #[cfg(debug_assertions)] 129 | fn test_add_overflow() { 130 | assert_ne!(RGBA::new(255u8, 255, 0, 0), RED_RGBA + BLUE_RGBA); 131 | } 132 | 133 | #[test] 134 | fn test_sub() { 135 | assert_eq!(RED_RGB, (WHITE_RGB - GREEN_RGB) - BLUE_RGB); 136 | assert_eq!(BLACK_RGB, WHITE_RGB - 255); 137 | 138 | assert_eq!(RGBA::new(255, 255, 0, 0), WHITE_RGBA - BLUE_RGBA); 139 | assert_eq!(BLACK_RGBA, WHITE_RGBA - 255); 140 | } 141 | 142 | #[test] 143 | #[cfg(feature = "checked_fns")] 144 | fn test_checked_sub() { 145 | assert_eq!(RGBA::::new(2,4,6,111).checked_sub(RGBA::::new(3,4,6,0)), None); 146 | assert_eq!(RGB::::new(2,4,6).checked_sub(RGB::::new(2,5,6)), None); 147 | assert_eq!(RGB::::new(2,4,6).checked_sub(RGB::::new(2,4,7)), None); 148 | assert_eq!(RGB::::new(2,4,6).checked_sub(RGB::::new(2,4,6)), Some(BLACK_RGB)); 149 | 150 | assert_eq!(RGB::::new(-128,4,6).checked_sub(RGB::::new(1,4,7)), None); 151 | assert_eq!(RGB::::new(2,-128,6).checked_sub(RGB::::new(2,1,7)), None); 152 | assert_eq!(RGB::::new(2,4,-128).checked_sub(RGB::::new(2,4,1)), None); 153 | assert_eq!(RGB::::new(2,4,6).checked_sub(RGB::::new(-2,4,6)), Some(RGB::::new(4,0,0))); 154 | } 155 | 156 | #[test] 157 | fn test_add_assign() { 158 | let mut green_rgb = RGB::new(0, 255, 0); 159 | green_rgb += RGB::new(255, 0, 255); 160 | assert_eq!(WHITE_RGB, green_rgb); 161 | 162 | let mut black_rgb = RGB::new(0, 0, 0); 163 | black_rgb += 255; 164 | assert_eq!(WHITE_RGB, black_rgb); 165 | 166 | let mut green_rgba = RGBA::new(0, 255, 0, 0); 167 | green_rgba += RGBA::new(255, 0, 255, 255); 168 | assert_eq!(WHITE_RGBA, green_rgba); 169 | 170 | let mut black_rgba = RGBA::new(0, 0, 0, 0); 171 | black_rgba += 255; 172 | assert_eq!(WHITE_RGBA, black_rgba); 173 | } 174 | 175 | #[test] 176 | fn test_sub_assign() { 177 | let mut green_rgb = RGB::new(0, 255, 0); 178 | green_rgb -= RGB::new(0, 255, 0); 179 | assert_eq!(BLACK_RGB, green_rgb); 180 | 181 | let mut white_rgb = RGB::new(255, 255, 255); 182 | white_rgb -= 255; 183 | assert_eq!(BLACK_RGB, white_rgb); 184 | 185 | let mut green_rgba = RGBA::new(0, 255, 0, 0); 186 | green_rgba -= RGBA::new(0, 255, 0, 0); 187 | assert_eq!(BLACK_RGBA, green_rgba); 188 | 189 | let mut white_rgba = RGBA::new(255, 255, 255, 255); 190 | white_rgba -= 255; 191 | assert_eq!(BLACK_RGBA, white_rgba); 192 | } 193 | 194 | #[test] 195 | fn test_mult() { 196 | assert_eq!(RGB::new(0.5,1.5,2.5), RGB::new(1.,3.,5.) * 0.5); 197 | assert_eq!(RGBA::new(2,4,6,8), RGBA::new(1,2,3,4) * 2); 198 | assert_eq!(RGB::new(0.5,1.5,2.5) * RGB::new(1.,3.,5.), 199 | RGB::new(0.5,4.5,12.5)); 200 | } 201 | 202 | #[test] 203 | fn test_mult_assign() { 204 | let mut green_rgb = RGB::new(0u16, 255, 0); 205 | green_rgb *= 1; 206 | assert_eq!(RGB::new(0, 255, 0), green_rgb); 207 | green_rgb *= 2; 208 | assert_eq!(RGB::new(0, 255*2, 0), green_rgb); 209 | 210 | let mut rgb = RGB::new(0.5,1.5,2.5); 211 | rgb *= RGB::new(1.,3.,5.); 212 | assert_eq!(rgb, RGB::new(0.5,4.5,12.5)); 213 | 214 | let mut green_rgba = RGBA::new(0u16, 255, 0, 0); 215 | green_rgba *= 1; 216 | assert_eq!(RGBA::new(0, 255, 0, 0), green_rgba); 217 | green_rgba *= 2; 218 | assert_eq!(RGBA::new(0, 255*2, 0, 0), green_rgba); 219 | } 220 | 221 | #[test] 222 | fn sum() { 223 | use crate::*; 224 | 225 | let s1 = [RGB::new(1u8,1,1), RGB::new(2,3,4)].iter().copied().sum::>(); 226 | let s2 = [RGB::new(1u16,1,1), RGB::new(2,3,4)].iter().copied().sum::>(); 227 | let s3 = [RGBA::new_alpha(1u16,1,1,Wrapping(1u16)), RGBA::new_alpha(2,3,4,Wrapping(5))].iter().copied().sum::>>(); 228 | let s4 = [RGBA::new_alpha(1u16,1,1,1u16), RGBA::new_alpha(2,3,4,5)].iter().copied().sum::>(); 229 | assert_eq!(s1, RGB::new(3, 4, 5)); 230 | assert_eq!(s2, RGB::new(3, 4, 5)); 231 | assert_eq!(s3, RGBA::new_alpha(3, 4, 5, Wrapping(6))); 232 | assert_eq!(s4, RGBA::new_alpha(3, 4, 5, 6)); 233 | } 234 | } 235 | -------------------------------------------------------------------------------- /src/legacy/internal/pixel.rs: -------------------------------------------------------------------------------- 1 | /// Casting the struct to slices of its components 2 | pub trait ComponentSlice { 3 | /// The components interpreted as an array, e.g. one `RGB` expands to 3 elements. 4 | /// 5 | /// It's implemented for individual pixels as well as slices of pixels. 6 | fn as_slice(&self) -> &[T]; 7 | 8 | /// The components interpreted as a mutable array, e.g. one `RGB` expands to 3 elements. 9 | /// 10 | /// It's implemented for individual pixels as well as slices of pixels. 11 | /// 12 | /// If you get an error when calling this on an array, add `[..]` 13 | /// 14 | /// > use of unstable library feature 'array_methods' 15 | /// 16 | /// ```rust,ignore 17 | /// arr[..].as_mut_slice() 18 | /// ``` 19 | fn as_mut_slice(&mut self) -> &mut [T]; 20 | } 21 | 22 | /// Casting a slice of `RGB/A` values to a slice of `u8` 23 | /// 24 | /// If instead of `RGB8` you use `RGB`, and you want to cast from/to that custom type, 25 | /// implement the `Plain` trait for it: 26 | /// 27 | /// ```rust 28 | /// # #[derive(Copy, Clone)] 29 | /// # struct MyCustomType; 30 | /// unsafe impl rgb::Pod for MyCustomType {} 31 | /// unsafe impl rgb::Zeroable for MyCustomType {} 32 | /// ``` 33 | /// 34 | /// Plain types are not allowed to contain struct padding, booleans, chars, enums, references or pointers. 35 | #[cfg(feature = "as-bytes")] 36 | pub trait ComponentBytes { 37 | /// The components interpreted as raw bytes, in machine's native endian. In `RGB` bytes of the red component are first. 38 | fn as_bytes(&self) -> &[u8]; 39 | 40 | /// The components interpreted as raw bytes, in machine's native endian. In `RGB` bytes of the red component are first. 41 | fn as_bytes_mut(&mut self) -> &mut [u8]; 42 | } 43 | 44 | /// Same as `Pixel::map`, but doesn't change the alpha channel (if there's any alpha). 45 | pub trait ColorComponentMap { 46 | /// Convenience function for applying the same formula to every rgb/gray component, but skipping the alpha component. 47 | /// 48 | /// Note that it returns the pixel directly, not an Iterator. 49 | fn map_c(&self, f: Callback) -> DestPixel 50 | where Callback: FnMut(SrcComponent) -> DestComponent; 51 | } 52 | 53 | #[test] 54 | #[allow(dead_code)] 55 | #[cfg(feature = "as-bytes")] 56 | fn shared_impl() { 57 | struct SharedPixelBuffer { 58 | data: [Pixel; 1], 59 | } 60 | 61 | impl SharedPixelBuffer 62 | where [Pixel]: crate::ComponentBytes 63 | { 64 | pub fn as_bytes(&self) -> &[u8] { 65 | self.data.as_slice().as_bytes() 66 | } 67 | } 68 | 69 | let b = SharedPixelBuffer { 70 | data: [crate::RGB8::new(0, 0, 0)], 71 | }; 72 | let _ = b.as_bytes(); 73 | } 74 | -------------------------------------------------------------------------------- /src/legacy/internal/rgb.rs: -------------------------------------------------------------------------------- 1 | use crate::alt::*; 2 | use crate::*; 3 | use super::pixel::{ColorComponentMap, ComponentSlice}; 4 | 5 | impl BGR { 6 | /// Convenience function for creating a new pixel 7 | /// Warning: The order of arguments is R,G,B 8 | #[deprecated(note = "This function has a misleading order of arguments. Use BGR{} literal instead")] 9 | #[inline(always)] 10 | pub const fn new(r: T, g: T, b: T) -> Self { 11 | Self { b, g, r } 12 | } 13 | } 14 | 15 | macro_rules! impl_rgb { 16 | ($RGB:ident) => { 17 | impl $RGB { 18 | /// Iterate over color components (R, G, and B) 19 | #[inline(always)] 20 | pub fn iter(&self) -> core::iter::Cloned> { 21 | self.as_slice().iter().cloned() 22 | } 23 | } 24 | 25 | impl ColorComponentMap<$RGB, T, B> for $RGB { 26 | #[inline(always)] 27 | fn map_c(&self, mut f: F) -> $RGB 28 | where 29 | F: FnMut(T) -> B, 30 | { 31 | $RGB { 32 | r: f(self.r), 33 | g: f(self.g), 34 | b: f(self.b), 35 | } 36 | } 37 | } 38 | 39 | impl ComponentSlice for $RGB { 40 | #[inline(always)] 41 | fn as_slice(&self) -> &[T] { 42 | unsafe { core::slice::from_raw_parts(self as *const Self as *const T, 3) } 43 | } 44 | 45 | #[inline(always)] 46 | fn as_mut_slice(&mut self) -> &mut [T] { 47 | unsafe { core::slice::from_raw_parts_mut(self as *mut Self as *mut T, 3) } 48 | } 49 | } 50 | 51 | impl ComponentSlice for [$RGB] { 52 | #[inline] 53 | fn as_slice(&self) -> &[T] { 54 | unsafe { core::slice::from_raw_parts(self.as_ptr() as *const _, self.len() * 3) } 55 | } 56 | 57 | #[inline] 58 | fn as_mut_slice(&mut self) -> &mut [T] { 59 | unsafe { 60 | core::slice::from_raw_parts_mut(self.as_mut_ptr() as *mut _, self.len() * 3) 61 | } 62 | } 63 | } 64 | 65 | #[cfg(feature = "as-bytes")] 66 | impl ComponentBytes for [$RGB] { 67 | fn as_bytes(&self) -> &[u8] { 68 | assert_ne!(0, core::mem::size_of::()); 69 | ::bytemuck::cast_slice(self) 70 | } 71 | 72 | fn as_bytes_mut(&mut self) -> &mut [u8] { 73 | assert_ne!(0, core::mem::size_of::()); 74 | ::bytemuck::cast_slice_mut(self) 75 | } 76 | } 77 | }; 78 | } 79 | 80 | macro_rules! impl_rgb_to_alpha { 81 | ($RGB:ident, $RGBA:ident) => { 82 | impl $RGB { 83 | /// Deprecated convenience function for converting to RGBA 84 | #[doc(hidden)] 85 | #[deprecated(note = "use .with_alpha(a) instead")] 86 | #[inline(always)] 87 | pub fn alpha(&self, a: T) -> $RGBA { 88 | $RGBA { 89 | r: self.r.clone(), 90 | g: self.g.clone(), 91 | b: self.b.clone(), 92 | a, 93 | } 94 | } 95 | 96 | /// Convenience function for converting to RGBA 97 | #[inline(always)] 98 | pub fn with_alpha(&self, a: T) -> $RGBA { 99 | $RGBA { 100 | r: self.r.clone(), 101 | g: self.g.clone(), 102 | b: self.b.clone(), 103 | a, 104 | } 105 | } 106 | 107 | /// Convenience function for converting to RGBA with alpha channel of a different type than type of the pixels 108 | #[inline(always)] 109 | pub fn new_alpha(&self, a: A) -> $RGBA { 110 | $RGBA { 111 | r: self.r.clone(), 112 | g: self.g.clone(), 113 | b: self.b.clone(), 114 | a, 115 | } 116 | } 117 | } 118 | }; 119 | } 120 | 121 | impl core::iter::FromIterator for Rgb { 122 | /// Takes exactly 3 elements from the iterator and creates a new instance. 123 | /// Panics if there are fewer elements in the iterator. 124 | #[inline(always)] 125 | fn from_iter>(into_iter: I) -> Self { 126 | let mut iter = into_iter.into_iter(); 127 | Self { 128 | r: iter.next().unwrap(), 129 | g: iter.next().unwrap(), 130 | b: iter.next().unwrap(), 131 | } 132 | } 133 | } 134 | 135 | impl_rgb! {Rgb} 136 | impl_rgb_to_alpha! {Rgb, Rgba} 137 | impl_rgb! {Bgr} 138 | impl_rgb_to_alpha! {Bgr, Bgra} 139 | impl_rgb! {Grb} 140 | 141 | #[cfg(test)] 142 | #[allow(deprecated)] 143 | mod rgb_test { 144 | use crate::alt::*; 145 | use crate::*; 146 | 147 | #[test] 148 | fn grb_test() { 149 | let grb = GRB { g: 1, r: 2, b: 3 }.map(|c| c * 2) + 1; 150 | let rgb: crate::RGB8 = grb.into(); 151 | assert_eq!(rgb, RGB::new(5, 3, 7)); 152 | } 153 | 154 | #[test] 155 | fn sanity_check() { 156 | let neg = RGB::new(1, 2, 3i32).map(|x| -x); 157 | assert_eq!(neg.r, -1); 158 | assert_eq!(neg.g, -2); 159 | assert_eq!(neg.b, -3); 160 | 161 | let mut px = RGB::new(3, 4, 5); 162 | px.as_mut_slice()[1] = 111; 163 | assert_eq!(111, px.g); 164 | 165 | assert_eq!( 166 | RGBA::new(250, 251, 252, 253), 167 | RGB::new(250, 251, 252).with_alpha(253) 168 | ); 169 | 170 | assert_eq!(RGB { r: 1u8, g: 2, b: 3 }, RGB::new(1u8, 2, 3)); 171 | assert!(RGB { r: 1u8, g: 1, b: 2 } < RGB::new(2, 1, 1)); 172 | 173 | let mut h = std::collections::HashSet::new(); 174 | h.insert(px); 175 | assert!(h.contains(&RGB::new(3, 111, 5))); 176 | assert!(!h.contains(&RGB::new(111, 5, 3))); 177 | 178 | #[cfg(feature = "as-bytes")] 179 | { 180 | use crate::ComponentBytes; 181 | let v = vec![RGB::new(1u8, 2, 3), RGB::new(4, 5, 6)]; 182 | assert_eq!(&[1, 2, 3, 4, 5, 6], v.as_bytes()); 183 | } 184 | 185 | assert_eq!(RGB::new(0u8, 0, 0), Default::default()); 186 | } 187 | 188 | #[test] 189 | #[allow(deprecated)] 190 | fn test_fmt() { 191 | let red_rgb = RGB::new(255u8, 1, 0); 192 | let red_bgr = BGR::new(255u8, 1, 0); 193 | assert_eq!("#FF0100", &format!("{:X}", red_rgb)); 194 | assert_eq!("#FF0100", &format!("{:X}", red_bgr)); 195 | assert_eq!("#ff0100", &format!("{:x}", red_rgb)); 196 | assert_eq!("#ff0100", &format!("{:x}", red_bgr)); 197 | 198 | assert_eq!("rgb(255,1,0)", &format!("{}", red_rgb)); 199 | assert_eq!("bgr(0,1,255)", &format!("{}", red_bgr)); 200 | } 201 | } 202 | -------------------------------------------------------------------------------- /src/legacy/internal/rgba.rs: -------------------------------------------------------------------------------- 1 | use crate::alt::*; 2 | use crate::*; 3 | use super::pixel::{ColorComponentMap, ComponentSlice}; 4 | 5 | impl Rgba { 6 | #[inline(always)] 7 | /// Convenience function for creating a new pixel 8 | /// The order of arguments is R,G,B,A 9 | pub const fn new_alpha(r: T, g: T, b: T, a: A) -> Self { 10 | Self { r, g, b, a } 11 | } 12 | } 13 | 14 | impl BGRA { 15 | #[inline(always)] 16 | /// Convenience function for creating a new pixel 17 | /// Warning: The order of arguments is R,G,B,A 18 | #[deprecated(note = "This function has a misleading order of arguments. Use BGRA{} literal instead")] 19 | pub const fn new(r: T, g: T, b: T, a: T) -> Self { 20 | Self { b, g, r, a } 21 | } 22 | } 23 | 24 | /// ```rust,compile_fail 25 | /// let r = rgb::BGRA::::zeroed(); 26 | /// ``` 27 | impl BGRA { 28 | #[inline(always)] 29 | /// Convenience function for creating a new pixel 30 | /// Warning: The order of arguments is R,G,B,A 31 | #[deprecated(note = "This function has a misleading order of arguments. Use BGRA{} literal instead")] 32 | pub const fn new_alpha(r: T, g: T, b: T, a: A) -> Self { 33 | Self { b, g, r, a } 34 | } 35 | } 36 | 37 | impl Argb { 38 | #[inline(always)] 39 | /// Convenience function for creating a new pixel 40 | /// The order of arguments is R,G,B,A 41 | #[deprecated(note = "This function has a misleading order of arguments. Use ARGB{} literal instead")] 42 | pub const fn new(r: T, g: T, b: T, a: T) -> Self { 43 | Self { a, r, g, b } 44 | } 45 | } 46 | 47 | impl Argb { 48 | #[inline(always)] 49 | /// Convenience function for creating a new pixel 50 | /// The order of arguments is R,G,B,A 51 | #[deprecated(note = "This function has a misleading order of arguments. Use ARGB{} literal instead")] 52 | pub const fn new_alpha(r: T, g: T, b: T, a: A) -> Self { 53 | Self { a, r, g, b } 54 | } 55 | } 56 | 57 | impl Abgr { 58 | #[inline(always)] 59 | /// Convenience function for creating a new pixel 60 | /// The order of arguments is R,G,B,A 61 | #[deprecated(note = "This function has a misleading order of arguments. Use ABGR{} literal instead")] 62 | pub const fn new(r: T, g: T, b: T, a: T) -> Self { 63 | Self { a, b, g, r } 64 | } 65 | } 66 | 67 | impl Abgr { 68 | #[inline(always)] 69 | /// Convenience function for creating a new pixel 70 | /// The order of arguments is R,G,B,A 71 | #[deprecated(note = "This function has a misleading order of arguments. Use ABGR{} literal instead")] 72 | pub const fn new_alpha(r: T, g: T, b: T, a: A) -> Self { 73 | Self { a, b, g, r } 74 | } 75 | } 76 | 77 | macro_rules! impl_rgba { 78 | ($RGBA:ident) => { 79 | impl $RGBA { 80 | /// Iterate over all components (length=4) 81 | #[inline(always)] 82 | pub fn iter(&self) -> core::iter::Cloned> { 83 | self.as_slice().iter().cloned() 84 | } 85 | } 86 | 87 | impl $RGBA { 88 | /// Copy RGB components out of the RGBA struct 89 | /// 90 | /// Note: you can use `.into()` to convert between other types 91 | #[inline(always)] 92 | pub fn bgr(&self) -> Bgr { 93 | BGR { 94 | r: self.r.clone(), 95 | g: self.g.clone(), 96 | b: self.b.clone(), 97 | } 98 | } 99 | } 100 | 101 | impl $RGBA { 102 | /// Create new RGBA with the same alpha value, but different RGB values 103 | #[inline(always)] 104 | pub fn map_rgb(&self, mut f: F) -> $RGBA 105 | where F: FnMut(T) -> U, U: Clone, B: From + Clone 106 | { 107 | $RGBA { 108 | r: f(self.r), 109 | g: f(self.g), 110 | b: f(self.b), 111 | a: self.a.clone().into(), 112 | } 113 | } 114 | 115 | /// Deprecated convenience function for converting to RGBA 116 | #[doc(hidden)] 117 | #[deprecated(note = "use .with_alpha(a) instead")] 118 | #[inline(always)] 119 | pub fn alpha(&self, a: A) -> Self { 120 | Self { r: self.r, g: self.g, b: self.b, a } 121 | } 122 | 123 | /// Create a new RGBA with the new alpha value, but same RGB values 124 | #[inline(always)] 125 | pub const fn with_alpha(&self, a: A) -> Self { 126 | Self { r: self.r, g: self.g, b: self.b, a } 127 | } 128 | 129 | /// Create a new RGBA with a new alpha value created by the callback. 130 | /// Allows changing of the type used for the alpha channel. 131 | #[inline] 132 | pub fn map_alpha(&self, f: F) -> $RGBA 133 | where F: FnOnce(A) -> B { 134 | $RGBA { 135 | r: self.r, 136 | g: self.g, 137 | b: self.b, 138 | a: f(self.a.clone()), 139 | } 140 | } 141 | } 142 | 143 | impl ColorComponentMap<$RGBA, T, B> for $RGBA { 144 | #[inline(always)] 145 | fn map_c(&self, mut f: F) -> $RGBA 146 | where F: FnMut(T) -> B { 147 | $RGBA { 148 | r: f(self.r), 149 | g: f(self.g), 150 | b: f(self.b), 151 | a: self.a, 152 | } 153 | } 154 | } 155 | 156 | impl ComponentSlice for $RGBA { 157 | #[inline(always)] 158 | fn as_slice(&self) -> &[T] { 159 | unsafe { 160 | core::slice::from_raw_parts(self as *const Self as *const T, 4) 161 | } 162 | } 163 | 164 | #[inline(always)] 165 | fn as_mut_slice(&mut self) -> &mut [T] { 166 | unsafe { 167 | core::slice::from_raw_parts_mut(self as *mut Self as *mut T, 4) 168 | } 169 | } 170 | } 171 | 172 | impl ComponentSlice for [$RGBA] { 173 | #[inline] 174 | fn as_slice(&self) -> &[T] { 175 | unsafe { 176 | core::slice::from_raw_parts(self.as_ptr() as *const _, self.len() * 4) 177 | } 178 | } 179 | 180 | #[inline] 181 | fn as_mut_slice(&mut self) -> &mut [T] { 182 | unsafe { 183 | core::slice::from_raw_parts_mut(self.as_mut_ptr() as *mut _, self.len() * 4) 184 | } 185 | } 186 | } 187 | 188 | #[cfg(feature = "as-bytes")] 189 | impl ComponentBytes for [$RGBA] { 190 | fn as_bytes(&self) -> &[u8] { 191 | assert_ne!(0, core::mem::size_of::()); 192 | ::bytemuck::cast_slice(self) 193 | } 194 | 195 | fn as_bytes_mut(&mut self) -> &mut [u8] { 196 | assert_ne!(0, core::mem::size_of::()); 197 | ::bytemuck::cast_slice_mut(self) 198 | } 199 | } 200 | }; 201 | } 202 | 203 | macro_rules! impl_alpha_conv { 204 | ($RGB:ident, $RGBA:ident) => { 205 | /// Assumes 255 is opaque 206 | impl From<$RGB> for $RGBA { 207 | #[inline(always)] 208 | fn from(other: $RGB) -> Self { 209 | Self { 210 | r: other.r, 211 | g: other.g, 212 | b: other.b, 213 | a: 0xFF, 214 | } 215 | } 216 | } 217 | 218 | /// Assumes 65535 is opaque 219 | impl From<$RGB> for $RGBA { 220 | #[inline(always)] 221 | fn from(other: $RGB) -> Self { 222 | Self { 223 | r: other.r, 224 | g: other.g, 225 | b: other.b, 226 | a: 0xFFFF, 227 | } 228 | } 229 | } 230 | }; 231 | } 232 | 233 | impl Rgba { 234 | /// Provide a mutable view of only RGB components (leaving out alpha). 235 | /// Useful to change color without changing opacity. 236 | #[inline(always)] 237 | pub fn rgb_mut(&mut self) -> &mut Rgb { 238 | unsafe { &mut *(self as *mut Self).cast::>() } 239 | } 240 | } 241 | 242 | impl BGRA { 243 | /// Provide a mutable view of only RGB components (leaving out alpha). 244 | /// Useful to change color without changing opacity. 245 | #[inline(always)] 246 | #[deprecated(note = "This function will change. Use bgr_mut()")] 247 | pub fn rgb_mut(&mut self) -> &mut Bgr { 248 | unsafe { &mut *(self as *mut Self).cast::>() } 249 | } 250 | 251 | /// Provide a mutable view of only RGB components (leaving out alpha). 252 | /// Useful to change color without changing opacity. 253 | #[inline(always)] 254 | pub fn bgr_mut(&mut self) -> &mut Bgr { 255 | unsafe { &mut *(self as *mut Self).cast::>() } 256 | } 257 | } 258 | 259 | impl core::iter::FromIterator for Rgba { 260 | #[inline(always)] 261 | /// Takes exactly 4 elements from the iterator and creates a new instance. 262 | /// Panics if there are fewer elements in the iterator. 263 | fn from_iter>(into_iter: I) -> Self { 264 | let mut iter = into_iter.into_iter(); 265 | Self { 266 | r: iter.next().unwrap(), 267 | g: iter.next().unwrap(), 268 | b: iter.next().unwrap(), 269 | a: iter.next().unwrap(), 270 | } 271 | } 272 | } 273 | 274 | impl Rgba { 275 | /// Copy RGB components out of the RGBA struct 276 | /// 277 | /// Note: you can use `.into()` to convert between other types 278 | #[inline(always)] 279 | pub fn rgb(&self) -> Rgb { 280 | Rgb { 281 | r: self.r.clone(), 282 | g: self.g.clone(), 283 | b: self.b.clone(), 284 | } 285 | } 286 | } 287 | 288 | impl Argb { 289 | /// Copy RGB components out of the ARGB struct 290 | /// 291 | /// Note: you can use `.into()` to convert between other types 292 | #[inline(always)] 293 | pub fn rgb(&self) -> Rgb { 294 | Rgb { 295 | r: self.r.clone(), 296 | g: self.g.clone(), 297 | b: self.b.clone(), 298 | } 299 | } 300 | } 301 | 302 | impl BGRA { 303 | /// Copy RGB components out of the RGBA struct 304 | /// 305 | /// Note: you can use `.into()` to convert between other types 306 | #[inline(always)] 307 | #[deprecated(note = "This function will change. Use bgr()")] 308 | pub fn rgb(&self) -> Bgr { 309 | BGR { 310 | r: self.r.clone(), 311 | g: self.g.clone(), 312 | b: self.b.clone(), 313 | } 314 | } 315 | } 316 | 317 | impl_rgba! {Rgba} 318 | impl_rgba! {Bgra} 319 | impl_rgba! {Argb} 320 | impl_rgba! {Abgr} 321 | 322 | impl_alpha_conv! {Bgr, Bgra} 323 | impl_alpha_conv! {Rgb, Bgra} 324 | impl_alpha_conv! {Bgr, Rgba} 325 | impl_alpha_conv! {Rgb, Rgba} 326 | impl_alpha_conv! {Bgr, Abgr} 327 | impl_alpha_conv! {Rgb, Abgr} 328 | impl_alpha_conv! {Bgr, Argb} 329 | impl_alpha_conv! {Rgb, Argb} 330 | 331 | #[test] 332 | #[allow(deprecated)] 333 | fn rgba_test() { 334 | use crate::Pixel; 335 | 336 | let neg = Rgba::new(1,2,3i32,1000).map(|x| -x); 337 | assert_eq!(neg.r, -1); 338 | assert_eq!(neg.rgb().r, -1); 339 | assert_eq!(neg.g, -2); 340 | assert_eq!(neg.rgb().g, -2); 341 | assert_eq!(neg.b, -3); 342 | assert_eq!(neg.rgb().b, -3); 343 | assert_eq!(neg.a, -1000); 344 | assert_eq!(neg.map_alpha(|x| x+1).a, -999); 345 | assert_eq!(neg, neg.as_slice().iter().copied().collect()); 346 | assert!(neg < Rgba::new(0,0,0,0)); 347 | 348 | let neg = Rgba::new(1u8,2,3,4).map_rgb(|c| -i16::from(c)); 349 | assert_eq!(-1i16, neg.r); 350 | assert_eq!(4i16, neg.a); 351 | let neg = Rgba::new(1u8,2,3,4).map_c(|c| -i16::from(c)); 352 | assert_eq!(-1i16, neg.r); 353 | assert_eq!(4u8, neg.a); 354 | 355 | let mut px = Rgba{r:1,g:2,b:3,a:4}; 356 | px.as_mut_slice()[3] = 100; 357 | assert_eq!(1, px.rgb_mut().r); 358 | assert_eq!(2, px.rgb_mut().g); 359 | px.rgb_mut().b = 4; 360 | assert_eq!(4, px.rgb_mut().b); 361 | assert_eq!(100, px.a); 362 | 363 | #[cfg(feature = "as-bytes")] 364 | { 365 | let v = [Rgba::new(1u8,2,3,4), Rgba::new(5,6,7,8)]; 366 | assert_eq!(&[1,2,3,4,5,6,7,8], v.as_bytes()); 367 | } 368 | } 369 | 370 | #[test] 371 | #[cfg(feature = "as-bytes")] 372 | fn abgr_test() { 373 | let abgr = ABGR {r:1,g:2,b:3,a:4}; 374 | assert_eq!(4, abgr.as_slice()[0]); 375 | use crate::AsPixels; 376 | assert_eq!(abgr, [abgr].as_bytes().as_pixels()[0]); 377 | } 378 | 379 | #[test] 380 | #[allow(deprecated)] 381 | fn bgra_test() { 382 | use crate::ComponentMap; 383 | 384 | let neg = BGRA::new(1, 2, 3i32, 1000).map(|x| -x); 385 | let _ = neg.as_slice(); 386 | 387 | #[cfg(feature = "as-bytes")] 388 | { 389 | let _ = [neg].as_bytes(); 390 | } 391 | assert_eq!(neg.r, -1); 392 | assert_eq!(neg.bgr().r, -1); 393 | assert_eq!(neg.g, -2); 394 | assert_eq!(neg.bgr().g, -2); 395 | assert_eq!(neg.b, -3); 396 | assert_eq!(neg.bgr().b, -3); 397 | assert_eq!(neg.a, -1000); 398 | assert_eq!(&[-3, -2, -1, -1000], neg.as_slice()); 399 | assert!(neg < Bgra::new(0, 0, 0, 0)); 400 | 401 | let neg = Bgra::new(1u8, 2u8, 3u8, 4u8).map_rgb(|c| -i16::from(c)); 402 | assert_eq!(-1i16, neg.r); 403 | assert_eq!(4i16, neg.a); 404 | let neg = Bgra::new(1u8, 2u8, 3u8, 4u8).map_c(|c| -i16::from(c)); 405 | assert_eq!(-1i16, neg.r); 406 | assert_eq!(4u8, neg.a); 407 | 408 | let mut px = Bgra{r:1,g:2,b:3,a:-9}.with_alpha(4); 409 | px.as_mut_slice()[3] = 100; 410 | assert_eq!(1, px.bgr_mut().r); 411 | assert_eq!(2, px.bgr_mut().g); 412 | px.bgr_mut().b = 4; 413 | assert_eq!(4, px.bgr_mut().b); 414 | assert_eq!(100, px.a); 415 | 416 | #[cfg(feature = "as-bytes")] 417 | { 418 | use crate::ComponentBytes; 419 | let v = vec![BGRA::new(3u8, 2, 1, 4), BGRA::new(7, 6, 5, 8)]; 420 | assert_eq!(&[1, 2, 3, 4, 5, 6, 7, 8], v.as_bytes()); 421 | } 422 | } 423 | -------------------------------------------------------------------------------- /src/legacy/mod.rs: -------------------------------------------------------------------------------- 1 | pub(crate) mod internal { 2 | pub mod convert; 3 | pub mod ops; 4 | pub mod pixel; 5 | pub mod rgb; 6 | pub mod rgba; 7 | } 8 | 9 | /// For backwards-compatibility only. This is where BGR/BGRA alernative layouts & grayscale used to be. 10 | /// 11 | /// BGR might be useful for some Windows or OpenGL APIs. 12 | pub mod alt; 13 | 14 | #[doc(hidden)] 15 | #[deprecated(note = "Renamed to `Rgb`")] 16 | /// Renamed to `Rgb` 17 | pub type RGB = crate::Rgb; 18 | #[doc(hidden)] 19 | #[deprecated(note = "Renamed to `Rgba`")] 20 | /// Renamed to `Rgba` 21 | pub type RGBA = crate::Rgba; 22 | 23 | #[test] 24 | #[allow(deprecated)] 25 | fn rgb_works() { 26 | use crate::*; 27 | 28 | let rgb = Rgb{r:0u8,g:128,b:255}.clone(); 29 | assert_eq!(rgb.b, 255); 30 | 31 | assert_eq!(rgb, rgb.iter().map(|ch| ch).collect()); 32 | 33 | #[cfg(feature = "as-bytes")] 34 | { 35 | assert_eq!(0, [rgb].as_bytes()[0]); 36 | assert_eq!(128, [rgb].as_bytes()[1]); 37 | assert_eq!(255, [rgb].as_bytes()[2]); 38 | } 39 | 40 | let rgb = RGB16{r:0u16,g:0x7F7F,b:65535}; 41 | assert_eq!(rgb.b, 65535); 42 | assert_eq!(rgb.as_slice()[1], 0x7F7F); 43 | 44 | #[cfg(feature = "as-bytes")] 45 | { 46 | assert_eq!(0, [rgb].as_bytes()[0]); 47 | assert_eq!(0, [rgb].as_bytes()[1]); 48 | assert_eq!(0x7F, [rgb].as_bytes()[2]); 49 | assert_eq!(0x7F, [rgb].as_bytes()[3]); 50 | assert_eq!(0xFF, [rgb].as_bytes()[4]); 51 | assert_eq!(0xFF, [rgb].as_bytes()[5]); 52 | } 53 | 54 | assert_eq!("rgb(1,2,3)", format!("{}", RGB::new(1, 2, 3))); 55 | } 56 | 57 | #[test] 58 | #[allow(deprecated)] 59 | fn sub_floats() { 60 | 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.}); 61 | } 62 | 63 | #[test] 64 | #[allow(deprecated)] 65 | fn into() { 66 | let a: crate::RGB8 = crate::Rgb { r: 0, g: 1, b: 2 }; 67 | let b: RGB = a.into(); 68 | let c: RGB = b.into(); 69 | let d: RGB = a.into(); 70 | assert_eq!(c, d); 71 | } 72 | 73 | #[test] 74 | #[allow(deprecated)] 75 | fn rgba_works() { 76 | let rgba = RGBA{r:0u8,g:128,b:255,a:33}.clone(); 77 | assert_eq!(rgba.b, 255); 78 | assert_eq!(rgba.a, 33); 79 | 80 | assert_eq!(rgba, rgba.iter().map(|ch| ch).collect()); 81 | 82 | assert_eq!("rgba(1,2,3,4)", format!("{}", RGBA::new(1, 2, 3, 4))); 83 | 84 | assert_eq!(rgba - rgba, RGBA::new(0, 0, 0, 0)); 85 | } 86 | 87 | #[test] 88 | #[allow(deprecated)] 89 | fn bytes() { 90 | use crate::*; 91 | 92 | let rgb = RGB8::new(1,2,3); 93 | 94 | #[cfg(feature = "as-bytes")] 95 | { 96 | let rgb_arr = [rgb]; 97 | let rgb_bytes = rgb_arr.as_bytes(); 98 | assert_eq!(&[1,2,3], rgb_bytes); 99 | assert_eq!(rgb_bytes.as_rgba().len(), 0); 100 | assert_eq!({let t: &[RGBA8] = rgb_bytes.as_pixels(); t}.len(), 0); 101 | assert_eq!(rgb, rgb_bytes.into_iter().cloned().collect()); 102 | assert_eq!(&[rgb], rgb_bytes.as_rgb()); 103 | assert_eq!(&[rgb], rgb_bytes.as_pixels()); 104 | } 105 | let mut rgb2 = [rgb]; 106 | assert_eq!(rgb2[..].as_mut_slice().as_rgb_mut(), &mut [rgb]); 107 | assert_eq!(&mut [rgb], rgb2[..].as_mut_slice().as_pixels_mut()); 108 | 109 | 110 | #[cfg(feature = "as-bytes")] 111 | { 112 | let rgba = RGBA8::new(1,2,3,4); 113 | let mut rgba_arr = [rgba]; 114 | let rgba_bytes = rgba_arr.as_bytes_mut(); 115 | assert_eq!(&[1,2,3,4], rgba_bytes); 116 | assert_eq!(&[rgba], rgba_bytes.as_rgba()); 117 | rgba_bytes[3] = 99; 118 | assert_eq!(RGBA8::new(1,2,3,99), rgba_arr.as_bytes().iter().copied().collect()); 119 | } 120 | 121 | let rgb = RGB16::new(1,2,3); 122 | let rgb_slice = rgb.as_slice(); 123 | assert_eq!(&[1,2,3], rgb_slice); 124 | assert_eq!(rgb_slice.as_rgba(), &[]); 125 | assert_eq!(&[rgb], rgb_slice.as_rgb()); 126 | assert_eq!(rgb, rgb_slice.into_iter().cloned().collect()); 127 | 128 | let rgba = RGBA16::new(1,2,3,4); 129 | let rgba_slice = rgba.as_slice(); 130 | assert_eq!(&[1,2,3,4], rgba_slice); 131 | assert_eq!(&[1,2,3], rgba_slice.as_rgb()[0].as_slice()); 132 | assert_eq!(&[rgba], rgba_slice.as_rgba()); 133 | assert_eq!(rgba, rgba_slice.iter().copied().collect()); 134 | let mut rgba2 = [rgba]; 135 | assert_eq!(rgba2[..].as_mut_slice().as_rgba_mut(), &mut [rgba]); 136 | 137 | let mut foo = vec![0u8; 8]; 138 | foo.as_rgba_mut()[1] = RGBA::new(1,2,3,4); 139 | assert_eq!(&[0u8,0,0,0,1,2,3,4], &foo[..]); 140 | } 141 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #![doc = include_str!("../README.md")] 2 | #![doc(html_logo_url = "https://kornel.ski/rgb-logo.png")] 3 | #![warn(missing_docs)] 4 | #![cfg_attr(docsrs, feature(doc_auto_cfg))] 5 | #![no_std] 6 | 7 | #[cfg(test)] 8 | #[macro_use] 9 | extern crate std; 10 | 11 | mod formats { 12 | pub mod abgr; 13 | pub mod argb; 14 | pub mod bgr; 15 | pub mod bgra; 16 | pub mod gray; 17 | pub mod gray_a; 18 | pub mod gray_alpha; 19 | pub mod gray_a44; 20 | pub mod grb; 21 | pub mod rgb; 22 | pub mod rgba; 23 | pub mod rgbw; 24 | } 25 | mod core_traits; 26 | mod from; 27 | mod inherent_impls; 28 | mod tuples; 29 | mod pixel_traits { 30 | pub mod arraylike; 31 | pub mod gain_alpha; 32 | pub mod has_alpha; 33 | pub mod het_pixel; 34 | pub mod pixel; 35 | } 36 | 37 | /// Re-export of the [`bytemuck` crate](https://lib.rs/bytemuck). 38 | /// 39 | /// Use [`::bytemuck::cast_slice()`] or [`::bytemuck::from_bytes()`] to convert 40 | /// pixels to/from `&[u8]`. 41 | #[cfg(feature = "bytemuck")] 42 | #[doc(alias = "ComponentSlice")] 43 | #[doc(alias = "as_bytes")] 44 | #[doc(alias = "Pod")] 45 | #[doc(inline)] 46 | pub use ::bytemuck; 47 | 48 | #[cfg(feature = "bytemuck")] 49 | mod bytemuck_impl; 50 | 51 | mod legacy; 52 | #[cfg(feature = "bytemuck")] 53 | pub use ::bytemuck::{Pod, Zeroable}; 54 | pub use legacy::internal::convert::{AsPixels, FromSlice}; 55 | #[cfg(feature = "as-bytes")] 56 | pub use legacy::internal::pixel::ComponentBytes; 57 | pub use legacy::internal::pixel::{ColorComponentMap, ComponentSlice}; 58 | pub use legacy::*; 59 | pub use pixel_traits::pixel::Pixel as ComponentMap; 60 | 61 | /// If the `num-traits` feature is enabled, the implemented traits are in this module 62 | #[cfg(feature = "num-traits")] 63 | pub mod num_traits; 64 | 65 | pub use formats::abgr::Abgr; 66 | pub use formats::argb::Argb; 67 | pub use formats::bgr::Bgr; 68 | pub use formats::bgra::Bgra; 69 | pub use formats::gray::Gray_v08 as Gray; 70 | pub use formats::gray::Gray_v09; 71 | pub use formats::gray_a::GrayA; 72 | pub use formats::gray_alpha::GrayAlpha_v08 as GrayAlpha; 73 | pub use formats::gray_a44::GrayA44; 74 | pub use formats::grb::Grb; 75 | pub use formats::rgb::Rgb; 76 | pub use formats::rgba::Rgba; 77 | pub use formats::rgbw::Rgbw; 78 | 79 | pub use pixel_traits::{ 80 | arraylike::ArrayLike, gain_alpha::GainAlpha, has_alpha::HasAlpha, het_pixel::HetPixel, 81 | pixel::Pixel, 82 | }; 83 | /// A module of re-exports of all the traits provided by this crate 84 | /// for use with glob imports instead of importing relevant pixel 85 | /// traits individually. 86 | /// 87 | /// ``` 88 | /// use rgb::Rgb; 89 | /// use rgb::prelude::*; 90 | /// 91 | /// let pixel = Rgb::try_from_components([0, 0, 0]).unwrap(); 92 | /// ``` 93 | pub mod prelude { 94 | pub use crate::ArrayLike; 95 | pub use crate::GainAlpha; 96 | pub use crate::HasAlpha; 97 | pub use crate::HetPixel; 98 | pub use crate::Pixel; 99 | } 100 | 101 | /// `TryFrom` errors 102 | pub mod error { 103 | pub use crate::pixel_traits::het_pixel::TryFromColorsAlphaError; 104 | pub use crate::pixel_traits::pixel::TryFromComponentsError; 105 | pub use crate::formats::gray_a44::OutOfRangeError; 106 | } 107 | 108 | /// [`Abgr`] 109 | pub type ABGR8 = formats::abgr::Abgr; 110 | /// [`Argb`] 111 | pub type ARGB8 = formats::argb::Argb; 112 | /// [`Bgr`] 113 | pub type BGR8 = formats::bgr::Bgr; 114 | /// [`Bgra`] 115 | pub type BGRA8 = formats::bgra::Bgra; 116 | /// [`Gray`] 117 | pub type GRAY8 = formats::gray::Gray_v09; 118 | /// 4 bit for gray and 4 bit for alpha 119 | pub type GRAYA4 = formats::gray_a44::GrayA44; 120 | /// [`GrayA`] 121 | pub type GRAYA8 = formats::gray_a::GrayA; 122 | /// [`Grb`] 123 | pub type GRB8 = formats::grb::Grb; 124 | /// [`Rgb`] 8-bit RGB 125 | /// 126 | /// The colorspace is technically undefined, but generally sRGB is assumed. 127 | pub type RGB8 = formats::rgb::Rgb; 128 | /// [`Rgba`] 8-bit RGBA, alpha is last. 0 = transparent, 255 = opaque. 129 | pub type RGBA8 = formats::rgba::Rgba; 130 | /// [`Rgbw`] 131 | pub type RGBW8 = formats::rgbw::Rgbw; 132 | 133 | /// [`Abgr`] 134 | pub type ABGR16 = formats::abgr::Abgr; 135 | /// [`Argb`] 136 | pub type ARGB16 = formats::argb::Argb; 137 | /// [`Bgr`] 138 | pub type BGR16 = formats::bgr::Bgr; 139 | /// [`Bgra`] 140 | pub type BGRA16 = formats::bgra::Bgra; 141 | /// [`Gray`] 142 | pub type GRAY16 = formats::gray::Gray_v09; 143 | /// [`GrayA`] 144 | pub type GRAYA16 = formats::gray_a::GrayA; 145 | /// [`Grb`] 146 | pub type GRB16 = formats::grb::Grb; 147 | /// [`Rgb`] 16-bit RGB in machine's native endian 148 | /// 149 | /// Be careful to perform byte-swapping when reading from files. 150 | pub type RGB16 = formats::rgb::Rgb; 151 | /// [`Rgba`] 16-bit RGB in machine's native endian. 0 = transparent, 65535 = opaque. 152 | /// 153 | /// Alpha is last. 154 | pub type RGBA16 = formats::rgba::Rgba; 155 | /// [`Rgbw`] 156 | pub type RGBW16 = formats::rgbw::Rgbw; 157 | 158 | /// [`Rgba`] 159 | pub type RGBA32F = formats::rgba::Rgba; 160 | -------------------------------------------------------------------------------- /src/num_traits.rs: -------------------------------------------------------------------------------- 1 | use crate::{Abgr, Argb, Bgr, Bgra, GrayA, Gray_v09, Grb, Rgb, Rgba, Rgbw}; 2 | 3 | /// Re-exports from [the `num-traits` crate](https://lib.rs/crates/num-traits). 4 | pub use num_traits::ops::checked::{CheckedAdd, CheckedDiv, CheckedMul, CheckedSub}; 5 | pub use num_traits::ops::saturating::{SaturatingAdd, SaturatingMul, SaturatingSub}; 6 | 7 | macro_rules! num_traits_without_alpha { 8 | ($name:ident, [$($bit:tt),*]) => { 9 | impl CheckedAdd for $name { 10 | #[inline(always)] 11 | fn checked_add(&self, other: &Self) -> Option { 12 | Some(Self { 13 | $( 14 | $bit: self.$bit.checked_add(&other.$bit)?, 15 | )+ 16 | }) 17 | } 18 | } 19 | 20 | impl CheckedSub for $name { 21 | #[inline(always)] 22 | fn checked_sub(&self, other: &Self) -> Option { 23 | Some(Self { 24 | $( 25 | $bit: self.$bit.checked_sub(&other.$bit)?, 26 | )+ 27 | }) 28 | } 29 | } 30 | 31 | impl CheckedMul for $name { 32 | #[inline(always)] 33 | fn checked_mul(&self, other: &Self) -> Option { 34 | Some(Self { 35 | $( 36 | $bit: self.$bit.checked_mul(&other.$bit)?, 37 | )+ 38 | }) 39 | } 40 | } 41 | 42 | impl CheckedDiv for $name { 43 | #[inline(always)] 44 | fn checked_div(&self, other: &Self) -> Option { 45 | Some(Self { 46 | $( 47 | $bit: self.$bit.checked_div(&other.$bit)?, 48 | )+ 49 | }) 50 | } 51 | } 52 | 53 | impl SaturatingAdd for $name { 54 | #[inline(always)] 55 | fn saturating_add(&self, other: &Self) -> Self { 56 | Self { 57 | $( 58 | $bit: self.$bit.saturating_add(&other.$bit), 59 | )+ 60 | } 61 | } 62 | } 63 | 64 | impl SaturatingSub for $name { 65 | #[inline(always)] 66 | fn saturating_sub(&self, other: &Self) -> Self { 67 | Self { 68 | $( 69 | $bit: self.$bit.saturating_sub(&other.$bit), 70 | )+ 71 | } 72 | } 73 | } 74 | 75 | impl SaturatingMul for $name { 76 | #[inline(always)] 77 | fn saturating_mul(&self, other: &Self) -> Self { 78 | Self { 79 | $( 80 | $bit: self.$bit.saturating_mul(&other.$bit), 81 | )+ 82 | } 83 | } 84 | } 85 | }; 86 | } 87 | 88 | macro_rules! num_traits_with_alpha { 89 | ($name:ident, [$($bit:tt),*]) => { 90 | impl CheckedSub for $name { 91 | #[inline(always)] 92 | fn checked_sub(&self, other: &Self) -> Option { 93 | Some(Self { 94 | $( 95 | $bit: self.$bit.checked_sub(&other.$bit)?, 96 | )+ 97 | }) 98 | } 99 | } 100 | 101 | impl CheckedMul for $name { 102 | #[inline(always)] 103 | fn checked_mul(&self, other: &Self) -> Option { 104 | Some(Self { 105 | $( 106 | $bit: self.$bit.checked_mul(&other.$bit)?, 107 | )+ 108 | }) 109 | } 110 | } 111 | 112 | impl CheckedDiv for $name { 113 | #[inline(always)] 114 | fn checked_div(&self, other: &Self) -> Option { 115 | Some(Self { 116 | $( 117 | $bit: self.$bit.checked_div(&other.$bit)?, 118 | )+ 119 | }) 120 | } 121 | } 122 | 123 | impl SaturatingAdd for $name { 124 | #[inline(always)] 125 | fn saturating_add(&self, other: &Self) -> Self { 126 | Self { 127 | $( 128 | $bit: self.$bit.saturating_add(&other.$bit), 129 | )+ 130 | } 131 | } 132 | } 133 | 134 | impl SaturatingSub for $name { 135 | #[inline(always)] 136 | fn saturating_sub(&self, other: &Self) -> Self { 137 | Self { 138 | $( 139 | $bit: self.$bit.saturating_sub(&other.$bit), 140 | )+ 141 | } 142 | } 143 | } 144 | 145 | impl SaturatingMul for $name { 146 | #[inline(always)] 147 | fn saturating_mul(&self, other: &Self) -> Self { 148 | Self { 149 | $( 150 | $bit: self.$bit.saturating_mul(&other.$bit), 151 | )+ 152 | } 153 | } 154 | } 155 | }; 156 | } 157 | 158 | num_traits_without_alpha!(Rgb, [r, g, b]); 159 | num_traits_without_alpha!(Bgr, [b, g, r]); 160 | num_traits_without_alpha!(Grb, [g, r, b]); 161 | num_traits_without_alpha!(Gray_v09, [v]); 162 | num_traits_without_alpha!(Rgbw, [r, g, b, w]); 163 | 164 | num_traits_with_alpha!(Rgba, [r, g, b, a]); 165 | num_traits_with_alpha!(Argb, [a, r, g, b]); 166 | num_traits_with_alpha!(Bgra, [b, g, r, a]); 167 | num_traits_with_alpha!(Abgr, [a, b, g, r]); 168 | num_traits_with_alpha!(GrayA, [v, a]); 169 | 170 | #[test] 171 | #[cfg(not(feature = "checked_fns"))] 172 | fn test_checked_sub() { 173 | assert_eq!(Rgba::::new(2,4,6,111).checked_sub(&Rgba::::new(3,4,6,0)), None); 174 | assert_eq!(Rgb::::new(2,4,6).checked_sub(&Rgb::::new(2,5,6)), None); 175 | assert_eq!(Rgb::::new(2,4,6).checked_sub(&Rgb::::new(2,4,7)), None); 176 | assert_eq!(Rgb::::new(2,4,6).checked_sub(&Rgb::::new(2,4,6)), Some([0,0,0].into())); 177 | 178 | assert_eq!(Rgb::::new(-128,4,6).checked_sub(&Rgb::::new(1,4,7)), None); 179 | assert_eq!(Rgb::::new(2,-128,6).checked_sub(&Rgb::::new(2,1,7)), None); 180 | assert_eq!(Rgb::::new(2,4,-128).checked_sub(&Rgb::::new(2,4,1)), None); 181 | assert_eq!(Rgb::::new(2,4,6).checked_sub(&Rgb::::new(-2,4,6)), Some(Rgb::::new(4,0,0))); 182 | } 183 | -------------------------------------------------------------------------------- /src/pixel_traits/arraylike.rs: -------------------------------------------------------------------------------- 1 | use core::borrow::{Borrow, BorrowMut}; 2 | use core::ops::{Index, IndexMut}; 3 | 4 | /// A trait used when returning arrays from the two pixel traits due to the lack of the const 5 | /// generic expressions feature on stable rust. 6 | /// 7 | /// See [`HetPixel::to_color_array()`](crate::HetPixel::to_color_array) as 8 | /// an example. 9 | pub trait ArrayLike: 10 | AsRef<[T]> 11 | + AsMut<[T]> 12 | + Index 13 | + IndexMut 14 | + Borrow<[T]> 15 | + BorrowMut<[T]> 16 | + IntoIterator 17 | { 18 | } 19 | impl ArrayLike for [T; N] {} 20 | -------------------------------------------------------------------------------- /src/pixel_traits/gain_alpha.rs: -------------------------------------------------------------------------------- 1 | use crate::HasAlpha; 2 | use crate::HetPixel; 3 | use crate::{Abgr, Argb, Bgr, Bgra, GrayA, Rgb, Rgba}; 4 | use crate::formats::gray::{Gray_v08, Gray_v09}; 5 | use crate::formats::gray_alpha::GrayAlpha_v08; 6 | 7 | /// A pixel which can gain an alpha component. 8 | /// 9 | /// It's implemented for every pixel type in the crate, including those which 10 | /// already have an alpha component. 11 | pub trait GainAlpha: HetPixel { 12 | /// The pixel type after gaining an alpha component. 13 | /// 14 | /// For example, for `Rgb`: `GainAlpha = Rgba`. 15 | type GainAlpha: HasAlpha; 16 | 17 | /// Returns the pixel type after gaining an alpha component. 18 | /// 19 | /// If an alpha is already contained then it remains at the same value. If 20 | /// no alpha component is already contained then it is set to the given 21 | /// `alpha` value. 22 | /// 23 | /// # Examples 24 | /// 25 | /// ``` 26 | /// use rgb::{Rgb, Rgba, GainAlpha}; 27 | /// 28 | /// let rgb = Rgb {r: 0_u8, g: 10, b: 100}; 29 | /// let rgba = Rgba {r: 0_u8, g: 10, b: 100, a: 50}; 30 | /// 31 | /// assert_eq!(rgb.with_default_alpha(0), Rgba {r: 0, g: 10, b: 100, a: 0}); 32 | /// assert_eq!(rgba.with_default_alpha(0), Rgba {r: 0, g: 10, b: 100, a: 50}); 33 | /// ``` 34 | #[doc(alias = "gain_alpha")] 35 | fn with_default_alpha(self, alpha: Self::AlphaComponent) -> Self::GainAlpha; 36 | 37 | /// Returns the pixel type after gaining an alpha component. 38 | /// 39 | /// The alpha value is set to the given `alpha` value regardless of whether 40 | /// the pixel already contained an alpha component. 41 | /// 42 | /// # Examples 43 | /// 44 | /// ``` 45 | /// use rgb::{Rgb, Rgba, GainAlpha}; 46 | /// 47 | /// let rgb = Rgb {r: 0_u8, g: 10, b: 100}; 48 | /// let rgba = Rgba {r: 0_u8, g: 10, b: 100, a: 50}; 49 | /// 50 | /// assert_eq!(rgb.with_alpha(0), Rgba {r: 0, g: 10, b: 100, a: 0}); 51 | /// assert_eq!(rgba.with_alpha(0), Rgba {r: 0, g: 10, b: 100, a: 0}); 52 | /// ``` 53 | #[doc(alias = "gain_alpha")] 54 | fn with_alpha(self, alpha: Self::AlphaComponent) -> Self::GainAlpha; 55 | } 56 | 57 | macro_rules! lower_upper { 58 | ($lower:ident, $upper:ident, {$($color_bit:tt),*}, $alpha_bit:tt) => { 59 | impl GainAlpha for $lower where T: Copy + 'static { 60 | type GainAlpha = $upper; 61 | 62 | #[inline] 63 | fn with_default_alpha(self, alpha: Self::AlphaComponent) -> Self::GainAlpha { 64 | $upper { 65 | $($color_bit: self.$color_bit),*, 66 | $alpha_bit: alpha, 67 | } 68 | } 69 | 70 | #[inline] 71 | fn with_alpha(self, alpha: Self::AlphaComponent) -> Self::GainAlpha { 72 | $upper { 73 | $($color_bit: self.$color_bit),*, 74 | $alpha_bit: alpha, 75 | } 76 | } 77 | } 78 | }; 79 | } 80 | 81 | macro_rules! gain_already_alpha { 82 | ($original:ident, $alpha_bit: tt) => { 83 | impl GainAlpha for $original where T: Copy + 'static { 84 | type GainAlpha = $original; 85 | 86 | #[inline] 87 | fn with_default_alpha(self, _: Self::AlphaComponent) -> Self::GainAlpha { 88 | self 89 | } 90 | 91 | #[inline] 92 | fn with_alpha(mut self, alpha: Self::AlphaComponent) -> Self::GainAlpha { 93 | self.$alpha_bit = alpha; 94 | self 95 | } 96 | } 97 | }; 98 | } 99 | 100 | gain_already_alpha!(Rgba, a); 101 | gain_already_alpha!(Argb, a); 102 | gain_already_alpha!(Bgra, a); 103 | gain_already_alpha!(Abgr, a); 104 | gain_already_alpha!(GrayA, a); 105 | gain_already_alpha!(GrayAlpha_v08, 1); 106 | 107 | lower_upper!(Rgb, Rgba, {r, g, b}, a); 108 | lower_upper!(Bgr, Bgra, {r, g, b}, a); 109 | lower_upper!(Gray_v08, GrayAlpha_v08, { 0 }, 1); 110 | lower_upper!(Gray_v09, GrayA, { v }, a); 111 | -------------------------------------------------------------------------------- /src/pixel_traits/has_alpha.rs: -------------------------------------------------------------------------------- 1 | use crate::HetPixel; 2 | use crate::{Abgr, Argb, Bgra, GrayA, Rgba}; 3 | 4 | /// A pixel which has an alpha component. 5 | /// 6 | /// This trait is implemented only for those types in the crate that 7 | /// contain an alpha component, such as [`Rgba`]. 8 | /// 9 | /// There are no trait methods for dropping of the alpha component, 10 | /// because doing that correctly requires alpha-blending of the 11 | /// color components with some background color. Otherwise, 12 | /// meaningless garbage values of the RGB channels of fully-transparent 13 | /// pixels may be uncovered. For example, removing the alpha channel 14 | /// from Rgba { r: 255, g: 0, b: 0, a: 100 } would result in `Rgb {r: 15 | /// 255, g: 0, b: 0}` which is very red when you might want to use a white 16 | /// background color blended with the original color which would end 17 | /// up being much lighter. 18 | pub trait HasAlpha: HetPixel { 19 | /// Returns a copy of the pixel's alpha component. 20 | /// 21 | /// Due to a naming conflict with several now-deprecated inherent 22 | /// functions with the same name (such as `Rgb::alpha()`) the 23 | /// `HasAlpha::alpha()` method requires fully qualified syntax for 24 | /// disambiguation. The deprecated functions are due to be removed in a 25 | /// future release which will solve this issue. 26 | /// 27 | /// # Examples 28 | /// ``` 29 | /// use rgb::{HasAlpha, Rgba}; 30 | /// 31 | /// let mut rgba = Rgba { r: 0_u8, g: 10, b: 100, a: 50 }; 32 | /// 33 | /// assert_eq!(HasAlpha::alpha(&rgba), 50); 34 | /// 35 | /// rgba.a = 0; 36 | /// 37 | /// assert_eq!(HasAlpha::alpha(&rgba), 0); 38 | /// ``` 39 | fn alpha(&self) -> Self::AlphaComponent; 40 | 41 | /// Returns a mutable reference of the pixel's alpha component. 42 | /// 43 | /// # Examples 44 | /// ``` 45 | /// use rgb::{HasAlpha, Rgba}; 46 | /// 47 | /// let mut rgba = Rgba { r: 0_u8, g: 10, b: 100, a: 50 }; 48 | /// 49 | /// let alpha = rgba.alpha_mut(); 50 | /// 51 | /// *alpha += 100; 52 | /// 53 | /// assert_eq!(HasAlpha::alpha(&rgba), 150); 54 | /// ``` 55 | fn alpha_mut(&mut self) -> &mut Self::AlphaComponent; 56 | } 57 | 58 | macro_rules! has_alpha { 59 | ($name:ident, $alpha_bit: tt) => { 60 | impl HasAlpha for $name where T: Copy + 'static, A: Copy + 'static { 61 | #[inline] 62 | fn alpha(&self) -> Self::AlphaComponent { 63 | self.$alpha_bit 64 | } 65 | 66 | #[inline] 67 | fn alpha_mut(&mut self) -> &mut Self::AlphaComponent { 68 | &mut self.$alpha_bit 69 | } 70 | } 71 | }; 72 | } 73 | 74 | has_alpha!(Rgba, a); 75 | has_alpha!(Argb, a); 76 | has_alpha!(Bgra, a); 77 | has_alpha!(Abgr, a); 78 | has_alpha!(GrayA, a); 79 | 80 | use crate::formats::gray_alpha::GrayAlpha_v08; 81 | has_alpha!(GrayAlpha_v08, 1); 82 | -------------------------------------------------------------------------------- /src/pixel_traits/het_pixel.rs: -------------------------------------------------------------------------------- 1 | use crate::{Abgr, Argb, ArrayLike, Bgr, Bgra, GrayA, Gray_v09, Grb, Rgb, Rgba, Rgbw}; 2 | use core::fmt::Display; 3 | 4 | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] 5 | /// Error returned from the [`HetPixel::try_from_colors_alpha()`] function. 6 | pub struct TryFromColorsAlphaError; 7 | impl Display for TryFromColorsAlphaError { 8 | #[cold] 9 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 10 | f.write_str("the colors iterator did not contain enough items to create this pixel") 11 | } 12 | } 13 | 14 | /// A Pixel made up of a compile-time known number of color components and optionally an 15 | /// alpha component. 16 | /// 17 | /// Unlike [`Pixel`](crate::Pixel) the alpha component does not have to be the same type as the color 18 | /// components. 19 | /// 20 | /// This trait is implemented on every pixel type in the crate. 21 | /// 22 | /// # Terminology 23 | /// 24 | /// Component = An element of a pixel, inclusive of alpha. For example, [`Rgba`](crate::Rgba) is a pixel made up 25 | /// of four components, three color components and one alpha component. 26 | pub trait HetPixel: Copy { 27 | /// The component type of the pixel used the color component(s). 28 | type ColorComponent: Copy + 'static; 29 | /// The component type of the pixel used the alpha component if any. 30 | type AlphaComponent: Copy + 'static; 31 | 32 | /// The total number of components in the pixel. 33 | /// 34 | /// If the pixel contains an alpha components then this number should be equal to the number of 35 | /// color components + 1. That is, you cannot have more than 1 alpha components, but you can 36 | /// have 0. 37 | /// 38 | /// For example, [`Rgb`] has `NUM_COMPONENTS` == 3 whereas 39 | /// [`Rgba`] has `NUM_COMPONENTS` == 4. 40 | const NUM_COMPONENTS: u8; 41 | 42 | /// The number of components in the pixel minus alpha. 43 | /// 44 | /// For example, [`Rgb`] has `NUM_COLOR_COMPONENTS` == 3 whereas 45 | /// [`Rgbw`] has `NUM_COLOR_COMPONENTS` == 4. 46 | const NUM_COLOR_COMPONENTS: u8; 47 | 48 | /// The same pixel type as `Self` but with a different component type `U`. 49 | /// 50 | /// This is used to allow the implementation of 51 | /// [`HetPixel::map_colors()`] and similar methods due to rust's 52 | /// current lack of higher kinded types. 53 | /// 54 | /// For example, [`Rgb`] has `SelfType = Rgb` whereas 55 | /// [`Rgba`] has `SelfType = Rgba`. 56 | type SelfType: 57 | HetPixel = Self>; 58 | 59 | /// A generic associated type used to return the array of color 60 | /// components despite rust's lack of const generic expressions. 61 | /// 62 | /// Used in functions like [`HetPixel::to_color_array()`]. 63 | /// 64 | /// For example, [`Rgb`] has `ColorArray = [U; 3]` and 65 | /// [`Rgba`] has `ColorArray = [U; 3]` also. 66 | type ColorArray: ArrayLike; 67 | 68 | /// Returns an owned array of copies of the pixel's color components. 69 | /// 70 | /// # Examples 71 | /// 72 | /// ``` 73 | /// use rgb::{HetPixel, Rgb, Rgba}; 74 | /// 75 | /// let rgb = Rgb { r: 0_u8, g: 10, b: 100 }; 76 | /// let rgba = Rgba { r: 0_u8, g: 10, b: 100, a: 50 }; 77 | /// 78 | /// assert_eq!(rgb.to_color_array(), [0, 10, 100]); 79 | /// assert_eq!(rgba.to_color_array(), [0, 10, 100]); 80 | /// ``` 81 | //TODO switch to returning an plain array if const generic expressions ever stabilize 82 | #[doc(alias = "rgb")] 83 | #[doc(alias = "to_rgb")] 84 | #[doc(alias = "as_rgb")] 85 | fn to_color_array(&self) -> Self::ColorArray where Self::ColorArray: Copy; 86 | 87 | /// Returns an owned array of the pixel's mutably borrowed color components. 88 | /// 89 | /// # Examples 90 | /// 91 | /// ``` 92 | /// use rgb::{HetPixel, Rgb, Rgba}; 93 | /// 94 | /// let mut rgb = Rgb { r: 0_u8, g: 10, b: 100 }; 95 | /// let mut rgba = Rgba { r: 0_u8, g: 10, b: 100, a: 50 }; 96 | /// 97 | /// *rgb.each_color_mut()[1] = 40; 98 | /// *rgba.each_color_mut()[2] = 40; 99 | /// 100 | /// assert_eq!(rgb.to_color_array(), [0, 40, 100]); 101 | /// assert_eq!(rgba.to_color_array(), [0, 10, 40]); 102 | /// ``` 103 | //TODO switch to returning an plain array if const generic expressions ever stabilize 104 | #[doc(alias = "rgb_mut")] 105 | fn each_color_mut(&mut self) -> Self::ColorArray<&mut Self::ColorComponent>; 106 | 107 | /// Returns a copy of the pixel's alpha component if it has one. 108 | /// 109 | /// # Examples 110 | /// 111 | /// ``` 112 | /// use rgb::{HetPixel, Rgb, Rgba}; 113 | /// 114 | /// let mut rgb = Rgb { r: 0_u8, g: 10, b: 100 }; 115 | /// let mut rgba = Rgba { r: 0_u8, g: 10, b: 100, a: 50 }; 116 | /// 117 | /// assert_eq!(rgb.alpha_opt(), None); 118 | /// assert_eq!(rgba.alpha_opt(), Some(50)); 119 | /// ``` 120 | #[doc(alias = "alpha")] 121 | #[doc(alias = "try_alpha")] 122 | #[doc(alias = "alpha_checked")] 123 | fn alpha_opt(&self) -> Option; 124 | /// Returns a mutable reference of the pixel's alpha component if it has one. 125 | /// 126 | /// # Examples 127 | /// 128 | /// ``` 129 | /// use rgb::{HetPixel, Rgb, Rgba}; 130 | /// 131 | /// let mut rgb = Rgb { r: 0_u8, g: 10, b: 100 }; 132 | /// let mut rgba = Rgba { r: 0_u8, g: 10, b: 100, a: 50 }; 133 | /// 134 | /// let f = |a: Option<&mut u8>| { 135 | /// if let Some(a) = a { 136 | /// *a -= 10; 137 | /// } 138 | /// }; 139 | /// 140 | /// f(rgb.alpha_opt_mut()); 141 | /// f(rgba.alpha_opt_mut()); 142 | /// 143 | /// assert_eq!(rgb.alpha_opt(), None); 144 | /// assert_eq!(rgba.alpha_opt(), Some(40)); 145 | /// ``` 146 | #[doc(alias = "alpha_checked_mut")] 147 | fn alpha_opt_mut(&mut self) -> Option<&mut Self::AlphaComponent>; 148 | 149 | /// Tries to create new instance given an iterator of color components and an alpha component. 150 | /// 151 | /// Returns an error if the `colors` iterator does not contain enough items to create the pixel. 152 | /// 153 | /// # Examples 154 | /// 155 | /// ``` 156 | /// use rgb::error::TryFromColorsAlphaError; 157 | /// use rgb::{HetPixel, Rgb, Rgba}; 158 | /// 159 | /// let mut values2 = [0_u8, 10]; 160 | /// let mut values4 = [0_u8, 10, 100, 40]; 161 | /// 162 | /// let alpha = 50; 163 | /// 164 | /// assert_eq!(Rgb::try_from_colors_alpha(values2, alpha), Err(TryFromColorsAlphaError)); 165 | /// assert_eq!(Rgba::try_from_colors_alpha(values2, alpha), Err(TryFromColorsAlphaError)); 166 | /// 167 | /// assert_eq!(Rgb::try_from_colors_alpha(values4, alpha), Ok(Rgb {r: 0, g: 10, b: 100})); 168 | /// assert_eq!(Rgba::try_from_colors_alpha(values4, alpha), Ok(Rgba {r: 0, g: 10, b: 100, a: 50})); 169 | /// ``` 170 | fn try_from_colors_alpha( 171 | colors: impl IntoIterator, 172 | alpha: Self::AlphaComponent, 173 | ) -> Result; 174 | 175 | /// Maps each of the pixel's color components with a function `f` to any other type. 176 | /// 177 | /// See [`HetPixel::map_colors_same()`] if you want to map the color components to the 178 | /// same type. 179 | /// 180 | /// # Examples 181 | /// 182 | /// ``` 183 | /// use rgb::{HetPixel, Rgb, Rgba}; 184 | /// 185 | /// let rgb = Rgb { r: 0_u8, g: 10, b: 100 }; 186 | /// let rgba = Rgba { r: 0_u8, g: 10, b: 100, a: 50 }; 187 | /// 188 | /// let f = |color: u8| { 189 | /// u16::from(color) * 10 190 | /// }; 191 | /// 192 | /// assert_eq!(rgb.map_colors(f), Rgb { r: 0, g: 100, b: 1000 }); 193 | /// assert_eq!(rgba.map_colors(f), Rgba { r: 0, g: 100, b: 1000, a: 50 }); 194 | /// ``` 195 | #[doc(alias = "map_c")] 196 | #[doc(alias = "map_gray")] 197 | fn map_colors( 198 | &self, 199 | f: impl FnMut(Self::ColorComponent) -> U, 200 | ) -> Self::SelfType 201 | where 202 | U: Copy + 'static; 203 | /// Maps each of the pixel's color components with a function `f` to the same type. 204 | /// 205 | /// See [`HetPixel::map_colors()`] if you want to map the color components to a 206 | /// different type. 207 | /// 208 | /// # Examples 209 | /// 210 | /// ``` 211 | /// use rgb::{HetPixel, Rgb, Rgba}; 212 | /// 213 | /// let rgb = Rgb { r: 0_u8, g: 10, b: 100 }; 214 | /// let rgba = Rgba { r: 0_u8, g: 10, b: 100, a: 50 }; 215 | /// 216 | /// let f = |color: u8| { 217 | /// color / 2 218 | /// }; 219 | /// 220 | /// assert_eq!(rgb.map_colors_same(f), Rgb { r: 0, g: 5, b: 50 }); 221 | /// assert_eq!(rgba.map_colors_same(f), Rgba { r: 0, g: 5, b: 50, a: 50 }); 222 | /// ``` 223 | fn map_colors_same(&self, f: impl FnMut(Self::ColorComponent) -> Self::ColorComponent) -> Self; 224 | 225 | /// Maps the pixel's alpha component with a function `f` to any other type. 226 | /// 227 | /// If the pixel has no alpha component then the pixel is returned unchanged. 228 | /// 229 | /// See [`HetPixel::map_alpha_same()`] if you want to map the alpha component to the 230 | /// same type. 231 | /// 232 | /// # Examples 233 | /// 234 | /// ``` 235 | /// use rgb::{HetPixel, Rgb, Rgba}; 236 | /// 237 | /// let rgb = Rgb {r: 0_u8, g: 10, b: 100}; 238 | /// let rgba = Rgba {r: 0_u8, g: 10, b: 100, a: 50}; 239 | /// 240 | /// let f = |alpha: u8| { 241 | /// u16::from(alpha) * 10 242 | /// }; 243 | /// 244 | /// assert_eq!(rgb.map_alpha(f), Rgb {r: 0, g: 10, b: 100}); 245 | /// assert_eq!(rgba.map_alpha(f), Rgba {r: 0, g: 10, b: 100, a: 500}); 246 | /// ``` 247 | fn map_alpha( 248 | &self, 249 | f: impl FnMut(Self::AlphaComponent) -> U, 250 | ) -> Self::SelfType 251 | where 252 | U: Copy + 'static; 253 | /// Maps the pixel's alpha component with a function `f` to the same type. 254 | /// 255 | /// If the pixel has no alpha component then the pixel is returned unchanged. 256 | /// 257 | /// See [`HetPixel::map_alpha()`] if you want to map the alpha component to a 258 | /// different type. 259 | /// 260 | /// # Examples 261 | /// 262 | /// ``` 263 | /// use rgb::{HetPixel, Rgb, Rgba}; 264 | /// 265 | /// let rgb = Rgb {r: 0_u8, g: 10, b: 100}; 266 | /// let rgba = Rgba {r: 0_u8, g: 10, b: 100, a: 50}; 267 | /// 268 | /// let f = |alpha: u8| { 269 | /// alpha / 2 270 | /// }; 271 | /// 272 | /// assert_eq!(rgb.map_alpha_same(f), Rgb {r: 0, g: 10, b: 100}); 273 | /// assert_eq!(rgba.map_alpha_same(f), Rgba {r: 0, g: 10, b: 100, a: 25}); 274 | /// ``` 275 | fn map_alpha_same(&self, f: impl FnMut(Self::AlphaComponent) -> Self::AlphaComponent) -> Self; 276 | } 277 | 278 | macro_rules! without_alpha { 279 | ($name:ident, $length:literal, [$($color_bit:tt),*]) => { 280 | impl HetPixel for $name where T: Copy + 'static { 281 | type ColorComponent = T; 282 | type AlphaComponent = T; 283 | 284 | const NUM_COMPONENTS: u8 = $length; 285 | const NUM_COLOR_COMPONENTS: u8 = $length; 286 | 287 | type SelfType = $name; 288 | type ColorArray = [U; $length]; 289 | 290 | #[inline] 291 | fn to_color_array(&self) -> Self::ColorArray where Self::ColorArray: Copy { 292 | [$(self.$color_bit),*] 293 | } 294 | 295 | #[inline] 296 | fn each_color_mut(&mut self) -> Self::ColorArray<&mut Self::ColorComponent> { 297 | [$(&mut self.$color_bit),*] 298 | } 299 | 300 | #[inline] 301 | fn alpha_opt(&self) -> Option { 302 | None 303 | } 304 | 305 | #[inline] 306 | fn alpha_opt_mut(&mut self) -> Option<&mut Self::AlphaComponent> { 307 | None 308 | } 309 | 310 | #[inline] 311 | fn try_from_colors_alpha(colors: impl IntoIterator, _: Self::AlphaComponent) -> Result { 312 | let mut iter = colors.into_iter(); 313 | Ok(Self {$($color_bit: iter.next().ok_or(TryFromColorsAlphaError)?),*}) 314 | } 315 | 316 | #[inline] 317 | fn map_colors(&self, mut f: impl FnMut(Self::ColorComponent) -> U) -> Self::SelfType where U: Copy + 'static { 318 | $name {$($color_bit: f(self.$color_bit),)*} 319 | } 320 | 321 | #[inline] 322 | fn map_colors_same(&self, mut f: impl FnMut(Self::ColorComponent) -> Self::ColorComponent) -> Self 323 | { 324 | Self {$($color_bit: f(self.$color_bit),)*} 325 | } 326 | 327 | #[inline] 328 | fn map_alpha(&self, _: impl FnMut(Self::AlphaComponent) -> U) -> Self::SelfType where U: Copy + 'static { 329 | *self 330 | } 331 | 332 | #[inline] 333 | fn map_alpha_same(&self, _: impl FnMut(Self::AlphaComponent) -> Self::AlphaComponent) -> Self { 334 | *self 335 | } 336 | } 337 | } 338 | } 339 | macro_rules! with_alpha { 340 | ($name:tt, $length:literal, [$($color_bit:tt),*], $alpha_bit:tt) => { 341 | impl HetPixel for $name where T: Copy + 'static, A: Copy + 'static { 342 | type ColorComponent = T; 343 | type AlphaComponent = A; 344 | 345 | const NUM_COMPONENTS: u8 = $length; 346 | const NUM_COLOR_COMPONENTS: u8 = $length - 1; 347 | 348 | type SelfType = $name; 349 | type ColorArray = [U; $length - 1]; 350 | 351 | #[inline] 352 | fn to_color_array(&self) -> Self::ColorArray where Self::ColorArray: Copy { 353 | [$(self.$color_bit),*] 354 | } 355 | 356 | #[inline] 357 | fn each_color_mut(&mut self) -> Self::ColorArray<&mut Self::ColorComponent> { 358 | [$(&mut self.$color_bit),*] 359 | } 360 | 361 | #[inline] 362 | fn alpha_opt(&self) -> Option { 363 | Some(self.$alpha_bit) 364 | } 365 | 366 | #[inline] 367 | fn alpha_opt_mut(&mut self) -> Option<&mut Self::AlphaComponent> { 368 | Some(&mut self.$alpha_bit) 369 | } 370 | 371 | #[inline] 372 | fn try_from_colors_alpha(colors: impl IntoIterator, alpha: Self::AlphaComponent) -> Result { 373 | let mut iter = colors.into_iter(); 374 | Ok(Self {$($color_bit: iter.next().ok_or(TryFromColorsAlphaError)?),*, $alpha_bit: alpha}) 375 | } 376 | 377 | #[inline] 378 | fn map_colors(&self, mut f: impl FnMut(Self::ColorComponent) -> U) -> Self::SelfType where U: Copy + 'static { 379 | $name {$($color_bit: f(self.$color_bit),)* $alpha_bit: self.$alpha_bit} 380 | } 381 | 382 | #[inline] 383 | fn map_colors_same(&self, mut f: impl FnMut(Self::ColorComponent) -> Self::ColorComponent) -> Self 384 | { 385 | Self {$($color_bit: f(self.$color_bit),)* $alpha_bit: self.$alpha_bit} 386 | } 387 | 388 | #[inline] 389 | fn map_alpha(&self, mut f: impl FnMut(Self::AlphaComponent) -> U) -> Self::SelfType where U: Copy + 'static { 390 | $name {$($color_bit: self.$color_bit,)* $alpha_bit: f(self.$alpha_bit)} 391 | } 392 | 393 | #[inline] 394 | fn map_alpha_same(&self, mut f: impl FnMut(Self::AlphaComponent) -> Self::AlphaComponent) -> Self { 395 | $name {$($color_bit: self.$color_bit,)* $alpha_bit: f(self.$alpha_bit)} 396 | } 397 | } 398 | } 399 | } 400 | 401 | with_alpha!(Rgba, 4, [r, g, b], a); 402 | with_alpha!(Abgr, 4, [b, g, r], a); 403 | with_alpha!(Argb, 4, [r, g, b], a); 404 | with_alpha!(Bgra, 4, [b, g, r], a); 405 | with_alpha!(GrayA, 2, [v], a); 406 | 407 | use crate::formats::gray_alpha::GrayAlpha_v08; 408 | with_alpha!(GrayAlpha_v08, 2, [0], 1); 409 | 410 | without_alpha!(Bgr, 3, [b, g, r]); 411 | without_alpha!(Rgb, 3, [r, g, b]); 412 | without_alpha!(Grb, 3, [r, g, b]); 413 | without_alpha!(Gray_v09, 1, [v]); 414 | without_alpha!(Rgbw, 4, [r, g, b, w]); 415 | 416 | use crate::formats::gray::Gray_v08; 417 | without_alpha!(Gray_v08, 1, [0]); 418 | -------------------------------------------------------------------------------- /src/pixel_traits/pixel.rs: -------------------------------------------------------------------------------- 1 | use core::fmt::Display; 2 | use crate::HetPixel; 3 | use crate::{Abgr, Argb, ArrayLike, Bgr, Bgra, Gray_v09, GrayA, Grb,Rgb, Rgba, Rgbw}; 4 | 5 | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] 6 | /// Error returned from the [`Pixel::try_from_components()`] function. 7 | pub struct TryFromComponentsError; 8 | impl Display for TryFromComponentsError { 9 | #[cold] 10 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 11 | f.write_str("the components iterator did not contain enough items to create this pixel") 12 | } 13 | } 14 | 15 | /// A Pixel made up of a compile-time known number of color components and optionally an 16 | /// alpha component. 17 | /// 18 | /// Unlike [`HetPixel`] the alpha component must be the same type as the color 19 | /// components. 20 | /// 21 | /// This trait is implemented on every pixel type in the crate. 22 | /// 23 | /// All types which implement [`Pixel`] also implement [`HetPixel`] due to the super-trait trait bound. 24 | pub trait Pixel: 25 | HetPixel 26 | { 27 | /// The component type of the pixel used for both color and alpha components if any. 28 | type Component: Copy; 29 | 30 | /// A generic associated type used to return the array of 31 | /// components despite rust's lack of const generic expressions. 32 | /// 33 | /// Used in functions like [`Pixel::to_array()`]. 34 | /// 35 | /// For example, [`Rgb`] has `ComponentArray = [U; 3]` wheareas 36 | /// [`Rgba`] has `ComponentArray = [U; 4]`. 37 | type ComponentArray: ArrayLike; 38 | 39 | /// Returns an owned array of copies of the pixel's components. 40 | /// 41 | /// # Examples 42 | /// 43 | /// ``` 44 | /// use rgb::{Pixel, Rgb, Rgba}; 45 | /// 46 | /// let rgb = Rgb { r: 0_u8, g: 10, b: 100 }; 47 | /// let rgba = Rgba { r: 0_u8, g: 10, b: 100, a: 50 }; 48 | /// 49 | /// assert_eq!(rgb.to_array(), [0, 10, 100]); 50 | /// assert_eq!(rgba.to_array(), [0, 10, 100, 50]); 51 | /// ``` 52 | //TODO switch to returning an plain array if const generic expressions ever stabilize 53 | #[doc(alias = "into_array")] 54 | #[doc(alias = "component_array")] 55 | fn to_array(&self) -> Self::ComponentArray 56 | where Self::ComponentArray: Copy; 57 | 58 | /// Casts a reference of the pixel to an array reference of the pixel's 59 | /// components. 60 | /// 61 | /// # Examples 62 | /// 63 | /// ``` 64 | /// use rgb::{Pixel, Rgb, Rgba}; 65 | /// 66 | /// let rgb = Rgb {r: 0_u8, g: 10, b: 100}; 67 | /// let rgba = Rgba {r: 0_u8, g: 10, b: 100, a: 50}; 68 | /// 69 | /// assert_eq!(rgb.as_array(), &[0, 10, 100]); 70 | /// assert_eq!(rgba.as_array(), &[0, 10, 100, 50]); 71 | /// ``` 72 | #[doc(alias = "as_ref")] 73 | fn as_array(&self) -> &Self::ComponentArray; 74 | 75 | /// Casts a mutable reference of the pixel to an mutable array reference of the pixel's 76 | /// components. 77 | /// 78 | /// # Examples 79 | /// 80 | /// ``` 81 | /// use rgb::{Pixel, Rgb, Rgba}; 82 | /// 83 | /// let mut rgb = Rgb {r: 0_u8, g: 10, b: 100}; 84 | /// let mut rgba = Rgba {r: 0_u8, g: 10, b: 100, a: 50}; 85 | /// 86 | /// rgb.as_array_mut()[1] = 40; 87 | /// rgba.as_array_mut()[2] = 40; 88 | /// 89 | /// assert_eq!(rgb.as_array(), &[0, 40, 100]); 90 | /// assert_eq!(rgba.as_array(), &[0, 10, 40, 50]); 91 | /// ``` 92 | #[doc(alias = "as_mut")] 93 | fn as_array_mut(&mut self) -> &mut Self::ComponentArray; 94 | 95 | /// Returns an owned array of the pixel's mutably borrowed components. 96 | /// 97 | /// # Examples 98 | /// 99 | /// ``` 100 | /// use rgb::{Pixel, Rgb, Rgba}; 101 | /// 102 | /// let mut rgb = Rgb { r: 0_u8, g: 10, b: 100 }; 103 | /// let mut rgba = Rgba { r: 0_u8, g: 10, b: 100, a: 50 }; 104 | /// 105 | /// *rgb.each_mut()[1] = 40; 106 | /// *rgba.each_mut()[2] = 40; 107 | /// 108 | /// assert_eq!(rgb.to_array(), [0, 40, 100]); 109 | /// assert_eq!(rgba.to_array(), [0, 10, 40, 50]); 110 | /// ``` 111 | //TODO switch to returning an plain array if const generic expressions ever stabilize 112 | #[doc(alias = "to_array_mut")] 113 | fn each_mut(&mut self) -> Self::ComponentArray<&mut Self::Component>; 114 | 115 | /// Tries to create new instance given an iterator of its components. 116 | /// 117 | /// Returns an error if the `components` iterator does not contain enough items to create the pixel. 118 | /// 119 | /// # Examples 120 | /// 121 | /// ``` 122 | /// use rgb::error::TryFromComponentsError; 123 | /// use rgb::{Pixel, Rgb, Rgba}; 124 | /// 125 | /// let mut values2 = [0_u8, 10]; 126 | /// let mut values4 = [0_u8, 10, 100, 40]; 127 | /// 128 | /// assert_eq!(Rgb::try_from_components(values2), Err(TryFromComponentsError)); 129 | /// assert_eq!(Rgba::try_from_components(values2), Err(TryFromComponentsError)); 130 | /// 131 | /// assert_eq!(Rgb::try_from_components(values4), Ok(Rgb { r: 0, g: 10, b: 100 })); 132 | /// assert_eq!(Rgba::try_from_components(values4), Ok(Rgba { r: 0, g: 10, b: 100, a: 40 })); 133 | /// ``` 134 | fn try_from_components( 135 | components: impl IntoIterator, 136 | ) -> Result; 137 | 138 | /// Maps each of the pixel's components with a function `f` to any other component type. 139 | /// 140 | /// See [`Pixel::map_same()`] if you want to map the components to the 141 | /// same type. 142 | /// 143 | /// # Examples 144 | /// 145 | /// ``` 146 | /// use rgb::{Pixel, Rgb, Rgba}; 147 | /// 148 | /// let rgb = Rgb { r: 0_u8, g: 10, b: 100 }; 149 | /// let rgba = Rgba { r: 0_u8, g: 10, b: 100, a: 50 }; 150 | /// 151 | /// let f = |color: u8| { 152 | /// u16::from(color) * 10 153 | /// }; 154 | /// 155 | /// assert_eq!(rgb.map(f), Rgb { r: 0, g: 100, b: 1000 }); 156 | /// assert_eq!(rgba.map(f), Rgba { r: 0, g: 100, b: 1000, a: 500 }); 157 | /// ``` 158 | fn map(&self, f: impl FnMut(Self::Component) -> U) -> Self::SelfType where U: Copy; 159 | 160 | /// Maps each of the pixel's components with a function `f` to the same component type. 161 | /// 162 | /// See [`Pixel::map()`] if you want to map the components to a 163 | /// different type. 164 | /// 165 | /// # Examples 166 | /// 167 | /// ``` 168 | /// use rgb::{Pixel, Rgb, Rgba}; 169 | /// 170 | /// let rgb = Rgb { r: 0_u8, g: 10, b: 100 }; 171 | /// let rgba = Rgba { r: 0_u8, g: 10, b: 100, a: 50 }; 172 | /// 173 | /// let f = |color: u8| { 174 | /// color / 2 175 | /// }; 176 | /// 177 | /// assert_eq!(rgb.map_same(f), Rgb { r: 0, g: 5, b: 50 }); 178 | /// assert_eq!(rgba.map_same(f), Rgba { r: 0, g: 5, b: 50, a: 25 }); 179 | /// ``` 180 | fn map_same(&self, f: impl FnMut(Self::Component) -> Self::Component) -> Self; 181 | } 182 | 183 | macro_rules! without_alpha { 184 | ($name:tt, $length:literal, [$($bit:tt),*]) => { 185 | impl Pixel for $name where T: Copy + 'static { 186 | type Component = T; 187 | type ComponentArray = [U; $length]; 188 | 189 | #[inline] 190 | fn to_array(&self) -> Self::ComponentArray where Self::ComponentArray: Copy { 191 | [$(self.$bit),*] 192 | } 193 | 194 | #[inline] 195 | fn as_array(&self) -> &Self::ComponentArray { 196 | unsafe { 197 | &*(self as *const Self).cast() 198 | } 199 | } 200 | 201 | #[inline] 202 | fn as_array_mut(&mut self) -> &mut Self::ComponentArray { 203 | unsafe { 204 | &mut *(self as *mut Self).cast() 205 | } 206 | } 207 | 208 | #[inline] 209 | fn each_mut(&mut self) -> Self::ComponentArray<&mut Self::Component> { 210 | [$(&mut self.$bit),*] 211 | } 212 | 213 | #[inline] 214 | fn try_from_components(components: impl IntoIterator) -> Result { 215 | let mut iter = components.into_iter(); 216 | Ok(Self {$($bit: iter.next().ok_or(TryFromComponentsError)?),*}) 217 | } 218 | 219 | #[inline] 220 | fn map(&self, mut f: impl FnMut(Self::Component) -> U) -> Self::SelfType where U: Copy + 'static { 221 | $name { $($bit: f(self.$bit),)* } 222 | } 223 | 224 | #[inline] 225 | fn map_same(&self, mut f: impl FnMut(Self::Component) -> Self::Component) -> Self { 226 | $name { $($bit: f(self.$bit),)* } 227 | } 228 | } 229 | } 230 | } 231 | 232 | macro_rules! with_alpha { 233 | ($name:tt, $length:literal, [$($bit:tt),*]) => { 234 | impl Pixel for $name where T: Copy + 'static { 235 | type Component = T; 236 | type ComponentArray = [U; $length]; 237 | 238 | #[inline] 239 | fn to_array(&self) -> Self::ComponentArray where Self::ComponentArray: Copy { 240 | [$(self.$bit),*] 241 | } 242 | 243 | #[inline] 244 | fn as_array(&self) -> &Self::ComponentArray { 245 | unsafe { 246 | &*(self as *const Self).cast() 247 | } 248 | } 249 | 250 | #[inline] 251 | fn as_array_mut(&mut self) -> &mut Self::ComponentArray { 252 | unsafe { 253 | &mut *(self as *mut Self).cast() 254 | } 255 | } 256 | 257 | #[inline] 258 | fn each_mut(&mut self) -> Self::ComponentArray<&mut Self::Component> { 259 | [$(&mut self.$bit),*] 260 | } 261 | 262 | #[inline] 263 | fn try_from_components(components: impl IntoIterator) -> Result { 264 | let mut iter = components.into_iter(); 265 | Ok(Self {$($bit: iter.next().ok_or(TryFromComponentsError)?),*}) 266 | } 267 | 268 | #[inline] 269 | fn map(&self, mut f: impl FnMut(Self::Component) -> U) -> Self::SelfType where U: Copy + 'static { 270 | $name { $($bit: f(self.$bit),)* } 271 | } 272 | 273 | #[inline] 274 | fn map_same(&self, mut f: impl FnMut(Self::Component) -> Self::Component) -> Self { 275 | $name { $($bit: f(self.$bit),)* } 276 | } 277 | } 278 | } 279 | } 280 | 281 | with_alpha!(Rgba, 4, [r, g, b, a]); 282 | with_alpha!(Abgr, 4, [a, b, g, r]); 283 | with_alpha!(Argb, 4, [a, r, g, b]); 284 | with_alpha!(Bgra, 4, [b, g, r, a]); 285 | with_alpha!(GrayA, 2, [v, a]); 286 | 287 | without_alpha!(Bgr, 3, [b, g, r]); 288 | without_alpha!(Rgb, 3, [r, g, b]); 289 | without_alpha!(Grb, 3, [r, g, b]); 290 | without_alpha!(Gray_v09, 1, [v]); 291 | without_alpha!(Rgbw, 4, [r, g, b, w]); 292 | 293 | use crate::formats::gray::Gray_v08; 294 | without_alpha!(Gray_v08, 1, [0]); 295 | 296 | use crate::formats::gray_alpha::GrayAlpha_v08; 297 | with_alpha!(GrayAlpha_v08, 2, [0, 1]); 298 | 299 | 300 | #[test] 301 | fn as_refs() { 302 | let mut r = Rgba::new(1u8,2,3,4u8); 303 | assert_eq!(&[1,2,3,4], r.as_array()); 304 | assert_eq!(&[1,2,3,4], AsRef::<[u8; 4]>::as_ref(&r)); 305 | assert_eq!(&[1,2,3,4], r.as_ref()); 306 | assert_eq!([1,2,3,4], *r.as_array_mut()); 307 | assert_eq!([1,2,3,4], *AsMut::<[u8; 4]>::as_mut(&mut r)); 308 | assert_eq!([1,2,3,4], *r.as_mut()); 309 | 310 | let mut r = GrayA::new(1u8,4u8); 311 | assert_eq!(&[1,4], r.as_array()); 312 | assert_eq!(&[1,4], AsRef::<[u8; 2]>::as_ref(&r)); 313 | assert_eq!(&[1,4], r.as_ref()); 314 | assert_eq!([1,4], *r.as_array_mut()); 315 | assert_eq!([1,4], *AsMut::<[u8; 2]>::as_mut(&mut r)); 316 | assert_eq!([1,4], *r.as_mut()); 317 | } 318 | -------------------------------------------------------------------------------- /src/tuples.rs: -------------------------------------------------------------------------------- 1 | use crate::formats::gray::{Gray_v08, Gray_v09}; 2 | use crate::formats::gray_alpha::GrayAlpha_v08; 3 | use crate::{Abgr, Argb, Bgr, Bgra, GrayA, Grb, Rgb, Rgba, Rgbw}; 4 | 5 | macro_rules! tuple_conversion { 6 | ($name:ident, 1, [$($bit:tt:$num:tt),*]) => { 7 | impl From<$name> for (S,) where R: Into { 8 | #[inline] 9 | fn from(value: $name) -> Self { 10 | ($(value.$bit.into()),*,) 11 | } 12 | } 13 | 14 | impl From<(R,)> for $name where R: Into { 15 | #[inline] 16 | fn from(value: (R,)) -> Self { 17 | Self { $($bit: value.$num.into()),* } 18 | } 19 | } 20 | }; 21 | ($name:ident, 2, [$($bit:tt:$num:tt),*]) => { 22 | impl From<$name> for (S, S) where R: Into { 23 | #[inline] 24 | fn from(value: $name) -> Self { 25 | ($(value.$bit.into()),*) 26 | } 27 | } 28 | 29 | impl From<(R, R)> for $name where R: Into { 30 | #[inline] 31 | fn from(value: (R, R)) -> Self { 32 | Self { $($bit: value.$num.into()),* } 33 | } 34 | } 35 | }; 36 | ($name:ident, 3, [$($bit:tt:$num:tt),*]) => { 37 | impl From<$name> for (S, S, S) where R: Into { 38 | #[inline] 39 | fn from(value: $name) -> Self { 40 | ($(value.$bit.into()),*) 41 | } 42 | } 43 | 44 | impl From<(R, R, R)> for $name where R: Into { 45 | #[inline] 46 | fn from(value: (R, R, R)) -> Self { 47 | Self { $($bit: value.$num.into()),* } 48 | } 49 | } 50 | }; 51 | ($name:ident, 4, [$($bit:tt:$num:tt),*]) => { 52 | impl From<$name> for (S, S, S, S) where R: Into { 53 | #[inline] 54 | fn from(value: $name) -> Self { 55 | ($(value.$bit.into()),*) 56 | } 57 | } 58 | 59 | impl From<(R, R, R, R)> for $name where R: Into { 60 | #[inline] 61 | fn from(value: (R, R, R, R)) -> Self { 62 | Self { $($bit: value.$num.into()),* } 63 | } 64 | } 65 | }; 66 | } 67 | 68 | tuple_conversion!(Rgb, 3, [r:0, g:1, b:2]); 69 | tuple_conversion!(Bgr, 3, [b:0, g:1, r:2]); 70 | tuple_conversion!(Grb, 3, [g:0, r:1, b:2]); 71 | tuple_conversion!(Gray_v09, 1, [v:0]); 72 | tuple_conversion!(Gray_v08, 1, [0:0]); 73 | tuple_conversion!(Rgbw, 4, [r:0, g:1, b:2, w:3]); 74 | 75 | tuple_conversion!(Rgba, 4, [r:0, g:1, b:2, a:3]); 76 | tuple_conversion!(Argb, 4, [a:0, r:1, g:2, b:3]); 77 | tuple_conversion!(Bgra, 4, [b:0, g:1, r:2, a:3]); 78 | tuple_conversion!(Abgr, 4, [a:0, b:1, g:2, r:3]); 79 | tuple_conversion!(GrayA, 2, [v:0, a:1]); 80 | tuple_conversion!(GrayAlpha_v08, 2, [0:0, 1:1]); 81 | --------------------------------------------------------------------------------