UNPKG

@ha4us/hue.adapter

Version:

Adapter for the hue system to ha4us

192 lines (191 loc) 6.5 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var tinycolor = require("tinycolor2"); var GAMUT_A = [[0.703, 0.296], [0.214, 0.709], [0.139, 0.081]]; var GAMUT_B = [[0.674, 0.322], [0.408, 0.517], [0.168, 0.041]]; var GAMUT_C = [[0.692, 0.308], [0.17, 0.7], [0.153, 0.048]]; var GAMUT_DEFAULT = [[1.0, 0.0], [0.0, 1.0], [0.0, 0.0]]; exports.MODEL_GAMUTS = { LLC001: GAMUT_A, LLC005: GAMUT_A, LLC006: GAMUT_A, LLC007: GAMUT_A, LLC010: GAMUT_A, LLC011: GAMUT_A, LLC012: GAMUT_A, LLC014: GAMUT_A, LLC013: GAMUT_A, LST001: GAMUT_A, LCT001: GAMUT_B, LCT002: GAMUT_B, LCT003: GAMUT_B, LCT004: GAMUT_B, LLM001: GAMUT_B, LCT005: GAMUT_B, LCT006: GAMUT_B, LCT007: GAMUT_B, LCT010: GAMUT_C, LCT011: GAMUT_C, LCT012: GAMUT_C, LCT014: GAMUT_C, LCT015: GAMUT_C, LCT016: GAMUT_C, LLC020: GAMUT_C, LST002: GAMUT_C, }; var XY = /** @class */ (function () { function XY(xy) { this.x = xy[0]; this.y = xy[1]; } return XY; }()); var HueLimit = /** @class */ (function () { function HueLimit(gamut) { this.red = new XY(gamut[0]); this.green = new XY(gamut[1]); this.blue = new XY(gamut[2]); } return HueLimit; }()); function _crossProduct(p1, p2) { return p1.x * p2.y - p1.y * p2.x; } function _isInColorGamut(p, lampLimits) { var v1 = new XY([ lampLimits.green.x - lampLimits.red.x, lampLimits.green.y - lampLimits.red.y, ]); var v2 = new XY([ lampLimits.blue.x - lampLimits.red.x, lampLimits.blue.y - lampLimits.red.y, ]); var q = new XY([p.x - lampLimits.red.x, p.y - lampLimits.red.y]); var s = _crossProduct(q, v2) / _crossProduct(v1, v2); var t = _crossProduct(v1, q) / _crossProduct(v1, v2); return s >= 0.0 && t >= 0.0 && s + t <= 1.0; } /** * Find the closest point on a line. This point will be reproducible by the limits. * * @param start The point where the line starts. * @param stop The point where the line ends. * @param point The point which is close to the line. * @return A point that is on the line specified, and closest to the XY provided. */ function _getClosestPoint(start, stop, point) { var AP = new XY([point.x - start.x, point.y - start.y]); var AB = new XY([stop.x - start.x, stop.y - start.y]); var ab2 = AB.x * AB.x + AB.y * AB.y; var apAb = AP.x * AB.x + AP.y * AB.y; var t = apAb / ab2; if (t < 0.0) { t = 0.0; } else if (t > 1.0) { t = 1.0; } return new XY([start.x + AB.x * t, start.y + AB.y * t]); } function _getDistanceBetweenPoints(pOne, pTwo) { var dx = pOne.x - pTwo.x; var dy = pOne.y - pTwo.y; return Math.sqrt(dx * dx + dy * dy); } /** * When a color is outside the limits, find the closest point on each line in the CIE 1931 'triangle'. * @param point The point that is outside the limits * @param limits The limits of the bulb (red, green and blue XY points). * @return [description] */ function _resolveXYPointForLamp(point, limits) { var pAB = _getClosestPoint(limits.red, limits.green, point); var pAC = _getClosestPoint(limits.blue, limits.red, point); var pBC = _getClosestPoint(limits.green, limits.blue, point); var dAB = _getDistanceBetweenPoints(point, pAB); var dAC = _getDistanceBetweenPoints(point, pAC); var dBC = _getDistanceBetweenPoints(point, pBC); var lowest = dAB; var closestPoint = pAB; if (dAC < lowest) { lowest = dAC; closestPoint = pAC; } if (dBC < lowest) { closestPoint = pBC; } return closestPoint; } function gammaCorrection(value) { return value > 0.04045 ? Math.pow((value + 0.055) / (1.0 + 0.055), 2.4) : value / 12.92; } var XY2RGBConverter = /** @class */ (function () { function XY2RGBConverter(colorgamut) { this.limit = new HueLimit(colorgamut); } XY2RGBConverter.prototype.toRGB = function (xy, brightness) { var point = new XY(xy); // 4th - 2: check for model gamut if (!_isInColorGamut(point, this.limit)) { point = _resolveXYPointForLamp(xy, this.limit); } var z = 1 - point.x - point.y; var Y = brightness; var X = (Y / point.y) * point.x; var Z = (Y / point.y) * z; // Convert to RGB using Wide RGB D65 conversion var rgb = [ X * 1.656492 - Y * 0.354851 - Z * 0.255038, -X * 0.707196 + Y * 1.655397 + Z * 0.036152, X * 0.051713 - Y * 0.121364 + Z * 1.01153, ]; // Apply reverse gamma correction. rgb = rgb.map(function (_x) { return _x <= 0.0031308 ? 12.92 * _x : (1.0 + 0.055) * Math.pow(_x, 1.0 / 2.4) - 0.055; }); // Bring all negative components to zero. rgb = rgb.map(function (_x) { return Math.max(0, _x); }); // If one component is greater than 1, weight components by that value. var max = Math.max(rgb[0], rgb[1], rgb[2]); if (max > 1) { rgb = rgb.map(function (_x) { return _x / max; }); } rgb = rgb.map(function (_x) { return Math.floor(_x * 255); }); var r = rgb[0], g = rgb[1], b = rgb[2]; return tinycolor({ r: r, g: g, b: b }).toHexString(); }; XY2RGBConverter.prototype.toXY = function (rgbColor) { var _a = tinycolor(rgbColor).toRgb(), r = _a.r, g = _a.g, b = _a.b; // 1st + 2nd : Normalize a scale 1 + apply Gamma Correction r = gammaCorrection(r / 255); g = gammaCorrection(g / 255); b = gammaCorrection(b / 255); // 3rd: Wide RGB D65 var X = r * 0.4360747 + g * 0.3850649 + b * 0.0930804; var Y = r * 0.2225045 + g * 0.7168786 + b * 0.0406169; var Z = r * 0.0139322 + g * 0.0971045 + b * 0.7141733; // 4th: calculate xy var cx = X / (X + Y + Z); var cy = Y / (X + Y + Z); cx = isNaN(cx) ? 0.0 : cx; cy = isNaN(cy) ? 0.0 : cy; var xyPoint = new XY([cx, cy]); // 4th - 2: check for model gamut if (!_isInColorGamut(xyPoint, this.limit)) { xyPoint = _resolveXYPointForLamp(xyPoint, this.limit); } return [xyPoint.x, xyPoint.y]; }; return XY2RGBConverter; }()); exports.XY2RGBConverter = XY2RGBConverter;