Permalink
Browse files

Add hwb()

  • Loading branch information...
1 parent 6ce6490 commit bda7ba5ca6b8fcbe22874ba9820ab05ce1749abf @MoOx MoOx committed Jul 14, 2014
Showing with 147 additions and 17 deletions.
  1. +107 −17 conversions.js
  2. +40 −0 test/basic.js
View
@@ -3,6 +3,7 @@
module.exports = {
rgb2hsl: rgb2hsl,
rgb2hsv: rgb2hsv,
+ rgb2hwb: rgb2hwb,
rgb2cmyk: rgb2cmyk,
rgb2keyword: rgb2keyword,
rgb2xyz: rgb2xyz,
@@ -11,30 +12,40 @@ module.exports = {
hsl2rgb: hsl2rgb,
hsl2hsv: hsl2hsv,
+ hsl2hwb: hsl2hwb,
hsl2cmyk: hsl2cmyk,
hsl2keyword: hsl2keyword,
hsv2rgb: hsv2rgb,
hsv2hsl: hsv2hsl,
+ hsv2hwb: hsv2hwb,
hsv2cmyk: hsv2cmyk,
hsv2keyword: hsv2keyword,
+ hwb2rgb: hwb2rgb,
+ hwb2hsl: hwb2hsl,
+ hwb2hsv: hwb2hsv,
+ hwb2cmyk: hwb2cmyk,
+ hwb2keyword: hwb2keyword,
+
cmyk2rgb: cmyk2rgb,
cmyk2hsl: cmyk2hsl,
cmyk2hsv: cmyk2hsv,
+ cmyk2hwb: cmyk2hwb,
cmyk2keyword: cmyk2keyword,
-
+
keyword2rgb: keyword2rgb,
keyword2hsl: keyword2hsl,
keyword2hsv: keyword2hsv,
+ keyword2hwb: keyword2hwb,
keyword2cmyk: keyword2cmyk,
keyword2lab: keyword2lab,
keyword2xyz: keyword2xyz,
-
+
xyz2rgb: xyz2rgb,
xyz2lab: xyz2lab,
xyz2lch: xyz2lch,
-
+
lab2xyz: lab2xyz,
lab2rgb: lab2rgb,
lab2lch: lab2lch,
@@ -56,10 +67,10 @@ function rgb2hsl(rgb) {
if (max == min)
h = 0;
- else if (r == max)
- h = (g - b) / delta;
+ else if (r == max)
+ h = (g - b) / delta;
else if (g == max)
- h = 2 + (b - r) / delta;
+ h = 2 + (b - r) / delta;
else if (b == max)
h = 4 + (r - g)/ delta;
@@ -96,29 +107,40 @@ function rgb2hsv(rgb) {
if (max == min)
h = 0;
- else if (r == max)
- h = (g - b) / delta;
+ else if (r == max)
+ h = (g - b) / delta;
else if (g == max)
- h = 2 + (b - r) / delta;
+ h = 2 + (b - r) / delta;
else if (b == max)
h = 4 + (r - g) / delta;
h = Math.min(h * 60, 360);
- if (h < 0)
+ if (h < 0)
h += 360;
v = ((max / 255) * 1000) / 10;
return [h, s, v];
}
+function rgb2hwb(rgb) {
+ var r = rgb[0],
+ g = rgb[1],
+ b = rgb[2],
+ h = rgb2hsl(rgb)[0]
+ w = 1/255 * Math.min(r, Math.min(g, b))
+ b = 1 - 1/255 * Math.max(r, Math.max(g, b));
+
+ return [h, w * 100, b * 100];
+}
+
function rgb2cmyk(rgb) {
var r = rgb[0] / 255,
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);
m = (1 - g - k) / (1 - k);
@@ -139,7 +161,7 @@ function rgb2xyz(rgb) {
r = r > 0.04045 ? Math.pow(((r + 0.055) / 1.055), 2.4) : (r / 12.92);
g = g > 0.04045 ? Math.pow(((g + 0.055) / 1.055), 2.4) : (g / 12.92);
b = b > 0.04045 ? Math.pow(((b + 0.055) / 1.055), 2.4) : (b / 12.92);
-
+
var x = (r * 0.4124) + (g * 0.3576) + (b * 0.1805);
var y = (r * 0.2126) + (g * 0.7152) + (b * 0.0722);
var z = (r * 0.0193) + (g * 0.1192) + (b * 0.9505);
@@ -165,7 +187,7 @@ function rgb2lab(rgb) {
l = (116 * y) - 16;
a = 500 * (x - y);
b = 200 * (y - z);
-
+
return [l, a, b];
}
@@ -207,7 +229,7 @@ function hsl2rgb(hsl) {
rgb[i] = val * 255;
}
-
+
return rgb;
}
@@ -223,6 +245,10 @@ function hsl2hsv(hsl) {
return [h, sv * 100, v * 100];
}
+function hsl2hwb(args) {
+ return rgb2hwb(hsl2rgb(args));
+}
+
function hsl2cmyk(args) {
return rgb2cmyk(hsl2rgb(args));
}
@@ -266,13 +292,17 @@ function hsv2hsl(hsv) {
v = hsv[2] / 100,
sl, l;
- l = (2 - s) * v;
+ l = (2 - s) * v;
sl = s * v;
sl /= (l <= 1) ? l : 2 - l;
l /= 2;
return [h, sl * 100, l * 100];
}
+function hsv2hwb(args) {
+ return rgb2hwb(hsv2rgb(args))
+}
+
function hsv2cmyk(args) {
return rgb2cmyk(hsv2rgb(args));
}
@@ -281,6 +311,58 @@ function hsv2keyword(args) {
return rgb2keyword(hsv2rgb(args));
}
+// http://dev.w3.org/csswg/css-color/#hwb-to-rgb
+function hwb2rgb(hwb) {
+ var h = hwb[0] / 360,
+ wh = hwb[1] / 100,
+ bl = hwb[2] / 100,
+ ratio = wh + bl,
+ i, v, f, n;
+
+ // wh + bl cant be > 1
+ if (ratio > 1) {
+ wh /= ratio;
+ bl /= ratio;
+ }
+
+ i = Math.floor(6 * h);
+ v = 1 - bl;
+ f = 6 * h - i;
+ if ((i & 0x01) != 0) {
+ f = 1 - f;
+ }
+ n = wh + f * (v - wh); // linear interpolation
+
+ switch (i) {
+ default:
+ case 6:
+ case 0: r = v; g = n; b = wh; break;
+ case 1: r = n; g = v; b = wh; break;
+ case 2: r = wh; g = v; b = n; break;
+ case 3: r = wh; g = n; b = v; break;
+ case 4: r = n; g = wh; b = v; break;
+ case 5: r = v; g = wh; b = n; break;
+ }
+
+ return [r * 255, g * 255, b * 255];
+}
+
+function hwb2hsl(args) {
+ return rgb2hsl(hwb2rgb(args));
+}
+
+function hwb2hsv(args) {
+ return rgb2hsv(hwb2rgb(args));
+}
+
+function hwb2cmyk(args) {
+ return rgb2cmyk(hwb2rgb(args));
+}
+
+function hwb2keyword(args) {
+ return rgb2keyword(hwb2rgb(args));
+}
+
function cmyk2rgb(cmyk) {
var c = cmyk[0] / 100,
m = cmyk[1] / 100,
@@ -302,6 +384,10 @@ function cmyk2hsv(args) {
return rgb2hsv(cmyk2rgb(args));
}
+function cmyk2hwb(args) {
+ return rgb2hwb(cmyk2rgb(args));
+}
+
function cmyk2keyword(args) {
return rgb2keyword(cmyk2rgb(args));
}
@@ -323,7 +409,7 @@ function xyz2rgb(xyz) {
g = g > 0.0031308 ? ((1.055 * Math.pow(g, 1.0 / 2.4)) - 0.055)
: g = (g * 12.92);
-
+
b = b > 0.0031308 ? ((1.055 * Math.pow(b, 1.0 / 2.4)) - 0.055)
: b = (b * 12.92);
@@ -351,7 +437,7 @@ function xyz2lab(xyz) {
l = (116 * y) - 16;
a = 500 * (x - y);
b = 200 * (y - z);
-
+
return [l, a, b];
}
@@ -431,6 +517,10 @@ function keyword2hsv(args) {
return rgb2hsv(keyword2rgb(args));
}
+function keyword2hwb(args) {
+ return rgb2hwb(keyword2rgb(args));
+}
+
function keyword2cmyk(args) {
return rgb2cmyk(keyword2rgb(args));
}
View
@@ -3,6 +3,7 @@ var convert = require("../index"),
assert.deepEqual(convert.rgb2hsl([140, 200, 100]), [96, 48, 59]);
assert.deepEqual(convert.rgb2hsv([140, 200, 100]), [96, 50, 78]);
+assert.deepEqual(convert.rgb2hwb([140, 200, 100]), [96, 39, 22]);
assert.deepEqual(convert.rgb2cmyk([140, 200, 100]), [30, 0, 50, 22]);
assert.deepEqual(convert.rgb2keyword([255, 228, 196]), "bisque");
assert.deepEqual(convert.rgb2xyz([92, 191, 84]), [25, 40, 15]);
@@ -11,22 +12,26 @@ assert.deepEqual(convert.rgb2lch([92, 191, 84]), [70, 67, 138]);
assert.deepEqual(convert.hsl2rgb([96, 48, 59]), [140, 201, 100]);
assert.deepEqual(convert.hsl2hsv([96, 48, 59]), [96, 50, 79]); // colorpicker says [96,50,79]
+assert.deepEqual(convert.hsl2hwb([96, 48, 59]), [96, 39, 21]); // computer round to 21, should be 22
assert.deepEqual(convert.hsl2cmyk([96, 48, 59]), [30, 0, 50, 21]);
assert.deepEqual(convert.hsl2keyword([240, 100, 50]), "blue");
assert.deepEqual(convert.hsv2rgb([96, 50, 78]), [139, 199, 99]);
assert.deepEqual(convert.hsv2hsl([96, 50, 78]), [96, 47, 59]);
+assert.deepEqual(convert.hsv2hwb([96, 50, 78]), [96, 39, 22]);
assert.deepEqual(convert.hsv2cmyk([96, 50, 78]), [30, 0, 50, 22]);
assert.deepEqual(convert.hsv2keyword([240, 100, 100]), "blue");
assert.deepEqual(convert.cmyk2rgb([30, 0, 50, 22]), [139, 199, 99]);
assert.deepEqual(convert.cmyk2hsl([30, 0, 50, 22]), [96, 47, 59]);
assert.deepEqual(convert.cmyk2hsv([30, 0, 50, 22]), [96, 50, 78]);
+assert.deepEqual(convert.cmyk2hwb([30, 0, 50, 22]), [96, 39, 22]);
assert.deepEqual(convert.cmyk2keyword([100, 100, 0, 0]), "blue");
assert.deepEqual(convert.keyword2rgb("blue"), [0, 0, 255]);
assert.deepEqual(convert.keyword2hsl("blue"), [240, 100, 50]);
assert.deepEqual(convert.keyword2hsv("blue"), [240, 100, 100]);
+assert.deepEqual(convert.keyword2hwb("blue"), [240, 0, 0]);
assert.deepEqual(convert.keyword2cmyk("blue"), [100, 100, 0, 0]);
assert.deepEqual(convert.keyword2lab("blue"), [32, 79, -108]);
assert.deepEqual(convert.keyword2xyz("blue"), [18, 7, 95]);
@@ -60,6 +65,9 @@ assert.deepEqual(round(convert.rgb2hslRaw([140, 200, 100])), [96, 47.6, 58.8]);
assert.deepEqual(round(convert.hsv2rgbRaw([96, 50, 78])), [139.2, 198.9, 99.5]);
assert.deepEqual(round(convert.rgb2hsvRaw([140, 200, 100])), [96, 50, 78.4]);
+assert.deepEqual(round(convert.hwb2rgbRaw([96, 39, 22])), [139.2, 198.9, 99.5]);
+assert.deepEqual(round(convert.rgb2hwbRaw([140, 200, 100])), [96, 39.2, 21.6]);
+
assert.deepEqual(round(convert.cmyk2rgbRaw([30, 0, 50, 22])), [139.2, 198.9, 99.5]);
assert.deepEqual(round(convert.rgb2cmykRaw([140, 200, 100])), [30, 0, 50, 21.6]);
@@ -69,6 +77,8 @@ assert.deepEqual(convert.rgb2keywordRaw([255, 228, 196]), "bisque");
assert.deepEqual(round(convert.hsv2hslRaw([96, 50, 78])), [96, 47, 58.5]);
assert.deepEqual(round(convert.hsl2hsvRaw([96, 48, 59])), [96, 50, 78.7]);
+assert.deepEqual(round(convert.hsl2hsvRaw([96, 48, 59])), [96, 50, 78.7]);
+
assert.deepEqual(round(convert.xyz2rgbRaw([25, 40, 15])), [97.4, 189.9, 85]);
assert.deepEqual(round(convert.rgb2xyzRaw([92, 191, 84])), [24.6, 40.2, 14.8]);
@@ -78,6 +88,7 @@ assert.deepEqual(round(convert.rgb2labRaw([92, 191, 84])), [69.6, -50.1, 44.6]);
var val = [140, 200, 100];
assert.deepEqual(convert["rgb"]["hsl"](val), convert.rgb2hsl(val));
assert.deepEqual(convert["rgb"]["hsv"](val), convert.rgb2hsv(val));
+assert.deepEqual(convert["rgb"]["hwb"](val), convert.rgb2hwb(val));
assert.deepEqual(convert["rgb"]["cmyk"](val), convert.rgb2cmyk(val));
assert.deepEqual(convert["rgb"]["xyz"](val), convert.rgb2xyz(val));
assert.deepEqual(convert["rgb"]["lab"](val), convert.rgb2lab(val));
@@ -86,25 +97,29 @@ assert.deepEqual(convert["rgb"]["keyword"]([255, 228, 196]), "bisque");
val = [96, 48, 59];
assert.deepEqual(convert["hsl"]["rgb"](val), convert.hsl2rgb(val));
assert.deepEqual(convert["hsl"]["hsv"](val), convert.hsl2hsv(val));
+assert.deepEqual(convert["hsl"]["hwb"](val), convert.hsl2hwb(val));
assert.deepEqual(convert["hsl"]["cmyk"](val), convert.hsl2cmyk(val));
assert.deepEqual(convert["hsl"]["keyword"](val), convert.hsl2keyword(val ));
val = [96, 50, 78];
assert.deepEqual(convert["hsv"]["rgb"](val), convert.hsv2rgb(val));
assert.deepEqual(convert["hsv"]["hsl"](val), convert.hsv2hsl(val));
+assert.deepEqual(convert["hsv"]["hwb"](val), convert.hsv2hwb(val));
assert.deepEqual(convert["hsv"]["cmyk"](val), convert.hsv2cmyk(val));
assert.deepEqual(convert["hsv"]["keyword"](val), convert.hsv2keyword(val));
val = [30, 0, 50, 22];
assert.deepEqual(convert["cmyk"]["rgb"](val), convert.cmyk2rgb(val));
assert.deepEqual(convert["cmyk"]["hsl"](val), convert.cmyk2hsl(val));
assert.deepEqual(convert["cmyk"]["hsv"](val), convert.cmyk2hsv(val));
+assert.deepEqual(convert["cmyk"]["hwb"](val), convert.cmyk2hwb(val));
assert.deepEqual(convert["cmyk"]["keyword"](val), convert.cmyk2keyword(val));
val = "blue";
assert.deepEqual(convert["keyword"]["rgb"](val), convert.keyword2rgb(val));
assert.deepEqual(convert["keyword"]["hsl"](val), convert.keyword2hsl(val));
assert.deepEqual(convert["keyword"]["hsv"](val), convert.keyword2hsv(val));
+assert.deepEqual(convert["keyword"]["hwb"](val), convert.keyword2hwb(val));
assert.deepEqual(convert["keyword"]["cmyk"](val), convert.keyword2cmyk(val));
assert.deepEqual(convert["keyword"]["lab"](val), convert.keyword2lab(val));
assert.deepEqual(convert["keyword"]["xyz"](val), convert.keyword2xyz(val));
@@ -135,3 +150,28 @@ assert.deepEqual(converter.rgb(), convert.hsl2rgb(vals));
assert.deepEqual(converter.hsv(), convert.hsl2hsv(vals));
assert.deepEqual(converter.cmyk(), convert.hsl2cmyk(vals));
assert.deepEqual(converter.keyword(), convert.hsl2keyword(vals));
+
+// hwb
+// http://dev.w3.org/csswg/css-color/#hwb-examples
+
+// all extrem value should give black, white or grey
+for(var angle = 0; angle <= 360; angle ++) {
+ assert.deepEqual(convert.hwb2rgb([angle, 0, 100]), [0, 0, 0]);
+ assert.deepEqual(convert.hwb2rgb([angle, 100, 0]), [255, 255, 255]);
+ assert.deepEqual(convert.hwb2rgb([angle, 100, 100]), [128, 128, 128]);
+}
+
+assert.deepEqual(convert.hwb2rgb([0, 0, 0]), [255,0,0]);
+assert.deepEqual(convert.hwb2rgb([0, 20, 40]), [153, 51, 51]);
+assert.deepEqual(convert.hwb2rgb([0, 40, 40]), [153, 102, 102]);
+assert.deepEqual(convert.hwb2rgb([0, 40, 20]), [204, 102, 102]);
+
+assert.deepEqual(convert.hwb2rgb([120, 0, 0]), [0,255,0]);
+assert.deepEqual(convert.hwb2rgb([120, 20, 40]), [51, 153, 51]);
+assert.deepEqual(convert.hwb2rgb([120, 40, 40]), [102, 153, 102]);
+assert.deepEqual(convert.hwb2rgb([120, 40, 20]), [102, 204, 102]);
+
+assert.deepEqual(convert.hwb2rgb([240, 0, 0]), [0,0,255]);
+assert.deepEqual(convert.hwb2rgb([240, 20, 40]), [51, 51, 153]);
+assert.deepEqual(convert.hwb2rgb([240, 40, 40]), [102, 102, 153]);
+assert.deepEqual(convert.hwb2rgb([240, 40, 20]), [102, 102, 204]);

0 comments on commit bda7ba5

Please sign in to comment.