|
|
@@ -0,0 +1,338 @@
|
|
|
+#include "Color.h"
|
|
|
+#include <StringAlgorithm.h>
|
|
|
+#include <iomanip>
|
|
|
+#include <sstream>
|
|
|
+
|
|
|
+
|
|
|
+namespace Color {
|
|
|
+
|
|
|
+Color::Color(const Color::HSL& hsl) :
|
|
|
+ m_hsl(hsl)
|
|
|
+{
|
|
|
+}
|
|
|
+
|
|
|
+Color::Color(const Color::RGB& rgb) :
|
|
|
+ m_hsl(rgbToHSL(rgb))
|
|
|
+{
|
|
|
+}
|
|
|
+
|
|
|
+Color Color::FromHSL(int hue, int saturation, int luminance)
|
|
|
+{
|
|
|
+ return Color(HSL{Conversion::Hue(hue), Conversion::Saturation(saturation), Conversion::Luminance(luminance)});
|
|
|
+}
|
|
|
+
|
|
|
+Color Color::FromHSLString(const std::string& hslString)
|
|
|
+{
|
|
|
+ std::vector<std::string> tokens = StringAlgorithm::split(hslString, '-');
|
|
|
+ return Color(HSL{Conversion::Hue(Conversion::Hue(tokens[0])), Conversion::Saturation(Conversion::Saturation(tokens[1])), Conversion::Luminance(Conversion::Luminance(tokens[2]))});
|
|
|
+}
|
|
|
+
|
|
|
+Color Color::FromRGB(int red, int green, int blue)
|
|
|
+{
|
|
|
+ return Color(RGB{Conversion::Red(red), Conversion::Green(green), Conversion::Blue(blue)});
|
|
|
+}
|
|
|
+
|
|
|
+Color Color::FromRGBString(const std::string& rgbString)
|
|
|
+{
|
|
|
+ std::vector<std::string> tokens = StringAlgorithm::split(rgbString, '-');
|
|
|
+ return Color(RGB{Conversion::Red(Conversion::Red(tokens[0])), Conversion::Green(Conversion::Green(tokens[1])), Conversion::Blue(Conversion::Blue(tokens[2]))});
|
|
|
+}
|
|
|
+
|
|
|
+int Color::Hue() const
|
|
|
+{
|
|
|
+ return Conversion::Hue(m_hsl.hue);
|
|
|
+}
|
|
|
+
|
|
|
+void Color::Hue(int hue)
|
|
|
+{
|
|
|
+ Hue(Conversion::Hue(hue));
|
|
|
+}
|
|
|
+
|
|
|
+void Color::Hue(double hue)
|
|
|
+{
|
|
|
+ m_hsl.hue = hue;
|
|
|
+}
|
|
|
+
|
|
|
+int Color::Saturation() const
|
|
|
+{
|
|
|
+ return Conversion::Saturation(m_hsl.saturation);
|
|
|
+}
|
|
|
+
|
|
|
+void Color::Saturation(int saturation)
|
|
|
+{
|
|
|
+ Saturation(Conversion::Saturation(saturation));
|
|
|
+}
|
|
|
+
|
|
|
+void Color::Saturation(double saturation)
|
|
|
+{
|
|
|
+ m_hsl.saturation = saturation;
|
|
|
+}
|
|
|
+
|
|
|
+int Color::Luminance() const
|
|
|
+{
|
|
|
+ return Conversion::Luminance(m_hsl.luminance);
|
|
|
+}
|
|
|
+
|
|
|
+void Color::Luminance(int luminance)
|
|
|
+{
|
|
|
+ Luminance(Conversion::Luminance(luminance));
|
|
|
+}
|
|
|
+
|
|
|
+void Color::Luminance(double luminance)
|
|
|
+{
|
|
|
+ m_hsl.luminance = luminance;
|
|
|
+}
|
|
|
+
|
|
|
+std::string Color::HSLString() const
|
|
|
+{
|
|
|
+ std::stringstream ss;
|
|
|
+ ss << std::setw(3) << std::setfill('0') << Hue();
|
|
|
+ ss << "-";
|
|
|
+ ss << std::setw(3) << std::setfill('0') << Saturation();
|
|
|
+ ss << "-";
|
|
|
+ ss << std::setw(3) << std::setfill('0') << Luminance();
|
|
|
+ return ss.str();
|
|
|
+}
|
|
|
+
|
|
|
+int Color::Red() const
|
|
|
+{
|
|
|
+ RGB rgb = hslToRGB(m_hsl);
|
|
|
+ return Conversion::Red(rgb.red);
|
|
|
+}
|
|
|
+
|
|
|
+void Color::Red(int red)
|
|
|
+{
|
|
|
+ RGB rgb = hslToRGB(m_hsl);
|
|
|
+ rgb.red = Conversion::Red(red);
|
|
|
+ m_hsl = rgbToHSL(rgb);
|
|
|
+}
|
|
|
+
|
|
|
+void Color::Red(double red)
|
|
|
+{
|
|
|
+ RGB rgb = hslToRGB(m_hsl);
|
|
|
+ rgb.red = red;
|
|
|
+ m_hsl = rgbToHSL(rgb);
|
|
|
+}
|
|
|
+
|
|
|
+int Color::Green() const
|
|
|
+{
|
|
|
+ RGB rgb = hslToRGB(m_hsl);
|
|
|
+ return Conversion::Green(rgb.green);
|
|
|
+}
|
|
|
+
|
|
|
+void Color::Green(int green)
|
|
|
+{
|
|
|
+ RGB rgb = hslToRGB(m_hsl);
|
|
|
+ rgb.green = Conversion::Green(green);
|
|
|
+ m_hsl = rgbToHSL(rgb);
|
|
|
+}
|
|
|
+
|
|
|
+void Color::Green(double green)
|
|
|
+{
|
|
|
+ RGB rgb = hslToRGB(m_hsl);
|
|
|
+ rgb.green = green;
|
|
|
+ m_hsl = rgbToHSL(rgb);
|
|
|
+}
|
|
|
+
|
|
|
+int Color::Blue() const
|
|
|
+{
|
|
|
+ RGB rgb = hslToRGB(m_hsl);
|
|
|
+ return Conversion::Blue(rgb.blue);
|
|
|
+}
|
|
|
+
|
|
|
+void Color::Blue(int blue)
|
|
|
+{
|
|
|
+ RGB rgb = hslToRGB(m_hsl);
|
|
|
+ rgb.blue = Conversion::Blue(blue);
|
|
|
+ m_hsl = rgbToHSL(rgb);
|
|
|
+}
|
|
|
+
|
|
|
+void Color::Blue(double blue)
|
|
|
+{
|
|
|
+ RGB rgb = hslToRGB(m_hsl);
|
|
|
+ rgb.blue = blue;
|
|
|
+ m_hsl = rgbToHSL(rgb);
|
|
|
+}
|
|
|
+
|
|
|
+std::string Color::RGBString() const
|
|
|
+{
|
|
|
+ std::stringstream ss;
|
|
|
+ ss << std::setw(3) << std::setfill('0') << Red();
|
|
|
+ ss << "-";
|
|
|
+ ss << std::setw(3) << std::setfill('0') << Green();
|
|
|
+ ss << "-";
|
|
|
+ ss << std::setw(3) << std::setfill('0') << Blue();
|
|
|
+ return ss.str();
|
|
|
+}
|
|
|
+
|
|
|
+double Color::Conversion::Hue(int hue)
|
|
|
+{
|
|
|
+ return static_cast<double>(hue) / m_hueFactor;
|
|
|
+}
|
|
|
+
|
|
|
+int Color::Conversion::Hue(double hue)
|
|
|
+{
|
|
|
+ return static_cast<int>(hue * m_hueFactor);
|
|
|
+}
|
|
|
+
|
|
|
+int Color::Conversion::Hue(const std::string& hue)
|
|
|
+{
|
|
|
+ return std::stoi(hue);
|
|
|
+}
|
|
|
+
|
|
|
+double Color::Conversion::Saturation(int saturation)
|
|
|
+{
|
|
|
+ return static_cast<double>(saturation) / m_saturationFactor;
|
|
|
+}
|
|
|
+
|
|
|
+int Color::Conversion::Saturation(double saturation)
|
|
|
+{
|
|
|
+ return static_cast<int>(saturation * m_saturationFactor);
|
|
|
+}
|
|
|
+
|
|
|
+int Color::Conversion::Saturation(const std::string& saturation)
|
|
|
+{
|
|
|
+ return std::stoi(saturation);
|
|
|
+}
|
|
|
+
|
|
|
+double Color::Conversion::Luminance(int luminance)
|
|
|
+{
|
|
|
+ return static_cast<double>(luminance) / m_luminanceFactor;
|
|
|
+}
|
|
|
+
|
|
|
+int Color::Conversion::Luminance(double luminance)
|
|
|
+{
|
|
|
+ return static_cast<int>(luminance * m_luminanceFactor);
|
|
|
+}
|
|
|
+
|
|
|
+int Color::Conversion::Luminance(const std::string& luminance)
|
|
|
+{
|
|
|
+ return std::stoi(luminance);
|
|
|
+}
|
|
|
+
|
|
|
+double Color::Conversion::Red(int red)
|
|
|
+{
|
|
|
+ return static_cast<double>(red) / m_redFactor;
|
|
|
+}
|
|
|
+
|
|
|
+int Color::Conversion::Red(double red)
|
|
|
+{
|
|
|
+ return static_cast<int>(red * m_redFactor);
|
|
|
+}
|
|
|
+
|
|
|
+int Color::Conversion::Red(const std::string& red)
|
|
|
+{
|
|
|
+ return std::stoi(red);
|
|
|
+}
|
|
|
+
|
|
|
+double Color::Conversion::Green(int green)
|
|
|
+{
|
|
|
+ return static_cast<double>(green) / m_greenFactor;
|
|
|
+}
|
|
|
+
|
|
|
+int Color::Conversion::Green(double green)
|
|
|
+{
|
|
|
+ return static_cast<int>(green * m_greenFactor);
|
|
|
+}
|
|
|
+
|
|
|
+int Color::Conversion::Green(const std::string& green)
|
|
|
+{
|
|
|
+ return std::stoi(green);
|
|
|
+}
|
|
|
+
|
|
|
+double Color::Conversion::Blue(int blue)
|
|
|
+{
|
|
|
+ return static_cast<double>(blue) / m_blueFactor;
|
|
|
+}
|
|
|
+
|
|
|
+int Color::Conversion::Blue(double blue)
|
|
|
+{
|
|
|
+ return static_cast<int>(blue * m_blueFactor);
|
|
|
+}
|
|
|
+
|
|
|
+int Color::Conversion::Blue(const std::string& blue)
|
|
|
+{
|
|
|
+ return std::stoi(blue);
|
|
|
+}
|
|
|
+
|
|
|
+Color::HSL Color::rgbToHSL(const Color::RGB& rgb)
|
|
|
+{
|
|
|
+ double min = rgb.red < rgb.green? rgb.red: rgb.green;
|
|
|
+ min = min < rgb.blue? min: rgb.blue;
|
|
|
+
|
|
|
+ double max = rgb.red > rgb.green? rgb.red: rgb.green;
|
|
|
+ max = max > rgb.blue? max: rgb.blue;
|
|
|
+
|
|
|
+ double luminance = max;
|
|
|
+ double delta = max - min;
|
|
|
+ if (delta < 0.00001)
|
|
|
+ return HSL{0, 0, 0};
|
|
|
+
|
|
|
+ if (max <= 0.0)
|
|
|
+ return HSL{0, 0, 0};
|
|
|
+
|
|
|
+ double saturation = (delta / max);
|
|
|
+ double hue;
|
|
|
+
|
|
|
+ if (rgb.red >= max)
|
|
|
+ {
|
|
|
+ hue = (rgb.green - rgb.blue) / delta;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ if (rgb.green >= max)
|
|
|
+ hue = 2.0 + (rgb.blue - rgb.red) / delta;
|
|
|
+ else
|
|
|
+ hue = 4.0 + (rgb.red - rgb.green) / delta;
|
|
|
+ }
|
|
|
+
|
|
|
+ hue *= 60.0;
|
|
|
+
|
|
|
+ if (hue < 0.0)
|
|
|
+ hue += 360.0;
|
|
|
+
|
|
|
+ hue /= 360;
|
|
|
+
|
|
|
+ return Color::HSL{hue, saturation, luminance};
|
|
|
+}
|
|
|
+
|
|
|
+Color::RGB Color::hslToRGB(const Color::HSL& hsl)
|
|
|
+{
|
|
|
+ double red, green, blue;
|
|
|
+
|
|
|
+ if (hsl.saturation <= 0.0)
|
|
|
+ return Color::RGB{hsl.luminance, hsl.luminance, hsl.luminance};
|
|
|
+
|
|
|
+ double hue = hsl.hue * 360;
|
|
|
+ if (hue >= 360.0)
|
|
|
+ hue = 0.0;
|
|
|
+
|
|
|
+ hue /= 60.0;
|
|
|
+
|
|
|
+ long i = static_cast<long>(hue);
|
|
|
+ double ff = hue - i;
|
|
|
+ double p = hsl.luminance * (1.0 - hsl.saturation);
|
|
|
+ double q = hsl.luminance * (1.0 - (hsl.saturation * ff));
|
|
|
+ double t = hsl.luminance * (1.0 - (hsl.saturation * (1.0 - ff)));
|
|
|
+
|
|
|
+ switch(i)
|
|
|
+ {
|
|
|
+ case 0:
|
|
|
+ return Color::RGB{hsl.luminance, t, p};
|
|
|
+ case 1:
|
|
|
+ return Color::RGB{q, hsl.luminance, p};
|
|
|
+ case 2:
|
|
|
+ return Color::RGB{p, hsl.luminance, t};
|
|
|
+ case 3:
|
|
|
+ return Color::RGB{p, q, hsl.luminance};
|
|
|
+ case 4:
|
|
|
+ return Color::RGB{t, p, hsl.luminance};
|
|
|
+ case 5:
|
|
|
+ default:
|
|
|
+ return Color::RGB{hsl.luminance, p, q};
|
|
|
+ }
|
|
|
+
|
|
|
+ return Color::RGB{0, 0, 0};
|
|
|
+}
|
|
|
+
|
|
|
+} // namespace Color
|