Friday, 26 March 2021

Colour Pick 1: Goldenrod

As part of my investigation into colour names, I've been writing a lot of JavaScript code to perform colour space transformations.

When I started the colour pick work, I did the "right thing" and refactored all the colour-related functionality into a library. The library is named "goldenrod" after the X11 colour of that name (#DAA520).

Solidago virgaurea minuta "Dwarf Goldenrod"

The library is just a plain old bunch of functions and lists organised into three files:

goldenrod.js

This script contains the main entry points exposed as fields of the global object "chilliant.goldenrod". They are primarily conversion functions with signatures of the following form:

float[3] chilliant.goldenrod.{source}_to_{destination}(float value[3])

Above, "{source}" and "{destination}" are colour space tags as listed in the following table:

TagColour Spacevalue[0]value[1]value[2]
sRGBsRGBred
0.0 to 1.0
green
0.0 to 1.0
blue
0.0 to 1.0
HSVHSV
a.k.a. HSB
hue
0.0 to 360.0 degrees
saturation
0.0 to 1.0
value
0.0 to 1.0
HSLHSLhue
0.0 to 360.0 degrees
saturation
0.0 to 1.0
lightness
0.0 to 1.0
HWBHWBhue
0.0 to 360.0 degrees
whiteness
0.0 to 1.0
blackness
0.0 to 1.0
CIEXYZCIE 1931 XYZX
0.0 to 1.0
Y luminance
0.0 to 1.0
Z
0.0 to 1.0
CIExyYCIE 1931 xyYx
0.0 to 100.0
y
0.0 to 100.0
Y luminance
0.0 to 100.0
CIELabCIE 1976 L*a*b*L* lightness
0.0 to 100.0
a*
~ -100.0 to 100.0
b*
~ -100.0 to 100.0
CIELuvCIE 1976 L*u*v*L* lightness
0.0 to 100.0
u*
~ -200.0 to 200.0
v*
~ -200.0 to 200.0
CIELChabCIE 1976 L*C*habL* lightness
0.0 to 100.0
C* chroma
~ 0.0 to 100.0
hab hue
0.0 to 360.0 degrees
CIELChuvCIE 1976 L*C*huvL* lightness
0.0 to 100.0
C* chroma
~ 0.0 to 100.0
huv hue
0.0 to 360.0 degrees

Note that for conversions to and from the hexacone colour spaces (HSV/HSL/HWB) the tag "RGB" is used instead of "sRGB" to emphasize the fact that no linearization or delinearization is performed. Thus, the name "chilliant.goldenrod.RGB_to_HSL" is used instead of "chilliant.goldenrod.sRGB_to_HSL".

All conversions assume a standard D65 illuminant with a two-degree observer angle.

At the time of writing, not all permutations of source and destination are directly supported, but it's a trivial change to add the missing "chains".

The additional members of "chilliant.goldenrod" are listed below.

bool chilliant.goldenrod.within_sRGB(any srgb)

A function that returns true if, and only if, 'srgb' is an array of at least three numbers all between 0.0 and 1.0 inclusive.

float[3] chilliant.goldenrod.force_sRGB(any srgb)

Forces 'srgb' to be a valid sRGB triplet with each element between 0.0 and 1.0. If any channel is greater than one, the whole triplet is scaled back. If 'srgb' cannot be interpretted as a valid triplet, black [0,0,0] is returned.

float chilliant.goldenrod.deltaE1994(float ref[3], float lab[3])

Computes the CIELAB ΔE*(1994) colour difference between the two CIEL*a*b* colours. Note that this metric is not symmetric.

float chilliant.goldenrod.deltaE2000(float ref[3], float lab[3])

Computes the CIELAB ΔE*(2000) colour difference between the two CIEL*a*b* colours.

string chilliant.goldenrod.sRGB_to_HEX(float srgb[])

Converts the sRGB triplet (or quartet with alpha) 'srgb' to a hexadecimal colour in the form "#rrggbb" or "#rrggbbaa".

float[3] chilliant.goldenrod.HEX_to_sRGB(string hex)

Converts an hexadecimal colour string in the form "#rgb", "#rgba", "#rrggbb" or "#rrggbbaa" into an sRGB triplet. Any alpha component is ignored.

string chilliant.goldenrod.version

A string field containing the goldenrod library version in semver format, e.g. "1.0.0".

util.js

This script contains the guts of the functionality of goldenrod exposed as members of the object "chilliant.goldenrod.util". A large portion is based on the formulae outlined on Bruce Lindbloom's excellent site and should be fairly self-explanatory.

data.js

This script contains useful datasets exposed as members of the object "chilliant.goldenrod.data".

float[][] chilliant.goldenrod.data.cie1931_xyy

The CIE 1931 2-degree chromaticity xyY coordinates from UCL Colour & Vision Research Laboratory. The columns are:

  1. Wavelength in nm,
  2. CIE xyY x-ordinate,
  3. CIE xyY y-ordinate, and
  4. CIE xyY Y luminance.

object[] chilliant.goldenrod.data.css4

The CSS 4 colour names taken from Mozilla.

any[] chilliant.goldenrod.data.centore

The 267 ISCC-NBS centroids from Paul Centore's site in index order. The columns are:

  1. Name (string),
  2. Munsell colour (string),
  3. Red (int),
  4. Green (int),
  5. Blue (int),
  6. sRGB hexadecimal (string).

Note that seven of the centroids are outside the sRGB gamut so are missing the final four columns. It would be nice to have the out-of-gamut values for red/green/blue because those points could still be matched via (for instance) Euclidean distance searchers. However, I have been unable to recreate Paul's methodology to fill in the blanks.

object chilliant.goldenrod.data.cns

A 627-entry map between the Color Naming System and sRGB values in the form:

{
  "black": {hex: "#000000", srgb: [0,0,0]},
  ...
  "yellowish orange": {hex: "#CC9333", srgb: [0.8,0.575,0.2]}
}

This is a "best guess" at the values based on "A New Color-Naming System for Graphics Languages".

See "generateCNS()" for details.

any[] chilliant.goldenrod.data.iscc

The 260 ISCC-NBS centroids from "data.centore" that are within the sRGB gamut, formatted like "data.cns".

See "generateISCC()" for details.

Unit Tests

The goldenrod library has a minimal unit test suite. The values were checked against Bruce Lindbloom's colour calculator, amongst other tools.

No comments:

Post a Comment