54f16e4f70c75c836d95645c07d4d57901a735abcdd8a4e1f6bbd3ecc214c765164ad9c1fe2882443924cc6386cf06ed6b2d629fec2233b2d71c2fc3a1206d 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. import { bound01, pad2 } from './util.js';
  2. // `rgbToHsl`, `rgbToHsv`, `hslToRgb`, `hsvToRgb` modified from:
  3. // <http://mjijackson.com/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript>
  4. /**
  5. * Handle bounds / percentage checking to conform to CSS color spec
  6. * <http://www.w3.org/TR/css3-color/>
  7. * *Assumes:* r, g, b in [0, 255] or [0, 1]
  8. * *Returns:* { r, g, b } in [0, 255]
  9. */
  10. export function rgbToRgb(r, g, b) {
  11. return {
  12. r: bound01(r, 255) * 255,
  13. g: bound01(g, 255) * 255,
  14. b: bound01(b, 255) * 255,
  15. };
  16. }
  17. /**
  18. * Converts an RGB color value to HSL.
  19. * *Assumes:* r, g, and b are contained in [0, 255] or [0, 1]
  20. * *Returns:* { h, s, l } in [0,1]
  21. */
  22. export function rgbToHsl(r, g, b) {
  23. r = bound01(r, 255);
  24. g = bound01(g, 255);
  25. b = bound01(b, 255);
  26. var max = Math.max(r, g, b);
  27. var min = Math.min(r, g, b);
  28. var h = 0;
  29. var s = 0;
  30. var l = (max + min) / 2;
  31. if (max === min) {
  32. s = 0;
  33. h = 0; // achromatic
  34. }
  35. else {
  36. var d = max - min;
  37. s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
  38. switch (max) {
  39. case r:
  40. h = (g - b) / d + (g < b ? 6 : 0);
  41. break;
  42. case g:
  43. h = (b - r) / d + 2;
  44. break;
  45. case b:
  46. h = (r - g) / d + 4;
  47. break;
  48. default:
  49. break;
  50. }
  51. h /= 6;
  52. }
  53. return { h: h, s: s, l: l };
  54. }
  55. function hue2rgb(p, q, t) {
  56. if (t < 0) {
  57. t += 1;
  58. }
  59. if (t > 1) {
  60. t -= 1;
  61. }
  62. if (t < 1 / 6) {
  63. return p + (q - p) * (6 * t);
  64. }
  65. if (t < 1 / 2) {
  66. return q;
  67. }
  68. if (t < 2 / 3) {
  69. return p + (q - p) * (2 / 3 - t) * 6;
  70. }
  71. return p;
  72. }
  73. /**
  74. * Converts an HSL color value to RGB.
  75. *
  76. * *Assumes:* h is contained in [0, 1] or [0, 360] and s and l are contained [0, 1] or [0, 100]
  77. * *Returns:* { r, g, b } in the set [0, 255]
  78. */
  79. export function hslToRgb(h, s, l) {
  80. var r;
  81. var g;
  82. var b;
  83. h = bound01(h, 360);
  84. s = bound01(s, 100);
  85. l = bound01(l, 100);
  86. if (s === 0) {
  87. // achromatic
  88. g = l;
  89. b = l;
  90. r = l;
  91. }
  92. else {
  93. var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
  94. var p = 2 * l - q;
  95. r = hue2rgb(p, q, h + 1 / 3);
  96. g = hue2rgb(p, q, h);
  97. b = hue2rgb(p, q, h - 1 / 3);
  98. }
  99. return { r: r * 255, g: g * 255, b: b * 255 };
  100. }
  101. /**
  102. * Converts an RGB color value to HSV
  103. *
  104. * *Assumes:* r, g, and b are contained in the set [0, 255] or [0, 1]
  105. * *Returns:* { h, s, v } in [0,1]
  106. */
  107. export function rgbToHsv(r, g, b) {
  108. r = bound01(r, 255);
  109. g = bound01(g, 255);
  110. b = bound01(b, 255);
  111. var max = Math.max(r, g, b);
  112. var min = Math.min(r, g, b);
  113. var h = 0;
  114. var v = max;
  115. var d = max - min;
  116. var s = max === 0 ? 0 : d / max;
  117. if (max === min) {
  118. h = 0; // achromatic
  119. }
  120. else {
  121. switch (max) {
  122. case r:
  123. h = (g - b) / d + (g < b ? 6 : 0);
  124. break;
  125. case g:
  126. h = (b - r) / d + 2;
  127. break;
  128. case b:
  129. h = (r - g) / d + 4;
  130. break;
  131. default:
  132. break;
  133. }
  134. h /= 6;
  135. }
  136. return { h: h, s: s, v: v };
  137. }
  138. /**
  139. * Converts an HSV color value to RGB.
  140. *
  141. * *Assumes:* h is contained in [0, 1] or [0, 360] and s and v are contained in [0, 1] or [0, 100]
  142. * *Returns:* { r, g, b } in the set [0, 255]
  143. */
  144. export function hsvToRgb(h, s, v) {
  145. h = bound01(h, 360) * 6;
  146. s = bound01(s, 100);
  147. v = bound01(v, 100);
  148. var i = Math.floor(h);
  149. var f = h - i;
  150. var p = v * (1 - s);
  151. var q = v * (1 - f * s);
  152. var t = v * (1 - (1 - f) * s);
  153. var mod = i % 6;
  154. var r = [v, q, p, p, t, v][mod];
  155. var g = [t, v, v, q, p, p][mod];
  156. var b = [p, p, t, v, v, q][mod];
  157. return { r: r * 255, g: g * 255, b: b * 255 };
  158. }
  159. /**
  160. * Converts an RGB color to hex
  161. *
  162. * Assumes r, g, and b are contained in the set [0, 255]
  163. * Returns a 3 or 6 character hex
  164. */
  165. export function rgbToHex(r, g, b, allow3Char) {
  166. var hex = [
  167. pad2(Math.round(r).toString(16)),
  168. pad2(Math.round(g).toString(16)),
  169. pad2(Math.round(b).toString(16)),
  170. ];
  171. // Return a 3 character hex if possible
  172. if (allow3Char &&
  173. hex[0].startsWith(hex[0].charAt(1)) &&
  174. hex[1].startsWith(hex[1].charAt(1)) &&
  175. hex[2].startsWith(hex[2].charAt(1))) {
  176. return hex[0].charAt(0) + hex[1].charAt(0) + hex[2].charAt(0);
  177. }
  178. return hex.join('');
  179. }
  180. /**
  181. * Converts an RGBA color plus alpha transparency to hex
  182. *
  183. * Assumes r, g, b are contained in the set [0, 255] and
  184. * a in [0, 1]. Returns a 4 or 8 character rgba hex
  185. */
  186. // eslint-disable-next-line max-params
  187. export function rgbaToHex(r, g, b, a, allow4Char) {
  188. var hex = [
  189. pad2(Math.round(r).toString(16)),
  190. pad2(Math.round(g).toString(16)),
  191. pad2(Math.round(b).toString(16)),
  192. pad2(convertDecimalToHex(a)),
  193. ];
  194. // Return a 4 character hex if possible
  195. if (allow4Char &&
  196. hex[0].startsWith(hex[0].charAt(1)) &&
  197. hex[1].startsWith(hex[1].charAt(1)) &&
  198. hex[2].startsWith(hex[2].charAt(1)) &&
  199. hex[3].startsWith(hex[3].charAt(1))) {
  200. return hex[0].charAt(0) + hex[1].charAt(0) + hex[2].charAt(0) + hex[3].charAt(0);
  201. }
  202. return hex.join('');
  203. }
  204. /**
  205. * Converts an RGBA color to an ARGB Hex8 string
  206. * Rarely used, but required for "toFilter()"
  207. */
  208. export function rgbaToArgbHex(r, g, b, a) {
  209. var hex = [
  210. pad2(convertDecimalToHex(a)),
  211. pad2(Math.round(r).toString(16)),
  212. pad2(Math.round(g).toString(16)),
  213. pad2(Math.round(b).toString(16)),
  214. ];
  215. return hex.join('');
  216. }
  217. /** Converts a decimal to a hex value */
  218. export function convertDecimalToHex(d) {
  219. return Math.round(parseFloat(d) * 255).toString(16);
  220. }
  221. /** Converts a hex value to a decimal */
  222. export function convertHexToDecimal(h) {
  223. return parseIntFromHex(h) / 255;
  224. }
  225. /** Parse a base-16 hex value into a base-10 integer */
  226. export function parseIntFromHex(val) {
  227. return parseInt(val, 16);
  228. }
  229. export function numberInputToObject(color) {
  230. return {
  231. r: color >> 16,
  232. g: (color & 0xff00) >> 8,
  233. b: color & 0xff,
  234. };
  235. }