Skip to main content

Crate colr

Crate colr 

Source
Expand description

§colr

Latest Version docs Minimum Supported Rust Version

A general purpose, type-safe color library.

Color spaces, transfer functions, chromatic adaptation, and channel layouts are encoded in the type system. Mixing an sRGB color with a Display P3 color is a compile error unless you convert explicitly. All colorimetric matrices are derived at compile time. Colors themselves are generic over their storage representation, which itself is generic over its layout.

§Usage

use colr::{Color, Srgb, Rgb, Oklab, Oklch, XyzD65};

// Construct an sRGB color. Layout is part of the type.
let srgb: Color<[f32; 3], Srgb<Rgb>> = Color::new_unchecked([0.8, 0.4, 0.2]);

// Convert to Oklab for perceptual work. The path goes through XYZ
// automatically when you chain transforms. All matrices are compile-time.
let lab: Color<[f32; 3], Oklab> = srgb
    .transform::<Color<[f32; 3], XyzD65>>()
    .transform();

// Pull out chroma and hue, reduce chroma, put it back.
let lch: Color<[f32; 3], Oklch> = lab.transform();
let [l, c, h] = lch.inner();
let muted: Color<[f32; 3], Oklch> = Color::new_unchecked([l, c * 0.5, h]);

// Converting from a large space back to sRGB can produce out-of-gamut
// values. try_transform gives you the error and the clamped result.
let result = muted
    .transform::<Color<[f32; 3], Oklab>>()
    .transform::<Color<[f32; 3], XyzD65>>()
    .try_transform::<Color<[f32; 3], Srgb<Rgb>>>();

let final_color = result.unwrap_or_else(|e| e.clamped);

§Color spaces

§Perceptual spaces

TypeDescription
LabCIE 1976 L*a*b* parameterized by reference white W
LChPolar form of L*a*b*
OklabOklab (Ottosson 2020); improved hue linearity over Lab
OklchPolar form of Oklab

Lab and LCh are parameterized by illuminant: Lab<D65>, Lab<D50>, and so on. Oklab and Oklch have D65 baked into the specification. The aliases LabD65 and LChD65 cover the common case.

§RGB spaces

AliasPrimariesTransfer functionWhite
SrgbsRGB/Rec709sRGBD65
LinearSrgbsRGB/Rec709LinearD65
Rec709sRGB/Rec709Rec. 709D65
DisplayP3P3sRGBD65
LinearP3P3LinearD65
Hdr10Rec. 2020PQ (ST 2084)D65
HlgRec. 2020HLG (BT.2100)D65
LinearRec2020Rec. 2020LinearD65
AcesCgAP1LinearACES
Aces2065AP0LinearACES
AcesCcAP1ACEScc logACES
AcesCctAP1ACEScct log+toeACES
ProPhotoProPhotogamma 1.8D50
LinearProPhotoProPhotoLinearD50
DciP3DCI-P3gamma 2.6DCI

Each alias defaults to RGBA layout. Alternate layouts are selected with the type parameter: Srgb<Rgb>, Srgb<Bgra>, and so on.

§XYZ spaces

AliasIlluminantTypical use
XyzD65D65sRGB, P3, Rec. 2020 connection space
XyzD50D50ICC profile connection space
XyzAcesACES whiteACES pipeline connection space

Conversions between different XYZ illuminants apply Bradford chromatic adaptation, computed at compile time.

§Planned spaces

CMYK support is planned. The intent is to support ICC-described CMYK profiles as a runtime context parameter on the transform, consistent with how other context-parameterized transforms work in this library. There is no timeline for this yet.

If a space from an open standard is not listed above, please open an issue.

§Transforms

Use transform for conversions that are always in range, and try_transform for conversions into a bounded space where the source may not fit.

MethodWhen to use
transformInfallible: RGB to XYZ, layout reorders, Lab
try_transformFallible: XYZ or large gamut to bounded RGB
transform_viaTwo steps through an intermediate, both infallible
try_transform_viaTwo steps; returns error if either leg clips

try_transform returns Result<Dst, OutOfGamut<Dst>>. The OutOfGamut value always contains the clamped approximation, so a usable result is always present regardless of whether you propagate the error:

let value = src.try_transform::<Color<[f32; 3], Srgb<Rgb>>>().unwrap_or_else(|e| e.clamped);

