Wacton.Unicolour 4.1.0

There is a newer version of this package available.
See the version list below for details.
dotnet add package Wacton.Unicolour --version 4.1.0
NuGet\Install-Package Wacton.Unicolour -Version 4.1.0
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Wacton.Unicolour" Version="4.1.0" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add Wacton.Unicolour --version 4.1.0
#r "nuget: Wacton.Unicolour, 4.1.0"
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install Wacton.Unicolour as a Cake Addin
#addin nuget:?package=Wacton.Unicolour&version=4.1.0

// Install Wacton.Unicolour as a Cake Tool
#tool nuget:?package=Wacton.Unicolour&version=4.1.0


GitHub GitLab NuGet pipeline status tests passed coverage report

Unicolour is a .NET library written in C# for working with colour:

  • Colour space conversion
  • Colour mixing / colour interpolation
  • Colour difference / colour distance
  • Colour gamut mapping
  • Colour chromaticity
  • Colour temperature
  • Wavelength attributes

Targets .NET Standard 2.0 for use in .NET 5.0+, .NET Core 2.0+ and .NET Framework 4.6.1+ applications.


  1. 🧭 Overview
  2. 🔆 Installation
  3. Quickstart
  4. 🌈 Features
  5. 💡 Configuration
  6. Examples
  7. 🔮 Datasets

🧭 Overview

A Unicolour encapsulates a single colour and its representation across different colour spaces. It can be used to mix and compare colours, as well as other useful tools for working with colour.

Supported colour spaces

RGB · Linear RGB · HSB/HSV · HSL · HWB · CIEXYZ · CIExyY · CIELAB · CIELChab · CIELUV · CIELChuv · HSLuv · HPLuv · ICTCP · Jzazbz · JzCzhz · Oklab · Oklch · CIECAM02 · CAM16 · HCT

Unicolour pink = new("#FF1493");
Console.WriteLine(pink.Oklab); // 0.65 +0.26 -0.01

This library was initially written for personal projects since existing libraries had complex APIs, missing features, or inaccurate conversions. The goal of this library is to be accurate, intuitive, and easy to use. Although performance is not a priority, conversions are only calculated once; when first evaluated (either on access or as part of an intermediate conversion step) the result is stored for future use.

Unicolour also extensively tested, including verification of roundtrip conversions, validation using known colour values, and 100% line coverage and branch coverage.

🔆 Installation

  1. Install the package from NuGet
dotnet add package Wacton.Unicolour
  1. Import the package
using Wacton.Unicolour;
  1. Use the package
Unicolour colour = new(ColourSpace.Rgb255, 192, 255, 238);

⚡ Quickstart

The simplest way to get started is to make a Unicolour and use it to see how the colour is represented in a different colour space.

var cyan = new Unicolour("#00FFFF");
Console.WriteLine(cyan.Hsl); // 180.0° 100.0% 50.0%

var yellow = new Unicolour(ColourSpace.Rgb255, 255, 255, 0);
Console.WriteLine(yellow.Hex); // #FFFF00

Colours can be mixed or interpolated using any colour space.

var red = new Unicolour(ColourSpace.Rgb, 1.0, 0.0, 0.0);
var blue = new Unicolour(ColourSpace.Hsb, 240, 1.0, 1.0);

/* RGB: [1, 0, 0] ⟶ [0, 0, 1] = [0.5, 0, 0.5] */
var purple = red.Mix(blue, ColourSpace.Rgb);
Console.WriteLine(purple.Rgb); // 0.50 0.00 0.50
Console.WriteLine(purple.Hex); // #800080

/* HSL: [0, 1, 0.5] ⟶ [240, 1, 0.5] = [300, 1, 0.5] */
var magenta = red.Mix(blue, ColourSpace.Hsl); 
Console.WriteLine(magenta.Rgb); // 1.00 0.00 1.00
Console.WriteLine(magenta.Hex); // #FF00FF

The difference or distance between colours can be calculated using any delta E metric.

