Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2024-11-15 09:12:38

0001 //
0002 // Copyright 2005-2007 Adobe Systems Incorporated
0003 //
0004 // Distributed under the Boost Software License, Version 1.0
0005 // See accompanying file LICENSE_1_0.txt or copy at
0006 // http://www.boost.org/LICENSE_1_0.txt
0007 //
0008 #ifndef BOOST_GIL_GIL_CHANNEL_ALGORITHM_HPP
0009 #define BOOST_GIL_GIL_CHANNEL_ALGORITHM_HPP
0010 
0011 #include <boost/gil/channel.hpp>
0012 #include <boost/gil/promote_integral.hpp>
0013 #include <boost/gil/typedefs.hpp>
0014 #include <boost/gil/detail/is_channel_integral.hpp>
0015 #include <boost/gil/detail/mp11.hpp>
0016 
0017 #include <limits>
0018 #include <type_traits>
0019 
0020 namespace boost { namespace gil {
0021 
0022 namespace detail {
0023 
0024 // some forward declarations
0025 template <typename SrcChannelV, typename DstChannelV, bool SrcIsIntegral, bool DstIsIntegral>
0026 struct channel_converter_unsigned_impl;
0027 
0028 template <typename SrcChannelV, typename DstChannelV, bool SrcIsGreater>
0029 struct channel_converter_unsigned_integral;
0030 
0031 template <typename SrcChannelV, typename DstChannelV, bool SrcLessThanDst, bool SrcDivisible>
0032 struct channel_converter_unsigned_integral_impl;
0033 
0034 template <typename SrcChannelV, typename DstChannelV, bool SrcLessThanDst, bool CannotFitInInteger>
0035 struct channel_converter_unsigned_integral_nondivisible;
0036 
0037 //////////////////////////////////////
0038 ////  unsigned_integral_max_value - given an unsigned integral channel type,
0039 //// returns its maximum value as an integral constant
0040 //////////////////////////////////////
0041 
0042 template <typename UnsignedIntegralChannel>
0043 struct unsigned_integral_max_value
0044     : std::integral_constant
0045     <
0046         UnsignedIntegralChannel,
0047         (std::numeric_limits<UnsignedIntegralChannel>::max)()
0048     >
0049 {};
0050 
0051 template <>
0052 struct unsigned_integral_max_value<uint8_t>
0053     : std::integral_constant<uint32_t, 0xFF>
0054 {};
0055 
0056 template <>
0057 struct unsigned_integral_max_value<uint16_t>
0058     : std::integral_constant<uint32_t, 0xFFFF>
0059 {};
0060 
0061 template <>
0062 struct unsigned_integral_max_value<uint32_t>
0063     : std::integral_constant<uintmax_t, 0xFFFFFFFF>
0064 {};
0065 
0066 template <int K>
0067 struct unsigned_integral_max_value<packed_channel_value<K>>
0068     : std::integral_constant
0069     <
0070         typename packed_channel_value<K>::integer_t,
0071         (uint64_t(1)<<K)-1
0072     >
0073 {};
0074 
0075 //////////////////////////////////////
0076 //// unsigned_integral_num_bits - given an unsigned integral channel type,
0077 //// returns the minimum number of bits needed to represent it
0078 //////////////////////////////////////
0079 
0080 template <typename UnsignedIntegralChannel>
0081 struct unsigned_integral_num_bits
0082     : std::integral_constant<int, static_cast<int>(sizeof(UnsignedIntegralChannel) * 8)>
0083 {};
0084 
0085 template <int K>
0086 struct unsigned_integral_num_bits<packed_channel_value<K>>
0087     : std::integral_constant<int, K>
0088 {};
0089 
0090 } // namespace detail
0091 
0092 /// \defgroup ChannelConvertAlgorithm channel_convert
0093 /// \brief Converting from one channel type to another
0094 /// \ingroup ChannelAlgorithm
0095 ///
0096 /// Conversion is done as a simple linear mapping of one channel range to the other,
0097 /// such that the minimum/maximum value of the source maps to the minimum/maximum value of the destination.
0098 /// One implication of this is that the value 0 of signed channels may not be preserved!
0099 ///
0100 /// When creating new channel models, it is often a good idea to provide specializations for the channel conversion algorithms, for
0101 /// example, for performance optimizations. If the new model is an integral type that can be signed, it is easier to define the conversion
0102 /// only for the unsigned type (\p channel_converter_unsigned) and provide specializations of \p detail::channel_convert_to_unsigned
0103 /// and \p detail::channel_convert_from_unsigned to convert between the signed and unsigned type.
0104 ///
0105 /// Example:
0106 /// \code
0107 /// // float32_t is a floating point channel with range [0.0f ... 1.0f]
0108 /// float32_t src_channel = channel_traits<float32_t>::max_value();
0109 /// assert(src_channel == 1);
0110 ///
0111 /// // uint8_t is 8-bit unsigned integral channel (aliased from unsigned char)
0112 /// uint8_t dst_channel = channel_convert<uint8_t>(src_channel);
0113 /// assert(dst_channel == 255);     // max value goes to max value
0114 /// \endcode
0115 
0116 ///
0117 /// \defgroup ChannelConvertUnsignedAlgorithm channel_converter_unsigned
0118 /// \ingroup ChannelConvertAlgorithm
0119 /// \brief Convert one unsigned/floating point channel to another. Converts both the channel type and range
0120 /// @{
0121 
0122 //////////////////////////////////////
0123 ////  channel_converter_unsigned
0124 //////////////////////////////////////
0125 
0126 template <typename SrcChannelV, typename DstChannelV>     // Model ChannelValueConcept
0127 struct channel_converter_unsigned
0128     : detail::channel_converter_unsigned_impl
0129     <
0130         SrcChannelV,
0131         DstChannelV,
0132         detail::is_channel_integral<SrcChannelV>::value,
0133         detail::is_channel_integral<DstChannelV>::value
0134     >
0135 {};
0136 
0137 /// \brief Converting a channel to itself - identity operation
0138 template <typename T> struct channel_converter_unsigned<T,T> : public detail::identity<T> {};
0139 
0140 namespace detail {
0141 
0142 //////////////////////////////////////
0143 ////  channel_converter_unsigned_impl
0144 //////////////////////////////////////
0145 
0146 /// \brief This is the default implementation. Performance specializatons are provided
0147 template <typename SrcChannelV, typename DstChannelV, bool SrcIsIntegral, bool DstIsIntegral>
0148 struct channel_converter_unsigned_impl {
0149     using argument_type = SrcChannelV;
0150     using result_type = DstChannelV;
0151     auto operator()(SrcChannelV src) const -> DstChannelV
0152     {
0153         return DstChannelV(channel_traits<DstChannelV>::min_value() +
0154             (src - channel_traits<SrcChannelV>::min_value()) / channel_range<SrcChannelV>() * channel_range<DstChannelV>());
0155     }
0156 
0157 private:
0158     template <typename C>
0159     static auto channel_range() -> double
0160     {
0161         return double(channel_traits<C>::max_value()) - double(channel_traits<C>::min_value());
0162     }
0163 };
0164 
0165 // When both the source and the destination are integral channels, perform a faster conversion
0166 template <typename SrcChannelV, typename DstChannelV>
0167 struct channel_converter_unsigned_impl<SrcChannelV, DstChannelV, true, true>
0168     : channel_converter_unsigned_integral
0169     <
0170         SrcChannelV,
0171         DstChannelV,
0172         mp11::mp_less
0173         <
0174             unsigned_integral_max_value<SrcChannelV>,
0175             unsigned_integral_max_value<DstChannelV>
0176         >::value
0177     >
0178 {};
0179 
0180 //////////////////////////////////////
0181 ////  channel_converter_unsigned_integral
0182 //////////////////////////////////////
0183 
0184 template <typename SrcChannelV, typename DstChannelV>
0185 struct channel_converter_unsigned_integral<SrcChannelV,DstChannelV,true>
0186     : public channel_converter_unsigned_integral_impl<SrcChannelV,DstChannelV,true,
0187     !(unsigned_integral_max_value<DstChannelV>::value % unsigned_integral_max_value<SrcChannelV>::value) > {};
0188 
0189 template <typename SrcChannelV, typename DstChannelV>
0190 struct channel_converter_unsigned_integral<SrcChannelV,DstChannelV,false>
0191     : public channel_converter_unsigned_integral_impl<SrcChannelV,DstChannelV,false,
0192     !(unsigned_integral_max_value<SrcChannelV>::value % unsigned_integral_max_value<DstChannelV>::value) > {};
0193 
0194 
0195 //////////////////////////////////////
0196 ////  channel_converter_unsigned_integral_impl
0197 //////////////////////////////////////
0198 
0199 // Both source and destination are unsigned integral channels,
0200 // the src max value is less than the dst max value,
0201 // and the dst max value is divisible by the src max value
0202 template <typename SrcChannelV, typename DstChannelV>
0203 struct channel_converter_unsigned_integral_impl<SrcChannelV,DstChannelV,true,true> {
0204     auto operator()(SrcChannelV src) const -> DstChannelV
0205     {
0206         using integer_t = typename unsigned_integral_max_value<DstChannelV>::value_type;
0207         static const integer_t mul = unsigned_integral_max_value<DstChannelV>::value / unsigned_integral_max_value<SrcChannelV>::value;
0208         return DstChannelV(src * mul);
0209     }
0210 };
0211 
0212 // Both source and destination are unsigned integral channels,
0213 // the dst max value is less than (or equal to) the src max value,
0214 // and the src max value is divisible by the dst max value
0215 template <typename SrcChannelV, typename DstChannelV>
0216 struct channel_converter_unsigned_integral_impl<SrcChannelV,DstChannelV,false,true> {
0217     auto operator()(SrcChannelV src) const -> DstChannelV
0218     {
0219         using integer_t = typename unsigned_integral_max_value<SrcChannelV>::value_type;
0220         static const integer_t div = unsigned_integral_max_value<SrcChannelV>::value / unsigned_integral_max_value<DstChannelV>::value;
0221         static const integer_t div2 = div/2;
0222         return DstChannelV((src + div2) / div);
0223     }
0224 };
0225 
0226 // Prevent overflow for the largest integral type
0227 template <typename DstChannelV>
0228 struct channel_converter_unsigned_integral_impl<uintmax_t,DstChannelV,false,true> {
0229     auto operator()(uintmax_t src) const -> DstChannelV
0230     {
0231         static const uintmax_t div = unsigned_integral_max_value<uint32_t>::value / unsigned_integral_max_value<DstChannelV>::value;
0232         static const uintmax_t div2 = div/2;
0233         if (src > unsigned_integral_max_value<uintmax_t>::value - div2)
0234             return unsigned_integral_max_value<DstChannelV>::value;
0235         return DstChannelV((src + div2) / div);
0236     }
0237 };
0238 
0239 // Both source and destination are unsigned integral channels,
0240 // and the dst max value is not divisible by the src max value
0241 // See if you can represent the expression (src * dst_max) / src_max in integral form
0242 template <typename SrcChannelV, typename DstChannelV, bool SrcLessThanDst>
0243 struct channel_converter_unsigned_integral_impl<SrcChannelV, DstChannelV, SrcLessThanDst, false>
0244     : channel_converter_unsigned_integral_nondivisible
0245     <
0246         SrcChannelV,
0247         DstChannelV,
0248         SrcLessThanDst,
0249         mp11::mp_less
0250         <
0251             unsigned_integral_num_bits<uintmax_t>,
0252             mp11::mp_plus
0253             <
0254                 unsigned_integral_num_bits<SrcChannelV>,
0255                 unsigned_integral_num_bits<DstChannelV>
0256             >
0257         >::value
0258     >
0259 {};
0260 
0261 // Both source and destination are unsigned integral channels,
0262 // the src max value is less than the dst max value,
0263 // and the dst max value is not divisible by the src max value
0264 // The expression (src * dst_max) / src_max fits in an integer
0265 template <typename SrcChannelV, typename DstChannelV>
0266 struct channel_converter_unsigned_integral_nondivisible<SrcChannelV, DstChannelV, true, false>
0267 {
0268     auto operator()(SrcChannelV src) const -> DstChannelV
0269     {
0270         using dest_t = typename base_channel_type<DstChannelV>::type;
0271         return DstChannelV(
0272             static_cast<dest_t>(src * unsigned_integral_max_value<DstChannelV>::value)
0273             / unsigned_integral_max_value<SrcChannelV>::value);
0274     }
0275 };
0276 
0277 // Both source and destination are unsigned integral channels,
0278 // the src max value is less than the dst max value,
0279 // and the dst max value is not divisible by the src max value
0280 // The expression (src * dst_max) / src_max cannot fit in an integer (overflows). Use a double
0281 template <typename SrcChannelV, typename DstChannelV>
0282 struct channel_converter_unsigned_integral_nondivisible<SrcChannelV, DstChannelV, true, true>
0283 {
0284     auto operator()(SrcChannelV src) const -> DstChannelV
0285     {
0286         static const double mul
0287             = unsigned_integral_max_value<DstChannelV>::value
0288             / double(unsigned_integral_max_value<SrcChannelV>::value);
0289         return DstChannelV(src * mul);
0290     }
0291 };
0292 
0293 // Both source and destination are unsigned integral channels,
0294 // the dst max value is less than (or equal to) the src max value,
0295 // and the src max value is not divisible by the dst max value
0296 template <typename SrcChannelV, typename DstChannelV, bool CannotFit>
0297 struct channel_converter_unsigned_integral_nondivisible<SrcChannelV,DstChannelV,false,CannotFit>
0298 {
0299     auto operator()(SrcChannelV src) const -> DstChannelV
0300     {
0301         using src_integer_t = typename detail::unsigned_integral_max_value<SrcChannelV>::value_type;
0302         using dst_integer_t = typename detail::unsigned_integral_max_value<DstChannelV>::value_type;
0303 
0304         static const double div = unsigned_integral_max_value<SrcChannelV>::value
0305                                 / static_cast< double >( unsigned_integral_max_value<DstChannelV>::value );
0306 
0307         static const src_integer_t div2 = static_cast< src_integer_t >( div / 2.0 );
0308 
0309         return DstChannelV( static_cast< dst_integer_t >(( static_cast< double >( src + div2 ) / div )));
0310     }
0311 };
0312 
0313 } // namespace detail
0314 
0315 /////////////////////////////////////////////////////
0316 ///  float32_t conversion
0317 /////////////////////////////////////////////////////
0318 
0319 template <typename DstChannelV> struct channel_converter_unsigned<float32_t,DstChannelV> {
0320     using argument_type = float32_t;
0321     using result_type = DstChannelV;
0322     auto operator()(float32_t x) const -> DstChannelV
0323     {
0324         using dst_integer_t = typename detail::unsigned_integral_max_value<DstChannelV>::value_type;
0325         return DstChannelV( static_cast< dst_integer_t >(x*channel_traits<DstChannelV>::max_value()+0.5f ));
0326     }
0327 };
0328 
0329 template <typename SrcChannelV> struct channel_converter_unsigned<SrcChannelV,float32_t> {
0330     using argument_type = float32_t;
0331     using result_type = SrcChannelV;
0332     auto operator()(SrcChannelV x) const -> float32_t { return float32_t(x/float(channel_traits<SrcChannelV>::max_value())); }
0333 };
0334 
0335 template <> struct channel_converter_unsigned<float32_t,float32_t> {
0336     using argument_type = float32_t;
0337     using result_type = float32_t;
0338     auto operator()(float32_t x) const -> float32_t { return x; }
0339 };
0340 
0341 
0342 /// \brief 32 bit <-> float channel conversion
0343 template <> struct channel_converter_unsigned<uint32_t,float32_t> {
0344     using argument_type = uint32_t;
0345     using result_type = float32_t;
0346     auto operator()(uint32_t x) const -> float32_t
0347     {
0348         // unfortunately without an explicit check it is possible to get a round-off error. We must ensure that max_value of uint32_t matches max_value of float32_t
0349         if (x>=channel_traits<uint32_t>::max_value()) return channel_traits<float32_t>::max_value();
0350         return float(x) / float(channel_traits<uint32_t>::max_value());
0351     }
0352 };
0353 /// \brief 32 bit <-> float channel conversion
0354 template <> struct channel_converter_unsigned<float32_t,uint32_t> {
0355     using argument_type = float32_t;
0356     using result_type = uint32_t;
0357     auto operator()(float32_t x) const -> uint32_t
0358     {
0359         // unfortunately without an explicit check it is possible to get a round-off error. We must ensure that max_value of uint32_t matches max_value of float32_t
0360         if (x>=channel_traits<float32_t>::max_value())
0361             return channel_traits<uint32_t>::max_value();
0362 
0363         auto const max_value = channel_traits<uint32_t>::max_value();
0364         auto const result = x * static_cast<float32_t::base_channel_t>(max_value) + 0.5f;
0365         return static_cast<uint32_t>(result);
0366     }
0367 };
0368 
0369 /// @}
0370 
0371 namespace detail {
0372 // Converting from signed to unsigned integral channel.
0373 // It is both a unary function, and a metafunction (thus requires the 'type' nested alias, which equals result_type)
0374 template <typename ChannelValue>     // Model ChannelValueConcept
0375 struct channel_convert_to_unsigned : public detail::identity<ChannelValue> {
0376     using type = ChannelValue;
0377 };
0378 
0379 template <> struct channel_convert_to_unsigned<int8_t> {
0380     using argument_type = int8_t;
0381     using result_type = uint8_t;
0382     using type = uint8_t;
0383     type operator()(int8_t val) const {
0384         return static_cast<uint8_t>(static_cast<uint32_t>(val) + 128u);
0385     }
0386 };
0387 
0388 template <> struct channel_convert_to_unsigned<int16_t> {
0389     using argument_type = int16_t;
0390     using result_type = uint16_t;
0391     using type = uint16_t;
0392     type operator()(int16_t val) const {
0393         return static_cast<uint16_t>(static_cast<uint32_t>(val) + 32768u);
0394     }
0395 };
0396 
0397 template <> struct channel_convert_to_unsigned<int32_t> {
0398     using argument_type = int32_t;
0399     using result_type = uint32_t;
0400     using type = uint32_t;
0401     type operator()(int32_t val) const {
0402         return static_cast<uint32_t>(val)+(1u<<31);
0403     }
0404 };
0405 
0406 
0407 // Converting from unsigned to signed integral channel
0408 // It is both a unary function, and a metafunction (thus requires the 'type' nested alias, which equals result_type)
0409 template <typename ChannelValue>     // Model ChannelValueConcept
0410 struct channel_convert_from_unsigned : public detail::identity<ChannelValue> {
0411     using type = ChannelValue;
0412 };
0413 
0414 template <> struct channel_convert_from_unsigned<int8_t> {
0415     using argument_type = uint8_t;
0416     using result_type = int8_t;
0417     using type = int8_t;
0418     type operator()(uint8_t val) const {
0419         return static_cast<int8_t>(static_cast<int32_t>(val) - 128);
0420     }
0421 };
0422 
0423 template <> struct channel_convert_from_unsigned<int16_t> {
0424     using argument_type = uint16_t;
0425     using result_type = int16_t;
0426     using type = int16_t;
0427     type operator()(uint16_t val) const {
0428         return static_cast<int16_t>(static_cast<int32_t>(val) - 32768);
0429     }
0430 };
0431 
0432 template <> struct channel_convert_from_unsigned<int32_t> {
0433     using argument_type = uint32_t;
0434     using result_type = int32_t;
0435     using type = int32_t;
0436     type operator()(uint32_t val) const {
0437         return static_cast<int32_t>(val - (1u<<31));
0438     }
0439 };
0440 
0441 }   // namespace detail
0442 
0443 /// \ingroup ChannelConvertAlgorithm
0444 /// \brief A unary function object converting between channel types
0445 template <typename SrcChannelV, typename DstChannelV> // Model ChannelValueConcept
0446 struct channel_converter {
0447     using argument_type = SrcChannelV;
0448     using result_type = DstChannelV;
0449     auto operator()(SrcChannelV const& src) const -> DstChannelV
0450     {
0451         using to_unsigned = detail::channel_convert_to_unsigned<SrcChannelV>;
0452         using from_unsigned = detail::channel_convert_from_unsigned<DstChannelV>;
0453         using converter_unsigned = channel_converter_unsigned<typename to_unsigned::result_type, typename from_unsigned::argument_type>;
0454         return from_unsigned()(converter_unsigned()(to_unsigned()(src)));
0455     }
0456 };
0457 
0458 /// \ingroup ChannelConvertAlgorithm
0459 /// \brief Converting from one channel type to another.
0460 template <typename DstChannel, typename SrcChannel> // Model ChannelConcept (could be channel references)
0461 inline auto channel_convert(SrcChannel const& src) -> typename channel_traits<DstChannel>::value_type
0462 {
0463     return channel_converter<typename channel_traits<SrcChannel>::value_type,
0464                              typename channel_traits<DstChannel>::value_type>()(src);
0465 }
0466 
0467 /// \ingroup ChannelConvertAlgorithm
0468 /// \brief Same as channel_converter, except it takes the destination channel by reference, which allows
0469 ///        us to move the templates from the class level to the method level. This is important when invoking it
0470 ///        on heterogeneous pixels.
0471 struct default_channel_converter {
0472     template <typename Ch1, typename Ch2>
0473     void operator()(Ch1 const& src, Ch2& dst) const
0474     {
0475         dst=channel_convert<Ch2>(src);
0476     }
0477 };
0478 
0479 namespace detail
0480 {
0481     // fast integer division by 255
0482     inline auto div255(uint32_t in) -> uint32_t
0483     {
0484         uint32_t tmp = in + 128;
0485         return (tmp + (tmp >> 8)) >> 8;
0486     }
0487 
0488     // fast integer divison by 32768
0489     inline auto div32768(uint32_t in) -> uint32_t
0490     {
0491         return (in + 16384) >> 15;
0492     }
0493 }
0494 
0495 /// \defgroup ChannelMultiplyAlgorithm channel_multiply
0496 /// \ingroup ChannelAlgorithm
0497 /// \brief Multiplying unsigned channel values of the same type. Performs scaled multiplication result = a * b / max_value
0498 ///
0499 /// Example:
0500 /// \code
0501 /// uint8_t x=128;
0502 /// uint8_t y=128;
0503 /// uint8_t mul = channel_multiply(x,y);
0504 /// assert(mul == 64);    // 64 = 128 * 128 / 255
0505 /// \endcode
0506 /// @{
0507 
0508 /// \brief This is the default implementation. Performance specializatons are provided
0509 template <typename ChannelValue>
0510 struct channel_multiplier_unsigned {
0511     using first_argument_type = ChannelValue;
0512     using second_argument_type = ChannelValue;
0513     using result_type = ChannelValue;
0514     auto operator()(ChannelValue a, ChannelValue b) const -> ChannelValue
0515     {
0516         return ChannelValue(static_cast<typename base_channel_type<ChannelValue>::type>(a / double(channel_traits<ChannelValue>::max_value()) * b));
0517     }
0518 };
0519 
0520 /// \brief Specialization of channel_multiply for 8-bit unsigned channels
0521 template<> struct channel_multiplier_unsigned<uint8_t> {
0522     using first_argument_type = uint8_t;
0523     using second_argument_type = uint8_t;
0524     using result_type = uint8_t;
0525     auto operator()(uint8_t a, uint8_t b) const -> uint8_t { return uint8_t(detail::div255(uint32_t(a) * uint32_t(b))); }
0526 };
0527 
0528 /// \brief Specialization of channel_multiply for 16-bit unsigned channels
0529 template<> struct channel_multiplier_unsigned<uint16_t> {
0530     using first_argument_type = uint16_t;
0531     using second_argument_type = uint16_t;
0532     using result_type = uint16_t;
0533     auto operator()(uint16_t a, uint16_t b) const -> uint16_t { return uint16_t((uint32_t(a) * uint32_t(b))/65535); }
0534 };
0535 
0536 /// \brief Specialization of channel_multiply for float 0..1 channels
0537 template<> struct channel_multiplier_unsigned<float32_t> {
0538     using first_argument_type = float32_t;
0539     using second_argument_type = float32_t;
0540     using result_type = float32_t;
0541     auto operator()(float32_t a, float32_t b) const -> float32_t { return a*b; }
0542 };
0543 
0544 /// \brief A function object to multiply two channels. result = a * b / max_value
0545 template <typename ChannelValue>
0546 struct channel_multiplier {
0547     using first_argument_type = ChannelValue;
0548     using second_argument_type = ChannelValue;
0549     using result_type = ChannelValue;
0550     auto operator()(ChannelValue a, ChannelValue b) const -> ChannelValue
0551     {
0552         using to_unsigned = detail::channel_convert_to_unsigned<ChannelValue>;
0553         using from_unsigned = detail::channel_convert_from_unsigned<ChannelValue>;
0554         using multiplier_unsigned = channel_multiplier_unsigned<typename to_unsigned::result_type>;
0555         return from_unsigned()(multiplier_unsigned()(to_unsigned()(a), to_unsigned()(b)));
0556     }
0557 };
0558 
0559 /// \brief A function multiplying two channels. result = a * b / max_value
0560 template <typename Channel> // Models ChannelConcept (could be a channel reference)
0561 inline auto channel_multiply(Channel a, Channel b) -> typename channel_traits<Channel>::value_type
0562 {
0563     return channel_multiplier<typename channel_traits<Channel>::value_type>()(a,b);
0564 }
0565 /// @}
0566 
0567 /// \defgroup ChannelInvertAlgorithm channel_invert
0568 /// \ingroup ChannelAlgorithm
0569 /// \brief Returns the inverse of a channel. result = max_value - x + min_value
0570 ///
0571 /// Example:
0572 /// \code
0573 /// // uint8_t == uint8_t == unsigned char
0574 /// uint8_t x=255;
0575 /// uint8_t inv = channel_invert(x);
0576 /// assert(inv == 0);
0577 /// \endcode
0578 
0579 /// \brief Default implementation. Provide overloads for performance
0580 /// \ingroup ChannelInvertAlgorithm channel_invert
0581 template <typename Channel> // Models ChannelConcept (could be a channel reference)
0582 inline auto channel_invert(Channel x) -> typename channel_traits<Channel>::value_type
0583 {
0584     using base_t = typename base_channel_type<Channel>::type;
0585     using promoted_t = typename promote_integral<base_t>::type;
0586     promoted_t const promoted_x = x;
0587     promoted_t const promoted_max = channel_traits<Channel>::max_value();
0588     promoted_t const promoted_min = channel_traits<Channel>::min_value();
0589     promoted_t const promoted_inverted_x = promoted_max - promoted_x + promoted_min;
0590     auto const inverted_x = static_cast<base_t>(promoted_inverted_x);
0591     return inverted_x;
0592 }
0593 
0594 }}  // namespace boost::gil
0595 
0596 #endif