mirror of
https://github.com/zoriya/react-native-svg.git
synced 2026-05-27 12:41:49 +00:00
Optimize color extraction, allow passing color arrays to avoid parsing
This commit is contained in:
+123
-136
@@ -149,124 +149,6 @@ const colorNames = {
|
||||
yellowgreen: [154, 205, 50],
|
||||
};
|
||||
|
||||
function clamp(num, min, max) {
|
||||
return Math.min(Math.max(min, num), max);
|
||||
}
|
||||
|
||||
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*)?\)$/;
|
||||
const per = /^rgba?\(\s*([+-]?[\d.]+)%\s*,\s*([+-]?[\d.]+)%\s*,\s*([+-]?[\d.]+)%\s*(?:,\s*([+-]?[\d.]+)\s*)?\)$/;
|
||||
const keyword = /(\D+)/;
|
||||
|
||||
function rgbFromString(string) {
|
||||
let rgb = [0, 0, 0, 1];
|
||||
let match;
|
||||
let i;
|
||||
let hexAlpha;
|
||||
|
||||
if ((match = string.match(hex))) {
|
||||
hexAlpha = match[2];
|
||||
match = match[1];
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
// https://jsperf.com/slice-vs-substr-vs-substring-methods-long-string/19
|
||||
const i2 = i * 2;
|
||||
rgb[i] = parseInt(match.slice(i2, i2 + 2), 16);
|
||||
}
|
||||
|
||||
if (hexAlpha) {
|
||||
rgb[3] = Math.round((parseInt(hexAlpha, 16) / 255) * 100) / 100;
|
||||
}
|
||||
} else if ((match = string.match(abbr))) {
|
||||
match = match[1];
|
||||
hexAlpha = match[3];
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
rgb[i] = parseInt(match[i] + match[i], 16);
|
||||
}
|
||||
|
||||
if (hexAlpha) {
|
||||
rgb[3] =
|
||||
Math.round((parseInt(hexAlpha + hexAlpha, 16) / 255) * 100) / 100;
|
||||
}
|
||||
} else if ((match = string.match(rgba))) {
|
||||
for (i = 0; i < 3; i++) {
|
||||
rgb[i] = parseInt(match[i + 1], 0);
|
||||
}
|
||||
|
||||
if (match[4]) {
|
||||
rgb[3] = parseFloat(match[4]);
|
||||
}
|
||||
} else if ((match = string.match(per))) {
|
||||
for (i = 0; i < 3; i++) {
|
||||
rgb[i] = Math.round(parseFloat(match[i + 1]) * 2.55);
|
||||
}
|
||||
|
||||
if (match[4]) {
|
||||
rgb[3] = parseFloat(match[4]);
|
||||
}
|
||||
} else if ((match = string.match(keyword))) {
|
||||
if (match[1] === 'transparent') {
|
||||
return [0, 0, 0, 0];
|
||||
}
|
||||
|
||||
rgb = colorNames[match[1]];
|
||||
|
||||
if (!rgb) {
|
||||
return null;
|
||||
}
|
||||
|
||||
rgb[3] = 1;
|
||||
|
||||
return rgb;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
rgb[i] = clamp(rgb[i], 0, 255);
|
||||
}
|
||||
rgb[3] = clamp(rgb[3], 0, 1);
|
||||
|
||||
return rgb;
|
||||
}
|
||||
|
||||
const hslRegEx = /^hsla?\(\s*([+-]?(?:\d*\.)?\d+)(?:deg)?\s*,\s*([+-]?[\d.]+)%\s*,\s*([+-]?[\d.]+)%\s*(?:,\s*([+-]?[\d.]+)\s*)?\)$/;
|
||||
|
||||
function hslFromString(string) {
|
||||
const match = string.match(hslRegEx);
|
||||
|
||||
if (match) {
|
||||
const alpha = parseFloat(match[4]);
|
||||
const h = (parseFloat(match[1]) + 360) % 360;
|
||||
const s = clamp(parseFloat(match[2]), 0, 100);
|
||||
const l = clamp(parseFloat(match[3]), 0, 100);
|
||||
const a = clamp(isNaN(alpha) ? 1 : alpha, 0, 1);
|
||||
|
||||
return [h, s, l, a];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
const hwbRegEx = /^hwb\(\s*([+-]?\d*[.]?\d+)(?:deg)?\s*,\s*([+-]?[\d.]+)%\s*,\s*([+-]?[\d.]+)%\s*(?:,\s*([+-]?[\d.]+)\s*)?\)$/;
|
||||
|
||||
function hwbFromString(string) {
|
||||
const match = string.match(hwbRegEx);
|
||||
|
||||
if (match) {
|
||||
const alpha = parseFloat(match[4]);
|
||||
const h = ((parseFloat(match[1]) % 360) + 360) % 360;
|
||||
const w = clamp(parseFloat(match[2]), 0, 100);
|
||||
const b = clamp(parseFloat(match[3]), 0, 100);
|
||||
const a = clamp(isNaN(alpha) ? 1 : alpha, 0, 1);
|
||||
return [h, w, b, a];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function hslToRgb(hsl) {
|
||||
const h = hsl[0] / 360;
|
||||
const s = hsl[1] / 100;
|
||||
@@ -383,32 +265,137 @@ function hwbToRgb(hwb) {
|
||||
return [r * 255, g * 255, b * 255];
|
||||
}
|
||||
|
||||
export default function extractColor(string) {
|
||||
if (!string || typeof string !== 'string') {
|
||||
function clamp(num, min, max) {
|
||||
return Math.min(Math.max(min, num), max);
|
||||
}
|
||||
|
||||
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*)?\)$/;
|
||||
const per = /^rgba?\(\s*([+-]?[\d.]+)%\s*,\s*([+-]?[\d.]+)%\s*,\s*([+-]?[\d.]+)%\s*(?:,\s*([+-]?[\d.]+)\s*)?\)$/;
|
||||
const keyword = /(\D+)/;
|
||||
|
||||
function rgbFromString(string) {
|
||||
let rgb = [0, 0, 0, 1];
|
||||
let match;
|
||||
let i;
|
||||
let hexAlpha;
|
||||
|
||||
if ((match = string.match(hex))) {
|
||||
hexAlpha = match[2];
|
||||
match = match[1];
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
// https://jsperf.com/slice-vs-substr-vs-substring-methods-long-string/19
|
||||
const i2 = i * 2;
|
||||
rgb[i] = parseInt(match.slice(i2, i2 + 2), 16);
|
||||
}
|
||||
|
||||
if (hexAlpha) {
|
||||
rgb[3] = Math.round((parseInt(hexAlpha, 16) / 255) * 100) / 100;
|
||||
}
|
||||
} else if ((match = string.match(abbr))) {
|
||||
match = match[1];
|
||||
hexAlpha = match[3];
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
rgb[i] = parseInt(match[i] + match[i], 16);
|
||||
}
|
||||
|
||||
if (hexAlpha) {
|
||||
rgb[3] =
|
||||
Math.round((parseInt(hexAlpha + hexAlpha, 16) / 255) * 100) / 100;
|
||||
}
|
||||
} else if ((match = string.match(rgba))) {
|
||||
for (i = 0; i < 3; i++) {
|
||||
rgb[i] = parseInt(match[i + 1], 0);
|
||||
}
|
||||
|
||||
if (match[4]) {
|
||||
rgb[3] = parseFloat(match[4]);
|
||||
}
|
||||
} else if ((match = string.match(per))) {
|
||||
for (i = 0; i < 3; i++) {
|
||||
rgb[i] = Math.round(parseFloat(match[i + 1]) * 2.55);
|
||||
}
|
||||
|
||||
if (match[4]) {
|
||||
rgb[3] = parseFloat(match[4]);
|
||||
}
|
||||
} else if ((match = string.match(keyword))) {
|
||||
if (match[1] === 'transparent') {
|
||||
return [0, 0, 0, 0];
|
||||
}
|
||||
|
||||
rgb = colorNames[match[1]];
|
||||
|
||||
if (!rgb) {
|
||||
return null;
|
||||
}
|
||||
|
||||
rgb[3] = 1;
|
||||
|
||||
return rgb;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
rgb[i] = clamp(rgb[i], 0, 255);
|
||||
}
|
||||
rgb[3] = clamp(rgb[3], 0, 1);
|
||||
|
||||
return rgb;
|
||||
}
|
||||
|
||||
const hslRegEx = /^hsla?\(\s*([+-]?(?:\d*\.)?\d+)(?:deg)?\s*,\s*([+-]?[\d.]+)%\s*,\s*([+-]?[\d.]+)%\s*(?:,\s*([+-]?[\d.]+)\s*)?\)$/;
|
||||
|
||||
function rgbFromHslString(string) {
|
||||
const match = string.match(hslRegEx);
|
||||
|
||||
if (match) {
|
||||
const alpha = parseFloat(match[4]);
|
||||
const h = (parseFloat(match[1]) + 360) % 360;
|
||||
const s = clamp(parseFloat(match[2]), 0, 100);
|
||||
const l = clamp(parseFloat(match[3]), 0, 100);
|
||||
const a = clamp(isNaN(alpha) ? 1 : alpha, 0, 1);
|
||||
|
||||
return hslToRgb([h, s, l, a]);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
const hwbRegEx = /^hwb\(\s*([+-]?\d*[.]?\d+)(?:deg)?\s*,\s*([+-]?[\d.]+)%\s*,\s*([+-]?[\d.]+)%\s*(?:,\s*([+-]?[\d.]+)\s*)?\)$/;
|
||||
|
||||
function rgbFromHwbString(string) {
|
||||
const match = string.match(hwbRegEx);
|
||||
|
||||
if (match) {
|
||||
const alpha = parseFloat(match[4]);
|
||||
const h = ((parseFloat(match[1]) % 360) + 360) % 360;
|
||||
const w = clamp(parseFloat(match[2]), 0, 100);
|
||||
const b = clamp(parseFloat(match[3]), 0, 100);
|
||||
const a = clamp(isNaN(alpha) ? 1 : alpha, 0, 1);
|
||||
return hwbToRgb([h, w, b, a]);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
export default function extractColor(string) {
|
||||
if (typeof string !== 'string') {
|
||||
return string;
|
||||
}
|
||||
|
||||
const prefix = string.substring(0, 3).toLowerCase();
|
||||
|
||||
let value;
|
||||
let converter;
|
||||
switch (prefix) {
|
||||
case 'hsl':
|
||||
value = hslFromString(string);
|
||||
converter = hslToRgb;
|
||||
break;
|
||||
return rgbFromHslString(string);
|
||||
case 'hwb':
|
||||
value = hwbFromString(string);
|
||||
converter = hwbToRgb;
|
||||
break;
|
||||
return rgbFromHwbString(string);
|
||||
default:
|
||||
value = rgbFromString(string);
|
||||
break;
|
||||
return rgbFromString(string);
|
||||
}
|
||||
|
||||
if (!value) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return converter ? converter(value).concat(value[3]) : value;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user