###

#

color_convert.hpp
//
// Copyright 2005-2007 Adobe Systems Incorporated
//
// 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 BOOST_GIL_COLOR_CONVERT_HPP
#define BOOST_GIL_COLOR_CONVERT_HPP
#include <boost/gil/channel_algorithm.hpp>
#include <boost/gil/cmyk.hpp>
#include <boost/gil/color_base_algorithm.hpp>
#include <boost/gil/gray.hpp>
#include <boost/gil/metafunctions.hpp>
#include <boost/gil/pixel.hpp>
#include <boost/gil/rgb.hpp>
#include <boost/gil/rgba.hpp>
#include <boost/gil/utilities.hpp>
#include <algorithm>
#include <functional>
#include <type_traits>
namespace boost { namespace gil {
// Forward-declare
template <typename P> struct channel_type;
template <typename C1, typename C2>
struct default_color_converter_impl
{
static_assert(
std::is_same<C1, C2>::value,
"default_color_converter_impl not specialized for given color spaces");
};
template <typename C>
struct default_color_converter_impl<C,C> {
template <typename P1, typename P2>
void operator()(const P1& src, P2& dst) const {
static_for_each(src,dst,default_channel_converter());
}
};
namespace detail {
// The default implementation of to_luminance uses float0..1 as the intermediate channel type
template <typename RedChannel, typename GreenChannel, typename BlueChannel, typename GrayChannelValue>
struct rgb_to_luminance_fn {
GrayChannelValue operator()(const RedChannel& red, const GreenChannel& green, const BlueChannel& blue) const {
return channel_convert<GrayChannelValue>(float32_t(
channel_convert<float32_t>(red )*0.30f +
channel_convert<float32_t>(green)*0.59f +
channel_convert<float32_t>(blue )*0.11f) );
}
};
// performance specialization for unsigned char
template <typename GrayChannelValue>
struct rgb_to_luminance_fn<uint8_t,uint8_t,uint8_t, GrayChannelValue> {
GrayChannelValue operator()(uint8_t red, uint8_t green, uint8_t blue) const {
return channel_convert<GrayChannelValue>(uint8_t(
((uint32_t(red )*4915 + uint32_t(green)*9667 + uint32_t(blue )*1802) + 8192) >> 14));
}
};
template <typename GrayChannel, typename RedChannel, typename GreenChannel, typename BlueChannel>
typename channel_traits<GrayChannel>::value_type rgb_to_luminance(const RedChannel& red, const GreenChannel& green, const BlueChannel& blue) {
return rgb_to_luminance_fn<RedChannel,GreenChannel,BlueChannel,
typename channel_traits<GrayChannel>::value_type>()(red,green,blue);
}
} // namespace detail
template <>
struct default_color_converter_impl<gray_t,rgb_t> {
template <typename P1, typename P2>
void operator()(const P1& src, P2& dst) const {
get_color(dst,red_t()) =
channel_convert<typename color_element_type<P2, red_t >::type>(get_color(src,gray_color_t()));
get_color(dst,green_t())=
channel_convert<typename color_element_type<P2, green_t>::type>(get_color(src,gray_color_t()));
get_color(dst,blue_t()) =
channel_convert<typename color_element_type<P2, blue_t >::type>(get_color(src,gray_color_t()));
}
};
template <>
struct default_color_converter_impl<gray_t,cmyk_t> {
template <typename P1, typename P2>
void operator()(const P1& src, P2& dst) const {
get_color(dst,cyan_t())=
channel_traits<typename color_element_type<P2, cyan_t >::type>::min_value();
get_color(dst,magenta_t())=
channel_traits<typename color_element_type<P2, magenta_t>::type>::min_value();
get_color(dst,yellow_t())=
channel_traits<typename color_element_type<P2, yellow_t >::type>::min_value();
get_color(dst,black_t())=
channel_convert<typename color_element_type<P2, black_t >::type>(get_color(src,gray_color_t()));
}
};
template <>
struct default_color_converter_impl<rgb_t,gray_t> {
template <typename P1, typename P2>
void operator()(const P1& src, P2& dst) const {
get_color(dst,gray_color_t()) =
detail::rgb_to_luminance<typename color_element_type<P2,gray_color_t>::type>(
get_color(src,red_t()), get_color(src,green_t()), get_color(src,blue_t())
);
}
};
template <>
struct default_color_converter_impl<rgb_t, cmyk_t>
{
template <typename SrcPixel, typename DstPixel>
void operator()(SrcPixel const& src, DstPixel& dst) const
{
using src_t = typename channel_type<SrcPixel>::type;
src_t const r = get_color(src, red_t());
src_t const g = get_color(src, green_t());
src_t const b = get_color(src, blue_t());
using dst_t = typename channel_type<DstPixel>::type;
dst_t const c = channel_invert(channel_convert<dst_t>(r)); // c = 1 - r
dst_t const m = channel_invert(channel_convert<dst_t>(g)); // m = 1 - g
dst_t const y = channel_invert(channel_convert<dst_t>(b)); // y = 1 - b
dst_t const k = (std::min)(c, (std::min)(m, y)); // k = minimum(c, m, y)
// Apply color correction, strengthening, reducing non-zero components by
// s = 1 / (1 - k) for k < 1, where 1 denotes dst_t max, otherwise s = 1 (literal).
dst_t const dst_max = channel_traits<dst_t>::max_value();
dst_t const s_div = dst_max - k;
if (s_div != 0)
{
double const s = dst_max / static_cast<double>(s_div);
get_color(dst, cyan_t()) = static_cast<dst_t>((c - k) * s);
get_color(dst, magenta_t()) = static_cast<dst_t>((m - k) * s);
get_color(dst, yellow_t()) = static_cast<dst_t>((y - k) * s);
}
else
{
// Black only for k = 1 (max of dst_t)
get_color(dst, cyan_t()) = channel_traits<dst_t>::min_value();
get_color(dst, magenta_t()) = channel_traits<dst_t>::min_value();
get_color(dst, yellow_t()) = channel_traits<dst_t>::min_value();
}
get_color(dst, black_t()) = k;
}
};
template <>
struct default_color_converter_impl<cmyk_t,rgb_t> {
template <typename P1, typename P2>
void operator()(const P1& src, P2& dst) const {
using T1 = typename channel_type<P1>::type;
get_color(dst,red_t()) =
channel_convert<typename color_element_type<P2,red_t>::type>(
channel_invert<T1>(
(std::min)(channel_traits<T1>::max_value(),
T1(channel_multiply(get_color(src,cyan_t()),channel_invert(get_color(src,black_t())))+get_color(src,black_t())))));
get_color(dst,green_t())=
channel_convert<typename color_element_type<P2,green_t>::type>(
channel_invert<T1>(
(std::min)(channel_traits<T1>::max_value(),
T1(channel_multiply(get_color(src,magenta_t()),channel_invert(get_color(src,black_t())))+get_color(src,black_t())))));
get_color(dst,blue_t()) =
channel_convert<typename color_element_type<P2,blue_t>::type>(
channel_invert<T1>(
(std::min)(channel_traits<T1>::max_value(),
T1(channel_multiply(get_color(src,yellow_t()),channel_invert(get_color(src,black_t())))+get_color(src,black_t())))));
}
};
template <>
struct default_color_converter_impl<cmyk_t,gray_t> {
template <typename P1, typename P2>
void operator()(const P1& src, P2& dst) const {
get_color(dst,gray_color_t())=
channel_convert<typename color_element_type<P2,gray_color_t>::type>(
channel_multiply(
channel_invert(
detail::rgb_to_luminance<typename color_element_type<P1,black_t>::type>(
get_color(src,cyan_t()),
get_color(src,magenta_t()),
get_color(src,yellow_t())
)
),
channel_invert(get_color(src,black_t()))));
}
};
namespace detail {
template <typename Pixel>
auto alpha_or_max_impl(Pixel const& p, std::true_type) -> typename channel_type<Pixel>::type
{
return get_color(p,alpha_t());
}
template <typename Pixel>
auto alpha_or_max_impl(Pixel const&, std::false_type) -> typename channel_type<Pixel>::type
{
return channel_traits<typename channel_type<Pixel>::type>::max_value();
}
} // namespace detail
// Returns max_value if the pixel has no alpha channel. Otherwise returns the alpha.
template <typename Pixel>
auto alpha_or_max(Pixel const& p) -> typename channel_type<Pixel>::type
{
return detail::alpha_or_max_impl(
p,
mp11::mp_contains<typename color_space_type<Pixel>::type, alpha_t>());
}
template <typename C1>
struct default_color_converter_impl<C1,rgba_t> {
template <typename P1, typename P2>
void operator()(const P1& src, P2& dst) const {
using T2 = typename channel_type<P2>::type;
pixel<T2,rgb_layout_t> tmp;
default_color_converter_impl<C1,rgb_t>()(src,tmp);
get_color(dst,red_t()) =get_color(tmp,red_t());
get_color(dst,green_t())=get_color(tmp,green_t());
get_color(dst,blue_t()) =get_color(tmp,blue_t());
get_color(dst,alpha_t())=channel_convert<T2>(alpha_or_max(src));
}
};
template <typename C2>
struct default_color_converter_impl<rgba_t,C2> {
template <typename P1, typename P2>
void operator()(const P1& src, P2& dst) const {
using T1 = typename channel_type<P1>::type;
default_color_converter_impl<rgb_t,C2>()(
pixel<T1,rgb_layout_t>(channel_multiply(get_color(src,red_t()), get_color(src,alpha_t())),
channel_multiply(get_color(src,green_t()),get_color(src,alpha_t())),
channel_multiply(get_color(src,blue_t()), get_color(src,alpha_t())))
,dst);
}
};
template <>
struct default_color_converter_impl<rgba_t,rgba_t> {
template <typename P1, typename P2>
void operator()(const P1& src, P2& dst) const {
static_for_each(src,dst,default_channel_converter());
}
};
struct default_color_converter {
template <typename SrcP, typename DstP>
void operator()(const SrcP& src,DstP& dst) const {
using SrcColorSpace = typename color_space_type<SrcP>::type;
using DstColorSpace = typename color_space_type<DstP>::type;
default_color_converter_impl<SrcColorSpace,DstColorSpace>()(src,dst);
}
};
template <typename SrcP, typename DstP>
inline void color_convert(const SrcP& src, DstP& dst) {
default_color_converter()(src,dst);
}
} } // namespace boost::gil
#endif
boost::gil::magenta_t
Magenta.
Definition: cmyk.hpp:25
boost::gil::channel_invert
channel_traits< Channel >::value_type channel_invert(Channel x)
Default implementation. Provide overloads for performance.
Definition: channel_algorithm.hpp:559
boost::gil::pixel
Represents a pixel value (a container of channels). Models: HomogeneousColorBaseValueConcept,...
Definition: metafunctions.hpp:23
boost::gil::float32_t
scoped_channel_value< float, float_point_zero< float >, float_point_one< float > > float32_t
32-bit floating point channel type with range [0.0f ... 1.0f]. Models ChannelValueConcept
Definition: typedefs.hpp:124
boost::gil::yellow_t
Yellow.
Definition: cmyk.hpp:28
boost::gil::channel_multiply
channel_traits< Channel >::value_type channel_multiply(Channel a, Channel b)
A function multiplying two channels. result = a * b / max_value.
Definition: channel_algorithm.hpp:539
boost::gil::get_color
color_element_reference_type< ColorBase, Color >::type get_color(ColorBase &cb, Color=Color())
Mutable accessor to the element associated with a given color name.
Definition: color_base_algorithm.hpp:190
boost::gil::green_t
Green.
Definition: rgb.hpp:27
boost::gil::default_channel_converter
Same as channel_converter, except it takes the destination channel by reference, which allows us to m...
Definition: channel_algorithm.hpp:460
boost::gil::alpha_t
Alpha.
Definition: rgba.hpp:22
boost::gil::channel_type
Definition: color_convert.hpp:31
boost::gil::default_color_converter_impl
Color Convertion function object. To be specialized for every src/dst color space.
Definition: color_convert.hpp:42
boost::gil::blue_t
Blue.
Definition: rgb.hpp:30
boost::gil::color_convert
void color_convert(const SrcP &src, DstP &dst)
helper function for converting one pixel to another using GIL default color-converters where ScrP mod...
Definition: color_convert.hpp:336
boost::gil::detail::rgb_to_luminance_fn
red * .3 + green * .59 + blue * .11 + .5
Definition: color_convert.hpp:65
boost::gil::black_t
Black.
Definition: cmyk.hpp:31
boost::gil::red_t
Red.
Definition: rgb.hpp:24
boost::gil::gray_color_t
Gray.
Definition: gray.hpp:18
boost::gil::cyan_t
Cyan.
Definition: cmyk.hpp:22
boost::gil::default_color_converter
class for color-converting one pixel to another
Definition: color_convert.hpp:322