§Transform context

Most transforms are fully static and require no runtime data. The Ctx parameter on Transform exists for cases where runtime data is needed:

TransformCtx
sRGB to XYZ()
XYZ to CAM16-UCSViewingConditions
Relative to absolute XYZf32 (cd/m2)
Device CMYK to XYZ (planned)IccProfile

Implement Transform<Src, YourCtx> for custom transforms.

§Channel layouts

Layout is a type parameter, not a runtime tag. The compiler distinguishes RGBA from BGRA and will not accept one where the other is expected.

TypeOrder
RgbaR G B A
BgraB G R A
ArgbA R G B
AbgrA B G R
RgbR G B
BgrB G R

Layout reorders are infallible and compile to a shuffle with no arithmetic:

let bgra: Color<[f32; 4], Srgb<Bgra>> = rgba.transform();

§Chromatic adaptation

Four methods are provided. Bradford is used automatically by all built-in conversions and is the correct default for standard RGB work.

TypeStandard
BradfordICC, ACES, CSS Color Level 4
Cat02CIECAM02, ICC v4 appearance models
Cat16CAM16
VonKriesLegacy and reference

Custom adaptation matrices can be computed at compile time with adapt::<A>.

§no_std support

no_std support is available with the libm feature. Either std or libm must be enabled; the crate will not compile without at least one.

[dependencies]
colr = { version = "0.1", default-features = false, features = ["libm"] }

To support both std and no_std builds in a library crate:

[features]
default = ["std"]
std     = ["colr/std"]
libm    = ["colr/libm"]

[dependencies]
colr = { version = "0.1", default-features = false }

§Optional features

std is the default feature and enables standard library math functions. The remaining features are opt-in.

FeatureDescription
glamAdds VecN types as valid color impls
libmUses libm math functions for no_std targets

§Adding a custom primary set

Implement Primaries for your type and register it with the provided macros. All matrices are derived at compile time from the chromaticity coordinates and white point you supply.

use colr::primaries::{Primaries, derive_rgb_to_xyz};
use colr::illuminant::{Illuminant, D65};
use colr::math::Mat3;

pub struct CustomPrimaries;

const CUSTOM_TO_XYZ: Mat3 = derive_rgb_to_xyz(
    [0.680, 0.320],  // red
    [0.265, 0.690],  // green
    [0.150, 0.060],  // blue
    D65::WHITE_POINT_XYZ,
);

impl Primaries for CustomPrimaries {
    type Native = D65;
    const R: [f32; 2] = [0.680, 0.320];
    const G: [f32; 2] = [0.265, 0.690];
    const B: [f32; 2] = [0.150, 0.060];
    const TO_XYZ_NATIVE:  Mat3 = CUSTOM_TO_XYZ;
    const FROM_XYZ_NATIVE: Mat3 = Mat3::invert(&CUSTOM_TO_XYZ);
}

Then call impl_native! and any needed impl_adapted! to register the XYZ connection hubs for your target illuminant. See src/primaries.rs for examples.

§Design notes

All colorimetric matrices are derived in const fn at compile time, including RGB-to-XYZ, chromatic adaptation, and composed primaries-to-primaries transforms. There is no matrix inversion or multiplication at runtime, in any build profile.

Color<S, Sp> is #[repr(transparent)] over its storage type. The space is carried only as PhantomData. There is no runtime memory overhead from the type-level bookkeeping.

§Minimum Supported Rust Version (MSRV)

The minimum supported version of Rust for this crate is 1.85.

Edition 2024 requires Rust 1.85. Inline const {} blocks, used to evaluate transform matrices at compile time in generic contexts, stabilized in Rust 1.82.

§Contributing

This crate is early in development. Consider raising an issue if the crate doesn’t fit your needs, is missing any obvious functionality, or is unergonomic in any way.

Contributions are welcome for any color space or transfer function defined in an open standard. If a standard space is missing, please open an issue before implementing it so the approach can be agreed on first. Spaces from proprietary or closed formats belong in a separate crate.

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this work, as defined in the Apache-2.0 license, shall be dual licensed as below, without any additional terms or conditions.

§License

Licensed under either of

at your option.

Universal color library.

Provides compile-time-safe color space types, conversions, and storage formats. All colorimetric math is computed at compile time with zero runtime cost.

