Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
e452cfc
Bootstrapping package
Antonio-Laguna May 1, 2022
4203628
Merge branch 'main' into feature/color-helpers
Antonio-Laguna May 3, 2022
4feb9be
Configuring tsconfig.json
Antonio-Laguna May 3, 2022
d825445
Ensuring no loss of precission is disabled
Antonio-Laguna May 3, 2022
8dc9dc3
Adding global Color
Antonio-Laguna May 3, 2022
5abe02d
Adding all of the functions
Antonio-Laguna May 3, 2022
d224c83
Merge branch 'main' into feature/color-helpers
Antonio-Laguna May 21, 2022
d3d6cfc
Keeping track of changes
Antonio-Laguna May 21, 2022
5f460fe
Updating global lock
Antonio-Laguna May 21, 2022
bd75958
Creating exports
Antonio-Laguna May 21, 2022
a604c00
Linting
Antonio-Laguna May 21, 2022
ba8da1c
Some docs
Antonio-Laguna May 23, 2022
44afdc5
Merge branch 'main' into feature/color-helpers
Antonio-Laguna May 24, 2022
3bcd1bd
Getting creative
Antonio-Laguna May 25, 2022
b756c55
Merge branch 'main' into feature/color-helpers
Antonio-Laguna Jun 11, 2022
c29a59f
Revert "Getting creative"
Antonio-Laguna Jun 11, 2022
8112127
Exporting
Antonio-Laguna Jun 11, 2022
8917493
Merge remote-tracking branch 'origin/main' into feature/color-helpers
romainmenke Jan 29, 2023
7d59940
fix
romainmenke Jan 29, 2023
25a13ae
bring in latest changes
romainmenke Jan 29, 2023
eebc81b
remove license from code that was written by me
romainmenke Jan 29, 2023
7134781
wip
romainmenke Jan 29, 2023
899bed1
add named colors
romainmenke Jan 29, 2023
c03e024
tweaks
romainmenke Jan 30, 2023
344837c
migrate some plugins
romainmenke Jan 30, 2023
667747f
use the final conversion helpers
romainmenke Jan 30, 2023
5745348
one more plugin
romainmenke Jan 30, 2023
9856951
final conversions
romainmenke Jan 30, 2023
6b2614b
Merge branch 'main' into feature/color-helpers
romainmenke Jan 31, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Adding all of the functions
  • Loading branch information
