palette
repository·master·Indexed 21 days ago
https://github.com/ogeon/paletteA color management and conversion library for Rust that uses the type system to ensure correctness across various color spaces. It supports a wide range of built-in and user-defined color spaces, providing traits like FromColor and IntoColor for conversions, and a cast module for efficient pixel buffer manipulation. The library includes palette_math for floating-point operations and gamma lookup tables, and palette_derive for procedural macros such as FromColorUnclamped, WithAlpha, and ArrayCast.
What's inside palette
- palette is a color management and conversion library designed for correctness, flexibility, and ease of use. It leverages the Rust type system to prevent color space mistakes and supports a wide range of color spaces, including user-defined variants. The library is designed to integrate easily with other libraries and provides robust color conversion capabilities.
Perform color operations with operator traits
masterPalette implements various color operations (like saturate, desaturate, hue shift, and lightening) as operator traits. This allows you to write generic functions that operate on any color space that supports the specific operation.
Common traits include:
ShiftHueLightenMix(for interpolation)
Additionally, Palette provides SVG blend and composition functions, such as
.over()for alpha blending.use palette::{Hsl, Hsv, Lighten, Mix, ShiftHue}; fn transform_color<C>(color: C, amount: f32) -> C where C: ShiftHue<Scalar = f32> + Lighten<Scalar = f32> + Mix<Scalar = f32> + Copy, { let new_color = color.shift_hue(170.0).lighten(1.0); // Interpolate between the old and new color. color.mix(new_color, amount) } let new_hsl = transform_color(Hsl::new_srgb(0.00, 0.70, 0.20), 0.8); let new_hsv = transform_color(Hsv::new_srgb(0.00, 0.82, 0.34), 0.8);Use palette_derive macros via the palette crate
masterThe
palette_derivecrate provides derive macros for thepalettecrate. Instead of addingpalette_deriveas a direct dependency, you should addpaletteto yourCargo.toml. The macros are re-exported through the mainpalettecrate.To use them, ensure
paletteis in your dependencies and use the macros as provided by thepalettenamespace.// In your Cargo.toml [dependencies] palette = "0.7.7" // In your code use palette::SomeDeriveMacro; #[derive(SomeDeriveMacro)] struct MyColor;Create custom color spaces
masterBuilt-in color spaces are highly customizable. You can define new color spaces by composing different components, such as primaries, white points, and transfer functions (encodings).
For example, you can define a custom RGB standard by combining
encoding,white_point, andrgb::Rgbtypes.use palette::{ encoding, white_point, rgb::Rgb, Srgb }; // Combining sRGB primaries, the CIE equal energy white point and the sRGB transfer function type EqualEnergyStandard = (encoding::Srgb, white_point::E, encoding::Srgb); type EqualEnergySrgb<T> = Rgb<EqualEnergyStandard, T>; let ee_rgb = EqualEnergySrgb::new(1.0, 0.5, 0.3);Install Palette via Cargo
masterTo use Palette in your project, add it to your
Cargo.tomldependencies. By default, it includesstd,alloc,namedconstants, andapproxcomparison support.For standard usage:
[dependencies] palette = "0.7.7"If you are working in an embedded or
no_stdenvironment, you must disable default features and enablelibmto provide floating-point math without the standard library:[dependencies.palette] version = "0.7.7" default-features = false features = ["libm"][dependencies] palette = "0.7.7"Configure palette_math for #![no_std] and embedded environments
masterTo use
palette_mathin a#![no_std]environment, you must disable the defaultstdfeature. You should then enable thelibmfeature to provide floating-point math operations via thelibmcrate, and theallocfeature if you require types that allocate memory (likeVec).# Uses libm instead of std for floating point math: palette_math = { version = "0.7.7", features = ["libm"], default-features = false }Minimum Supported Rust Version (MSRV) for palette
masterThe current version of Palette is tested with Rust version1.71.0acrossstable,beta, andnightlychannels. Note that the MSRV may vary depending on which features you enable in your configuration.Implement conversion for custom color types
masterTo integrate a custom color type into Palette, you can use the
palette_derivemacros and implement the necessary conversion traits.- Use
#[derive(FromColorUnclamped, WithAlpha)]on your struct. - Use
#[palette(skip_derives(Rgb), rgb_standard = "...")]to specify how to handle RGB conversions. - Use
#[palette(alpha)]to mark the alpha channel. - Implement
FromColorUnclamped<T>for your type to allow conversion from Palette types. - Implement
FromColorUnclamped<YourType>for Palette types to allow conversion into your type. - Implement
Clampto define how your color values should be constrained.
use palette::{ convert::FromColorUnclamped, encoding, rgb::Rgb, IntoColor, WithAlpha, Clamp, Srgb, Lcha }; #[derive(FromColorUnclamped, WithAlpha)] #[palette(skip_derives(Rgb), rgb_standard = "encoding::Srgb")] struct Color { r: f32, g: f32, b: f32, #[palette(alpha)] a: f32, } impl Clamp for Color { fn clamp(self) -> Self { Color { r: self.r.min(1.0).max(0.0), g: self.g.min(1.0).max(0.0), b: self.b.min(1.0).max(0.0), a: self.a.min(1.0).max(0.0), } } } // To allow generic usage: fn generic_do_something(color: impl IntoColor<Color>) { let color = color.into_color(); // ... }- Use
Install palette_math
masterTo use
palette_mathin your Rust project, add it to yourCargo.tomldependencies. By default, it enables thestdandallocfeatures.[dependencies] palette_math = "0.7.7"Work with pixels and buffers using the cast module
masterThe
castmodule provides traits and functions to treat slices or arrays of components (like&[u8]) as slices of Palette colors without cloning the entire buffer. This is highly efficient for image or pixel buffers.- Use
components_as_mut()to convert a mutable slice of components into a mutable slice of Palette colors (e.g.,&mut [Srgb<u8>]). - Use
components_as()to convert a slice of components into a slice of Palette colors (e.g.,&[Srgb<u8>]). - You can also convert a single color from an object that implements
AsMut<[u8; N]>.
use palette::{cast::ComponentsAsMut, Srgb}; // Convert `my_rgb_image` into `&mut [Srgb<u8>]` without copying. fn swap_red_and_blue(my_rgb_image: &mut [u8]) { let my_rgb_image: &mut [Srgb<u8>] = my_rgb_image.components_as_mut(); for color in my_rgb_image { std::mem::swap(&mut color.red, &mut color.blue); } }- Use
What is the UintCast trait?
masterThe
UintCasttrait is a marker trait used to identify types that can be represented as an unsigned integer with the same memory layout and size. This allows for zero-cost conversions between color types and integer types (e.g., converting anSrgba<u8>to au32).Safety Requirements
To implement
UintCastsafely, the type must satisfy these conditions:- It must be inhabited (not
Infallible). - It must allow any bit pattern (or have a way to recover from invalid values).
- It must be a wrapper around
Self::Uintor be safe to transmute to/fromSelf::Uint. - It must not contain any internal padding.
- It must be
repr(C)orrepr(transparent). - It must have the same size and alignment as
Self::Uint. - It is assumed not to implement
Drop.
- It must be inhabited (not
Chain multiple in-place conversions with `then_into_color_mut`
masterWhen performing multiple sequential conversions (e.g.,
Srgb$\rightarrow$Hsv$\rightarrow$Hsl$\rightarrow$Srgb), a standard guard drop would convert the colors back to the intermediate type at each step (e.g.,Hsv$\rightarrow$Hsl$\rightarrow$Hsv$\rightarrow$Srgb).To optimize this, use
FromColorMutGuard::then_into_color_mut. This method replaces the current guard with a new one that points to the next color type, but ensures that when the final guard is dropped, the colors are restored directly to the original starting type, skipping the intermediate restoration steps.use palette::{FromColorMut, ShiftHueAssign, LightenAssign, Srgb, Hsv, Hsl}; let mut rgb = [ Srgb::new(1.0, 0.0, 0.0), Srgb::new(0.0, 1.0, 0.0), Srgb::new(0.0, 0.0, 1.0), ]; { let mut hsv = <[Hsv]>::from_color_mut(&mut rgb); hsv.shift_hue_assign(60.0); // Chain to Hsl. The final drop will restore directly to Srgb. let mut hsl = hsv.then_into_color_mut::<[Hsl]>(); hsl.lighten_assign(0.5); } // Colors are restored directly to Srgb here.