A color value is Color<S, Sp> where:

  • S is the storage type ([f32; 4], glam::Vec4)
  • Sp is the color space (Srgb, AcesCg, Xyz<D65>)

For RGB spaces the layout is a parameter of the space itself: RgbSpace<P, TF, L> where L defaults to Rgba.

Re-exports§

pub use adaptation::Bradford;
pub use adaptation::Cat02;
pub use adaptation::Cat16;
pub use adaptation::ChromaticAdaptation;
pub use adaptation::VonKries;
pub use illuminant::AcesWhitePoint;
pub use illuminant::D50;
pub use illuminant::D60;
pub use illuminant::D65;
pub use illuminant::DciWhite;
pub use illuminant::Illuminant;
pub use perceptual::LCh;
pub use perceptual::LChD65;
pub use perceptual::Lab;
pub use perceptual::LabD65;
pub use perceptual::Oklab;
pub use perceptual::Oklch;
pub use rgb::Abgr;
pub use rgb::Aces2065;
pub use rgb::AcesCc;
pub use rgb::AcesCct;
pub use rgb::AcesCg;
pub use rgb::Argb;
pub use rgb::Bgr;
pub use rgb::Bgra;
pub use rgb::ChannelMap;
pub use rgb::DciP3;
pub use rgb::DisplayP3;
pub use rgb::Hdr10;
pub use rgb::Hlg;
pub use rgb::LinearP3;
pub use rgb::LinearProPhoto;
pub use rgb::LinearRec2020;
pub use rgb::LinearSrgb;
pub use rgb::P3D65Gamma26;
pub use rgb::ProPhoto;
pub use rgb::Rec709;
pub use rgb::Rgb;
pub use rgb::RgbColorSpace;
pub use rgb::RgbSpace;
pub use rgb::Rgba;
pub use rgb::Srgb;
pub use spectral::Bispectral;
pub use spectral::IsBispectral;
pub use spectral::IsRadiance;
pub use spectral::IsReflectance;
pub use spectral::IsTransmittance;
pub use spectral::Radiance;
pub use spectral::Reflectance;
pub use spectral::SpectralKind;
pub use spectral::SpectralSpace;
pub use spectral::Transmittance;
pub use spectral::WavelengthGrid;
pub use transfer::AcesCcTf;
pub use transfer::AcesCctTf;
pub use transfer::DciP3Tf;
pub use transfer::HlgTf;
pub use transfer::IsDisplayReferred;
pub use transfer::IsLinearEncoding;
pub use transfer::IsSceneReferred;
pub use transfer::LinearTf;
pub use transfer::PqTf;
pub use transfer::ProPhotoTf;
pub use transfer::Rec709Tf;
pub use transfer::SrgbTf;
pub use transfer::TransferFunction;
pub use xyz::Xyz;
pub use xyz::XyzAces;
pub use xyz::XyzD50;
pub use xyz::XyzD65;

Modules§

adaptation
Chromatic adaptation transforms XYZ tristimulus values from one illuminant to another.
illuminant
CIE standard illuminants and reference white points.
math
Compile-time matrix arithmetic (Mat3) and transcendental math injection (MathState).
perceptual
Perceptual color spaces.
primaries
RGB primary sets and the PrimariesToXyz routing trait.
rgb
Standard RGB color spaces, channel layouts, and their transforms.
spectral
Spectral color spaces.
transfer
Signal encoding and decoding curves (transfer functions).
xyz
CIE 1931 XYZ color space parameterized by illuminant.

Structs§

Color
A color value in color space Sp carried by storage type S.
OutOfGamut
Returned when a transform produces values outside the target’s valid bounds.

Traits§

Absolute
Marks a ColorSpace where luminance has photometric units (cd/m2).
Asserts
Compatibility marker between two types.
ColorSpace
A color domain defined by a fixed set of channels.
Delta
Distance between two colors in ColorSpace Sp.
DisplayReferred
Marks a ColorSpace as display-referred.
LinearLight
Marks a ColorSpace as linear-light.
SceneReferred
Marks a ColorSpace as scene-referred.
Transform
Produce Self from a source color Src infallibly.
TryTransform
Produce Self from a source color Src, returning OutOfGamut if any channel clips.