channel.hppGo to the documentation of this file.00001 /* 00002 Copyright 2005-2007 Adobe Systems Incorporated 00003 00004 Use, modification and distribution are subject to the Boost Software License, 00005 Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at 00006 http://www.boost.org/LICENSE_1_0.txt). 00007 00008 See http://stlab.adobe.com/gil for most recent version including documentation. 00009 */ 00010 00011 /*************************************************************************************************/ 00012 00013 #ifndef GIL_CHANNEL_HPP 00014 #define GIL_CHANNEL_HPP 00015 00026 00027 #include <limits> 00028 #include <cassert> 00029 #include <boost/cstdint.hpp> 00030 #include "gil_config.hpp" 00031 #include "utilities.hpp" 00032 00033 namespace boost { namespace gil { 00034 00035 00050 00051 namespace detail { 00052 template <typename T, bool is_class> struct channel_traits_impl; 00053 00054 // channel traits for custom class 00055 template <typename T> 00056 struct channel_traits_impl<T, true> { 00057 typedef typename T::value_type value_type; 00058 typedef typename T::reference reference; 00059 typedef typename T::pointer pointer; 00060 typedef typename T::const_reference const_reference; 00061 typedef typename T::const_pointer const_pointer; 00062 BOOST_STATIC_CONSTANT(bool, is_mutable=T::is_mutable); 00063 static value_type min_value() { return T::min_value(); } 00064 static value_type max_value() { return T::max_value(); } 00065 }; 00066 00067 // channel traits implementation for built-in integral or floating point channel type 00068 template <typename T> 00069 struct channel_traits_impl<T, false> { 00070 typedef T value_type; 00071 typedef T& reference; 00072 typedef T* pointer; 00073 typedef const T& const_reference; 00074 typedef T const* const_pointer; 00075 BOOST_STATIC_CONSTANT(bool, is_mutable=true); 00076 static value_type min_value() { return (std::numeric_limits<T>::min)(); } 00077 static value_type max_value() { return (std::numeric_limits<T>::max)(); } 00078 }; 00079 00080 // channel traits implementation for constant built-in scalar or floating point type 00081 template <typename T> 00082 struct channel_traits_impl<const T, false> : public channel_traits_impl<T, false> { 00083 typedef const T& reference; 00084 typedef const T* pointer; 00085 BOOST_STATIC_CONSTANT(bool, is_mutable=false); 00086 }; 00087 } 00088 00107 template <typename T> 00108 struct channel_traits : public detail::channel_traits_impl<T, is_class<T>::value> {}; 00109 00110 // Channel traits for C++ reference type - remove the reference 00111 template <typename T> struct channel_traits< T&> : public channel_traits<T> {}; 00112 00113 // Channel traits for constant C++ reference type 00114 template <typename T> struct channel_traits<const T&> : public channel_traits<T> { 00115 typedef typename channel_traits<T>::const_reference reference; 00116 typedef typename channel_traits<T>::const_pointer pointer; 00117 BOOST_STATIC_CONSTANT(bool, is_mutable=false); 00118 }; 00119 00125 00146 00147 00148 template <typename BaseChannelValue, // base channel (models ChannelValueConcept) 00149 typename MinVal, typename MaxVal> // classes with a static apply() function returning the minimum/maximum channel values 00150 struct scoped_channel_value { 00151 typedef scoped_channel_value value_type; 00152 typedef value_type& reference; 00153 typedef value_type* pointer; 00154 typedef const value_type& const_reference; 00155 typedef const value_type* const_pointer; 00156 BOOST_STATIC_CONSTANT(bool, is_mutable=channel_traits<BaseChannelValue>::is_mutable); 00157 00158 static value_type min_value() { return MinVal::apply(); } 00159 static value_type max_value() { return MaxVal::apply(); } 00160 00161 scoped_channel_value() {} 00162 scoped_channel_value(const scoped_channel_value& c) : _value(c._value) {} 00163 scoped_channel_value(BaseChannelValue val) : _value(val) {} 00164 00165 scoped_channel_value& operator++() { ++_value; return *this; } 00166 scoped_channel_value& operator--() { --_value; return *this; } 00167 00168 scoped_channel_value operator++(int) { scoped_channel_value tmp=*this; this->operator++(); return tmp; } 00169 scoped_channel_value operator--(int) { scoped_channel_value tmp=*this; this->operator--(); return tmp; } 00170 00171 template <typename Scalar2> scoped_channel_value& operator+=(Scalar2 v) { _value+=v; return *this; } 00172 template <typename Scalar2> scoped_channel_value& operator-=(Scalar2 v) { _value-=v; return *this; } 00173 template <typename Scalar2> scoped_channel_value& operator*=(Scalar2 v) { _value*=v; return *this; } 00174 template <typename Scalar2> scoped_channel_value& operator/=(Scalar2 v) { _value/=v; return *this; } 00175 00176 scoped_channel_value& operator=(BaseChannelValue v) { _value=v; return *this; } 00177 operator BaseChannelValue() const { return _value; } 00178 private: 00179 BaseChannelValue _value; 00180 }; 00181 00182 struct float_zero { static float apply() { return 0.0f; } }; 00183 struct float_one { static float apply() { return 1.0f; } }; 00184 00185 00191 00192 // It is necessary for packed channels to have their own value type. They cannot simply use an integral large enough to store the data. Here is why: 00193 // - Any operation that requires returning the result by value will otherwise return the built-in integral type, which will have incorrect range 00194 // That means that after getting the value of the channel we cannot properly do channel_convert, channel_invert, etc. 00195 // - Two channels are declared compatible if they have the same value type. That means that a packed channel is incorrectly declared compatible with an integral type 00196 namespace detail { 00197 // returns the smallest fast unsigned integral type that has at least NumBits bits 00198 template <int NumBits> 00199 struct min_fast_uint : public mpl::if_c< (NumBits<=8), 00200 uint_least8_t, 00201 typename mpl::if_c< (NumBits<=16), 00202 uint_least16_t, 00203 typename mpl::if_c< (NumBits<=32), 00204 uint_least32_t, 00205 uintmax_t 00206 >::type 00207 >::type 00208 > {}; 00209 } 00210 00227 00228 00229 template <int NumBits> 00230 class packed_channel_value { 00231 static const std::size_t num_values = 1<<NumBits; 00232 public: 00233 typedef typename detail::min_fast_uint<NumBits>::type integer_t; 00234 00235 typedef packed_channel_value value_type; 00236 typedef value_type& reference; 00237 typedef const value_type& const_reference; 00238 typedef value_type* pointer; 00239 typedef const value_type* const_pointer; 00240 00241 static value_type min_value() { return value_type(0); } 00242 static value_type max_value() { return value_type(num_values-1); } 00243 BOOST_STATIC_CONSTANT(bool, is_mutable=true); 00244 00245 packed_channel_value() {} 00246 packed_channel_value(integer_t v) : _value(v % num_values) {} 00247 packed_channel_value(const packed_channel_value& v) : _value(v._value) {} 00248 template <typename Scalar> packed_channel_value(Scalar v) : _value(integer_t(v) % num_values) {} // suppress GCC implicit conversion warnings in channel regression file 00249 00250 operator integer_t() const { return _value; } 00251 private: 00252 integer_t _value; 00253 }; 00254 00255 namespace detail { 00256 00257 template <std::size_t K> 00258 struct static_copy_bytes { 00259 void operator()(const unsigned char* from, unsigned char* to) const { 00260 *to = *from; 00261 static_copy_bytes<K-1>()(++from,++to); 00262 } 00263 }; 00264 00265 template <> 00266 struct static_copy_bytes<0> { 00267 void operator()(const unsigned char* , unsigned char*) const {} 00268 }; 00269 00270 template <typename Derived, typename BitField, int NumBits, bool Mutable> 00271 class packed_channel_reference_base { 00272 protected: 00273 typedef typename mpl::if_c<Mutable,void*,const void*>::type data_ptr_t; 00274 public: 00275 data_ptr_t _data_ptr; // void* pointer to the first byte of the bit range 00276 00277 typedef packed_channel_value<NumBits> value_type; 00278 typedef const Derived reference; 00279 typedef value_type* pointer; 00280 typedef const value_type* const_pointer; 00281 BOOST_STATIC_CONSTANT(int, num_bits=NumBits); 00282 BOOST_STATIC_CONSTANT(bool, is_mutable=Mutable); 00283 00284 static value_type min_value() { return channel_traits<value_type>::min_value(); } 00285 static value_type max_value() { return channel_traits<value_type>::max_value(); } 00286 00287 typedef BitField bitfield_t; 00288 typedef typename value_type::integer_t integer_t; 00289 00290 packed_channel_reference_base(data_ptr_t data_ptr) : _data_ptr(data_ptr) {} 00291 packed_channel_reference_base(const packed_channel_reference_base& ref) : _data_ptr(ref._data_ptr) {} 00292 const Derived& operator=(integer_t v) const { set(v); return derived(); } 00293 00294 const Derived& operator++() const { set(get()+1); return derived(); } 00295 const Derived& operator--() const { set(get()-1); return derived(); } 00296 00297 Derived operator++(int) const { Derived tmp=derived(); this->operator++(); return tmp; } 00298 Derived operator--(int) const { Derived tmp=derived(); this->operator--(); return tmp; } 00299 00300 template <typename Scalar2> const Derived& operator+=(Scalar2 v) const { set(get()+v); return derived(); } 00301 template <typename Scalar2> const Derived& operator-=(Scalar2 v) const { set(get()-v); return derived(); } 00302 template <typename Scalar2> const Derived& operator*=(Scalar2 v) const { set(get()*v); return derived(); } 00303 template <typename Scalar2> const Derived& operator/=(Scalar2 v) const { set(get()/v); return derived(); } 00304 00305 operator integer_t() const { return get(); } 00306 data_ptr_t operator &() const {return _data_ptr;} 00307 protected: 00308 static const integer_t max_val = (1<<NumBits) - 1; 00309 00310 #ifdef GIL_NONWORD_POINTER_ALIGNMENT_SUPPORTED 00311 const bitfield_t& get_data() const { return *static_cast<const bitfield_t*>(_data_ptr); } 00312 void set_data(const bitfield_t& val) const { *static_cast< bitfield_t*>(_data_ptr) = val; } 00313 #else 00314 bitfield_t get_data() const { 00315 bitfield_t ret; 00316 static_copy_bytes<sizeof(bitfield_t) >()(gil_reinterpret_cast_c<const unsigned char*>(_data_ptr),gil_reinterpret_cast<unsigned char*>(&ret)); 00317 return ret; 00318 } 00319 void set_data(const bitfield_t& val) const { 00320 static_copy_bytes<sizeof(bitfield_t) >()(gil_reinterpret_cast_c<const unsigned char*>(&val),gil_reinterpret_cast<unsigned char*>(_data_ptr)); 00321 } 00322 #endif 00323 00324 private: 00325 void set(integer_t value) const { // can this be done faster?? 00326 const integer_t num_values = max_val+1; 00327 this->derived().set_unsafe(((value % num_values) + num_values) % num_values); 00328 } 00329 integer_t get() const { return derived().get(); } 00330 const Derived& derived() const { return static_cast<const Derived&>(*this); } 00331 }; 00332 } // namespace detail 00333 00350 template <typename BitField, // A type that holds the bits of the pixel from which the channel is referenced. Typically an integral type, like boost::uint16_t 00351 int FirstBit, int NumBits,// Defines the sequence of bits in the data value that contain the channel 00352 bool Mutable> // true if the reference is mutable 00353 class packed_channel_reference; 00354 00355 template <typename BitField, // A type that holds the bits of the pixel from which the channel is referenced. Typically an integral type, like boost::uint16_t 00356 int NumBits, // Defines the sequence of bits in the data value that contain the channel 00357 bool Mutable> // true if the reference is mutable 00358 class packed_dynamic_channel_reference; 00359 00362 template <typename BitField, int FirstBit, int NumBits> 00363 class packed_channel_reference<BitField,FirstBit,NumBits,false> 00364 : public detail::packed_channel_reference_base<packed_channel_reference<BitField,FirstBit,NumBits,false>,BitField,NumBits,false> { 00365 typedef detail::packed_channel_reference_base<packed_channel_reference<BitField,FirstBit,NumBits,false>,BitField,NumBits,false> parent_t; 00366 friend class packed_channel_reference<BitField,FirstBit,NumBits,true>; 00367 00368 static const BitField channel_mask = parent_t::max_val<<FirstBit; 00369 void operator=(const packed_channel_reference&); 00370 public: 00371 typedef const packed_channel_reference<BitField,FirstBit,NumBits,false> const_reference; 00372 typedef const packed_channel_reference<BitField,FirstBit,NumBits,true> mutable_reference; 00373 typedef typename parent_t::integer_t integer_t; 00374 00375 explicit packed_channel_reference(const void* data_ptr) : parent_t(data_ptr) {} 00376 packed_channel_reference(const packed_channel_reference& ref) : parent_t(ref._data_ptr) {} 00377 packed_channel_reference(const mutable_reference& ref) : parent_t(ref._data_ptr) {} 00378 00379 unsigned first_bit() const { return FirstBit; } 00380 00381 integer_t get() const { return integer_t((this->get_data()&channel_mask) >> FirstBit); } 00382 }; 00383 00386 template <typename BitField, int FirstBit, int NumBits> 00387 class packed_channel_reference<BitField,FirstBit,NumBits,true> 00388 : public detail::packed_channel_reference_base<packed_channel_reference<BitField,FirstBit,NumBits,true>,BitField,NumBits,true> { 00389 typedef detail::packed_channel_reference_base<packed_channel_reference<BitField,FirstBit,NumBits,true>,BitField,NumBits,true> parent_t; 00390 friend class packed_channel_reference<BitField,FirstBit,NumBits,false>; 00391 00392 static const BitField channel_mask = parent_t::max_val<<FirstBit; 00393 public: 00394 typedef const packed_channel_reference<BitField,FirstBit,NumBits,false> const_reference; 00395 typedef const packed_channel_reference<BitField,FirstBit,NumBits,true> mutable_reference; 00396 typedef typename parent_t::integer_t integer_t; 00397 00398 explicit packed_channel_reference(void* data_ptr) : parent_t(data_ptr) {} 00399 packed_channel_reference(const packed_channel_reference& ref) : parent_t(ref._data_ptr) {} 00400 00401 const packed_channel_reference& operator=(integer_t value) const { assert(value<=parent_t::max_val); set_unsafe(value); return *this; } 00402 const packed_channel_reference& operator=(const mutable_reference& ref) const { set_from_reference(ref.get_data()); return *this; } 00403 const packed_channel_reference& operator=(const const_reference& ref) const { set_from_reference(ref.get_data()); return *this; } 00404 00405 template <bool Mutable1> 00406 const packed_channel_reference& operator=(const packed_dynamic_channel_reference<BitField,NumBits,Mutable1>& ref) const { set_unsafe(ref.get()); return *this; } 00407 00408 unsigned first_bit() const { return FirstBit; } 00409 00410 integer_t get() const { return integer_t((this->get_data()&channel_mask) >> FirstBit); } 00411 void set_unsafe(integer_t value) const { this->set_data((this->get_data() & ~channel_mask) | (value<<FirstBit)); } 00412 private: 00413 void set_from_reference(const BitField& other_bits) const { this->set_data((this->get_data() & ~channel_mask) | (other_bits & channel_mask)); } 00414 }; 00415 00416 } } // namespace boost::gil 00417 00418 namespace std { 00419 // We are forced to define swap inside std namespace because on some platforms (Visual Studio 8) STL calls swap qualified. 00420 // swap with 'left bias': 00421 // - swap between proxy and anything 00422 // - swap between value type and proxy 00423 // - swap between proxy and proxy 00424 00427 template <typename BF, int FB, int NB, bool M, typename R> inline 00428 void swap(const boost::gil::packed_channel_reference<BF,FB,NB,M> x, R& y) { 00429 boost::gil::swap_proxy<typename boost::gil::packed_channel_reference<BF,FB,NB,M>::value_type>(x,y); 00430 } 00431 00432 00435 template <typename BF, int FB, int NB, bool M> inline 00436 void swap(typename boost::gil::packed_channel_reference<BF,FB,NB,M>::value_type& x, const boost::gil::packed_channel_reference<BF,FB,NB,M> y) { 00437 boost::gil::swap_proxy<typename boost::gil::packed_channel_reference<BF,FB,NB,M>::value_type>(x,y); 00438 } 00439 00440 00443 template <typename BF, int FB, int NB, bool M> inline 00444 void swap(const boost::gil::packed_channel_reference<BF,FB,NB,M> x, const boost::gil::packed_channel_reference<BF,FB,NB,M> y) { 00445 boost::gil::swap_proxy<typename boost::gil::packed_channel_reference<BF,FB,NB,M>::value_type>(x,y); 00446 } 00447 } // namespace std 00448 00449 namespace boost { namespace gil { 00450 00468 00469 00470 00471 template <typename BitField, int NumBits> 00472 class packed_dynamic_channel_reference<BitField,NumBits,false> 00473 : public detail::packed_channel_reference_base<packed_dynamic_channel_reference<BitField,NumBits,false>,BitField,NumBits,false> { 00474 typedef detail::packed_channel_reference_base<packed_dynamic_channel_reference<BitField,NumBits,false>,BitField,NumBits,false> parent_t; 00475 friend class packed_dynamic_channel_reference<BitField,NumBits,true>; 00476 00477 unsigned _first_bit; // 0..7 00478 00479 void operator=(const packed_dynamic_channel_reference&); 00480 public: 00481 typedef const packed_dynamic_channel_reference<BitField,NumBits,false> const_reference; 00482 typedef const packed_dynamic_channel_reference<BitField,NumBits,true> mutable_reference; 00483 typedef typename parent_t::integer_t integer_t; 00484 00485 packed_dynamic_channel_reference(const void* data_ptr, unsigned first_bit) : parent_t(data_ptr), _first_bit(first_bit) {} 00486 packed_dynamic_channel_reference(const const_reference& ref) : parent_t(ref._data_ptr), _first_bit(ref._first_bit) {} 00487 packed_dynamic_channel_reference(const mutable_reference& ref) : parent_t(ref._data_ptr), _first_bit(ref._first_bit) {} 00488 00489 unsigned first_bit() const { return _first_bit; } 00490 00491 integer_t get() const { 00492 const BitField channel_mask = parent_t::max_val<<_first_bit; 00493 return (this->get_data()&channel_mask) >> _first_bit; 00494 } 00495 }; 00496 00500 template <typename BitField, int NumBits> 00501 class packed_dynamic_channel_reference<BitField,NumBits,true> 00502 : public detail::packed_channel_reference_base<packed_dynamic_channel_reference<BitField,NumBits,true>,BitField,NumBits,true> { 00503 typedef detail::packed_channel_reference_base<packed_dynamic_channel_reference<BitField,NumBits,true>,BitField,NumBits,true> parent_t; 00504 friend class packed_dynamic_channel_reference<BitField,NumBits,false>; 00505 00506 unsigned _first_bit; 00507 00508 public: 00509 typedef const packed_dynamic_channel_reference<BitField,NumBits,false> const_reference; 00510 typedef const packed_dynamic_channel_reference<BitField,NumBits,true> mutable_reference; 00511 typedef typename parent_t::integer_t integer_t; 00512 00513 packed_dynamic_channel_reference(void* data_ptr, unsigned first_bit) : parent_t(data_ptr), _first_bit(first_bit) {} 00514 packed_dynamic_channel_reference(const packed_dynamic_channel_reference& ref) : parent_t(ref._data_ptr), _first_bit(ref._first_bit) {} 00515 00516 const packed_dynamic_channel_reference& operator=(integer_t value) const { assert(value<=parent_t::max_val); set_unsafe(value); return *this; } 00517 const packed_dynamic_channel_reference& operator=(const mutable_reference& ref) const { set_unsafe(ref.get()); return *this; } 00518 const packed_dynamic_channel_reference& operator=(const const_reference& ref) const { set_unsafe(ref.get()); return *this; } 00519 00520 template <typename BitField1, int FirstBit1, bool Mutable1> 00521 const packed_dynamic_channel_reference& operator=(const packed_channel_reference<BitField1, FirstBit1, NumBits, Mutable1>& ref) const 00522 { set_unsafe(ref.get()); return *this; } 00523 00524 unsigned first_bit() const { return _first_bit; } 00525 00526 integer_t get() const { 00527 const BitField channel_mask = parent_t::max_val<<_first_bit; 00528 return (this->get_data()&channel_mask) >> _first_bit; 00529 } 00530 void set_unsafe(integer_t value) const { 00531 const BitField channel_mask = parent_t::max_val<<_first_bit; 00532 this->set_data((this->get_data() & ~channel_mask) | value<<_first_bit); 00533 } 00534 }; 00535 } } // namespace boost::gil 00536 00537 namespace std { 00538 // We are forced to define swap inside std namespace because on some platforms (Visual Studio 8) STL calls swap qualified. 00539 // swap with 'left bias': 00540 // - swap between proxy and anything 00541 // - swap between value type and proxy 00542 // - swap between proxy and proxy 00543 00544 00547 template <typename BF, int NB, bool M, typename R> inline 00548 void swap(const boost::gil::packed_dynamic_channel_reference<BF,NB,M> x, R& y) { 00549 boost::gil::swap_proxy<typename boost::gil::packed_dynamic_channel_reference<BF,NB,M>::value_type>(x,y); 00550 } 00551 00552 00555 template <typename BF, int NB, bool M> inline 00556 void swap(typename boost::gil::packed_dynamic_channel_reference<BF,NB,M>::value_type& x, const boost::gil::packed_dynamic_channel_reference<BF,NB,M> y) { 00557 boost::gil::swap_proxy<typename boost::gil::packed_dynamic_channel_reference<BF,NB,M>::value_type>(x,y); 00558 } 00559 00560 00563 template <typename BF, int NB, bool M> inline 00564 void swap(const boost::gil::packed_dynamic_channel_reference<BF,NB,M> x, const boost::gil::packed_dynamic_channel_reference<BF,NB,M> y) { 00565 boost::gil::swap_proxy<typename boost::gil::packed_dynamic_channel_reference<BF,NB,M>::value_type>(x,y); 00566 } 00567 } // namespace std 00568 00569 namespace boost { namespace gil { 00575 00579 00581 typedef uint8_t bits8; 00582 00586 00588 typedef uint16_t bits16; 00589 00593 00595 typedef uint32_t bits32; 00596 00600 00602 typedef int8_t bits8s; 00603 00607 00609 typedef int16_t bits16s; 00610 00614 00616 typedef int32_t bits32s; 00617 00621 00623 typedef scoped_channel_value<float,float_zero,float_one> bits32f; 00624 00625 } } // namespace boost::gil 00626 00627 namespace boost { 00628 00629 template <int NumBits> 00630 struct is_integral<gil::packed_channel_value<NumBits> > : public mpl::true_ {}; 00631 00632 template <typename BitField, int FirstBit, int NumBits, bool IsMutable> 00633 struct is_integral<gil::packed_channel_reference<BitField,FirstBit,NumBits,IsMutable> > : public mpl::true_ {}; 00634 00635 template <typename BitField, int NumBits, bool IsMutable> 00636 struct is_integral<gil::packed_dynamic_channel_reference<BitField,NumBits,IsMutable> > : public mpl::true_ {}; 00637 00638 template <typename BaseChannelValue, typename MinVal, typename MaxVal> 00639 struct is_integral<gil::scoped_channel_value<BaseChannelValue,MinVal,MaxVal> > : public is_integral<BaseChannelValue> {}; 00640 00641 } 00642 00643 #endif Generated on Sat May 2 13:50:13 2009 for Generic Image Library by 1.5.6 |