algorithm.hpp 40 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132
  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. #include <boost/gil/bit_aligned_pixel_iterator.hpp>
  11. #include <boost/gil/color_base_algorithm.hpp>
  12. #include <boost/gil/concepts.hpp>
  13. #include <boost/gil/image_view.hpp>
  14. #include <boost/gil/image_view_factory.hpp>
  15. #include <boost/gil/detail/mp11.hpp>
  16. #include <boost/gil/detail/type_traits.hpp>
  17. #include <boost/assert.hpp>
  18. #include <boost/config.hpp>
  19. #include <algorithm>
  20. #include <cstddef>
  21. #include <cstring>
  22. #include <iterator>
  23. #include <memory>
  24. #include <type_traits>
  25. #include <typeinfo>
  26. namespace boost { namespace gil {
  27. //forward declarations
  28. template <typename ChannelPtr, typename ColorSpace>
  29. struct planar_pixel_iterator;
  30. template <typename Iterator>
  31. class memory_based_step_iterator;
  32. template <typename StepIterator>
  33. class memory_based_2d_locator;
  34. // a tag denoting incompatible arguments
  35. struct error_t {};
  36. /// \defgroup ImageViewSTLAlgorithms STL-like Algorithms
  37. /// \ingroup ImageViewAlgorithm
  38. /// \brief Image view-equivalents of STL algorithms
  39. ///
  40. /// Image views provide 1D iteration of their pixels via \p begin() and \p end() methods,
  41. /// which makes it possible to use STL algorithms with them. However, using nested loops
  42. /// over X and Y is in many cases more efficient. The algorithms in this section resemble
  43. /// STL algorithms, but they abstract away the nested loops and take views (as opposed to ranges) as input.
  44. ///
  45. /// Most algorithms check whether the image views are 1D-traversable. A 1D-traversable image view has no gaps
  46. /// 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
  47. /// it will move to the first pixel of the next row. When image views are 1D-traversable, the algorithms use
  48. /// a single loop and run more efficiently. If one or more of the input views are not 1D-traversable, the algorithms
  49. /// fall-back to an X-loop nested inside a Y-loop.
  50. ///
  51. /// The algorithms typically delegate the work to their corresponding STL algorithms. For example, \p copy_pixels calls
  52. /// \p std::copy either for each row, or, when the images are 1D-traversable, once for all pixels.
  53. ///
  54. /// In addition, overloads are sometimes provided for the STL algorithms. For example, std::copy for planar iterators
  55. /// is overloaded to perform \p std::copy for each of the planes. \p std::copy over bitwise-copiable pixels results in
  56. /// std::copy over unsigned char, which STL typically implements via \p memmove.
  57. ///
  58. /// As a result \p copy_pixels may result in a single call to \p memmove for interleaved 1D-traversable views,
  59. /// or one per each plane of planar 1D-traversable views, or one per each row of interleaved non-1D-traversable images, etc.
  60. /// \defgroup STLOptimizations Performance overloads of STL algorithms
  61. /// \ingroup ImageViewAlgorithm
  62. /// \brief overloads of STL algorithms allowing more efficient implementation when used with GIL constructs
  63. /// \brief A generic binary operation on views
  64. /// \ingroup ImageViewSTLAlgorithms
  65. ///
  66. /// Use this class as a convenience superclass when defining an operation for any image views.
  67. /// Many operations have different behavior when the two views are compatible. This class checks
  68. /// for compatibility and invokes apply_compatible(V1,V2) or apply_incompatible(V1,V2) of the subclass.
  69. /// You must provide apply_compatible(V1,V2) method in your subclass, but apply_incompatible(V1,V2)
  70. /// is not required and the default throws std::bad_cast.
  71. template <typename Derived, typename Result=void>
  72. struct binary_operation_obj
  73. {
  74. using result_type = Result;
  75. template <typename V1, typename V2> BOOST_FORCEINLINE
  76. result_type operator()(const std::pair<const V1*,const V2*>& p) const {
  77. return apply(*p.first, *p.second, typename views_are_compatible<V1,V2>::type());
  78. }
  79. template <typename V1, typename V2> BOOST_FORCEINLINE
  80. result_type operator()(const V1& v1, const V2& v2) const {
  81. return apply(v1, v2, typename views_are_compatible<V1,V2>::type());
  82. }
  83. result_type operator()(const error_t&) const { throw std::bad_cast(); }
  84. private:
  85. // dispatch from apply overload to a function with distinct name
  86. template <typename V1, typename V2>
  87. BOOST_FORCEINLINE
  88. result_type apply(V1 const& v1, V2 const& v2, std::false_type) const
  89. {
  90. return ((const Derived*)this)->apply_incompatible(v1, v2);
  91. }
  92. // dispatch from apply overload to a function with distinct name
  93. template <typename V1, typename V2>
  94. BOOST_FORCEINLINE
  95. result_type apply(V1 const& v1, V2 const& v2, std::true_type) const
  96. {
  97. return ((const Derived*)this)->apply_compatible(v1, v2);
  98. }
  99. // function with distinct name - it can be overloaded by subclasses
  100. template <typename V1, typename V2>
  101. BOOST_FORCEINLINE
  102. result_type apply_incompatible(V1 const& /*v1*/, V2 const& /*v2*/) const
  103. {
  104. throw std::bad_cast();
  105. }
  106. };
  107. }} // namespace boost::gil
  108. //////////////////////////////////////////////////////////////////////////////////////
  109. // std::copy and gil::copy_pixels
  110. //////////////////////////////////////////////////////////////////////////////////////
  111. /// \defgroup ImageViewSTLAlgorithmsCopyPixels copy_pixels
  112. /// \ingroup ImageViewSTLAlgorithms
  113. /// \brief std::copy for image views
  114. namespace std {
  115. /// \ingroup STLOptimizations
  116. /// \brief Copy when both src and dst are interleaved and of the same type can be just memmove
  117. template<typename T, typename CS>
  118. BOOST_FORCEINLINE
  119. auto copy(
  120. boost::gil::pixel<T, CS>* first,
  121. boost::gil::pixel<T, CS>* last,
  122. boost::gil::pixel<T, CS>* dst)
  123. -> boost::gil::pixel<T, CS>*
  124. {
  125. auto p = std::copy((unsigned char*)first, (unsigned char*)last, (unsigned char*)dst);
  126. return reinterpret_cast<boost::gil::pixel<T, CS>*>(p);
  127. }
  128. /// \ingroup STLOptimizations
  129. /// \brief Copy when both src and dst are interleaved and of the same type can be just memmove
  130. template<typename T, typename CS>
  131. BOOST_FORCEINLINE boost::gil::pixel<T,CS>*
  132. copy(const boost::gil::pixel<T,CS>* first, const boost::gil::pixel<T,CS>* last,
  133. boost::gil::pixel<T,CS>* dst) {
  134. return (boost::gil::pixel<T,CS>*)std::copy((unsigned char*)first,(unsigned char*)last, (unsigned char*)dst);
  135. }
  136. } // namespace std
  137. namespace boost { namespace gil {
  138. namespace detail {
  139. template <typename I, typename O> struct copy_fn {
  140. BOOST_FORCEINLINE I operator()(I first, I last, O dst) const { return std::copy(first,last,dst); }
  141. };
  142. } // namespace detail
  143. } } // namespace boost::gil
  144. namespace std {
  145. /// \ingroup STLOptimizations
  146. /// \brief Copy when both src and dst are planar pointers is copy for each channel
  147. template<typename CS, typename IC1, typename IC2> BOOST_FORCEINLINE
  148. 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) {
  149. boost::gil::gil_function_requires<boost::gil::ChannelsCompatibleConcept<typename std::iterator_traits<IC1>::value_type,typename std::iterator_traits<IC2>::value_type>>();
  150. static_for_each(first,last,dst,boost::gil::detail::copy_fn<IC1,IC2>());
  151. return dst+(last-first);
  152. }
  153. } // namespace std
  154. namespace boost { namespace gil {
  155. namespace detail {
  156. /// Does a copy-n. If the inputs contain image iterators, performs a copy at each row using the row iterators
  157. /// \ingroup CopyPixels
  158. template <typename I, typename O>
  159. struct copier_n {
  160. BOOST_FORCEINLINE void operator()(I src, typename std::iterator_traits<I>::difference_type n, O dst) const { std::copy(src,src+n, dst); }
  161. };
  162. /// Source range is delimited by image iterators
  163. template <typename IL, typename O> // IL Models ConstPixelLocatorConcept, O Models PixelIteratorConcept
  164. struct copier_n<iterator_from_2d<IL>,O> {
  165. using diff_t = typename std::iterator_traits<iterator_from_2d<IL>>::difference_type;
  166. BOOST_FORCEINLINE void operator()(iterator_from_2d<IL> src, diff_t n, O dst) const {
  167. gil_function_requires<PixelLocatorConcept<IL>>();
  168. gil_function_requires<MutablePixelIteratorConcept<O>>();
  169. while (n>0) {
  170. diff_t l=src.width()-src.x_pos();
  171. diff_t numToCopy=(n<l ? n:l);
  172. detail::copy_n(src.x(), numToCopy, dst);
  173. dst+=numToCopy;
  174. src+=numToCopy;
  175. n-=numToCopy;
  176. }
  177. }
  178. };
  179. /// Destination range is delimited by image iterators
  180. template <typename I, typename OL> // I Models ConstPixelIteratorConcept, OL Models PixelLocatorConcept
  181. struct copier_n<I,iterator_from_2d<OL>> {
  182. using diff_t = typename std::iterator_traits<I>::difference_type;
  183. BOOST_FORCEINLINE void operator()(I src, diff_t n, iterator_from_2d<OL> dst) const {
  184. gil_function_requires<PixelIteratorConcept<I>>();
  185. gil_function_requires<MutablePixelLocatorConcept<OL>>();
  186. while (n>0) {
  187. diff_t l=dst.width()-dst.x_pos();
  188. diff_t numToCopy=(n<l ? n:l);
  189. detail::copy_n(src, numToCopy, dst.x());
  190. dst+=numToCopy;
  191. src+=numToCopy;
  192. n-=numToCopy;
  193. }
  194. }
  195. };
  196. /// Both source and destination ranges are delimited by image iterators
  197. template <typename IL, typename OL>
  198. struct copier_n<iterator_from_2d<IL>,iterator_from_2d<OL>> {
  199. using diff_t = typename iterator_from_2d<IL>::difference_type;
  200. BOOST_FORCEINLINE void operator()(iterator_from_2d<IL> src, diff_t n, iterator_from_2d<OL> dst) const {
  201. gil_function_requires<PixelLocatorConcept<IL>>();
  202. gil_function_requires<MutablePixelLocatorConcept<OL>>();
  203. if (src.x_pos()!=dst.x_pos() || src.width()!=dst.width()) {
  204. while(n-->0) {
  205. *dst++=*src++;
  206. }
  207. }
  208. while (n>0) {
  209. diff_t l=dst.width()-dst.x_pos();
  210. diff_t numToCopy=(n<l ? n : l);
  211. detail::copy_n(src.x(), numToCopy, dst.x());
  212. dst+=numToCopy;
  213. src+=numToCopy;
  214. n-=numToCopy;
  215. }
  216. }
  217. };
  218. template <typename SrcIterator, typename DstIterator>
  219. BOOST_FORCEINLINE DstIterator copy_with_2d_iterators(SrcIterator first, SrcIterator last, DstIterator dst) {
  220. using src_x_iterator = typename SrcIterator::x_iterator;
  221. using dst_x_iterator = typename DstIterator::x_iterator;
  222. typename SrcIterator::difference_type n = last - first;
  223. if (first.is_1d_traversable()) {
  224. if (dst.is_1d_traversable())
  225. copier_n<src_x_iterator,dst_x_iterator>()(first.x(),n, dst.x());
  226. else
  227. copier_n<src_x_iterator,DstIterator >()(first.x(),n, dst);
  228. } else {
  229. if (dst.is_1d_traversable())
  230. copier_n<SrcIterator,dst_x_iterator>()(first,n, dst.x());
  231. else
  232. copier_n<SrcIterator,DstIterator>()(first,n,dst);
  233. }
  234. return dst+n;
  235. }
  236. } // namespace detail
  237. } } // namespace boost::gil
  238. namespace std {
  239. /// \ingroup STLOptimizations
  240. /// \brief std::copy(I1,I1,I2) with I1 and I2 being a iterator_from_2d
  241. template <typename IL, typename OL>
  242. 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) {
  243. return boost::gil::detail::copy_with_2d_iterators(first,last,dst);
  244. }
  245. } // namespace std
  246. namespace boost { namespace gil {
  247. /// \ingroup ImageViewSTLAlgorithmsCopyPixels
  248. /// \brief std::copy for image views
  249. template <typename View1, typename View2> BOOST_FORCEINLINE
  250. void copy_pixels(const View1& src, const View2& dst)
  251. {
  252. BOOST_ASSERT(src.dimensions() == dst.dimensions());
  253. detail::copy_with_2d_iterators(src.begin(),src.end(),dst.begin());
  254. }
  255. //////////////////////////////////////////////////////////////////////////////////////
  256. // copy_and_convert_pixels
  257. //////////////////////////////////////////////////////////////////////////////////////
  258. /// \defgroup ImageViewSTLAlgorithmsCopyAndConvertPixels copy_and_convert_pixels
  259. /// \ingroup ImageViewSTLAlgorithms
  260. /// \brief copies src view into dst view, color converting if necessary.
  261. ///
  262. /// Versions taking static and runtime views are provided. Versions taking user-defined color convered are provided.
  263. namespace detail {
  264. template <typename CC>
  265. class copy_and_convert_pixels_fn : public binary_operation_obj<copy_and_convert_pixels_fn<CC>>
  266. {
  267. private:
  268. CC _cc;
  269. public:
  270. using result_type = typename binary_operation_obj<copy_and_convert_pixels_fn<default_color_converter>>::result_type;
  271. copy_and_convert_pixels_fn() {}
  272. copy_and_convert_pixels_fn(CC cc_in) : _cc(cc_in) {}
  273. // when the two color spaces are incompatible, a color conversion is performed
  274. template <typename V1, typename V2> BOOST_FORCEINLINE
  275. result_type apply_incompatible(const V1& src, const V2& dst) const {
  276. copy_pixels(color_converted_view<typename V2::value_type>(src,_cc),dst);
  277. }
  278. // If the two color spaces are compatible, copy_and_convert is just copy
  279. template <typename V1, typename V2> BOOST_FORCEINLINE
  280. result_type apply_compatible(const V1& src, const V2& dst) const {
  281. copy_pixels(src,dst);
  282. }
  283. };
  284. } // namespace detail
  285. /// \ingroup ImageViewSTLAlgorithmsCopyAndConvertPixels
  286. template <typename V1, typename V2,typename CC>
  287. BOOST_FORCEINLINE
  288. void copy_and_convert_pixels(const V1& src, const V2& dst,CC cc) {
  289. detail::copy_and_convert_pixels_fn<CC> ccp(cc);
  290. ccp(src,dst);
  291. }
  292. struct default_color_converter;
  293. /// \ingroup ImageViewSTLAlgorithmsCopyAndConvertPixels
  294. template <typename View1, typename View2>
  295. BOOST_FORCEINLINE
  296. void copy_and_convert_pixels(const View1& src, const View2& dst) {
  297. detail::copy_and_convert_pixels_fn<default_color_converter> ccp;
  298. ccp(src,dst);
  299. }
  300. } } // namespace boost::gil
  301. //////////////////////////////////////////////////////////////////////////////////////
  302. // std::fill and gil::fill_pixels
  303. //////////////////////////////////////////////////////////////////////////////////////
  304. /// \defgroup ImageViewSTLAlgorithmsFillPixels fill_pixels
  305. /// \ingroup ImageViewSTLAlgorithms
  306. /// \brief std::fill for image views
  307. namespace std {
  308. /// \ingroup STLOptimizations
  309. /// \brief std::fill(I,I,V) with I being a iterator_from_2d
  310. ///
  311. /// Invoked when one calls std::fill(I,I,V) with I being a iterator_from_2d (which is
  312. /// a 1D iterator over the pixels in an image). For contiguous images (i.e. images that have
  313. /// no alignment gap at the end of each row) it is more efficient to use the underlying
  314. /// pixel iterator that does not check for the end of rows. For non-contiguous images fill
  315. /// resolves to fill of each row using the underlying pixel iterator, which is still faster
  316. template <typename IL, typename V>
  317. void fill(boost::gil::iterator_from_2d<IL> first, boost::gil::iterator_from_2d<IL> last, const V& val) {
  318. boost::gil::gil_function_requires<boost::gil::MutablePixelLocatorConcept<IL>>();
  319. if (first.is_1d_traversable()) {
  320. std::fill(first.x(), last.x(), val);
  321. } else {
  322. // fill row by row
  323. std::ptrdiff_t n=last-first;
  324. while (n>0) {
  325. std::ptrdiff_t numToDo=std::min<const std::ptrdiff_t>(n,(std::ptrdiff_t)(first.width()-first.x_pos()));
  326. std::fill_n(first.x(), numToDo, val);
  327. first+=numToDo;
  328. n-=numToDo;
  329. }
  330. }
  331. }
  332. } // namespace std
  333. namespace boost { namespace gil {
  334. namespace detail {
  335. /// struct to do std::fill
  336. struct std_fill_t {
  337. template <typename It, typename P>
  338. void operator()(It first, It last, const P& p_in) {
  339. std::fill(first,last,p_in);
  340. }
  341. };
  342. /// std::fill for planar iterators
  343. template <typename It, typename P>
  344. BOOST_FORCEINLINE
  345. void fill_aux(It first, It last, P const& p, std::true_type)
  346. {
  347. static_for_each(first, last, p, std_fill_t());
  348. }
  349. /// std::fill for interleaved iterators
  350. template <typename It, typename P>
  351. BOOST_FORCEINLINE
  352. void fill_aux(It first, It last, P const& p, std::false_type)
  353. {
  354. std::fill(first, last, p);
  355. }
  356. } // namespace detail
  357. /// \ingroup ImageViewSTLAlgorithmsFillPixels
  358. /// \brief std::fill for image views
  359. template <typename View, typename Value>
  360. BOOST_FORCEINLINE
  361. void fill_pixels(View const& view, Value const& value)
  362. {
  363. if (view.is_1d_traversable())
  364. {
  365. detail::fill_aux(
  366. view.begin().x(), view.end().x(), value, is_planar<View>());
  367. }
  368. else
  369. {
  370. for (std::ptrdiff_t y = 0; y < view.height(); ++y)
  371. detail::fill_aux(
  372. view.row_begin(y), view.row_end(y), value, is_planar<View>());
  373. }
  374. }
  375. //////////////////////////////////////////////////////////////////////////////////////
  376. // destruct_pixels
  377. //////////////////////////////////////////////////////////////////////////////////////
  378. /// \defgroup ImageViewSTLAlgorithmsDestructPixels destruct_pixels
  379. /// \ingroup ImageViewSTLAlgorithms
  380. /// \brief invokes the destructor on every pixel of an image view
  381. namespace detail {
  382. template <typename Iterator>
  383. BOOST_FORCEINLINE
  384. void destruct_range_impl(Iterator first, Iterator last,
  385. typename std::enable_if
  386. <
  387. mp11::mp_and
  388. <
  389. std::is_pointer<Iterator>,
  390. mp11::mp_not
  391. <
  392. detail::is_trivially_destructible<typename std::iterator_traits<Iterator>::value_type>
  393. >
  394. >::value
  395. >::type* /*ptr*/ = 0)
  396. {
  397. while (first != last)
  398. {
  399. first->~value_t();
  400. ++first;
  401. }
  402. }
  403. template <typename Iterator>
  404. BOOST_FORCEINLINE
  405. void destruct_range_impl(Iterator /*first*/, Iterator /*last*/,
  406. typename std::enable_if
  407. <
  408. mp11::mp_or
  409. <
  410. mp11::mp_not<std::is_pointer<Iterator>>,
  411. detail::is_trivially_destructible<typename std::iterator_traits<Iterator>::value_type>
  412. >::value
  413. >::type* /* ptr */ = nullptr)
  414. {
  415. }
  416. template <typename Iterator>
  417. BOOST_FORCEINLINE
  418. void destruct_range(Iterator first, Iterator last)
  419. {
  420. destruct_range_impl(first, last);
  421. }
  422. struct std_destruct_t
  423. {
  424. template <typename Iterator>
  425. void operator()(Iterator first, Iterator last) const
  426. {
  427. destruct_range(first,last);
  428. }
  429. };
  430. /// destruct for planar iterators
  431. template <typename It>
  432. BOOST_FORCEINLINE
  433. void destruct_aux(It first, It last, std::true_type)
  434. {
  435. static_for_each(first,last,std_destruct_t());
  436. }
  437. /// destruct for interleaved iterators
  438. template <typename It>
  439. BOOST_FORCEINLINE
  440. void destruct_aux(It first, It last, std::false_type)
  441. {
  442. destruct_range(first,last);
  443. }
  444. } // namespace detail
  445. /// \ingroup ImageViewSTLAlgorithmsDestructPixels
  446. /// \brief Invokes the in-place destructor on every pixel of the view
  447. template <typename View>
  448. BOOST_FORCEINLINE
  449. void destruct_pixels(View const& view)
  450. {
  451. if (view.is_1d_traversable())
  452. {
  453. detail::destruct_aux(
  454. view.begin().x(), view.end().x(), is_planar<View>());
  455. }
  456. else
  457. {
  458. for (std::ptrdiff_t y = 0; y < view.height(); ++y)
  459. detail::destruct_aux(
  460. view.row_begin(y), view.row_end(y), is_planar<View>());
  461. }
  462. }
  463. //////////////////////////////////////////////////////////////////////////////////////
  464. // uninitialized_fill_pixels
  465. //////////////////////////////////////////////////////////////////////////////////////
  466. /// \defgroup ImageViewSTLAlgorithmsUninitializedFillPixels uninitialized_fill_pixels
  467. /// \ingroup ImageViewSTLAlgorithms
  468. /// \brief std::uninitialized_fill for image views
  469. namespace detail {
  470. /// std::uninitialized_fill for planar iterators
  471. /// If an exception is thrown destructs any in-place copy-constructed objects
  472. template <typename It, typename P>
  473. BOOST_FORCEINLINE
  474. void uninitialized_fill_aux(It first, It last, P const& p, std::true_type)
  475. {
  476. int channel = 0;
  477. try
  478. {
  479. using pixel_t = typename std::iterator_traits<It>::value_type;
  480. while (channel < num_channels<pixel_t>::value)
  481. {
  482. std::uninitialized_fill(
  483. dynamic_at_c(first,channel),
  484. dynamic_at_c(last,channel),
  485. dynamic_at_c(p,channel));
  486. ++channel;
  487. }
  488. }
  489. catch (...)
  490. {
  491. for (int c = 0; c < channel; ++c)
  492. destruct_range(dynamic_at_c(first, c), dynamic_at_c(last, c));
  493. throw;
  494. }
  495. }
  496. /// std::uninitialized_fill for interleaved iterators
  497. /// If an exception is thrown destructs any in-place copy-constructed objects
  498. template <typename It, typename P>
  499. BOOST_FORCEINLINE
  500. void uninitialized_fill_aux(It first, It last, P const& p, std::false_type)
  501. {
  502. std::uninitialized_fill(first,last,p);
  503. }
  504. } // namespace detail
  505. /// \ingroup ImageViewSTLAlgorithmsUninitializedFillPixels
  506. /// \brief std::uninitialized_fill for image views.
  507. /// Does not support planar heterogeneous views.
  508. /// If an exception is thrown destructs any in-place copy-constructed pixels
  509. template <typename View, typename Value>
  510. void uninitialized_fill_pixels(const View& view, const Value& val) {
  511. if (view.is_1d_traversable())
  512. detail::uninitialized_fill_aux(view.begin().x(), view.end().x(),
  513. val,is_planar<View>());
  514. else {
  515. typename View::y_coord_t y = 0;
  516. try {
  517. for (y=0; y<view.height(); ++y)
  518. detail::uninitialized_fill_aux(view.row_begin(y),view.row_end(y),
  519. val,is_planar<View>());
  520. } catch(...) {
  521. for (typename View::y_coord_t y0=0; y0<y; ++y0)
  522. detail::destruct_aux(view.row_begin(y0),view.row_end(y0), is_planar<View>());
  523. throw;
  524. }
  525. }
  526. }
  527. //////////////////////////////////////////////////////////////////////////////////////
  528. // default_construct_pixels
  529. //////////////////////////////////////////////////////////////////////////////////////
  530. /// \defgroup ImageViewSTLAlgorithmsDefaultConstructPixels default_construct_pixels
  531. /// \ingroup ImageViewSTLAlgorithms
  532. /// \brief invokes the default constructor on every pixel of an image view
  533. namespace detail {
  534. template <typename It> BOOST_FORCEINLINE
  535. void default_construct_range_impl(It first, It last, std::true_type)
  536. {
  537. It first1 = first;
  538. try
  539. {
  540. using value_t = typename std::iterator_traits<It>::value_type;
  541. while (first != last)
  542. {
  543. new (first) value_t();
  544. ++first;
  545. }
  546. }
  547. catch (...)
  548. {
  549. destruct_range(first1, first);
  550. throw;
  551. }
  552. }
  553. template <typename It>
  554. BOOST_FORCEINLINE
  555. void default_construct_range_impl(It, It, std::false_type) {}
  556. template <typename It>
  557. BOOST_FORCEINLINE
  558. void default_construct_range(It first, It last)
  559. {
  560. default_construct_range_impl(first, last, typename std::is_pointer<It>::type());
  561. }
  562. /// uninitialized_default_construct for planar iterators
  563. template <typename It>
  564. BOOST_FORCEINLINE
  565. void default_construct_aux(It first, It last, std::true_type)
  566. {
  567. int channel = 0;
  568. try
  569. {
  570. using pixel_t = typename std::iterator_traits<It>::value_type;
  571. while (channel < num_channels<pixel_t>::value)
  572. {
  573. default_construct_range(dynamic_at_c(first, channel), dynamic_at_c(last, channel));
  574. ++channel;
  575. }
  576. }
  577. catch (...)
  578. {
  579. for (int c = 0; c < channel; ++c)
  580. destruct_range(dynamic_at_c(first, c), dynamic_at_c(last, c));
  581. throw;
  582. }
  583. }
  584. /// uninitialized_default_construct for interleaved iterators
  585. template <typename It>
  586. BOOST_FORCEINLINE
  587. void default_construct_aux(It first, It last, std::false_type)
  588. {
  589. default_construct_range(first, last);
  590. }
  591. template <typename View, bool IsPlanar>
  592. struct has_trivial_pixel_constructor
  593. : detail::is_trivially_default_constructible<typename View::value_type>
  594. {};
  595. template <typename View>
  596. struct has_trivial_pixel_constructor<View, true>
  597. : detail::is_trivially_default_constructible<typename channel_type<View>::type>
  598. {};
  599. template<typename View, bool IsTriviallyConstructible>
  600. BOOST_FORCEINLINE
  601. void default_construct_pixels_impl(
  602. View const& view,
  603. std::enable_if<!IsTriviallyConstructible>* /*ptr*/ = nullptr)
  604. {
  605. if (view.is_1d_traversable())
  606. {
  607. detail::default_construct_aux(
  608. view.begin().x(), view.end().x(), is_planar<View>());
  609. }
  610. else
  611. {
  612. typename View::y_coord_t y = 0;
  613. try
  614. {
  615. for( y = 0; y < view.height(); ++y )
  616. detail::default_construct_aux(
  617. view.row_begin(y), view.row_end(y), is_planar<View>());
  618. }
  619. catch(...)
  620. {
  621. for (typename View::y_coord_t y0 = 0; y0 < y; ++y0 )
  622. detail::destruct_aux(
  623. view.row_begin(y0), view.row_end(y0), is_planar<View>());
  624. throw;
  625. }
  626. }
  627. }
  628. } // namespace detail
  629. /// \ingroup ImageViewSTLAlgorithmsDefaultConstructPixels
  630. /// \brief Invokes the in-place default constructor on every pixel of the (uninitialized) view.
  631. /// Does not support planar heterogeneous views.
  632. /// If an exception is thrown destructs any in-place default-constructed pixels
  633. template <typename View>
  634. void default_construct_pixels(View const& view)
  635. {
  636. detail::default_construct_pixels_impl
  637. <
  638. View,
  639. detail::has_trivial_pixel_constructor
  640. <
  641. View,
  642. is_planar<View>::value
  643. >::value
  644. >(view);
  645. }
  646. //////////////////////////////////////////////////////////////////////////////////////
  647. // uninitialized_copy_pixels
  648. //////////////////////////////////////////////////////////////////////////////////////
  649. /// \defgroup ImageViewSTLAlgorithmsUninitializedCopyPixels uninitialized_copy_pixels
  650. /// \ingroup ImageViewSTLAlgorithms
  651. /// \brief std::uninitialized_copy for image views
  652. namespace detail {
  653. /// std::uninitialized_copy for pairs of planar iterators
  654. template <typename It1, typename It2>
  655. BOOST_FORCEINLINE
  656. void uninitialized_copy_aux(It1 first1, It1 last1, It2 first2, std::true_type)
  657. {
  658. int channel=0;
  659. try {
  660. using pixel_t = typename std::iterator_traits<It1>::value_type;
  661. while (channel < num_channels<pixel_t>::value)
  662. {
  663. std::uninitialized_copy(
  664. dynamic_at_c(first1, channel),
  665. dynamic_at_c(last1, channel),
  666. dynamic_at_c(first2, channel));
  667. ++channel;
  668. }
  669. }
  670. catch (...)
  671. {
  672. It2 last2 = first2;
  673. std::advance(last2, std::distance(first1, last1));
  674. for (int c = 0; c < channel; ++c)
  675. destruct_range(dynamic_at_c(first2, c), dynamic_at_c(last2, c));
  676. throw;
  677. }
  678. }
  679. /// std::uninitialized_copy for interleaved or mixed iterators
  680. template <typename It1, typename It2>
  681. BOOST_FORCEINLINE
  682. void uninitialized_copy_aux(It1 first1, It1 last1, It2 first2, std::false_type)
  683. {
  684. std::uninitialized_copy(first1, last1, first2);
  685. }
  686. } // namespace detail
  687. /// \ingroup ImageViewSTLAlgorithmsUninitializedCopyPixels
  688. /// \brief std::uninitialized_copy for image views.
  689. /// Does not support planar heterogeneous views.
  690. /// If an exception is thrown destructs any in-place copy-constructed objects
  691. template <typename View1, typename View2>
  692. void uninitialized_copy_pixels(View1 const& view1, View2 const& view2)
  693. {
  694. using is_planar = std::integral_constant<bool, is_planar<View1>::value && is_planar<View2>::value>;
  695. BOOST_ASSERT(view1.dimensions() == view2.dimensions());
  696. if (view1.is_1d_traversable() && view2.is_1d_traversable())
  697. {
  698. detail::uninitialized_copy_aux(
  699. view1.begin().x(), view1.end().x(), view2.begin().x(), is_planar());
  700. }
  701. else
  702. {
  703. typename View1::y_coord_t y = 0;
  704. try
  705. {
  706. for (y = 0; y < view1.height(); ++y)
  707. detail::uninitialized_copy_aux(
  708. view1.row_begin(y), view1.row_end(y), view2.row_begin(y), is_planar());
  709. }
  710. catch(...)
  711. {
  712. for (typename View1::y_coord_t y0 = 0; y0 < y; ++y0)
  713. detail::destruct_aux(view2.row_begin(y0), view2.row_end(y0), is_planar());
  714. throw;
  715. }
  716. }
  717. }
  718. //////////////////////////////////////////////////////////////////////////////////////
  719. // for_each_pixel
  720. //////////////////////////////////////////////////////////////////////////////////////
  721. /// \defgroup ImageViewSTLAlgorithmsForEachPixel for_each_pixel
  722. /// \ingroup ImageViewSTLAlgorithms
  723. /// \brief std::for_each for image views
  724. ///
  725. /// For contiguous images (i.e. images that have no alignment gap at the end of each row) it is
  726. /// more efficient to use the underlying pixel iterator that does not check for the end of rows.
  727. /// For non-contiguous images for_each_pixel resolves to for_each of each row using the underlying
  728. /// pixel iterator, which is still faster
  729. /// \ingroup ImageViewSTLAlgorithmsForEachPixel
  730. template <typename View, typename F>
  731. F for_each_pixel(View const& view, F fun)
  732. {
  733. if (view.is_1d_traversable())
  734. {
  735. return std::for_each(view.begin().x(), view.end().x(), fun);
  736. }
  737. else
  738. {
  739. for (std::ptrdiff_t y = 0; y < view.height(); ++y)
  740. std::for_each(view.row_begin(y), view.row_end(y), fun);
  741. return fun;
  742. }
  743. }
  744. /// \defgroup ImageViewSTLAlgorithmsForEachPixelPosition for_each_pixel_position
  745. /// \ingroup ImageViewSTLAlgorithms
  746. /// \brief adobe::for_each_position for image views (passes locators, instead of pixel references, to the function object)
  747. /// \ingroup ImageViewSTLAlgorithmsForEachPixelPosition
  748. template <typename View, typename F>
  749. F for_each_pixel_position(View const& view, F fun)
  750. {
  751. typename View::xy_locator loc = view.xy_at(0, 0);
  752. for (std::ptrdiff_t y = 0; y < view.height(); ++y)
  753. {
  754. for (std::ptrdiff_t x = 0; x < view.width(); ++x, ++loc.x())
  755. fun(loc);
  756. loc.x() -= view.width(); ++loc.y();
  757. }
  758. return fun;
  759. }
  760. //////////////////////////////////////////////////////////////////////////////////////
  761. // generate_pixels
  762. //////////////////////////////////////////////////////////////////////////////////////
  763. /// \defgroup ImageViewSTLAlgorithmsGeneratePixels generate_pixels
  764. /// \ingroup ImageViewSTLAlgorithms
  765. /// \brief std::generate for image views
  766. /// \ingroup ImageViewSTLAlgorithmsGeneratePixels
  767. /// \brief std::generate for image views
  768. template <typename View, typename F>
  769. void generate_pixels(View const& view, F fun)
  770. {
  771. if (view.is_1d_traversable())
  772. {
  773. std::generate(view.begin().x(), view.end().x(), fun);
  774. }
  775. else
  776. {
  777. for (std::ptrdiff_t y = 0; y < view.height(); ++y)
  778. std::generate(view.row_begin(y), view.row_end(y), fun);
  779. }
  780. }
  781. //////////////////////////////////////////////////////////////////////////////////////
  782. // std::equal and gil::equal_pixels for GIL constructs
  783. //////////////////////////////////////////////////////////////////////////////////////
  784. /// \defgroup ImageViewSTLAlgorithmsEqualPixels equal_pixels
  785. /// \ingroup ImageViewSTLAlgorithms
  786. /// \brief std::equal for image views
  787. template <typename I1, typename I2>
  788. BOOST_FORCEINLINE
  789. bool equal_n(I1 i1, std::ptrdiff_t n, I2 i2);
  790. namespace detail {
  791. template <typename I1, typename I2>
  792. struct equal_n_fn
  793. {
  794. BOOST_FORCEINLINE
  795. bool operator()(I1 i1, std::ptrdiff_t n, I2 i2) const
  796. {
  797. return std::equal(i1, i1 + n, i2);
  798. }
  799. };
  800. /// Equal when both ranges are interleaved and of the same type.
  801. /// GIL pixels are bitwise comparable, so memcmp is used. User-defined pixels that are not bitwise comparable need to provide an overload
  802. template<typename T, typename CS>
  803. struct equal_n_fn<pixel<T, CS> const*, pixel<T, CS> const*>
  804. {
  805. BOOST_FORCEINLINE
  806. bool operator()(pixel<T, CS> const* i1, std::ptrdiff_t n, pixel<T, CS> const* i2) const
  807. {
  808. return memcmp(i1, i2, n * sizeof(pixel<T, CS>)) == 0;
  809. }
  810. };
  811. template<typename T, typename CS>
  812. struct equal_n_fn<pixel<T, CS>*, pixel<T, CS>*>
  813. : equal_n_fn<pixel<T, CS> const*, pixel<T, CS> const*>
  814. {};
  815. /// EqualPixels
  816. /// Equal when both ranges are planar pointers of the same type. memcmp is invoked for each channel plane
  817. /// User-defined channels that are not bitwise comparable need to provide an overload
  818. template<typename IC, typename CS>
  819. struct equal_n_fn<planar_pixel_iterator<IC, CS>, planar_pixel_iterator<IC, CS>>
  820. {
  821. BOOST_FORCEINLINE
  822. bool operator()(planar_pixel_iterator<IC, CS> const i1, std::ptrdiff_t n, planar_pixel_iterator<IC, CS> const i2) const
  823. {
  824. // FIXME: ptrdiff_t vs size_t
  825. constexpr std::ptrdiff_t byte_size = n * sizeof(typename std::iterator_traits<IC>::value_type);
  826. for (std::ptrdiff_t i = 0; i < mp11::mp_size<CS>::value; ++i)
  827. {
  828. if (memcmp(dynamic_at_c(i1, i), dynamic_at_c(i2, i), byte_size) != 0)
  829. return false;
  830. }
  831. return true;
  832. }
  833. };
  834. /// Source range is delimited by image iterators
  835. /// \tparam Loc Models ConstPixelLocatorConcept
  836. /// \tparam It Models PixelIteratorConcept
  837. template <typename Loc, typename It>
  838. struct equal_n_fn<boost::gil::iterator_from_2d<Loc>, It>
  839. {
  840. BOOST_FORCEINLINE
  841. bool operator()(boost::gil::iterator_from_2d<Loc> i1, std::ptrdiff_t n, It i2) const
  842. {
  843. gil_function_requires<boost::gil::PixelLocatorConcept<Loc>>();
  844. gil_function_requires<boost::gil::PixelIteratorConcept<It>>();
  845. while (n > 0)
  846. {
  847. std::ptrdiff_t const num = std::min<std::ptrdiff_t>(n, i1.width() - i1.x_pos());
  848. if (!equal_n(i1.x(), num, i2))
  849. return false;
  850. i1 += num;
  851. i2 += num;
  852. n -= num;
  853. }
  854. return true;
  855. }
  856. };
  857. /// Destination range is delimited by image iterators
  858. /// \tparam It Models PixelIteratorConcept
  859. /// \tparam Loc Models PixelLocatorConcept
  860. template <typename It, typename Loc>
  861. struct equal_n_fn<It, boost::gil::iterator_from_2d<Loc>>
  862. {
  863. BOOST_FORCEINLINE
  864. bool operator()(It i1, std::ptrdiff_t n, boost::gil::iterator_from_2d<Loc> i2) const
  865. {
  866. gil_function_requires<boost::gil::PixelIteratorConcept<It>>();
  867. gil_function_requires<boost::gil::PixelLocatorConcept<Loc>>();
  868. while (n > 0)
  869. {
  870. std::ptrdiff_t const num = std::min<std::ptrdiff_t>(n, i2.width() - i2.x_pos());
  871. if (!equal_n(i1, num, i2.x()))
  872. return false;
  873. i1 += num;
  874. i2 += num;
  875. n -= num;
  876. }
  877. return true;
  878. }
  879. };
  880. /// Both source and destination ranges are delimited by image iterators
  881. template <typename Loc1, typename Loc2>
  882. struct equal_n_fn<boost::gil::iterator_from_2d<Loc1>,boost::gil::iterator_from_2d<Loc2>> {
  883. BOOST_FORCEINLINE bool operator()(boost::gil::iterator_from_2d<Loc1> i1, std::ptrdiff_t n, boost::gil::iterator_from_2d<Loc2> i2) const {
  884. gil_function_requires<boost::gil::PixelLocatorConcept<Loc1>>();
  885. gil_function_requires<boost::gil::PixelLocatorConcept<Loc2>>();
  886. if (i1.x_pos()!=i2.x_pos() || i1.width()!=i2.width()) {
  887. while(n-->0) {
  888. if (*i1++!=*i2++) return false;
  889. }
  890. }
  891. while (n>0) {
  892. std::ptrdiff_t num=std::min<const std::ptrdiff_t>(n,i2.width()-i2.x_pos());
  893. if (!equal_n(i1.x(), num, i2.x()))
  894. return false;
  895. i1+=num;
  896. i2+=num;
  897. n-=num;
  898. }
  899. return true;
  900. }
  901. };
  902. } // namespace detail
  903. template <typename I1, typename I2> BOOST_FORCEINLINE
  904. bool equal_n(I1 i1, std::ptrdiff_t n, I2 i2) {
  905. return detail::equal_n_fn<I1,I2>()(i1,n,i2);
  906. }
  907. } } // namespace boost::gil
  908. namespace std {
  909. /// \ingroup STLOptimizations
  910. /// \brief std::equal(I1,I1,I2) with I1 and I2 being a iterator_from_2d
  911. ///
  912. /// Invoked when one calls std::equal(I1,I1,I2) with I1 and I2 being a iterator_from_2d (which is
  913. /// a 1D iterator over the pixels in an image). Attempts to demote the source and destination
  914. /// iterators to simpler/faster types if the corresponding range is contiguous.
  915. /// For contiguous images (i.e. images that have
  916. /// no alignment gap at the end of each row) it is more efficient to use the underlying
  917. /// pixel iterator that does not check for the end of rows. If the underlying pixel iterator
  918. /// happens to be a fundamental planar/interleaved pointer, the call may further resolve
  919. /// to memcmp. Otherwise it resolves to copying each row using the underlying pixel iterator
  920. template <typename Loc1, typename Loc2> BOOST_FORCEINLINE
  921. bool equal(boost::gil::iterator_from_2d<Loc1> first, boost::gil::iterator_from_2d<Loc1> last, boost::gil::iterator_from_2d<Loc2> first2) {
  922. boost::gil::gil_function_requires<boost::gil::PixelLocatorConcept<Loc1>>();
  923. boost::gil::gil_function_requires<boost::gil::PixelLocatorConcept<Loc2>>();
  924. std::ptrdiff_t n=last-first;
  925. if (first.is_1d_traversable()) {
  926. if (first2.is_1d_traversable())
  927. return boost::gil::detail::equal_n_fn<typename Loc1::x_iterator,typename Loc2::x_iterator>()(first.x(),n, first2.x());
  928. else
  929. return boost::gil::detail::equal_n_fn<typename Loc1::x_iterator,boost::gil::iterator_from_2d<Loc2>>()(first.x(),n, first2);
  930. } else {
  931. if (first2.is_1d_traversable())
  932. return boost::gil::detail::equal_n_fn<boost::gil::iterator_from_2d<Loc1>,typename Loc2::x_iterator>()(first,n, first2.x());
  933. else
  934. return boost::gil::detail::equal_n_fn<boost::gil::iterator_from_2d<Loc1>,boost::gil::iterator_from_2d<Loc2>>()(first,n,first2);
  935. }
  936. }
  937. } // namespace std
  938. namespace boost { namespace gil {
  939. /// \ingroup ImageViewSTLAlgorithmsEqualPixels
  940. /// \brief std::equal for image views
  941. template <typename View1, typename View2> BOOST_FORCEINLINE
  942. bool equal_pixels(const View1& v1, const View2& v2) {
  943. BOOST_ASSERT(v1.dimensions() == v2.dimensions());
  944. return std::equal(v1.begin(),v1.end(),v2.begin()); // std::equal has overloads with GIL iterators for optimal performance
  945. }
  946. //////////////////////////////////////////////////////////////////////////////////////
  947. ///
  948. /// transform_pixels
  949. ///
  950. //////////////////////////////////////////////////////////////////////////////////////
  951. /// \defgroup ImageViewSTLAlgorithmsTransformPixels transform_pixels
  952. /// \ingroup ImageViewSTLAlgorithms
  953. /// \brief std::transform for image views
  954. /// \ingroup ImageViewSTLAlgorithmsTransformPixels
  955. /// \brief std::transform for image views
  956. template <typename View1, typename View2, typename F> BOOST_FORCEINLINE
  957. F transform_pixels(const View1& src,const View2& dst, F fun) {
  958. BOOST_ASSERT(src.dimensions() == dst.dimensions());
  959. for (std::ptrdiff_t y=0; y<src.height(); ++y) {
  960. typename View1::x_iterator srcIt=src.row_begin(y);
  961. typename View2::x_iterator dstIt=dst.row_begin(y);
  962. for (std::ptrdiff_t x=0; x<src.width(); ++x)
  963. dstIt[x]=fun(srcIt[x]);
  964. }
  965. return fun;
  966. }
  967. /// \ingroup ImageViewSTLAlgorithmsTransformPixels
  968. /// \brief transform_pixels with two sources
  969. template <typename View1, typename View2, typename View3, typename F> BOOST_FORCEINLINE
  970. F transform_pixels(const View1& src1, const View2& src2,const View3& dst, F fun) {
  971. for (std::ptrdiff_t y=0; y<dst.height(); ++y) {
  972. typename View1::x_iterator srcIt1=src1.row_begin(y);
  973. typename View2::x_iterator srcIt2=src2.row_begin(y);
  974. typename View3::x_iterator dstIt=dst.row_begin(y);
  975. for (std::ptrdiff_t x=0; x<dst.width(); ++x)
  976. dstIt[x]=fun(srcIt1[x],srcIt2[x]);
  977. }
  978. return fun;
  979. }
  980. /// \defgroup ImageViewSTLAlgorithmsTransformPixelPositions transform_pixel_positions
  981. /// \ingroup ImageViewSTLAlgorithms
  982. /// \brief adobe::transform_positions for image views (passes locators, instead of pixel references, to the function object)
  983. /// \ingroup ImageViewSTLAlgorithmsTransformPixelPositions
  984. /// \brief Like transform_pixels but passes to the function object pixel locators instead of pixel references
  985. template <typename View1, typename View2, typename F> BOOST_FORCEINLINE
  986. F transform_pixel_positions(const View1& src,const View2& dst, F fun) {
  987. BOOST_ASSERT(src.dimensions() == dst.dimensions());
  988. typename View1::xy_locator loc=src.xy_at(0,0);
  989. for (std::ptrdiff_t y=0; y<src.height(); ++y) {
  990. typename View2::x_iterator dstIt=dst.row_begin(y);
  991. for (std::ptrdiff_t x=0; x<src.width(); ++x, ++loc.x())
  992. dstIt[x]=fun(loc);
  993. loc.x()-=src.width(); ++loc.y();
  994. }
  995. return fun;
  996. }
  997. /// \ingroup ImageViewSTLAlgorithmsTransformPixelPositions
  998. /// \brief transform_pixel_positions with two sources
  999. template <typename View1, typename View2, typename View3, typename F> BOOST_FORCEINLINE
  1000. F transform_pixel_positions(const View1& src1,const View2& src2,const View3& dst, F fun) {
  1001. BOOST_ASSERT(src1.dimensions() == dst.dimensions());
  1002. BOOST_ASSERT(src2.dimensions() == dst.dimensions());
  1003. typename View1::xy_locator loc1=src1.xy_at(0,0);
  1004. typename View2::xy_locator loc2=src2.xy_at(0,0);
  1005. for (std::ptrdiff_t y=0; y<src1.height(); ++y) {
  1006. typename View3::x_iterator dstIt=dst.row_begin(y);
  1007. for (std::ptrdiff_t x=0; x<src1.width(); ++x, ++loc1.x(), ++loc2.x())
  1008. dstIt[x]=fun(loc1,loc2);
  1009. loc1.x()-=src1.width(); ++loc1.y();
  1010. loc2.x()-=src2.width(); ++loc2.y();
  1011. }
  1012. return fun;
  1013. }
  1014. } } // namespace boost::gil
  1015. #endif