UNPKG

@bigfishtv/cockpit

Version:

219 lines (187 loc) 9.75 kB
'use strict'; exports.__esModule = true; var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; /** * Color Utilities * @module Utilities/colorUtils */ exports.curvesHashTable = curvesHashTable; exports.getContrastCurve = getContrastCurve; exports.getVibranceMatrix = getVibranceMatrix; exports.getTemperatureRGB = getTemperatureRGB; exports.componentToHex = componentToHex; exports.rgbToHex = rgbToHex; exports.hexToRgb = hexToRgb; exports.blackOrWhite = blackOrWhite; exports.interpolateGradient = interpolateGradient; var _regression = require('regression'); var _regression2 = _interopRequireDefault(_regression); var _ColorNames = require('../constants/ColorNames'); var _ColorNames2 = _interopRequireDefault(_ColorNames); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } /** * Returns a hash table corresponding to a polynomial regression equation generated from array of points * @param {Array} points - An array of points, where a point is [x, y] * @param {Number} [min=0] - Number where hash table starts, typically 0 * @param {Number} [max=255] - Number where hash table ends, typically 255 * @return {Array} - Returns array of length max-min containing values reflecting the polynomial regression values of the points provided */ function curvesHashTable() { var points = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [[0, 0], [255, 255]]; var min = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; var max = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 255; var result = (0, _regression2.default)('polynomial', points, points.length - 1); var coefficients = result.equation; var curvesHashTable = {}; for (var x = min; x <= max; x++) { curvesHashTable[x] = 0; for (var c = points.length - 1; c >= 0; c--) { curvesHashTable[x] += coefficients[c] * Math.pow(x, c); } curvesHashTable[x] = Math.min(Math.max(curvesHashTable[x], min), max - 1); } return curvesHashTable; } /** * Returns an array of curve points based on contrast value * @param {Number} contrast - Contrast value, can be negative * @return {Array} - Returns array of curve points corresponding the contrast value */ function getContrastCurve() { var contrast = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0; if (typeof contrast == 'string') contrast = parseInt(contrast); var amt = 75; return [[0, 0], [amt, 0 + amt - contrast], [180, 255 - amt + contrast], [255, 255]]; } /** * Returns a ColorMatrix grid based on vibrance value * @param {Number} vibrance - Vibrance value, can be negative * @return {Array} - Returns array of ColorMatrix adjustments, a 5x4 grid */ function getVibranceMatrix(vibrance) { var amt = vibrance / 200; return [1 + amt, -amt / 1.5, -amt / 1.5, 0, 0, -amt / 1.5, 1 + amt, -amt / 1.5, 0, 0, -amt / 1.5, -amt / 1.5, 1 + amt, 0, 0, 0, 0, 0, 1, 0]; } /** * Returns an RGB object based on Kelvin temperature value * @param {Number} temperature - Temperature value, corresponds to actual Kelvin value e.g. 1000 - 40,000. Neutural is 6600 * @return {Object} - Returns object containing keys: red, green, blue */ // http://www.tannerhelland.com/4435/convert-temperature-rgb-algorithm-code/ function getTemperatureRGB() { var temp = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 6600; temp /= 100; var red = temp <= 66 ? 255 : 329.698727446 * Math.pow(temp - 60, -0.1332047592); red = red < 0 ? 0 : red > 255 ? 255 : red; var green = temp <= 66 ? 99.4708025861 * Math.log(temp) - 161.1195681661 : 288.1221695283 * Math.pow(temp - 60, -0.0755148492); green = green < 0 ? 0 : green > 255 ? 255 : green; var blue = temp >= 66 ? 255 : temp <= 19 ? 0 : 138.5177312231 * Math.log(temp - 10) - 305.0447927307; blue = blue < 0 ? 0 : blue > 255 ? 255 : blue; return { red: red, green: green, blue: blue }; } /** * Converts a r/g/b value to hex * @param {Integer} c * @return {String} */ function componentToHex(c) { var hex = c.toString(16); return hex.length == 1 ? '0' + hex : hex; } /** * Converts rgb object with keys red, green, blue to hex string * @param {Object} rgb * @param {Integer} rgb.red * @param {Integer} rgb.green * @param {Integer} rgb.blue * @return {String} */ function rgbToHex(rgb) { return '#' + componentToHex(rgb.red) + componentToHex(rgb.green) + componentToHex(rgb.blue); } /** * Converts hex string (longform or shortform) to object with red, green blue keys * @param {String} hex * @return {Object} returns object with keys red, green, blue */ function hexToRgb(_hex) { // Expand shorthand form (e.g. "03F") to full form (e.g. "0033FF") var shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i; var hex = _hex.replace(shorthandRegex, function (m, r, g, b) { return r + r + g + g + b + b; }); var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); return result ? { red: parseInt(result[1], 16), green: parseInt(result[2], 16), blue: parseInt(result[3], 16) } : null; } /** * Returns either black or white based on provided color. Used for deciding font color on a colored background. * @param {String} backgroundColor - hex color or color name * @return {String} */ function blackOrWhite(backgroundColor) { var threshold = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0.179; if (typeof backgroundColor != 'string') return null; if (backgroundColor.indexOf('#') < 0) { backgroundColor = backgroundColor.toLowerCase(); if (_ColorNames.colorNameKeys.indexOf(backgroundColor.toLowerCase()) >= 0) backgroundColor = _ColorNames2.default[backgroundColor];else return null; } var bgRGB = hexToRgb(backgroundColor); var C = [bgRGB.red / 255, bgRGB.green / 255, bgRGB.blue / 255].map(function (val) { return val < 0.03928 ? val / 12.92 : Math.pow((val + 0.055) / 1.055, 2.4); }); var L = 0.2126 * C[0] + 0.7152 * C[1] + 0.0722 * C[2]; return L > threshold ? '#000000' : '#FFFFFF'; } /** * Converts color markers from a gradient map interface into an array of color values * The color values should be viewed in groups of 4 for rgba values. * So the length of the returned array will be 4x the provided range (255 by default), e.g. * [ r0, g0, b0, a0, r1, g1, b1, a1, ... , r255, g255, b255, a255 ] * @param {Object[]} markers - array of objects containing * @param {Number} markers[].position - float from 0 to 1 * @param {Number} markers[].alpha - float from 0 to 1 * @param {Number[]} markers[].color - array of 3 values for rgb, 0 to 255 * @param {Number} range - detail of returned gradient values (essentially width) * @return {Array} Returns an array of numbers to be interpretted in groups of 4 as rgba values */ function interpolateGradient(_markers) { var range = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 256; // map the position and alpha to 255 then sort by position in case they're submitted out of order var markers = _markers.map(function (marker) { return _extends({}, marker, { position: Math.floor(marker.position * (range - 1)), alpha: Math.floor(marker.alpha * 255) }); }).sort(function (a, b) { return a.position < b.position ? -1 : a.position > b.position ? 1 : 0; }); // if first marker is above 0 then create an identical one at 0 if (markers[0].position > 0) markers = [_extends({}, markers[0], { position: 0 })].concat(markers); // and vice versa if (markers[markers.length - 1].position < range - 1) markers = [].concat(markers, [_extends({}, markers[markers.length - 1], { position: range - 1 })]); var rgbaData = []; var currentMarker = markers[0]; var nextMarker = markers[1]; for (var i = 0; i < range; i++) { // bump current marker if reached next marker position if (i >= nextMarker.position) currentMarker = nextMarker; // don't proceed if reached last marker (position 255) var currentMarkerIndex = markers.indexOf(currentMarker); if (currentMarkerIndex === markers.length - 1) { rgbaData.push.apply(rgbaData, currentMarker.color.concat([currentMarker.alpha])); break; } nextMarker = markers[currentMarkerIndex + 1]; // get percentage along current and next marker var amt = (i - currentMarker.position) / (nextMarker.position - currentMarker.position); // add pixel data to array rgbaData.push(Math.round(currentMarker.color[0] * (1 - amt) + nextMarker.color[0] * amt)); rgbaData.push(Math.round(currentMarker.color[1] * (1 - amt) + nextMarker.color[1] * amt)); rgbaData.push(Math.round(currentMarker.color[2] * (1 - amt) + nextMarker.color[2] * amt)); rgbaData.push(Math.round(currentMarker.alpha * (1 - amt) + nextMarker.alpha * amt)); } return rgbaData; }