Skip to content

Commit 7ef0467

Browse files
committed
Update color conversions
1 parent 52efbb6 commit 7ef0467

File tree

5 files changed

+40
-223
lines changed

5 files changed

+40
-223
lines changed

lib/color.js

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
import { convertRGBtoHSL, convertRGBtoHWB, convertHSLtoRGB, convertHSLtoHWB, convertHWBtoRGB, convertHWBtoHSL, convertRGBtoH } from './conversions';
1+
import { rgb2hsl, rgb2hwb, hsl2rgb, hsl2hwb, hwb2rgb, hwb2hsl, rgb2hue } from '@csstools/convert-colors';
22

33
export default class Color {
44
constructor(color) {
55
this.color = Object(Object(color).color || color);
66

77
if (color.colorspace === 'rgb') {
8-
this.color.hue = convertRGBtoH(color.red, color.green, color.blue, color.hue || 0);
8+
this.color.hue = rgb2hue(color.red, color.green, color.blue, color.hue || 0);
99
}
1010
}
1111

@@ -222,7 +222,7 @@ function assign(base, channels) {
222222

223223
if (isRGB) {
224224
// conditionally preserve the hue
225-
color.hue = convertRGBtoH(color.red, color.green, color.blue, base.hue || 0);
225+
color.hue = rgb2hue(color.red, color.green, color.blue, base.hue || 0);
226226
}
227227
}
228228
);
@@ -250,29 +250,29 @@ function normalize(value, channel) {
250250

251251
function color2rgb(color) {
252252
const [ red, green, blue ] = color.colorspace === 'hsl'
253-
? convertHSLtoRGB(color.hue, color.saturation, color.lightness)
253+
? hsl2rgb(color.hue, color.saturation, color.lightness)
254254
: color.colorspace === 'hwb'
255-
? convertHWBtoRGB(color.hue, color.whiteness, color.blackness)
255+
? hwb2rgb(color.hue, color.whiteness, color.blackness)
256256
: [ color.red, color.green, color.blue ];
257257

258258
return { red, green, blue, hue: color.hue, alpha: color.alpha, colorspace: 'rgb' };
259259
}
260260

261261
function color2hsl(color) {
262262
const [ hue, saturation, lightness ] = color.colorspace === 'rgb'
263-
? convertRGBtoHSL(color.red, color.green, color.blue, color.hue)
263+
? rgb2hsl(color.red, color.green, color.blue, color.hue)
264264
: color.colorspace === 'hwb'
265-
? convertHWBtoHSL(color.hue, color.whiteness, color.blackness)
265+
? hwb2hsl(color.hue, color.whiteness, color.blackness)
266266
: [ color.hue, color.saturation, color.lightness ];
267267

268268
return { hue, saturation, lightness, alpha: color.alpha, colorspace: 'hsl' };
269269
}
270270

271271
function color2hwb(color) {
272272
const [ hue, whiteness, blackness ] = color.colorspace === 'rgb'
273-
? convertRGBtoHWB(color.red, color.green, color.blue, color.hue)
273+
? rgb2hwb(color.red, color.green, color.blue, color.hue)
274274
: color.colorspace === 'hsl'
275-
? convertHSLtoHWB(color.hue, color.saturation, color.lightness)
275+
? hsl2hwb(color.hue, color.saturation, color.lightness)
276276
: [ color.hue, color.whiteness, color.blackness ];
277277

278278
return { hue, whiteness, blackness, alpha: color.alpha, colorspace: 'hwb' };

lib/conversions.js

Lines changed: 23 additions & 196 deletions
Original file line numberDiff line numberDiff line change
@@ -26,201 +26,6 @@ export function convertTtoD(turn) {
2626
return turn * 360 % 360;
2727
}
2828

29-
/* Convert Red/Green/Blue to Red/Green/Blue (0 - 255)
30-
/* ========================================================================== */
31-
32-
export function convertRGBtoRGB255(red, green, blue) {
33-
const red255 = convertChannelToChannel255(red);
34-
const green255 = convertChannelToChannel255(green);
35-
const blue255 = convertChannelToChannel255(blue);
36-
37-
return [red255, green255, blue255];
38-
}
39-
40-
/* Convert Red/Green/Blue to Hue/Saturation/Lightness
41-
/* ========================================================================== */
42-
43-
export function convertRGBtoHSL(red, green, blue, fallbackHue = 0) {
44-
const hue = convertRGBtoH(red, green, blue, fallbackHue);
45-
const whiteness = convertRGBtoW(red, green, blue);
46-
const value = convertRGBtoV(red, green, blue);
47-
const lightness = convertWVtoL(whiteness, value);
48-
const saturation = convertLVWtoS(lightness, value, whiteness);
49-
50-
return [ hue, saturation, lightness ];
51-
}
52-
53-
/* Convert Red/Green/Blue to Hue/Whiteness/Blackness
54-
/* ========================================================================== */
55-
56-
export function convertRGBtoHWB(red, green, blue, fallbackHue = 0) {
57-
const hue = convertRGBtoH(red, green, blue, fallbackHue);
58-
const whiteness = convertRGBtoW(red, green, blue);
59-
const value = convertRGBtoV(red, green, blue);
60-
const blackness = convertVtoB(value);
61-
62-
return [ hue, whiteness, blackness ];
63-
}
64-
65-
/* Convert Hue/Saturation/Lightness to Red/Green/Blue (and fallback Hue)
66-
/* ========================================================================== */
67-
68-
export function convertHSLtoRGB(hue, saturation, lightness) {
69-
const hexagon = hue / 60;
70-
71-
const t2 = lightness <= 50
72-
? lightness * (saturation + 100) / 10000
73-
: (lightness + saturation) / 100 - lightness * saturation / 10000;
74-
75-
const t1 = lightness * 0.02 - t2;
76-
77-
const red = convertTTHtoChannel(t1, t2, hexagon + 2) * 100;
78-
const green = convertTTHtoChannel(t1, t2, hexagon) * 100;
79-
const blue = convertTTHtoChannel(t1, t2, hexagon - 2) * 100;
80-
81-
return [red, green, blue];
82-
}
83-
84-
/* Convert Hue/Saturation/Lightness to Hue/Whiteness/Blackness
85-
/* ========================================================================== */
86-
87-
export function convertHSLtoHWB(hue, saturation, lightness) {
88-
const [ red, green, blue ] = convertHSLtoRGB(hue, saturation, lightness);
89-
const [ , whiteness, blackness ] = convertRGBtoHWB(red, green, blue, hue);
90-
91-
return [ hue, whiteness, blackness ];
92-
}
93-
94-
/* Convert Hue/Whiteness/Blackness to Hue/Saturation/Lightness
95-
/* ========================================================================== */
96-
97-
export function convertHWBtoHSL(hue, whiteness, blackness) {
98-
const [ red, green, blue ] = convertHWBtoRGB(hue, whiteness, blackness);
99-
const [ , saturation, lightness ] = convertRGBtoHSL(red, green, blue, hue);
100-
101-
return [ hue, saturation, lightness ];
102-
}
103-
104-
/* Convert Hue/Whiteness/Blackness to Red/Green/Blue (and fallback Hue)
105-
/* ========================================================================== */
106-
107-
export function convertHWBtoRGB(hue, whiteness, blackness) {
108-
const [ hslRed, hslGreen, hslBlue ] = convertHSLtoRGB(hue, 100, 50);
109-
110-
const tot = whiteness + blackness;
111-
const w = tot > 100 ? whiteness / tot * 100 : whiteness;
112-
const b = tot > 100 ? blackness / tot * 100 : blackness;
113-
114-
const red = hslRed * (100 - w - b) / 100 + w;
115-
const green = hslGreen * (100 - w - b) / 100 + w;
116-
const blue = hslBlue * (100 - w - b) / 100 + w;
117-
118-
return [red, green, blue];
119-
}
120-
121-
/* Convert Channel to Channel (0 - 255)
122-
/* ========================================================================== */
123-
124-
export function convertChannelToChannel255(channel) {
125-
return Math.round(channel * 2.55);
126-
}
127-
128-
/* Convert Red/Green/Blue to Hue
129-
/* ========================================================================== */
130-
131-
export function convertRGBtoH(red, green, blue, fallbackHue = 0) {
132-
const whiteness = convertRGBtoW(red, green, blue);
133-
const value = convertRGBtoV(red, green, blue);
134-
const chroma = convertVWtoC(value, whiteness);
135-
136-
if (chroma === 0) {
137-
return fallbackHue;
138-
} else {
139-
const segment = value === red
140-
? (green - blue) / chroma
141-
: value === green
142-
? (blue - red) / chroma
143-
: (red - green) / chroma;
144-
145-
const shift = value === red
146-
? segment < 0
147-
? 360 / 60
148-
: 0 / 60
149-
: value === green
150-
? 120 / 60
151-
: 240 / 60;
152-
153-
const hue = (segment + shift) * 60;
154-
155-
return hue;
156-
}
157-
}
158-
159-
/* Convert Red/Green/Blue to Whiteness
160-
/* ========================================================================== */
161-
162-
export function convertRGBtoW(red, green, blue) {
163-
return Math.min(red, green, blue);
164-
}
165-
166-
/* Convert Red/Green/Blue to Value
167-
/* ========================================================================== */
168-
169-
export function convertRGBtoV(red, green, blue) {
170-
return Math.max(red, green, blue);
171-
}
172-
173-
/* Convert Value/Whiteness to Chroma
174-
/* ========================================================================== */
175-
176-
export function convertVWtoC(value, whiteness) {
177-
return value - whiteness;
178-
}
179-
180-
/* Convert Whiteness/Value to Lightness
181-
/* ========================================================================== */
182-
183-
export function convertWVtoL(whiteness, value) {
184-
return (whiteness + value) / 2;
185-
}
186-
187-
/* Convert Lightness/Value/Whiteness to Saturation
188-
/* ========================================================================== */
189-
190-
export function convertLVWtoS(lightness, value, whiteness) {
191-
return whiteness === value
192-
? 0
193-
: lightness < 50
194-
? (value - whiteness) / (value + whiteness) * 100
195-
: (value - whiteness) / (200 - value - whiteness) * 100;
196-
}
197-
198-
/* Convert Value to Blackness
199-
/* ========================================================================== */
200-
201-
export function convertVtoB(value) {
202-
return 100 - value;
203-
}
204-
205-
/* Convert Hue parts to Channel
206-
/* ========================================================================== */
207-
208-
export function convertTTHtoChannel(t1, t2, hexagon) {
209-
const althexagon = hexagon < 0
210-
? hexagon + 6
211-
: hexagon >= 6
212-
? hexagon - 6
213-
: hexagon;
214-
215-
return althexagon < 1
216-
? (t2 - t1) * althexagon + t1
217-
: althexagon < 3
218-
? t2
219-
: althexagon < 4
220-
? (t2 - t1) * (4 - althexagon) + t1
221-
: t1;
222-
}
223-
22429
/* Convert a Name to Red/Green/Blue
22530
/* ========================================================================== */
22631

@@ -376,5 +181,27 @@ export function convertNtoRGB(name) {
376181
yellowgreen: [154, 205, 50]
377182
};
378183

379-
return names[name];
184+
return names[name] && names[name].map(c => c / 2.55);
380185
}
186+
187+
188+
/* Convert a Hex to Red/Green/Blue
189+
/* ========================================================================== */
190+
191+
export function convertHtoRGB(hex) {
192+
// #<hex-color>{3,4,6,8}
193+
const [r, g, b, a, rr, gg, bb, aa] = (hex.match(hexColorMatch) || []).slice(1);
194+
195+
if (rr !== undefined || r !== undefined) {
196+
const red = rr !== undefined ? parseInt(rr, 16) : r !== undefined ? parseInt(r + r, 16) : 0;
197+
const green = gg !== undefined ? parseInt(gg, 16) : g !== undefined ? parseInt(g + g, 16) : 0;
198+
const blue = bb !== undefined ? parseInt(bb, 16) : b !== undefined ? parseInt(b + b, 16) : 0;
199+
const alpha = aa !== undefined ? parseInt(aa, 16) : a !== undefined ? parseInt(a + a, 16) : 255;
200+
201+
return [red, green, blue, alpha].map(c => c / 2.55);
202+
}
203+
204+
return undefined;
205+
}
206+
207+
const hexColorMatch = /^#(?:([a-f0-9])([a-f0-9])([a-f0-9])([a-f0-9])?|([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})?)$/i;

lib/transform.js

Lines changed: 4 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// tooling
2-
import { convertDtoD, convertGtoD, convertRtoD, convertTtoD, convertNtoRGB } from './conversions';
2+
import { convertDtoD, convertGtoD, convertRtoD, convertTtoD, convertNtoRGB, convertHtoRGB } from './conversions';
33
import Color from './color';
44
import manageUnresolved from './manage-unresolved';
55
import parser from 'postcss-values-parser';
@@ -136,14 +136,9 @@ function transformColorModFunction(node, opts) {
136136
function transformHexColor(node, opts) {
137137
if (hexColorMatch.test(node.value)) {
138138
// #<hex-color>{3,4,6,8}
139-
const [r, g, b, a, rr, gg, bb, aa] = (node.value.match(hexColorMatch) || []).slice(1);
139+
const [red, green, blue, alpha] = convertHtoRGB(node.value);
140140

141-
const color = new Color({
142-
red: rr !== undefined ? parseInt(rr, 16) / 2.55 : r !== undefined ? parseInt(r + r, 16) / 2.55 : 0,
143-
green: gg !== undefined ? parseInt(gg, 16) / 2.55 : g !== undefined ? parseInt(g + g, 16) / 2.55 : 0,
144-
blue: bb !== undefined ? parseInt(bb, 16) / 2.55 : b !== undefined ? parseInt(b + b, 16) / 2.55 : 0,
145-
alpha: aa !== undefined ? parseInt(aa, 16) / 2.55 : a !== undefined ? parseInt(a + a, 16) / 2.55 : 100
146-
});
141+
const color = new Color({ red, green, blue, alpha });
147142

148143
return color;
149144
} else {
@@ -157,13 +152,7 @@ function transformNamedColor(node, opts) {
157152
// <named-color>
158153
const [red, green, blue] = convertNtoRGB(node.value);
159154

160-
const color = new Color({
161-
red: red / 2.55,
162-
green: green / 2.55,
163-
blue: blue / 2.55,
164-
alpha: 100,
165-
colorspace: 'rgb'
166-
});
155+
const color = new Color({ red, green, blue, alpha: 100, colorspace: 'rgb' });
167156

168157
return color;
169158
} else {

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
"node": ">=4.0.0"
2727
},
2828
"dependencies": {
29+
"@csstools/convert-colors": "^1.1",
2930
"postcss": "^6.0",
3031
"postcss-values-parser": "^1.3"
3132
},

test/basic.expect.css

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,10 +70,10 @@ test-lightness-saturation-adjuster {
7070
}
7171

7272
test-blackness-whiteness-adjuster {
73-
color: rgb(207, 207, 207);
74-
color: rgb(200, 200, 200);
73+
color: rgb(204, 204, 204);
74+
color: rgb(194, 194, 194);
7575
color: rgb(248, 248, 220);
76-
color: rgb(134, 134, 134);
76+
color: rgb(55, 55, 55);
7777
color: rgb(245, 245, 51);
7878
color: rgb(245, 245, 223);
7979
color: rgb(245, 245, 169);

0 commit comments

Comments
 (0)