Crate cosmic::cosmic_theme::palette
source · 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.
§Where Do I Start?
The sections below give an overview of how the types in this library work,
including color conversion. If you want to get your hands dirty, you’ll
probably want to start with Srgb
or Srgba
. They are aliases for the
more generic Rgb
type and represent sRGB(A), the most common
RGB format in images and tools. Their documentation has more details and
examples.
The documentation for each module and type goes deeper into their concepts. Here are a few you may want to read:
Rgb
- For getting started with RGB values.Alpha
- For more details on transparency.convert
- Describes the conversion traits and how to use and implement them.cast
- Describes how to cast color types to and from other data formats, such as arrays and unsigned integers.color_difference
- Describes different ways of measuring the difference between colors.
§Type Safety for Colors
Digital colors are not “just RGB”, and not even RGB is “just RGB”. There are multiple representations of color, with a variety of pros and cons, and multiple standards for how to encode and decode them. Palette represents these “color spaces” as separate types for increased expressiveness and to prevent mistakes.
Taking RGB as an example, it’s often stored or displayed as “gamma
corrected” values, meaning that a non-linear function has been applied to
its values. This encoding is not suitable for all kinds of calculations
(such as rescaling) and will give visibly incorrect results. Functions that
require linear RGB can therefore request, for example, LinSrgb
as their
input type.
// Srgb is an alias for Rgb<Srgb, T>, which is what most pictures store.
// LinSrgb is an alias for Rgb<Linear<Srgb>, T>, better for color manipulation.
use palette::{Srgb, LinSrgb};
fn do_something(a: LinSrgb, b: LinSrgb) -> LinSrgb {
// ...
}
let orangeish = Srgb::new(1.0, 0.6, 0.0);
let blueish = Srgb::new(0.0, 0.2, 1.0);
let result = do_something(orangeish, blueish); // Does not compile
The colors will have to be decoded before being used in the function:
// Srgb is an alias for Rgb<Srgb, T>, which is what most pictures store.
// LinSrgb is an alias for Rgb<Linear<Srgb>, T>, better for color manipulation.
use palette::{Srgb, LinSrgb};
fn do_something(a: LinSrgb, b: LinSrgb) -> LinSrgb {
// ...
}
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 result = do_something(orangeish, blueish);
See the rgb module for a deeper dive into RGB and (non-)linearity.
§Color Spaces and Conversion
As the previous section mentions, there are many different ways of representing colors. These “color spaces” are represented as different types in Palette, each with a description of what it is and how it works. Most of them also have two type parameters for customization:
- The component type (
T
) that decides which number type is used. The default isf32
, butu8
,f64
, and any other type that implement the required traits will work. Including SIMD types in many cases. - The reference white point (
W
) or standard (S
) that affects the range, encoding or display properties of the color. This varies between color spaces and can usually be left as its default or be set via a type alias. For example, theSrgb
andLinSrgb
type aliases are both variants of theRgb
type, but with different standard (S
) types.
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, ShiftHue, 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 would just be unused memory space. Palette has
therefore adopted a structure where the transparency component (alpha) is
attachable using the Alpha
type. This approach has shown to be very
modular and easy to maintain, compared to having transparent copies of each
type.
An additional benefit is allowing operations to selectively affect the alpha component:
// Each color type has a transparent alias that ends with "a" for "alpha"
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
There’s also PreAlpha
that represents pre-multiplied
alpha (also known as alpha masked colors). It’s commonly used in color
blending and composition.
§Images and Buffers
Oftentimes, pixel data is stored in a plain array or slice such as a [u8; 3]
. The cast
module allows for easy conversion between Palette colors
and arrays or slices. This also helps when working with other crates or
systems. Here’s an example of how the pixels in an image from the image
crate can be worked with as Srgb<u8>
:
use image::RgbImage;
use palette::{Srgb, Oklab, cast::FromComponents, Lighten, IntoColor, FromColor};
fn lighten(image: &mut RgbImage, amount: f32) {
// RgbImage can be dereferenced as [u8], allowing us to cast it as a
// component slice to sRGB with u8 components.
for pixel in <&mut [Srgb<u8>]>::from_components(&mut **image) {
// Converting to linear sRGB with f32 components, and then to Oklab.
let color: Oklab = pixel.into_linear::<f32>().into_color();
let lightened_color = color.lighten(amount);
// Converting back to non-linear sRGB with u8 components.
*pixel = Srgb::from_linear(lightened_color.into_color());
}
}
Some of the conversions are also implemented on the color types as From
,
TryFrom
, Into
, TryFrom
and AsRef
. This example shows how from
can
be used to convert a [u8;3]
into a Palette color, into_format
converts
from Srgb<u8>
to Srgb<f32>
, and finally into
converts back from a
Palette color back to a [u8;3]
:
use approx::assert_relative_eq;
use palette::Srgb;
let buffer = [255, 0, 255];
let srgb = Srgb::from(buffer);
assert_eq!(srgb, Srgb::<u8>::new(255u8, 0, 255));
let srgb_float: Srgb<f32> = srgb.into_format();
assert_relative_eq!(srgb_float, Srgb::new(1.0, 0.0, 1.0));
let array: [u8; 3] = srgb_float.into_format().into();
assert_eq!(array, buffer);
§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, cast::ComponentsAsMut};
// This works for any color type (not only RGB) that can have the
// buffer element type as component.
let color_buffer: &mut [Srgb<u8>] = image_buffer.components_as_mut();
- 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.
Modules§
- Types related to transparent colors.
- Traits for working with angular values, such as for in hues.
- Color blending and blending equations.
- Traits for abstracting over Boolean types.
- Types for the CIE CAM16 color appearance model.
- Traits and functions for casting colors to and from other data types.
- Convert colors from one reference white point to another
- Algorithms for calculating the difference between colors.
- Traits related to traditional color theory.
- Traits for converting between color spaces.
- Number and color encoding traits, types and standards.
- Types for the HSL color space.
- Types for the HSLuv color space.
- Types for the HSV color space.
- Hues and hue related types.
- Types for the HWB color space.
- Types for the CIE L*a*b* (CIELAB) color space.
- Types for the CIE L*C*h° color space.
- Types for the CIE L*C*uv h°uv color space.
- Types for luma and luminance (grayscale) values.
- Types for the CIE L*u*v* (CIELUV) color space.
- A collection of named color constants. Can be toggled with the
"named"
and"named_from_str"
Cargo features. - Traits for abstracting over numeric types.
- Types for the Okhsl color space.
- Types for the Okhsv color space.
- Types for the Okhwb color space.
- Types for the Oklab color space.
- Types for the Oklch color space.
- Types for the RGB color space, including spaces and standards.
- Utilities for serializing and deserializing with
serde
. - Traits for working with stimulus colors and values, such as RGB and XYZ.
- Defines the tristimulus values of the CIE Illuminants.
- Types for the CIE 1931 XYZ color space.
- Types for the CIE 1931 Yxy (xyY) color space.
Structs§
- An alpha component wrapper for colors, for adding transparency.
- A scope guard that restores the guarded colors to their original type when dropped.
- 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.
- A Hue/Saturation/Lightness representation of
Oklab
in thesRGB
color space. - A Hue/Saturation/Value representation of
Oklab
in thesRGB
color space. - The Oklab color space.
- A hue type for the Oklab color space.
- Oklch, a polar version of Oklab.
- A hue type for the RGB family of color spaces.
- The CIE 1931 XYZ color space.
- The CIE 1931 Yxy (xyY) color space.
Traits§
- Extension trait for fixed size arrays.
- An operator for restricting a color’s components to their expected ranges.
- An assigning operator for restricting a color’s components to their expected ranges.
- Color
Difference Deprecated A trait for calculating the color difference between two colors. - Operators for darkening a color;
- Assigning operators for darkening a color;
- Operator for decreasing the saturation (or chroma) of a color.
- Assigning operator for decreasing the saturation (or chroma) of a color.
- A trait for converting one color from another, in a possibly lossy way.
- Temporarily convert colors in place.
- A trait for colors where a hue may be calculated.
- A trait for converting a color into another, in a possibly lossy way.
- Temporarily convert colors in place. The
Into
counterpart toFromColorMut
. - Checks if color components are within their expected range bounds.
- Operators for lightening a color.
- Assigning operators for lightening a color.
- Linear color interpolation of two colors.
- Assigning linear color interpolation of two colors.
- Temporary helper trait for getting an array type of size
N + 1
. - Relative
Contrast Deprecated A trait for calculating relative contrast between two colors. - Operator for increasing the saturation (or chroma) of a color.
- Assigning operator for increasing the saturation (or chroma) of a color.
- Change the hue of a color to a specific value without moving.
- Operator for increasing or decreasing the hue by an amount.
- Assigning operator for increasing or decreasing the hue by an amount.
- A trait for color types that can have or be given transparency (alpha channel).
- Change the hue of a color to a specific value.
Functions§
- contrast_
ratio Deprecated Calculate the ratio between twoluma
values.
Type Aliases§
- Gamma 2.2 encoded luminance.
- Gamma 2.2 encoded luminance with an alpha component.
- Gamma 2.2 encoded sRGB.
- Gamma 2.2 encoded sRGB with an alpha component.
- Linear HSL with an alpha component. See the
Hsla
implementation inAlpha
. - HSLuv with an alpha component. See the
Hsluva
implementation inAlpha
. - Linear HSV with an alpha component. See the
Hsva
implementation inAlpha
. - Linear HWB with an alpha component. See the
Hwba
implementation inAlpha
. - CIE L*a*b* (CIELAB) with an alpha component. See the
Laba
implementation inAlpha
. - CIE L*C*h° with an alpha component. See the
Lcha
implementation inAlpha
. - CIE L*C*uv h°uv with an alpha component. See the
Lchuva
implementation inAlpha
. - Linear luminance.
- Linear luminance with an alpha component.
- Linear sRGB.
- Linear sRGB with an alpha component.
- CIE L*u*v* (CIELUV) with an alpha component. See the
Luva
implementation inAlpha
. - A 9 element array representing a 3x3 matrix.
- Okhsl with an alpha component.
- Okhsv with an alpha component. See the
Okhsva
implementation inAlpha
. - Okhwb with an alpha component. See the
Okhwba
implementation inAlpha
. - Oklab with an alpha component.
- Oklch with an alpha component. See the
Oklcha
implementation inAlpha
. - Non-linear sRGB, the most common RGB input/output format.
- sRGB encoded luminance.
- sRGB encoded luminance with an alpha component.
- Non-linear sRGB with an alpha component.
- CIE 1931 XYZ with an alpha component. See the
Xyza
implementation inAlpha
. - CIE 1931 Yxy (xyY) with an alpha component. See the
Yxya
implementation inAlpha
.