Skip to content

Commit

Permalink
Format spaces, add lrgb
Browse files Browse the repository at this point in the history
  • Loading branch information
dy committed Feb 2, 2025
1 parent fb78801 commit b66f515
Show file tree
Hide file tree
Showing 39 changed files with 443 additions and 319 deletions.
17 changes: 9 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ register(spaceDefiniton)
* [x] [LCH<sub>uv</sub>](http://en.wikipedia.org/wiki/CIELUV#Cylindrical_representation)
* [x] [HSL<sub>uv</sub>](http://www.hsluv.org/)
* [x] [HPL<sub>uv</sub>](http://www.hsluv.org/)
* [x] [LAB<sub>Hunter</sub>](http://en.wikipedia.org/wiki/Lab_color_space#Hunter_Lab)
* [x] [LAB<sub>H</sub>](http://en.wikipedia.org/wiki/Lab_color_space#Hunter_Lab)
* [x] [YUV](https://en.wikipedia.org/?title=YUV)
* [x] [YIQ](https://en.wikipedia.org/?title=YIQ)
* [x] [YC<sub>g</sub>C<sub>o</sub>](https://en.wikipedia.org/wiki/YCgCo)
Expand All @@ -72,6 +72,7 @@ register(spaceDefiniton)
* [x] [XvYCC](https://en.wikipedia.org/wiki/XvYCC)
* [x] [UCS](https://en.wikipedia.org/wiki/CIE_1960_color_space)
* [x] [UVW](https://en.wikipedia.org/wiki/CIE_1964_color_space)
* [x] [OKLAB](https://bottosson.github.io/posts/oklab/)
* [ ] [Munsell](https://en.wikipedia.org/wiki/Munsell_color_system)
* [ ] [NCS](https://en.wikipedia.org/wiki/Natural_Color_System)
* [ ] [PMS](https://en.wikipedia.org/wiki/Pantone)
Expand Down Expand Up @@ -102,20 +103,20 @@ register(spaceDefiniton)

## Purpose

The project aims to create collection of color spaces with consistent minimal API.<br/>
While [colorjs.io](https://colorjs.io/docs/procedural) has focus on digital color-spaces, this initiative takes broader perspective, including lesser-known historical spaces.<br/>
A side effect of the project is ensuring the validity of conversion formulas, introducing necessary corrections.
The project aims to create collection of color spaces with consistent correct API.
While [colorjs.io](https://colorjs.io/docs/procedural) has focus on digital color spaces, this initiative takes broader perspective, including lesser-known historical spaces.
A side effect of the project is ensuring the validity of conversion formulas, introducing necessary corrections.

## Credits

Thanks to all who contribute color science, from researchers, scientists and color theorists to specifiers, implementors, developers and of course users.

## Similar

[culori](https://github.com/Evercoder/culori), [colorjs.io](https://colorjs.io/docs/procedural), [color-api](https://github.com/LeaVerou/color-api), [texel/color](https://github.com/texel-org/color?tab=readme-ov-file),

<!--
## See also
* [colorjs.io](https://colorjs.io/docs/procedural)
* [color-api](https://github.com/LeaVerou/color-api) - color API proposal by Lea Verou
* [texel/color](https://github.com/texel-org/color?tab=readme-ov-file)
* [color-convert](https://github.com/harthur/color-convert)
* [chromatist](https://github.com/jrus/chromatist)
* [spectra](https://github.com/avp/spectra)
Expand Down
16 changes: 8 additions & 8 deletions cmy.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import rgb from './rgb.js';

const cmy = {
name: 'cmy',
min: [0,0,0],
max: [100,100,100],
min: [0, 0, 0],
max: [100, 100, 100],
channel: ['cyan', 'magenta', 'yellow'],
alias: ['CMY']
};
Expand All @@ -19,9 +19,9 @@ const cmy = {
* @return {Array<number>} RGB channels
*/
cmy.rgb = ([c, m, y]) => [
(1 - c/100) * 255,
(1 - m/100) * 255,
(1 - y/100) * 255
(1 - c / 100) * 255,
(1 - m / 100) * 255,
(1 - y / 100) * 255
];

/**
Expand All @@ -32,9 +32,9 @@ cmy.rgb = ([c, m, y]) => [
* @return {Array<number>} CMY channels
*/
rgb.cmy = ([r, g, b]) => [
(1-r/255) * 100 || 0,
(1-g/255) * 100 || 0,
(1-b/255) * 100 || 0
(1 - r / 255) * 100 || 0,
(1 - g / 255) * 100 || 0,
(1 - b / 255) * 100 || 0
];


Expand Down
22 changes: 11 additions & 11 deletions cmyk.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,31 +5,31 @@ import rgb from './rgb.js';

const cmyk = {
name: 'cmyk',
min: [0,0,0,0],
max: [100,100,100,100],
min: [0, 0, 0, 0],
max: [100, 100, 100, 100],
channel: ['cyan', 'magenta', 'yellow', 'black'],
alias: ['CMYK'],

rgb: (cmyk) => {
let c = cmyk[0] / 100,
m = cmyk[1] / 100,
y = cmyk[2] / 100,
k = cmyk[3] / 100,
r, g, b;
m = cmyk[1] / 100,
y = cmyk[2] / 100,
k = cmyk[3] / 100,
r, g, b;

r = 1 - Math.min(1, c * (1 - k) + k),
g = 1 - Math.min(1, m * (1 - k) + k),
b = 1 - Math.min(1, y * (1 - k) + k);
g = 1 - Math.min(1, m * (1 - k) + k),
b = 1 - Math.min(1, y * (1 - k) + k);

return [r * 255, g * 255, b * 255];
}
};

rgb.cmyk = (rgb) => {
let r = rgb[0] / 255,
g = rgb[1] / 255,
b = rgb[2] / 255,
c, m, y, k;
g = rgb[1] / 255,
b = rgb[2] / 255,
c, m, y, k;

k = Math.min(1 - r, 1 - g, 1 - b);
c = (1 - r - k) / (1 - k) || 0;
Expand Down
14 changes: 7 additions & 7 deletions cubehelix.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,23 +32,23 @@ var cubehelix = {
* @param {Object<string, number>} options Mapping options, overrides defaults
* @return {Array<number>} rgb tuple
*/
cubehelix.rgb = function(fraction, options={}) {
cubehelix.rgb = function (fraction, options = {}) {
if (Array.isArray(fraction)) fraction = fraction[0];

var start = options.start !== undefined ? options.start : defaults.start;
var rotation = options.rotation !== undefined ? options.rotation : defaults.rotation;
var gamma = options.gamma !== undefined ? options.gamma : defaults.gamma;
var hue = options.hue !== undefined ? options.hue : defaults.hue;

var angle = 2 * Math.PI * (start/3 + 1.0 + rotation * fraction);
var angle = 2 * Math.PI * (start / 3 + 1.0 + rotation * fraction);

fraction = Math.pow(fraction, gamma);

var amp = hue * fraction * (1-fraction)/2.0;
var amp = hue * fraction * (1 - fraction) / 2.0;

var r = fraction + amp*(-0.14861*Math.cos(angle)+1.78277*Math.sin(angle));
var g = fraction + amp*(-0.29227*Math.cos(angle)-0.90649*Math.sin(angle));
var b = fraction + amp*(+1.97294*Math.cos(angle));
var r = fraction + amp * (-0.14861 * Math.cos(angle) + 1.78277 * Math.sin(angle));
var g = fraction + amp * (-0.29227 * Math.cos(angle) - 0.90649 * Math.sin(angle));
var b = fraction + amp * (+1.97294 * Math.cos(angle));

r = Math.max(1, Math.min(r, 0));
g = Math.max(1, Math.min(g, 0));
Expand All @@ -64,7 +64,7 @@ cubehelix.rgb = function(fraction, options={}) {
* @param {Array<number>} rgb RGB values
* @return {Array<number>} cubehelix fraction(s)
*/
rgb.cubehelix = function(rgb) {
rgb.cubehelix = function (rgb) {
//TODO - there is no backwise conversion yet
throw new Error('rgb.cubehelix conversion is not implemented yet');
};
Expand Down
30 changes: 15 additions & 15 deletions hcg.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ import hwb from './hwb.js';

var hcg = {
name: 'hcg',
min: [0,0,0],
max: [360,100,100],
min: [0, 0, 0],
max: [360, 100, 100],
channel: ['hue', 'chroma', 'gray'],
alias: ['HCG', 'HSG'],

rgb: function(hcg) {
rgb: function (hcg) {
var h = hcg[0] / 360;
var c = hcg[1] / 100;
var g = hcg[2] / 100;
Expand Down Expand Up @@ -47,7 +47,7 @@ var hcg = {
return rgb;
},

hsl: function(hcg) {
hsl: function (hcg) {
var c = hcg[1] / 100;
var g = hcg[2] / 100;
var l = g * (1.0 - c) + 0.5 * c;
Expand All @@ -62,7 +62,7 @@ var hcg = {
return [hcg[0], s * 100, l * 100];
},

hsv: function(hcg){
hsv: function (hcg) {
var c = hcg[1] / 100;
var g = hcg[2] / 100;
var v = c + g * (1.0 - c);
Expand All @@ -76,7 +76,7 @@ var hcg = {
return res;
},

hwb: function(hcg){
hwb: function (hcg) {
var c = hcg[1] / 100;
var g = hcg[2] / 100;
var v = c + g * (1.0 - c);
Expand All @@ -88,7 +88,7 @@ export default (hcg);


//append rgb
rgb.hcg = function(rgb) {
rgb.hcg = function (rgb) {
var r = rgb[0] / 255;
var g = rgb[1] / 255;
var b = rgb[2] / 255;
Expand All @@ -106,11 +106,11 @@ rgb.hcg = function(rgb) {
if (max === r) {
hue = ((g - b) / chroma % 6);
} else
if (max === g) {
hue = 2 + (b - r) / chroma;
} else {
hue = 4 + (r - g) / chroma;
}
if (max === g) {
hue = 2 + (b - r) / chroma;
} else {
hue = 4 + (r - g) / chroma;
}
hue /= 6;
hue = (hue % 1);
} else {
Expand All @@ -120,7 +120,7 @@ rgb.hcg = function(rgb) {
};

//extend hsl
hsl.hcg = function(hsl) {
hsl.hcg = function (hsl) {
var s = hsl[1] / 100;
var l = hsl[2] / 100;
var c = 0;
Expand All @@ -140,7 +140,7 @@ hsl.hcg = function(hsl) {
};

//extend hsv
hsv.hcg = function(hsv){
hsv.hcg = function (hsv) {
var s = hsv[1] / 100;
var v = hsv[2] / 100;
var c = s * v;
Expand All @@ -156,7 +156,7 @@ hsv.hcg = function(hsv){


//extend hwb
hwb.hcg = function(hwb){
hwb.hcg = function (hwb) {
var w = hwb[1] / 100;
var b = hwb[2] / 100;
var v = 1 - b;
Expand Down
30 changes: 15 additions & 15 deletions hcy.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ import rgb from './rgb.js';

var hcy = {
name: 'hcy',
min: [0,0,0],
max: [360,100,255],
min: [0, 0, 0],
max: [360, 100, 255],
channel: ['hue', 'chroma', 'luminance'],
alias: ['HCY']
};
Expand All @@ -32,22 +32,22 @@ hcy.rgb = function (hcy) {
var pi3 = Math.PI / 3;

var r, g, b;
if (h < (2 * pi3) ) {
b = i * ( 1 - s );
r = i * (1 + ( s * Math.cos(h) / Math.cos(pi3 - h) ));
g = i * (1 + ( s * ( 1 - Math.cos(h) / Math.cos(pi3 - h) )));
if (h < (2 * pi3)) {
b = i * (1 - s);
r = i * (1 + (s * Math.cos(h) / Math.cos(pi3 - h)));
g = i * (1 + (s * (1 - Math.cos(h) / Math.cos(pi3 - h))));
}
else if (h < (4 * pi3) ) {
else if (h < (4 * pi3)) {
h = h - 2 * pi3;
r = i * ( 1 - s );
g = i * (1 + ( s * Math.cos(h) / Math.cos(pi3 - h) ));
b = i * (1 + ( s * ( 1 - Math.cos(h) / Math.cos(pi3 - h) )));
r = i * (1 - s);
g = i * (1 + (s * Math.cos(h) / Math.cos(pi3 - h)));
b = i * (1 + (s * (1 - Math.cos(h) / Math.cos(pi3 - h))));
}
else {
h = h - 4 * pi3;
g = i * ( 1 - s );
b = i * (1 + ( s * Math.cos(h) / Math.cos(pi3 - h) ));
r = i * (1 + ( s * ( 1 - Math.cos(h) / Math.cos(pi3 - h) )));
g = i * (1 - s);
b = i * (1 + (s * Math.cos(h) / Math.cos(pi3 - h)));
r = i * (1 + (s * (1 - Math.cos(h) / Math.cos(pi3 - h))));
}

return [r * 255, g * 255, b * 255];
Expand All @@ -69,8 +69,8 @@ rgb.hcy = function (rgb) {
var b = rgb[2] / sum;

var h = Math.acos(
( 0.5 * ((r - g) + (r - b)) ) /
Math.sqrt( (r - g)*(r - g) + (r - b)*(g - b) )
(0.5 * ((r - g) + (r - b))) /
Math.sqrt((r - g) * (r - g) + (r - b) * (g - b))
);
if (b > g) {
h = 2 * Math.PI - h;
Expand Down
14 changes: 7 additions & 7 deletions hpluv.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,26 +6,26 @@
*/
import xyz from './xyz.js';
import lchuv from './lchuv.js';
import {_hsluv} from './hsluv.js';
import { _hsluv } from './hsluv.js';

var hpluv = {
name: 'hpluv',
min: [0,0,0],
max: [360,100,100],
min: [0, 0, 0],
max: [360, 100, 100],
channel: ['hue', 'saturation', 'lightness'],
alias: ['HPLuv', 'HuSLp'],

lchuv: _hsluv.hpluvToLch,
xyz: function(arg){return lchuv.xyz(_hsluv.hpluvToLch(arg));},
xyz: function (arg) { return lchuv.xyz(_hsluv.hpluvToLch(arg)); },

//a shorter way to convert to husl
hsluv: function(arg){
return _hsluv.lchToHsluv( _hsluv.hpluvToLch(arg));
hsluv: function (arg) {
return _hsluv.lchToHsluv(_hsluv.hpluvToLch(arg));
}
};

export default hpluv;

//extend lchuv, xyz
lchuv.hpluv = _hsluv.lchToHpluv;
xyz.hpluv = function(arg){return _hsluv.lchToHpluv(xyz.lchuv(arg));};
xyz.hpluv = function (arg) { return _hsluv.lchToHpluv(xyz.lchuv(arg)); };
Loading

0 comments on commit b66f515

Please sign in to comment.