var white = new Unicolour(ColourSpace.Oklab, 1.0, 0.0, 0.0);
var black = new Unicolour(ColourSpace.Oklab, 0.0, 0.0, 0.0);
var difference = white.Difference(black, DeltaE.Ciede2000);
Console.WriteLine(difference); // 100.0000

Other useful colour information is available, such as chromaticity coordinates, temperature, and dominant wavelength..

var equalTristimulus = new Unicolour(ColourSpace.Xyz, 0.5, 0.5, 0.5);
Console.WriteLine(equalTristimulus.Chromaticity.Xy); // (0.3333, 0.3333)
Console.WriteLine(equalTristimulus.Chromaticity.Uv); // (0.2105, 0.3158)
Console.WriteLine(equalTristimulus.Temperature); // 5455.5 K (Δuv -0.00442)
Console.WriteLine(equalTristimulus.DominantWavelength); // 596.1

Reference white points (e.g. D65) and the RGB model (e.g. sRGB) can be configured.

🌈 Features

Convert between colour spaces

Unicolour calculates all transformations required to convert from one colour space to any other, so there is no need to manually chain multiple functions and removes the risk of rounding errors.

Unicolour colour = new(ColourSpace.Rgb255, 192, 255, 238);
var (l, c, h) = colour.Oklch.Triplet;
Colour space Enum Property
RGB (0–255) ColourSpace.Rgb255 .Rgb.Byte255
RGB ColourSpace.Rgb .Rgb
Linear RGB ColourSpace.RgbLinear .RgbLinear
HSB/HSV ColourSpace.Hsb .Hsb
HSL ColourSpace.Hsl .Hsl
HWB ColourSpace.Hwb .Hwb
CIEXYZ ColourSpace.Xyz .Xyz
CIExyY ColourSpace.Xyy .Xyy
CIELAB ColourSpace.Lab .Lab
CIELChab ColourSpace.Lchab .Lchab
CIELUV ColourSpace.Luv .Luv
CIELChuv ColourSpace.Lchuv .Lchuv
HSLuv ColourSpace.Hsluv .Hsluv
HPLuv ColourSpace.Hpluv .Hpluv
ICTCP ColourSpace.Ictcp .Ictcp
Jzazbz ColourSpace.Jzazbz .Jzazbz
JzCzhz ColourSpace.Jzczhz .Jzczhz
Oklab ColourSpace.Oklab .Oklab
Oklch ColourSpace.Oklch .Oklch
CIECAM02 ColourSpace.Cam02 .Cam02
CAM16 ColourSpace.Cam16 .Cam16
HCT ColourSpace.Hct .Hct
HCT ColourSpace.Hct .Hct

Mix colours

Two colours can be mixed by interpolating between them in any colour space, taking into account cyclic hue, interpolation distance, and alpha premultiplication.

var red = new Unicolour(ColourSpace.Rgb, 1.0, 0.0, 0.0);
var blue = new Unicolour(ColourSpace.Hsb, 240, 1.0, 1.0);
var magenta = red.Mix(blue, ColourSpace.Hsl, 0.5, HueSpan.Decreasing); 
var green = red.Mix(blue, ColourSpace.Hsl, 0.5, HueSpan.Increasing); 
Hue span Enum
Shorter 👈 default HueSpan.Shorter
Longer HueSpan.Longer
Increasing HueSpan.Increasing
Decreasing HueSpan.Decreasing

Compare colours

Two methods of comparing colours are available: contrast and difference. Difference is calculated according to a specific delta E (ΔE) metric.

var red = new Unicolour(ColourSpace.Rgb, 1.0, 0.0, 0.0);
var blue = new Unicolour(ColourSpace.Hsb, 240, 1.0, 1.0);
var contrast = red.Contrast(blue);
var difference = red.Difference(blue, DeltaE.Cie76);
Delta E Enum
ΔE76 (CIE76) DeltaE.Cie76
ΔE94 (CIE94) - graphic arts DeltaE.Cie94
ΔE94 (CIE94) - textiles DeltaE.Cie94Textiles
ΔE00 (CIEDE2000) DeltaE.Ciede2000
ΔECMC (CMC l:c) - 2:1 acceptability DeltaE.CmcAcceptability
ΔECMC (CMC l:c) - 1:1 perceptibility DeltaE.CmcPerceptibility
ΔEITP DeltaE.Itp
ΔEz DeltaE.Z
ΔEHyAB DeltaE.Hyab
ΔEOK DeltaE.Ok
ΔECAM02 DeltaE.Cam02
ΔECAM16 DeltaE.Cam16

