2016-03-10 17:27:25 +01:00
|
|
|
#include <algorithm>
|
|
|
|
#include <cmath>
|
|
|
|
#include <utils/HslTransform.h>
|
|
|
|
|
2016-12-18 00:47:53 +01:00
|
|
|
HslTransform::HslTransform()
|
|
|
|
: _saturationGain(1.0)
|
|
|
|
, _luminanceGain(1.0)
|
|
|
|
, _luminanceMinimum(0.0)
|
2016-03-10 17:27:25 +01:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2016-05-23 00:00:48 +02:00
|
|
|
HslTransform::HslTransform(double saturationGain, double luminanceGain, double luminanceMinimum) :
|
2016-03-10 17:27:25 +01:00
|
|
|
_saturationGain(saturationGain),
|
2016-05-23 00:00:48 +02:00
|
|
|
_luminanceGain(luminanceGain),
|
|
|
|
_luminanceMinimum(luminanceMinimum)
|
2016-03-10 17:27:25 +01:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
HslTransform::~HslTransform()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void HslTransform::setSaturationGain(double saturationGain)
|
|
|
|
{
|
|
|
|
_saturationGain = saturationGain;
|
|
|
|
}
|
|
|
|
|
|
|
|
double HslTransform::getSaturationGain() const
|
|
|
|
{
|
|
|
|
return _saturationGain;
|
|
|
|
}
|
|
|
|
|
|
|
|
void HslTransform::setLuminanceGain(double luminanceGain)
|
|
|
|
{
|
|
|
|
_luminanceGain = luminanceGain;
|
|
|
|
}
|
|
|
|
|
|
|
|
double HslTransform::getLuminanceGain() const
|
|
|
|
{
|
|
|
|
return _luminanceGain;
|
|
|
|
}
|
|
|
|
|
2016-05-23 00:00:48 +02:00
|
|
|
void HslTransform::setLuminanceMinimum(double luminanceMinimum)
|
|
|
|
{
|
|
|
|
_luminanceMinimum = luminanceMinimum;
|
|
|
|
}
|
|
|
|
|
|
|
|
double HslTransform::getLuminanceMinimum() const
|
|
|
|
{
|
|
|
|
return _luminanceMinimum;
|
|
|
|
}
|
|
|
|
|
2016-03-10 17:27:25 +01:00
|
|
|
void HslTransform::transform(uint8_t & red, uint8_t & green, uint8_t & blue) const
|
|
|
|
{
|
2016-05-23 00:00:48 +02:00
|
|
|
if (_saturationGain != 1.0 || _luminanceGain != 1.0 || _luminanceMinimum != 0.0)
|
2016-03-10 17:27:25 +01:00
|
|
|
{
|
|
|
|
uint16_t hue;
|
|
|
|
float saturation, luminance;
|
|
|
|
rgb2hsl(red, green, blue, hue, saturation, luminance);
|
2016-12-18 00:47:53 +01:00
|
|
|
|
2016-03-10 17:27:25 +01:00
|
|
|
float s = saturation * _saturationGain;
|
2016-12-18 00:47:53 +01:00
|
|
|
saturation = std::min(s, 1.0f);
|
2016-03-10 17:27:25 +01:00
|
|
|
|
|
|
|
float l = luminance * _luminanceGain;
|
2016-05-23 00:00:48 +02:00
|
|
|
if (l < _luminanceMinimum)
|
2016-05-24 22:15:39 +02:00
|
|
|
{
|
2016-07-12 23:33:30 +02:00
|
|
|
saturation = 0;
|
2016-05-23 00:00:48 +02:00
|
|
|
l = _luminanceMinimum;
|
2016-05-24 22:15:39 +02:00
|
|
|
}
|
2016-12-18 00:47:53 +01:00
|
|
|
luminance = std::min(l, 1.0f);
|
|
|
|
|
2016-03-10 17:27:25 +01:00
|
|
|
hsl2rgb(hue, saturation, luminance, red, green, blue);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void HslTransform::rgb2hsl(uint8_t red, uint8_t green, uint8_t blue, uint16_t & hue, float & saturation, float & luminance)
|
|
|
|
{
|
2016-12-18 00:47:53 +01:00
|
|
|
float r = (float)red / 255.0f;
|
|
|
|
float g = (float)green / 255.0f;
|
|
|
|
float b = (float)blue / 255.0f;
|
2016-03-10 17:27:25 +01:00
|
|
|
|
2016-12-18 00:47:53 +01:00
|
|
|
float rgbMin = std::min(r,std::min(g,b));
|
|
|
|
float rgbMax = std::max(r,std::max(g,b));
|
2016-03-10 17:27:25 +01:00
|
|
|
float diff = rgbMax - rgbMin;
|
|
|
|
|
|
|
|
//luminance
|
|
|
|
luminance = (rgbMin + rgbMax) / 2.0f;
|
|
|
|
|
2016-12-18 00:47:53 +01:00
|
|
|
if (diff == 0.0f)
|
|
|
|
{
|
2016-03-10 17:27:25 +01:00
|
|
|
saturation = 0.0f;
|
2016-12-18 00:47:53 +01:00
|
|
|
hue = 0;
|
2016-03-10 17:27:25 +01:00
|
|
|
return;
|
2016-12-18 00:47:53 +01:00
|
|
|
}
|
2016-03-10 17:27:25 +01:00
|
|
|
|
|
|
|
//saturation
|
2016-12-18 00:47:53 +01:00
|
|
|
saturation = (luminance < 0.5f)
|
|
|
|
? (diff / (rgbMin + rgbMax))
|
|
|
|
: (diff / (2.0f - rgbMin - rgbMax));
|
2016-03-10 17:27:25 +01:00
|
|
|
|
|
|
|
if (rgbMax == r)
|
|
|
|
{
|
|
|
|
// start from 360 to be sure that we won't assign a negative number to the unsigned hue value
|
|
|
|
hue = 360 + 60 * (g - b) / (rgbMax - rgbMin);
|
|
|
|
|
|
|
|
if (hue > 359)
|
|
|
|
hue -= 360;
|
|
|
|
}
|
|
|
|
else if (rgbMax == g)
|
|
|
|
{
|
|
|
|
hue = 120 + 60 * (b - r) / (rgbMax - rgbMin);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
hue = 240 + 60 * (r - g) / (rgbMax - rgbMin);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void HslTransform::hsl2rgb(uint16_t hue, float saturation, float luminance, uint8_t & red, uint8_t & green, uint8_t & blue)
|
|
|
|
{
|
2016-12-18 00:47:53 +01:00
|
|
|
if (saturation == 0.0f)
|
|
|
|
{
|
|
|
|
red = (uint8_t)(luminance * 255.0f);
|
2016-03-10 17:27:25 +01:00
|
|
|
green = (uint8_t)(luminance * 255.0f);
|
2016-12-18 00:47:53 +01:00
|
|
|
blue = (uint8_t)(luminance * 255.0f);
|
2016-03-10 17:27:25 +01:00
|
|
|
return;
|
|
|
|
}
|
2016-12-18 00:47:53 +01:00
|
|
|
|
|
|
|
float q = (luminance < 0.5f)
|
|
|
|
? luminance * (1.0f + saturation)
|
|
|
|
: (luminance + saturation) - (luminance * saturation);
|
|
|
|
|
2016-03-10 17:27:25 +01:00
|
|
|
float p = (2.0f * luminance) - q;
|
|
|
|
float h = hue / 360.0f;
|
2016-12-18 00:47:53 +01:00
|
|
|
|
2016-03-10 17:27:25 +01:00
|
|
|
float t[3];
|
|
|
|
|
|
|
|
t[0] = h + (1.0f / 3.0f);
|
|
|
|
t[1] = h;
|
|
|
|
t[2] = h - (1.0f / 3.0f);
|
|
|
|
|
2016-12-18 00:47:53 +01:00
|
|
|
for (int i = 0; i < 3; i++)
|
|
|
|
{
|
2016-03-10 17:27:25 +01:00
|
|
|
if (t[i] < 0.0f)
|
|
|
|
t[i] += 1.0f;
|
|
|
|
if (t[i] > 1.0f)
|
|
|
|
t[i] -= 1.0f;
|
|
|
|
}
|
|
|
|
|
|
|
|
float out[3];
|
|
|
|
|
2016-12-18 00:47:53 +01:00
|
|
|
for (int i = 0; i < 3; i++)
|
|
|
|
{
|
2016-03-10 17:27:25 +01:00
|
|
|
if (t[i] * 6.0f < 1.0f)
|
|
|
|
out[i] = p + (q - p) * 6.0f * t[i];
|
|
|
|
else if (t[i] * 2.0f < 1.0f)
|
|
|
|
out[i] = q;
|
|
|
|
else if (t[i] * 3.0f < 2.0f)
|
|
|
|
out[i] = p + (q - p) * ((2.0f / 3.0f) - t[i]) * 6.0f;
|
|
|
|
else out[i] = p;
|
|
|
|
}
|
|
|
|
|
|
|
|
//convert back to 0...255 range
|
2016-12-18 00:47:53 +01:00
|
|
|
red = (uint8_t)(out[0] * 255.0f);
|
2016-03-10 17:27:25 +01:00
|
|
|
green = (uint8_t)(out[1] * 255.0f);
|
2016-12-18 00:47:53 +01:00
|
|
|
blue = (uint8_t)(out[2] * 255.0f);
|
2016-03-10 17:27:25 +01:00
|
|
|
|
|
|
|
}
|