UNPKG

huefree

Version:

HueFree provides a suite of utility functions specifically designed to facilitate color manipulation and transformation, particularly with an emphasis on accommodating color blindness. It includes methods for converting color representations, applying col

162 lines (147 loc) 5.71 kB
/* HueFree - Color transformations for color blind visions and more. Copyright (C) 2023, 2024 Piyush Katyal This file is part of HueFree Library. HueFree is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. HueFree is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with HueFree. If not, see <https://www.gnu.org/licenses/>. */ /** * Converts a CSS color string to an array of RGB values. * Supports rgb(x,x,x) and rgba(x,x,x,x) formats. If rgb(x,x,x,x) is provided then input is percieved as rgba type. * Similarly if rgba(x,x,x) is provided then input is percieved as rgb type. * * @param {string} color - The CSS color string to convert, e.g., 'rgb(255, 23, 45)'. * @returns {number[]|undefined} - An array containing the RGB components [red, green, blue], * or undefined if the input string is invalid, e.g., [255, 23, 45]. */ function stringToRgb(color) { let rgbStart; let rgbRegex = /rgba?\(\s*(-?\d+(?:\.\d+)?)\s*,\s*(-?\d+(?:\.\d+)?)\s*,\s*(-?\d+(?:\.\d+)?)(?:\s*,\s*(-?\d+(?:\.\d+)?))?\s*\)/; let startIndex = color.search(rgbRegex); if (startIndex == -1) return; if (color[startIndex + 3] == 'a') rgbStart = startIndex + 5; else if (color[startIndex + 3] == '(') rgbStart = startIndex + 4; else return; let sRGB = color.substring(rgbStart, color.length - 1); sRGB = sRGB.split(/\s*,\s*/); for (let i = 0; i < sRGB.length; ++i) sRGB[i] = parseFloat(sRGB[i]); return sRGB; } /** * Converts an array of RGB or RGBA values to a CSS color string. * If invalid format is provided then the array is returned without any modifications. * * @param {number[]} color - An array containing the RGB components [red, green, blue] or [red, green, blue, alpha]. * @returns {string} - The CSS color string in the format 'rgb(r, g, b)' or 'rgba(r, g, b, a)'. */ function rgbToString(color) { let rgbString = "rgb("; if (color.length === 4) { rgbString = "rgba("; rgbString += color[0] + ", " + color[1] + ", " + color[2] + ", " + color[3] + ")"; } else if(color.length === 3) rgbString += color[0] + ", " + color[1] + ", " + color[2] + ")"; else return color; return rgbString; } /** * Linearizes an sRGB color array by applying a gamma correction formula. * * @param {string|number[]} color - The CSS color string or an array containing the RGB components [red, green, blue, alpha]. * @returns {number[]|undefined} - An array containing the linearized RGB components [red, green, blue, alpha], * or undefined if the input is invalid. */ function linearize(color) { let sRGB = color; if (typeof (sRGB) === "string") sRGB = stringToRgb(sRGB); if (!sRGB) return; // Linearize the sRGB color values let rgbLinear = sRGB; const boundLimit = 0.04045; const maxRGBValue = 255; const gamma = 2.4; const rgbLength = 3; // Constant length due to rgba format for (let i = 0; i < rgbLength; ++i) { let v = sRGB[i] / maxRGBValue; if (v <= boundLimit) { const fact = 12.92; rgbLinear[i] = v / fact; } else { const fact = 0.055; rgbLinear[i] = Math.pow(((v + fact) / (1 + fact)), gamma); } } return rgbLinear; } /** * De-linearizes an RGB color array from linear to gamma-corrected sRGB values. * * @param {string|number[]} color - The CSS color string or an array containing the linearized RGB components [red, green, blue, alpha]. * @returns {number[]|undefined} - An array containing the de-linearized sRGB components [red, green, blue, alpha], * or undefined if the input is invalid. */ function deLinearize(color) { let rgbLinear = color; if (typeof (rgbLinear) === "string") rgbLinear = stringToRgb(rgbLinear); if (!rgbLinear) return; // De-Linearize the color to sRGB let sRGB = rgbLinear; const gamma = 2.4; const boundLimit = 0.0031308; const maxRGBValue = 255; const rgbLength = 3; // Constant length due to rgba format for (let i = 0; i < rgbLength; ++i) { let v = rgbLinear[i]; if (v <= boundLimit) { const fact = 12.92; sRGB[i] = maxRGBValue * fact * v; } else { const fact = 0.055; sRGB[i] = maxRGBValue * ((1 + fact) * (Math.pow(v, 1 / gamma)) - fact); } } return sRGB; } /** * Applies a color transformation matrix to an RGB color array. * * @param {number[][]} transMat - The transformation matrix, a 3x3 array of numbers. * @param {number[]} rgbMat - An array containing the RGB components [red, green, blue, alpha]. * @returns {number[]} An array containing the transformed RGB components. */ function colorTransform(transMat, rgbMat) { let transColor = [...rgbMat]; for (let i = 0; i < transMat.length; ++i) { let color = transMat[i][0] * rgbMat[0] + transMat[i][1] * rgbMat[1] + transMat[i][2] * rgbMat[2]; transColor[i] = color; } return transColor; } module.exports = { stringToRgb, rgbToString, linearize, deLinearize, colorTransform };