Map colour into display gamut

Colours that cannot be displayed with the configured RGB model can be mapped to the closest in-gamut colour. The gamut mapping algorithm conforms to CSS specifications.

var outOfGamut = new Unicolour(ColourSpace.Rgb, -0.51, 1.02, -0.31);
var inGamut = colour.MapToGamut();

Convert between colour and temperature

Correlated colour temperature (CCT) and delta UV (∆uv) can be obtained from a colour, and can be used to create a colour. CCT from 500 K to 1,000,000,000 K is supported but only CCT from 1,000 K to 20,000 K is guaranteed to have high accuracy.

var chromaticity = new Chromaticity(0.3457, 0.3585);
var d50 = new Unicolour(chromaticity);
var (cct, duv) = d50.Temperature;

var temperature = new Temperature(6504, 0.0032);
var d65 = new Unicolour(temperature);
var (x, y) = d65.Chromaticity;

Create colour from spectral power distribution

A spectral power distribution (SPD) can be used to create a colour. Wavelengths should be provided in either 1 nm or 5 nm intervals, and omitted wavelengths are assumed to have zero spectral power.

var spd = new Spd
    { 575, 0.5 }, 
    { 580, 1.0 }, 
    { 585, 0.5 }
var intenseYellow = new Unicolour(spd);

Get wavelength attributes

The dominant wavelength and excitation purity of a colour can be derived using the spectral locus. Wavelengths from 360 nm to 700 nm are supported.

var chromaticity = new Chromaticity(0.1, 0.8);
var hyperGreen = new Unicolour(chromaticity);
var dominantWavelength = hyperGreen.DominantWavelength;
var excitationPurity = hyperGreen.ExcitationPurity;

Detect imaginary colours

Whether or not a colour is imaginary — one that cannot be produced by the eye — can be determined using the spectral locus. They are the colours that lie outside of the horseshoe-shaped curve of the CIE xy chromaticity diagram.

var chromaticity = new Chromaticity(0.05, 0.05);
var impossibleBlue = new Unicolour(chromaticity);
var isImaginary = impossibleBlue.IsImaginary;

Simulate colour vision deficiency

A new Unicolour can be generated that simulates how a colour appears to someone with a particular colour vision deficiency (CVD) or colour blindness.

var colour = new Unicolour(ColourSpace.Rgb255, 192, 255, 238);
var noRed = colour.SimulateProtanopia();
Colour vision deficiency Method
Protanopia (no red perception) SimulateProtanopia()
Deuteranopia (no green perception) SimulateDeuteranopia()
Tritanopia (no blue perception) SimulateTritanopia()
Achromatopsia (no colour perception) SimulateAchromatopsia()

Handle invalid values

It is possible for invalid or unreasonable values to be used in calculations, either because conversion formulas have limitations or because a user passes them as arguments. Although these values don't make sense to use, they should propagate safely and avoid triggering exceptions.

var bad1 = new Unicolour(ColourSpace.Oklab, double.NegativeInfinity, double.NaN, double.Epsilon);
var bad2 = new Unicolour(ColourSpace.Cam16, double.NaN, double.MaxValue, double.MinValue);
var bad3 = bad1.Mix(bad2, ColourSpace.Hct, amount: double.PositiveInfinity);

Sensible defaults, highly configurable

Unicolour uses sRGB as the default RGB model and standard illuminant D65 (2° observer) as the default white point of all colour spaces, ensuring consistency and a suitable starting point for simple applications. These can be overridden using the Configuration parameter, and common configurations have been predefined.

