@bigfishtv/cockpit
Version:
219 lines (187 loc) • 9.75 kB
JavaScript
;
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;
}