Antonio-Laguna committed May 3, 2022
commit 5abe02d69b12208057df49cacbcc5b7dfc06b047
3 changes: 3 additions & 0 deletions packages/color-helpers/src/calculations/LICENSE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
All documents in this Directory are licensed by contributors
under the
[W3C Software and Document License](https://www.w3.org/Consortium/Legal/copyright-software).
33 changes: 33 additions & 0 deletions packages/color-helpers/src/calculations/binary-search-gamut.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { clip } from 'utils/clip';
import { OKLCH_to_OKLab } from 'conversions/oklch-to-oklab';
import { deltaEOK } from 'calculations/deltaEOK';

/**
* @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
*
* @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/map-gamut.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
*/
export function binarySearchGamut(
startOKLCH: Color,
toDestination: (x: Color) => Color,
fromDestination: (x: Color) => Color,
): Color {
let min = 0;
let max = startOKLCH[1];
const current = startOKLCH;

while (max - min > 0.0001) {
const clipped = clip(toDestination(current));
const deltaE = deltaEOK(OKLCH_to_OKLab(current), OKLCH_to_OKLab(fromDestination(clipped)));
// are we inside the gamut (or very close to the boundary, outside)
if (deltaE - 0.02 < 0.0001) {
min = current[1];
} else {
max = current[1];
}
// binary search
current[1] = (max + min) / 2;
}

return clip(toDestination([...current]));
}
23 changes: 23 additions & 0 deletions packages/color-helpers/src/calculations/contrast.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/**
* Return WCAG 2.1 contrast ratio for two sRGB values given as arrays
*
* of 0.0 to 1.0
* @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
*
* @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
*
* @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/utilities.js
* @see https://www.w3.org/TR/WCAG21/#dfn-contrast-ratio
*/
import { sRGB_to_luminance } from 'conversions/srgb-to-luminance';

export function contrast(RGB1: Color, RGB2: Color): number {
const L1 = sRGB_to_luminance(RGB1);
const L2 = sRGB_to_luminance(RGB2);

if (L1 > L2) {
return (L1 + 0.05) / (L2 + 0.05);
}

return (L2 + 0.05) / (L1 + 0.05);
}
18 changes: 18 additions & 0 deletions packages/color-helpers/src/calculations/deltaEOK.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/**
* @description Calculate deltaE OK which is the simple root sum of squares
*
* @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
*
* @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/deltaEOK.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
*
* @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/deltaEOK.js
*/
export function deltaEOK(reference: Color, sample: Color): number {
// Given reference and sample are both in OKLab
const [L1, a1, b1] = reference;
const [L2, a2, b2] = sample;
const ΔL = L1 - L2;
const Δa = a1 - a2;
const Δb = b1 - b2;
return Math.sqrt(ΔL ** 2 + Δa ** 2 + Δb ** 2);
}
10 changes: 10 additions & 0 deletions packages/color-helpers/src/calculations/map-gamut.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { binarySearchGamut } from 'calculations/binary-search-gamut';

/**
* @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
*
* @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/map-gamut.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
*/
export function mapGamut(startOKLCH: Color, toDestination: (x: Color) => Color, fromDestination: (x: Color) => Color): Color {
return binarySearchGamut(startOKLCH, toDestination, fromDestination);
}
49 changes: 49 additions & 0 deletions packages/color-helpers/src/calculations/multiply-matrices.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/**
* Simple matrix (and vector) multiplication
* Warning: No error handling for incompatible dimensions!
* @author Lea Verou 2020 MIT License
*
* @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
*
* @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/multiply-matrices.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
*
* @see https://github.com/w3c/csswg-drafts/blob/main/css-color-4/multiply-matrices.js
*/
// A is m x n. B is n x p. product is m x p.
export function multiplyMatrices(a: Array<Array<number>> | Array<number>, b: Array<Array<number>> | Array<number>): Array<Array<number>> | Array<number> {
const m = a.length;

let A: Array<Array<number>>;
if (!Array.isArray(a[0])) {
// A is vector, convert to [[a, b, c, ...]]
A = [a as Array<number>];
} else {
A = a as Array<Array<number>>;
}

let B: Array<Array<number>>;
if (!Array.isArray(b[0])) {
// B is vector, convert to [[a], [b], [c], ...]]
B = (b as Array<number>).map(x => [x]);
}

const p = B[0].length;
const B_cols = B[0].map((_, i) => B.map(x => x[i])); // transpose B
let product: Array<Array<number>> | Array<number> = A.map(row => B_cols.map(col => {
if (!Array.isArray(row)) {
return col.reduce((d, f) => d + f * row, 0);
}

return row.reduce((d, f, i) => d + f * (col[i] || 0), 0);
}));

if (m === 1) {
product = product[0]; // Avoid [[a, b, c, ...]]
}

if (p === 1) {
return product.map(x => x[0]); // Avoid [[a], [b], [c], ...]]
}

return product;
}
17 changes: 17 additions & 0 deletions packages/color-helpers/src/calculations/polar-premultiply.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/**
* Given a color in a cylindical polar colorspace and an alpha value
* return the premultiplied form. The index says which entry in the
* color array corresponds to hue angle for example, in OKLCH it
* would be 2 while in HSL it would be 0
*
* @param color
* @param alpha
* @param hueIndex
*
* @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
*
* @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
*/
export function polar_premultiply(color: Color, alpha: number, hueIndex: number): Color {
return color.map((c, i) => c * (hueIndex === i ? 1 : alpha)) as Color;
}
3 changes: 3 additions & 0 deletions packages/color-helpers/src/conversions/LICENSE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Some documents in this Directory are licensed by contributors
under the
[W3C Software and Document License](https://www.w3.org/Consortium/Legal/copyright-software).
54 changes: 54 additions & 0 deletions packages/color-helpers/src/conversions/a98-rgb-to-srgb.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { lin_a98rgb } from 'conversions/lin-a98rgb';
import { lin_a98rgb_to_XYZ } from 'conversions/lin-a98rgb-to-xyz';
import { XYZ_to_OKLab } from 'conversions/xyz-to-oklab';
import { OKLab_to_OKLCH } from 'conversions/oklab-to-oklch';
import { XYZ_to_lin_sRGB } from 'conversions/xyz-to-lin-srgb';
import { gam_sRGB } from 'conversions/gam-srgb';
import { inGamut } from 'utils/in-gamut';
import { clip } from 'utils/clip';
import { mapGamut } from 'calculations/map-gamut';
import { OKLab_to_XYZ } from 'conversions/oklab-to-xyz';
import { lin_sRGB } from 'conversions/lin-srgb';
import { lin_sRGB_to_XYZ } from 'conversions/lin-srgb-to-xyz';
import { OKLCH_to_OKLab } from 'conversions/oklch-to-oklab';

export function a98_RGB_to_sRGB(a98: Color): Color {
let conversion = a98.slice() as Color;

// https://www.w3.org/TR/css-color-4/#predefined-to-predefined
// https://www.w3.org/TR/css-color-4/#predefined-to-lab-oklab
conversion = lin_a98rgb(conversion);
conversion = lin_a98rgb_to_XYZ(conversion);

let oklch = conversion.slice() as Color;
oklch = XYZ_to_OKLab(oklch);
oklch = OKLab_to_OKLCH(oklch);
if (oklch[0] < 0.000001) {
oklch = [0, 0, 0] as Color;
}

if (oklch[0] > 0.999999) {
oklch = [1, 0, 0] as Color;
}

// 3. Convert from(D65 - adapted) CIE XYZ to linear RGB
conversion = XYZ_to_lin_sRGB(conversion);
// 4. Convert from linear - light RGB to RGB(do gamma encoding)
conversion = gam_sRGB(conversion);

if (inGamut(conversion)) {
return clip(conversion);
}

return mapGamut(oklch, (x: Color) => {
x = OKLCH_to_OKLab(x);
x = OKLab_to_XYZ(x);
x = XYZ_to_lin_sRGB(x);
return gam_sRGB(x);
}, (x: Color) => {
x = lin_sRGB(x);
x = lin_sRGB_to_XYZ(x);
x = XYZ_to_OKLab(x);
return OKLab_to_OKLCH(x);
});
}
52 changes: 52 additions & 0 deletions packages/color-helpers/src/conversions/cie-xyz-50-to-srgb.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { XYZ_to_OKLab } from 'conversions/xyz-to-oklab';
import { OKLab_to_OKLCH } from 'conversions/oklab-to-oklch';
import { D50_to_D65 } from 'conversions/d50-to-d65';
import { XYZ_to_lin_sRGB } from 'conversions/xyz-to-lin-srgb';
import { gam_sRGB } from 'conversions/gam-srgb';
import { inGamut } from 'utils/in-gamut';
import { clip } from 'utils/clip';
import { mapGamut } from 'calculations/map-gamut';
import { OKLCH_to_OKLab } from 'conversions/oklch-to-oklab';
import { OKLab_to_XYZ } from 'conversions/oklab-to-xyz';
import { lin_sRGB } from 'conversions/lin-srgb';
import { lin_sRGB_to_XYZ } from 'conversions/lin-srgb-to-xyz';

export function cie_XYZ_50_to_sRGB(xyz: Color): Color {
let conversion = xyz.slice() as Color;

// https://www.w3.org/TR/css-color-4/#predefined-to-predefined
// https://www.w3.org/TR/css-color-4/#predefined-to-lab-oklab
conversion = D50_to_D65(conversion);

let oklch = conversion.slice() as Color;
oklch = XYZ_to_OKLab(oklch);
oklch = OKLab_to_OKLCH(oklch);
if (oklch[0] < 0.000001) {
oklch = [0, 0, 0] as Color;
}

if (oklch[0] > 0.999999) {
oklch = [1, 0, 0] as Color;
}

// 3. Convert from(D65 - adapted) CIE XYZ to linear RGB
conversion = XYZ_to_lin_sRGB(conversion);
// 4. Convert from linear - light RGB to RGB(do gamma encoding)
conversion = gam_sRGB(conversion);

if (inGamut(conversion)) {
return clip(conversion);
}

return mapGamut(oklch, (x: Color) => {
x = OKLCH_to_OKLab(x);
x = OKLab_to_XYZ(x);
x = XYZ_to_lin_sRGB(x);
return gam_sRGB(x);
}, (x: Color) => {
x = lin_sRGB(x);
x = lin_sRGB_to_XYZ(x);
x = XYZ_to_OKLab(x);
return OKLab_to_OKLCH(x);
});
}
49 changes: 49 additions & 0 deletions packages/color-helpers/src/conversions/cie-xyz-65-to-srgb.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { XYZ_to_OKLab } from 'conversions/xyz-to-oklab';
import { OKLab_to_OKLCH } from 'conversions/oklab-to-oklch';
import { XYZ_to_lin_sRGB } from 'conversions/xyz-to-lin-srgb';
import { gam_sRGB } from 'conversions/gam-srgb';
import { inGamut } from 'utils/in-gamut';
import { clip } from 'utils/clip';
import { mapGamut } from 'calculations/map-gamut';
import { OKLCH_to_OKLab } from 'conversions/oklch-to-oklab';
import { OKLab_to_XYZ } from 'conversions/oklab-to-xyz';
import { lin_sRGB } from 'conversions/lin-srgb';
import { lin_sRGB_to_XYZ } from 'conversions/lin-srgb-to-xyz';

export function cie_XYZ_65_to_sRGB(xyz: Color): Color {
let conversion = xyz.slice() as Color;

// https://www.w3.org/TR/css-color-4/#predefined-to-predefined
// https://www.w3.org/TR/css-color-4/#predefined-to-lab-oklab
let oklch = conversion.slice() as Color;
oklch = XYZ_to_OKLab(oklch);
oklch = OKLab_to_OKLCH(oklch);
if (oklch[0] < 0.000001) {
oklch = [0, 0, 0] as Color;
}

if (oklch[0] > 0.999999) {
oklch = [1, 0, 0] as Color;
}

// 3. Convert from(D65 - adapted) CIE XYZ to linear RGB
conversion = XYZ_to_lin_sRGB(conversion);
// 4. Convert from linear - light RGB to RGB(do gamma encoding)
conversion = gam_sRGB(conversion);

if (inGamut(conversion)) {
return clip(conversion);
}

return mapGamut(oklch, (x: Color) => {
x = OKLCH_to_OKLab(x);
x = OKLab_to_XYZ(x);
x = XYZ_to_lin_sRGB(x);
return gam_sRGB(x);
}, (x: Color) => {
x = lin_sRGB(x);
x = lin_sRGB_to_XYZ(x);
x = XYZ_to_OKLab(x);
return OKLab_to_OKLCH(x);
});
}
3 changes: 3 additions & 0 deletions packages/color-helpers/src/conversions/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// standard white points, defined by 4-figure CIE x,y chromaticities
export const D50 = [0.3457 / 0.3585, 1.00000, (1.0 - 0.3457 - 0.3585) / 0.3585];
export const D65 = [0.3127 / 0.3290, 1.00000, (1.0 - 0.3127 - 0.3290) / 0.3290];
18 changes: 18 additions & 0 deletions packages/color-helpers/src/conversions/d50-to-d65.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/**
* Bradford chromatic adaptation from D50 to D65
*
* @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
*
* @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
*/
import { multiplyMatrices } from 'calculations/multiply-matrices';

export function D50_to_D65(XYZ: Color): Color {
const M = [
[0.9554734527042182, -0.023098536874261423, 0.0632593086610217],
[-0.028369706963208136, 1.0099954580058226, 0.021041398966943008],
[0.012314001688319899, -0.020507696433477912, 1.3303659366080753],
];

return multiplyMatrices(M, XYZ) as Color;
}
23 changes: 23 additions & 0 deletions packages/color-helpers/src/conversions/d65-to-d50.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/**
* Bradford chromatic adaptation from D65 to D50
* @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
*
* @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
*
* @see http://www.brucelindbloom.com/index.html?Eqn_ChromAdapt.html
*/
import { multiplyMatrices } from 'calculations/multiply-matrices';

export function D65_to_D50(XYZ: Color): Color {
// The matrix below is the result of three operations:
// - convert from XYZ to retinal cone domain
// - scale components from one reference white to another
// - convert back to XYZ
const M = [
[1.0479298208405488, 0.022946793341019088, -0.05019222954313557],
[0.029627815688159344, 0.990434484573249, -0.01707382502938514],
[-0.009243058152591178, 0.015055144896577895, 0.7518742899580008],
];

return multiplyMatrices(M, XYZ) as Color;
}
23 changes: 23 additions & 0 deletions packages/color-helpers/src/conversions/gam-2020.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/**
* Convert an array of linear-light rec2020 RGB in the range 0.0-1.0
* to gamma corrected form ITU-R BT.2020-2 p.4
*
* @license W3C https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
*
* @copyright This software or document includes material copied from or derived from https://github.com/w3c/csswg-drafts/blob/main/css-color-4/conversions.js. Copyright © 2022 W3C® (MIT, ERCIM, Keio, Beihang).
*/
export function gam_2020(RGB: Color): Color {
const α = 1.09929682680944;
const β = 0.018053968510807;

return RGB.map(function (val) {
const sign = val < 0 ? -1 : 1;
const abs = Math.abs(val);

if (abs > β) {
return sign * (α * Math.pow(abs, 0.45) - (α - 1));
}

return 4.5 * val;
}) as Color;
}
Loading