/* * Copyright (c) 2010 Tim Baumann * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // NOTE: // Extracted from ColorTriangle and // Converted to ES6 by MightyPork (2017) /******************* * Color conversion * *******************/ const M = Math const PI = M.PI exports.hue_to_rgb = function (v1, v2, h) { if (h < 0) h += 1 if (h > 1) h -= 1 if ((6 * h) < 1) return v1 + (v2 - v1) * 6 * h if ((2 * h) < 1) return v2 if ((3 * h) < 2) return v1 + (v2 - v1) * ((2 / 3) - h) * 6 return v1 } exports.hsl_to_rgb = function (h, s, l) { h /= 2 * PI let r, g, b if (s === 0) { r = g = b = l } else { let var_1, var_2 if (l < 0.5) var_2 = l * (1 + s) else var_2 = (l + s) - (s * l) var_1 = 2 * l - var_2 r = exports.hue_to_rgb(var_1, var_2, h + (1 / 3)) g = exports.hue_to_rgb(var_1, var_2, h) b = exports.hue_to_rgb(var_1, var_2, h - (1 / 3)) } return [r, g, b] } exports.rgb_to_hsl = function (r, g, b) { const min = M.min(r, g, b) const max = M.max(r, g, b) const d = max - min // delta let h, s, l l = (max + min) / 2 if (d === 0) { // gray h = s = 0 // HSL results from 0 to 1 } else { // chroma if (l < 0.5) s = d / (max + min) else s = d / (2 - max - min) const d_r = (((max - r) / 6) + (d / 2)) / d const d_g = (((max - g) / 6) + (d / 2)) / d const d_b = (((max - b) / 6) + (d / 2)) / d // deltas if (r === max) h = d_b - d_g else if (g === max) h = (1 / 3) + d_r - d_b else if (b === max) h = (2 / 3) + d_g - d_r if (h < 0) h += 1 else if (h > 1) h -= 1 } h *= 2 * PI return [h, s, l] } exports.hex_to_rgb = function (hex) { const groups = hex.match(/^#([A-Fa-f0-9]+)$/) if (groups && groups[1].length % 3 === 0) { hex = groups[1] const bytes = hex.length / 3 const max = Math.pow(16, bytes) - 1 const r = parseInt(hex.slice(0 * bytes, 1 * bytes), 16) / max const g = parseInt(hex.slice(1 * bytes, 2 * bytes), 16) / max const b = parseInt(hex.slice(2 * bytes, 3 * bytes), 16) / max return [r, g, b] } return [0, 0, 0] } function pad (n) { if (n.length === 1) n = '0' + n return n } exports.rgb255_to_hex = function (r, g, b) { r = r.toString(16) g = g.toString(16) b = b.toString(16) return `#${pad(r)}${pad(g)}${pad(b)}` } exports.rgb_to_hex = function (r, g, b) { r = Math.round(r * 255).toString(16) g = Math.round(g * 255).toString(16) b = Math.round(b * 255).toString(16) return `#${pad(r)}${pad(g)}${pad(b)}` }