# Color Theory/Algorithms
## color conversion

* sRGB to linear conversion
* AMPAS Academy Color Encoding System Developer Resources

### convertion inside sRGB
#### linearisation

Steps
* read value ( from sRGB)
* linearize and widening your intensity (convert 8-bit integer to 16 bit integer of float)
* process image
* delinearize and convert to 8-bit
* save as sRGB
When you're reading an sRGB image, and you want linear intensities, apply this formula to each intensity:
Going the other way, when you want to write an image as sRGB, apply this formula to each linear intensity:
Stages:
* applying the inverse of the sRGB nonlinear transform function f_inv
* doing computations
* then switching back by f
For colors in sRGB in range 0.0 to 1.0 this can be done by applying these functions component wise (provided in C-like pseudocode):

### Convertion between HSL and sRGB

Converting an HSL color to sRGB in JavaScript.
Converting sRGB Colors to HSL

### Converting from linear sRGB to Oklab

A color in Oklab is represented with three coordinates Lab:
* L – perceived lightness ( a unitless number in the range [0,1] )
* a – how green/red the color is
* b – how blue/yellow the color is
It's corresponding polar form is called Oklch.
The standard coordinate can also be transformed into polar form ( Lch), with the coordinates:
* L = lightness
* c = chroma
* h = hue
    $C={\sqrt {a^{2}+b^{2}}}$
    $h^{\circ }={\text{atan2}}(b,a)$
In reverse direction:
    $a=C\cos(h^{\circ })$
    $b=C\sin(h^{\circ })$
Converting from linear sRGB to Oklab in c++

## Image conversion

* color convert from colorjs library
C code

## Gray conversion

Python code

## matrix multiplication

matrix multiplication. (This is more readable than inlining all the multiplies and adds). The matrices are in column-major order.

## Mix colors

Methods
* simple interpolation of the sRGB values (gamma-corrected values). Lerp
* interpolation on linear values makes the red-green gradient better, but at the expense of the back-white gradient.
* Hue Interpolation ( in HSV, HSB). We could convert RGB to HSV and lerp each of the H, S, and V components. This is also pretty bad.
* separating the light intensities from the color
* Luminosity Interpolation: The best way is to lerp in perceptually linear colourspace ( LAB, OKLab, HCL...). The default color space for mixing (and gradients) in CSS is oklab
Goal: The intensity of the gradient must be constant
Code:
* d3js: interpolate color in js
* R colorRamp function

### simple interpolation

Mix 2 RGB colors ( naive and wrong form)
Simple interpolation of the sRGB values, particularly the red-green gradient is too dark in the middle.
Intuitively, lerping ( linear interpolations) draws a straight line between two points in the colourspace being used. However, a straight line in the colourspace usually does not result in a perceptually linear interpolation.

### interpolation on linear values

RGB colors on computers are in the sRGB color space. And those numerical values have a gamma of approx 2.4 applied.
Without applying the inverse gamma, the mixed colors are darker than they're supposed to be.
In order to mix the colors correctly you must first undo this gamma adjustment. Correct steps are:
* undo the gamma adjustment ( Invert sRGB gamma compression, InverseSrgbCompanding)
* apply your r,g,b mixing algorithm above
* reapply the gamma ( Reapply sRGB gamma compression, SrgbCompanding)
The gamma adjustment of sRGB isn't quite just 2.4. They actually have a linear section near black - so it's a piecewise function.
Helper functions:
And you re-apply the companding as:
The color blending in linear RGB space is good when colors are equal RGB total value; but the linear blending scale does not seem linear - especially for the black-white case. Using interpolation on linear values rather than gamma-corrected values makes the red-green gradient better, but at the expense of the back-white gradient.

### separating the light intensities from the color

Steps
* calculate L (lightness) for an RGB color:
** calculate only the Y (luminance) of CIE XYZ and use that to get L
** That gives L as 0-1 for any RGB
* Then to lerp RGB:
** first interpolate linear RGB,
** fix lightness by lerping the start/end L
** scale the RGB by targetL / resultL

### LAB

How to generate a smooth color gradient between two colors.
The intensity of the gradient must be constant in a perceptual color space or it will look unnaturally dark or light at points in the gradient. You can see this easily in a gradient based on simple interpolation of the sRGB values, particularly the red-green gradient is too dark in the middle. Using interpolation on linear values rather than gamma-corrected values makes the red-green gradient better, but at the expense of the back-white gradient. By separating the light intensities from the color you can get the best of both worlds.
Often when a perceptual color space is required, the Lab color space will be proposed. I think sometimes it goes too far, because it tries to accommodate the perception that blue is darker than an equivalent intensity of other colors such as yellow. This is true, but we are used to seeing this effect in our natural environment and in a gradient you end up with an overcompensation.
A power-law function of 0.43 was experimentally determined by researchers to be the best fit for relating gray light intensity to perceived brightness.
Algorithm in pseudocode:
Python code by Mark Ransom
The default color space for mixing (and gradients) in CSS is oklab

## perceptually uniform gradient

* color-gradient-algorithm by Roman Frołow
* perceptually-smooth-multi-color-linear-gradients by Matt DesLauriers
* color-gradient-algorithm-in-lab-color-space
* pereptual-color by Olivier Vicario

## How to Programmatically Lighten a Color ?

* SO Q&A

## How to convert hsl color to name ?

* Lea Verou: human-colours: A set of functions you can use to translate the HSL colour notation to human readable text.
* Trying to map the correct human colour names to hsl-hue values by VASILIS VAN GEMERT
* Trying to map the correct human saturation names to hsl-saturation values.
Examples:
* hsl(120,100%,50%) = A highly saturated green
* hsl(120,65%,25%) = A rather saturated, dark green.

## spline gradient

* spline gradient in js by Matt DesLauriers

## See also

* Computer graphic techniques : 2D algorithms
* pure-color = Pure functions for color conversion and parsing in JavaScript by Wicky Nilliams
* Useful Color Equations by Bruce Lindbloom
* the Best Gamma From a Data Set by Bruce Lindbloom
* ColorConverter by cpetry in JS
* easy RGB
* stackoverflow: questions tagged rgb

## References

* ↑ srgb-transform-library by Nayuki
* ↑ stackoverflow question : what-are-the-practical-differences-when-working-with-colors-in-a-linear-vs-a-no
* ↑ Björn Ottosson: How software gets color wrong
* ↑ oklab: A perceptual color space for image processing
* ↑ OKLAB by Tycho Tatitscheff
* ↑ github 0xStarlight ( Bhaskar Pal) : Filter-Program
* ↑ Doug-Luce Grayscale rev9.py code
* ↑ alan zucconi: colour-interpolation
* ↑ stackoverflow question: color-gradient-algorithm
* ↑ stackoverflow questions: programmatically-lighten-a-color