text: // __BEGIN_LICENSE__
  //  Copyright (c) 2006-2013, United States Government as represented by the
  //  Administrator of the National Aeronautics and Space Administration. All
  //  rights reserved.
  //
  //  The NASA Vision Workbench is licensed under the Apache License,
  //  Version 2.0 (the "License"); you may not use this file except in
  //  compliance with the License. You may obtain a copy of the License at
  //  http://www.apache.org/licenses/LICENSE-2.0
  //
  //  Unless required by applicable law or agreed to in writing, software
  //  distributed under the License is distributed on an "AS IS" BASIS,
  //  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  //  See the License for the specific language governing permissions and
  //  limitations under the License.
  // __END_LICENSE__
  
  
  /// \file PixelTypeInfo.h
  ///
  /// Base classes, support classes, and other infrastructure
  /// to support the pixel types.
  ///
  #ifndef __VW_IMAGE_PIXELTYPEINFO_H__
  #define __VW_IMAGE_PIXELTYPEINFO_H__
  
  #include <vw/Core/FundamentalTypes.h>
  #include <vw/Core/CompoundTypes.h>
  #include <vw/Core/Functors.h>
  #include <vw/Math/Functions.h>
  #include <vw/Math/Vector.h>
  
  #include <complex>
  
  #include <boost/integer_traits.hpp>
  #include <boost/mpl/if.hpp>
  #include <boost/type_traits/is_floating_point.hpp>
  #include <boost/type_traits/is_same.hpp>
  #include <boost/utility/enable_if.hpp>
  
  namespace vw {
  
    // Forward declaration, used to disable certain pixel functions when
    // the arguments are actually images.
    template <class ImageT> struct ImageViewBase;
  
    // *******************************************************************
    // Basic pixel type manipulation logic
    //
    // Here we provide basic pixel type manipulation classes, most of
    // which are just thin wrappers provided for backwards
    // compatability.  We also provide tools to convert between real
    // and complex pixel types.
    // *******************************************************************
  
    template <class T> struct PixelChannelType : CompoundChannelType<T> {};
    template <class T> struct PixelNumChannels : CompoundNumChannels<T> {};
    template <class T, class ChannelT> struct PixelChannelCast : CompoundChannelCast<T,ChannelT> {};
    template <class T> struct PixelHasAlpha : false_type {};
    template <class T> struct PixelWithAlpha {};
    template <class T> struct PixelWithoutAlpha { typedef T type; };
  
    template <class PixelT>
    struct PixelMakeComplex {
      typedef typename PixelChannelCast<PixelT,typename MakeComplex<typename PixelChannelType<PixelT>::type>::type>::type type;
    };
  
    template <class PixelT>
    struct PixelMakeReal {
      typedef typename PixelChannelCast<PixelT,typename MakeReal<typename PixelChannelType<PixelT>::type>::type>::type type;
    };
  
    /// Use this to get the raw underlying type of an image type (ex: double, int, float)
    template <class T>
    struct ImageChannelType {
      typedef typename PixelChannelType<typename T::pixel_type>::type type;
    };
  
    template <class T>
    struct PixelNumBytes {
      static const uint32 value =  uint32(PixelNumChannels<T>::value) * sizeof(typename PixelChannelType<T>::type);
    };
  
    // *******************************************************************
    // Pixel channel standard range computation logic
    //
    // In some functions it is necessary to assume that the values in a
    // pixel span some meaningful range.  For example, when compositing
    // with alpha you have to know what value of alpha corresponds to
    // full opacity.  For floating-point types the range is generally
    // from zero to one.  These classes allow you to compute the range
    // for an arbitrary pixel type.
    // *******************************************************************
  
    // Channel range helper for integer types
    template <class T, bool>
    struct ChannelRangeHelper {
      static inline T max() {
        return boost::integer_traits<T>::max();
      }
      static inline T min() {
        return T();
      }
    };
  
    // Channel range helper for floating-point types
    template <class T>
    struct ChannelRangeHelper<T,false> {
      static inline T max() {
        return (T)(1.0);
      }
      static inline T min() {
        return (T)(0.0);
      }
    };
  
    // Channel range helper for complex types
    template <class T> struct ChannelRangeHelper<std::complex<T>,false> : 
              public ChannelRangeHelper<T,boost::integer_traits<T>::is_integer> {};
  
    /// A channel range computation class.  This class is templatized on
    /// the pixel type and provides two static functions, max() and min(),
    /// that return the top and bottom of the standard range of the
    /// underlying channel type.  That is, max() corresponds to 1.0 in
    /// the floating-point world and min() corresponds to 0.0.  The value
    /// of min() is generally zero, *not* some negative number.  If you
    /// really just want to know the range of values you can store in a
    /// given type, use std::numeric_limits instead.
    template <class T> struct ChannelRange : 
            public ChannelRangeHelper<typename CompoundChannelType<T>::type, 
                                       boost::integer_traits<typename CompoundChannelType<T>::type>::is_integer> {};
  
  
    // *******************************************************************
    // Basic pixel alpha channel logic
    //
    // Here we provide basic pixel type manipulation classes for
    // determining whether a pixel is transparent (i.e. its alpha is
    // zero).  For pixel types without alpha, the pixel is always
    // considered to be non-transparent.
    // *******************************************************************
    template <class PixelT>
    inline typename boost::enable_if< typename IsScalarOrCompound<PixelT>::type, typename boost::enable_if<typename PixelHasAlpha<PixelT>::type, bool>::type>::type
    is_transparent(PixelT const& pixel) { return !(pixel.a()); }
  
    template <class PixelT>
    inline typename boost::enable_if< typename IsScalarOrCompound<PixelT>::type, typename boost::enable_if<typename PixelHasAlpha<PixelT>::type, bool>::type>::type
    is_opaque(PixelT const& pixel) { return pixel.a() == ChannelRange<PixelT>::max(); }
  
    template <class PixelT>
    inline typename boost::enable_if< typename IsScalarOrCompound<PixelT>::type, typename boost::disable_if<typename PixelHasAlpha<PixelT>::type, bool>::type>::type
    is_transparent(PixelT const& /*pixel*/) { return false; }
  
    template <class PixelT>
    inline typename boost::enable_if< typename IsScalarOrCompound<PixelT>::type, typename boost::disable_if<typename PixelHasAlpha<PixelT>::type, bool>::type>::type
    is_opaque(PixelT const& /*pixel*/) { return true; }
  
    template <class PixelT>
    inline typename boost::enable_if< typename IsScalarOrCompound<PixelT>::type, typename PixelChannelType<PixelT>::type >::type
    alpha_channel( PixelT& /*pix*/ ) {
      return ChannelRange<PixelT>::max();
    }
  
    template <class PixelT>
    inline typename boost::enable_if< typename IsScalarOrCompound<PixelT>::type, PixelT& >::type
    non_alpha_channels( PixelT& pix ) {
      return pix;
    }
  
    template <class PixelT>
    inline typename boost::enable_if< typename IsScalarOrCompound<PixelT>::type, const PixelT& >::type
    non_alpha_channels( const PixelT& pix ) {
      return pix;
    }
  
  
    // *******************************************************************
    // Pixel channel casting and rescaling logic.
    //
    // Here we defined channel_cast and channel_cast_rescale to operate
    // on pixels.  We've forward-declared ImageViewBase so that we can
    // disable these functions for images, allowing other whole-image
    // overloads to work in that case.  The simple channel_cast could be
    // put into Core/CompoundTypes.h instead, but it's only used in the
    // context of pixel casting and mirrors channel_cast_rescale nicely,
    // so we leave it here.
    //
    // FIXME The _clamp version clamps to the min/max integer values of
    // the destination.  This function does not work at all for floating-
    // point destination types, and the user might expect it to clamp to
    // the ChannelRange instead.  Probably the _clamp behavior should be
    // promoted to the default behavior for integer destination types.
    // Anyone who is relying on channel_cast's overvlow behavior probably
    // deserves to lose anyway.  At the moment the only thing using this
    // code is BicubicInterpolation.
    // *******************************************************************
  
    template <class DestT>
    class ChannelCastFunctor : public ReturnFixedType<DestT> {
    public:
      template <class SourceT>
      inline DestT operator()( SourceT source ) const {
        return (DestT)source;
      }
    };
  
    template <class ChannelT, class PixelT>
    typename boost::enable_if< typename IsScalarOrCompound<PixelT>::type, typename CompoundChannelCast<PixelT, ChannelT>::type >::type
    inline channel_cast( PixelT pixel ) {
      return compound_apply( ChannelCastFunctor<ChannelT>(), pixel );
    }
  
    template <class DestT>
    class ChannelCastRescaleFunctor : public ReturnFixedType<DestT> {
    public:
      template <class SourceT>
      inline DestT operator()( SourceT source ) const {
        // Clamping semantics are more reasonable for float->int rescaling.
        if( boost::is_floating_point<SourceT>::value && ! boost::is_floating_point<DestT>::value) {
          if( source > ChannelRange<SourceT>::max() ) source = ChannelRange<SourceT>::max();
          else if( source < ChannelRange<SourceT>::min() ) source = ChannelRange<SourceT>::min();
        }
        return (DestT)(source*(((double)(ChannelRange<DestT>::max()))/(ChannelRange<SourceT>::max())));
      }
      inline DestT operator()( DestT source ) const {
        return source;
      }
    };
  
    template <class ChannelT, class PixelT>
    typename boost::enable_if< typename IsScalarOrCompound<PixelT>::type, typename CompoundChannelCast<PixelT, ChannelT>::type >::type
    inline channel_cast_rescale( PixelT pixel ) {
      return compound_apply( ChannelCastRescaleFunctor<ChannelT>(), pixel );
    }
  
    template <class DestT>
    class ChannelCastClampFunctor : public ReturnFixedType<DestT> {
    public:
      template <class SourceT>
      inline DestT operator()( SourceT source ) const {
        if( source > boost::integer_traits<DestT>::max() ) return boost::integer_traits<DestT>::max();
        else if( source < boost::integer_traits<DestT>::min() ) return boost::integer_traits<DestT>::min();
        else return DestT( source );
      }
      inline DestT operator()( DestT source ) const {
        return source;
      }
    };
  
    template <class ChannelT, class PixelT>
    typename boost::enable_if< typename IsScalarOrCompound<PixelT>::type, typename CompoundChannelCast<PixelT, ChannelT>::type >::type
    inline channel_cast_clamp( PixelT pixel ) {
      return compound_apply( ChannelCastClampFunctor<ChannelT>(), pixel );
    }
  
    template <class ChannelT, class PixelT>
    typename boost::enable_if< typename IsScalarOrCompound<PixelT>::type, typename CompoundChannelCast<PixelT, ChannelT>::type >::type
    inline channel_cast_clamp_if_int( PixelT pixel ) {
      typedef typename boost::is_floating_point<ChannelT>::type is_float_type;
      typedef typename boost::mpl::if_<is_float_type, ChannelCastFunctor<ChannelT>, ChannelCastClampFunctor<ChannelT> >::type functor_type;
      return compound_apply( functor_type(), pixel );
    }
  
    template <class DestT>
    class ChannelCastRoundFunctor : public ReturnFixedType<DestT> {
    public:
      template <class SourceT>
      inline DestT operator()( SourceT source ) const {
        return DestT( math::impl::_round( source ) );
      }
      inline DestT operator()( DestT source ) const {
        return source;
      }
    };
  
    template <class ChannelT, class PixelT>
    typename boost::enable_if< typename IsScalarOrCompound<PixelT>::type, typename CompoundChannelCast<PixelT, ChannelT>::type >::type
    inline channel_cast_round( PixelT pixel ) {
      return compound_apply( ChannelCastRoundFunctor<ChannelT>(), pixel );
    }
  
    template <class ChannelT, class PixelT>
    typename boost::enable_if< typename IsScalarOrCompound<PixelT>::type, typename CompoundChannelCast<PixelT, ChannelT>::type >::type
    inline channel_cast_round_if_int( PixelT pixel ) {
      typedef typename boost::is_floating_point<ChannelT>::type is_float_type;
      typedef typename boost::mpl::if_<is_float_type, ChannelCastFunctor<ChannelT>, ChannelCastRoundFunctor<ChannelT> >::type functor_type;
      return compound_apply( functor_type(), pixel );
    }
  
    template <class DestT>
    class ChannelCastRoundClampFunctor : public ReturnFixedType<DestT> {
    public:
      template <class SourceT>
      inline DestT operator()( SourceT source ) const {
        if( source > boost::integer_traits<DestT>::max() ) return boost::integer_traits<DestT>::max();
        else if( source < boost::integer_traits<DestT>::min() ) return boost::integer_traits<DestT>::min();
        else return DestT( math::impl::_round( source ) );
      }
      inline DestT operator()( DestT source ) const {
        return source;
      }
    };
  
    template <class ChannelT, class PixelT>
    typename boost::enable_if< typename IsScalarOrCompound<PixelT>::type, typename CompoundChannelCast<PixelT, ChannelT>::type >::type
    inline channel_cast_round_and_clamp( PixelT pixel ) {
      return compound_apply( ChannelCastRoundClampFunctor<ChannelT>(), pixel );
    }
  
    template <class ChannelT, class PixelT>
    typename boost::enable_if< typename IsScalarOrCompound<PixelT>::type, typename CompoundChannelCast<PixelT, ChannelT>::type >::type
    inline channel_cast_round_and_clamp_if_int( PixelT pixel ) {
      typedef typename boost::is_floating_point<ChannelT>::type is_float_type;
      typedef typename boost::mpl::if_<is_float_type, ChannelCastFunctor<ChannelT>, ChannelCastRoundClampFunctor<ChannelT> >::type functor_type;
      return compound_apply( functor_type(), pixel );
    }
  
    // *******************************************************************
    // Pixel casting and rescaling logic.
    //
    // We implement pixel casting indirectly through this pixel_cast<>
    // template so that users can easily control the behavior of casts
    // between user-defined and standard pixel types.  When the source
    // and destination channel types differ, the channel conversion is
    // handled separately from the pixel format conversion.  The pixel
    // conversion itself takes place in whichever channel space has
    // greater precision, and occurs via a call to the corresponding
    // pixel_cast function.  Thus, if the user wishes to overload the
    // conversion behavior between two pixel formats, they need only
    // overload it for the case when the channel types are the same.
    // The rescaling variant, pixel_cast_rescale<>, performs a scale
    // conversion when converting the channel type.
    // *******************************************************************
  
    // Default behavior, invoked when the source and destination channel
    // type are the same.
    template <bool SameN, bool SrcN, bool RescaleN>
    struct PixelCastHelper {
      template <class DestT, class SrcT>
      static inline DestT convert( SrcT src ) {
        return DestT( src );
      }
    };
  
    // Non-rescaling pixel cast free function
    template <class DestT, class SrcT>
    typename boost::enable_if< typename IsScalarOrCompound<SrcT>::type, DestT >::type
    inline pixel_cast( SrcT src ) {
      typedef typename CompoundChannelType<SrcT>::type src_ch;
      typedef typename CompoundChannelType<DestT>::type dest_ch;
      typedef typename boost::is_same<src_ch,dest_ch>::type is_same;
      typedef PixelCastHelper< is_same::value, (sizeof(src_ch)>sizeof(dest_ch)), false > helper;
      return helper::template convert<DestT>( src );
    }
  
    // Rescaling pixel cast free function
    template <class DestT, class SrcT>
    typename boost::enable_if< typename IsScalarOrCompound<SrcT>::type, DestT >::type
    inline pixel_cast_rescale( SrcT src ) {
      typedef typename CompoundChannelType<SrcT>::type src_ch;
      typedef typename CompoundChannelType<DestT>::type dest_ch;
      typedef typename boost::is_same<src_ch,dest_ch>::type is_same;
      typedef PixelCastHelper< is_same::value, (sizeof(src_ch)>sizeof(dest_ch)), true > helper;
      return helper::template convert<DestT>( src );
    }
  
    // Non-rescaling behavior when SrcT has less or same precision
    template <>
    struct PixelCastHelper<false, false, false> {
      template <class DestT, class SrcT>
      static inline DestT convert( SrcT src ) {
        typedef typename CompoundChannelType<DestT>::type dest_ch;
        return pixel_cast<DestT>( channel_cast<dest_ch>( src ) );
      }
    };
  
    // Non-rescaling behavior when SrcT has greater precision
    template <>
    struct PixelCastHelper<false, true, false> {
      template <class DestT, class SrcT>
      static inline DestT convert( SrcT src ) {
        typedef typename CompoundChannelType<SrcT>::type src_ch;
        typedef typename CompoundChannelType<DestT>::type dest_ch;
        typedef typename CompoundChannelCast<DestT,src_ch>::type dest_px;
        return channel_cast<dest_ch>( pixel_cast<dest_px>( src ) );
      }
    };
  
    // Rescaling behavior when SrcT has less or same precision
    template <>
    struct PixelCastHelper<false, false, true> {
      template <class DestT, class SrcT>
      static inline DestT convert( SrcT src ) {
        typedef typename CompoundChannelType<DestT>::type dest_ch;
        return pixel_cast<DestT>( channel_cast_rescale<dest_ch>( src ) );
      }
    };
  
    // Rescaling behavior when SrcT has greater precision
    template <>
    struct PixelCastHelper<false, true, true> {
      template <class DestT, class SrcT>
      static inline DestT convert( SrcT src ) {
        typedef typename CompoundChannelType<SrcT>::type src_ch;
        typedef typename CompoundChannelType<DestT>::type dest_ch;
        typedef typename CompoundChannelCast<DestT,src_ch>::type dest_px;
        return channel_cast_rescale<dest_ch>( pixel_cast<dest_px>( src ) );
      }
    };
  
  
    // *******************************************************************
    // A pixel type convenience macro and forward declrations.
    // *******************************************************************
  
    /// This macro provides the appropriate specializations of
    /// the compound type traits classes for a new pixel type
    /// with a fixed number of channels (the common case).
  #define VW_DECLARE_PIXEL_TYPE(PIXELT,NCHANNELS)              \
    template <class ChannelT>                                  \
    struct CompoundChannelType<PIXELT<ChannelT> > {            \
      typedef ChannelT type;                                   \
    };                                                         \
    template <class ChannelT>                                  \
    struct CompoundNumChannels<PIXELT<ChannelT> > {            \
      static const size_t value = NCHANNELS;                   \
    };                                                         \
    template <class OldChT, class NewChT>                      \
    struct CompoundChannelCast<PIXELT<OldChT>, NewChT> {       \
      typedef PIXELT<NewChT> type;                             \
    };                                                         \
    template <class OldChT, class NewChT>                      \
    struct CompoundChannelCast<PIXELT<OldChT>, const NewChT> { \
      typedef const PIXELT<NewChT> type;                       \
    }                                                          \
  
    /// This macro provides the appropriate specializations of
    /// the compound type traits classes for a new pixel type
    /// with a variable number of channels.
  #define VW_DECLARE_PIXEL_TYPE_NCHANNELS(PIXELT)              \
    template <class ChannelT, size_t SizeN>                    \
    struct CompoundChannelType<PIXELT<ChannelT,SizeN> > {      \
      typedef ChannelT type;                                   \
    };                                                         \
    template <class ChannelT, size_t SizeN>                    \
    struct CompoundNumChannels<PIXELT<ChannelT,SizeN> > {      \
      static const size_t value = SizeN;                       \
    };                                                         \
    template <class OldChT, class NewChT, size_t SizeN>        \
    struct CompoundChannelCast<PIXELT<OldChT,SizeN>, NewChT> { \
      typedef PIXELT<NewChT,SizeN> type;                       \
    };                                                         \
    template <class OldChT, class NewChT, size_t SizeN>        \
    struct CompoundChannelCast<PIXELT<OldChT,SizeN>, const NewChT> { \
      typedef const PIXELT<NewChT,SizeN> type;                 \
    }
  
  #define VW_ALPHA_PIXEL_TRAITS(opaque, alpha) \
    template <class T> struct PixelHasAlpha<alpha<T> > : true_type {};                  \
    template <class T> struct PixelWithAlpha<opaque<T> >    { typedef alpha<T> type; }; \
    template <class T> struct PixelWithAlpha<alpha<T> >     { typedef alpha<T> type; }; \
    template <class T> struct PixelWithoutAlpha<alpha<T> >  { typedef opaque<T> type; } \
  
  
    // Forward pixel type declarations for complex pixel types
    template <class ChannelT> class PixelGray;
    template <class ChannelT> class PixelGrayA;
    template <class ChannelT> class PixelRGB;
    template <class ChannelT> class PixelRGBA;
    template <class ChannelT> class PixelHSV;
    template <class ChannelT> class PixelXYZ;
    template <class ChannelT> class PixelLuv;
    template <class ChannelT> class PixelLab;
  
    // Forward pixel type declarations for the pixel mask wrapper
    template <class ChildT> struct PixelMask;
  
    // *******************************************************************
    // Run-time pixel type manipulation routines.
    // *******************************************************************
  
    enum PixelFormatEnum {
      VW_PIXEL_UNKNOWN = 0,
      VW_PIXEL_SCALAR = 1,
      VW_PIXEL_GRAY = 2,
      VW_PIXEL_GRAYA = 3,
      VW_PIXEL_RGB = 4,
      VW_PIXEL_RGBA = 5,
      VW_PIXEL_HSV = 6,
      VW_PIXEL_XYZ = 7,
      VW_PIXEL_LUV = 8,
      VW_PIXEL_LAB = 9,
      VW_PIXEL_UNKNOWN_MASKED = 40,
      VW_PIXEL_SCALAR_MASKED = 41,
      VW_PIXEL_GRAY_MASKED = 42,
      VW_PIXEL_GRAYA_MASKED = 43,
      VW_PIXEL_RGB_MASKED = 44,
      VW_PIXEL_RGBA_MASKED = 45,
      VW_PIXEL_HSV_MASKED = 46,
      VW_PIXEL_XYZ_MASKED = 47,
      VW_PIXEL_LUV_MASKED = 48,
      VW_PIXEL_LAB_MASKED = 49,
      VW_PIXEL_GENERIC_1_CHANNEL = 90,
      VW_PIXEL_GENERIC_2_CHANNEL = 91,
      VW_PIXEL_GENERIC_3_CHANNEL = 92,
      VW_PIXEL_GENERIC_4_CHANNEL = 93,
      VW_PIXEL_GENERIC_5_CHANNEL = 94,
      VW_PIXEL_GENERIC_6_CHANNEL = 95,
      VW_PIXEL_GENERIC_7_CHANNEL = 96,
      VW_PIXEL_GENERIC_8_CHANNEL = 97,
      VW_PIXEL_GENERIC_9_CHANNEL = 98,
      VW_PIXEL_USER = 100
    };
  
    enum ChannelTypeEnum {
      VW_CHANNEL_UNKNOWN = 0,
      VW_CHANNEL_INT8 = 1,
      VW_CHANNEL_UINT8 = 2,
      VW_CHANNEL_INT16 = 3,
      VW_CHANNEL_UINT16 = 4,
      VW_CHANNEL_INT32 = 5,
      VW_CHANNEL_UINT32 = 6,
      VW_CHANNEL_INT64 = 7,
      VW_CHANNEL_UINT64 = 8,
      VW_CHANNEL_FLOAT16 = 9,
      VW_CHANNEL_FLOAT32 = 10,
      VW_CHANNEL_FLOAT64 = 11,
      VW_CHANNEL_BOOL = 12,
      VW_CHANNEL_CHAR = 13, // A tag to identify e.g. string medadata
      VW_CHANNEL_GENERIC_1_BYTE = 90,
      VW_CHANNEL_GENERIC_2_BYTE = 91,
      VW_CHANNEL_GENERIC_4_BYTE = 92,
      VW_CHANNEL_GENERIC_8_BYTE = 93,
      VW_CHANNEL_USER = 100
    };
  
    // PixelFormatID<>
    /// Return a VW enum for a pixel data type.
    template <class PixelT> struct PixelFormatID { static const PixelFormatEnum value = VW_PIXEL_UNKNOWN; };
    template<> struct PixelFormatID<vw::int8>    { static const PixelFormatEnum value = VW_PIXEL_SCALAR; };
    template<> struct PixelFormatID<vw::uint8>   { static const PixelFormatEnum value = VW_PIXEL_SCALAR; };
    template<> struct PixelFormatID<vw::int16>   { static const PixelFormatEnum value = VW_PIXEL_SCALAR; };
    template<> struct PixelFormatID<vw::uint16>  { static const PixelFormatEnum value = VW_PIXEL_SCALAR; };
    template<> struct PixelFormatID<vw::int32>   { static const PixelFormatEnum value = VW_PIXEL_SCALAR; };
    template<> struct PixelFormatID<vw::uint32>  { static const PixelFormatEnum value = VW_PIXEL_SCALAR; };
    template<> struct PixelFormatID<vw::int64>   { static const PixelFormatEnum value = VW_PIXEL_SCALAR; };
    template<> struct PixelFormatID<vw::uint64>  { static const PixelFormatEnum value = VW_PIXEL_SCALAR; };
    template<> struct PixelFormatID<vw::float32> { static const PixelFormatEnum value = VW_PIXEL_SCALAR; };
    template<> struct PixelFormatID<vw::float64> { static const PixelFormatEnum value = VW_PIXEL_SCALAR; };
    template<> struct PixelFormatID<bool>        { static const PixelFormatEnum value = VW_PIXEL_SCALAR; };
    template <class ChT> struct PixelFormatID<PixelGray<ChT> >  { static const PixelFormatEnum value = VW_PIXEL_GRAY; };
    template <class ChT> struct PixelFormatID<PixelGrayA<ChT> > { static const PixelFormatEnum value = VW_PIXEL_GRAYA; };
    template <class ChT> struct PixelFormatID<PixelRGB<ChT> >   { static const PixelFormatEnum value = VW_PIXEL_RGB; };
    template <class ChT> struct PixelFormatID<PixelRGBA<ChT> >  { static const PixelFormatEnum value = VW_PIXEL_RGBA; };
    template <class ChT> struct PixelFormatID<PixelHSV<ChT> >   { static const PixelFormatEnum value = VW_PIXEL_HSV; };
    template <class ChT> struct PixelFormatID<PixelXYZ<ChT> >   { static const PixelFormatEnum value = VW_PIXEL_XYZ; };
    template <class ChT> struct PixelFormatID<PixelLuv<ChT> >   { static const PixelFormatEnum value = VW_PIXEL_LUV; };
    template <class ChT> struct PixelFormatID<PixelLab<ChT> >   { static const PixelFormatEnum value = VW_PIXEL_LAB; };
  
    // PixelFormatID<> specialized for masked pixel types
    template<> struct PixelFormatID<PixelMask<vw::int8> >    { static const PixelFormatEnum value = VW_PIXEL_SCALAR_MASKED; };
    template<> struct PixelFormatID<PixelMask<vw::uint8> >   { static const PixelFormatEnum value = VW_PIXEL_SCALAR_MASKED; };
    template<> struct PixelFormatID<PixelMask<vw::int16> >   { static const PixelFormatEnum value = VW_PIXEL_SCALAR_MASKED; };
    template<> struct PixelFormatID<PixelMask<vw::uint16> >  { static const PixelFormatEnum value = VW_PIXEL_SCALAR_MASKED; };
    template<> struct PixelFormatID<PixelMask<vw::int32> >   { static const PixelFormatEnum value = VW_PIXEL_SCALAR_MASKED; };
    template<> struct PixelFormatID<PixelMask<vw::uint32> >  { static const PixelFormatEnum value = VW_PIXEL_SCALAR_MASKED; };
    template<> struct PixelFormatID<PixelMask<vw::int64> >   { static const PixelFormatEnum value = VW_PIXEL_SCALAR_MASKED; };
    template<> struct PixelFormatID<PixelMask<vw::uint64> >  { static const PixelFormatEnum value = VW_PIXEL_SCALAR_MASKED; };
    template<> struct PixelFormatID<PixelMask<vw::float32> > { static const PixelFormatEnum value = VW_PIXEL_SCALAR_MASKED; };
    template<> struct PixelFormatID<PixelMask<vw::float64> > { static const PixelFormatEnum value = VW_PIXEL_SCALAR_MASKED; };
    template<> struct PixelFormatID<PixelMask<bool> >        { static const PixelFormatEnum value = VW_PIXEL_SCALAR_MASKED; };
    template <class ChT> struct PixelFormatID<PixelMask<PixelGray<ChT> > >  { static const PixelFormatEnum value = VW_PIXEL_GRAY_MASKED; };
    template <class ChT> struct PixelFormatID<PixelMask<PixelGrayA<ChT> > > { static const PixelFormatEnum value = VW_PIXEL_GRAYA_MASKED; };
    template <class ChT> struct PixelFormatID<PixelMask<PixelRGB<ChT> > >   { static const PixelFormatEnum value = VW_PIXEL_RGB_MASKED; };
    template <class ChT> struct PixelFormatID<PixelMask<PixelRGBA<ChT> > >  { static const PixelFormatEnum value = VW_PIXEL_RGBA_MASKED; };
    template <class ChT> struct PixelFormatID<PixelMask<PixelHSV<ChT> > >   { static const PixelFormatEnum value = VW_PIXEL_HSV_MASKED; };
    template <class ChT> struct PixelFormatID<PixelMask<PixelXYZ<ChT> > >   { static const PixelFormatEnum value = VW_PIXEL_XYZ_MASKED; };
    template <class ChT> struct PixelFormatID<PixelMask<PixelLuv<ChT> > >   { static const PixelFormatEnum value = VW_PIXEL_LUV_MASKED; };
    template <class ChT> struct PixelFormatID<PixelMask<PixelLab<ChT> > >   { static const PixelFormatEnum value = VW_PIXEL_LAB_MASKED; };
  
    // Define everything we are likely to need here so we are unlikely to have to deal with the weird failures
    //  produced when one of these types is missing.
  
    // PixelFormatID<> specialized for vector pixel types
    template<> struct PixelFormatID<Vector<float, 2> >   { static const PixelFormatEnum value = VW_PIXEL_GENERIC_2_CHANNEL; };
    template<> struct PixelFormatID<Vector<float, 3> >   { static const PixelFormatEnum value = VW_PIXEL_GENERIC_3_CHANNEL; };
    template<> struct PixelFormatID<Vector<float, 4> >   { static const PixelFormatEnum value = VW_PIXEL_GENERIC_4_CHANNEL; };
    template<> struct PixelFormatID<Vector<float, 5> >   { static const PixelFormatEnum value = VW_PIXEL_GENERIC_5_CHANNEL; };
    template<> struct PixelFormatID<Vector<float, 6> >   { static const PixelFormatEnum value = VW_PIXEL_GENERIC_6_CHANNEL; };
    template<> struct PixelFormatID<Vector<float, 7> >   { static const PixelFormatEnum value = VW_PIXEL_GENERIC_7_CHANNEL; };
    template<> struct PixelFormatID<Vector<float, 8> >   { static const PixelFormatEnum value = VW_PIXEL_GENERIC_8_CHANNEL; };
  
    template<> struct PixelFormatID<Vector<double, 2> >   { static const PixelFormatEnum value = VW_PIXEL_GENERIC_2_CHANNEL; };
    template<> struct PixelFormatID<Vector<double, 3> >   { static const PixelFormatEnum value = VW_PIXEL_GENERIC_3_CHANNEL; };
    template<> struct PixelFormatID<Vector<double, 4> >   { static const PixelFormatEnum value = VW_PIXEL_GENERIC_4_CHANNEL; };
    template<> struct PixelFormatID<Vector<double, 5> >   { static const PixelFormatEnum value = VW_PIXEL_GENERIC_5_CHANNEL; };
    template<> struct PixelFormatID<Vector<double, 6> >   { static const PixelFormatEnum value = VW_PIXEL_GENERIC_6_CHANNEL; };
    template<> struct PixelFormatID<Vector<double, 7> >   { static const PixelFormatEnum value = VW_PIXEL_GENERIC_7_CHANNEL; };
    template<> struct PixelFormatID<Vector<double, 8> >   { static const PixelFormatEnum value = VW_PIXEL_GENERIC_8_CHANNEL; };
  
    template<> struct PixelFormatID<Vector<int, 2> >   { static const PixelFormatEnum value = VW_PIXEL_GENERIC_2_CHANNEL; };
    template<> struct PixelFormatID<Vector<int, 3> >   { static const PixelFormatEnum value = VW_PIXEL_GENERIC_3_CHANNEL; };
    template<> struct PixelFormatID<Vector<int, 4> >   { static const PixelFormatEnum value = VW_PIXEL_GENERIC_4_CHANNEL; };
    template<> struct PixelFormatID<Vector<int, 5> >   { static const PixelFormatEnum value = VW_PIXEL_GENERIC_5_CHANNEL; };
    template<> struct PixelFormatID<Vector<int, 6> >   { static const PixelFormatEnum value = VW_PIXEL_GENERIC_6_CHANNEL; };
    template<> struct PixelFormatID<Vector<int, 7> >   { static const PixelFormatEnum value = VW_PIXEL_GENERIC_7_CHANNEL; };
    template<> struct PixelFormatID<Vector<int, 8> >   { static const PixelFormatEnum value = VW_PIXEL_GENERIC_8_CHANNEL; };
    
    template<> struct PixelFormatID<Vector<uint8, 2> >   { static const PixelFormatEnum value = VW_PIXEL_GENERIC_2_CHANNEL; };
    template<> struct PixelFormatID<Vector<uint8, 3> >   { static const PixelFormatEnum value = VW_PIXEL_GENERIC_3_CHANNEL; };
    template<> struct PixelFormatID<Vector<uint8, 4> >   { static const PixelFormatEnum value = VW_PIXEL_GENERIC_4_CHANNEL; };
    template<> struct PixelFormatID<Vector<uint8, 5> >   { static const PixelFormatEnum value = VW_PIXEL_GENERIC_5_CHANNEL; };
    template<> struct PixelFormatID<Vector<uint8, 6> >   { static const PixelFormatEnum value = VW_PIXEL_GENERIC_6_CHANNEL; };
    template<> struct PixelFormatID<Vector<uint8, 7> >   { static const PixelFormatEnum value = VW_PIXEL_GENERIC_7_CHANNEL; };
    template<> struct PixelFormatID<Vector<uint8, 8> >   { static const PixelFormatEnum value = VW_PIXEL_GENERIC_8_CHANNEL; };
    
    template<> struct PixelFormatID<Vector<uint16, 2> >   { static const PixelFormatEnum value = VW_PIXEL_GENERIC_2_CHANNEL; };
    template<> struct PixelFormatID<Vector<uint16, 3> >   { static const PixelFormatEnum value = VW_PIXEL_GENERIC_3_CHANNEL; };
    template<> struct PixelFormatID<Vector<uint16, 4> >   { static const PixelFormatEnum value = VW_PIXEL_GENERIC_4_CHANNEL; };
    template<> struct PixelFormatID<Vector<uint16, 5> >   { static const PixelFormatEnum value = VW_PIXEL_GENERIC_5_CHANNEL; };
    template<> struct PixelFormatID<Vector<uint16, 6> >   { static const PixelFormatEnum value = VW_PIXEL_GENERIC_6_CHANNEL; };
    template<> struct PixelFormatID<Vector<uint16, 7> >   { static const PixelFormatEnum value = VW_PIXEL_GENERIC_7_CHANNEL; };
    template<> struct PixelFormatID<Vector<uint16, 8> >   { static const PixelFormatEnum value = VW_PIXEL_GENERIC_8_CHANNEL; };
    
    // PixelFormatID<> specialized for masked vector pixel types
    template<> struct PixelFormatID<PixelMask<Vector<float, 2> > >   { static const PixelFormatEnum value = VW_PIXEL_GENERIC_3_CHANNEL; };
    template<> struct PixelFormatID<PixelMask<Vector<float, 3> > >   { static const PixelFormatEnum value = VW_PIXEL_GENERIC_4_CHANNEL; };
    template<> struct PixelFormatID<PixelMask<Vector<float, 4> > >   { static const PixelFormatEnum value = VW_PIXEL_GENERIC_5_CHANNEL; };
    template<> struct PixelFormatID<PixelMask<Vector<float, 5> > >   { static const PixelFormatEnum value = VW_PIXEL_GENERIC_6_CHANNEL; };
    template<> struct PixelFormatID<PixelMask<Vector<float, 6> > >   { static const PixelFormatEnum value = VW_PIXEL_GENERIC_7_CHANNEL; };
    template<> struct PixelFormatID<PixelMask<Vector<float, 7> > >   { static const PixelFormatEnum value = VW_PIXEL_GENERIC_8_CHANNEL; };
    template<> struct PixelFormatID<PixelMask<Vector<float, 8> > >   { static const PixelFormatEnum value = VW_PIXEL_GENERIC_9_CHANNEL; };
  
    template<> struct PixelFormatID<PixelMask<Vector<double, 2> > >   { static const PixelFormatEnum value = VW_PIXEL_GENERIC_3_CHANNEL; };
    template<> struct PixelFormatID<PixelMask<Vector<double, 3> > >   { static const PixelFormatEnum value = VW_PIXEL_GENERIC_4_CHANNEL; };
    template<> struct PixelFormatID<PixelMask<Vector<double, 4> > >   { static const PixelFormatEnum value = VW_PIXEL_GENERIC_5_CHANNEL; };
    template<> struct PixelFormatID<PixelMask<Vector<double, 5> > >   { static const PixelFormatEnum value = VW_PIXEL_GENERIC_6_CHANNEL; };
    template<> struct PixelFormatID<PixelMask<Vector<double, 6> > >   { static const PixelFormatEnum value = VW_PIXEL_GENERIC_7_CHANNEL; };
    template<> struct PixelFormatID<PixelMask<Vector<double, 7> > >   { static const PixelFormatEnum value = VW_PIXEL_GENERIC_8_CHANNEL; };
    template<> struct PixelFormatID<PixelMask<Vector<double, 8> > >   { static const PixelFormatEnum value = VW_PIXEL_GENERIC_9_CHANNEL; };
  
    template<> struct PixelFormatID<PixelMask<Vector<int, 2> > >   { static const PixelFormatEnum value = VW_PIXEL_GENERIC_3_CHANNEL; };
    template<> struct PixelFormatID<PixelMask<Vector<int, 3> > >   { static const PixelFormatEnum value = VW_PIXEL_GENERIC_4_CHANNEL; };
    template<> struct PixelFormatID<PixelMask<Vector<int, 4> > >   { static const PixelFormatEnum value = VW_PIXEL_GENERIC_5_CHANNEL; };
    template<> struct PixelFormatID<PixelMask<Vector<int, 5> > >   { static const PixelFormatEnum value = VW_PIXEL_GENERIC_6_CHANNEL; };
    template<> struct PixelFormatID<PixelMask<Vector<int, 6> > >   { static const PixelFormatEnum value = VW_PIXEL_GENERIC_7_CHANNEL; };
    template<> struct PixelFormatID<PixelMask<Vector<int, 7> > >   { static const PixelFormatEnum value = VW_PIXEL_GENERIC_8_CHANNEL; };
    template<> struct PixelFormatID<PixelMask<Vector<int, 8> > >   { static const PixelFormatEnum value = VW_PIXEL_GENERIC_9_CHANNEL; };
    
    template<> struct PixelFormatID<PixelMask<Vector<uint8, 2> > >   { static const PixelFormatEnum value = VW_PIXEL_GENERIC_3_CHANNEL; };
    template<> struct PixelFormatID<PixelMask<Vector<uint8, 3> > >   { static const PixelFormatEnum value = VW_PIXEL_GENERIC_4_CHANNEL; };
    template<> struct PixelFormatID<PixelMask<Vector<uint8, 4> > >   { static const PixelFormatEnum value = VW_PIXEL_GENERIC_5_CHANNEL; };
    template<> struct PixelFormatID<PixelMask<Vector<uint8, 5> > >   { static const PixelFormatEnum value = VW_PIXEL_GENERIC_6_CHANNEL; };
    template<> struct PixelFormatID<PixelMask<Vector<uint8, 6> > >   { static const PixelFormatEnum value = VW_PIXEL_GENERIC_7_CHANNEL; };
    template<> struct PixelFormatID<PixelMask<Vector<uint8, 7> > >   { static const PixelFormatEnum value = VW_PIXEL_GENERIC_8_CHANNEL; };
    template<> struct PixelFormatID<PixelMask<Vector<uint8, 8> > >   { static const PixelFormatEnum value = VW_PIXEL_GENERIC_9_CHANNEL; };
  
    template<> struct PixelFormatID<PixelMask<Vector<uint16, 2> > >   { static const PixelFormatEnum value = VW_PIXEL_GENERIC_3_CHANNEL; };
    template<> struct PixelFormatID<PixelMask<Vector<uint16, 3> > >   { static const PixelFormatEnum value = VW_PIXEL_GENERIC_4_CHANNEL; };
    template<> struct PixelFormatID<PixelMask<Vector<uint16, 4> > >   { static const PixelFormatEnum value = VW_PIXEL_GENERIC_5_CHANNEL; };
    template<> struct PixelFormatID<PixelMask<Vector<uint16, 5> > >   { static const PixelFormatEnum value = VW_PIXEL_GENERIC_6_CHANNEL; };
    template<> struct PixelFormatID<PixelMask<Vector<uint16, 6> > >   { static const PixelFormatEnum value = VW_PIXEL_GENERIC_7_CHANNEL; };
    template<> struct PixelFormatID<PixelMask<Vector<uint16, 7> > >   { static const PixelFormatEnum value = VW_PIXEL_GENERIC_8_CHANNEL; };
    template<> struct PixelFormatID<PixelMask<Vector<uint16, 8> > >   { static const PixelFormatEnum value = VW_PIXEL_GENERIC_9_CHANNEL; };
    
    // ChannelTypeID<>
    /// Get the VW enum for a data type.
    template <class ChannelT> struct ChannelTypeID { static const ChannelTypeEnum value = VW_CHANNEL_UNKNOWN; };
    template<> struct ChannelTypeID<vw::int8>      { static const ChannelTypeEnum value = VW_CHANNEL_INT8; };
    template<> struct ChannelTypeID<vw::uint8>     { static const ChannelTypeEnum value = VW_CHANNEL_UINT8; };
    template<> struct ChannelTypeID<vw::int16>     { static const ChannelTypeEnum value = VW_CHANNEL_INT16; };
    template<> struct ChannelTypeID<vw::uint16>    { static const ChannelTypeEnum value = VW_CHANNEL_UINT16; };
    template<> struct ChannelTypeID<vw::int32>     { static const ChannelTypeEnum value = VW_CHANNEL_INT32; };
    template<> struct ChannelTypeID<vw::uint32>    { static const ChannelTypeEnum value = VW_CHANNEL_UINT32; };
    template<> struct ChannelTypeID<vw::int64>     { static const ChannelTypeEnum value = VW_CHANNEL_INT64; };
    template<> struct ChannelTypeID<vw::uint64>    { static const ChannelTypeEnum value = VW_CHANNEL_UINT64; };
    template<> struct ChannelTypeID<vw::float32>   { static const ChannelTypeEnum value = VW_CHANNEL_FLOAT32; };
    template<> struct ChannelTypeID<vw::float64>   { static const ChannelTypeEnum value = VW_CHANNEL_FLOAT64; };
    template<> struct ChannelTypeID<bool>          { static const ChannelTypeEnum value = VW_CHANNEL_BOOL; };
  
    // This function determines whether a POD-style copy is sufficient
    bool simple_conversion(PixelFormatEnum a, PixelFormatEnum b);
    bool simple_conversion(ChannelTypeEnum a, ChannelTypeEnum b);
  
    uint32          channel_size        ( ChannelTypeEnum type    );
    uint32          channel_size_nothrow( ChannelTypeEnum type    );
    const char *    channel_type_name   ( ChannelTypeEnum type    );
    uint32          num_channels        ( PixelFormatEnum format  ); ///< Return the number of channels of a PixelFormatEnum.
    uint32          num_channels_nothrow( PixelFormatEnum format  );
    const char *    pixel_format_name   ( PixelFormatEnum format  );
    ChannelTypeEnum channel_name_to_enum( const std::string& name );
  
  } // namespace vw
  
  #endif // __VW_IMAGE_PIXELTYPEINFO_H__
  