1 // 2 // Copyright 2012 Christian Henning 3 // 4 // Distributed under the Boost Software License, Version 1.0 5 // See accompanying file LICENSE_1_0.txt or copy at 6 // http://www.boost.org/LICENSE_1_0.txt 7 // 8 #ifndef BOOST_GIL_EXTENSION_TOOLBOX_COLOR_SPACES_HSL_HPP 9 #define BOOST_GIL_EXTENSION_TOOLBOX_COLOR_SPACES_HSL_HPP 10 11 #include <boost/gil/color_convert.hpp> 12 #include <boost/gil/typedefs.hpp> 13 #include <boost/gil/detail/mp11.hpp> 14 15 namespace boost{ namespace gil { 16 17 /// \addtogroup ColorNameModel 18 /// \{ 19 namespace hsl_color_space 20 { 21 /// \brief Hue 22 struct hue_t {}; 23 /// \brief Saturation 24 struct saturation_t {}; 25 /// \brief Lightness 26 struct lightness_t {}; 27 } 28 /// \} 29 30 /// \ingroup ColorSpaceModel 31 using hsl_t = mp11::mp_list 32 < 33 hsl_color_space::hue_t, 34 hsl_color_space::saturation_t, 35 hsl_color_space::lightness_t 36 >; 37 38 /// \ingroup LayoutModel 39 using hsl_layout_t = layout<hsl_t>; 40 41 42 BOOST_GIL_DEFINE_ALL_TYPEDEFS(32f, float32_t, hsl) 43 44 /// \ingroup ColorConvert 45 /// \brief RGB to HSL 46 template <> 47 struct default_color_converter_impl< rgb_t, hsl_t > 48 { 49 template <typename P1, typename P2> operator ()boost::gil::default_color_converter_impl50 void operator()( const P1& src, P2& dst ) const 51 { 52 using namespace hsl_color_space; 53 54 // only float32_t for hsl is supported 55 float32_t temp_red = channel_convert<float32_t>( get_color( src, red_t() )); 56 float32_t temp_green = channel_convert<float32_t>( get_color( src, green_t() )); 57 float32_t temp_blue = channel_convert<float32_t>( get_color( src, blue_t() )); 58 59 float32_t hue, saturation, lightness; 60 61 float32_t min_color = (std::min)( temp_red, (std::min)( temp_green, temp_blue )); 62 float32_t max_color = (std::max)( temp_red, (std::max)( temp_green, temp_blue )); 63 64 if( std::abs( min_color - max_color ) < 0.001 ) 65 { 66 // rgb color is gray 67 68 hue = 0.f; 69 saturation = 0.f; 70 71 // doesn't matter which rgb channel we use. 72 lightness = temp_red; 73 } 74 else 75 { 76 77 float32_t diff = max_color - min_color; 78 79 // lightness calculation 80 81 lightness = ( min_color + max_color ) / 2.f; 82 83 // saturation calculation 84 85 if( lightness < 0.5f ) 86 { 87 saturation = diff 88 / ( min_color + max_color ); 89 } 90 else 91 { 92 saturation = ( max_color - min_color ) 93 / ( 2.f - diff ); 94 95 } 96 97 // hue calculation 98 if( std::abs( max_color - temp_red ) < 0.0001f ) 99 { 100 // max_color is red 101 hue = ( temp_green - temp_blue ) 102 / diff; 103 104 } 105 else if( std::abs( max_color - temp_green) < 0.0001f ) 106 { 107 // max_color is green 108 // 2.0 + (b - r) / (maxColor - minColor); 109 hue = 2.f 110 + ( temp_blue - temp_red ) 111 / diff; 112 113 } 114 else 115 { 116 // max_color is blue 117 hue = 4.f 118 + ( temp_red - temp_blue ) 119 / diff; 120 } 121 122 hue /= 6.f; 123 124 if( hue < 0.f ) 125 { 126 hue += 1.f; 127 } 128 } 129 130 get_color( dst,hue_t() ) = hue; 131 get_color( dst,saturation_t() ) = saturation; 132 get_color( dst,lightness_t() ) = lightness; 133 } 134 }; 135 136 /// \ingroup ColorConvert 137 /// \brief HSL to RGB 138 template <> 139 struct default_color_converter_impl<hsl_t,rgb_t> 140 { 141 template <typename P1, typename P2> operator ()boost::gil::default_color_converter_impl142 void operator()( const P1& src, P2& dst) const 143 { 144 using namespace hsl_color_space; 145 146 float32_t red, green, blue; 147 148 if( std::abs( get_color( src, saturation_t() )) < 0.0001 ) 149 { 150 // If saturation is 0, the color is a shade of gray 151 red = get_color( src, lightness_t() ); 152 green = get_color( src, lightness_t() ); 153 blue = get_color( src, lightness_t() ); 154 } 155 else 156 { 157 float temp1, temp2; 158 float tempr, tempg, tempb; 159 160 //Set the temporary values 161 if( get_color( src, lightness_t() ) < 0.5 ) 162 { 163 temp2 = get_color( src, lightness_t() ) 164 * ( 1.f + get_color( src, saturation_t() ) ); 165 } 166 else 167 { 168 temp2 = ( get_color( src, lightness_t() ) + get_color( src, saturation_t() )) 169 - ( get_color( src, lightness_t() ) * get_color( src, saturation_t() )); 170 } 171 172 temp1 = 2.f 173 * get_color( src, lightness_t() ) 174 - temp2; 175 176 tempr = get_color( src, hue_t() ) + 1.f / 3.f; 177 178 if( tempr > 1.f ) 179 { 180 tempr--; 181 } 182 183 tempg = get_color( src, hue_t() ); 184 tempb = get_color( src, hue_t() ) - 1.f / 3.f; 185 186 if( tempb < 0.f ) 187 { 188 tempb++; 189 } 190 191 //Red 192 if( tempr < 1.f / 6.f ) 193 { 194 red = temp1 + ( temp2 - temp1 ) * 6.f * tempr; 195 } 196 else if( tempr < 0.5f ) 197 { 198 red = temp2; 199 } 200 else if( tempr < 2.f / 3.f ) 201 { 202 red = temp1 + (temp2 - temp1) 203 * (( 2.f / 3.f ) - tempr) * 6.f; 204 } 205 else 206 { 207 red = temp1; 208 } 209 210 //Green 211 if( tempg < 1.f / 6.f ) 212 { 213 green = temp1 + ( temp2 - temp1 ) * 6.f * tempg; 214 } 215 else if( tempg < 0.5f ) 216 { 217 green = temp2; 218 } 219 else if( tempg < 2.f / 3.f ) 220 { 221 green = temp1 + ( temp2 - temp1 ) 222 * (( 2.f / 3.f ) - tempg) * 6.f; 223 } 224 else 225 { 226 green = temp1; 227 } 228 229 //Blue 230 if( tempb < 1.f / 6.f ) 231 { 232 blue = temp1 + (temp2 - temp1) * 6.f * tempb; 233 } 234 else if( tempb < 0.5f ) 235 { 236 blue = temp2; 237 } 238 else if( tempb < 2.f / 3.f ) 239 { 240 blue = temp1 + (temp2 - temp1) 241 * (( 2.f / 3.f ) - tempb) * 6.f; 242 } 243 else 244 { 245 blue = temp1; 246 } 247 } 248 249 get_color(dst,red_t()) = 250 channel_convert<typename color_element_type< P2, red_t >::type>( red ); 251 get_color(dst,green_t())= 252 channel_convert<typename color_element_type< P2, green_t >::type>( green ); 253 get_color(dst,blue_t()) = 254 channel_convert<typename color_element_type< P2, blue_t >::type>( blue ); 255 } 256 }; 257 258 } // namespace gil 259 } // namespace boost 260 261 #endif 262