Boost GIL


algorithm.hpp
1 //
2 // Copyright 2005-2007 Adobe Systems Incorporated
3 //
4 // Distributed under the Boost Software License, Version 1.0
5 // See accompanying file LICENSE_1_0.txt or copy at
6 // http://www.boost.org/LICENSE_1_0.txt
7 //
8 #ifndef BOOST_GIL_ALGORITHM_HPP
9 #define BOOST_GIL_ALGORITHM_HPP
10 
11 #include <boost/gil/bit_aligned_pixel_iterator.hpp>
12 #include <boost/gil/color_base_algorithm.hpp>
13 #include <boost/gil/concepts.hpp>
14 #include <boost/gil/image_view.hpp>
15 #include <boost/gil/image_view_factory.hpp>
16 #include <boost/gil/detail/mp11.hpp>
17 #include <boost/gil/detail/type_traits.hpp>
18 
19 #include <boost/assert.hpp>
20 #include <boost/config.hpp>
21 
22 #include <algorithm>
23 #include <cstddef>
24 #include <cstring>
25 #include <iterator>
26 #include <memory>
27 #include <type_traits>
28 #include <typeinfo>
29 
30 namespace boost { namespace gil {
31 
32 //forward declarations
33 template <typename ChannelPtr, typename ColorSpace>
35 template <typename Iterator>
37 template <typename StepIterator>
39 
40 // a tag denoting incompatible arguments
41 struct error_t {};
42 
67 
71 
80 template <typename Derived, typename Result=void>
82 {
83  using result_type = Result;
84 
85  template <typename V1, typename V2> BOOST_FORCEINLINE
86  result_type operator()(const std::pair<const V1*,const V2*>& p) const {
87  return apply(*p.first, *p.second, typename views_are_compatible<V1,V2>::type());
88  }
89 
90  template <typename V1, typename V2> BOOST_FORCEINLINE
91  result_type operator()(const V1& v1, const V2& v2) const {
92  return apply(v1, v2, typename views_are_compatible<V1,V2>::type());
93  }
94 
95  result_type operator()(const error_t&) const { throw std::bad_cast(); }
96 private:
97 
98  // dispatch from apply overload to a function with distinct name
99  template <typename V1, typename V2>
100  BOOST_FORCEINLINE
101  result_type apply(V1 const& v1, V2 const& v2, std::false_type) const
102  {
103  return ((const Derived*)this)->apply_incompatible(v1, v2);
104  }
105 
106  // dispatch from apply overload to a function with distinct name
107  template <typename V1, typename V2>
108  BOOST_FORCEINLINE
109  result_type apply(V1 const& v1, V2 const& v2, std::true_type) const
110  {
111  return ((const Derived*)this)->apply_compatible(v1, v2);
112  }
113 
114  // function with distinct name - it can be overloaded by subclasses
115  template <typename V1, typename V2>
116  BOOST_FORCEINLINE
117  result_type apply_incompatible(V1 const& /*v1*/, V2 const& /*v2*/) const
118  {
119  throw std::bad_cast();
120  }
121 };
122 
123 }} // namespace boost::gil
124 
126 // std::copy and gil::copy_pixels
128 
132 
133 namespace std {
134 
137 template<typename T, typename CS>
138 BOOST_FORCEINLINE
139 auto copy(
144 {
145  auto p = std::copy((unsigned char*)first, (unsigned char*)last, (unsigned char*)dst);
146  return reinterpret_cast<boost::gil::pixel<T, CS>*>(p);
147 }
148 
151 template<typename T, typename CS>
152 BOOST_FORCEINLINE boost::gil::pixel<T,CS>*
155  return (boost::gil::pixel<T,CS>*)std::copy((unsigned char*)first,(unsigned char*)last, (unsigned char*)dst);
156 }
157 } // namespace std
158 
159 namespace boost { namespace gil {
160 namespace detail {
161 template <typename I, typename O> struct copy_fn {
162  BOOST_FORCEINLINE I operator()(I first, I last, O dst) const { return std::copy(first,last,dst); }
163 };
164 } // namespace detail
165 } } // namespace boost::gil
166 
167 namespace std {
170 template<typename CS, typename IC1, typename IC2> BOOST_FORCEINLINE
172  boost::gil::gil_function_requires<boost::gil::ChannelsCompatibleConcept<typename std::iterator_traits<IC1>::value_type,typename std::iterator_traits<IC2>::value_type>>();
173  static_for_each(first,last,dst,boost::gil::detail::copy_fn<IC1,IC2>());
174  return dst+(last-first);
175 }
176 } // namespace std
177 
178 namespace boost { namespace gil {
179 namespace detail {
182 template <typename I, typename O>
183 struct copier_n {
184  BOOST_FORCEINLINE void operator()(I src, typename std::iterator_traits<I>::difference_type n, O dst) const { std::copy(src,src+n, dst); }
185 };
186 
188 template <typename IL, typename O> // IL Models ConstPixelLocatorConcept, O Models PixelIteratorConcept
189 struct copier_n<iterator_from_2d<IL>,O> {
190  using diff_t = typename std::iterator_traits<iterator_from_2d<IL>>::difference_type;
191  BOOST_FORCEINLINE void operator()(iterator_from_2d<IL> src, diff_t n, O dst) const {
192  gil_function_requires<PixelLocatorConcept<IL>>();
193  gil_function_requires<MutablePixelIteratorConcept<O>>();
194  while (n>0) {
195  diff_t l=src.width()-src.x_pos();
196  diff_t numToCopy=(n<l ? n:l);
197  detail::copy_n(src.x(), numToCopy, dst);
198  dst+=numToCopy;
199  src+=numToCopy;
200  n-=numToCopy;
201  }
202  }
203 };
204 
206 template <typename I, typename OL> // I Models ConstPixelIteratorConcept, OL Models PixelLocatorConcept
207 struct copier_n<I,iterator_from_2d<OL>> {
208  using diff_t = typename std::iterator_traits<I>::difference_type;
209  BOOST_FORCEINLINE void operator()(I src, diff_t n, iterator_from_2d<OL> dst) const {
210  gil_function_requires<PixelIteratorConcept<I>>();
211  gil_function_requires<MutablePixelLocatorConcept<OL>>();
212  while (n>0) {
213  diff_t l=dst.width()-dst.x_pos();
214  diff_t numToCopy=(n<l ? n:l);
215  detail::copy_n(src, numToCopy, dst.x());
216  dst+=numToCopy;
217  src+=numToCopy;
218  n-=numToCopy;
219  }
220  }
221 };
222 
224 template <typename IL, typename OL>
226  using diff_t = typename iterator_from_2d<IL>::difference_type;
227  BOOST_FORCEINLINE void operator()(iterator_from_2d<IL> src, diff_t n, iterator_from_2d<OL> dst) const {
228  gil_function_requires<PixelLocatorConcept<IL>>();
229  gil_function_requires<MutablePixelLocatorConcept<OL>>();
230  if (src.x_pos()!=dst.x_pos() || src.width()!=dst.width()) {
231  while(n-->0) {
232  *dst++=*src++;
233  }
234  }
235  while (n>0) {
236  diff_t l=dst.width()-dst.x_pos();
237  diff_t numToCopy=(n<l ? n : l);
238  detail::copy_n(src.x(), numToCopy, dst.x());
239  dst+=numToCopy;
240  src+=numToCopy;
241  n-=numToCopy;
242  }
243  }
244 };
245 
246 template <typename SrcIterator, typename DstIterator>
247 BOOST_FORCEINLINE DstIterator copy_with_2d_iterators(SrcIterator first, SrcIterator last, DstIterator dst) {
248  using src_x_iterator = typename SrcIterator::x_iterator;
249  using dst_x_iterator = typename DstIterator::x_iterator;
250 
251  typename SrcIterator::difference_type n = last - first;
252 
253  if (first.is_1d_traversable()) {
254  if (dst.is_1d_traversable())
255  copier_n<src_x_iterator,dst_x_iterator>()(first.x(),n, dst.x());
256  else
257  copier_n<src_x_iterator,DstIterator >()(first.x(),n, dst);
258  } else {
259  if (dst.is_1d_traversable())
260  copier_n<SrcIterator,dst_x_iterator>()(first,n, dst.x());
261  else
262  copier_n<SrcIterator,DstIterator>()(first,n,dst);
263  }
264  return dst+n;
265 }
266 } // namespace detail
267 } } // namespace boost::gil
268 
269 namespace std {
272 template <typename IL, typename OL>
274  return boost::gil::detail::copy_with_2d_iterators(first,last,dst);
275 }
276 } // namespace std
277 
278 namespace boost { namespace gil {
281 template <typename View1, typename View2> BOOST_FORCEINLINE
282 void copy_pixels(const View1& src, const View2& dst)
283 {
284  BOOST_ASSERT(src.dimensions() == dst.dimensions());
285  detail::copy_with_2d_iterators(src.begin(),src.end(),dst.begin());
286 }
287 
289 // copy_and_convert_pixels
291 
297 
298 namespace detail {
299 template <typename CC>
300 class copy_and_convert_pixels_fn : public binary_operation_obj<copy_and_convert_pixels_fn<CC>>
301 {
302 private:
303  CC _cc;
304 public:
305  using result_type = typename binary_operation_obj<copy_and_convert_pixels_fn<default_color_converter>>::result_type;
306  copy_and_convert_pixels_fn() {}
307  copy_and_convert_pixels_fn(CC cc_in) : _cc(cc_in) {}
308  // when the two color spaces are incompatible, a color conversion is performed
309  template <typename V1, typename V2> BOOST_FORCEINLINE
310  result_type apply_incompatible(const V1& src, const V2& dst) const {
311  copy_pixels(color_converted_view<typename V2::value_type>(src,_cc),dst);
312  }
313 
314  // If the two color spaces are compatible, copy_and_convert is just copy
315  template <typename V1, typename V2> BOOST_FORCEINLINE
316  result_type apply_compatible(const V1& src, const V2& dst) const {
317  copy_pixels(src,dst);
318  }
319 };
320 } // namespace detail
321 
323 template <typename V1, typename V2,typename CC>
324 BOOST_FORCEINLINE
325 void copy_and_convert_pixels(const V1& src, const V2& dst,CC cc) {
326  detail::copy_and_convert_pixels_fn<CC> ccp(cc);
327  ccp(src,dst);
328 }
329 
330 struct default_color_converter;
331 
333 template <typename View1, typename View2>
334 BOOST_FORCEINLINE
335 void copy_and_convert_pixels(const View1& src, const View2& dst) {
336  detail::copy_and_convert_pixels_fn<default_color_converter> ccp;
337  ccp(src,dst);
338 }
339 } } // namespace boost::gil
340 
342 // std::fill and gil::fill_pixels
344 
348 
349 namespace std {
358 template <typename IL, typename V>
360  boost::gil::gil_function_requires<boost::gil::MutablePixelLocatorConcept<IL>>();
361  if (first.is_1d_traversable()) {
362  std::fill(first.x(), last.x(), val);
363  } else {
364  // fill row by row
365  std::ptrdiff_t n=last-first;
366  while (n>0) {
367  std::ptrdiff_t numToDo=std::min<const std::ptrdiff_t>(n,(std::ptrdiff_t)(first.width()-first.x_pos()));
368  std::fill_n(first.x(), numToDo, val);
369  first+=numToDo;
370  n-=numToDo;
371  }
372  }
373 }
374 } // namespace std
375 
376 namespace boost { namespace gil {
377 
378 namespace detail {
379 
381 struct std_fill_t {
382  template <typename It, typename P>
383  void operator()(It first, It last, const P& p_in) {
384  std::fill(first,last,p_in);
385  }
386 };
387 
389 template <typename It, typename P>
390 BOOST_FORCEINLINE
391 void fill_aux(It first, It last, P const& p, std::true_type)
392 {
393  static_for_each(first, last, p, std_fill_t());
394 }
395 
397 template <typename It, typename P>
398 BOOST_FORCEINLINE
399 void fill_aux(It first, It last, P const& p, std::false_type)
400 {
401  std::fill(first, last, p);
402 }
403 
404 } // namespace detail
405 
408 template <typename View, typename Value>
409 BOOST_FORCEINLINE
410 void fill_pixels(View const& view, Value const& value)
411 {
412  if (view.is_1d_traversable())
413  {
414  detail::fill_aux(
415  view.begin().x(), view.end().x(), value, is_planar<View>());
416  }
417  else
418  {
419  for (std::ptrdiff_t y = 0; y < view.height(); ++y)
420  detail::fill_aux(
421  view.row_begin(y), view.row_end(y), value, is_planar<View>());
422  }
423 }
424 
426 // destruct_pixels
428 
432 
433 namespace detail {
434 template <typename Iterator>
435 BOOST_FORCEINLINE
436 void destruct_range_impl(Iterator first, Iterator last,
437  typename std::enable_if
438  <
439  mp11::mp_and
440  <
441  std::is_pointer<Iterator>,
442  mp11::mp_not
443  <
444  detail::is_trivially_destructible<typename std::iterator_traits<Iterator>::value_type>
445  >
446  >::value
447  >::type* /*ptr*/ = 0)
448 {
449  while (first != last)
450  {
451  first->~value_t();
452  ++first;
453  }
454 }
455 
456 template <typename Iterator>
457 BOOST_FORCEINLINE
458 void destruct_range_impl(Iterator /*first*/, Iterator /*last*/,
459  typename std::enable_if
460  <
461  mp11::mp_or
462  <
463  mp11::mp_not<std::is_pointer<Iterator>>,
464  detail::is_trivially_destructible<typename std::iterator_traits<Iterator>::value_type>
465  >::value
466  >::type* /* ptr */ = nullptr)
467 {
468 }
469 
470 template <typename Iterator>
471 BOOST_FORCEINLINE
472 void destruct_range(Iterator first, Iterator last)
473 {
474  destruct_range_impl(first, last);
475 }
476 
477 struct std_destruct_t
478 {
479  template <typename Iterator>
480  void operator()(Iterator first, Iterator last) const
481  {
482  destruct_range(first,last);
483  }
484 };
485 
487 template <typename It>
488 BOOST_FORCEINLINE
489 void destruct_aux(It first, It last, std::true_type)
490 {
491  static_for_each(first,last,std_destruct_t());
492 }
493 
495 template <typename It>
496 BOOST_FORCEINLINE
497 void destruct_aux(It first, It last, std::false_type)
498 {
499  destruct_range(first,last);
500 }
501 
502 } // namespace detail
503 
506 template <typename View>
507 BOOST_FORCEINLINE
508 void destruct_pixels(View const& view)
509 {
510  if (view.is_1d_traversable())
511  {
512  detail::destruct_aux(
513  view.begin().x(), view.end().x(), is_planar<View>());
514  }
515  else
516  {
517  for (std::ptrdiff_t y = 0; y < view.height(); ++y)
518  detail::destruct_aux(
519  view.row_begin(y), view.row_end(y), is_planar<View>());
520  }
521 }
522 
524 // uninitialized_fill_pixels
526 
530 
531 namespace detail {
532 
535 template <typename It, typename P>
536 BOOST_FORCEINLINE
537 void uninitialized_fill_aux(It first, It last, P const& p, std::true_type)
538 {
539  std::size_t channel = 0;
540  try
541  {
542  using pixel_t = typename std::iterator_traits<It>::value_type;
543  while (channel < num_channels<pixel_t>::value)
544  {
545  std::uninitialized_fill(
546  dynamic_at_c(first,channel),
547  dynamic_at_c(last,channel),
548  dynamic_at_c(p,channel));
549 
550  ++channel;
551  }
552  }
553  catch (...)
554  {
555  for (std::size_t c = 0; c < channel; ++c)
556  destruct_range(dynamic_at_c(first, c), dynamic_at_c(last, c));
557  throw;
558  }
559 }
560 
563 template <typename It, typename P>
564 BOOST_FORCEINLINE
565 void uninitialized_fill_aux(It first, It last, P const& p, std::false_type)
566 {
567  std::uninitialized_fill(first,last,p);
568 }
569 
570 } // namespace detail
571 
576 template <typename View, typename Value>
577 void uninitialized_fill_pixels(const View& view, const Value& val) {
578  if (view.is_1d_traversable())
579  detail::uninitialized_fill_aux(view.begin().x(), view.end().x(),
580  val,is_planar<View>());
581  else {
582  typename View::y_coord_t y = 0;
583  try {
584  for (y=0; y<view.height(); ++y)
585  detail::uninitialized_fill_aux(view.row_begin(y),view.row_end(y),
586  val,is_planar<View>());
587  } catch(...) {
588  for (typename View::y_coord_t y0=0; y0<y; ++y0)
589  detail::destruct_aux(view.row_begin(y0),view.row_end(y0), is_planar<View>());
590  throw;
591  }
592  }
593 }
594 
596 // default_construct_pixels
598 
602 
603 namespace detail {
604 template <typename It> BOOST_FORCEINLINE
605 void default_construct_range_impl(It first, It last, std::true_type)
606 {
607  It first1 = first;
608  try
609  {
610  using value_t = typename std::iterator_traits<It>::value_type;
611  while (first != last)
612  {
613  new (first) value_t();
614  ++first;
615  }
616  }
617  catch (...)
618  {
619  destruct_range(first1, first);
620  throw;
621  }
622 }
623 
624 template <typename It>
625 BOOST_FORCEINLINE
626 void default_construct_range_impl(It, It, std::false_type) {}
627 
628 template <typename It>
629 BOOST_FORCEINLINE
630 void default_construct_range(It first, It last)
631 {
632  default_construct_range_impl(first, last, typename std::is_pointer<It>::type());
633 }
634 
636 template <typename It>
637 BOOST_FORCEINLINE
638 void default_construct_aux(It first, It last, std::true_type)
639 {
640  std::size_t channel = 0;
641  try
642  {
643  using pixel_t = typename std::iterator_traits<It>::value_type;
644  while (channel < num_channels<pixel_t>::value)
645  {
646  default_construct_range(dynamic_at_c(first, channel), dynamic_at_c(last, channel));
647  ++channel;
648  }
649  }
650  catch (...)
651  {
652  for (std::size_t c = 0; c < channel; ++c)
653  destruct_range(dynamic_at_c(first, c), dynamic_at_c(last, c));
654  throw;
655  }
656 }
657 
659 template <typename It>
660 BOOST_FORCEINLINE
661 void default_construct_aux(It first, It last, std::false_type)
662 {
663  default_construct_range(first, last);
664 }
665 
666 template <typename View, bool IsPlanar>
667 struct has_trivial_pixel_constructor
668  : detail::is_trivially_default_constructible<typename View::value_type>
669 {};
670 
671 template <typename View>
672 struct has_trivial_pixel_constructor<View, true>
673  : detail::is_trivially_default_constructible<typename channel_type<View>::type>
674 {};
675 
676 template<typename View, bool IsTriviallyConstructible>
677 BOOST_FORCEINLINE
678 void default_construct_pixels_impl(
679  View const& view,
680  std::enable_if<!IsTriviallyConstructible>* /*ptr*/ = nullptr)
681 {
682  if (view.is_1d_traversable())
683  {
684  detail::default_construct_aux(
685  view.begin().x(), view.end().x(), is_planar<View>());
686  }
687  else
688  {
689  typename View::y_coord_t y = 0;
690  try
691  {
692  for( y = 0; y < view.height(); ++y )
693  detail::default_construct_aux(
694  view.row_begin(y), view.row_end(y), is_planar<View>());
695  }
696  catch(...)
697  {
698  for (typename View::y_coord_t y0 = 0; y0 < y; ++y0 )
699  detail::destruct_aux(
700  view.row_begin(y0), view.row_end(y0), is_planar<View>());
701 
702  throw;
703  }
704  }
705 }
706 
707 } // namespace detail
708 
713 template <typename View>
715 {
716  detail::default_construct_pixels_impl
717  <
718  View,
719  detail::has_trivial_pixel_constructor
720  <
721  View,
722  is_planar<View>::value
723  >::value
724  >(view);
725 }
726 
728 // uninitialized_copy_pixels
730 
734 
735 namespace detail {
736 
738 template <typename It1, typename It2>
739 BOOST_FORCEINLINE
740 void uninitialized_copy_aux(It1 first1, It1 last1, It2 first2, std::true_type)
741 {
742  std::size_t channel=0;
743  try {
744  using pixel_t = typename std::iterator_traits<It1>::value_type;
745  while (channel < num_channels<pixel_t>::value)
746  {
747  std::uninitialized_copy(
748  dynamic_at_c(first1, channel),
749  dynamic_at_c(last1, channel),
750  dynamic_at_c(first2, channel));
751  ++channel;
752  }
753  }
754  catch (...)
755  {
756  It2 last2 = first2;
757  std::advance(last2, std::distance(first1, last1));
758  for (std::size_t c = 0; c < channel; ++c)
759  destruct_range(dynamic_at_c(first2, c), dynamic_at_c(last2, c));
760  throw;
761  }
762 }
763 
765 template <typename It1, typename It2>
766 BOOST_FORCEINLINE
767 void uninitialized_copy_aux(It1 first1, It1 last1, It2 first2, std::false_type)
768 {
769  std::uninitialized_copy(first1, last1, first2);
770 }
771 } // namespace detail
772 
777 template <typename View1, typename View2>
778 void uninitialized_copy_pixels(View1 const& view1, View2 const& view2)
779 {
780  using is_planar = std::integral_constant<bool, is_planar<View1>::value && is_planar<View2>::value>;
781  BOOST_ASSERT(view1.dimensions() == view2.dimensions());
782 
783  if (view1.is_1d_traversable() && view2.is_1d_traversable())
784  {
785  detail::uninitialized_copy_aux(
786  view1.begin().x(), view1.end().x(), view2.begin().x(), is_planar());
787  }
788  else
789  {
790  typename View1::y_coord_t y = 0;
791  try
792  {
793  for (y = 0; y < view1.height(); ++y)
794  detail::uninitialized_copy_aux(
795  view1.row_begin(y), view1.row_end(y), view2.row_begin(y), is_planar());
796  }
797  catch(...)
798  {
799  for (typename View1::y_coord_t y0 = 0; y0 < y; ++y0)
800  detail::destruct_aux(view2.row_begin(y0), view2.row_end(y0), is_planar());
801  throw;
802  }
803  }
804 }
805 
807 // for_each_pixel
809 
818 
820 template <typename View, typename F>
821 F for_each_pixel(View const& view, F fun)
822 {
823  if (view.is_1d_traversable())
824  {
825  return std::for_each(view.begin().x(), view.end().x(), fun);
826  }
827  else
828  {
829  for (std::ptrdiff_t y = 0; y < view.height(); ++y)
830  std::for_each(view.row_begin(y), view.row_end(y), fun);
831  return fun;
832  }
833 }
834 
838 
840 template <typename View, typename F>
841 F for_each_pixel_position(View const& view, F fun)
842 {
843  typename View::xy_locator loc = view.xy_at(0, 0);
844  for (std::ptrdiff_t y = 0; y < view.height(); ++y)
845  {
846  for (std::ptrdiff_t x = 0; x < view.width(); ++x, ++loc.x())
847  fun(loc);
848  loc.x() -= view.width(); ++loc.y();
849  }
850  return fun;
851 }
852 
854 // generate_pixels
856 
860 
863 template <typename View, typename F>
864 void generate_pixels(View const& view, F fun)
865 {
866  if (view.is_1d_traversable())
867  {
868  std::generate(view.begin().x(), view.end().x(), fun);
869  }
870  else
871  {
872  for (std::ptrdiff_t y = 0; y < view.height(); ++y)
873  std::generate(view.row_begin(y), view.row_end(y), fun);
874  }
875 }
876 
878 // std::equal and gil::equal_pixels for GIL constructs
880 
884 
885 template <typename I1, typename I2>
886 BOOST_FORCEINLINE
887 bool equal_n(I1 i1, std::ptrdiff_t n, I2 i2);
888 
889 namespace detail {
890 
891 template <typename I1, typename I2>
892 struct equal_n_fn
893 {
894  BOOST_FORCEINLINE
895  bool operator()(I1 i1, std::ptrdiff_t n, I2 i2) const
896  {
897  return std::equal(i1, i1 + n, i2);
898  }
899 };
900 
903 template<typename T, typename CS>
904 struct equal_n_fn<pixel<T, CS> const*, pixel<T, CS> const*>
905 {
906  BOOST_FORCEINLINE
907  bool operator()(pixel<T, CS> const* i1, std::ptrdiff_t n, pixel<T, CS> const* i2) const
908  {
909  return memcmp(i1, i2, n * sizeof(pixel<T, CS>)) == 0;
910  }
911 };
912 
913 template<typename T, typename CS>
914 struct equal_n_fn<pixel<T, CS>*, pixel<T, CS>*>
915  : equal_n_fn<pixel<T, CS> const*, pixel<T, CS> const*>
916 {};
917 
921 template<typename IC, typename CS>
922 struct equal_n_fn<planar_pixel_iterator<IC, CS>, planar_pixel_iterator<IC, CS>>
923 {
924  BOOST_FORCEINLINE
925  bool operator()(planar_pixel_iterator<IC, CS> const i1, std::ptrdiff_t n, planar_pixel_iterator<IC, CS> const i2) const
926  {
927  // FIXME: ptrdiff_t vs size_t
928  constexpr std::ptrdiff_t byte_size = n * sizeof(typename std::iterator_traits<IC>::value_type);
929  for (std::ptrdiff_t i = 0; i < mp11::mp_size<CS>::value; ++i)
930  {
931  if (memcmp(dynamic_at_c(i1, i), dynamic_at_c(i2, i), byte_size) != 0)
932  return false;
933  }
934  return true;
935  }
936 };
937 
941 template <typename Loc, typename It>
942 struct equal_n_fn<boost::gil::iterator_from_2d<Loc>, It>
943 {
944  BOOST_FORCEINLINE
945  bool operator()(boost::gil::iterator_from_2d<Loc> i1, std::ptrdiff_t n, It i2) const
946  {
947  gil_function_requires<boost::gil::PixelLocatorConcept<Loc>>();
948  gil_function_requires<boost::gil::PixelIteratorConcept<It>>();
949  while (n > 0)
950  {
951  std::ptrdiff_t const num = std::min<std::ptrdiff_t>(n, i1.width() - i1.x_pos());
952  if (!equal_n(i1.x(), num, i2))
953  return false;
954  i1 += num;
955  i2 += num;
956  n -= num;
957  }
958  return true;
959  }
960 };
961 
965 template <typename It, typename Loc>
966 struct equal_n_fn<It, boost::gil::iterator_from_2d<Loc>>
967 {
968  BOOST_FORCEINLINE
969  bool operator()(It i1, std::ptrdiff_t n, boost::gil::iterator_from_2d<Loc> i2) const
970  {
971  gil_function_requires<boost::gil::PixelIteratorConcept<It>>();
972  gil_function_requires<boost::gil::PixelLocatorConcept<Loc>>();
973  while (n > 0)
974  {
975  std::ptrdiff_t const num = std::min<std::ptrdiff_t>(n, i2.width() - i2.x_pos());
976  if (!equal_n(i1, num, i2.x()))
977  return false;
978  i1 += num;
979  i2 += num;
980  n -= num;
981  }
982  return true;
983  }
984 };
985 
987 template <typename Loc1, typename Loc2>
988 struct equal_n_fn<boost::gil::iterator_from_2d<Loc1>,boost::gil::iterator_from_2d<Loc2>> {
989  BOOST_FORCEINLINE bool operator()(boost::gil::iterator_from_2d<Loc1> i1, std::ptrdiff_t n, boost::gil::iterator_from_2d<Loc2> i2) const {
990  gil_function_requires<boost::gil::PixelLocatorConcept<Loc1>>();
991  gil_function_requires<boost::gil::PixelLocatorConcept<Loc2>>();
992  if (i1.x_pos()!=i2.x_pos() || i1.width()!=i2.width()) {
993  while(n-->0) {
994  if (*i1++!=*i2++) return false;
995  }
996  }
997  while (n>0) {
998  std::ptrdiff_t num=std::min<const std::ptrdiff_t>(n,i2.width()-i2.x_pos());
999  if (!equal_n(i1.x(), num, i2.x()))
1000  return false;
1001  i1+=num;
1002  i2+=num;
1003  n-=num;
1004  }
1005  return true;
1006  }
1007 };
1008 } // namespace detail
1009 
1010 template <typename I1, typename I2> BOOST_FORCEINLINE
1011 bool equal_n(I1 i1, std::ptrdiff_t n, I2 i2) {
1012  return detail::equal_n_fn<I1,I2>()(i1,n,i2);
1013 }
1014 } } // namespace boost::gil
1015 
1016 namespace std {
1028 template <typename Loc1, typename Loc2> BOOST_FORCEINLINE
1030  boost::gil::gil_function_requires<boost::gil::PixelLocatorConcept<Loc1>>();
1031  boost::gil::gil_function_requires<boost::gil::PixelLocatorConcept<Loc2>>();
1032  std::ptrdiff_t n=last-first;
1033  if (first.is_1d_traversable()) {
1034  if (first2.is_1d_traversable())
1035  return boost::gil::detail::equal_n_fn<typename Loc1::x_iterator,typename Loc2::x_iterator>()(first.x(),n, first2.x());
1036  else
1037  return boost::gil::detail::equal_n_fn<typename Loc1::x_iterator,boost::gil::iterator_from_2d<Loc2>>()(first.x(),n, first2);
1038  } else {
1039  if (first2.is_1d_traversable())
1040  return boost::gil::detail::equal_n_fn<boost::gil::iterator_from_2d<Loc1>,typename Loc2::x_iterator>()(first,n, first2.x());
1041  else
1042  return boost::gil::detail::equal_n_fn<boost::gil::iterator_from_2d<Loc1>,boost::gil::iterator_from_2d<Loc2>>()(first,n,first2);
1043  }
1044 }
1045 } // namespace std
1046 
1047 namespace boost { namespace gil {
1050 template <typename View1, typename View2> BOOST_FORCEINLINE
1051 bool equal_pixels(const View1& v1, const View2& v2) {
1052  BOOST_ASSERT(v1.dimensions() == v2.dimensions());
1053  return std::equal(v1.begin(),v1.end(),v2.begin()); // std::equal has overloads with GIL iterators for optimal performance
1054 }
1055 
1061 
1065 
1068 template <typename View1, typename View2, typename F> BOOST_FORCEINLINE
1069 F transform_pixels(const View1& src,const View2& dst, F fun) {
1070  BOOST_ASSERT(src.dimensions() == dst.dimensions());
1071  for (std::ptrdiff_t y=0; y<src.height(); ++y) {
1072  typename View1::x_iterator srcIt=src.row_begin(y);
1073  typename View2::x_iterator dstIt=dst.row_begin(y);
1074  for (std::ptrdiff_t x=0; x<src.width(); ++x)
1075  dstIt[x]=fun(srcIt[x]);
1076  }
1077  return fun;
1078 }
1079 
1082 template <typename View1, typename View2, typename View3, typename F> BOOST_FORCEINLINE
1083 F transform_pixels(const View1& src1, const View2& src2,const View3& dst, F fun) {
1084  for (std::ptrdiff_t y=0; y<dst.height(); ++y) {
1085  typename View1::x_iterator srcIt1=src1.row_begin(y);
1086  typename View2::x_iterator srcIt2=src2.row_begin(y);
1087  typename View3::x_iterator dstIt=dst.row_begin(y);
1088  for (std::ptrdiff_t x=0; x<dst.width(); ++x)
1089  dstIt[x]=fun(srcIt1[x],srcIt2[x]);
1090  }
1091  return fun;
1092 }
1093 
1097 
1100 template <typename View1, typename View2, typename F> BOOST_FORCEINLINE
1101 F transform_pixel_positions(const View1& src,const View2& dst, F fun) {
1102  BOOST_ASSERT(src.dimensions() == dst.dimensions());
1103  typename View1::xy_locator loc=src.xy_at(0,0);
1104  for (std::ptrdiff_t y=0; y<src.height(); ++y) {
1105  typename View2::x_iterator dstIt=dst.row_begin(y);
1106  for (std::ptrdiff_t x=0; x<src.width(); ++x, ++loc.x())
1107  dstIt[x]=fun(loc);
1108  loc.x()-=src.width(); ++loc.y();
1109  }
1110  return fun;
1111 }
1112 
1115 template <typename View1, typename View2, typename View3, typename F> BOOST_FORCEINLINE
1116 F transform_pixel_positions(const View1& src1,const View2& src2,const View3& dst, F fun) {
1117  BOOST_ASSERT(src1.dimensions() == dst.dimensions());
1118  BOOST_ASSERT(src2.dimensions() == dst.dimensions());
1119  typename View1::xy_locator loc1=src1.xy_at(0,0);
1120  typename View2::xy_locator loc2=src2.xy_at(0,0);
1121  for (std::ptrdiff_t y=0; y<src1.height(); ++y) {
1122  typename View3::x_iterator dstIt=dst.row_begin(y);
1123  for (std::ptrdiff_t x=0; x<src1.width(); ++x, ++loc1.x(), ++loc2.x())
1124  dstIt[x]=fun(loc1,loc2);
1125  loc1.x()-=src1.width(); ++loc1.y();
1126  loc2.x()-=src2.width(); ++loc2.y();
1127  }
1128  return fun;
1129 }
1130 } } // namespace boost::gil
1131 
1132 #endif
void default_construct_pixels(View const &view)
Invokes the in-place default constructor on every pixel of the (uninitialized) view....
Definition: algorithm.hpp:714
Represents a pixel value (a container of channels). Models: HomogeneousColorBaseValueConcept,...
Definition: metafunctions.hpp:23
BOOST_FORCEINLINE F transform_pixels(const View1 &src1, const View2 &src2, const View3 &dst, F fun)
transform_pixels with two sources
Definition: algorithm.hpp:1083
BOOST_FORCEINLINE void fill_pixels(View const &view, Value const &value)
std::fill for image views
Definition: algorithm.hpp:410
An iterator over planar pixels. Models HomogeneousColorBaseConcept, PixelIteratorConcept,...
Definition: algorithm.hpp:34
Definition: algorithm.hpp:183
Provides 1D random-access navigation to the pixels of the image. Models: PixelIteratorConcept,...
Definition: iterator_from_2d.hpp:42
BOOST_FORCEINLINE boost::gil::planar_pixel_iterator< IC2, CS > copy(boost::gil::planar_pixel_iterator< IC1, CS > first, boost::gil::planar_pixel_iterator< IC1, CS > last, boost::gil::planar_pixel_iterator< IC2, CS > dst)
Copy when both src and dst are planar pointers is copy for each channel.
Definition: algorithm.hpp:171
void generate_pixels(View const &view, F fun)
std::generate for image views
Definition: algorithm.hpp:864
void uninitialized_copy_pixels(View1 const &view1, View2 const &view2)
std::uninitialized_copy for image views. Does not support planar heterogeneous views....
Definition: algorithm.hpp:778
Memory-based pixel locator. Models: PixelLocatorConcept,HasDynamicXStepTypeConcept,...
Definition: algorithm.hpp:38
BOOST_FORCEINLINE bool equal_pixels(const View1 &v1, const View2 &v2)
std::equal for image views
Definition: algorithm.hpp:1051
void fill(boost::gil::iterator_from_2d< IL > first, boost::gil::iterator_from_2d< IL > last, const V &val)
std::fill(I,I,V) with I being a iterator_from_2d
Definition: algorithm.hpp:359
Returns whether two views are compatible.
Definition: concepts/image_view.hpp:522
BOOST_FORCEINLINE void copy_pixels(const View1 &src, const View2 &dst)
std::copy for image views
Definition: algorithm.hpp:282
BOOST_FORCEINLINE boost::gil::iterator_from_2d< OL > copy1(boost::gil::iterator_from_2d< IL > first, boost::gil::iterator_from_2d< IL > last, boost::gil::iterator_from_2d< OL > dst)
std::copy(I1,I1,I2) with I1 and I2 being a iterator_from_2d
Definition: algorithm.hpp:273
void uninitialized_fill_pixels(const View &view, const Value &val)
std::uninitialized_fill for image views. Does not support planar heterogeneous views....
Definition: algorithm.hpp:577
BOOST_FORCEINLINE bool equal(boost::gil::iterator_from_2d< Loc1 > first, boost::gil::iterator_from_2d< Loc1 > last, boost::gil::iterator_from_2d< Loc2 > first2)
std::equal(I1,I1,I2) with I1 and I2 being a iterator_from_2d
Definition: algorithm.hpp:1029
A generic binary operation on viewsUse this class as a convenience superclass when defining an operat...
Definition: algorithm.hpp:81
struct to do std::fill
Definition: algorithm.hpp:381
const image< Pixel, IsPlanar, Alloc >::view_t & view(image< Pixel, IsPlanar, Alloc > &img)
Returns the non-constant-pixel view of an image.
Definition: image.hpp:535
BOOST_FORCEINLINE F transform_pixel_positions(const View1 &src1, const View2 &src2, const View3 &dst, F fun)
transform_pixel_positions with two sources
Definition: algorithm.hpp:1116
BOOST_FORCEINLINE void destruct_pixels(View const &view)
Invokes the in-place destructor on every pixel of the view.
Definition: algorithm.hpp:508
MEMORY-BASED STEP ITERATOR.
Definition: algorithm.hpp:36