Imported Upstream version 1.72.0
[platform/upstream/boost.git] / boost / gil / extension / toolbox / color_spaces / hsl.hpp
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 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>
50    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>
142    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