var defaultConfig = new Configuration(RgbConfiguration.StandardRgb, XyzConfiguration.D65);
var colour = new Unicolour(defaultConfig, ColourSpace.Rgb255, 192, 255, 238);

💡 Configuration

The Configuration parameter can be used to customise how colour is processed.

Example configuration with predefined Rec. 2020 RGB & illuminant D50 (2° observer) XYZ:

Configuration config = new(RgbConfiguration.Rec2020, XyzConfiguration.D50);
Unicolour colour = new(config, ColourSpace.Rgb255, 204, 64, 132);

Example configuration with manually defined wide-gamut RGB & illuminant C (10° observer) XYZ:

var rgbConfig = new RgbConfiguration(
    chromaticityR: new(0.7347, 0.2653),
    chromaticityG: new(0.1152, 0.8264),
    chromaticityB: new(0.1566, 0.0177),
    whitePoint: Illuminant.D50.GetWhitePoint(Observer.Degree2),
    fromLinear: value => Math.Pow(value, 1 / 2.19921875),
    toLinear: value => Math.Pow(value, 2.19921875)

var xyzConfig = new XyzConfiguration(Illuminant.C, Observer.Degree10);

var config = new Configuration(rgbConfig, xyzConfig);
var colour = new Unicolour(config, ColourSpace.Rgb255, 202, 97, 143);

A Configuration is composed of sub-configurations. Each sub-configuration is optional and will fall back to a sensible default if not provided.


Defines the RGB model, most commonly used to specify a wider gamut than standard RGB (sRGB).

  • Predefined
    • sRGB 👈 default
    • Display P3
    • Rec. 2020
    • A98
    • ProPhoto
  • Parameters
    • Red, green, and blue chromaticity coordinates
    • Reference white point
    • Companding functions to and from linear values


Defines the white point for colour spaces that need no other configuration, as well as the observer to use for temperature calculations.

  • Predefined
    • D65 (2° observer) 👈 default
    • D50 (2° observer)
  • Parameters
    • Reference white point or illuminant
    • Observer


Defines the viewing conditions for CAM02 and CAM16, which take into account the surrounding environment to determine how a colour is perceived.

  • Predefined
    • sRGB (ambient illumination 64 lux, grey world assumption) 👈 default
    • HCT
  • Parameters
    • Reference white point
    • Adapting luminance
    • Background luminance

IctcpScalar & JzazbzScalar

There is ambiguity and no clear consensus about how XYZ values should be scaled before calculating ICTCP and Jzazbz. These scalars can be changed to match the behaviour of other implementations if needed.

White points

All colour spaces are impacted by the reference white point. Unicolour applies different reference white points to different sets of colour spaces, as shown in the table below. When a conversion to or from XYZ space involves a change in white point, a chromatic adaptation transform (CAT) is performed using the Bradford method.

White point configuration Affected colour spaces
RgbConfiguration RGB · Linear RGB · HSB/HSV · HSL · HWB
XyzConfiguration CIEXYZ · CIExyY · CIELAB · CIELChab · CIELUV · CIELChuv · HSLuv · HPLuv
CamConfiguration CIECAM02 · CAM16
None (always D65/2°) ICTCP · Jzazbz · JzCzhz · Oklab · Oklch · HCT

Convert between configurations

A Unicolour can be converted to a different configuration, in turn enabling conversions between different RGB models, XYZ white points, CAM viewing conditions, etc.

/* pure sRGB green */
var srgbConfig = new Configuration(RgbConfiguration.StandardRgb);
var srgbColour = new Unicolour(srgbConfig, ColourSpace.Rgb, 0, 1, 0);                         
Console.WriteLine(srgbColour.Rgb); // 0.00 1.00 0.00

/* ⟶ Display P3 */
var displayP3Config = new Configuration(RgbConfiguration.DisplayP3);
var displayP3Colour = srgbColour.ConvertToConfiguration(displayP3Config); 
Console.WriteLine(displayP3Colour.Rgb); // 0.46 0.99 0.30

/* ⟶ Rec. 2020 */
var rec2020Config = new Configuration(RgbConfiguration.Rec2020);
var rec2020Colour = displayP3Colour.ConvertToConfiguration(rec2020Config);
Console.WriteLine(rec2020Colour.Rgb); // 0.57 0.96 0.27

✨ Examples

This repository contains multiple projects to show examples of Unicolour being used to create:

  1. Images of gradients
  2. Diagrams of colour data
  3. A colourful console application


Example code to create images of gradients using 📷 SixLabors.ImageSharp can be seen in the Example.Gradients project.

Gradients generated through different colour spaces, created with Unicolour
Gradients generated through each colour space
Visualisation of temperature from 1,000 K to 13,000 K, created with Unicolour
Visualisation of temperature from 1,000 K to 13,000 K
Colour spectrum rendered with different colour vision deficiencies, created with Unicolour
Colour spectrum rendered with different colour vision deficiencies
Demonstration of interpolating from red to transparent to blue, with and without premultiplied alpha, created with Unicolour
Demonstration of interpolating from red to transparent to blue, with and without premultiplied alpha


Example code to create diagrams of colour data using 📈 ScottPlot can be seen in the Example.Diagrams project.

CIE xy chromaticity diagram with sRGB gamut, created with Unicolour
CIE xy chromaticity diagram with sRGB gamut
CIE xy chromaticity diagram with Planckian or blackbody locus, created with Unicolour
CIE xy chromaticity diagram with Planckian or blackbody locus
CIE xy chromaticity diagram with spectral locus plotted at 1 nm intervals, created with Unicolour
CIE xy chromaticity diagram with spectral locus plotted at 1 nm intervals
CIE 1960 colour space, created with Unicolour
CIE 1960 colour space
CIE 1960 colour space with Planckian or blackbody locus, created with Unicolour
CIE 1960 colour space with Planckian or blackbody locus


Example code to create a colourful console application using ⌨️ Spectre.Console can be seen in the Example.Console project.

Console application showing colour information from hex value, created with Unicolour
Console application showing colour information from hex value

🔮 Datasets

Some colour datasets have been compiled for convenience and are available as a NuGet package.

Commonly used sets of colours:

Colour data used in academic literature:

Example usage:

  1. Install the package from NuGet
dotnet add package Wacton.Unicolour.Datasets
  1. Import the package
using Wacton.Unicolour.Datasets;
  1. Reference the predefined Unicolour
var unicolour = Css.DeepPink;

Wacton.Unicolour is licensed under the MIT License, copyright © 2022-2024 William Acton.

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • .NETStandard 2.0

    • No dependencies.

NuGet packages (3)

Showing the top 3 NuGet packages that depend on Wacton.Unicolour:

Package Downloads

Powerfull binary search set of nodes for vl, to interpolate any kind of type.


Datasets for use with 🌈 Wacton.Unicolour


Unicolour for VL

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
4.4.0 467 5/9/2024
4.3.0 391 4/17/2024
4.2.0 582 3/24/2024
4.1.0 592 2/13/2024
4.0.0 379 1/27/2024
3.0.0 1,068 11/5/2023
2.5.0 482 10/22/2023
2.4.0 314 10/7/2023
2.3.0 169 9/24/2023
2.2.0 3,241 6/9/2023
2.1.0 356 4/24/2023
2.0.0 266 2/27/2023
1.11.0 298 1/21/2023
1.10.0 288 1/16/2023
1.9.0 309 1/4/2023
1.8.0 294 12/10/2022
1.7.0 431 8/6/2022
1.6.2 428 5/5/2022
1.6.1 401 5/5/2022
1.6.0 404 5/5/2022
1.5.0 412 4/30/2022
1.4.0 408 4/16/2022
1.3.0 412 4/5/2022
1.2.0 406 3/28/2022
1.1.1 387 3/21/2022
1.1.0 399 3/21/2022
1.0.0 437 2/8/2022
1.0.0-alpha.3 134 2/1/2022
1.0.0-alpha.2 135 1/24/2022
1.0.0-alpha.1 129 1/24/2022

Add dominant wavelength, excitation purity, and imaginary colours