Skip to content

Commit

Permalink
Merge branch 'hct' into 'main'
Browse files Browse the repository at this point in the history
Add HCT support

See merge request Wacton/Unicolour!32
  • Loading branch information
waacton committed Oct 22, 2023
2 parents 9a97741 + 425276a commit d64bd52
Show file tree
Hide file tree
Showing 101 changed files with 1,916 additions and 962 deletions.
9 changes: 7 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ A `Unicolour` encapsulates a single colour and its representation across differe
- Oklch
- CIECAM02
- CAM16
- HCT

<details>
<summary>Diagram of colour space relationships</summary>
Expand Down Expand Up @@ -58,7 +59,7 @@ Unicolour can be used to calculate colour difference via:
- ΔE<sub>CAM02</sub>
- ΔE<sub>CAM16</sub>

Simulations of colour vision deficiency (CVD) / colour blindness is supported for:
Simulation of colour vision deficiency (CVD) / colour blindness is supported for:
- Protanopia (no red perception)
- Deuteranopia (no green perception)
- Tritanopia (no blue perception)
Expand All @@ -70,7 +71,7 @@ These [can be overridden](#advanced-configuration-) using the `Configuration` pa
This library was initially written for personal projects since existing libraries had complex APIs or missing features.
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.
It is also [extensively tested](Unicolour.Tests), including comparisons against known colour values and other .NET libraries.
It is also [extensively tested](Unicolour.Tests), including verification of roundtrip conversions, validation using known colour values, and comparisons against other .NET libraries.

Targets [.NET Standard 2.0](https://docs.microsoft.com/en-us/dotnet/standard/net-standard?tabs=net-standard-2-0) for use in .NET 5.0+, .NET Core 2.0+ and .NET Framework 4.6.1+ applications.

Expand Down Expand Up @@ -98,6 +99,7 @@ Targets [.NET Standard 2.0](https://docs.microsoft.com/en-us/dotnet/standard/net
| Oklch | `Unicolour.FromOklch()` | `.Oklch` | `.InterpolateOklch()` |
| CIECAM02 | `Unicolour.FromCam02()` | `.Cam02` | `.InterpolateCam02()` |
| CAM16 | `Unicolour.FromCam16()` | `.Cam16` | `.InterpolateCam16()` |
| HCT | `Unicolour.FromHct()` | `.Hct` | `.InterpolateHct()` |

## How to use 🌈
1. Install the package from [NuGet](https://www.nuget.org/packages/Wacton.Unicolour/)
Expand Down Expand Up @@ -133,6 +135,7 @@ var unicolour = Unicolour.FromOklab(0.65, 0.26, -0.01);
var unicolour = Unicolour.FromOklch(0.65, 0.26, 356.9);
var unicolour = Unicolour.FromCam02(62.86, 40.81, -1.18);
var unicolour = Unicolour.FromCam16(62.47, 42.60, -1.36);
var unicolour = Unicolour.FromHct(358.2, 100.38, 55.96);
```

4. Get representations of a colour in different colour spaces:
Expand All @@ -156,6 +159,7 @@ var oklab = unicolour.Oklab;
var oklch = unicolour.Oklch;
var cam02 = unicolour.Cam02;
var cam16 = unicolour.Cam16;
var hct = unicolour.Hct;
```

5. Get properties of a colour
Expand Down Expand Up @@ -186,6 +190,7 @@ var interpolated = unicolour1.InterpolateOklab(unicolour2, 0.5);
var interpolated = unicolour1.InterpolateOklch(unicolour2, 0.5);
var interpolated = unicolour1.InterpolateCam02(unicolour2, 0.5);
var interpolated = unicolour1.InterpolateCam16(unicolour2, 0.5);
var interpolated = unicolour1.InterpolateHct(unicolour2, 0.5);
```

7. Compare colours:
Expand Down
1 change: 1 addition & 0 deletions Unicolour.Console/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ static Table GetTable(Unicolour unicolour)
table.AddRow("Oklch", $"{unicolour.Oklch}");
table.AddRow("Cam02", $"{unicolour.Cam02}");
table.AddRow("Cam16", $"{unicolour.Cam16}");
table.AddRow("Hct", $"{unicolour.Hct}");
return table;
}

Binary file modified Unicolour.Console/colour-info.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 3 additions & 1 deletion Unicolour.Example/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ void GenerateColourSpaceGradients()
{
const int columns = 3;
const int columnWidth = 800;
const int rows = 19;
const int rows = 20;
const int rowHeight = 100;

var purple = Unicolour.FromHsb(260, 1.0, 0.33);
Expand Down Expand Up @@ -55,6 +55,7 @@ Image<Rgba32> DrawColumn(Unicolour[] colourPoints)
var oklch = Gradient.Draw(("OKLCH", light), columnWidth, rowHeight, colourPoints, (start, end, distance) => start.InterpolateOklch(end, distance));
var cam02 = Gradient.Draw(("CAM02", light), columnWidth, rowHeight, colourPoints, (start, end, distance) => start.InterpolateCam02(end, distance));
var cam16 = Gradient.Draw(("CAM16", light), columnWidth, rowHeight, colourPoints, (start, end, distance) => start.InterpolateCam16(end, distance));
var hct = Gradient.Draw(("HCT", light), columnWidth, rowHeight, colourPoints, (start, end, distance) => start.InterpolateHct(end, distance));

var columnImage = new Image<Rgba32>(columnWidth, rowHeight * rows);
columnImage.Mutate(context => context
Expand All @@ -77,6 +78,7 @@ Image<Rgba32> DrawColumn(Unicolour[] colourPoints)
.DrawImage(oklch, new Point(0, rowHeight * 16), 1f)
.DrawImage(cam02, new Point(0, rowHeight * 17), 1f)
.DrawImage(cam16, new Point(0, rowHeight * 18), 1f)
.DrawImage(hct, new Point(0, rowHeight * 19), 1f)
);

return columnImage;
Expand Down
Binary file modified Unicolour.Example/gradients.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ namespace Wacton.Unicolour.Tests;
using NUnit.Framework;
using Wacton.Unicolour.Tests.Utils;

public static class CamConfigurationTests
public class ConfigureCamTests
{
[TestCase(Illuminant.A)]
[TestCase(Illuminant.C)]
Expand All @@ -15,7 +15,7 @@ public static class CamConfigurationTests
[TestCase(Illuminant.F2)]
[TestCase(Illuminant.F7)]
[TestCase(Illuminant.F11)]
public static void XyzWhitePointRoundTripViaCam02(Illuminant xyzIlluminant)
public void XyzWhitePointRoundTripViaCam02(Illuminant xyzIlluminant)
{
var initialXyzConfig = new XyzConfiguration(CamConfiguration.StandardRgb.WhitePoint);
var initialXyz = new Xyz(0.4676, 0.2387, 0.2974);
Expand All @@ -37,7 +37,7 @@ public static void XyzWhitePointRoundTripViaCam02(Illuminant xyzIlluminant)
[TestCase(Illuminant.F2)]
[TestCase(Illuminant.F7)]
[TestCase(Illuminant.F11)]
public static void XyzWhitePointRoundTripViaCam16(Illuminant xyzIlluminant)
public void XyzWhitePointRoundTripViaCam16(Illuminant xyzIlluminant)
{
var initialXyzConfig = new XyzConfiguration(CamConfiguration.StandardRgb.WhitePoint);
var initialXyz = new Xyz(0.4676, 0.2387, 0.2974);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
using Wacton.Unicolour.Datasets;
using Wacton.Unicolour.Tests.Utils;

public static class IctcpConfigurationTests
public class ConfigureIctcpTests
{
private static readonly WhitePoint D65WhitePoint = WhitePoint.From(Illuminant.D65);
private static readonly ColourTriplet XyzWhite = new(D65WhitePoint.X / 100.0, D65WhitePoint.Y / 100.0, D65WhitePoint.Z / 100.0);
Expand All @@ -20,7 +20,7 @@ public static class IctcpConfigurationTests
private static readonly Configuration Config203 = new(RgbConfiguration.Rec2020, XyzConfiguration.D65, ictcpScalar: 203);

[Test] // matches the behaviour of papers on Hung & Berns dataset (https://professional.dolby.com/siteassets/pdfs/ictcp_dolbywhitepaper_v071.pdf, figure 6)
public static void Rec2020RgbToIctcp100()
public void Rec2020RgbToIctcp100()
{
var red = Unicolour.FromXyz(Config100, HungBerns.RedRef.Xyz.Triplet.Tuple);
var blue = Unicolour.FromXyz(Config100, HungBerns.BlueRef.Xyz.Triplet.Tuple);
Expand All @@ -42,7 +42,7 @@ public static void Rec2020RgbToIctcp100()
}

[Test] // matches the behaviour of python-based "colour-science/colour" (https://github.com/colour-science/colour#31224ictcp-colour-encoding)
public static void Rec2020RgbToIctcp1()
public void Rec2020RgbToIctcp1()
{
var unicolour = Unicolour.FromRgb(Config1, TestRgb.Tuple);
AssertUtils.AssertTriplet(unicolour.Rgb.Linear.Triplet, TestLinearRgb, 0.00000000001);
Expand All @@ -55,7 +55,7 @@ public static void Rec2020RgbToIctcp1()
}

[Test] // matches the behaviour of javascript-based "color.js" (https://github.com/LeaVerou/color.js / https://colorjs.io/apps/picker)
public static void Rec2020RgbToIctcp203()
public void Rec2020RgbToIctcp203()
{
var unicolour = Unicolour.FromRgb(Config203, TestRgb.Tuple);
AssertUtils.AssertTriplet(unicolour.Rgb.Linear.Triplet, TestLinearRgb, 0.00000000001);
Expand All @@ -68,7 +68,7 @@ public static void Rec2020RgbToIctcp203()
}

[Test]
public static void ConvertTestColour()
public void ConvertTestColour()
{
var initial100 = Unicolour.FromRgb(Config100, TestRgb.Tuple);
var convertedTo1 = initial100.ConvertToConfiguration(Config1);
Expand All @@ -81,7 +81,7 @@ public static void ConvertTestColour()
}

[Test]
public static void ConvertWhite()
public void ConvertWhite()
{
var initial100 = Unicolour.FromXyz(Config100, XyzWhite.Tuple);
var convertedTo1 = initial100.ConvertToConfiguration(Config1);
Expand All @@ -95,7 +95,7 @@ public static void ConvertWhite()
}

[Test]
public static void ConvertBlack()
public void ConvertBlack()
{
var initial100 = Unicolour.FromXyz(Config100, 0, 0, 0);
var convertedTo1 = initial100.ConvertToConfiguration(Config1);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
using Wacton.Unicolour.Datasets;
using Wacton.Unicolour.Tests.Utils;

public static class JzazbzConfigurationTests
public class ConfigureJzazbzTests
{
private static readonly WhitePoint D65WhitePoint = WhitePoint.From(Illuminant.D65);
private static readonly ColourTriplet XyzWhite = new(D65WhitePoint.X / 100.0, D65WhitePoint.Y / 100.0, D65WhitePoint.Z / 100.0);
Expand All @@ -17,7 +17,7 @@ public static class JzazbzConfigurationTests
private static readonly Configuration Config203 = new(RgbConfiguration.StandardRgb, XyzConfiguration.D65, jzazbzScalar: 203);

[Test] // matches the behaviour of papers on Hung & Berns dataset (https://www.researchgate.net/figure/The-Hung-Berns-data-plotted-in-six-different-color-spaces-a-CIELAB-b-CIELUV-c_fig2_317811721)
public static void XyzD65ToJzazbz100()
public void XyzD65ToJzazbz100()
{
var red = Unicolour.FromXyz(Config100, HungBerns.RedRef.Xyz.Triplet.Tuple);
var blue = Unicolour.FromXyz(Config100, HungBerns.BlueRef.Xyz.Triplet.Tuple);
Expand All @@ -39,7 +39,7 @@ public static void XyzD65ToJzazbz100()
}

[Test] // matches the behaviour of python-based "colour-science/colour" (https://github.com/colour-science/colour#31212jzazbz-colourspace)
public static void XyzD65ToJzazbz1()
public void XyzD65ToJzazbz1()
{
var unicolour = Unicolour.FromXyz(Config1, TestXyz.Tuple);
AssertUtils.AssertTriplet<Jzazbz>(unicolour, new(0.00535048, 0.00924302, 0.00526007), 0.00001);
Expand All @@ -51,7 +51,7 @@ public static void XyzD65ToJzazbz1()
}

[Test] // matches the behaviour of javascript-based "color.js" (https://github.com/LeaVerou/color.js / https://colorjs.io/apps/picker)
public static void XyzD65ToJzazbz203()
public void XyzD65ToJzazbz203()
{
var unicolour = Unicolour.FromXyz(Config203, TestXyz.Tuple);
AssertUtils.AssertTriplet<Jzazbz>(unicolour, new(0.10287841, 0.08613415, 0.05873694), 0.0001);
Expand All @@ -63,7 +63,7 @@ public static void XyzD65ToJzazbz203()
}

[Test]
public static void ConvertTestColour()
public void ConvertTestColour()
{
var initial100 = Unicolour.FromXyz(Config100, TestXyz.Tuple);
var convertedTo1 = initial100.ConvertToConfiguration(Config1);
Expand All @@ -76,7 +76,7 @@ public static void ConvertTestColour()
}

[Test]
public static void ConvertWhite()
public void ConvertWhite()
{
var initial100 = Unicolour.FromXyz(Config100, XyzWhite.Tuple);
var convertedTo1 = initial100.ConvertToConfiguration(Config1);
Expand All @@ -90,7 +90,7 @@ public static void ConvertWhite()
}

[Test]
public static void ConvertBlack()
public void ConvertBlack()
{
var initial100 = Unicolour.FromXyz(Config100, 0, 0, 0);
var convertedTo1 = initial100.ConvertToConfiguration(Config1);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
* expected colour values for these tests based on calculations from
* http://www.brucelindbloom.com/index.html?ColorCalculator.html
*/
public static class RgbConfigurationTests
public class ConfigureRgbTests
{
private const double Tolerance = 0.01;

Expand Down Expand Up @@ -45,7 +45,7 @@ public static class RgbConfigurationTests
};

[Test]
public static void XyzD65ToStandardRgbD65()
public void XyzD65ToStandardRgbD65()
{
// https://en.wikipedia.org/wiki/SRGB#From_CIE_XYZ_to_sRGB
var expectedMatrixA = new[,]
Expand Down Expand Up @@ -80,7 +80,7 @@ public static void XyzD65ToStandardRgbD65()
}

[Test]
public static void XyzD50ToStandardRgbD65()
public void XyzD50ToStandardRgbD65()
{
var standardRgbConfig = new RgbConfiguration(
Chromaticity.StandardRgb.R,
Expand Down Expand Up @@ -111,7 +111,7 @@ public static void XyzD50ToStandardRgbD65()
}

[Test]
public static void XyzD65ToAdobeRgbD65()
public void XyzD65ToAdobeRgbD65()
{
var adobeRgbConfig = new RgbConfiguration(
AdobeChromaticityR,
Expand All @@ -131,7 +131,7 @@ public static void XyzD65ToAdobeRgbD65()
}

[Test]
public static void XyzD50ToAdobeRgbD65()
public void XyzD50ToAdobeRgbD65()
{
var adobeRgbConfig = new RgbConfiguration(
AdobeChromaticityR,
Expand All @@ -151,7 +151,7 @@ public static void XyzD50ToAdobeRgbD65()
}

[Test]
public static void XyzD65ToWideGamutRgbD50()
public void XyzD65ToWideGamutRgbD50()
{
var wideGamutRgbConfig = new RgbConfiguration(
WideGamutChromaticityR,
Expand All @@ -171,7 +171,7 @@ public static void XyzD65ToWideGamutRgbD50()
}

[Test]
public static void XyzD50ToWideGamutRgbD50()
public void XyzD50ToWideGamutRgbD50()
{
var wideGamutRgbConfig = new RgbConfiguration(
WideGamutChromaticityR,
Expand All @@ -191,7 +191,7 @@ public static void XyzD50ToWideGamutRgbD50()
}

[Test]
public static void ConvertStandardRgbToDisplayP3()
public void ConvertStandardRgbToDisplayP3()
{
var standardRgbConfig = new Configuration(RgbConfiguration.StandardRgb, XyzConfiguration.D65);
var displayP3Config = new Configuration(RgbConfiguration.DisplayP3, XyzConfiguration.D65);
Expand All @@ -205,7 +205,7 @@ public static void ConvertStandardRgbToDisplayP3()
}

[Test]
public static void ConvertDisplayP3ToStandardRgb()
public void ConvertDisplayP3ToStandardRgb()
{
var standardRgbConfig = new Configuration(RgbConfiguration.StandardRgb, XyzConfiguration.D65);
var displayP3Config = new Configuration(RgbConfiguration.DisplayP3, XyzConfiguration.D65);
Expand All @@ -219,7 +219,7 @@ public static void ConvertDisplayP3ToStandardRgb()
}

[Test]
public static void ConvertStandardRgbToRec2020()
public void ConvertStandardRgbToRec2020()
{
var standardRgbConfig = new Configuration(RgbConfiguration.StandardRgb, XyzConfiguration.D65);
var rec2020Config = new Configuration(RgbConfiguration.Rec2020, XyzConfiguration.D65);
Expand All @@ -233,7 +233,7 @@ public static void ConvertStandardRgbToRec2020()
}

[Test]
public static void ConvertRec2020ToStandardRgb()
public void ConvertRec2020ToStandardRgb()
{
var standardRgbConfig = new Configuration(RgbConfiguration.StandardRgb, XyzConfiguration.D65);
var rec2020Config = new Configuration(RgbConfiguration.Rec2020, XyzConfiguration.D65);
Expand All @@ -256,7 +256,7 @@ public static void ConvertRec2020ToStandardRgb()
[TestCase(Illuminant.F2)]
[TestCase(Illuminant.F7)]
[TestCase(Illuminant.F11)]
public static void XyzWhitePointRoundTrip(Illuminant xyzIlluminant)
public void XyzWhitePointRoundTrip(Illuminant xyzIlluminant)
{
var initialXyzConfig = new XyzConfiguration(RgbConfiguration.StandardRgb.WhitePoint);
var initialXyz = new Xyz(0.4676, 0.2387, 0.2974);
Expand Down
Loading

0 comments on commit d64bd52

Please sign in to comment.