From: Foster B. <fos...@us...> - 2006-01-09 19:41:19
|
Update of /cvsroot/adobe-source/adobe-source/adobe/gil/core In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv21157 Added Files: algorithm.hpp channel.hpp cmyk.hpp color_convert.hpp gil_concept.hpp gil_config.hpp gray.hpp image.hpp image_view_factory.hpp lab.hpp metafunctions.hpp pixel.hpp pixel_iterator.hpp rgb.hpp rgba.hpp typedefs.hpp utilities.hpp variant.hpp Log Message: asl 1.0.12 stragglers --- NEW FILE: image.hpp --- /* Copyright 2005-2006 Adobe Systems Incorporated Distributed under the MIT License (see accompanying file LICENSE_1_0_0.txt or a copy at http://opensource.adobe.com/licenses.html) */ /*************************************************************************************************/ #ifndef GIL_IMAGE_H #define GIL_IMAGE_H //////////////////////////////////////////////////////////////////////////////////////// /// \file /// \brief Templated image /// \author Lubomir Bourdev and Hailin Jin \n /// Adobe Systems Incorporated /// /// //////////////////////////////////////////////////////////////////////////////////////// #include "gil_config.hpp" #include <memory> #include "pixel_iterator.hpp" ADOBE_GIL_NAMESPACE_BEGIN template <typename V1, typename V2> void copy_pixels(const V1& src, const V2& dst); #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable : 4244) // conversion from 'gil::image<V,ALLOC>::coord_type' to 'int', possible loss of data (visual studio compiler doesn't realize that the two types are the same) #endif //////////////////////////////////////////////////////////////////////////////////////// /// \class image_view /// \ingroup ImageView /// \brief A lightweight object that interprets memory as a 2D array of pixels. /// /// Image view consists of a pixel 2D locator (defining the mechanism for navigating in 2D) /// and the image dimensions. /// /// Image views to images are what ranges are to STL containers. They are lightweight objects, /// that don't own the pixels. It is the user's responsibility that the underlying data remains /// valid for the lifetime of the image view. /// /// Similar to iterators and ranges, constness of views does not extend to constness of pixels. /// A const image_view does not allow changing its location in memory (resizing, moving) but does /// not prevent one from changing the pixels. The latter requires an image view whose value_type /// is const. /// /// Images have interfaces consistent with STL 1D random access containers, so they can be used /// directly in STL algorithms like: /// std::fill(img.begin(), img.end(), red_pixel); /// or /// std::transform(img.begin(), img.end(), dst.begin(), color_converter<rgb8_pixel>()); // convert src to RGB /// /// In addition, horizontal, vertical and 2D random access iterators are provided. /// //////////////////////////////////////////////////////////////////////////////////////// template <typename LOC> class pixel_image_iterator; template <typename LOC> // Models 2D Pixel Locator class image_view { GIL_CLASS_REQUIRE(LOC, GIL, XYLocatorConcept); public: // typedefs required by ConstRandomAccessNDImageViewConcept static const size_t num_dimensions=2; typedef typename LOC::value_type value_type; typedef typename LOC::reference reference; // result of dereferencing typedef typename LOC::coord_type coord_type; // 1D difference type (same for all dimensions) typedef coord_type difference_type; // result of operator-(1d_iterator,1d_iterator) typedef value_type domain_type; typedef typename LOC::point_type point_type; typedef LOC locator; typedef image_view<typename LOC::const_type> const_type; // same as this type, but over const values template <size_t D> struct axis { typedef typename LOC::template axis<D>::coord_type coord_type; // difference_type along each dimension typedef typename LOC::template axis<D>::iterator iterator; // 1D iterator type along each dimension }; typedef pixel_image_iterator<LOC> iterator; // 1D iterator type for each pixel left-to-right inside top-to-bottom typedef std::reverse_iterator<iterator> reverse_iterator; typedef size_t size_type; // typedefs required by ConstRandomAccess2DImageViewConcept typedef locator xy_locator; typedef typename xy_locator::x_iterator x_iterator; // pixel iterator along a row typedef typename xy_locator::y_iterator y_iterator; // pixel iterator along a column typedef typename xy_locator::x_coord_type x_coord_type; typedef typename xy_locator::y_coord_type y_coord_type; // typedefs required by ConstRandomAccess2DImageViewConcept typedef image_view<typename LOC::dynamic_step_type> dynamic_step_type; typedef typename LOC::channel_type channel_type; // type of the channel of a pixel typedef typename LOC::color_space_type color_space_type;// tag indicating the color space of an image image_view() : _dimensions(0,0) {} template <typename VIEW> image_view(const VIEW& iv) : _dimensions(iv.dimensions()), _pixels(iv.pixels()) {} template <typename L2> image_view(const point_type& sz , const L2& loc) : _dimensions(sz), _pixels(loc) {} template <typename L2> image_view(coord_type width, coord_type height, const L2& loc) : _dimensions(x_coord_type(width),y_coord_type(height)), _pixels(loc) {} image_view(const point_type& sz , const x_iterator& x_it, coord_type row_bytes) : _dimensions(sz), _pixels(x_it, row_bytes) {} image_view(coord_type width, coord_type height, const x_iterator& x_it, coord_type row_bytes) : _dimensions(x_coord_type(width),y_coord_type(height)), _pixels(x_it, row_bytes) {} template <typename VIEW> image_view& operator=(const VIEW& iv) { _pixels=iv.pixels(); _dimensions=iv.dimensions(); return *this; } image_view& operator=(const image_view& iv) { _pixels=iv.pixels(); _dimensions=iv.dimensions(); return *this; } template <typename VIEW> bool operator==(const VIEW& v) const { return pixels()==v.pixels() && dimensions()==v.dimensions(); } template <typename VIEW> bool operator!=(const VIEW& v) const { return !(*this==v); } template <typename L2> friend void swap(image_view<L2>& x, image_view<L2>& y); const point_type& dimensions() const { return _dimensions; } const locator& pixels() const { return _pixels; } x_coord_type width() const { return dimensions().x; } y_coord_type height() const { return dimensions().y; } difference_type row_bytes() const { return _pixels.row_bytes(); } // number of bytes per row difference_type pix_bytestep() const { return _pixels.pix_bytestep(); } // number of bytes between two adjacent pixels on the same row //\{@ /// \name 1D navigation size_type size() const { return width()*height(); } iterator begin() const { return iterator(_pixels,_dimensions.x); } iterator end() const { return begin()+size(); } // potential performance problem! reverse_iterator rbegin() const { return reverse_iterator(end()); } reverse_iterator rend() const { return reverse_iterator(begin()); } reference operator[](difference_type i) const { return begin()[i]; } // potential performance problem! iterator at(const point_type& p)const { return begin()+p.y*width()+p.x; } iterator at(x_coord_type x, y_coord_type y)const { return begin()+y*width()+x; } //\}@ //\{@ /// \name 2-D navigation reference operator()(const point_type& p) const { return _pixels(p.x,p.y); } reference operator()(x_coord_type x, y_coord_type y)const { return _pixels(x,y); } template <size_t D> typename axis<D>::iterator axis_iterator(const point_type& p) const { return _pixels.axis_iterator<D>(p); } xy_locator xy_at(x_coord_type x, y_coord_type y) const { return _pixels+point_type(x_coord_type(x),y_coord_type(y)); } locator xy_at(const point_type& p) const { return _pixels+p; } //\}@ //\{@ /// \name X navigation x_iterator x_at(x_coord_type x, y_coord_type y) const { return _pixels.x_at(x,y); } x_iterator x_at(const point_type& p) const { return _pixels.x_at(p); } x_iterator row_begin(y_coord_type y) const { return x_at(0,y); } x_iterator row_end(y_coord_type y) const { return x_at(width(),y); } //\}@ //\{@ /// \name Y navigation y_iterator y_at(x_coord_type x, y_coord_type y) const { return xy_at(x,y).y(); } y_iterator y_at(const point_type& p) const { return xy_at(p).y(); } y_iterator col_begin(x_coord_type x) const { return y_at(x,0); } y_iterator col_end(x_coord_type x) const { return y_at(x,height()); } //\}@ private: template <typename L2> friend class image_view; point_type _dimensions; xy_locator _pixels; }; template <typename L2> inline void swap(image_view<L2>& x, image_view<L2>& y) { std::swap(x._dimensions,y._dimensions); std::swap(x._pixels, y._pixels); // TODO: Extend further } //////////////////////////////////////////////////////////////////////////////////////// /// \class image /// \ingroup Image /// \brief container interface over image view /// /// image is a wrapper over image_view that owns the data. /// Images have deep copy constructor, operator= and operator==. /// A constant image does not allow for modifying its pixels. //////////////////////////////////////////////////////////////////////////////////////// template <typename V2,typename ALLOC2> void swap(image<V2,ALLOC2>& im1,image<V2,ALLOC2>& im2); template <typename V, typename ALLOC=std::allocator<unsigned char> > class image { public: typedef ALLOC allocator_type; typedef V view_type; typedef typename view_type::const_type const_view_type; typedef typename view_type::point_type point_type; typedef typename view_type::coord_type coord_type; typedef coord_type x_coord_type; typedef coord_type y_coord_type; typedef typename view_type::iterator iterator; typedef iterator pointer; typedef typename const_view_type::iterator const_iterator; typedef const_iterator const_pointer; typedef typename view_type::difference_type difference_type; typedef typename view_type::value_type value_type; typedef typename view_type::reference reference; typedef typename const_view_type::reference const_reference; typedef typename view_type::size_type size_type; typedef typename view_type::reverse_iterator reverse_iterator; typedef typename const_view_type::reverse_iterator const_reverse_iterator; const_iterator begin() const { return const_view(*this).begin(); } const_iterator end() const { return const_view(*this).end(); } const_reverse_iterator rbegin() const { return const_view(*this).rbegin(); } const_reverse_iterator rend() const { return const_view(*this).rend(); } iterator begin() { return _view.begin(); } iterator end() { return _view.end(); } reverse_iterator rbegin() { return _view.rbegin(); } reverse_iterator rend() { return _view.rend(); } reference operator[](size_type i) { return _view[i]; } const_reference operator[](size_type i) const { return const_view(*this)[i]; } // Warning: Slow!! size_type size() const { return _view.size(); } size_type max_size() const { return size(); } bool empty() const { return size()==0; } const point_type& dimensions() const { return _view.dimensions(); } x_coord_type width() const { return _view.width(); } y_coord_type height() const { return _view.height(); } image() {} // image that allocates own data. Calls new/delete[] image(const point_type& dimensions, unsigned int alignment=1) { create_with_own_data(dimensions,alignment); } image(x_coord_type width, y_coord_type height, unsigned int alignment=1) { create_with_own_data(point_type(width,height),alignment); } image(const image& img) : _alloc(img._alloc) { create_with_own_data(const_view(img).dimensions()); // TODO: Use the same alignment copy_pixels(const_view(img),_view); } template <typename V2,typename ALLOC2> image(const image<V2,ALLOC2>& img) :_alloc(img._alloc) { create_with_own_data(view(img).dimensions()); copy_pixels(view(img),_view); } template <typename IMG> image& operator=(const IMG& img) { image tmp(img); swap(tmp); return *this; } image& operator=(const image& img) { image tmp(img); swap(tmp); return *this; } ~image() { size_t size_in_bytes=_view.row_bytes()*_view.height(); if(std::iterator_traits<typename V::x_iterator>::is_planar) size_in_bytes*=V::color_space_type::num_channels; _alloc.deallocate((unsigned char*)&(_view(0,0)[0]),size_in_bytes); } template <typename V2, typename ALLOC2> friend const V2& view(image<V2,ALLOC2>& img); template <typename V2, typename ALLOC2> friend const typename V2::const_type& const_view(const image<V2,ALLOC2>& img); ALLOC& allocator() { return _alloc; } ALLOC const& allocator() const { return _alloc; } template <typename V2,typename ALLOC2> friend void swap(image<V2,ALLOC2>& im1,image<V2,ALLOC2>& im2); void swap(image& img) { GIL::swap(*this,img); } // required by boost::MutableContainerConcept private: view_type _view; // contains pointer to the pixels, the image size and ways to navigate pixels allocator_type _alloc; template <bool> class is_planar {}; void create_with_own_data(const point_type& dimensions, unsigned int alignment=1) { BOOST_STATIC_ASSERT(!has_dynamic_step<typename V::x_iterator>::value); create_with_own_data_(dimensions,alignment,is_planar<std::iterator_traits<typename V::x_iterator>::is_planar>()); } void create_with_own_data_(const point_type& dimensions, unsigned int alignment, is_planar<false>) { size_t rowsize_in_bytes=get_aligned(dimensions.x*sizeof(typename V::value_type),alignment); unsigned char* tmp=_alloc.allocate(rowsize_in_bytes*dimensions.y); try { _view=V(dimensions,typename V::x_iterator(tmp),rowsize_in_bytes); } catch(...) { _alloc.deallocate(tmp, rowsize_in_bytes*dimensions.y); throw; } } void create_with_own_data_(const point_type& dimensions, unsigned int alignment, is_planar<true>) { size_t planesize_in_bytes=get_aligned(dimensions.x*dimensions.y*sizeof(typename V::channel_type),alignment); size_t image_size_in_bytes=planesize_in_bytes*V::color_space_type::num_channels; unsigned char* tmp=_alloc.allocate(image_size_in_bytes); try { _view=V(dimensions, typename V::x_iterator(tmp,planesize_in_bytes),dimensions.x*sizeof(typename V::channel_type)); } catch(...) { _alloc.deallocate(tmp, image_size_in_bytes); throw; } } }; template <typename V1,typename V2> bool operator==(const image<V1>& im1,const image<V2>& im2) { if (&im1==&im2) return true; if (const_view(im1).dimensions()!=const_view(im2).dimensions()) return false; return std::equal(const_view(im1).begin(),const_view(im1).end(),const_view(im2).begin()); // TODO: change this to equal_pixels (for performance) } template <typename V1,typename V2> bool operator!=(const image<V1>& im1,const image<V2>& im2) {return !(im1==im2);} template <typename V2,typename ALLOC2> inline void swap(image<V2,ALLOC2>& im1,image<V2,ALLOC2>& im2) { swap(im1._view, im2._view); std::swap(im1.allocator(), im2.allocator()); } template <typename C> class variant; namespace detail { template <typename VC> // Models View Concept Space struct any_image_get_view { typedef variant<VC> result_type; template <typename V> result_type operator()( image<V>& img) const { return result_type(view(img)); } }; template <typename VC> // Models ConstView Concept Space struct any_image_get_const_view { typedef variant<VC> result_type; template <typename V> result_type operator()(const image<V>& img) const { return result_type(const_view(img)); } }; struct any_image_view_get_num_channels { typedef int result_type; template <typename VIEW> result_type operator()(const VIEW& v) const { return VIEW::color_space_type::num_channels; } }; struct any_image_view_get_dimensions { typedef point2<ptrdiff_t> result_type; template <typename VIEW> result_type operator()(const VIEW& v) const { return v.dimensions(); } }; } ///@{ /// \name view, const_view /// \brief Get an image view from an image /// \ingroup Image /// \brief Returns the non-constant-pixel view of an image template <typename V2, typename ALLOC2> inline const V2& view(image<V2,ALLOC2>& img) { return img._view; } /// \brief Returns the constant-pixel view of an image template <typename V2, typename ALLOC2> inline const typename V2::const_type& const_view(const image<V2,ALLOC2>& img) { return (typename V2::const_type&)img._view; } /// \brief Returns the non-constant-pixel view of any image. The returned view is any view. See variant.h for more template <typename IC> // Models Image Concept Space inline variant<typename IC::view_concept_space> view(variant<IC>& anyImage) { return anyImage.apply_visitor(detail::any_image_get_view<typename IC::view_concept_space>()); } /// \brief Returns the constant-pixel view of any image. The returned view is any view. See variant.h for more template <typename IC> // Models Image Concept Space inline variant<typename IC::const_view_concept_space> const_view(const variant<IC>& anyImage) { return anyImage.apply_visitor(detail::any_image_get_const_view<typename IC::const_view_concept_space>()); } ///@} ///@{ /// \name get_num_channels /// \brief Returns the number of channels of an image view /// \ingroup ImageView template <typename LOC> int get_num_channels(const image_view<LOC>& view) { return image_view<LOC>::color_space_type::num_channels; } template <typename C_S> int get_num_channels(const variant<C_S>& img_view) { return img_view.apply_visitor(detail::any_image_view_get_num_channels()); } ///@} ///@{ /// \name get_width, get_height, get_dimensions /// \brief Returns the dimensions of an image view /// \ingroup ImageView /// \brief Returns the width of a templated image view template <typename LOC> int get_width(const image_view<LOC>& view) { return view.width(); } /// \brief Returns the width of any image view template <typename C_S> int get_width(const variant<C_S>& img_view) { return img_view.apply_visitor(detail::any_image_view_get_dimensions()).x; } /// \brief Returns the height of a templated image view template <typename LOC> int get_height(const image_view<LOC>& view) { return view.width(); } /// \brief Returns the height of any image view template <typename C_S> int get_height(const variant<C_S>& img_view) { return img_view.apply_visitor(detail::any_image_view_get_dimensions()).y; } /// \brief Returns the dimensions of a templated image view template <typename LOC> point2<int> get_dimensions(const image_view<LOC>& view) { return view.dimensions(); } /// \brief Returns the dimensions of any image view template <typename C_S> point2<int> get_dimensions(const variant<C_S>& img_view) { return img_view.apply_visitor(detail::any_image_view_get_dimensions()); } ///@} ///@{ /// \name resize_clobber_image /// \brief Resizes a given image and invalidates its pixel values. If out of memory exception is thrown the image remains unchanged /// \ingroup Image template <typename IMG> void resize_clobber_image(IMG& img, const typename IMG::point_type& new_size) { gil_function_requires<ImageConcept<IMG> >(); IMG tmp(new_size); swap(tmp,img); } template <typename IMG> void resize_clobber_image(IMG& img, const typename IMG::x_coord_type& width, const typename IMG::y_coord_type& height) { resize_clobber_image(img, typename IMG::point_type(width,height)); } ///@} #ifdef _MSC_VER #pragma warning(pop) #endif ADOBE_GIL_NAMESPACE_END #endif --- NEW FILE: cmyk.hpp --- /* Copyright 2005-2006 Adobe Systems Incorporated Distributed under the MIT License (see accompanying file LICENSE_1_0_0.txt or a copy at http://opensource.adobe.com/licenses.html) */ /*************************************************************************************************/ #ifndef GIL_CMYK_H #define GIL_CMYK_H //////////////////////////////////////////////////////////////////////////////////////// /// \file /// \brief Support for CMYK color space and variants /// \author Lubomir Bourdev and Hailin Jin \n /// Adobe Systems Incorporated //////////////////////////////////////////////////////////////////////////////////////// #include "gil_config.hpp" #include <boost/type_traits.hpp> ADOBE_GIL_NAMESPACE_BEGIN //forward declarations for pixel and color_base template <typename T, typename C> struct pixel; namespace detail { template <typename T, typename C> struct color_base; } template <typename T, typename C> struct planar_ptr; template <typename T, typename C> struct planar_ptr_base; /// @defgroup CMYK CMYK Color Space /// @ingroup ColorSpaces /// \brief Constructs and utilities specific to the CMYK color space /// \brief CMYK color space identifier /// \ingroup CMYK struct cmyk_tag { typedef cmyk_tag base; BOOST_STATIC_CONSTANT(int, num_channels=4); }; namespace detail { /// \ingroup ColorBase /// \ingroup CMYK /// \brief cyan, magenta, yellow and black channel values/references/pointers /// /// Represents a CMYK unit of channel values (when used to construct a pixel), channel references (when used in a planar CMYK reference) /// or channel pointers (when used in a CMYK planar pointer) defined in this specific ordering in memory. Also provides channel accessors /// v0(), v1(), v2(), v3() agnostic of color space, which allow uniform operations on channels of different color spaces. The accessors also have /// consistent mapping between color bases representing order variations of the same color space. For example, v0() returns the red /// channel value/reference/pointer in both an rgb color base and in a bgr color base. template <typename T> struct color_base<T,cmyk_tag> { typedef cmyk_tag color_space_type; typedef T channel_type; typedef typename boost::add_const<channel_type>::type channel_const_type; typedef typename boost::add_reference<channel_type>::type channel_reference; typedef typename boost::add_reference<channel_const_type>::type channel_const_reference; T c,m,y,k; color_base() {} color_base(channel_type v0, channel_type v1, channel_type v2, channel_type v3) : c(v0), m(v1), y(v2), k(v3) {} template <typename T1, typename C1> color_base(const color_base<T1,C1>& cb) : c(cb.c), m(cb.m), y(cb.y), k(cb.k) {} template <typename T1, typename C1> color_base( color_base<T1,C1>& cb) : c(cb.c), m(cb.m), y(cb.y), k(cb.k) {} }; } ADOBE_GIL_NAMESPACE_END #include "pixel_iterator.hpp" // these need to be defined after including pixel... ADOBE_GIL_NAMESPACE_BEGIN //////////////////////////////////////////////////////////////////////////////////////// /// PLANAR CMYK //////////////////////////////////////////////////////////////////////////////////////// /// \brief Represents a pointer to a planar CMYK pixel. /// \ingroup PlanarPtr /// \ingroup CMYK /// /// A pointer can be constructed from and assigned to the address of a value, the address of a reference or another pointer /// It can also be dereferenced returning a reference template <typename T> struct planar_ptr<T,cmyk_tag> : public planar_ptr_base<T,cmyk_tag> { typedef planar_ptr_base<T,cmyk_tag> parent_type; typedef typename parent_type::reference reference; typedef typename parent_type::color_space_type color_space_type; planar_ptr() : parent_type(0,0,0,0) {} planar_ptr(T* ic, T* im, T* iy, T* ik) : parent_type(ic,im,iy,ik) {} // from raw data planar_ptr(unsigned char* data, ptrdiff_t step=1) : parent_type((T*)data, (T*)(data+step), (T*)(data+step+step), (T*)(data+step*3)) {} planar_ptr(const planar_ptr& ptr) : parent_type(ptr) {} planar_ptr& operator=(const planar_ptr& ptr) { this->p=ptr.p; return *this; } /// Copy constructor and operator= from pointers to compatible planar pixels or planar pixel references. /// That allow constructs like pointer = &value or pointer = &reference /// Since we should not override operator& that's the best we can do. template <typename T1, typename C1> planar_ptr(pixel<T1,C1>* pix) : parent_type(&pix->template v<0>(),&pix->template v<1>(), &pix->template v<2>(), &pix->template v<3>()) { STATIC_ASSERT_COMPATIBLE(T1,C1,T,color_space_type); } template <typename T1, typename C1> planar_ptr& operator=(pixel<T1,C1>* pix) { STATIC_ASSERT_COMPATIBLE(T1,C1,T,color_space_type); this->p.template v<0>()=&pix->template v<0>(); this->p.template v<1>()=&pix->template v<1>(); this->p.template v<2>()=&pix->template v<2>(); this->p.template v<3>()=&pix->template v<3>(); return *this; } reference dereference() const { return reference(*(this->p.c),*(this->p.m),*(this->p.y),*(this->p.k)); } }; /// \ingroup byte_advanced_ref /// Advancing a CMYK pixel by a given number of bytes template <typename T> inline pixel<T&,cmyk_tag> byte_advanced_ref(const planar_ptr<T,cmyk_tag>& p, ptrdiff_t byteDiff) { return pixel<T&,cmyk_tag>(*byte_advanced(p.p.c, byteDiff), *byte_advanced(p.p.m, byteDiff), *byte_advanced(p.p.y, byteDiff), *byte_advanced(p.p.k, byteDiff)); } namespace detail { template <typename CS,int N> struct logical_channel_accessor; /// \ingroup ChannelAccessor template <> struct logical_channel_accessor<cmyk_tag,0> { template <typename T> typename boost::add_reference<T>::type operator()(pixel<T,cmyk_tag>& p) const {return p.c;} template <typename T> typename boost::add_reference<typename boost::add_const<T>::type>::type operator()(const pixel<T,cmyk_tag>& p) const {return p.c;} }; /// \ingroup ChannelAccessor template <> struct logical_channel_accessor<cmyk_tag,1> { template <typename T> typename boost::add_reference<T>::type operator()(pixel<T,cmyk_tag>& p) const {return p.m;} template <typename T> typename boost::add_reference<typename boost::add_const<T>::type>::type operator()(const pixel<T,cmyk_tag>& p) const {return p.m;} }; /// \ingroup ChannelAccessor template <> struct logical_channel_accessor<cmyk_tag,2> { template <typename T> typename boost::add_reference<T>::type operator()(pixel<T,cmyk_tag>& p) const {return p.y;} template <typename T> typename boost::add_reference<typename boost::add_const<T>::type>::type operator()(const pixel<T,cmyk_tag>& p) const {return p.y;} }; /// \ingroup ChannelAccessor template <> struct logical_channel_accessor<cmyk_tag,3> { template <typename T> typename boost::add_reference<T>::type operator()(pixel<T,cmyk_tag>& p) const {return p.k;} template <typename T> typename boost::add_reference<typename boost::add_const<T>::type>::type operator()(const pixel<T,cmyk_tag>& p) const {return p.k;} }; } ADOBE_GIL_NAMESPACE_END #endif --- NEW FILE: pixel.hpp --- /* Copyright 2005-2006 Adobe Systems Incorporated Distributed under the MIT License (see accompanying file LICENSE_1_0_0.txt or a copy at http://opensource.adobe.com/licenses.html) */ /*************************************************************************************************/ #ifndef GIL_PIXEL_H #define GIL_PIXEL_H //////////////////////////////////////////////////////////////////////////////////////// /// \file /// \brief generic pixel definitions and utilities /// \author Lubomir Bourdev and Hailin Jin \n /// Adobe Systems Incorporated /// Last updated on 11-06-2005 /// //////////////////////////////////////////////////////////////////////////////////////// #include "gil_config.hpp" #include "gil_concept.hpp" #include "channel.hpp" #include <boost/static_assert.hpp> #include <boost/utility/enable_if.hpp> #include <functional> #include "metafunctions.hpp" #include "utilities.hpp" ADOBE_GIL_NAMESPACE_BEGIN namespace detail { /// \addtogroup ColorBase /// \brief Represents a bundle of channel values/references/pointers for a specific color space. /// /// The class is used in three different cases: /// - As a base for pixel values, in which case it instantiates into a set of channel values whose relative ordering is specified by C /// - As a base for the proxy class representing a reference to a planar pixel, in which case it instantiates into a set of channel references /// - In the construction of planar_ptr, the proxy class representing a pointer to a planar pixel, in which case in instantiates into a set of channel pointers /// /// Color bases also provide color-space independent accessors to the channel values/references/pointers, which allows us to perform color-space-independent /// channel operations (see pixel_base for more). /// /// color_base specializations are provided for each color space. See concrete specializations for more. template <typename T, typename C> struct color_base {}; /// \ingroup ColorConvert /// \brief Color Convertion function object. To be specialized for every src/dst color space template <typename T1, typename C1, typename T2, typename C2> struct _color_converter { template <typename P1, typename P2> void operator()(const P1& src, P2& dst); }; /// \addtogroup ChannelAccessor /// /// Returns the N-th logical channel of a pixel. Logical channel indices are the same across related color spaces. For example, the red channel has index 0 in both rgb and bgr /// Specialized for each index and each color space. Instead of this class, it would be easier to provide in each color base specialization a /// member function templated over the channel index. Unfortunately many compilers don't support fully specialized member functions inside partially specialized classes. template <typename CS,int N> struct logical_channel_accessor {}; /// \brief Returns the N-th channel of a pixel as laid down in memory /// \ingroup ChannelAccessor template <typename CS> struct physical_channel_accessor { // pixel has the structure of an array of T. Getting a reference to the i-th value template <typename T> T& operator()(pixel<T,CS>& p,size_t i) const { return ((T*)(&p))[i]; } template <typename T> const T& operator()(const pixel<T,CS>& p,size_t i) const {return ((const T*)(&p))[i]; } // pixel is an array of _references_ to T. Getting the i-th reference template <typename T> T& operator()(pixel<T&,CS>& p,size_t i) const { return *(((T**)((T*)&p))[i]); } template <typename T> const T& operator()(pixel<const T&,CS>& p,size_t i) const { return *(((const T**)((const T*)&p))[i]); } }; /// \brief compile-time recursion for per-channel operations of pixels /// \ingroup Pixel template <int N> struct recur { template <typename P,typename F> static void multiplies_eq(P& p, F x) { recur<N-1>::multiplies_eq(p,x); p.template v<N>()*=x; } template <typename P,typename F> static void divides_eq(P& p, F x) { recur<N-1>::divides_eq(p,x); p.template v<N>()/=x; } template <typename P1,typename P2> static void set_val(P1& p1, const P2& p2) { recur<N-1>::set_val(p1,p2); p1.template v<N>()=p2.template v<N>(); } template <typename P1,typename P2> static void plus_eq(P1& p1, const P2& p2) { recur<N-1>::plus_eq(p1,p2); p1.template v<N>()+=p2.template v<N>(); } template <typename P1,typename P2> static void minus_eq(P1& p1, const P2& p2) { recur<N-1>::minus_eq(p1,p2); p1.template v<N>()-=p2.template v<N>(); } template <typename P,typename T2> static void set_channels(P& p, T2 v) { recur<N-1>::set_channels(p,v); p.template v<N>()=v; } template <typename P1,typename P2> static bool equal_to(const P1& p1, const P2& p2) { return recur<N-1>::equal_to(p1,p2) && p1.template v<N>()==p2.template v<N>(); } template <typename OP,typename P1> static void per_channel_op(const P1& p1, OP& op) { recur<N-1>::per_channel_op(p1,op); op(p1.template v<N>()); } template <typename OP, typename P1,typename P2> static void per_channel_op(const P1& p1, const P2& p2, OP& op) { recur<N-1>::per_channel_op(p1,p2,op); op(p1.template v<N>(), p2.template v<N>()); } template <typename OP, typename P1,typename P2, typename P3> static void per_channel_op(const P1& p1, const P2& p2, const P3& p3, OP& op) { recur<N-1>::per_channel_op(p1,p2,p3,op); op(p1.template v<N>(), p2.template v<N>(), p3.template v<N>()); } template <typename OP,typename P> static void per_channel_set_op(P& dst, OP& op) { recur<N-1>::per_channel_set_op(dst,op); dst.template v<N>()=op(); } template <typename OP,typename P, typename P1> static void per_channel_set_op(P& dst, const P1& src, OP& op) { recur<N-1>::per_channel_set_op(dst,src,op); dst.template v<N>()=op(src.template v<N>()); } template <typename OP,typename P,typename P1, typename P2> static void per_channel_set_op(P& dst, const P1& src1, const P2& src2, OP& op) { recur<N-1>::per_channel_set_op(dst,src1,src2,op); dst.template v<N>()=op(src1.template v<N>(), src2.template v<N>()); } //#ifdef PROVIDE_CONST_VERSIONS template <typename OP,typename P1> static void per_channel_op(const P1& p1, const OP& op) { recur<N-1>::per_channel_op(p1,op); op(p1.template v<N>()); } template <typename OP, typename P1,typename P2> static void per_channel_op(const P1& p1, const P2& p2, const OP& op) { recur<N-1>::per_channel_op(p1,p2,op); op(p1.template v<N>(), p2.template v<N>()); } template <typename OP, typename P1, typename P2, typename P3> static void per_channel_op(const P1& p1, const P2& p2, const P3& p3, const OP& op) { recur<N-1>::per_channel_op(p1,p2,p3,op); op(p1.template v<N>(), p2.template v<N>(), p3.template v<N>()); } template <typename OP,typename P> static void per_channel_set_op(P& dst, const OP& op) { recur<N-1>::per_channel_set_op(dst,op); dst.template v<N>()=op(); } template <typename OP,typename P,typename P1> static void per_channel_set_op(P& dst, const P1& src, const OP& op) { recur<N-1>::per_channel_set_op(dst,src,op); dst.template v<N>()=op(src.template v<N>()); } template <typename OP,typename P,typename P1,typename P2> static void per_channel_set_op(P& dst, const P1& src1, const P2& src2, const OP& op) { recur<N-1>::per_channel_set_op(dst,src1,src2,op); dst.template v<N>()=op(src1.template v<N>(), src2.template v<N>()); } //#endif }; /// \brief termination condition of the compile-time recursion for channel operations on a pixel /// \ingroup Pixel template<> struct recur<-1> { template <typename P, typename F> static void multiplies_eq(P& p, F x) {} template <typename P, typename F> static void divides_eq(P& p, F x) {} template <typename P1,typename P2> static void set_val(P1& p1, const P2& p2) {} template <typename P1,typename P2> static void plus_eq(P1& p1, const P2& p2) {} template <typename P1,typename P2> static void minus_eq(P1& p1, const P2& p2) {} template <typename P, typename T2> static void set_channels(P& p, T2 v) {} template <typename P1,typename P2> static bool equal_to(const P1& p1, const P2& p2) { return true; } template <typename OP,typename P1> static void per_channel_op(const P1&,OP&){} template <typename OP,typename P1,typename P2> static void per_channel_op(const P1&,const P2&,OP&){} template <typename OP,typename P1,typename P2,typename P3> static void per_channel_op(const P1&,const P2&,const P3&,OP&){} template <typename OP,typename P> static void per_channel_set_op(P&,OP&){} template <typename OP,typename P, typename P1> static void per_channel_set_op(P&,const P1&,OP&){} template <typename OP,typename P, typename P1, typename P2> static void per_channel_set_op(P&,const P1&,const P2&,OP&){} //#ifdef PROVIDE_CONST_VERSIONS template <typename OP,typename P1> static void per_channel_op(const P1&,const OP&){} template <typename OP,typename P1,typename P2> static void per_channel_op(const P1&,const P2&,const OP&){} template <typename OP,typename P1,typename P2,typename P3> static void per_channel_op(const P1&,const P2&,const P3&,const OP&){} template <typename OP,typename P> static void per_channel_set_op(P&,const OP&){} template <typename OP,typename P, typename P1> static void per_channel_set_op(P&,const P1&,const OP&){} template <typename OP,typename P, typename P1, typename P2> static void per_channel_set_op(P&,const P1&,const P2&,const OP&){} //#endif }; /// \brief compile-time recursion for min/max channel /// \ingroup Pixel template <int N> struct min_max_recur { template <typename P> static typename P::channel_value_type max_(const P& p) { return std::max(min_max_recur<N-1>::max_(p),p.template v<N>()); } template <typename P> static typename P::channel_value_type min_(const P& p) { return std::min(min_max_recur<N-1>::min_(p),p.template v<N>()); } }; /// \brief termination condition of the compile-time recursion for min/max channel /// \ingroup Pixel template <> struct min_max_recur<0> { template <typename P> static typename P::channel_value_type max_(const P& p) { return p.template v<0>(); } template <typename P> static typename P::channel_value_type min_(const P& p) { return p.template v<0>(); } }; } // namespace detail //@{ /// \name Pixel global functions /// /// Functions defined for any class that models PixelConcept /// \ingroup Pixel template <typename P> typename P::channel_value_type max_channel(const P& p) { return detail::min_max_recur<P::max_channel_index>::max_(p); } template <typename P> typename P::channel_value_type min_channel(const P& p) { return detail::min_max_recur<P::max_channel_index>::min_(p); } template <typename P> void set_channels(P& p, const typename P::channel_type& v) { detail::recur<P::max_channel_index>::set_channels(p,v); } /// \brief returns the alpha channel value for a pixel. Default returns 100% opaque. Overload for color spaces containing alpha template <typename P> typename P::channel_value_type alpha(const P& p) { return channel_traits<typename P::channel_type>::max(); } // no alpha = 100% alpha template <typename OP,typename P1> void per_channel_set_op(OP& op, P1& p1) { detail::recur<P1::max_channel_index>::per_channel_set_op(p1,op); } template <typename OP,typename P1,typename P2> void per_channel_set_op(OP& op, P1& p1,const P2& p2) { detail::recur<P1::max_channel_index>::per_channel_set_op(p1,p2,op); } template <typename OP,typename P1,typename P2,typename P3> void per_channel_set_op(OP& op, P1& p1,const P2& p2,const P3& p3) { detail::recur<P1::max_channel_index>::per_channel_set_op(p1,p2,p3,op); } template <typename OP,typename P1> void per_channel_op(OP& op,const P1& p1) { detail::recur<P1::max_channel_index>::per_channel_op(p1,op); } template <typename OP,typename P1,typename P2> void per_channel_op(OP& op,const P1& p1,const P2& p2) { detail::recur<P1::max_channel_index>::per_channel_op(p1,p2,op); } template <typename OP,typename P1,typename P2,typename P3> void per_channel_op(OP& op,const P1& p1,const P2& p2,const P3& p3){ detail::recur<P1::max_channel_index>::per_channel_op(p1,p2,p3,op); } //#ifdef PROVIDE_CONST_VERSIONS template <typename OP,typename P1> void per_channel_set_op(const OP& op, P1& p1) { detail::recur<P1::max_channel_index>::per_channel_set_op(p1,op); } template <typename OP,typename P1,typename P2> void per_channel_set_op(const OP& op, P1& p1,const P2& p2) { detail::recur<P1::max_channel_index>::per_channel_set_op(p1,p2,op); } template <typename OP,typename P1,typename P2,typename P3> void per_channel_set_op(const OP& op, P1& p1,const P2& p2,const P3& p3) { detail::recur<P1::max_channel_index>::per_channel_set_op(p1,p2,p3,op); } template <typename OP,typename P1> void per_channel_op(const OP& op,const P1& p1) { detail::recur<P1::max_channel_index>::per_channel_op(p1,op); } template <typename OP,typename P1,typename P2> void per_channel_op(const OP& op,const P1& p1,const P2& p2) { detail::recur<P1::max_channel_index>::per_channel_op(p1,p2,op); } template <typename OP,typename P1,typename P2,typename P3> void per_channel_op(const OP& op,const P1& p1,const P2& p2,const P3& p3){ detail::recur<P1::max_channel_index>::per_channel_op(p1,p2,p3,op); } //#endif //@} /// \brief Does a static assert that the two pixel values, planar references or planar pointers are compatible. /// /// In particular, their channel types are the same (ignoring reference, constness, and pointerness), and their base color spaces are the same /// (ignoring reference tags and bgr vs rgb ordering) #define STATIC_ASSERT_COMPATIBLE(T1,C1,T2,C2) BOOST_STATIC_ASSERT( \ (are_color_spaces_compatible<C1,C2>::value && \ are_channels_compatible<typename boost::remove_pointer<T1>::type,typename boost::remove_pointer<T1>::type>::value )) /// \addtogroup Pixel /// /// Models: PixelConcept /// /// Pixels are first class objects; dereferencing, assignment, copy construction, etc. are /// defined and behave as expected. /// /// \ingroup Pixel /// \brief GIL's model of PixelConcept /// /// Pixel values are represented as specializations of the pixel struct. /// Multi-channel pixels may have different channel ordering (RGB vs BGR for example). /// Each channel ordering is represented as a separate specialization of pixel /// /// Interleaved pixels have channels that are consecutive in memory. Therefore their pointers and references /// are built-in pointers and references to the value structs. Planar pixels, on the other hand, represent /// non-consecutive channels and thus pointers and references to planar pixels are represented by special classes. /// /// Pointers, references, values, color spaces and channel types of pixels are defined in iterator_traits /// of pixel iterators. /// Its base class, color_base, provides color-space specific channels. The pixel class /// provides per-channel operations that depend on the number of components but not on /// the specifics of the color space. For example, the same code is used to compare two /// BGR pixels, two LAB pixels and two planar pointers to RGB pixels. /// Per-channel operations are implemented as compile-time recursions. /// The binary per-channel operations pair channels semantically and not based on their order /// in memory. For example a binary operation between RGB and BGR color bases will properly pair /// the first channel of RGB to the third channel of BGR. This is done by using the /// semantic channel accessors v<N>() /// /// Note that pixel<T&,C> represents a bundle of references to channels. It is used as the /// reference proxy class for planar pixels. Similarly, pixel<T*,C>, a bundle of pointers to channels, /// is used in the implementation of planar_ptr<T,C>, the pointer proxy class for planar pixels. template <typename T, typename C> struct pixel : public detail::color_base<T,C> { private: typedef detail::color_base<T,C> parent_type; public: typedef C color_space_type; typedef T channel_type; typedef typename boost::add_const<channel_type>::type channel_const_type; typedef typename boost::add_reference<channel_type>::type channel_reference; typedef typename boost::add_reference<channel_const_type>::type channel_const_reference; typedef typename boost::remove_reference<channel_type>::type channel_value_type; typedef pixel<channel_value_type,color_space_type> pixel_value_type; // type to return when returning by value template <int N> struct nth_channel_type { typedef channel_type type; }; static const int max_channel_index=color_space_type::num_channels-1; pixel(){} explicit pixel(channel_type v) { set_channels(*this,v); } pixel(channel_type v0, channel_type v1) : parent_type(v0,v1) {} pixel(channel_type v0, channel_type v1, channel_type v2) : parent_type(v0,v1,v2) {} pixel(channel_type v0, channel_type v1, channel_type v2, channel_type v3) : parent_type(v0,v1,v2,v3) {} pixel(channel_type v0, channel_type v1, channel_type v2, channel_type v3, channel_type v4) : parent_type(v0,v1,v2,v3,v4) {} pixel(const pixel& p) : parent_type(p) {} template <typename T1, typename C1> pixel(const pixel<T1,C1>& p) : parent_type(p) {STATIC_ASSERT_COMPATIBLE(T,C,T1,C1);} template <typename T1, typename C1> pixel( pixel<T1,C1>& p) : parent_type(p) {STATIC_ASSERT_COMPATIBLE(T,C,T1,C1);} // copy constructor used when T is a reference pixel& operator=(const pixel& p) { detail::recur<max_channel_index>::set_val(*this,p); return *this; } template <typename T1, typename C1> pixel& operator=(const pixel<T1,C1>& p) { STATIC_ASSERT_COMPATIBLE(T,C,T1,C1); detail::recur<max_channel_index>::set_val(*this,p); return *this; } channel_reference operator[](size_t i) { return detail::physical_channel_accessor<C>()(*this,i); } channel_const_reference operator[](size_t i) const { return detail::physical_channel_accessor<C>()(*this,i); } template <typename T1, typename C1> bool operator==(const pixel<T1,C1>& p) const { STATIC_ASSERT_COMPATIBLE(T,C,T1,C1); return detail::recur<max_channel_index>::equal_to(*this,p); } template <typename T1, typename C1> bool operator!=(const pixel<T1,C1>& p) const { return !(*this==p); } template <int N> channel_const_reference v() const { return detail::logical_channel_accessor<C,N>()(*this); } template <int N> channel_reference v() { return detail::logical_channel_accessor<C,N>()(*this); } }; //@{ /// \name Pixel operator overloads /// \brief operators +=, -=, *=, /=, +, -, /, * for gil::pixel /// /// Unfortunately they can be defined only for gil::pixel. Generic implementations would have to take the pixel as a template parameter and /// would be indistinguishable from the above operators applied to any other object. /// User-defined pixels must provide separate implementations of these operators. /// \ingroup Pixel template <typename T1, typename CS1,typename T2,typename CS2> inline pixel<T1,CS1>& operator+=(pixel<T1,CS1>& p1,const pixel<T2,CS2>& p2) { STATIC_ASSERT_COMPATIBLE(T1,CS1,T2,CS2); detail::recur<CS1::num_channels-1>::plus_eq(p1,p2); return p1; } template <typename T1, typename CS1,typename T2,typename CS2> inline pixel<T1,CS1>& operator-=(pixel<T1,CS1>& p1,const pixel<T2,CS2>& p2) { STATIC_ASSERT_COMPATIBLE(T1,CS1,T2,CS2); detail::recur<CS1::num_channels-1>::minus_eq(p1,p2); return p1; } template <typename T, typename CS,typename S> inline pixel<T,CS>& operator*=(pixel<T,CS>& p,const S& x) {detail::recur<CS::num_channels-1>::multiplies_eq(p,x); return p; } template <typename T, typename CS,typename S> inline pixel<T,CS>& operator/=(pixel<T,CS>& p,const S& x) {detail::recur<CS::num_channels-1>::divides_eq(p,x); return p; } template <typename T1, typename CS1,typename T2,typename CS2> inline typename pixel<T1,CS1>::pixel_value_type operator+(const pixel<T1,CS1>& p1,const pixel<T2,CS2>& p2) { typename pixel<T1,CS1>::pixel_value_type tmp(p1); tmp+=p2; return tmp; } template <typename T1, typename CS1,typename T2,typename CS2> inline typename pixel<T1,CS1>::pixel_value_type operator-(const pixel<T1,CS1>& p1,const pixel<T2,CS2>& p2) { typename pixel<T1,CS1>::pixel_value_type tmp(p1); tmp-=p2; return tmp; } template <typename T, typename CS, typename S> inline typename pixel<T,CS>::pixel_value_type operator/(const pixel<T,CS>& p, const S& x) { typename pixel<T,CS>::pixel_value_type tmp(p); tmp/=x; return tmp; } template <typename T, typename CS, typename S> inline typename pixel<T,CS>::pixel_value_type operator*(const pixel<T,CS>& p, const S& x) { typename pixel<T,CS>::pixel_value_type tmp(p); tmp*=x; return tmp; } //@} ADOBE_GIL_NAMESPACE_END #endif --- NEW FILE: algorithm.hpp --- /* Copyright 2005-2006 Adobe Systems Incorporated Distributed under the MIT License (see accompanying file LICENSE_1_0_0.txt or a copy at http://opensource.adobe.com/licenses.html) */ /*************************************************************************************************/ #ifndef GIL_ALGORITHMS_H #define GIL_ALGORITHMS_H #include "gil_config.hpp" #include "gil_concept.hpp" #include <cassert> #include <algorithm> #include "image.hpp" #include "variant.hpp" //////////////////////////////////////////////////////////////////////////////////////// /// \file /// \brief Some basic STL-style algorithms when applied to image views /// \author Lubomir Bourdev and Hailin Jin \n /// Adobe Systems Incorporated /// //////////////////////////////////////////////////////////////////////////////////////// namespace std { //@{ /// \name STL optimizations /// \brief overloads of STL algorithms allowing more efficient implementation when used with GIL constructs /// \ingroup Algorithms /// \brief Copy when both src and dst are interleaved and of the same type can be just memmove template<typename T, typename CS> inline GIL::pixel<T,CS>* copy(GIL::pixel<T,CS>* first, GIL::pixel<T,CS>* last, GIL::pixel<T,CS>* dst) { return (GIL::pixel<T,CS>*)std::copy((unsigned char*)first,(unsigned char*)last, (unsigned char*)dst); } /// \brief Copy when both src and dst are interleaved and of the same type can be just memmove template<typename T, typename CS> inline GIL::pixel<T,CS>* copy(GIL::pixel<const T,CS>* first, GIL::pixel<const T,CS>* last, GIL::pixel<T,CS>* dst) { return (GIL::pixel<T,CS>*)std::copy((unsigned char*)first,(unsigned char*)last, (unsigned char*)dst); } } ADOBE_GIL_NAMESPACE_BEGIN namespace detail { template <typename I, typename O> struct copy_fn { I operator()(I first, I last, O dst) const { return std::copy(first,last,dst); } }; } ADOBE_GIL_NAMESPACE_END namespace std { /// \brief Copy when both src and dst are planar pointers is copy for each channel template<typename T1, typename CS1, typename T2, typename CS2> inline GIL::planar_ptr<T2,CS2> copy(GIL::planar_ptr<T1,CS1> first, GIL::planar_ptr<T1,CS1> last, GIL::planar_ptr<T2,CS2> dst) { GIL::gil_function_requires<GIL::ChannelsCompatibleConcept<T1,T2> >(); GIL::gil_function_requires<GIL::ColorSpacesCompatibleConcept<CS1,CS2> >(); per_channel_op(GIL::detail::copy_fn<T1*,T2*>(),first.p,last.p,dst.p); return dst+(last-first); } } ADOBE_GIL_NAMESPACE_BEGIN namespace detail { /// Does a copy-n. If the inputs contain image iterators, performs a copy at each row using the row iterators /// \ingroup Algorithms template <typename I, typename O> struct copier_n { void operator()(I src, ptrdiff_t n, O dst) const { std::copy(src,src+n, dst); } }; /// Source range is delimited by image iterators /// \ingroup Algorithms template <typename IL, typename O> // IL Models ConstXYLocatorConcept, O Models PixelIteratorConcept struct copier_n<GIL::pixel_image_iterator<IL>,O> { void operator()(GIL::pixel_image_iterator<IL> src, ptrdiff_t n, O dst) const { GIL::gil_function_requires<GIL::XYLocatorConcept<IL> >(); GIL::gil_function_requires<GIL::MutablePixelIteratorConcept<O> >(); while (n>0) { ptrdiff_t numToCopy=std::min<const ptrdiff_t>(n, src.width()-src.x()); copy_n(src.x_it(), numToCopy, dst); dst+=numToCopy; src+=numToCopy; n-=numToCopy; } } }; /// Destination range is delimited by image iterators /// \ingroup Algorithms template <typename I, typename OL> // I Models ConstPixelIteratorConcept, OL Models XYLocatorConcept struct copier_n<I,GIL::pixel_image_iterator<OL> > { void operator()(I src, ptrdiff_t n, GIL::pixel_image_iterator<OL> dst) const { GIL::gil_function_requires<GIL::PixelIteratorConcept<I> >(); GIL::gil_function_requires<GIL::MutableXYLocatorConcept<OL> >(); while (n>0) { ptrdiff_t numToCopy=std::min<const ptrdiff_t>(n,dst.width()-dst.x()); copy_n(src, numToCopy, dst.x_it()); dst+=numToCopy; src+=numToCopy; n-=numToCopy; } } }; /// Both source and destination ranges are delimited by image iterators /// \ingroup Algorithms template <typename IL, typename OL> struct copier_n<GIL::pixel_image_iterator<IL>,GIL::pixel_image_iterator<OL> > { void operator()(GIL::pixel_image_iterator<IL> src, ptrdiff_t n, GIL::pixel_image_iterator<OL> dst) const { GIL::gil_function_requires<GIL::XYLocatorConcept<IL> >(); GIL::gil_function_requires<GIL::MutableXYLocatorConcept<OL> >(); if (src.x()!=dst.x() || src.width()!=dst.width()) { while(n-->0) { *dst++=*src++; } } while (n>0) { ptrdiff_t numToCopy=std::min<const ptrdiff_t>(n,dst.width()-dst.x()); copy_n(src.x_it(), numToCopy, dst.x_it()); dst+=numToCopy; src+=numToCopy; n-=numToCopy; } } }; } ADOBE_GIL_NAMESPACE_END namespace std { /// \brief std::copy(I1,I1,I2) with I1 and I2 being a pixel_image_iterator /// /// Invoked when one calls std::copy(I1,I1,I2) with I1 and I2 being a pixel_image_iterator (which is /// a 1D iterator over the pixels in an image). Attempts to demote the source and destination /// iterators to simpler/faster types if the corresponding range is contiguous. /// For contiguous images (i.e. images that have /// no alignment gap at the end of each row) it is more efficient to use the underlying /// pixel iterator that does not check for the end of rows. If the underlying pixel iterator /// happens to be a fundamental planar/interleaved pointer, the call may further resolve /// to memmove. Otherwise it resolves to copying each row using the underlying pixel iterator template <typename IL, typename OL> inline GIL::pixel_image_iterator<OL> copy(GIL::pixel_image_iterator<IL> first, GIL::pixel_image_iterator<IL> last, GIL::pixel_image_iterator<OL> dst) { GIL::gil_function_requires<GIL::XYLocatorConcept<IL> >(); GIL::gil_function_requires<GIL::MutableXYLocatorConcept<OL> >(); ptrdiff_t n=last-first; if (first.is_contiguous()) { if (dst.is_contiguous()) GIL::detail::copier_n<typename IL::x_iterator,typename OL::x_iterator>()(first.x_it(),n, dst.x_it()); else GIL::detail::copier_n<typename IL::x_iterator,GIL::pixel_image_iterator<OL> >()(first.x_it(),n, dst); } else { if (dst.is_contiguous()) GIL::detail::copier_n<GIL::pixel_image_iterator<IL>,typename OL::x_iterator>()(first,n, dst.x_it()); else GIL::detail::copier_n<GIL::pixel_image_iterator<IL>,GIL::pixel_image_iterator<OL> >()(first,n,dst); } return dst+n; } /// \brief std::fill(I,I,V) with I being a pixel_image_iterator /// /// Invoked when one calls std::fill(I,I,V) with I being a pixel_image_iterator (which is /// a 1D iterator over the pixels in an image). For contiguous images (i.e. images that have /// no alignment gap at the end of each row) it is more efficient to use the underlying /// pixel iterator that does not check for the end of rows. For non-contiguous images fill /// resolves to fill of each row using the underlying pixel iterator, which is still faster template <typename IL, typename V> void fill(GIL::pixel_image_iterator<IL> first, GIL::pixel_image_iterator<IL> last, const V& val) { GIL::gil_function_requires<GIL::MutableXYLocatorConcept<IL> >(); if (first.is_contiguous()) { std::fill(first.x_it(), last.x_it(), val); } else { // fill row by row ptrdiff_t n=last-first; while (n>0) { ptrdiff_t numToDo=std::min<const ptrdiff_t>(n,(ptrdiff_t)(first.width()-first.x())); fill_n(first.x_it(), numToDo, val); first+=numToDo; n-=numToDo; } } } //@} } ADOBE_GIL_NAMESPACE_BEGIN //@{ /// \name copy_pixels /// \brief std::copy for image views namespace detail { template <bool COMPATIBLE> struct copy_pixels_fn1 { template <typename V1, typename V2> static void apply(const V1& src, const V2& dst) { copy_pixels(src,dst); } }; // copy_pixels invoked on incompatible images template <> struct copy_pixels_fn1<false> { template <typename V1, typename V2> static void apply(const V1& src, const V2& dst) { throw std::bad_cast();} }; struct copy_pixels_fn { typedef void result_type; template <typename V1, typename V2> result_type operator()(const V1& src, const V2& dst) const { copy_pixels_fn1<are_pixels_compatible<typename V1::value_type, typename V2::value_type>::value>::apply(src,dst); } }; } /// \ingroup Algorithms template <typename V1, typename V2> void copy_pixels(const V1& src, const V2& dst) { assert(src.dimensions()==dst.dimensions()); std::copy(src.begin(),src.end(),dst.begin()); // std::copy will choose the optimal method (see stl_override.h) } template <typename C1, // Model image view concept space typename V2> // Model image view void copy_pixels(const variant<C1>& src, const V2& dst) { src.apply_visitor(GIL::bind2nd(GIL::detail::copy_pixels_fn(), dst)); } template <typename V1, // Model image view typename C2> // Model non-const image view concept space void copy_pixels(const V1& src, const variant<C2>& dst) { dst.apply_visitor(GIL::bind1st(GIL::detail::copy_pixels_fn(), src)); } template <typename C1, typename C2> // Model image view concept spaces void copy_pixels(const variant<C1>& src, const variant<C2>& dst) { apply_visitor(src,dst,detail::copy_pixels_fn()); } //@} namespace detail { // If the two color spaces are compatible, copy_and_convert is just copy template <bool COMPATIBLE> struct copy_and_convert_pixels_fn1 { template <typename V1, typename V2> static void apply(const V1& src, const V2& dst) { copy_pixels(src,dst); } }; // when the two color spaces are incompatible, a color conversion is performed template <> struct copy_and_convert_pixels_fn1<false> { template <typename V1, typename V2> static void apply(const V1& src, const V2& dst) { copy_pixels(color_convert_view<typename V2::value_type>(src),dst); } }; struct copy_and_convert_pixels_fn { typedef void result_type; template <typename V1, typename V2> result_type operator()(const V1& src, const V2& dst) const { assert(src.dimensions()==dst.dimensions()); copy_and_convert_pixels_fn1<are_pixels_compatible<typename V1::value_type, typename V2::value_type>::value>::apply(src,dst); } }; } //@{ /// \name copy_and_convert_pixels /// \brief copies src view into dst view, color converting if necessary /// \ingroup Algorithms template <typename V1, typename V2> void copy_and_convert_pixels(const V1& src, const V2& dst) { detail::copy_and_convert_pixels_fn()(src,dst); } template <typename C1, // Model image view concept space typename V2> // Model image view void copy_and_convert_pixels(const variant<C1>& src, const V2& dst) { src.apply_visitor(GIL::bind2nd(detail::copy_and_convert_pixels_fn(), dst)); } template <typename V1, // Model image view typename C2> // Model non-const image view concept space void copy_and_convert_pixels(const V1& src, const variant<C2>& dst) { dst.apply_visitor(GIL::bind1st(detail::copy_and_convert_pixels_fn(), src)); } template <typename C1, typename C2> // Model image view concept spaces void copy_and_convert_pixels(const variant<C1>& src, const variant<C2>& dst) { apply_visitor(src,dst,detail::copy_and_convert_pixels_fn()); } //@} //@{ /// \name fill_pixels /// \brief std::fill for image views namespace detail { template <bool COMPATIBLE> struct fill_pixels_fn1 { template <typename V, typename VAL> static void apply(const V& src, const VAL& val) { fill_pixels(src,val); } }; // copy_pixels invoked on incompatible images template <> struct fill_pixels_fn1<false> { template <typename V, typename VAL> static void apply(const V& src, const VAL& val) { throw std::bad_cast();} }; template <typename VAL> struct fill_pixels_fn { fill_pixels_fn(const VAL& val) : _val(val) {} typedef void result_type; template <typename V> result_type operator()(const V& img_view) const { fill_pixels_fn1<are_pixels_compatible<typename V::value_type, VAL>::value>::apply(img_view,_val); } VAL _val; }; } /// \ingroup Algorithms template <typename V, typename VAL> void fill_pixels(const V& img_view, const VAL& val) { if (img_view.begin().is_contiguous()) { std::fill(img_view.begin().x_it(), img_view.end().x_it(), val); } else { for (int y=0; y<img_view.height(); ++y) std::fill(img_view.row_begin(y),img_view.row_end(y),val); } } template <typename C, typename VAL> void fill_pixels(const variant<C>& img_view, const VAL& val) { img_view.apply_visitor(GIL::detail::fill_pixels_fn<VAL>(val)); } //@} //@{ /// \name for_each_pixel /// \brief std::for_each for image views /// \ingroup Algorithms /// For contiguous images (i.e. images that have no alignment gap at the end of each row) it is /// more efficient to use the underlying pixel it... [truncated message content] |