blob: b68b6ca926e009eabf1031f70790f5ea101a0085 [file] [log] [blame]
/*
*
* Copyright (c) 2021 Project CHIP Authors
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "ColorFormat.h"
#include <math.h>
// define a clamp macro to substitute the std::clamp macro which is available from C++17 onwards
#define clamp(a, min, max) ((a) < (min) ? (min) : ((a) > (max) ? (max) : (a)))
RgbColor_t HsvToRgb(HsvColor_t hsv)
{
RgbColor_t rgb;
uint8_t region, p, q, t;
uint32_t h, s, v, remainder;
if (hsv.s == 0)
{
rgb.r = rgb.g = rgb.b = hsv.v;
}
else
{
h = hsv.h;
s = hsv.s;
v = hsv.v;
region = h / 43;
remainder = (h - (region * 43)) * 6;
p = (v * (255 - s)) >> 8;
q = (v * (255 - ((s * remainder) >> 8))) >> 8;
t = (v * (255 - ((s * (255 - remainder)) >> 8))) >> 8;
switch (region)
{
case 0:
rgb.r = v, rgb.g = t, rgb.b = p;
break;
case 1:
rgb.r = q, rgb.g = v, rgb.b = p;
break;
case 2:
rgb.r = p, rgb.g = v, rgb.b = t;
break;
case 3:
rgb.r = p, rgb.g = q, rgb.b = v;
break;
case 4:
rgb.r = t, rgb.g = p, rgb.b = v;
break;
case 5:
default:
rgb.r = v, rgb.g = p, rgb.b = q;
break;
}
}
return rgb;
}
RgbColor_t XYToRgb(uint8_t Level, uint16_t currentX, uint16_t currentY)
{
// convert xyY color space to RGB
// https://www.easyrgb.com/en/math.php
// https://en.wikipedia.org/wiki/SRGB
// refer https://en.wikipedia.org/wiki/CIE_1931_color_space#CIE_xy_chromaticity_diagram_and_the_CIE_xyY_color_space
// The currentX/currentY attribute contains the current value of the normalized chromaticity value of x/y.
// The value of x/y shall be related to the currentX/currentY attribute by the relationship
// x = currentX/65536
// y = currentY/65536
// z = 1-x-y
RgbColor_t rgb;
float x, y, z;
float X, Y, Z;
float r, g, b;
x = ((float) currentX) / 65535.0f;
y = ((float) currentY) / 65535.0f;
z = 1.0f - x - y;
// Calculate XYZ values
// Y - given brightness in 0 - 1 range
Y = ((float) Level) / 254.0f;
X = (Y / y) * x;
Z = (Y / y) * z;
// X, Y and Z input refer to a D65/2° standard illuminant.
// sR, sG and sB (standard RGB) output range = 0 ÷ 255
// convert XYZ to RGB - CIE XYZ to sRGB
X = X / 100.0f;
Y = Y / 100.0f;
Z = Z / 100.0f;
r = (X * 3.2406f) - (Y * 1.5372f) - (Z * 0.4986f);
g = -(X * 0.9689f) + (Y * 1.8758f) + (Z * 0.0415f);
b = (X * 0.0557f) - (Y * 0.2040f) + (Z * 1.0570f);
// apply gamma 2.2 correction
r = (r <= 0.0031308f ? 12.92f * r : (1.055f) * pow(r, (1.0f / 2.4f)) - 0.055f);
g = (g <= 0.0031308f ? 12.92f * g : (1.055f) * pow(g, (1.0f / 2.4f)) - 0.055f);
b = (b <= 0.0031308f ? 12.92f * b : (1.055f) * pow(b, (1.0f / 2.4f)) - 0.055f);
// Round off
r = clamp(r, 0, 1);
g = clamp(g, 0, 1);
b = clamp(b, 0, 1);
// these rgb values are in the range of 0 to 1, convert to limit of HW specific LED
rgb.r = (uint8_t)(r * 255);
rgb.g = (uint8_t)(g * 255);
rgb.b = (uint8_t)(b * 255);
return rgb;
}
RgbColor_t CTToRgb(CtColor_t ct)
{
RgbColor_t rgb;
float r, g, b;
// Algorithm credits to Tanner Helland: https://tannerhelland.com/2012/09/18/convert-temperature-rgb-algorithm-code.html
// Convert Mireds to centiKelvins. k = 1,000,000/mired
float ctCentiKelvin = 10000 / ct.ctMireds;
// Red
if (ctCentiKelvin <= 66)
{
r = 255;
}
else
{
r = 329.698727446f * pow(ctCentiKelvin - 60, -0.1332047592f);
}
// Green
if (ctCentiKelvin <= 66)
{
g = 99.4708025861f * log(ctCentiKelvin) - 161.1195681661f;
}
else
{
g = 288.1221695283f * pow(ctCentiKelvin - 60, -0.0755148492f);
}
// Blue
if (ctCentiKelvin >= 66)
{
b = 255;
}
else
{
if (ctCentiKelvin <= 19)
{
b = 0;
}
else
{
b = 138.5177312231 * log(ctCentiKelvin - 10) - 305.0447927307;
}
}
rgb.r = (uint8_t) clamp(r, 0, 255);
rgb.g = (uint8_t) clamp(g, 0, 255);
rgb.b = (uint8_t) clamp(b, 0, 255);
return rgb;
}