-
Notifications
You must be signed in to change notification settings - Fork 546
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix: use oklab implementation from W3C (#350)
- Loading branch information
Showing
19 changed files
with
192 additions
and
122 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -98,3 +98,4 @@ const xyz2rgb = (x, y, z) => { | |
}; | ||
|
||
export default lab2rgb; | ||
export { xyz2rgb }; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -64,3 +64,4 @@ const rgb2xyz = (r, g, b) => { | |
}; | ||
|
||
export default rgb2lab; | ||
export { rgb2xyz }; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,33 +1,34 @@ | ||
import { unpack } from '../../utils/index.js'; | ||
const { pow, sign } = Math; | ||
import multiplyMatrices from '../../utils/multiply-matrices.js'; | ||
import { xyz2rgb } from '../lab/lab2rgb.js'; | ||
|
||
/* | ||
* L* [0..100] | ||
* a [-100..100] | ||
* b [-100..100] | ||
*/ | ||
const oklab2rgb = (...args) => { | ||
args = unpack(args, 'lab'); | ||
const [L, a, b] = args; | ||
|
||
const l = pow(L + 0.3963377774 * a + 0.2158037573 * b, 3); | ||
const m = pow(L - 0.1055613458 * a - 0.0638541728 * b, 3); | ||
const s = pow(L - 0.0894841775 * a - 1.291485548 * b, 3); | ||
|
||
return [ | ||
255 * lrgb2rgb(+4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s), | ||
255 * lrgb2rgb(-1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s), | ||
255 * lrgb2rgb(-0.0041960863 * l - 0.7034186147 * m + 1.707614701 * s), | ||
args.length > 3 ? args[3] : 1 | ||
]; | ||
const [L, a, b, ...rest] = args; | ||
const [X, Y, Z] = OKLab_to_XYZ([L, a, b]); | ||
const [r, g, b_] = xyz2rgb(X, Y, Z); | ||
return [r, g, b_, ...(rest.length > 0 && rest[0] < 1 ? [rest[0]] : [])]; | ||
}; | ||
|
||
export default oklab2rgb; | ||
// from https://www.w3.org/TR/css-color-4/#color-conversion-code | ||
function OKLab_to_XYZ(OKLab) { | ||
// Given OKLab, convert to XYZ relative to D65 | ||
var LMStoXYZ = [ | ||
[1.2268798758459243, -0.5578149944602171, 0.2813910456659647], | ||
[-0.0405757452148008, 1.112286803280317, -0.0717110580655164], | ||
[-0.0763729366746601, -0.4214933324022432, 1.5869240198367816] | ||
]; | ||
var OKLabtoLMS = [ | ||
[1.0, 0.3963377773761749, 0.2158037573099136], | ||
[1.0, -0.1055613458156586, -0.0638541728258133], | ||
[1.0, -0.0894841775298119, -1.2914855480194092] | ||
]; | ||
|
||
function lrgb2rgb(c) { | ||
const abs = Math.abs(c); | ||
if (abs > 0.0031308) { | ||
return (sign(c) || 1) * (1.055 * pow(abs, 1 / 2.4) - 0.055); | ||
} | ||
return c * 12.92; | ||
var LMSnl = multiplyMatrices(OKLabtoLMS, OKLab); | ||
return multiplyMatrices( | ||
LMStoXYZ, | ||
LMSnl.map((c) => c ** 3) | ||
); | ||
} | ||
|
||
export default oklab2rgb; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,33 +1,37 @@ | ||
import { unpack } from '../../utils/index.js'; | ||
const { cbrt, pow, sign } = Math; | ||
import multiplyMatrices from '../../utils/multiply-matrices.js'; | ||
import { rgb2xyz } from '../lab/rgb2lab.js'; | ||
|
||
const rgb2oklab = (...args) => { | ||
// OKLab color space implementation taken from | ||
// https://bottosson.github.io/posts/oklab/ | ||
const [r, g, b, ...rest] = unpack(args, 'rgb'); | ||
const [lr, lg, lb] = [ | ||
rgb2lrgb(r / 255), | ||
rgb2lrgb(g / 255), | ||
rgb2lrgb(b / 255) | ||
]; | ||
const l = cbrt(0.4122214708 * lr + 0.5363325363 * lg + 0.0514459929 * lb); | ||
const m = cbrt(0.2119034982 * lr + 0.6806995451 * lg + 0.1073969566 * lb); | ||
const s = cbrt(0.0883024619 * lr + 0.2817188376 * lg + 0.6299787005 * lb); | ||
|
||
return [ | ||
0.2104542553 * l + 0.793617785 * m - 0.0040720468 * s, | ||
1.9779984951 * l - 2.428592205 * m + 0.4505937099 * s, | ||
0.0259040371 * l + 0.7827717662 * m - 0.808675766 * s, | ||
...(rest.length > 0 && rest[0] < 1 ? [rest[0]] : []) | ||
]; | ||
const xyz = rgb2xyz(r, g, b); | ||
const oklab = XYZ_to_OKLab(xyz); | ||
return [...oklab, ...(rest.length > 0 && rest[0] < 1 ? [rest[0]] : [])]; | ||
}; | ||
|
||
export default rgb2oklab; | ||
// from https://www.w3.org/TR/css-color-4/#color-conversion-code | ||
function XYZ_to_OKLab(XYZ) { | ||
// Given XYZ relative to D65, convert to OKLab | ||
const XYZtoLMS = [ | ||
[0.819022437996703, 0.3619062600528904, -0.1288737815209879], | ||
[0.0329836539323885, 0.9292868615863434, 0.0361446663506424], | ||
[0.0481771893596242, 0.2642395317527308, 0.6335478284694309] | ||
]; | ||
const LMStoOKLab = [ | ||
[0.210454268309314, 0.7936177747023054, -0.0040720430116193], | ||
[1.9779985324311684, -2.4285922420485799, 0.450593709617411], | ||
[0.0259040424655478, 0.7827717124575296, -0.8086757549230774] | ||
]; | ||
|
||
function rgb2lrgb(c) { | ||
const abs = Math.abs(c); | ||
if (abs < 0.04045) { | ||
return c / 12.92; | ||
} | ||
return (sign(c) || 1) * pow((abs + 0.055) / 1.055, 2.4); | ||
const LMS = multiplyMatrices(XYZtoLMS, XYZ); | ||
// JavaScript Math.cbrt returns a sign-matched cube root | ||
// beware if porting to other languages | ||
// especially if tempted to use a general power function | ||
return multiplyMatrices( | ||
LMStoOKLab, | ||
LMS.map((c) => Math.cbrt(c)) | ||
); | ||
// L in range [0,1]. For use in CSS, multiply by 100 and add a percent | ||
} | ||
|
||
export default rgb2oklab; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.