1/*
2 Copyright 2005-2007 Adobe Systems Incorporated
3
4 Use, modification and distribution are subject to the Boost Software License,
5 Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
6 http://www.boost.org/LICENSE_1_0.txt).
7
8 See http://opensource.adobe.com/gil for most recent version including documentation.
9*/
10/*************************************************************************************************/
11
12#ifndef GIL_CHANNEL_ALGORITHM_HPP
13#define GIL_CHANNEL_ALGORITHM_HPP
14
15////////////////////////////////////////////////////////////////////////////////////////
16/// \file
17/// \brief Channel algorithms
18/// \author Lubomir Bourdev and Hailin Jin \n
19/// Adobe Systems Incorporated
20/// \date 2005-2007 \n Last updated on May 6, 2007
21///
22/// Definitions of standard GIL 8-bit, 16-bit, 32-bit channels
23///
24////////////////////////////////////////////////////////////////////////////////////////
25
26#include "gil_config.hpp"
27#include "channel.hpp"
28#include <boost/mpl/less.hpp>
29#include <boost/mpl/integral_c.hpp>
30#include <boost/mpl/greater.hpp>
31#include <boost/type_traits.hpp>
32
33namespace boost { namespace gil {
34
35//#ifdef _MSC_VER
36//#pragma warning(push)
37//#pragma warning(disable: 4309) // disable truncation of constant value warning (using -1 to get the max value of an integral)
38//#endif
39
40namespace detail {
41
42// some forward declarations
43template <typename SrcChannelV, typename DstChannelV, bool SrcIsIntegral, bool DstIsIntegral> struct channel_converter_unsigned_impl;
44template <typename SrcChannelV, typename DstChannelV, bool SrcIsGreater> struct channel_converter_unsigned_integral;
45template <typename SrcChannelV, typename DstChannelV, bool SrcLessThanDst, bool SrcDivisible> struct channel_converter_unsigned_integral_impl;
46template <typename SrcChannelV, typename DstChannelV, bool SrcLessThanDst, bool CannotFitInInteger> struct channel_converter_unsigned_integral_nondivisible;
47
48//////////////////////////////////////
49//// unsigned_integral_max_value - given an unsigned integral channel type, returns its maximum value as an MPL integral constant
50//////////////////////////////////////
51
52
53template <typename UnsignedIntegralChannel>
54struct unsigned_integral_max_value : public mpl::integral_c<UnsignedIntegralChannel,-1> {};
55
56template <>
57struct unsigned_integral_max_value<uint8_t> : public mpl::integral_c<uint32_t,0xFF> {};
58template <>
59struct unsigned_integral_max_value<uint16_t> : public mpl::integral_c<uint32_t,0xFFFF> {};
60template <>
61struct unsigned_integral_max_value<uint32_t> : public mpl::integral_c<uintmax_t,0xFFFFFFFF> {};
62
63
64template <int K>
65struct unsigned_integral_max_value<packed_channel_value<K> >
66 : public mpl::integral_c<typename packed_channel_value<K>::integer_t, (1<<K)-1> {};
67
68//////////////////////////////////////
69//// unsigned_integral_num_bits - given an unsigned integral channel type, returns the minimum number of bits needed to represent it
70//////////////////////////////////////
71
72template <typename UnsignedIntegralChannel>
73struct unsigned_integral_num_bits : public mpl::int_<sizeof(UnsignedIntegralChannel)*8> {};
74
75template <int K>
76struct unsigned_integral_num_bits<packed_channel_value<K> >
77 : public mpl::int_<K> {};
78
79} // namespace detail
80
81/**
82\defgroup ChannelConvertAlgorithm channel_convert
83\brief Converting from one channel type to another
84\ingroup ChannelAlgorithm
85
86Conversion is done as a simple linear mapping of one channel range to the other,
87such that the minimum/maximum value of the source maps to the minimum/maximum value of the destination.
88One implication of this is that the value 0 of signed channels may not be preserved!
89
90When creating new channel models, it is often a good idea to provide specializations for the channel conversion algorithms, for
91example, for performance optimizations. If the new model is an integral type that can be signed, it is easier to define the conversion
92only for the unsigned type (\p channel_converter_unsigned) and provide specializations of \p detail::channel_convert_to_unsigned
93and \p detail::channel_convert_from_unsigned to convert between the signed and unsigned type.
94
95Example:
96\code
97// bits32f is a floating point channel with range [0.0f ... 1.0f]
98bits32f src_channel = channel_traits<bits32f>::max_value();
99assert(src_channel == 1);
100
101// bits8 is 8-bit unsigned integral channel (typedef-ed from unsigned char)
102bits8 dst_channel = channel_convert<bits8>(src_channel);
103assert(dst_channel == 255); // max value goes to max value
104\endcode
105*/
106
107/**
108\defgroup ChannelConvertUnsignedAlgorithm channel_converter_unsigned
109\ingroup ChannelConvertAlgorithm
110\brief Convert one unsigned/floating point channel to another. Converts both the channel type and range
111 @{
112 */
113
114//////////////////////////////////////
115//// channel_converter_unsigned
116//////////////////////////////////////
117
118template <typename SrcChannelV, typename DstChannelV> // Model ChannelValueConcept
119struct channel_converter_unsigned
120 : public detail::channel_converter_unsigned_impl<SrcChannelV,DstChannelV,is_integral<SrcChannelV>::value,is_integral<DstChannelV>::value> {};
121
122
123/// \brief Converting a channel to itself - identity operation
124template <typename T> struct channel_converter_unsigned<T,T> : public detail::identity<T> {};
125
126
127namespace detail {
128
129//////////////////////////////////////
130//// channel_converter_unsigned_impl
131//////////////////////////////////////
132
133/// \brief This is the default implementation. Performance specializatons are provided
134template <typename SrcChannelV, typename DstChannelV, bool SrcIsIntegral, bool DstIsIntegral>
135struct channel_converter_unsigned_impl : public std::unary_function<DstChannelV,SrcChannelV> {
136 DstChannelV operator()(SrcChannelV src) const {
137 return DstChannelV(channel_traits<DstChannelV>::min_value() +
138 (src - channel_traits<SrcChannelV>::min_value()) / channel_range<SrcChannelV>() * channel_range<DstChannelV>());
139 }
140private:
141 template <typename C>
142 static double channel_range() {
143 return double(channel_traits<C>::max_value()) - double(channel_traits<C>::min_value());
144 }
145};
146
147// When both the source and the destination are integral channels, perform a faster conversion
148template <typename SrcChannelV, typename DstChannelV>
149struct channel_converter_unsigned_impl<SrcChannelV,DstChannelV,true,true>
150 : public channel_converter_unsigned_integral<SrcChannelV,DstChannelV,
151 mpl::less<unsigned_integral_max_value<SrcChannelV>,unsigned_integral_max_value<DstChannelV> >::value > {};
152
153
154//////////////////////////////////////
155//// channel_converter_unsigned_integral
156//////////////////////////////////////
157
158template <typename SrcChannelV, typename DstChannelV>
159struct channel_converter_unsigned_integral<SrcChannelV,DstChannelV,true>
160 : public channel_converter_unsigned_integral_impl<SrcChannelV,DstChannelV,true,
161 !(unsigned_integral_max_value<DstChannelV>::value % unsigned_integral_max_value<SrcChannelV>::value) > {};
162
163template <typename SrcChannelV, typename DstChannelV>
164struct channel_converter_unsigned_integral<SrcChannelV,DstChannelV,false>
165 : public channel_converter_unsigned_integral_impl<SrcChannelV,DstChannelV,false,
166 !(unsigned_integral_max_value<SrcChannelV>::value % unsigned_integral_max_value<DstChannelV>::value) > {};
167
168
169//////////////////////////////////////
170//// channel_converter_unsigned_integral_impl
171//////////////////////////////////////
172
173// Both source and destination are unsigned integral channels,
174// the src max value is less than the dst max value,
175// and the dst max value is divisible by the src max value
176template <typename SrcChannelV, typename DstChannelV>
177struct channel_converter_unsigned_integral_impl<SrcChannelV,DstChannelV,true,true> {
178 DstChannelV operator()(SrcChannelV src) const {
179 typedef typename unsigned_integral_max_value<DstChannelV>::value_type integer_t;
180 static const integer_t mul = unsigned_integral_max_value<DstChannelV>::value / unsigned_integral_max_value<SrcChannelV>::value;
181 return DstChannelV(src * mul);
182 }
183};
184
185// Both source and destination are unsigned integral channels,
186// the dst max value is less than (or equal to) the src max value,
187// and the src max value is divisible by the dst max value
188template <typename SrcChannelV, typename DstChannelV>
189struct channel_converter_unsigned_integral_impl<SrcChannelV,DstChannelV,false,true> {
190 DstChannelV operator()(SrcChannelV src) const {
191 typedef typename unsigned_integral_max_value<SrcChannelV>::value_type integer_t;
192 static const integer_t div = unsigned_integral_max_value<SrcChannelV>::value / unsigned_integral_max_value<DstChannelV>::value;
193 static const integer_t div2 = div/2;
194 return DstChannelV((src + div2) / div);
195 }
196};
197
198// Prevent overflow for the largest integral type
199template <typename DstChannelV>
200struct channel_converter_unsigned_integral_impl<uintmax_t,DstChannelV,false,true> {
201 DstChannelV operator()(uintmax_t src) const {
202 static const uintmax_t div = unsigned_integral_max_value<bits32>::value / unsigned_integral_max_value<DstChannelV>::value;
203 static const uintmax_t div2 = div/2;
204 if (src > unsigned_integral_max_value<uintmax_t>::value - div2)
205 return unsigned_integral_max_value<DstChannelV>::value;
206 return DstChannelV((src + div2) / div);
207 }
208};
209
210// Both source and destination are unsigned integral channels,
211// and the dst max value is not divisible by the src max value
212// See if you can represent the expression (src * dst_max) / src_max in integral form
213template <typename SrcChannelV, typename DstChannelV, bool SrcLessThanDst>
214struct channel_converter_unsigned_integral_impl<SrcChannelV,DstChannelV,SrcLessThanDst,false>
215 : public channel_converter_unsigned_integral_nondivisible<SrcChannelV,DstChannelV,SrcLessThanDst,
216 mpl::greater<
217 mpl::plus<unsigned_integral_num_bits<SrcChannelV>,unsigned_integral_num_bits<DstChannelV> >,
218 unsigned_integral_num_bits<uintmax_t>
219 >::value> {};
220
221
222// Both source and destination are unsigned integral channels,
223// the src max value is less than the dst max value,
224// and the dst max value is not divisible by the src max value
225// The expression (src * dst_max) / src_max fits in an integer
226template <typename SrcChannelV, typename DstChannelV>
227struct channel_converter_unsigned_integral_nondivisible<SrcChannelV,DstChannelV,true,false> {
228 DstChannelV operator()(SrcChannelV src) const {
229 typedef typename detail::min_fast_uint<unsigned_integral_num_bits<SrcChannelV>::value+unsigned_integral_num_bits<DstChannelV>::value>::type integer_t;
230 return DstChannelV(integer_t(src * unsigned_integral_max_value<DstChannelV>::value) / unsigned_integral_max_value<SrcChannelV>::value);
231 }
232};
233
234// Both source and destination are unsigned integral channels,
235// the src max value is less than the dst max value,
236// and the dst max value is not divisible by the src max value
237// The expression (src * dst_max) / src_max cannot fit in an integer (overflows). Use a double
238template <typename SrcChannelV, typename DstChannelV>
239struct channel_converter_unsigned_integral_nondivisible<SrcChannelV,DstChannelV,true,true> {
240 DstChannelV operator()(SrcChannelV src) const {
241 static const double mul = unsigned_integral_max_value<DstChannelV>::value / double(unsigned_integral_max_value<SrcChannelV>::value);
242 return DstChannelV(src * mul);
243 }
244};
245
246// Both source and destination are unsigned integral channels,
247// the dst max value is less than (or equal to) the src max value,
248// and the src max value is not divisible by the dst max value
249template <typename SrcChannelV, typename DstChannelV, bool CannotFit>
250struct channel_converter_unsigned_integral_nondivisible<SrcChannelV,DstChannelV,false,CannotFit> {
251 DstChannelV operator()(SrcChannelV src) const {
252
253 typedef typename detail::unsigned_integral_max_value< SrcChannelV >::value_type src_integer_t;
254 typedef typename detail::unsigned_integral_max_value< DstChannelV >::value_type dst_integer_t;
255
256 static const double div = unsigned_integral_max_value<SrcChannelV>::value
257 / static_cast< double >( unsigned_integral_max_value<DstChannelV>::value );
258
259 static const src_integer_t div2 = static_cast< src_integer_t >( div / 2.0 );
260
261 return DstChannelV( static_cast< dst_integer_t >(( static_cast< double >( src + div2 ) / div )));
262 }
263};
264
265} // namespace detail
266
267/////////////////////////////////////////////////////
268/// bits32f conversion
269/////////////////////////////////////////////////////
270
271template <typename DstChannelV> struct channel_converter_unsigned<bits32f,DstChannelV> : public std::unary_function<bits32f,DstChannelV> {
272 DstChannelV operator()(bits32f x) const
273 {
274 typedef typename detail::unsigned_integral_max_value< DstChannelV >::value_type dst_integer_t;
275 return DstChannelV( static_cast< dst_integer_t >(x*channel_traits<DstChannelV>::max_value()+0.5f ));
276 }
277};
278
279template <typename SrcChannelV> struct channel_converter_unsigned<SrcChannelV,bits32f> : public std::unary_function<SrcChannelV,bits32f> {
280 bits32f operator()(SrcChannelV x) const { return bits32f(x/float(channel_traits<SrcChannelV>::max_value())); }
281};
282
283template <> struct channel_converter_unsigned<bits32f,bits32f> : public std::unary_function<bits32f,bits32f> {
284 bits32f operator()(bits32f x) const { return x; }
285};
286
287
288/// \brief 32 bit <-> float channel conversion
289template <> struct channel_converter_unsigned<bits32,bits32f> : public std::unary_function<bits32,bits32f> {
290 bits32f operator()(bits32 x) const {
291 // unfortunately without an explicit check it is possible to get a round-off error. We must ensure that max_value of bits32 matches max_value of bits32f
292 if (x>=channel_traits<bits32>::max_value()) return channel_traits<bits32f>::max_value();
293 return float(x) / float(channel_traits<bits32>::max_value());
294 }
295};
296/// \brief 32 bit <-> float channel conversion
297template <> struct channel_converter_unsigned<bits32f,bits32> : public std::unary_function<bits32f,bits32> {
298 bits32 operator()(bits32f x) const {
299 // unfortunately without an explicit check it is possible to get a round-off error. We must ensure that max_value of bits32 matches max_value of bits32f
300 if (x>=channel_traits<bits32f>::max_value()) return channel_traits<bits32>::max_value();
301 return bits32(x * channel_traits<bits32>::max_value() + 0.5f);
302 }
303};
304
305/// @}
306
307namespace detail {
308// Converting from signed to unsigned integral channel.
309// It is both a unary function, and a metafunction (thus requires the 'type' nested typedef, which equals result_type)
310template <typename ChannelValue> // Model ChannelValueConcept
311struct channel_convert_to_unsigned : public detail::identity<ChannelValue> {
312 typedef ChannelValue type;
313};
314
315template <> struct channel_convert_to_unsigned<bits8s> : public std::unary_function<bits8s,bits8> {
316 typedef bits8 type;
317 type operator()(bits8s val) const { return val+128; }
318};
319
320template <> struct channel_convert_to_unsigned<bits16s> : public std::unary_function<bits16s,bits16> {
321 typedef bits16 type;
322 type operator()(bits16s val) const { return val+32768; }
323};
324
325template <> struct channel_convert_to_unsigned<bits32s> : public std::unary_function<bits32s,bits32> {
326 typedef bits32 type;
327 type operator()(bits32s x) const { return static_cast<bits32>(x+(1<<31)); }
328};
329
330
331// Converting from unsigned to signed integral channel
332// It is both a unary function, and a metafunction (thus requires the 'type' nested typedef, which equals result_type)
333template <typename ChannelValue> // Model ChannelValueConcept
334struct channel_convert_from_unsigned : public detail::identity<ChannelValue> {
335 typedef ChannelValue type;
336};
337
338template <> struct channel_convert_from_unsigned<bits8s> : public std::unary_function<bits8,bits8s> {
339 typedef bits8s type;
340 type operator()(bits8 val) const { return val-128; }
341};
342
343template <> struct channel_convert_from_unsigned<bits16s> : public std::unary_function<bits16,bits16s> {
344 typedef bits16s type;
345 type operator()(bits16 val) const { return val-32768; }
346};
347
348template <> struct channel_convert_from_unsigned<bits32s> : public std::unary_function<bits32,bits32s> {
349 typedef bits32s type;
350 type operator()(bits32 x) const { return static_cast<bits32s>(x-(1<<31)); }
351};
352
353} // namespace detail
354
355/// \ingroup ChannelConvertAlgorithm
356/// \brief A unary function object converting between channel types
357template <typename SrcChannelV, typename DstChannelV> // Model ChannelValueConcept
358struct channel_converter : public std::unary_function<SrcChannelV,DstChannelV> {
359 DstChannelV operator()(const SrcChannelV& src) const {
360 typedef detail::channel_convert_to_unsigned<SrcChannelV> to_unsigned;
361 typedef detail::channel_convert_from_unsigned<DstChannelV> from_unsigned;
362 typedef channel_converter_unsigned<typename to_unsigned::result_type, typename from_unsigned::argument_type> converter_unsigned;
363 return from_unsigned()(converter_unsigned()(to_unsigned()(src)));
364 }
365};
366
367/// \ingroup ChannelConvertAlgorithm
368/// \brief Converting from one channel type to another.
369template <typename DstChannel, typename SrcChannel> // Model ChannelConcept (could be channel references)
370inline typename channel_traits<DstChannel>::value_type channel_convert(const SrcChannel& src) {
371 return channel_converter<typename channel_traits<SrcChannel>::value_type,
372 typename channel_traits<DstChannel>::value_type>()(src);
373}
374
375/// \ingroup ChannelConvertAlgorithm
376/// \brief Same as channel_converter, except it takes the destination channel by reference, which allows
377/// us to move the templates from the class level to the method level. This is important when invoking it
378/// on heterogeneous pixels.
379struct default_channel_converter {
380 template <typename Ch1, typename Ch2>
381 void operator()(const Ch1& src, Ch2& dst) const {
382 dst=channel_convert<Ch2>(src);
383 }
384};
385
386namespace detail {
387 // fast integer division by 255
388 inline uint32_t div255(uint32_t in) { uint32_t tmp=in+128; return (tmp + (tmp>>8))>>8; }
389
390 // fast integer divison by 32768
391 inline uint32_t div32768(uint32_t in) { return (in+16384)>>15; }
392}
393
394/**
395\defgroup ChannelMultiplyAlgorithm channel_multiply
396\ingroup ChannelAlgorithm
397\brief Multiplying unsigned channel values of the same type. Performs scaled multiplication result = a * b / max_value
398
399Example:
400\code
401bits8 x=128;
402bits8 y=128;
403bits8 mul = channel_multiply(x,y);
404assert(mul == 64); // 64 = 128 * 128 / 255
405\endcode
406*/
407/// @{
408
409/// \brief This is the default implementation. Performance specializatons are provided
410template <typename ChannelValue>
411struct channel_multiplier_unsigned : public std::binary_function<ChannelValue,ChannelValue,ChannelValue> {
412 ChannelValue operator()(ChannelValue a, ChannelValue b) const {
413 return ChannelValue(a / double(channel_traits<ChannelValue>::max_value()) * b);
414 }
415};
416
417/// \brief Specialization of channel_multiply for 8-bit unsigned channels
418template<> struct channel_multiplier_unsigned<bits8> : public std::binary_function<bits8,bits8,bits8> {
419 bits8 operator()(bits8 a, bits8 b) const { return bits8(detail::div255(in: uint32_t(a) * uint32_t(b))); }
420};
421
422/// \brief Specialization of channel_multiply for 16-bit unsigned channels
423template<> struct channel_multiplier_unsigned<bits16> : public std::binary_function<bits16,bits16,bits16> {
424 bits16 operator()(bits16 a, bits16 b) const { return bits16((uint32_t(a) * uint32_t(b))/65535); }
425};
426
427/// \brief Specialization of channel_multiply for float 0..1 channels
428template<> struct channel_multiplier_unsigned<bits32f> : public std::binary_function<bits32f,bits32f,bits32f> {
429 bits32f operator()(bits32f a, bits32f b) const { return a*b; }
430};
431
432/// \brief A function object to multiply two channels. result = a * b / max_value
433template <typename ChannelValue>
434struct channel_multiplier : public std::binary_function<ChannelValue, ChannelValue, ChannelValue> {
435 ChannelValue operator()(ChannelValue a, ChannelValue b) const {
436 typedef detail::channel_convert_to_unsigned<ChannelValue> to_unsigned;
437 typedef detail::channel_convert_from_unsigned<ChannelValue> from_unsigned;
438 typedef channel_multiplier_unsigned<typename to_unsigned::result_type> multiplier_unsigned;
439 return from_unsigned()(multiplier_unsigned()(to_unsigned()(a), to_unsigned()(b)));
440 }
441};
442
443/// \brief A function multiplying two channels. result = a * b / max_value
444template <typename Channel> // Models ChannelConcept (could be a channel reference)
445inline typename channel_traits<Channel>::value_type channel_multiply(Channel a, Channel b) {
446 return channel_multiplier<typename channel_traits<Channel>::value_type>()(a,b);
447}
448/// @}
449
450/**
451\defgroup ChannelInvertAlgorithm channel_invert
452\ingroup ChannelAlgorithm
453\brief Returns the inverse of a channel. result = max_value - x + min_value
454
455Example:
456\code
457// bits8 == uint8_t == unsigned char
458bits8 x=255;
459bits8 inv = channel_invert(x);
460assert(inv == 0);
461\endcode
462*/
463
464/// \brief Default implementation. Provide overloads for performance
465/// \ingroup ChannelInvertAlgorithm channel_invert
466template <typename Channel> // Models ChannelConcept (could be a channel reference)
467inline typename channel_traits<Channel>::value_type channel_invert(Channel x) {
468 return channel_traits<Channel>::max_value()-x + channel_traits<Channel>::min_value();
469}
470
471//#ifdef _MSC_VER
472//#pragma warning(pop)
473//#endif
474
475} } // namespace boost::gil
476
477#endif
478

source code of boost/boost/gil/channel_algorithm.hpp