Chris@16: /* Chris@16: Copyright 2005-2007 Adobe Systems Incorporated Chris@16: Chris@16: Use, modification and distribution are subject to the Boost Software License, Chris@16: Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at Chris@16: http://www.boost.org/LICENSE_1_0.txt). Chris@16: Chris@16: See http://opensource.adobe.com/gil for most recent version including documentation. Chris@16: */ Chris@16: Chris@16: Chris@16: /*************************************************************************************************/ Chris@16: Chris@16: #ifndef GIL_ALGORITHM_HPP Chris@16: #define GIL_ALGORITHM_HPP Chris@16: Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include "gil_config.hpp" Chris@16: #include "gil_concept.hpp" Chris@16: #include "color_base_algorithm.hpp" Chris@16: #include "image_view.hpp" Chris@16: #include "image_view_factory.hpp" Chris@16: #include "bit_aligned_pixel_iterator.hpp" Chris@16: Chris@16: //////////////////////////////////////////////////////////////////////////////////////// Chris@16: /// \file Chris@16: /// \brief Some basic STL-style algorithms when applied to image views Chris@16: /// \author Lubomir Bourdev and Hailin Jin \n Chris@16: /// Adobe Systems Incorporated Chris@16: /// \date 2005-2008 \n Last updated on March 12, 2008 Chris@16: /// Chris@16: //////////////////////////////////////////////////////////////////////////////////////// Chris@16: Chris@16: //#ifdef _MSC_VER Chris@16: //#pragma warning(push) Chris@16: //#pragma warning(disable : 4244) // conversion from 'gil::image::coord_t' to 'int', possible loss of data (visual studio compiler doesn't realize that the two types are the same) Chris@16: //#endif Chris@16: Chris@16: namespace boost { namespace gil { Chris@16: Chris@16: //forward declarations Chris@16: template Chris@16: struct planar_pixel_iterator; Chris@16: template Chris@16: class memory_based_step_iterator; Chris@16: template Chris@16: class memory_based_2d_locator; Chris@16: Chris@16: // a tag denoting incompatible arguments Chris@16: struct error_t {}; Chris@16: Chris@16: /// \defgroup ImageViewSTLAlgorithms STL-like Algorithms Chris@16: /// \ingroup ImageViewAlgorithm Chris@16: /// \brief Image view-equivalents of STL algorithms Chris@16: /// Chris@16: /// Image views provide 1D iteration of their pixels via \p begin() and \p end() methods, Chris@16: /// which makes it possible to use STL algorithms with them. However, using nested loops Chris@16: /// over X and Y is in many cases more efficient. The algorithms in this section resemble Chris@16: /// STL algorithms, but they abstract away the nested loops and take views (as opposed to ranges) as input. Chris@16: /// Chris@16: /// Most algorithms check whether the image views are 1D-traversable. A 1D-traversable image view has no gaps Chris@16: /// at the end of the rows. In other words, if an x_iterator of that view is advanced past the last pixel in a row Chris@16: /// it will move to the first pixel of the next row. When image views are 1D-traversable, the algorithms use Chris@16: /// a single loop and run more efficiently. If one or more of the input views are not 1D-traversable, the algorithms Chris@16: /// fall-back to an X-loop nested inside a Y-loop. Chris@16: /// Chris@16: /// The algorithms typically delegate the work to their corresponding STL algorithms. For example, \p copy_pixels calls Chris@16: /// \p std::copy either for each row, or, when the images are 1D-traversable, once for all pixels. Chris@16: /// Chris@16: /// In addition, overloads are sometimes provided for the STL algorithms. For example, std::copy for planar iterators Chris@16: /// is overloaded to perform \p std::copy for each of the planes. \p std::copy over bitwise-copiable pixels results in Chris@16: /// std::copy over unsigned char, which STL typically implements via \p memmove. Chris@16: /// Chris@16: /// As a result \p copy_pixels may result in a single call to \p memmove for interleaved 1D-traversable views, Chris@16: /// or one per each plane of planar 1D-traversable views, or one per each row of interleaved non-1D-traversable images, etc. Chris@16: Chris@16: Chris@16: /// \defgroup STLOptimizations Performance overloads of STL algorithms Chris@16: /// \ingroup ImageViewAlgorithm Chris@16: /// \brief overloads of STL algorithms allowing more efficient implementation when used with GIL constructs Chris@16: Chris@16: /// \brief A generic binary operation on views Chris@16: /// \ingroup ImageViewSTLAlgorithms Chris@16: /// Chris@16: /// Use this class as a convenience superclass when defining an operation for any image views. Chris@16: /// Many operations have different behavior when the two views are compatible. This class checks Chris@16: /// for compatibility and invokes apply_compatible(V1,V2) or apply_incompatible(V1,V2) of the subclass. Chris@16: /// You must provide apply_compatible(V1,V2) method in your subclass, but apply_incompatible(V1,V2) Chris@16: /// is not required and the default throws std::bad_cast. Chris@16: template Chris@16: struct binary_operation_obj { Chris@16: typedef Result result_type; Chris@16: Chris@16: template GIL_FORCEINLINE Chris@16: result_type operator()(const std::pair& p) const { Chris@16: return apply(*p.first, *p.second, typename views_are_compatible::type()); Chris@16: } Chris@16: Chris@16: template GIL_FORCEINLINE Chris@16: result_type operator()(const V1& v1, const V2& v2) const { Chris@16: return apply(v1, v2, typename views_are_compatible::type()); Chris@16: } Chris@16: Chris@16: result_type operator()(const error_t&) const { throw std::bad_cast(); } Chris@16: private: Chris@16: Chris@16: // dispatch from apply overload to a function with distinct name Chris@16: template Chris@16: GIL_FORCEINLINE result_type apply(const V1& v1, const V2& v2, mpl::false_) const { Chris@16: return ((const Derived*)this)->apply_incompatible(v1,v2); Chris@16: } Chris@16: Chris@16: // dispatch from apply overload to a function with distinct name Chris@16: template Chris@16: GIL_FORCEINLINE result_type apply(const V1& v1, const V2& v2, mpl::true_) const { Chris@16: return ((const Derived*)this)->apply_compatible(v1,v2); Chris@16: } Chris@16: Chris@16: // function with distinct name - it can be overloaded by subclasses Chris@16: template Chris@16: GIL_FORCEINLINE result_type apply_incompatible(const V1& v1, const V2& v2) const { Chris@16: throw std::bad_cast(); Chris@16: } Chris@16: }; Chris@16: } } // namespace boost::gil Chris@16: Chris@16: ////////////////////////////////////////////////////////////////////////////////////// Chris@16: /// Chris@16: /// std::copy and gil::copy_pixels Chris@16: /// Chris@16: ////////////////////////////////////////////////////////////////////////////////////// Chris@16: Chris@16: /// \defgroup ImageViewSTLAlgorithmsCopyPixels copy_pixels Chris@16: /// \ingroup ImageViewSTLAlgorithms Chris@16: /// \brief std::copy for image views Chris@16: Chris@16: namespace std { Chris@16: Chris@16: /// \ingroup STLOptimizations Chris@16: /// \brief Copy when both src and dst are interleaved and of the same type can be just memmove Chris@16: template Chris@16: GIL_FORCEINLINE boost::gil::pixel* Chris@16: copy(boost::gil::pixel* first, boost::gil::pixel* last, Chris@16: boost::gil::pixel* dst) { Chris@16: return (boost::gil::pixel*)std::copy((unsigned char*)first,(unsigned char*)last, (unsigned char*)dst); Chris@16: } Chris@16: Chris@16: /// \ingroup STLOptimizations Chris@16: /// \brief Copy when both src and dst are interleaved and of the same type can be just memmove Chris@16: template Chris@16: GIL_FORCEINLINE boost::gil::pixel* Chris@16: copy(const boost::gil::pixel* first, const boost::gil::pixel* last, Chris@16: boost::gil::pixel* dst) { Chris@16: return (boost::gil::pixel*)std::copy((unsigned char*)first,(unsigned char*)last, (unsigned char*)dst); Chris@16: } Chris@16: } // namespace std Chris@16: Chris@16: namespace boost { namespace gil { Chris@16: namespace detail { Chris@16: template struct copy_fn { Chris@16: GIL_FORCEINLINE I operator()(I first, I last, O dst) const { return std::copy(first,last,dst); } Chris@16: }; Chris@16: } // namespace detail Chris@16: } } // namespace boost::gil Chris@16: Chris@16: namespace std { Chris@16: /// \ingroup STLOptimizations Chris@16: /// \brief Copy when both src and dst are planar pointers is copy for each channel Chris@16: template GIL_FORCEINLINE Chris@16: boost::gil::planar_pixel_iterator copy(boost::gil::planar_pixel_iterator first, boost::gil::planar_pixel_iterator last, boost::gil::planar_pixel_iterator dst) { Chris@16: boost::gil::gil_function_requires::value_type,typename std::iterator_traits::value_type> >(); Chris@16: static_for_each(first,last,dst,boost::gil::detail::copy_fn()); Chris@16: return dst+(last-first); Chris@16: } Chris@16: } // namespace std Chris@16: Chris@16: namespace boost { namespace gil { Chris@16: namespace detail { Chris@16: /// Does a copy-n. If the inputs contain image iterators, performs a copy at each row using the row iterators Chris@16: /// \ingroup CopyPixels Chris@16: template Chris@16: struct copier_n { Chris@16: GIL_FORCEINLINE void operator()(I src, typename std::iterator_traits::difference_type n, O dst) const { std::copy(src,src+n, dst); } Chris@16: }; Chris@16: Chris@16: /// Source range is delimited by image iterators Chris@16: template // IL Models ConstPixelLocatorConcept, O Models PixelIteratorConcept Chris@16: struct copier_n,O> { Chris@16: typedef typename std::iterator_traits >::difference_type diff_t; Chris@16: GIL_FORCEINLINE void operator()(iterator_from_2d src, diff_t n, O dst) const { Chris@16: gil_function_requires >(); Chris@16: gil_function_requires >(); Chris@16: while (n>0) { Chris@16: typedef typename iterator_from_2d::difference_type diff_t; Chris@16: diff_t l=src.width()-src.x_pos(); Chris@16: diff_t numToCopy=(n // I Models ConstPixelIteratorConcept, OL Models PixelLocatorConcept Chris@16: struct copier_n > { Chris@16: typedef typename std::iterator_traits::difference_type diff_t; Chris@16: GIL_FORCEINLINE void operator()(I src, diff_t n, iterator_from_2d
    dst) const { Chris@16: gil_function_requires >(); Chris@16: gil_function_requires >(); Chris@16: while (n>0) { Chris@16: diff_t l=dst.width()-dst.x_pos(); Chris@16: diff_t numToCopy=(n Chris@16: struct copier_n,iterator_from_2d
      > { Chris@16: typedef typename iterator_from_2d::difference_type diff_t; Chris@16: GIL_FORCEINLINE void operator()(iterator_from_2d src, diff_t n, iterator_from_2d
        dst) const { Chris@16: gil_function_requires >(); Chris@16: gil_function_requires >(); Chris@16: if (src.x_pos()!=dst.x_pos() || src.width()!=dst.width()) { Chris@16: while(n-->0) { Chris@16: *dst++=*src++; Chris@16: } Chris@16: } Chris@16: while (n>0) { Chris@16: diff_t l=dst.width()-dst.x_pos(); Chris@16: diff_t numToCopy=(n Chris@16: GIL_FORCEINLINE DstIterator copy_with_2d_iterators(SrcIterator first, SrcIterator last, DstIterator dst) { Chris@16: typedef typename SrcIterator::x_iterator src_x_iterator; Chris@16: typedef typename DstIterator::x_iterator dst_x_iterator; Chris@16: Chris@16: typename SrcIterator::difference_type n = last - first; Chris@16: Chris@16: if (first.is_1d_traversable()) { Chris@16: if (dst.is_1d_traversable()) Chris@16: copier_n()(first.x(),n, dst.x()); Chris@16: else Chris@16: copier_n()(first.x(),n, dst); Chris@16: } else { Chris@16: if (dst.is_1d_traversable()) Chris@16: copier_n()(first,n, dst.x()); Chris@16: else Chris@16: copier_n()(first,n,dst); Chris@16: } Chris@16: return dst+n; Chris@16: } Chris@16: Chris@16: } // namespace detail Chris@16: } } // namespace boost::gil Chris@16: Chris@16: namespace std { Chris@16: /// \ingroup STLOptimizations Chris@16: /// \brief std::copy(I1,I1,I2) with I1 and I2 being a iterator_from_2d Chris@16: template Chris@16: GIL_FORCEINLINE boost::gil::iterator_from_2d
          copy1(boost::gil::iterator_from_2d first, boost::gil::iterator_from_2d last, boost::gil::iterator_from_2d
            dst) { Chris@16: return boost::gil::detail::copy_with_2d_iterators(first,last,dst); Chris@16: } Chris@16: Chris@16: } // namespace std Chris@16: Chris@16: namespace boost { namespace gil { Chris@16: Chris@16: Chris@16: /// \ingroup ImageViewSTLAlgorithmsCopyPixels Chris@16: /// \brief std::copy for image views Chris@16: template GIL_FORCEINLINE Chris@16: void copy_pixels(const View1& src, const View2& dst) { Chris@16: assert(src.dimensions()==dst.dimensions()); Chris@16: detail::copy_with_2d_iterators(src.begin(),src.end(),dst.begin()); Chris@16: } Chris@16: Chris@16: ////////////////////////////////////////////////////////////////////////////////////// Chris@16: /// Chris@16: /// copy_and_convert_pixels Chris@16: /// Chris@16: ////////////////////////////////////////////////////////////////////////////////////// Chris@16: Chris@16: /// \defgroup ImageViewSTLAlgorithmsCopyAndConvertPixels copy_and_convert_pixels Chris@16: /// \ingroup ImageViewSTLAlgorithms Chris@16: /// \brief copies src view into dst view, color converting if necessary. Chris@16: /// Chris@16: /// Versions taking static and runtime views are provided. Versions taking user-defined color convered are provided. Chris@16: Chris@16: namespace detail { Chris@16: template Chris@16: class copy_and_convert_pixels_fn : public binary_operation_obj > { Chris@16: private: Chris@16: CC _cc; Chris@16: public: Chris@16: typedef typename binary_operation_obj >::result_type result_type; Chris@16: copy_and_convert_pixels_fn() {} Chris@16: copy_and_convert_pixels_fn(CC cc_in) : _cc(cc_in) {} Chris@16: // when the two color spaces are incompatible, a color conversion is performed Chris@16: template GIL_FORCEINLINE Chris@16: result_type apply_incompatible(const V1& src, const V2& dst) const { Chris@16: copy_pixels(color_converted_view(src,_cc),dst); Chris@16: } Chris@16: Chris@16: // If the two color spaces are compatible, copy_and_convert is just copy Chris@16: template GIL_FORCEINLINE Chris@16: result_type apply_compatible(const V1& src, const V2& dst) const { Chris@16: copy_pixels(src,dst); Chris@16: } Chris@16: }; Chris@16: } // namespace detail Chris@16: Chris@16: /// \ingroup ImageViewSTLAlgorithmsCopyAndConvertPixels Chris@16: template Chris@16: GIL_FORCEINLINE Chris@16: void copy_and_convert_pixels(const V1& src, const V2& dst,CC cc) { Chris@16: detail::copy_and_convert_pixels_fn ccp(cc); Chris@16: ccp(src,dst); Chris@16: } Chris@16: Chris@16: struct default_color_converter; Chris@16: Chris@16: /// \ingroup ImageViewSTLAlgorithmsCopyAndConvertPixels Chris@16: template Chris@16: GIL_FORCEINLINE Chris@16: void copy_and_convert_pixels(const View1& src, const View2& dst) { Chris@16: detail::copy_and_convert_pixels_fn ccp; Chris@16: ccp(src,dst); Chris@16: } Chris@16: Chris@16: } } // namespace boost::gil Chris@16: Chris@16: ////////////////////////////////////////////////////////////////////////////////////// Chris@16: // Chris@16: // std::fill and gil::fill_pixels Chris@16: // Chris@16: ////////////////////////////////////////////////////////////////////////////////////// Chris@16: Chris@16: /// \defgroup ImageViewSTLAlgorithmsFillPixels fill_pixels Chris@16: /// \ingroup ImageViewSTLAlgorithms Chris@16: /// \brief std::fill for image views Chris@16: Chris@16: Chris@16: namespace std { Chris@16: /// \ingroup STLOptimizations Chris@16: /// \brief std::fill(I,I,V) with I being a iterator_from_2d Chris@16: /// Chris@16: /// Invoked when one calls std::fill(I,I,V) with I being a iterator_from_2d (which is Chris@16: /// a 1D iterator over the pixels in an image). For contiguous images (i.e. images that have Chris@16: /// no alignment gap at the end of each row) it is more efficient to use the underlying Chris@16: /// pixel iterator that does not check for the end of rows. For non-contiguous images fill Chris@16: /// resolves to fill of each row using the underlying pixel iterator, which is still faster Chris@16: template Chris@16: void fill(boost::gil::iterator_from_2d first, boost::gil::iterator_from_2d last, const V& val) { Chris@16: boost::gil::gil_function_requires >(); Chris@16: if (first.is_1d_traversable()) { Chris@16: std::fill(first.x(), last.x(), val); Chris@16: } else { Chris@16: // fill row by row Chris@16: std::ptrdiff_t n=last-first; Chris@16: while (n>0) { Chris@16: std::ptrdiff_t numToDo=std::min(n,(std::ptrdiff_t)(first.width()-first.x_pos())); Chris@16: fill_n(first.x(), numToDo, val); Chris@16: first+=numToDo; Chris@16: n-=numToDo; Chris@16: } Chris@16: } Chris@16: } Chris@16: } // namespace std Chris@16: Chris@16: namespace boost { namespace gil { Chris@16: Chris@16: namespace detail { Chris@16: /// struct to do std::fill Chris@16: struct std_fill_t { Chris@16: template Chris@16: void operator()(It first, It last, const P& p_in) { Chris@16: std::fill(first,last,p_in); Chris@16: } Chris@16: }; Chris@16: /// std::fill for planar iterators Chris@16: template Chris@16: GIL_FORCEINLINE Chris@16: void fill_aux(It first, It last, const P& p, mpl::true_) { Chris@16: static_for_each(first,last,p,std_fill_t()); Chris@16: } Chris@16: /// std::fill for interleaved iterators Chris@16: template Chris@16: GIL_FORCEINLINE Chris@16: void fill_aux(It first, It last, const P& p,mpl::false_) { Chris@16: std::fill(first,last,p); Chris@16: } Chris@16: } // namespace detail Chris@16: Chris@16: /// \ingroup ImageViewSTLAlgorithmsFillPixels Chris@16: /// \brief std::fill for image views Chris@16: template GIL_FORCEINLINE Chris@16: void fill_pixels(const View& img_view, const Value& val) { Chris@16: if (img_view.is_1d_traversable()) Chris@16: detail::fill_aux(img_view.begin().x(), img_view.end().x(), Chris@16: val,is_planar()); Chris@16: else Chris@16: for (std::ptrdiff_t y=0; y()); Chris@16: } Chris@16: Chris@16: ////////////////////////////////////////////////////////////////////////////////////// Chris@16: /// Chris@16: /// destruct_pixels Chris@16: /// Chris@16: ////////////////////////////////////////////////////////////////////////////////////// Chris@16: Chris@16: /// \defgroup ImageViewSTLAlgorithmsDestructPixels destruct_pixels Chris@16: /// \ingroup ImageViewSTLAlgorithms Chris@16: /// \brief invokes the destructor on every pixel of an image view Chris@16: Chris@16: Chris@16: namespace detail { Chris@16: Chris@16: template GIL_FORCEINLINE Chris@16: void destruct_range_impl(It first, It last, mpl::true_) { Chris@16: typedef typename std::iterator_traits::value_type value_t; Chris@16: if (boost::has_trivial_destructor::value) Chris@16: return; Chris@16: while (first!=last) { Chris@16: first->~value_t(); Chris@16: ++first; Chris@16: } Chris@16: } Chris@16: template GIL_FORCEINLINE Chris@16: void destruct_range_impl(It, It, mpl::false_) {} Chris@16: Chris@16: template GIL_FORCEINLINE Chris@16: void destruct_range(It first, It last) { Chris@16: destruct_range_impl(first,last,typename is_pointer::type()); Chris@16: } Chris@16: Chris@16: struct std_destruct_t { Chris@16: template void operator()(It first, It last) const { destruct_range(first,last); } Chris@16: }; Chris@16: Chris@16: /// destruct for planar iterators Chris@16: template Chris@16: GIL_FORCEINLINE Chris@16: void destruct_aux(It first, It last, mpl::true_) { Chris@16: static_for_each(first,last,std_destruct_t()); Chris@16: } Chris@16: /// destruct for interleaved iterators Chris@16: template Chris@16: GIL_FORCEINLINE Chris@16: void destruct_aux(It first, It last, mpl::false_) { Chris@16: destruct_range(first,last); Chris@16: } Chris@16: Chris@16: } // namespace detail Chris@16: Chris@16: /// \ingroup ImageViewSTLAlgorithmsDestructPixels Chris@16: /// \brief Invokes the in-place destructor on every pixel of the view Chris@16: template GIL_FORCEINLINE Chris@16: void destruct_pixels(const View& img_view) { Chris@16: if (img_view.is_1d_traversable()) Chris@16: detail::destruct_aux(img_view.begin().x(), img_view.end().x(), Chris@16: is_planar()); Chris@16: else Chris@16: for (std::ptrdiff_t y=0; y()); Chris@16: } Chris@16: Chris@16: ////////////////////////////////////////////////////////////////////////////////////// Chris@16: /// Chris@16: /// uninitialized_fill_pixels Chris@16: /// Chris@16: ////////////////////////////////////////////////////////////////////////////////////// Chris@16: Chris@16: /// \defgroup ImageViewSTLAlgorithmsUninitializedFillPixels uninitialized_fill_pixels Chris@16: /// \ingroup ImageViewSTLAlgorithms Chris@16: /// \brief std::uninitialized_fill for image views Chris@16: Chris@16: Chris@16: namespace detail { Chris@16: Chris@16: /// std::uninitialized_fill for planar iterators Chris@16: /// If an exception is thrown destructs any in-place copy-constructed objects Chris@16: template Chris@16: GIL_FORCEINLINE Chris@16: void uninitialized_fill_aux(It first, It last, Chris@16: const P& p, mpl::true_) { Chris@16: int channel=0; Chris@16: try { Chris@16: typedef typename std::iterator_traits::value_type pixel_t; Chris@16: while (channel < num_channels::value) { Chris@16: std::uninitialized_fill(dynamic_at_c(first,channel), dynamic_at_c(last,channel), Chris@16: dynamic_at_c(p,channel)); Chris@16: ++channel; Chris@16: } Chris@16: } catch (...) { Chris@16: for (int c=0; c Chris@16: GIL_FORCEINLINE Chris@16: void uninitialized_fill_aux(It first, It last, Chris@16: const P& p,mpl::false_) { Chris@16: std::uninitialized_fill(first,last,p); Chris@16: } Chris@16: Chris@16: } // namespace detail Chris@16: Chris@16: /// \ingroup ImageViewSTLAlgorithmsUninitializedFillPixels Chris@16: /// \brief std::uninitialized_fill for image views. Chris@16: /// Does not support planar heterogeneous views. Chris@16: /// If an exception is thrown destructs any in-place copy-constructed pixels Chris@16: template Chris@16: void uninitialized_fill_pixels(const View& img_view, const Value& val) { Chris@16: if (img_view.is_1d_traversable()) Chris@16: detail::uninitialized_fill_aux(img_view.begin().x(), img_view.end().x(), Chris@16: val,is_planar()); Chris@16: else { Chris@16: typename View::y_coord_t y; Chris@16: try { Chris@16: for (y=0; y()); Chris@16: } catch(...) { Chris@16: for (typename View::y_coord_t y0=0; y0()); Chris@16: throw; Chris@16: } Chris@16: } Chris@16: } Chris@16: Chris@16: ////////////////////////////////////////////////////////////////////////////////////// Chris@16: /// Chris@16: /// default_construct_pixels Chris@16: /// Chris@16: ////////////////////////////////////////////////////////////////////////////////////// Chris@16: Chris@16: /// \defgroup ImageViewSTLAlgorithmsDefaultConstructPixels default_construct_pixels Chris@16: /// \ingroup ImageViewSTLAlgorithms Chris@16: /// \brief invokes the default constructor on every pixel of an image view Chris@16: Chris@16: namespace detail { Chris@16: Chris@16: template GIL_FORCEINLINE Chris@16: void default_construct_range_impl(It first, It last, mpl::true_) { Chris@16: typedef typename std::iterator_traits::value_type value_t; Chris@16: It first1=first; Chris@16: try { Chris@16: while (first!=last) { Chris@16: new (first) value_t(); Chris@16: ++first; Chris@16: } Chris@16: } catch (...) { Chris@16: destruct_range(first1,first); Chris@16: throw; Chris@16: } Chris@16: } Chris@16: Chris@16: template GIL_FORCEINLINE Chris@16: void default_construct_range_impl(It, It, mpl::false_) {} Chris@16: Chris@16: template GIL_FORCEINLINE Chris@16: void default_construct_range(It first, It last) { default_construct_range_impl(first, last, typename is_pointer::type()); } Chris@16: Chris@16: /// uninitialized_default_construct for planar iterators Chris@16: template Chris@16: GIL_FORCEINLINE Chris@16: void default_construct_aux(It first, It last, mpl::true_) { Chris@16: int channel=0; Chris@16: try { Chris@16: typedef typename std::iterator_traits::value_type pixel_t; Chris@16: while (channel < num_channels::value) { Chris@16: default_construct_range(dynamic_at_c(first,channel), dynamic_at_c(last,channel)); Chris@16: ++channel; Chris@16: } Chris@16: } catch (...) { Chris@16: for (int c=0; c Chris@16: GIL_FORCEINLINE Chris@16: void default_construct_aux(It first, It last, mpl::false_) { Chris@16: default_construct_range(first,last); Chris@16: } Chris@16: Chris@16: template Chris@16: struct has_trivial_pixel_constructor : public boost::has_trivial_constructor {}; Chris@16: template Chris@16: struct has_trivial_pixel_constructor : public boost::has_trivial_constructor::type> {}; Chris@16: Chris@16: } // namespace detail Chris@16: Chris@16: /// \ingroup ImageViewSTLAlgorithmsDefaultConstructPixels Chris@16: /// \brief Invokes the in-place default constructor on every pixel of the (uninitialized) view. Chris@16: /// Does not support planar heterogeneous views. Chris@16: /// If an exception is thrown destructs any in-place default-constructed pixels Chris@16: template Chris@16: void default_construct_pixels(const View& img_view) { Chris@16: if (detail::has_trivial_pixel_constructor::value>::value) Chris@16: return; Chris@16: Chris@16: if (img_view.is_1d_traversable()) Chris@16: detail::default_construct_aux(img_view.begin().x(), img_view.end().x(), is_planar()); Chris@16: else { Chris@16: typename View::y_coord_t y; Chris@16: try { Chris@16: for (y=0; y()); Chris@16: } catch(...) { Chris@16: for (typename View::y_coord_t y0=0; y0()); Chris@16: throw; Chris@16: } Chris@16: } Chris@16: } Chris@16: Chris@16: Chris@16: ////////////////////////////////////////////////////////////////////////////////////// Chris@16: /// Chris@16: /// uninitialized_copy_pixels Chris@16: /// Chris@16: ////////////////////////////////////////////////////////////////////////////////////// Chris@16: Chris@16: /// \defgroup ImageViewSTLAlgorithmsUninitializedCopyPixels uninitialized_copy_pixels Chris@16: /// \ingroup ImageViewSTLAlgorithms Chris@16: /// \brief std::uninitialized_copy for image views Chris@16: Chris@16: namespace detail { Chris@16: Chris@16: /// std::uninitialized_copy for pairs of planar iterators Chris@16: template Chris@16: GIL_FORCEINLINE Chris@16: void uninitialized_copy_aux(It1 first1, It1 last1, Chris@16: It2 first2, mpl::true_) { Chris@16: int channel=0; Chris@16: try { Chris@16: typedef typename std::iterator_traits::value_type pixel_t; Chris@16: while (channel < num_channels::value) { Chris@16: std::uninitialized_copy(dynamic_at_c(first1,channel), dynamic_at_c(last1,channel), dynamic_at_c(first2,channel)); Chris@16: ++channel; Chris@16: } Chris@16: } catch (...) { Chris@16: It2 last2=first2; Chris@16: std::advance(last2, std::distance(first1,last1)); Chris@16: for (int c=0; c Chris@16: GIL_FORCEINLINE Chris@16: void uninitialized_copy_aux(It1 first1, It1 last1, Chris@16: It2 first2,mpl::false_) { Chris@16: std::uninitialized_copy(first1,last1,first2); Chris@16: } Chris@16: } // namespace detail Chris@16: Chris@16: /// \ingroup ImageViewSTLAlgorithmsUninitializedCopyPixels Chris@16: /// \brief std::uninitialized_copy for image views. Chris@16: /// Does not support planar heterogeneous views. Chris@16: /// If an exception is thrown destructs any in-place copy-constructed objects Chris@16: template Chris@16: void uninitialized_copy_pixels(const View1& view1, const View2& view2) { Chris@16: typedef mpl::bool_::value && is_planar::value> is_planar; Chris@16: assert(view1.dimensions()==view2.dimensions()); Chris@16: if (view1.is_1d_traversable() && view2.is_1d_traversable()) Chris@16: detail::uninitialized_copy_aux(view1.begin().x(), view1.end().x(), Chris@16: view2.begin().x(), Chris@16: is_planar()); Chris@16: else { Chris@16: typename View1::y_coord_t y; Chris@16: try { Chris@16: for (y=0; y Chris@16: F for_each_pixel(const V& img, F fun) { Chris@16: if (img.is_1d_traversable()) { Chris@16: return std::for_each(img.begin().x(), img.end().x(), fun); Chris@16: } else { Chris@16: for (std::ptrdiff_t y=0; y Chris@16: F for_each_pixel_position(const View& img, F fun) { Chris@16: typename View::xy_locator loc=img.xy_at(0,0); Chris@16: for (std::ptrdiff_t y=0; y Chris@16: void generate_pixels(const View& v, F fun) { Chris@16: if (v.is_1d_traversable()) { Chris@16: std::generate(v.begin().x(), v.end().x(), fun); Chris@16: } else { Chris@16: for (std::ptrdiff_t y=0; y GIL_FORCEINLINE bool equal_n(I1 i1, std::ptrdiff_t n, I2 i2); Chris@16: Chris@16: namespace detail { Chris@16: Chris@16: template Chris@16: struct equal_n_fn { Chris@16: GIL_FORCEINLINE bool operator()(I1 i1, std::ptrdiff_t n, I2 i2) const { return std::equal(i1,i1+n, i2); } Chris@16: }; Chris@16: Chris@16: /// Equal when both ranges are interleaved and of the same type. Chris@16: /// GIL pixels are bitwise comparable, so memcmp is used. User-defined pixels that are not bitwise comparable need to provide an overload Chris@16: template Chris@16: struct equal_n_fn*, const pixel*> { Chris@16: GIL_FORCEINLINE bool operator()(const pixel* i1, std::ptrdiff_t n, const pixel* i2) const { Chris@16: return memcmp(i1, i2, n*sizeof(pixel))==0; Chris@16: } Chris@16: }; Chris@16: template Chris@16: struct equal_n_fn*, pixel*> : equal_n_fn*, const pixel*> {}; Chris@16: Chris@16: /// EqualPixels Chris@16: /// Equal when both ranges are planar pointers of the same type. memcmp is invoked for each channel plane Chris@16: /// User-defined channels that are not bitwise comparable need to provide an overload Chris@16: template Chris@16: struct equal_n_fn, planar_pixel_iterator > { Chris@16: GIL_FORCEINLINE bool operator()(const planar_pixel_iterator i1, std::ptrdiff_t n, const planar_pixel_iterator i2) const { Chris@16: ptrdiff_t numBytes=n*sizeof(typename std::iterator_traits::value_type); Chris@16: Chris@16: for (std::ptrdiff_t i=0; i::value; ++i) Chris@16: if (memcmp(dynamic_at_c(i1,i), dynamic_at_c(i2,i), numBytes)!=0) Chris@16: return false; Chris@16: return true; Chris@16: } Chris@16: }; Chris@16: Chris@16: Chris@16: /// Source range is delimited by image iterators Chris@16: template // IL Models ConstPixelLocatorConcept, O Models PixelIteratorConcept Chris@16: struct equal_n_fn,I2> { Chris@16: GIL_FORCEINLINE bool operator()(boost::gil::iterator_from_2d i1, std::ptrdiff_t n, I2 i2) const { Chris@16: gil_function_requires >(); Chris@16: gil_function_requires >(); Chris@16: while (n>0) { Chris@16: std::ptrdiff_t num=std::min(n, i1.width()-i1.x_pos()); Chris@16: if (!equal_n(i1.x(), num, i2)) Chris@16: return false; Chris@16: i1+=num; Chris@16: i2+=num; Chris@16: n-=num; Chris@16: } Chris@16: return true; Chris@16: } Chris@16: }; Chris@16: Chris@16: /// Destination range is delimited by image iterators Chris@16: template // I Models PixelIteratorConcept, OL Models PixelLocatorConcept Chris@16: struct equal_n_fn > { Chris@16: GIL_FORCEINLINE bool operator()(I1 i1, std::ptrdiff_t n, boost::gil::iterator_from_2d i2) const { Chris@16: gil_function_requires >(); Chris@16: gil_function_requires >(); Chris@16: while (n>0) { Chris@16: std::ptrdiff_t num=std::min(n,i2.width()-i2.x_pos()); Chris@16: if (!equal_n(i1, num, i2.x())) Chris@16: return false; Chris@16: i1+=num; Chris@16: i2+=num; Chris@16: n-=num; Chris@16: } Chris@16: return true; Chris@16: } Chris@16: }; Chris@16: Chris@16: /// Both source and destination ranges are delimited by image iterators Chris@16: template Chris@16: struct equal_n_fn,boost::gil::iterator_from_2d > { Chris@16: GIL_FORCEINLINE bool operator()(boost::gil::iterator_from_2d i1, std::ptrdiff_t n, boost::gil::iterator_from_2d i2) const { Chris@16: gil_function_requires >(); Chris@16: gil_function_requires >(); Chris@16: if (i1.x_pos()!=i2.x_pos() || i1.width()!=i2.width()) { Chris@16: while(n-->0) { Chris@16: if (*i1++!=*i2++) return false; Chris@16: } Chris@16: } Chris@16: while (n>0) { Chris@16: std::ptrdiff_t num=std::min(n,i2.width()-i2.x_pos()); Chris@16: if (!equal_n(i1.x(), num, i2.x())) Chris@16: return false; Chris@16: i1+=num; Chris@16: i2+=num; Chris@16: n-=num; Chris@16: } Chris@16: return true; Chris@16: } Chris@16: }; Chris@16: } // namespace detail Chris@16: Chris@16: template GIL_FORCEINLINE Chris@16: bool equal_n(I1 i1, std::ptrdiff_t n, I2 i2) { Chris@16: return detail::equal_n_fn()(i1,n,i2); Chris@16: } Chris@16: } } // namespace boost::gil Chris@16: Chris@16: namespace std { Chris@16: /// \ingroup STLOptimizations Chris@16: /// \brief std::equal(I1,I1,I2) with I1 and I2 being a iterator_from_2d Chris@16: /// Chris@16: /// Invoked when one calls std::equal(I1,I1,I2) with I1 and I2 being a iterator_from_2d (which is Chris@16: /// a 1D iterator over the pixels in an image). Attempts to demote the source and destination Chris@16: /// iterators to simpler/faster types if the corresponding range is contiguous. Chris@16: /// For contiguous images (i.e. images that have Chris@16: /// no alignment gap at the end of each row) it is more efficient to use the underlying Chris@16: /// pixel iterator that does not check for the end of rows. If the underlying pixel iterator Chris@16: /// happens to be a fundamental planar/interleaved pointer, the call may further resolve Chris@16: /// to memcmp. Otherwise it resolves to copying each row using the underlying pixel iterator Chris@16: template GIL_FORCEINLINE Chris@16: bool equal(boost::gil::iterator_from_2d first, boost::gil::iterator_from_2d last, boost::gil::iterator_from_2d first2) { Chris@16: boost::gil::gil_function_requires >(); Chris@16: boost::gil::gil_function_requires >(); Chris@16: std::ptrdiff_t n=last-first; Chris@16: if (first.is_1d_traversable()) { Chris@16: if (first2.is_1d_traversable()) Chris@16: return boost::gil::detail::equal_n_fn()(first.x(),n, first2.x()); Chris@16: else Chris@16: return boost::gil::detail::equal_n_fn >()(first.x(),n, first2); Chris@16: } else { Chris@16: if (first2.is_1d_traversable()) Chris@16: return boost::gil::detail::equal_n_fn,typename Loc2::x_iterator>()(first,n, first2.x()); Chris@16: else Chris@16: return boost::gil::detail::equal_n_fn,boost::gil::iterator_from_2d >()(first,n,first2); Chris@16: } Chris@16: } Chris@16: } // namespace std Chris@16: Chris@16: namespace boost { namespace gil { Chris@16: Chris@16: /// \ingroup ImageViewSTLAlgorithmsEqualPixels Chris@16: /// \brief std::equal for image views Chris@16: template GIL_FORCEINLINE Chris@16: bool equal_pixels(const View1& v1, const View2& v2) { Chris@16: assert(v1.dimensions()==v2.dimensions()); Chris@16: return std::equal(v1.begin(),v1.end(),v2.begin()); // std::equal has overloads with GIL iterators for optimal performance Chris@16: } Chris@16: Chris@16: ////////////////////////////////////////////////////////////////////////////////////// Chris@16: /// Chris@16: /// transform_pixels Chris@16: /// Chris@16: ////////////////////////////////////////////////////////////////////////////////////// Chris@16: Chris@16: /// \defgroup ImageViewSTLAlgorithmsTransformPixels transform_pixels Chris@16: /// \ingroup ImageViewSTLAlgorithms Chris@16: /// \brief std::transform for image views Chris@16: Chris@16: /// \ingroup ImageViewSTLAlgorithmsTransformPixels Chris@16: /// \brief std::transform for image views Chris@16: template GIL_FORCEINLINE Chris@16: F transform_pixels(const View1& src,const View2& dst, F fun) { Chris@16: assert(src.dimensions()==dst.dimensions()); Chris@16: for (std::ptrdiff_t y=0; y GIL_FORCEINLINE Chris@16: F transform_pixels(const View1& src1, const View2& src2,const View3& dst, F fun) { Chris@16: for (std::ptrdiff_t y=0; y GIL_FORCEINLINE Chris@16: F transform_pixel_positions(const View1& src,const View2& dst, F fun) { Chris@16: assert(src.dimensions()==dst.dimensions()); Chris@16: typename View1::xy_locator loc=src.xy_at(0,0); Chris@16: for (std::ptrdiff_t y=0; y GIL_FORCEINLINE Chris@16: F transform_pixel_positions(const View1& src1,const View2& src2,const View3& dst, F fun) { Chris@16: assert(src1.dimensions()==dst.dimensions()); Chris@16: assert(src2.dimensions()==dst.dimensions()); Chris@16: typename View1::xy_locator loc1=src1.xy_at(0,0); Chris@16: typename View2::xy_locator loc2=src2.xy_at(0,0); Chris@16: for (std::ptrdiff_t y=0; y