Skip to content

Commit

Permalink
fix: Changed sRGB Logic
Browse files Browse the repository at this point in the history
  • Loading branch information
Tynopia committed Sep 22, 2024
1 parent d467597 commit 26985d0
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 59 deletions.
10 changes: 4 additions & 6 deletions packages/color-convert/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -205,27 +205,25 @@ rgbaToHexa({ b: 26, g: 2, r: 209, a: 1 }) // => '#d1021aff'
### `hexToXY`

```js
hexToXY('#4780f1')
hexToXY('#4780f1') // => { x: 0.261, y: 0.231, bri: 0.863 }
```

### `xyToHex`

```js
xyToHex({ x: 0.193, y: 0.17, bri: 1 })
xyToHex({ x: 0.193, y: 0.17, bri: 0.231 })
xyToHex({ x: 0.261, y: 0.231, bri: 0.863 }) // => #4780f1
```

### `rgbToXY`

```js
rgbToXY({ r: 71, g: 128, b: 241 })
rgbToXY({ r: 71, g: 128, b: 241 }) // => { x: 0.261, y: 0.231, bri: 0.863 }
```

### `xyToRgb`

```js
xyToRgb({ x: 0.193, y: 0.17, bri: 1 })
xyToRgb({ x: 0.193 y: 0.17, bri: 0.23 })
xyToRgb({ x: 0.261, y: 0.231, bri: 0.863 }) // => { r: 71, g: 128, b: 241 }
```

#### `color`
Expand Down
72 changes: 30 additions & 42 deletions packages/color-convert/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export type ColorResult = {
rgba: RgbaColor;
hsla: HslaColor;
hsva: HsvaColor;
xy: XYColor;
hex: string;
hexa: string;
};
Expand Down Expand Up @@ -287,59 +288,44 @@ export const xyToHex = (xy: XYColor): string =>
});

