diff --git a/lib/extract/extractColor.js b/lib/extract/extractColor.js index c5166697..570dcf13 100644 --- a/lib/extract/extractColor.js +++ b/lib/extract/extractColor.js @@ -1,35 +1,3 @@ -const colorString = {}; - -colorString.get = function(string) { - const prefix = string.substring(0, 3).toLowerCase(); - let val; - let model; - switch (prefix) { - case 'hsl': - val = colorString.get.hsl(string); - model = 'hsl'; - break; - case 'hwb': - val = colorString.get.hwb(string); - model = 'hwb'; - break; - default: - val = colorString.get.rgb(string); - model = 'rgb'; - break; - } - - if (!val) { - return null; - } - - return { model: model, value: val }; -}; - -function clamp(num, min, max) { - return Math.min(Math.max(min, num), max); -} - const colorNames = { aliceblue: [240, 248, 255], antiquewhite: [250, 235, 215], @@ -181,11 +149,11 @@ const colorNames = { yellowgreen: [154, 205, 50], }; -colorString.get.rgb = function(string) { - if (!string) { - return null; - } +function clamp(num, min, max) { + return Math.min(Math.max(min, num), max); +} +function rgbFromString(string) { const abbr = /^#([a-f0-9]{3,4})$/i; const hex = /^#([a-f0-9]{6})([a-f0-9]{2})?$/i; const rgba = /^rgba?\(\s*([+-]?\d+)\s*,\s*([+-]?\d+)\s*,\s*([+-]?\d+)\s*(?:,\s*([+-]?[\d.]+)\s*)?\)$/; @@ -262,13 +230,9 @@ colorString.get.rgb = function(string) { rgb[3] = clamp(rgb[3], 0, 1); return rgb; -}; - -colorString.get.hsl = function(string) { - if (!string) { - return null; - } +} +function hslFromString(string) { const hsl = /^hsla?\(\s*([+-]?(?:\d*\.)?\d+)(?:deg)?\s*,\s*([+-]?[\d.]+)%\s*,\s*([+-]?[\d.]+)%\s*(?:,\s*([+-]?[\d.]+)\s*)?\)$/; const match = string.match(hsl); @@ -283,13 +247,9 @@ colorString.get.hsl = function(string) { } return null; -}; - -colorString.get.hwb = function(string) { - if (!string) { - return null; - } +} +function hwbFromString(string) { const hwb = /^hwb\(\s*([+-]?\d*[.]?\d+)(?:deg)?\s*,\s*([+-]?[\d.]+)%\s*,\s*([+-]?[\d.]+)%\s*(?:,\s*([+-]?[\d.]+)\s*)?\)$/; const match = string.match(hwb); @@ -303,128 +263,161 @@ colorString.get.hwb = function(string) { } return null; -}; +} -const convert = {}; +const convert = { + hsl: function hslToRgb(hsl) { + const h = hsl[0] / 360; + const s = hsl[1] / 100; + const l = hsl[2] / 100; + let t1; + let t2; + let t3; + let rgb; + let val; -convert.hsl.rgb = function(hsl) { - const h = hsl[0] / 360; - const s = hsl[1] / 100; - const l = hsl[2] / 100; - let t1; - let t2; - let t3; - let rgb; - let val; - - if (s === 0) { - val = l * 255; - return [val, val, val]; - } - - if (l < 0.5) { - t2 = l * (1 + s); - } else { - t2 = l + s - l * s; - } - - t1 = 2 * l - t2; - - rgb = [0, 0, 0]; - for (let i = 0; i < 3; i++) { - t3 = h + (1 / 3) * -(i - 1); - if (t3 < 0) { - t3++; - } - if (t3 > 1) { - t3--; + if (s === 0) { + val = l * 255; + return [val, val, val]; } - if (6 * t3 < 1) { - val = t1 + (t2 - t1) * 6 * t3; - } else if (2 * t3 < 1) { - val = t2; - } else if (3 * t3 < 2) { - val = t1 + (t2 - t1) * (2 / 3 - t3) * 6; + if (l < 0.5) { + t2 = l * (1 + s); } else { - val = t1; + t2 = l + s - l * s; } - rgb[i] = val * 255; - } + t1 = 2 * l - t2; - return rgb; + rgb = [0, 0, 0]; + for (let i = 0; i < 3; i++) { + t3 = h + (1 / 3) * -(i - 1); + if (t3 < 0) { + t3++; + } + if (t3 > 1) { + t3--; + } + + if (6 * t3 < 1) { + val = t1 + (t2 - t1) * 6 * t3; + } else if (2 * t3 < 1) { + val = t2; + } else if (3 * t3 < 2) { + val = t1 + (t2 - t1) * (2 / 3 - t3) * 6; + } else { + val = t1; + } + + rgb[i] = val * 255; + } + + return rgb; + }, + hwb: function hwbToRgb(hwb) { + const h = hwb[0] / 360; + let wh = hwb[1] / 100; + let bl = hwb[2] / 100; + const ratio = wh + bl; + let i; + let v; + let f; + let n; + + // wh + bl cant be > 1 + if (ratio > 1) { + wh /= ratio; + bl /= ratio; + } + + i = Math.floor(6 * h); + v = 1 - bl; + f = 6 * h - i; + + if ((i & 0x01) !== 0) { + f = 1 - f; + } + + n = wh + f * (v - wh); // linear interpolation + + let r; + let g; + let b; + switch (i) { + default: + case 6: + case 0: + r = v; + g = n; + b = wh; + break; + case 1: + r = n; + g = v; + b = wh; + break; + case 2: + r = wh; + g = v; + b = n; + break; + case 3: + r = wh; + g = n; + b = v; + break; + case 4: + r = n; + g = wh; + b = v; + break; + case 5: + r = v; + g = wh; + b = n; + break; + } + + return [r * 255, g * 255, b * 255]; + }, }; -// http://dev.w3.org/csswg/css-color/#hwb-to-rgb -convert.hwb.rgb = function(hwb) { - const h = hwb[0] / 360; - let wh = hwb[1] / 100; - let bl = hwb[2] / 100; - const ratio = wh + bl; - let i; - let v; - let f; - let n; - - // wh + bl cant be > 1 - if (ratio > 1) { - wh /= ratio; - bl /= ratio; +function colorFromString(string) { + if (!string || typeof string !== 'string') { + return null; } - i = Math.floor(6 * h); - v = 1 - bl; - f = 6 * h - i; - - if ((i & 0x01) !== 0) { - f = 1 - f; - } - - n = wh + f * (v - wh); // linear interpolation - - let r; - let g; - let b; - switch (i) { + const prefix = string.substring(0, 3).toLowerCase(); + let value; + let model; + switch (prefix) { + case 'hsl': + value = hslFromString(string); + model = 'hsl'; + break; + case 'hwb': + value = hwbFromString(string); + model = 'hwb'; + break; default: - case 6: - case 0: - r = v; - g = n; - b = wh; - break; - case 1: - r = n; - g = v; - b = wh; - break; - case 2: - r = wh; - g = v; - b = n; - break; - case 3: - r = wh; - g = n; - b = v; - break; - case 4: - r = n; - g = wh; - b = v; - break; - case 5: - r = v; - g = wh; - b = n; + value = rgbFromString(string); + model = 'rgb'; break; } - return [r * 255, g * 255, b * 255]; -}; + if (!value) { + return null; + } + + return [model, value]; +} export default function extractColor(color) { - const { value, model } = colorString.get(color); - return model === 'rgb' ? value : convert[model].rgb(value).concat(value[3]); + const result = colorFromString(color); + if (!result) { + return null; + } + const model = result[0]; + const value = result[1]; + return model === 'rgb' ? value : convert[model](value).concat(value[3]); } diff --git a/lib/extract/extractGradient.js b/lib/extract/extractGradient.js index 3d37782c..135ce8b9 100644 --- a/lib/extract/extractGradient.js +++ b/lib/extract/extractGradient.js @@ -48,6 +48,10 @@ export default function extractGradient(props, parent) { const offsetNumber = percentToFloat(offset); if (stopColor && !isNaN(offsetNumber)) { const color = extractColor(stopColor); + if (!color) { + console.warn(`"${stopColor}" is not a valid color`); + continue; + } const r = color[0] / 255; const g = color[1] / 255; const b = color[2] / 255;