ParseColourCode.mjs 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. /**
  2. * @author n1474335 [n1474335@gmail.com]
  3. * @copyright Crown Copyright 2016
  4. * @license Apache-2.0
  5. */
  6. import Operation from "../Operation";
  7. /**
  8. * Parse colour code operation
  9. */
  10. class ParseColourCode extends Operation {
  11. /**
  12. * ParseColourCode constructor
  13. */
  14. constructor() {
  15. super();
  16. this.name = "Parse colour code";
  17. this.module = "Default";
  18. this.description = "Converts a colour code in a standard format to other standard formats and displays the colour itself.<br><br><strong>Example inputs</strong><ul><li><code>#d9edf7</code></li><li><code>rgba(217,237,247,1)</code></li><li><code>hsla(200,65%,91%,1)</code></li><li><code>cmyk(0.12, 0.04, 0.00, 0.03)</code></li></ul>";
  19. this.inputType = "string";
  20. this.outputType = "html";
  21. this.args = [];
  22. }
  23. /**
  24. * @param {string} input
  25. * @param {Object[]} args
  26. * @returns {html}
  27. */
  28. run(input, args) {
  29. let m = null,
  30. r = 0, g = 0, b = 0, a = 1;
  31. // Read in the input
  32. if ((m = input.match(/#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})/i))) {
  33. // Hex - #d9edf7
  34. r = parseInt(m[1], 16);
  35. g = parseInt(m[2], 16);
  36. b = parseInt(m[3], 16);
  37. } else if ((m = input.match(/rgba?\((\d{1,3}(?:\.\d+)?),\s?(\d{1,3}(?:\.\d+)?),\s?(\d{1,3}(?:\.\d+)?)(?:,\s?(\d(?:\.\d+)?))?\)/i))) {
  38. // RGB or RGBA - rgb(217,237,247) or rgba(217,237,247,1)
  39. r = parseFloat(m[1]);
  40. g = parseFloat(m[2]);
  41. b = parseFloat(m[3]);
  42. a = m[4] ? parseFloat(m[4]) : 1;
  43. } else if ((m = input.match(/hsla?\((\d{1,3}(?:\.\d+)?),\s?(\d{1,3}(?:\.\d+)?)%,\s?(\d{1,3}(?:\.\d+)?)%(?:,\s?(\d(?:\.\d+)?))?\)/i))) {
  44. // HSL or HSLA - hsl(200, 65%, 91%) or hsla(200, 65%, 91%, 1)
  45. const h_ = parseFloat(m[1]) / 360,
  46. s_ = parseFloat(m[2]) / 100,
  47. l_ = parseFloat(m[3]) / 100,
  48. rgb_ = ParseColourCode._hslToRgb(h_, s_, l_);
  49. r = rgb_[0];
  50. g = rgb_[1];
  51. b = rgb_[2];
  52. a = m[4] ? parseFloat(m[4]) : 1;
  53. } else if ((m = input.match(/cmyk\((\d(?:\.\d+)?),\s?(\d(?:\.\d+)?),\s?(\d(?:\.\d+)?),\s?(\d(?:\.\d+)?)\)/i))) {
  54. // CMYK - cmyk(0.12, 0.04, 0.00, 0.03)
  55. const c_ = parseFloat(m[1]),
  56. m_ = parseFloat(m[2]),
  57. y_ = parseFloat(m[3]),
  58. k_ = parseFloat(m[4]);
  59. r = Math.round(255 * (1 - c_) * (1 - k_));
  60. g = Math.round(255 * (1 - m_) * (1 - k_));
  61. b = Math.round(255 * (1 - y_) * (1 - k_));
  62. }
  63. const hsl_ = ParseColourCode._rgbToHsl(r, g, b),
  64. h = Math.round(hsl_[0] * 360),
  65. s = Math.round(hsl_[1] * 100),
  66. l = Math.round(hsl_[2] * 100);
  67. let k = 1 - Math.max(r/255, g/255, b/255),
  68. c = (1 - r/255 - k) / (1 - k),
  69. y = (1 - b/255 - k) / (1 - k);
  70. m = (1 - g/255 - k) / (1 - k);
  71. c = isNaN(c) ? "0" : c.toFixed(2);
  72. m = isNaN(m) ? "0" : m.toFixed(2);
  73. y = isNaN(y) ? "0" : y.toFixed(2);
  74. k = k.toFixed(2);
  75. const hex = "#" +
  76. Math.round(r).toString(16).padStart(2, "0") +
  77. Math.round(g).toString(16).padStart(2, "0") +
  78. Math.round(b).toString(16).padStart(2, "0"),
  79. rgb = "rgb(" + r + ", " + g + ", " + b + ")",
  80. rgba = "rgba(" + r + ", " + g + ", " + b + ", " + a + ")",
  81. hsl = "hsl(" + h + ", " + s + "%, " + l + "%)",
  82. hsla = "hsla(" + h + ", " + s + "%, " + l + "%, " + a + ")",
  83. cmyk = "cmyk(" + c + ", " + m + ", " + y + ", " + k + ")";
  84. // Generate output
  85. return `<div id="colorpicker" style="display: inline-block"></div>
  86. Hex: ${hex}
  87. RGB: ${rgb}
  88. RGBA: ${rgba}
  89. HSL: ${hsl}
  90. HSLA: ${hsla}
  91. CMYK: ${cmyk}
  92. <script>
  93. $('#colorpicker').colorpicker({
  94. format: 'rgba',
  95. color: '${rgba}',
  96. container: true,
  97. inline: true,
  98. }).on('changeColor', function(e) {
  99. var color = e.color.toRGB();
  100. document.getElementById('input-text').value = 'rgba(' +
  101. color.r + ', ' + color.g + ', ' + color.b + ', ' + color.a + ')';
  102. window.app.autoBake();
  103. });
  104. </script>`;
  105. }
  106. /**
  107. * Converts an HSL color value to RGB. Conversion formula
  108. * adapted from http://en.wikipedia.org/wiki/HSL_colorSpace.
  109. * Assumes h, s, and l are contained in the set [0, 1] and
  110. * returns r, g, and b in the set [0, 255].
  111. *
  112. * @author Mohsen (http://stackoverflow.com/a/9493060)
  113. *
  114. * @param {number} h - The hue
  115. * @param {number} s - The saturation
  116. * @param {number} l - The lightness
  117. * @return {Array} The RGB representation
  118. */
  119. static _hslToRgb(h, s, l) {
  120. let r, g, b;
  121. if (s === 0){
  122. r = g = b = l; // achromatic
  123. } else {
  124. const hue2rgb = function hue2rgb(p, q, t) {
  125. if (t < 0) t += 1;
  126. if (t > 1) t -= 1;
  127. if (t < 1/6) return p + (q - p) * 6 * t;
  128. if (t < 1/2) return q;
  129. if (t < 2/3) return p + (q - p) * (2/3 - t) * 6;
  130. return p;
  131. };
  132. const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
  133. const p = 2 * l - q;
  134. r = hue2rgb(p, q, h + 1/3);
  135. g = hue2rgb(p, q, h);
  136. b = hue2rgb(p, q, h - 1/3);
  137. }
  138. return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)];
  139. }
  140. /**
  141. * Converts an RGB color value to HSL. Conversion formula
  142. * adapted from http://en.wikipedia.org/wiki/HSL_colorSpace.
  143. * Assumes r, g, and b are contained in the set [0, 255] and
  144. * returns h, s, and l in the set [0, 1].
  145. *
  146. * @author Mohsen (http://stackoverflow.com/a/9493060)
  147. *
  148. * @param {number} r - The red color value
  149. * @param {number} g - The green color value
  150. * @param {number} b - The blue color value
  151. * @return {Array} The HSL representation
  152. */
  153. static _rgbToHsl(r, g, b) {
  154. r /= 255; g /= 255; b /= 255;
  155. const max = Math.max(r, g, b),
  156. min = Math.min(r, g, b),
  157. l = (max + min) / 2;
  158. let h, s;
  159. if (max === min) {
  160. h = s = 0; // achromatic
  161. } else {
  162. const d = max - min;
  163. s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
  164. switch (max) {
  165. case r: h = (g - b) / d + (g < b ? 6 : 0); break;
  166. case g: h = (b - r) / d + 2; break;
  167. case b: h = (r - g) / d + 4; break;
  168. }
  169. h /= 6;
  170. }
  171. return [h, s, l];
  172. }
  173. }
  174. export default ParseColourCode;