/**
* Converts RGB to XY. Based on formula from https://developers.meethue.com/develop/application-design-guidance/color-conversion-formulas-rgb-to-xy-and-back/
* @param color RGB color as an array [0-255, 0-255, 0-255]
* Converts XY to RGB. Based on formula from https://developers.meethue.com/develop/application-design-guidance/color-conversion-formulas-rgb-to-xy-and-back/
* @param color XY color and brightness as an array [0-1, 0-1, 0-1]
*/
export const rgbToXY = ({ r, g, b }: RgbColor): XYColor => {
let red = r / 255;
let green = g / 255;
let blue = b / 255;
export const xyToRgb = ({ x, y, bri = 255 }: XYColor): RgbColor => {
const red = x * 3.2406255 + y * -1.537208 + bri * -0.4986286;
const green = x * -0.9689307 + y * 1.8757561 + bri * 0.0415175;
const blue = x * 0.0557101 + y * -0.2040211 + bri * 1.0569959;

red = red > 0.04045 ? Math.pow((red + 0.055) / 1.055, 2.4) : red / 12.92;
green = green > 0.04045 ? Math.pow((green + 0.055) / 1.055, 2.4) : green / 12.92;
blue = blue > 0.04045 ? Math.pow((blue + 0.055) / 1.055, 2.4) : blue / 12.92;

const X = red * 0.4124 + green * 0.3576 + blue * 0.1805;
const Y = red * 0.2126 + green * 0.7152 + blue * 0.0722;
const Z = red * 0.0193 + green * 0.1192 + blue * 0.9505;

let x = X / (X + Y + Z);
let y = Y / (X + Y + Z);

if (isNaN(x)) x = 0;
if (isNaN(y)) y = 0;
const translate = function (color: number) {
return color <= 0.0031308 ? 12.92 * color : 1.055 * Math.pow(color, 1 / 2.4) - 0.055;
};

return {
x,
y,
bri: Y,
r: Math.round(255 * translate(red)),
g: Math.round(255 * translate(green)),
b: Math.round(255 * translate(blue)),
};
};

/**
* Converts XY to RGB. Based on formula from https://developers.meethue.com/develop/application-design-guidance/color-conversion-formulas-rgb-to-xy-and-back/
* @param color XY color and brightness as an array [0-1, 0-1, 0-1]
* Converts RGB to XY. Based on formula from https://developers.meethue.com/develop/application-design-guidance/color-conversion-formulas-rgb-to-xy-and-back/
* @param color RGB color as an array [0-255, 0-255, 0-255]
*/
export const xyToRgb = ({ x, y, bri = 1 }: XYColor): RgbColor => {
const z = 1.0 - x - y;

const Y = bri;
const X = (Y / y) * x;
const Z = (Y / y) * z;
export const rgbToXY = ({ r, g, b }: RgbColor): XYColor => {
const translateColor = function (color: number) {
return color <= 0.04045 ? color / 12.92 : Math.pow((color + 0.055) / 1.055, 2.4);
};

let r = X * 1.656492 - Y * 0.354851 - Z * 0.255038;
let g = -X * 0.707196 + Y * 1.655397 + Z * 0.036152;
let b = X * 0.051713 - Y * 0.121364 + Z * 1.01153;
const red = translateColor(r / 255);
const green = translateColor(g / 255);
const blud = translateColor(b / 255);

r = r <= 0.0031308 ? 12.92 * r : (1.0 + 0.055) * Math.pow(r, 1.0 / 2.4) - 0.055;
g = g <= 0.0031308 ? 12.92 * g : (1.0 + 0.055) * Math.pow(g, 1.0 / 2.4) - 0.055;
b = b <= 0.0031308 ? 12.92 * b : (1.0 + 0.055) * Math.pow(b, 1.0 / 2.4) - 0.055;
const xyz = {} as XYColor;
xyz.x = red * 0.4124 + green * 0.3576 + blud * 0.1805;
xyz.y = red * 0.2126 + green * 0.7152 + blud * 0.0722;
xyz.bri = red * 0.0193 + green * 0.1192 + blud * 0.9505;

return {
r: Math.round(r * 255),
g: Math.round(g * 255),
b: Math.round(b * 255),
};
return xyz;
};

export const color = (str: string | HsvaColor): ColorResult => {
Expand All @@ -349,6 +335,7 @@ export const color = (str: string | HsvaColor): ColorResult => {
let rgba!: RgbaColor;
let hsla!: HslaColor;
let hsva!: HsvaColor;
let xy!: XYColor;
let hex!: string;
let hexa!: string;
if (typeof str === 'string' && validHex(str)) {
Expand All @@ -365,8 +352,9 @@ export const color = (str: string | HsvaColor): ColorResult => {
hex = hsvaToHex(hsva);
hsl = hslaToHsl(hsla);
rgb = rgbaToRgb(rgba);
xy = rgbToXY(rgb);
}
return { rgb, hsl, hsv, rgba, hsla, hsva, hex, hexa };
return { rgb, hsl, hsv, rgba, hsla, hsva, hex, hexa, xy };
};

export const getContrastingColor = (str: string | HsvaColor) => {
Expand Down
23 changes: 12 additions & 11 deletions test/convert.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ it('Converts color => hslString To Hsl', () => {
});

it('Converts color => HEX to ColorResult', () => {
const { rgb, rgba, hex, hexa, hsl, hsla, hsv, hsva } = color('#d1021a');
const { rgb, rgba, hex, hexa, hsl, hsla, hsv, hsva, xy } = color('#d1021a');
expect(hex).toEqual('#d1021a');
expect(hexa).toEqual('#d1021aff');
expect(color({ h: 353.04347826086956, s: 99.04306220095694, v: 81.96078431372548, a: 1 }).hex).toEqual('#d1021a');
Expand All @@ -54,6 +54,7 @@ it('Converts color => HEX to ColorResult', () => {
expect(hsla).toEqual({ h: 353.04347826086956, l: 41.37254901960784, s: 98.10426540284361, a: 1 });
expect(hsv).toEqual({ h: 353.04347826086956, s: 99.04306220095694, v: 81.96078431372548 });
expect(hsva).toEqual({ h: 353.04347826086956, s: 99.04306220095694, v: 81.96078431372548, a: 1 });
expect(xy).toEqual({ x: 0.26502656639062083, y: 0.13673307363113865, bri: 0.022196477290623278 });
});

it('Converts color => HEXA to ColorResult', () => {
Expand Down Expand Up @@ -98,12 +99,12 @@ it('Converts RGBA to HEXA', () => {
});

it('Converts RGB to XY', () => {
expect(rgbToXY({ r: 255, g: 255, b: 255 })).toMatchObject({ x: 0.3127159072215825, y: 0.3290014805066623, bri: 1 });
expect(rgbToXY({ r: 255, g: 255, b: 255 })).toMatchObject({ x: 0.9505, y: 1, bri: 1.089 });
expect(rgbToXY({ r: 0, g: 0, b: 0 })).toMatchObject({ x: 0.0, y: 0.0, bri: 0 });
expect(rgbToXY({ r: 71, g: 128, b: 241 })).toMatchObject({
x: 0.19313993893216994,
y: 0.17053314882681408,
bri: 0.23128809648982562,
x: 0.26194888875915034,
y: 0.23128809648982562,
bri: 0.863027753196167,
});
});

Expand All @@ -128,9 +129,9 @@ it('Converts HEX to HSVA', () => {
});

it('Converts HEX to XY', () => {
expect(hexToXY('#ffffff')).toMatchObject({ x: 0.3127159072215825, y: 0.3290014805066623, bri: 1 });
expect(hexToXY('#ffffff')).toMatchObject({ x: 0.9505, y: 1, bri: 1.089 });
expect(hexToXY('#000000')).toMatchObject({ x: 0.0, y: 0.0, bri: 0 });
expect(hexToXY('#4780f1')).toMatchObject({ x: 0.19313993893216994, y: 0.17053314882681408, bri: 0.23128809648982562 });
expect(hexToXY('#4780f1')).toMatchObject({ x: 0.26194888875915034, y: 0.23128809648982562, bri: 0.863027753196167 });
});

it('Converts shorthand HEX to HSVA', () => {
Expand Down Expand Up @@ -429,17 +430,17 @@ it('Validates HEX colors', () => {
});

it('Converts XY to RGB', () => {
expect(xyToRgb({ x: 0.3127159072215825, y: 0.3290014805066623, bri: 1 })).toMatchObject({ r: 255, g: 255, b: 255 });
expect(xyToRgb({ x: 0.9505, y: 1, bri: 1.089 })).toMatchObject({ r: 255, g: 255, b: 255 });
expect(xyToRgb({ x: 0.0, y: 0.0, bri: 0 })).toMatchObject({ r: 0, g: 0, b: 0 });
expect(xyToRgb({ x: 0.19313993893216994, y: 0.17053314882681408, bri: 0.23128809648982562 })).toMatchObject({
expect(xyToRgb({ x: 0.26194888875915034, y: 0.23128809648982562, bri: 0.863027753196167 })).toMatchObject({
r: 71,
g: 128,
b: 241,
});
});

it('Converts XY to HEX', () => {
expect(xyToHex({ x: 0.3127159072215825, y: 0.3290014805066623, bri: 1 })).toBe('#ffffff');
expect(xyToHex({ x: 0.9505, y: 1, bri: 1.089 })).toBe('#ffffff');
expect(xyToHex({ x: 0.0, y: 0.0, bri: 0 })).toBe('#000000');
expect(xyToHex({ x: 0.19313993893216994, y: 0.17053314882681408, bri: 0.23128809648982562 })).toBe('#4780f1');
expect(xyToHex({ x: 0.26194888875915034, y: 0.23128809648982562, bri: 0.863027753196167 })).toBe('#4780f1');
});

0 comments on commit 26985d0

Please sign in to comment.