conversions.js 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839
  1. /* MIT license */
  2. /* eslint-disable no-mixed-operators */
  3. const cssKeywords = require('color-name');
  4. // NOTE: conversions should only return primitive values (i.e. arrays, or
  5. // values that give correct `typeof` results).
  6. // do not use box values types (i.e. Number(), String(), etc.)
  7. const reverseKeywords = {};
  8. for (const key of Object.keys(cssKeywords)) {
  9. reverseKeywords[cssKeywords[key]] = key;
  10. }
  11. const convert = {
  12. rgb: {channels: 3, labels: 'rgb'},
  13. hsl: {channels: 3, labels: 'hsl'},
  14. hsv: {channels: 3, labels: 'hsv'},
  15. hwb: {channels: 3, labels: 'hwb'},
  16. cmyk: {channels: 4, labels: 'cmyk'},
  17. xyz: {channels: 3, labels: 'xyz'},
  18. lab: {channels: 3, labels: 'lab'},
  19. lch: {channels: 3, labels: 'lch'},
  20. hex: {channels: 1, labels: ['hex']},
  21. keyword: {channels: 1, labels: ['keyword']},
  22. ansi16: {channels: 1, labels: ['ansi16']},
  23. ansi256: {channels: 1, labels: ['ansi256']},
  24. hcg: {channels: 3, labels: ['h', 'c', 'g']},
  25. apple: {channels: 3, labels: ['r16', 'g16', 'b16']},
  26. gray: {channels: 1, labels: ['gray']}
  27. };
  28. module.exports = convert;
  29. // Hide .channels and .labels properties
  30. for (const model of Object.keys(convert)) {
  31. if (!('channels' in convert[model])) {
  32. throw new Error('missing channels property: ' + model);
  33. }
  34. if (!('labels' in convert[model])) {
  35. throw new Error('missing channel labels property: ' + model);
  36. }
  37. if (convert[model].labels.length !== convert[model].channels) {
  38. throw new Error('channel and label counts mismatch: ' + model);
  39. }
  40. const {channels, labels} = convert[model];
  41. delete convert[model].channels;
  42. delete convert[model].labels;
  43. Object.defineProperty(convert[model], 'channels', {value: channels});
  44. Object.defineProperty(convert[model], 'labels', {value: labels});
  45. }
  46. convert.rgb.hsl = function (rgb) {
  47. const r = rgb[0] / 255;
  48. const g = rgb[1] / 255;
  49. const b = rgb[2] / 255;
  50. const min = Math.min(r, g, b);
  51. const max = Math.max(r, g, b);
  52. const delta = max - min;
  53. let h;
  54. let s;
  55. if (max === min) {
  56. h = 0;
  57. } else if (r === max) {
  58. h = (g - b) / delta;
  59. } else if (g === max) {
  60. h = 2 + (b - r) / delta;
  61. } else if (b === max) {
  62. h = 4 + (r - g) / delta;
  63. }
  64. h = Math.min(h * 60, 360);
  65. if (h < 0) {
  66. h += 360;
  67. }
  68. const l = (min + max) / 2;
  69. if (max === min) {
  70. s = 0;
  71. } else if (l <= 0.5) {
  72. s = delta / (max + min);
  73. } else {
  74. s = delta / (2 - max - min);
  75. }
  76. return [h, s * 100, l * 100];
  77. };
  78. convert.rgb.hsv = function (rgb) {
  79. let rdif;
  80. let gdif;
  81. let bdif;
  82. let h;
  83. let s;
  84. const r = rgb[0] / 255;
  85. const g = rgb[1] / 255;
  86. const b = rgb[2] / 255;
  87. const v = Math.max(r, g, b);
  88. const diff = v - Math.min(r, g, b);
  89. const diffc = function (c) {
  90. return (v - c) / 6 / diff + 1 / 2;
  91. };
  92. if (diff === 0) {
  93. h = 0;
  94. s = 0;
  95. } else {
  96. s = diff / v;
  97. rdif = diffc(r);
  98. gdif = diffc(g);
  99. bdif = diffc(b);
  100. if (r === v) {
  101. h = bdif - gdif;
  102. } else if (g === v) {
  103. h = (1 / 3) + rdif - bdif;
  104. } else if (b === v) {
  105. h = (2 / 3) + gdif - rdif;
  106. }
  107. if (h < 0) {
  108. h += 1;
  109. } else if (h > 1) {
  110. h -= 1;
  111. }
  112. }
  113. return [
  114. h * 360,
  115. s * 100,
  116. v * 100
  117. ];
  118. };
  119. convert.rgb.hwb = function (rgb) {
  120. const r = rgb[0];
  121. const g = rgb[1];
  122. let b = rgb[2];
  123. const h = convert.rgb.hsl(rgb)[0];
  124. const w = 1 / 255 * Math.min(r, Math.min(g, b));
  125. b = 1 - 1 / 255 * Math.max(r, Math.max(g, b));
  126. return [h, w * 100, b * 100];
  127. };
  128. convert.rgb.cmyk = function (rgb) {
  129. const r = rgb[0] / 255;
  130. const g = rgb[1] / 255;
  131. const b = rgb[2] / 255;
  132. const k = Math.min(1 - r, 1 - g, 1 - b);
  133. const c = (1 - r - k) / (1 - k) || 0;
  134. const m = (1 - g - k) / (1 - k) || 0;
  135. const y = (1 - b - k) / (1 - k) || 0;
  136. return [c * 100, m * 100, y * 100, k * 100];
  137. };
  138. function comparativeDistance(x, y) {
  139. /*
  140. See https://en.m.wikipedia.org/wiki/Euclidean_distance#Squared_Euclidean_distance
  141. */
  142. return (
  143. ((x[0] - y[0]) ** 2) +
  144. ((x[1] - y[1]) ** 2) +
  145. ((x[2] - y[2]) ** 2)
  146. );
  147. }
  148. convert.rgb.keyword = function (rgb) {
  149. const reversed = reverseKeywords[rgb];
  150. if (reversed) {
  151. return reversed;
  152. }
  153. let currentClosestDistance = Infinity;
  154. let currentClosestKeyword;
  155. for (const keyword of Object.keys(cssKeywords)) {
  156. const value = cssKeywords[keyword];
  157. // Compute comparative distance
  158. const distance = comparativeDistance(rgb, value);
  159. // Check if its less, if so set as closest
  160. if (distance < currentClosestDistance) {
  161. currentClosestDistance = distance;
  162. currentClosestKeyword = keyword;
  163. }
  164. }
  165. return currentClosestKeyword;
  166. };
  167. convert.keyword.rgb = function (keyword) {
  168. return cssKeywords[keyword];
  169. };
  170. convert.rgb.xyz = function (rgb) {
  171. let r = rgb[0] / 255;
  172. let g = rgb[1] / 255;
  173. let b = rgb[2] / 255;
  174. // Assume sRGB
  175. r = r > 0.04045 ? (((r + 0.055) / 1.055) ** 2.4) : (r / 12.92);
  176. g = g > 0.04045 ? (((g + 0.055) / 1.055) ** 2.4) : (g / 12.92);
  177. b = b > 0.04045 ? (((b + 0.055) / 1.055) ** 2.4) : (b / 12.92);
  178. const x = (r * 0.4124) + (g * 0.3576) + (b * 0.1805);
  179. const y = (r * 0.2126) + (g * 0.7152) + (b * 0.0722);
  180. const z = (r * 0.0193) + (g * 0.1192) + (b * 0.9505);
  181. return [x * 100, y * 100, z * 100];
  182. };
  183. convert.rgb.lab = function (rgb) {
  184. const xyz = convert.rgb.xyz(rgb);
  185. let x = xyz[0];
  186. let y = xyz[1];
  187. let z = xyz[2];
  188. x /= 95.047;
  189. y /= 100;
  190. z /= 108.883;
  191. x = x > 0.008856 ? (x ** (1 / 3)) : (7.787 * x) + (16 / 116);
  192. y = y > 0.008856 ? (y ** (1 / 3)) : (7.787 * y) + (16 / 116);
  193. z = z > 0.008856 ? (z ** (1 / 3)) : (7.787 * z) + (16 / 116);
  194. const l = (116 * y) - 16;
  195. const a = 500 * (x - y);
  196. const b = 200 * (y - z);
  197. return [l, a, b];
  198. };
  199. convert.hsl.rgb = function (hsl) {
  200. const h = hsl[0] / 360;
  201. const s = hsl[1] / 100;
  202. const l = hsl[2] / 100;
  203. let t2;
  204. let t3;
  205. let val;
  206. if (s === 0) {
  207. val = l * 255;
  208. return [val, val, val];
  209. }
  210. if (l < 0.5) {
  211. t2 = l * (1 + s);
  212. } else {
  213. t2 = l + s - l * s;
  214. }
  215. const t1 = 2 * l - t2;
  216. const rgb = [0, 0, 0];
  217. for (let i = 0; i < 3; i++) {
  218. t3 = h + 1 / 3 * -(i - 1);
  219. if (t3 < 0) {
  220. t3++;
  221. }
  222. if (t3 > 1) {
  223. t3--;
  224. }
  225. if (6 * t3 < 1) {
  226. val = t1 + (t2 - t1) * 6 * t3;
  227. } else if (2 * t3 < 1) {
  228. val = t2;
  229. } else if (3 * t3 < 2) {
  230. val = t1 + (t2 - t1) * (2 / 3 - t3) * 6;
  231. } else {
  232. val = t1;
  233. }
  234. rgb[i] = val * 255;
  235. }
  236. return rgb;
  237. };
  238. convert.hsl.hsv = function (hsl) {
  239. const h = hsl[0];
  240. let s = hsl[1] / 100;
  241. let l = hsl[2] / 100;
  242. let smin = s;
  243. const lmin = Math.max(l, 0.01);
  244. l *= 2;
  245. s *= (l <= 1) ? l : 2 - l;
  246. smin *= lmin <= 1 ? lmin : 2 - lmin;
  247. const v = (l + s) / 2;
  248. const sv = l === 0 ? (2 * smin) / (lmin + smin) : (2 * s) / (l + s);
  249. return [h, sv * 100, v * 100];
  250. };
  251. convert.hsv.rgb = function (hsv) {
  252. const h = hsv[0] / 60;
  253. const s = hsv[1] / 100;
  254. let v = hsv[2] / 100;
  255. const hi = Math.floor(h) % 6;
  256. const f = h - Math.floor(h);
  257. const p = 255 * v * (1 - s);
  258. const q = 255 * v * (1 - (s * f));
  259. const t = 255 * v * (1 - (s * (1 - f)));
  260. v *= 255;
  261. switch (hi) {
  262. case 0:
  263. return [v, t, p];
  264. case 1:
  265. return [q, v, p];
  266. case 2:
  267. return [p, v, t];
  268. case 3:
  269. return [p, q, v];
  270. case 4:
  271. return [t, p, v];
  272. case 5:
  273. return [v, p, q];
  274. }
  275. };
  276. convert.hsv.hsl = function (hsv) {
  277. const h = hsv[0];
  278. const s = hsv[1] / 100;
  279. const v = hsv[2] / 100;
  280. const vmin = Math.max(v, 0.01);
  281. let sl;
  282. let l;
  283. l = (2 - s) * v;
  284. const lmin = (2 - s) * vmin;
  285. sl = s * vmin;
  286. sl /= (lmin <= 1) ? lmin : 2 - lmin;
  287. sl = sl || 0;
  288. l /= 2;
  289. return [h, sl * 100, l * 100];
  290. };
  291. // http://dev.w3.org/csswg/css-color/#hwb-to-rgb
  292. convert.hwb.rgb = function (hwb) {
  293. const h = hwb[0] / 360;
  294. let wh = hwb[1] / 100;
  295. let bl = hwb[2] / 100;
  296. const ratio = wh + bl;
  297. let f;
  298. // Wh + bl cant be > 1
  299. if (ratio > 1) {
  300. wh /= ratio;
  301. bl /= ratio;
  302. }
  303. const i = Math.floor(6 * h);
  304. const v = 1 - bl;
  305. f = 6 * h - i;
  306. if ((i & 0x01) !== 0) {
  307. f = 1 - f;
  308. }
  309. const n = wh + f * (v - wh); // Linear interpolation
  310. let r;
  311. let g;
  312. let b;
  313. /* eslint-disable max-statements-per-line,no-multi-spaces */
  314. switch (i) {
  315. default:
  316. case 6:
  317. case 0: r = v; g = n; b = wh; break;
  318. case 1: r = n; g = v; b = wh; break;
  319. case 2: r = wh; g = v; b = n; break;
  320. case 3: r = wh; g = n; b = v; break;
  321. case 4: r = n; g = wh; b = v; break;
  322. case 5: r = v; g = wh; b = n; break;
  323. }
  324. /* eslint-enable max-statements-per-line,no-multi-spaces */
  325. return [r * 255, g * 255, b * 255];
  326. };
  327. convert.cmyk.rgb = function (cmyk) {
  328. const c = cmyk[0] / 100;
  329. const m = cmyk[1] / 100;
  330. const y = cmyk[2] / 100;
  331. const k = cmyk[3] / 100;
  332. const r = 1 - Math.min(1, c * (1 - k) + k);
  333. const g = 1 - Math.min(1, m * (1 - k) + k);
  334. const b = 1 - Math.min(1, y * (1 - k) + k);
  335. return [r * 255, g * 255, b * 255];
  336. };
  337. convert.xyz.rgb = function (xyz) {
  338. const x = xyz[0] / 100;
  339. const y = xyz[1] / 100;
  340. const z = xyz[2] / 100;
  341. let r;
  342. let g;
  343. let b;
  344. r = (x * 3.2406) + (y * -1.5372) + (z * -0.4986);
  345. g = (x * -0.9689) + (y * 1.8758) + (z * 0.0415);
  346. b = (x * 0.0557) + (y * -0.2040) + (z * 1.0570);
  347. // Assume sRGB
  348. r = r > 0.0031308
  349. ? ((1.055 * (r ** (1.0 / 2.4))) - 0.055)
  350. : r * 12.92;
  351. g = g > 0.0031308
  352. ? ((1.055 * (g ** (1.0 / 2.4))) - 0.055)
  353. : g * 12.92;
  354. b = b > 0.0031308
  355. ? ((1.055 * (b ** (1.0 / 2.4))) - 0.055)
  356. : b * 12.92;
  357. r = Math.min(Math.max(0, r), 1);
  358. g = Math.min(Math.max(0, g), 1);
  359. b = Math.min(Math.max(0, b), 1);
  360. return [r * 255, g * 255, b * 255];
  361. };
  362. convert.xyz.lab = function (xyz) {
  363. let x = xyz[0];
  364. let y = xyz[1];
  365. let z = xyz[2];
  366. x /= 95.047;
  367. y /= 100;
  368. z /= 108.883;
  369. x = x > 0.008856 ? (x ** (1 / 3)) : (7.787 * x) + (16 / 116);
  370. y = y > 0.008856 ? (y ** (1 / 3)) : (7.787 * y) + (16 / 116);
  371. z = z > 0.008856 ? (z ** (1 / 3)) : (7.787 * z) + (16 / 116);
  372. const l = (116 * y) - 16;
  373. const a = 500 * (x - y);
  374. const b = 200 * (y - z);
  375. return [l, a, b];
  376. };
  377. convert.lab.xyz = function (lab) {
  378. const l = lab[0];
  379. const a = lab[1];
  380. const b = lab[2];
  381. let x;
  382. let y;
  383. let z;
  384. y = (l + 16) / 116;
  385. x = a / 500 + y;
  386. z = y - b / 200;
  387. const y2 = y ** 3;
  388. const x2 = x ** 3;
  389. const z2 = z ** 3;
  390. y = y2 > 0.008856 ? y2 : (y - 16 / 116) / 7.787;
  391. x = x2 > 0.008856 ? x2 : (x - 16 / 116) / 7.787;
  392. z = z2 > 0.008856 ? z2 : (z - 16 / 116) / 7.787;
  393. x *= 95.047;
  394. y *= 100;
  395. z *= 108.883;
  396. return [x, y, z];
  397. };
  398. convert.lab.lch = function (lab) {
  399. const l = lab[0];
  400. const a = lab[1];
  401. const b = lab[2];
  402. let h;
  403. const hr = Math.atan2(b, a);
  404. h = hr * 360 / 2 / Math.PI;
  405. if (h < 0) {
  406. h += 360;
  407. }
  408. const c = Math.sqrt(a * a + b * b);
  409. return [l, c, h];
  410. };
  411. convert.lch.lab = function (lch) {
  412. const l = lch[0];
  413. const c = lch[1];
  414. const h = lch[2];
  415. const hr = h / 360 * 2 * Math.PI;
  416. const a = c * Math.cos(hr);
  417. const b = c * Math.sin(hr);
  418. return [l, a, b];
  419. };
  420. convert.rgb.ansi16 = function (args, saturation = null) {
  421. const [r, g, b] = args;
  422. let value = saturation === null ? convert.rgb.hsv(args)[2] : saturation; // Hsv -> ansi16 optimization
  423. value = Math.round(value / 50);
  424. if (value === 0) {
  425. return 30;
  426. }
  427. let ansi = 30
  428. + ((Math.round(b / 255) << 2)
  429. | (Math.round(g / 255) << 1)
  430. | Math.round(r / 255));
  431. if (value === 2) {
  432. ansi += 60;
  433. }
  434. return ansi;
  435. };
  436. convert.hsv.ansi16 = function (args) {
  437. // Optimization here; we already know the value and don't need to get
  438. // it converted for us.
  439. return convert.rgb.ansi16(convert.hsv.rgb(args), args[2]);
  440. };
  441. convert.rgb.ansi256 = function (args) {
  442. const r = args[0];
  443. const g = args[1];
  444. const b = args[2];
  445. // We use the extended greyscale palette here, with the exception of
  446. // black and white. normal palette only has 4 greyscale shades.
  447. if (r === g && g === b) {
  448. if (r < 8) {
  449. return 16;
  450. }
  451. if (r > 248) {
  452. return 231;
  453. }
  454. return Math.round(((r - 8) / 247) * 24) + 232;
  455. }
  456. const ansi = 16
  457. + (36 * Math.round(r / 255 * 5))
  458. + (6 * Math.round(g / 255 * 5))
  459. + Math.round(b / 255 * 5);
  460. return ansi;
  461. };
  462. convert.ansi16.rgb = function (args) {
  463. let color = args % 10;
  464. // Handle greyscale
  465. if (color === 0 || color === 7) {
  466. if (args > 50) {
  467. color += 3.5;
  468. }
  469. color = color / 10.5 * 255;
  470. return [color, color, color];
  471. }
  472. const mult = (~~(args > 50) + 1) * 0.5;
  473. const r = ((color & 1) * mult) * 255;
  474. const g = (((color >> 1) & 1) * mult) * 255;
  475. const b = (((color >> 2) & 1) * mult) * 255;
  476. return [r, g, b];
  477. };
  478. convert.ansi256.rgb = function (args) {
  479. // Handle greyscale
  480. if (args >= 232) {
  481. const c = (args - 232) * 10 + 8;
  482. return [c, c, c];
  483. }
  484. args -= 16;
  485. let rem;
  486. const r = Math.floor(args / 36) / 5 * 255;
  487. const g = Math.floor((rem = args % 36) / 6) / 5 * 255;
  488. const b = (rem % 6) / 5 * 255;
  489. return [r, g, b];
  490. };
  491. convert.rgb.hex = function (args) {
  492. const integer = ((Math.round(args[0]) & 0xFF) << 16)
  493. + ((Math.round(args[1]) & 0xFF) << 8)
  494. + (Math.round(args[2]) & 0xFF);
  495. const string = integer.toString(16).toUpperCase();
  496. return '000000'.substring(string.length) + string;
  497. };
  498. convert.hex.rgb = function (args) {
  499. const match = args.toString(16).match(/[a-f0-9]{6}|[a-f0-9]{3}/i);
  500. if (!match) {
  501. return [0, 0, 0];
  502. }
  503. let colorString = match[0];
  504. if (match[0].length === 3) {
  505. colorString = colorString.split('').map(char => {
  506. return char + char;
  507. }).join('');
  508. }
  509. const integer = parseInt(colorString, 16);
  510. const r = (integer >> 16) & 0xFF;
  511. const g = (integer >> 8) & 0xFF;
  512. const b = integer & 0xFF;
  513. return [r, g, b];
  514. };
  515. convert.rgb.hcg = function (rgb) {
  516. const r = rgb[0] / 255;
  517. const g = rgb[1] / 255;
  518. const b = rgb[2] / 255;
  519. const max = Math.max(Math.max(r, g), b);
  520. const min = Math.min(Math.min(r, g), b);
  521. const chroma = (max - min);
  522. let grayscale;
  523. let hue;
  524. if (chroma < 1) {
  525. grayscale = min / (1 - chroma);
  526. } else {
  527. grayscale = 0;
  528. }
  529. if (chroma <= 0) {
  530. hue = 0;
  531. } else
  532. if (max === r) {
  533. hue = ((g - b) / chroma) % 6;
  534. } else
  535. if (max === g) {
  536. hue = 2 + (b - r) / chroma;
  537. } else {
  538. hue = 4 + (r - g) / chroma;
  539. }
  540. hue /= 6;
  541. hue %= 1;
  542. return [hue * 360, chroma * 100, grayscale * 100];
  543. };
  544. convert.hsl.hcg = function (hsl) {
  545. const s = hsl[1] / 100;
  546. const l = hsl[2] / 100;
  547. const c = l < 0.5 ? (2.0 * s * l) : (2.0 * s * (1.0 - l));
  548. let f = 0;
  549. if (c < 1.0) {
  550. f = (l - 0.5 * c) / (1.0 - c);
  551. }
  552. return [hsl[0], c * 100, f * 100];
  553. };
  554. convert.hsv.hcg = function (hsv) {
  555. const s = hsv[1] / 100;
  556. const v = hsv[2] / 100;
  557. const c = s * v;
  558. let f = 0;
  559. if (c < 1.0) {
  560. f = (v - c) / (1 - c);
  561. }
  562. return [hsv[0], c * 100, f * 100];
  563. };
  564. convert.hcg.rgb = function (hcg) {
  565. const h = hcg[0] / 360;
  566. const c = hcg[1] / 100;
  567. const g = hcg[2] / 100;
  568. if (c === 0.0) {
  569. return [g * 255, g * 255, g * 255];
  570. }
  571. const pure = [0, 0, 0];
  572. const hi = (h % 1) * 6;
  573. const v = hi % 1;
  574. const w = 1 - v;
  575. let mg = 0;
  576. /* eslint-disable max-statements-per-line */
  577. switch (Math.floor(hi)) {
  578. case 0:
  579. pure[0] = 1; pure[1] = v; pure[2] = 0; break;
  580. case 1:
  581. pure[0] = w; pure[1] = 1; pure[2] = 0; break;
  582. case 2:
  583. pure[0] = 0; pure[1] = 1; pure[2] = v; break;
  584. case 3:
  585. pure[0] = 0; pure[1] = w; pure[2] = 1; break;
  586. case 4:
  587. pure[0] = v; pure[1] = 0; pure[2] = 1; break;
  588. default:
  589. pure[0] = 1; pure[1] = 0; pure[2] = w;
  590. }
  591. /* eslint-enable max-statements-per-line */
  592. mg = (1.0 - c) * g;
  593. return [
  594. (c * pure[0] + mg) * 255,
  595. (c * pure[1] + mg) * 255,
  596. (c * pure[2] + mg) * 255
  597. ];
  598. };
  599. convert.hcg.hsv = function (hcg) {
  600. const c = hcg[1] / 100;
  601. const g = hcg[2] / 100;
  602. const v = c + g * (1.0 - c);
  603. let f = 0;
  604. if (v > 0.0) {
  605. f = c / v;
  606. }
  607. return [hcg[0], f * 100, v * 100];
  608. };
  609. convert.hcg.hsl = function (hcg) {
  610. const c = hcg[1] / 100;
  611. const g = hcg[2] / 100;
  612. const l = g * (1.0 - c) + 0.5 * c;
  613. let s = 0;
  614. if (l > 0.0 && l < 0.5) {
  615. s = c / (2 * l);
  616. } else
  617. if (l >= 0.5 && l < 1.0) {
  618. s = c / (2 * (1 - l));
  619. }
  620. return [hcg[0], s * 100, l * 100];
  621. };
  622. convert.hcg.hwb = function (hcg) {
  623. const c = hcg[1] / 100;
  624. const g = hcg[2] / 100;
  625. const v = c + g * (1.0 - c);
  626. return [hcg[0], (v - c) * 100, (1 - v) * 100];
  627. };
  628. convert.hwb.hcg = function (hwb) {
  629. const w = hwb[1] / 100;
  630. const b = hwb[2] / 100;
  631. const v = 1 - b;
  632. const c = v - w;
  633. let g = 0;
  634. if (c < 1) {
  635. g = (v - c) / (1 - c);
  636. }
  637. return [hwb[0], c * 100, g * 100];
  638. };
  639. convert.apple.rgb = function (apple) {
  640. return [(apple[0] / 65535) * 255, (apple[1] / 65535) * 255, (apple[2] / 65535) * 255];
  641. };
  642. convert.rgb.apple = function (rgb) {
  643. return [(rgb[0] / 255) * 65535, (rgb[1] / 255) * 65535, (rgb[2] / 255) * 65535];
  644. };
  645. convert.gray.rgb = function (args) {
  646. return [args[0] / 100 * 255, args[0] / 100 * 255, args[0] / 100 * 255];
  647. };
  648. convert.gray.hsl = function (args) {
  649. return [0, 0, args[0]];
  650. };
  651. convert.gray.hsv = convert.gray.hsl;
  652. convert.gray.hwb = function (gray) {
  653. return [0, 100, gray[0]];
  654. };
  655. convert.gray.cmyk = function (gray) {
  656. return [0, 0, 0, gray[0]];
  657. };
  658. convert.gray.lab = function (gray) {
  659. return [gray[0], 0, 0];
  660. };
  661. convert.gray.hex = function (gray) {
  662. const val = Math.round(gray[0] / 100 * 255) & 0xFF;
  663. const integer = (val << 16) + (val << 8) + val;
  664. const string = integer.toString(16).toUpperCase();
  665. return '000000'.substring(string.length) + string;
  666. };
  667. convert.rgb.gray = function (rgb) {
  668. const val = (rgb[0] + rgb[1] + rgb[2]) / 3;
  669. return [val / 255 * 100];
  670. };