URL: https://svn.lrde.epita.fr/svn/oln/trunk/milena ChangeLog: 2009-09-21 Fabien Freling <fabien.freling@lrde.epita.fr> Add new algorithm for conversion HSL to RGB. * mln/fun/v2v/hsl_to_rgb.hh: Add new algorithm for conversion. * mln/value/rgb.hh: Enable convertion to HSL. --- fun/v2v/hsl_to_rgb.hh | 87 +++++++++++++++++++++++++++++++++++--------------- value/rgb.hh | 50 ++++++++++++++-------------- 2 files changed, 86 insertions(+), 51 deletions(-) Index: trunk/milena/mln/value/rgb.hh =================================================================== --- trunk/milena/mln/value/rgb.hh (revision 4513) +++ trunk/milena/mln/value/rgb.hh (revision 4514) @@ -29,7 +29,7 @@ # include <mln/value/ops.hh> -// # include <mln/fun/v2v/hsl_to_rgb.hh> +# include <mln/fun/v2v/hsl_to_rgb.hh> # include <mln/value/concept/vectorial.hh> # include <mln/value/int_u.hh> # include <mln/algebra/vec.hh> @@ -42,24 +42,24 @@ -// namespace fun -// { + namespace fun + { -// namespace v2v -// { + namespace v2v + { -// template <typename T_rgb> -// struct f_hsl_to_rgb_; + template <typename T_rgb> + struct f_hsl_to_rgb_; -// typedef f_hsl_to_rgb_< value::rgb<8> > f_hsl_to_rgb_3x8_t; + typedef f_hsl_to_rgb_< value::rgb<8> > f_hsl_to_rgb_3x8_t; // typedef f_hsl_to_rgb_< value::rgb<16> > f_hsl_to_rgb_3x16_t; -// extern f_hsl_to_rgb_3x8_t f_hsl_to_rgb_3x8; + extern f_hsl_to_rgb_3x8_t f_hsl_to_rgb_3x8; // extern f_hsl_to_rgb_3x16_t f_hsl_to_rgb_3x16; -// } + } -// } + } namespace literal @@ -90,11 +90,11 @@ } -// // Forward declaration. -// namespace value -// { -// template <typename H, typename S, typename L> class hsl_; -// } + // Forward declaration. + namespace value + { + template <typename H, typename S, typename L> class hsl_; + } namespace convert @@ -115,9 +115,9 @@ template <unsigned m> void from_to_(const value::int_u<m>& from, value::rgb<m>& to); -// // hsl -> rgb8. -// template <typename H, typename S, typename L> -// void from_to_(const value::hsl_<H,S,L>&, value::rgb<8>& to); + // hsl -> rgb8. + template <typename H, typename S, typename L> + void from_to_(const value::hsl_<H,S,L>&, value::rgb<8>& to); // // hsl -> rgb16. // template <typename H, typename S, typename L> @@ -791,12 +791,12 @@ to = value::rgb<m>(from, from, from); } -// template <typename H, typename S, typename L> -// void -// from_to_(const value::hsl_<H,S,L>& from, value::rgb<8>& to) -// { -// to = fun::v2v::f_hsl_to_rgb_3x8(from); -// } + template <typename H, typename S, typename L> + void + from_to_(const value::hsl_<H,S,L>& from, value::rgb<8>& to) + { + to = fun::v2v::f_hsl_to_rgb_3x8(from); + } // template <typename H, typename S, typename L> // void Index: trunk/milena/mln/fun/v2v/hsl_to_rgb.hh =================================================================== --- trunk/milena/mln/fun/v2v/hsl_to_rgb.hh (revision 4513) +++ trunk/milena/mln/fun/v2v/hsl_to_rgb.hh (revision 4514) @@ -92,40 +92,75 @@ /// \} + // This method implement the conversion from HSL to RGB + // explained by Wikipedia. + // url: http://en.wikipedia.org/wiki/HSL_and_HSV template <typename T_rgb> template <typename T_hsl> inline T_rgb f_hsl_to_rgb_<T_rgb>::operator()(const T_hsl& hsl) const { - typedef typename T_rgb::red_t red_t; - typedef typename T_rgb::green_t green_t; - typedef typename T_rgb::blue_t blue_t; - - static math::round<red_t> to_r; - static math::round<green_t> to_g; - static math::round<blue_t> to_b; - - static const float - sqrt3_3 = std::sqrt(3.0f) / 3.0f, - inv_sqrt6 = 1 / std::sqrt(6.0f), - inv_sqrt2 = 1 / std::sqrt(2.0f); - - float - h = hsl.hue() / 180.0 * 3.1415, - alpha = hsl.sat() * std::cos(h), - beta = hsl.sat() * std::sin(h); - - - red_t r = to_r(sqrt3_3 * hsl.lum() + 2 * inv_sqrt6 * beta); - green_t g = - to_g(sqrt3_3 * hsl.lum() + inv_sqrt2 * alpha - inv_sqrt6 * beta); - blue_t b = - to_b(sqrt3_3 * hsl.lum() - inv_sqrt2 * alpha - inv_sqrt6 * beta); + const float q = (hsl.lum() < 0.5) ? hsl.lum() * (1.0 + hsl.sat()) : + hsl.lum() + hsl.sat() - (hsl.lum() * hsl.sat()); + const float p = 2.0 * hsl.lum() - q; + const float hk = hsl.hue() / 360.0; // hk = normalized hue + float tr = hk + (1.0 / 3.0); + float tg = hk; + float tb = hk - (1.0 / 3.0); + + if (tr < 0.0) + tr += 1.0; + if (tr > 1.0) + tr -= 1.0; + + if (tg < 0.0) + tg += 1.0; + if (tg > 1.0) + tg -= 1.0; + + if (tb < 0.0) + tb += 1.0; + if (tb > 1.0) + tb -= 1.0; + + // Red. + float red; + if (tr < (1.0 / 6.0)) + red = p + ((q - p) * 6 * tr); + else if (tr < (1.0 / 2.0)) + red = q; + else if (tr < (2.0 / 3.0)) + red = p + ((q - p) * 6 * ((2.0 / 3.0) - tr)); + else + red = p; + + // Green. + float green; + if (tg < (1.0 / 6.0)) + green = p + ((q - p) * 6 * tg); + else if (tg < (1.0 / 2.0)) + green = q; + else if (tg < (2.0 / 3.0)) + green = p + ((q - p) * 6 * ((2.0 / 3.0) - tg)); + else + green = p; + + // Blue. + float blue; + if (tb < (1.0 / 6.0)) + blue = p + ((q - p) * 6 * tb); + else if (tb < (1.0 / 2.0)) + blue = q; + else if (tb < (2.0 / 3.0)) + blue = p + ((q - p) * 6 * ((2.0 / 3.0) - tb)); + else + blue = p; - T_rgb rgb(r, g, b); + // Each component is in [0, 1]. + T_rgb rgb_result(red * 255, green * 255, blue * 255); - return rgb; + return rgb_result; } # endif // !MLN_INCLUDE_ONLY