2012-06-17 19:16:48 +00:00
|
|
|
// Copyright 2007 Christian Henning.
|
|
|
|
// Distributed under the Boost Software License, Version 1.0. (See
|
|
|
|
// accompanying file LICENSE_1_0.txt or copy at
|
|
|
|
// http://www.boost.org/LICENSE_1_0.txt)
|
|
|
|
|
|
|
|
/*************************************************************************************************/
|
|
|
|
|
|
|
|
#ifndef GIL_HSL_H
|
|
|
|
#define GIL_HSL_H
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
/// \file
|
|
|
|
/// \brief Support for HSL color space
|
|
|
|
/// \author Christian Henning \n
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
2015-05-24 20:48:04 +00:00
|
|
|
#pragma GCC diagnostic push
|
2015-11-12 17:51:41 +00:00
|
|
|
#include <mapnik/warning_ignore.hpp>
|
2012-06-17 19:16:48 +00:00
|
|
|
#include <boost/gil/gil_all.hpp>
|
2015-05-24 20:48:04 +00:00
|
|
|
#pragma GCC diagnostic pop
|
2012-06-17 19:16:48 +00:00
|
|
|
|
|
|
|
namespace boost { namespace gil {
|
|
|
|
|
|
|
|
/// \addtogroup ColorNameModel
|
|
|
|
/// \{
|
|
|
|
namespace hsl_color_space
|
|
|
|
{
|
|
|
|
/// \brief Hue
|
|
|
|
struct hue_t {};
|
|
|
|
/// \brief Saturation
|
|
|
|
struct saturation_t {};
|
|
|
|
/// \brief Lightness
|
|
|
|
struct lightness_t {};
|
|
|
|
}
|
|
|
|
/// \}
|
|
|
|
|
|
|
|
/// \ingroup ColorSpaceModel
|
|
|
|
typedef mpl::vector3< hsl_color_space::hue_t
|
|
|
|
, hsl_color_space::saturation_t
|
|
|
|
, hsl_color_space::lightness_t
|
|
|
|
> hsl_t;
|
|
|
|
|
|
|
|
/// \ingroup LayoutModel
|
|
|
|
typedef layout<hsl_t> hsl_layout_t;
|
|
|
|
|
|
|
|
|
|
|
|
GIL_DEFINE_ALL_TYPEDEFS( 32f, hsl );
|
|
|
|
|
|
|
|
/// \ingroup ColorConvert
|
|
|
|
/// \brief RGB to HSL
|
|
|
|
template <>
|
|
|
|
struct default_color_converter_impl< rgb_t, hsl_t >
|
|
|
|
{
|
|
|
|
template <typename P1, typename P2>
|
|
|
|
void operator()( const P1& src, P2& dst ) const
|
|
|
|
{
|
|
|
|
using namespace hsl_color_space;
|
|
|
|
|
|
|
|
// only bits32f for hsl is supported
|
|
|
|
bits32f temp_red = channel_convert<bits32f>( get_color( src, red_t() ));
|
|
|
|
bits32f temp_green = channel_convert<bits32f>( get_color( src, green_t() ));
|
|
|
|
bits32f temp_blue = channel_convert<bits32f>( get_color( src, blue_t() ));
|
|
|
|
|
|
|
|
bits32f hue, saturation, lightness;
|
2012-11-15 01:04:44 +00:00
|
|
|
bits32f min_color, max_color;
|
2012-06-17 19:16:48 +00:00
|
|
|
|
2012-11-15 01:04:44 +00:00
|
|
|
if( temp_red < temp_green )
|
|
|
|
{
|
|
|
|
min_color = std::min( temp_blue, temp_red );
|
|
|
|
max_color = std::max( temp_blue, temp_green );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
min_color = std::min( temp_blue, temp_green );
|
|
|
|
max_color = std::max( temp_blue, temp_red );
|
|
|
|
}
|
2012-06-17 19:16:48 +00:00
|
|
|
|
|
|
|
if ( max_color - min_color < 0.001 )
|
|
|
|
{
|
|
|
|
// rgb color is gray
|
|
|
|
|
|
|
|
hue = 0.f;
|
|
|
|
saturation = 0.f;
|
|
|
|
|
|
|
|
// doesn't matter which rgb channel we use.
|
|
|
|
lightness = temp_red;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
|
|
|
|
bits32f diff = max_color - min_color;
|
|
|
|
|
|
|
|
// lightness calculation
|
|
|
|
|
|
|
|
lightness = ( min_color + max_color ) / 2.f;
|
|
|
|
|
|
|
|
// saturation calculation
|
|
|
|
|
|
|
|
if( lightness < 0.5f )
|
|
|
|
{
|
|
|
|
saturation = diff
|
|
|
|
/ ( min_color + max_color );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
saturation = ( max_color - min_color )
|
|
|
|
/ ( 2.f - diff );
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// hue calculation
|
|
|
|
if( std::abs( max_color - temp_red ) < 0.0001f )
|
|
|
|
{
|
|
|
|
// max_color is red
|
|
|
|
hue = ( temp_green - temp_blue )
|
|
|
|
/ diff;
|
|
|
|
|
|
|
|
}
|
|
|
|
else if( std::abs( max_color - temp_green) < 0.0001f )
|
|
|
|
{
|
|
|
|
// max_color is green
|
|
|
|
// 2.0 + (b - r) / (maxColor - minColor)
|
|
|
|
hue = 2.f
|
|
|
|
+ ( temp_blue - temp_red )
|
|
|
|
/ diff;
|
|
|
|
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// max_color is blue
|
|
|
|
// 4.0 + (r - g) / (maxColor - minColor)
|
|
|
|
hue = 4.f
|
|
|
|
+ ( temp_red - temp_green )
|
|
|
|
/ diff;
|
|
|
|
}
|
|
|
|
|
|
|
|
hue /= 6.f;
|
|
|
|
|
|
|
|
if( hue < 0.f )
|
|
|
|
{
|
|
|
|
hue += 1.f;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
get_color( dst,hue_t() ) = hue;
|
|
|
|
get_color( dst,saturation_t() ) = saturation;
|
|
|
|
get_color( dst,lightness_t() ) = lightness;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/// \ingroup ColorConvert
|
|
|
|
/// \brief HSL to RGB
|
|
|
|
template <>
|
|
|
|
struct default_color_converter_impl<hsl_t,rgb_t>
|
|
|
|
{
|
|
|
|
template <typename P1, typename P2>
|
|
|
|
void operator()( const P1& src, P2& dst) const
|
|
|
|
{
|
|
|
|
using namespace hsl_color_space;
|
|
|
|
|
|
|
|
bits32f red, green, blue;
|
|
|
|
|
|
|
|
if( std::abs( get_color( src, saturation_t() )) < 0.0001 )
|
|
|
|
{
|
|
|
|
// If saturation is 0, the color is a shade of gray
|
|
|
|
red = get_color( src, lightness_t() );
|
|
|
|
green = get_color( src, lightness_t() );
|
|
|
|
blue = get_color( src, lightness_t() );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
float temp1, temp2;
|
|
|
|
float tempr, tempg, tempb;
|
|
|
|
|
|
|
|
//Set the temporary values
|
|
|
|
if( get_color( src, lightness_t() ) < 0.5 )
|
|
|
|
{
|
|
|
|
temp2 = get_color( src, lightness_t() )
|
|
|
|
* ( 1.f + get_color( src, saturation_t() ) );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
temp2 = ( get_color( src, lightness_t() ) + get_color( src, saturation_t() ))
|
|
|
|
- ( get_color( src, lightness_t() ) * get_color( src, saturation_t() ));
|
|
|
|
}
|
|
|
|
|
|
|
|
temp1 = 2.f
|
|
|
|
* get_color( src, lightness_t() )
|
|
|
|
- temp2;
|
|
|
|
|
|
|
|
tempr = get_color( src, hue_t() ) + 1.f / 3.f;
|
|
|
|
|
|
|
|
if( tempr > 1.f )
|
|
|
|
{
|
|
|
|
tempr--;
|
|
|
|
}
|
|
|
|
|
|
|
|
tempg = get_color( src, hue_t() );
|
|
|
|
tempb = get_color( src, hue_t() ) - 1.f / 3.f;
|
|
|
|
|
|
|
|
if( tempb < 0.f )
|
|
|
|
{
|
|
|
|
tempb++;
|
|
|
|
}
|
|
|
|
|
|
|
|
//Red
|
|
|
|
if( tempr < 1.f / 6.f )
|
|
|
|
{
|
|
|
|
red = temp1 + ( temp2 - temp1 ) * 6.f * tempr;
|
|
|
|
}
|
|
|
|
else if( tempr < 0.5f )
|
|
|
|
{
|
|
|
|
red = temp2;
|
|
|
|
}
|
|
|
|
else if( tempr < 2.f / 3.f )
|
|
|
|
{
|
|
|
|
red = temp1 + (temp2 - temp1)
|
|
|
|
* (( 2.f / 3.f ) - tempr) * 6.f;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
red = temp1;
|
|
|
|
}
|
|
|
|
|
|
|
|
//Green
|
|
|
|
if( tempg < 1.f / 6.f )
|
|
|
|
{
|
|
|
|
green = temp1 + ( temp2 - temp1 ) * 6.f * tempg;
|
|
|
|
}
|
|
|
|
else if( tempg < 0.5f )
|
|
|
|
{
|
|
|
|
green = temp2;
|
|
|
|
}
|
|
|
|
else if( tempg < 2.f / 3.f )
|
|
|
|
{
|
|
|
|
green = temp1 + ( temp2 - temp1 )
|
|
|
|
* (( 2.f / 3.f ) - tempg) * 6.f;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
green = temp1;
|
|
|
|
}
|
|
|
|
|
|
|
|
//Blue
|
|
|
|
if( tempb < 1.f / 6.f )
|
|
|
|
{
|
|
|
|
blue = temp1 + (temp2 - temp1) * 6.f * tempb;
|
|
|
|
}
|
|
|
|
else if( tempb < 0.5f )
|
|
|
|
{
|
|
|
|
blue = temp2;
|
|
|
|
}
|
|
|
|
else if( tempb < 2.f / 3.f )
|
|
|
|
{
|
|
|
|
blue = temp1 + (temp2 - temp1)
|
|
|
|
* (( 2.f / 3.f ) - tempb) * 6.f;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
blue = temp1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
get_color(dst,red_t()) =
|
|
|
|
channel_convert<typename color_element_type< P2, red_t >::type>( red );
|
|
|
|
get_color(dst,green_t())=
|
|
|
|
channel_convert<typename color_element_type< P2, green_t >::type>( green );
|
|
|
|
get_color(dst,blue_t()) =
|
|
|
|
channel_convert<typename color_element_type< P2, blue_t >::type>( blue );
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
} } // namespace boost::gil
|
|
|
|
|
|
|
|
#endif // GIL_HSL_H
|