Crate palette[−][src]
Expand description
A library that makes linear color calculations and conversion easy and accessible for anyone. It uses the type system to enforce correctness and to avoid mistakes, such as mixing incompatible color types.
It’s Never “Just RGB”
Colors in images are often “gamma corrected”, or converted using some non-linear transfer function into a format like sRGB before being stored or displayed. This is done as a compression method and to prevent banding; it’s also a bit of a legacy from the ages of the CRT monitors, where the output from the electron gun was non-linear. The problem is that these formats are non-linear color spaces, which means that many operations that you may want to perform on colors (addition, subtraction, multiplication, linear interpolation, etc.) will work unexpectedly when performed in such a non-linear color space. Thus, the compression has to be reverted to restore linearity and ensure that many operations on the colors behave as expected.
For example, this does not work:
// An alias for Rgb<Srgb>, which is what most pictures store. use palette::Srgb; let orangeish = Srgb::new(1.0, 0.6, 0.0); let blueish = Srgb::new(0.0, 0.2, 1.0); let whatever_it_becomes = orangeish + blueish; // Does not compile
Instead, they have to be made linear before adding:
// An alias for Rgb<Srgb>, which is what most pictures store. use palette::{Pixel, Srgb}; let orangeish = Srgb::new(1.0, 0.6, 0.0).into_linear(); let blueish = Srgb::new(0.0, 0.2, 1.0).into_linear(); let whatever_it_becomes = orangeish + blueish; // Encode the result back into sRGB and create a byte array let pixel: [u8; 3] = Srgb::from_linear(whatever_it_becomes) .into_format() .into_raw();
See the rgb module for a deeper dive into RGB and (non-)linearity.
Color Spaces
“RGB” and other tristimulus based spaces like CIE Xyz are probably the most widely known color spaces. These spaces are great when you want to perform physically based math on color (like in a 2D or 3D rendering program) but there are also color spaces that are not defined in terms of tristimulus values.
You have probably used a color picker with a rainbow wheel and a brightness slider. That may have been an HSV or an HSL color picker, where the color is encoded as hue, saturation and brightness/lightness. Even though these spaces are defined using 3 values, they aren’t based on tristimulus values, since those three values don’t have a direct relation to human vision (i.e. our L, M, and S cones). Such color spaces are excellent when it comes to humans intuitively selecting color values, and as such are the go-to choice when this interaction is needed. They can then be converted into other color spaces to perform modifications to them.
There’s also a group of color spaces that are designed to be perceptually uniform, meaning that the perceptual change is equal to the numerical change. An example of this is the CIE L*a*b* color space. These color spaces are excellent when you want to “blend” between colors in a perceptually pleasing manner rather than based on physical light intensity.
Selecting the proper color space can have a big impact on how the resulting
image looks (as illustrated by some of the programs in examples
), and
Palette makes the conversion between them as easy as a call to from_color
or into_color
.
This example takes an sRGB color, converts it to CIE L*C*h°, a color space similar to the colloquial HSL/HSV color spaces, shifts its hue by 180° and converts it back to RGB:
use palette::{FromColor, Hue, IntoColor, Lch, Srgb}; let lch_color: Lch = Srgb::new(0.8, 0.2, 0.1).into_color(); let new_color = Srgb::from_color(lch_color.shift_hue(180.0));
Transparency
There are many cases where pixel transparency is important, but there are
also many cases where it becomes a dead weight, if it’s always stored
together with the color, but not used. Palette has therefore adopted a
structure where the transparency component (alpha) is attachable using the
Alpha
type, instead of having copies of each color
space.
This approach comes with the extra benefit of allowing operations to selectively affect the alpha component:
use palette::{LinSrgb, LinSrgba}; let mut c1 = LinSrgba::new(1.0, 0.5, 0.5, 0.8); let c2 = LinSrgb::new(0.5, 1.0, 1.0); c1.color = c1.color * c2; //Leave the alpha as it is c1.blue += 0.2; //The color components can easily be accessed c1 = c1 * 0.5; //Scale both the color and the alpha
A Basic Workflow
The overall workflow can be divided into three steps, where the first and last may be taken care of by other parts of the application:
Decoding -> Processing -> Encoding
1. Decoding
Find out what the source format is and convert it to a linear color space. There may be a specification, such as when working with SVG or CSS.
When working with RGB or gray scale (luma):
-
If you are asking your user to enter an RGB value, you are in a gray zone where it depends on the context. It’s usually safe to assume sRGB, but sometimes it’s already linear.
-
If you are decoding an image, there may be some meta data that gives you the necessary details. Otherwise it’s most commonly sRGB. Usually you will end up with a slice or vector with RGB bytes, which can easily be converted to Palette colors:
use palette::{Srgb, Pixel}; // This works for any (even non-RGB) color type that can have the // buffer element type as component. let color_buffer: &mut [Srgb<u8>] = Pixel::from_raw_slice_mut(&mut image_buffer);
- If you are getting your colors from the GPU, in a game or other graphical application, or if they are otherwise generated by the application, then chances are that they are already linear. Still, make sure to check that they are not being encoded somewhere.
When working with other colors:
-
For HSL, HSV, HWB: Check if they are based on any other color space than sRGB, such as Adobe or Apple RGB.
-
For any of the CIE color spaces, check for a specification of white point and light source. These are necessary for converting to RGB and other colors, that depend on perception and “viewing devices”. Common defaults are the D65 light source and the sRGB white point. The Palette defaults should take you far.
2. Processing
When your color has been decoded into some Palette type, it’s ready for
processing. This includes things like blending, hue shifting, darkening and
conversion to other formats. Just make sure that your non-linear RGB is
made linear first (my_srgb.into_linear()
), to make the operations
available.
Different color spaced have different capabilities, pros and cons. You may have to experiment a bit (or look at the example programs) to find out what gives the desired result.
3. Encoding
When the desired processing is done, it’s time to encode the colors back into some image format. The same rules applies as for the decoding, but the process reversed.
Working with Raw Data
Oftentimes, pixel data is stored in a raw buffer such as a [u8; 3]
. The
Pixel
trait allows for easy interoperation between
Palette colors and other crates or systems. from_raw
can be used to
convert into a Palette color, into_format
converts from Srgb<u8>
to
Srgb<f32>
, and finally into_raw
to convert from a Palette color back to
a [u8;3]
.
use approx::assert_relative_eq; use palette::{Srgb, Pixel}; let buffer = [255, 0, 255]; let raw = Srgb::from_raw(&buffer); assert_eq!(raw, &Srgb::<u8>::new(255u8, 0, 255)); let raw_float: Srgb<f32> = raw.into_format(); assert_relative_eq!(raw_float, Srgb::new(1.0, 0.0, 1.0)); let raw: [u8; 3] = Srgb::into_raw(raw_float.into_format()); assert_eq!(raw, buffer);
Re-exports
pub use gradient::Gradient;
pub use luma::GammaLuma;
pub use luma::GammaLumaa;
pub use luma::LinLuma;
pub use luma::LinLumaa;
pub use luma::SrgbLuma;
pub use luma::SrgbLumaa;
pub use rgb::GammaSrgb;
pub use rgb::GammaSrgba;
pub use rgb::LinSrgb;
pub use rgb::LinSrgba;
pub use rgb::Srgb;
pub use rgb::Srgba;
pub use convert::FromColor;
pub use convert::IntoColor;
pub use encoding::pixel::Pixel;
Modules
Color blending and blending equations.
Convert colors from one reference white point to another
Traits for converting between color spaces.
Various encoding traits, types and standards.
Floating point trait
Types for interpolation between multiple colors.
Luminance types.
A collection of named color constants. Can be toggled with the "named"
and
"named_from_str"
Cargo features.
RGB types, spaces and standards.
Defines the tristimulus values of the CIE Illuminants.
Structs
An alpha component wrapper for colors.
HSL color space.
HSLuv color space.
HSV color space.
HWB color space.
The CIE L*a*b* (CIELAB) color space.
A hue type for the CIE L*a*b* family of color spaces.
CIE L*C*h°, a polar version of CIE L*a*b*.
CIE L*C*uv h°uv, a polar version of CIE L*u*v*.
The CIE L*u*v* (CIELUV) color space.
A hue type for the CIE L*u*v* family of color spaces.
The Oklab color space.
A hue type for the Oklab color space.
Oklch, a polar version of Oklab.
RGBA color packed into a 32-bit unsigned integer. Defaults to ARGB
ordering for Rgb
types and RGBA ordering for Rgba
types.
A hue type for the RGB family of color spaces.
The CIE 1931 XYZ color space.
The CIE 1931 Yxy (xyY) color space.
Traits
A trait for colors that can be blended together.
A trait for clamping and checking if colors are within their ranges.
A trait for calculating the color difference between two colors.
Common trait for color components.
Perform a unary or binary operation on each component of a color.
Common trait for floating point color components.
Converts from a color component type, while performing the appropriate scaling, rounding and clamping.
A trait for infallible conversion from f64
. The conversion may be lossy.
A trait for colors where a hue may be calculated.
A trait for colors where the hue can be manipulated without conversion.
Converts into a color component type, while performing the appropriate scaling, rounding and clamping.
A trait for linear color interpolation.
A trait for calculating relative contrast between two colors.
Splits and combines RGB(A) types with some channel ordering. Channels may be
ordered as Abgr
, Argb
, Bgra
, or Rgba
.
A trait for colors where the saturation (or chroma) can be manipulated without conversion.
The Shade
trait allows a color to be lightened or darkened.
A trait for color types that can have or be given transparency (alpha channel).
Functions
Calculate the ratio between two luma
values.
Type Definitions
Linear HSL with an alpha component. See the Hsla
implementation in
Alpha
.
HSLuv with an alpha component. See the Hsluva
implementation in
Alpha
.
Linear HSV with an alpha component. See the Hsva
implementation in
Alpha
.
Linear HWB with an alpha component. See the Hwba
implementation in
Alpha
.
CIE L*a*b* (CIELAB) with an alpha component. See the Laba
implementation in Alpha
.
CIE L*C*h° with an alpha component. See the Lcha
implementation in
Alpha
.
CIE L*C*uv h°uv with an alpha component. See the Lchuva
implementation in
Alpha
.
CIE L*u*v* (CIELUV) with an alpha component. See the Luva
implementation in Alpha
.
A 9 element array representing a 3x3 matrix.
Oklab with an alpha component. See the Oklaba
implementation in
Alpha
.
Oklch with an alpha component. See the Oklcha
implementation in
Alpha
.
CIE 1931 XYZ with an alpha component. See the Xyza
implementation in
Alpha
.
CIE 1931 Yxy (xyY) with an alpha component. See the Yxya
implementation
in Alpha
.