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