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_CONCEPTS_IMAGE_VIEW_HPP
9 #define BOOST_GIL_CONCEPTS_IMAGE_VIEW_HPP
10 
11 #include <boost/gil/concepts/basic.hpp>
12 #include <boost/gil/concepts/concept_check.hpp>
13 #include <boost/gil/concepts/fwd.hpp>
14 #include <boost/gil/concepts/pixel.hpp>
15 #include <boost/gil/concepts/pixel_dereference.hpp>
16 #include <boost/gil/concepts/pixel_iterator.hpp>
17 #include <boost/gil/concepts/pixel_locator.hpp>
18 #include <boost/gil/concepts/point.hpp>
19 #include <boost/gil/concepts/detail/utility.hpp>
20 
21 #include <cstddef>
22 #include <iterator>
23 #include <type_traits>
24 
25 #if defined(BOOST_CLANG)
26 #pragma clang diagnostic push
27 #pragma clang diagnostic ignored "-Wunknown-pragmas"
28 #pragma clang diagnostic ignored "-Wunused-local-typedefs"
29 #endif
30 
31 #if defined(BOOST_GCC) && (BOOST_GCC >= 40900)
32 #pragma GCC diagnostic push
33 #pragma GCC diagnostic ignored "-Wunused-local-typedefs"
34 #pragma GCC diagnostic ignored "-Wunused-but-set-variable"
35 #endif
36 
37 namespace boost { namespace gil {
38 
39 /// \defgroup ImageViewNDConcept ImageViewNDLocatorConcept
40 /// \ingroup ImageViewConcept
41 /// \brief N-dimensional range
42 
43 /// \defgroup ImageView2DConcept ImageView2DLocatorConcept
44 /// \ingroup ImageViewConcept
45 /// \brief 2-dimensional range
46 
47 /// \defgroup PixelImageViewConcept ImageViewConcept
48 /// \ingroup ImageViewConcept
49 /// \brief 2-dimensional range over pixel data
50 
51 /// \ingroup ImageViewNDConcept
52 /// \brief N-dimensional view over immutable values
53 ///
54 /// \code
55 /// concept RandomAccessNDImageViewConcept<Regular View>
56 /// {
57 ///     typename value_type;
58 ///     typename reference;       // result of dereferencing
59 ///     typename difference_type; // result of operator-(iterator,iterator) (1-dimensional!)
60 ///     typename const_t;  where RandomAccessNDImageViewConcept<View>; // same as View, but over immutable values
61 ///     typename point_t;  where PointNDConcept<point_t>; // N-dimensional point
62 ///     typename locator;  where RandomAccessNDLocatorConcept<locator>; // N-dimensional locator.
63 ///     typename iterator; where RandomAccessTraversalConcept<iterator>; // 1-dimensional iterator over all values
64 ///     typename reverse_iterator; where RandomAccessTraversalConcept<reverse_iterator>;
65 ///     typename size_type;       // the return value of size()
66 ///
67 ///     // Equivalent to RandomAccessNDLocatorConcept::axis
68 ///     template <size_t D> struct axis {
69 ///         typename coord_t = point_t::axis<D>::coord_t;
70 ///         typename iterator; where RandomAccessTraversalConcept<iterator>;   // iterator along D-th axis.
71 ///         where SameType<coord_t, iterator::difference_type>;
72 ///         where SameType<iterator::value_type,value_type>;
73 ///     };
74 ///
75 ///     // Defines the type of a view similar to this type, except it invokes Deref upon dereferencing
76 ///     template <PixelDereferenceAdaptorConcept Deref> struct add_deref {
77 ///         typename type;        where RandomAccessNDImageViewConcept<type>;
78 ///         static type make(const View& v, const Deref& deref);
79 ///     };
80 ///
81 ///     static const size_t num_dimensions = point_t::num_dimensions;
82 ///
83 ///     // Create from a locator at the top-left corner and dimensions
84 ///     View::View(const locator&, const point_type&);
85 ///
86 ///     size_type        View::size()       const; // total number of elements
87 ///     reference        operator[](View, const difference_type&) const; // 1-dimensional reference
88 ///     iterator         View::begin()      const;
89 ///     iterator         View::end()        const;
90 ///     reverse_iterator View::rbegin()     const;
91 ///     reverse_iterator View::rend()       const;
92 ///     iterator         View::at(const point_t&);
93 ///     point_t          View::dimensions() const; // number of elements along each dimension
94 ///     bool             View::is_1d_traversable() const;   // can an iterator over the first dimension visit each value? I.e. are there gaps between values?
95 ///
96 ///     // iterator along a given dimension starting at a given point
97 ///     template <size_t D> View::axis<D>::iterator View::axis_iterator(const point_t&) const;
98 ///
99 ///     reference operator()(View,const point_t&) const;
100 /// };
101 /// \endcode
102 template <typename View>
103 struct RandomAccessNDImageViewConcept
104 {
constraintsboost::gil::RandomAccessNDImageViewConcept105     void constraints()
106     {
107         gil_function_requires<Regular<View>>();
108 
109         using value_type = typename View::value_type;
110         using reference = typename View::reference; // result of dereferencing
111         using pointer = typename View::pointer;
112         using difference_type = typename View::difference_type; // result of operator-(1d_iterator,1d_iterator)
113         using const_t = typename View::const_t; // same as this type, but over const values
114         using point_t = typename View::point_t; // N-dimensional point
115         using locator = typename View::locator; // N-dimensional locator
116         using iterator = typename View::iterator;
117         using const_iterator = typename View::const_iterator;
118         using reverse_iterator = typename View::reverse_iterator;
119         using size_type = typename View::size_type;
120         static const std::size_t N=View::num_dimensions;
121 
122         gil_function_requires<RandomAccessNDLocatorConcept<locator>>();
123         gil_function_requires<boost_concepts::RandomAccessTraversalConcept<iterator>>();
124         gil_function_requires<boost_concepts::RandomAccessTraversalConcept<reverse_iterator>>();
125 
126         using first_it_type = typename View::template axis<0>::iterator;
127         using last_it_type = typename View::template axis<N-1>::iterator;
128         gil_function_requires<boost_concepts::RandomAccessTraversalConcept<first_it_type>>();
129         gil_function_requires<boost_concepts::RandomAccessTraversalConcept<last_it_type>>();
130 
131 //        static_assert(typename std::iterator_traits<first_it_type>::difference_type, typename point_t::template axis<0>::coord_t>::value, "");
132 //        static_assert(typename std::iterator_traits<last_it_type>::difference_type, typename point_t::template axis<N-1>::coord_t>::value, "");
133 
134         // point_t must be an N-dimensional point, each dimension of which must have the same type as difference_type of the corresponding iterator
135         gil_function_requires<PointNDConcept<point_t>>();
136         static_assert(point_t::num_dimensions == N, "");
137         static_assert(std::is_same
138             <
139                 typename std::iterator_traits<first_it_type>::difference_type,
140                 typename point_t::template axis<0>::coord_t
141             >::value, "");
142         static_assert(std::is_same
143             <
144                 typename std::iterator_traits<last_it_type>::difference_type,
145                 typename point_t::template axis<N-1>::coord_t
146             >::value, "");
147 
148         point_t p;
149         locator lc;
150         iterator it;
151         reverse_iterator rit;
152         difference_type d; detail::initialize_it(d); ignore_unused_variable_warning(d);
153 
154         View(p,lc); // view must be constructible from a locator and a point
155 
156         p = view.dimensions();
157         lc = view.pixels();
158         size_type sz = view.size(); ignore_unused_variable_warning(sz);
159         bool is_contiguous = view.is_1d_traversable();
160         ignore_unused_variable_warning(is_contiguous);
161 
162         it = view.begin();
163         it = view.end();
164         rit = view.rbegin();
165         rit = view.rend();
166 
167         reference r1 = view[d]; ignore_unused_variable_warning(r1); // 1D access
168         reference r2 = view(p); ignore_unused_variable_warning(r2); // 2D access
169 
170         // get 1-D iterator of any dimension at a given pixel location
171         first_it_type fi = view.template axis_iterator<0>(p);
172         ignore_unused_variable_warning(fi);
173         last_it_type li = view.template axis_iterator<N-1>(p);
174         ignore_unused_variable_warning(li);
175 
176         using deref_t = PixelDereferenceAdaptorArchetype<typename View::value_type>;
177         using dtype = typename View::template add_deref<deref_t>::type;
178     }
179     View view;
180 };
181 
182 /// \ingroup ImageView2DConcept
183 /// \brief 2-dimensional view over immutable values
184 ///
185 /// \code
186 /// concept RandomAccess2DImageViewConcept<RandomAccessNDImageViewConcept View> {
187 ///     where num_dimensions==2;
188 ///
189 ///     typename x_iterator = axis<0>::iterator;
190 ///     typename y_iterator = axis<1>::iterator;
191 ///     typename x_coord_t  = axis<0>::coord_t;
192 ///     typename y_coord_t  = axis<1>::coord_t;
193 ///     typename xy_locator = locator;
194 ///
195 ///     x_coord_t View::width()  const;
196 ///     y_coord_t View::height() const;
197 ///
198 ///     // X-navigation
199 ///     x_iterator View::x_at(const point_t&) const;
200 ///     x_iterator View::row_begin(y_coord_t) const;
201 ///     x_iterator View::row_end  (y_coord_t) const;
202 ///
203 ///     // Y-navigation
204 ///     y_iterator View::y_at(const point_t&) const;
205 ///     y_iterator View::col_begin(x_coord_t) const;
206 ///     y_iterator View::col_end  (x_coord_t) const;
207 ///
208 ///     // navigating in 2D
209 ///     xy_locator View::xy_at(const point_t&) const;
210 ///
211 ///     // (x,y) versions of all methods taking point_t
212 ///     View::View(x_coord_t,y_coord_t,const locator&);
213 ///     iterator View::at(x_coord_t,y_coord_t) const;
214 ///     reference operator()(View,x_coord_t,y_coord_t) const;
215 ///     xy_locator View::xy_at(x_coord_t,y_coord_t) const;
216 ///     x_iterator View::x_at(x_coord_t,y_coord_t) const;
217 ///     y_iterator View::y_at(x_coord_t,y_coord_t) const;
218 /// };
219 /// \endcode
220 template <typename View>
221 struct RandomAccess2DImageViewConcept
222 {
constraintsboost::gil::RandomAccess2DImageViewConcept223     void constraints()
224     {
225         gil_function_requires<RandomAccessNDImageViewConcept<View>>();
226         static_assert(View::num_dimensions == 2, "");
227 
228         // TODO: This executes the requirements for RandomAccessNDLocatorConcept again. Fix it to improve compile time
229         gil_function_requires<RandomAccess2DLocatorConcept<typename View::locator>>();
230 
231         using dynamic_x_step_t = typename dynamic_x_step_type<View>::type;
232         using dynamic_y_step_t = typename dynamic_y_step_type<View>::type;
233         using transposed_t = typename transposed_type<View>::type;
234         using x_iterator = typename View::x_iterator;
235         using y_iterator = typename View::y_iterator;
236         using x_coord_t = typename View::x_coord_t;
237         using y_coord_t = typename View::y_coord_t;
238         using xy_locator = typename View::xy_locator;
239 
240         x_coord_t xd = 0; ignore_unused_variable_warning(xd);
241         y_coord_t yd = 0; ignore_unused_variable_warning(yd);
242         x_iterator xit;
243         y_iterator yit;
244         typename View::point_t d;
245 
246         View(xd, yd, xy_locator()); // constructible with width, height, 2d_locator
247 
248         xy_locator lc = view.xy_at(xd, yd);
249         lc = view.xy_at(d);
250 
251         typename View::reference r = view(xd, yd);
252         ignore_unused_variable_warning(r);
253         xd = view.width();
254         yd = view.height();
255 
256         xit = view.x_at(d);
257         xit = view.x_at(xd,yd);
258         xit = view.row_begin(xd);
259         xit = view.row_end(xd);
260 
261         yit = view.y_at(d);
262         yit = view.y_at(xd,yd);
263         yit = view.col_begin(xd);
264         yit = view.col_end(xd);
265     }
266     View view;
267 };
268 
269 /// \brief GIL view as Collection.
270 ///
271 /// \see https://www.boost.org/libs/utility/Collection.html
272 ///
273 template <typename View>
274 struct CollectionImageViewConcept
275 {
constraintsboost::gil::CollectionImageViewConcept276     void constraints()
277     {
278         using value_type = typename View::value_type;
279         using iterator = typename View::iterator;
280         using const_iterator =  typename View::const_iterator;
281         using reference = typename View::reference;
282         using const_reference = typename View::const_reference;
283         using pointer = typename View::pointer;
284         using difference_type = typename View::difference_type;
285         using size_type=  typename View::size_type;
286 
287         iterator i;
288         i = view1.begin();
289         i = view2.end();
290 
291         const_iterator ci;
292         ci = view1.begin();
293         ci = view2.end();
294 
295         size_type s;
296         s = view1.size();
297         s = view2.size();
298         ignore_unused_variable_warning(s);
299 
300         view1.empty();
301 
302         view1.swap(view2);
303     }
304     View view1;
305     View view2;
306 };
307 
308 /// \brief GIL view as ForwardCollection.
309 ///
310 /// \see https://www.boost.org/libs/utility/Collection.html
311 ///
312 template <typename View>
313 struct ForwardCollectionImageViewConcept
314 {
constraintsboost::gil::ForwardCollectionImageViewConcept315     void constraints()
316     {
317         gil_function_requires<CollectionImageViewConcept<View>>();
318 
319         using reference = typename View::reference;
320         using const_reference = typename View::const_reference;
321 
322         reference r = view.front();
323         ignore_unused_variable_warning(r);
324 
325         const_reference cr = view.front();
326         ignore_unused_variable_warning(cr);
327     }
328     View view;
329 };
330 
331 /// \brief GIL view as ReversibleCollection.
332 ///
333 /// \see https://www.boost.org/libs/utility/Collection.html
334 ///
335 template <typename View>
336 struct ReversibleCollectionImageViewConcept
337 {
constraintsboost::gil::ReversibleCollectionImageViewConcept338     void constraints()
339     {
340         gil_function_requires<CollectionImageViewConcept<View>>();
341 
342         using reverse_iterator = typename View::reverse_iterator;
343         using reference = typename View::reference;
344         using const_reference = typename View::const_reference;
345 
346         reverse_iterator i;
347         i = view.rbegin();
348         i = view.rend();
349 
350         reference r = view.back();
351         ignore_unused_variable_warning(r);
352 
353         const_reference cr = view.back();
354         ignore_unused_variable_warning(cr);
355     }
356     View view;
357 };
358 
359 /// \ingroup PixelImageViewConcept
360 /// \brief GIL's 2-dimensional view over immutable GIL pixels
361 /// \code
362 /// concept ImageViewConcept<RandomAccess2DImageViewConcept View>
363 /// {
364 ///     where PixelValueConcept<value_type>;
365 ///     where PixelIteratorConcept<x_iterator>;
366 ///     where PixelIteratorConcept<y_iterator>;
367 ///     where x_coord_t == y_coord_t;
368 ///
369 ///     typename coord_t = x_coord_t;
370 ///
371 ///     std::size_t View::num_channels() const;
372 /// };
373 /// \endcode
374 template <typename View>
375 struct ImageViewConcept
376 {
constraintsboost::gil::ImageViewConcept377     void constraints()
378     {
379         gil_function_requires<RandomAccess2DImageViewConcept<View>>();
380 
381         // TODO: This executes the requirements for RandomAccess2DLocatorConcept again. Fix it to improve compile time
382         gil_function_requires<PixelLocatorConcept<typename View::xy_locator>>();
383 
384         static_assert(std::is_same<typename View::x_coord_t, typename View::y_coord_t>::value, "");
385 
386         using coord_t = typename View::coord_t; // 1D difference type (same for all dimensions)
387         std::size_t num_chan = view.num_channels(); ignore_unused_variable_warning(num_chan);
388     }
389     View view;
390 };
391 
392 namespace detail {
393 
394 /// \tparam View Models RandomAccessNDImageViewConcept
395 template <typename View>
396 struct RandomAccessNDImageViewIsMutableConcept
397 {
constraintsboost::gil::detail::RandomAccessNDImageViewIsMutableConcept398     void constraints()
399     {
400         gil_function_requires<detail::RandomAccessNDLocatorIsMutableConcept<typename View::locator>>();
401 
402         gil_function_requires<detail::RandomAccessIteratorIsMutableConcept<typename View::iterator>>();
403 
404         gil_function_requires<detail::RandomAccessIteratorIsMutableConcept
405             <
406                 typename View::reverse_iterator
407             >>();
408 
409         gil_function_requires<detail::RandomAccessIteratorIsMutableConcept
410             <
411                 typename View::template axis<0>::iterator
412             >>();
413 
414         gil_function_requires<detail::RandomAccessIteratorIsMutableConcept
415             <
416                 typename View::template axis<View::num_dimensions - 1>::iterator
417             >>();
418 
419         typename View::difference_type diff;
420         initialize_it(diff);
421         ignore_unused_variable_warning(diff);
422 
423         typename View::point_t pt;
424         typename View::value_type v;
425         initialize_it(v);
426 
427         view[diff] = v;
428         view(pt) = v;
429     }
430     View view;
431 };
432 
433 /// \tparam View Models RandomAccessNDImageViewConcept
434 template <typename View>
435 struct RandomAccess2DImageViewIsMutableConcept
436 {
constraintsboost::gil::detail::RandomAccess2DImageViewIsMutableConcept437     void constraints()
438     {
439         gil_function_requires<detail::RandomAccessNDImageViewIsMutableConcept<View>>();
440         typename View::x_coord_t xd = 0; ignore_unused_variable_warning(xd);
441         typename View::y_coord_t yd = 0; ignore_unused_variable_warning(yd);
442         typename View::value_type v; initialize_it(v);
443         view(xd, yd) = v;
444     }
445     View view;
446 };
447 
448 /// \tparam View Models ImageViewConcept
449 template <typename View>
450 struct PixelImageViewIsMutableConcept
451 {
constraintsboost::gil::detail::PixelImageViewIsMutableConcept452     void constraints()
453     {
454         gil_function_requires<detail::RandomAccess2DImageViewIsMutableConcept<View>>();
455     }
456 };
457 
458 } // namespace detail
459 
460 /// \ingroup ImageViewNDConcept
461 /// \brief N-dimensional view over mutable values
462 ///
463 /// \code
464 /// concept MutableRandomAccessNDImageViewConcept<RandomAccessNDImageViewConcept View>
465 /// {
466 ///     where Mutable<reference>;
467 /// };
468 /// \endcode
469 template <typename View>
470 struct MutableRandomAccessNDImageViewConcept
471 {
constraintsboost::gil::MutableRandomAccessNDImageViewConcept472     void constraints()
473     {
474         gil_function_requires<RandomAccessNDImageViewConcept<View>>();
475         gil_function_requires<detail::RandomAccessNDImageViewIsMutableConcept<View>>();
476     }
477 };
478 
479 /// \ingroup ImageView2DConcept
480 /// \brief 2-dimensional view over mutable values
481 ///
482 /// \code
483 /// concept MutableRandomAccess2DImageViewConcept<RandomAccess2DImageViewConcept View>
484 ///     : MutableRandomAccessNDImageViewConcept<View> {};
485 /// \endcode
486 template <typename View>
487 struct MutableRandomAccess2DImageViewConcept
488 {
constraintsboost::gil::MutableRandomAccess2DImageViewConcept489     void constraints()
490     {
491         gil_function_requires<RandomAccess2DImageViewConcept<View>>();
492         gil_function_requires<detail::RandomAccess2DImageViewIsMutableConcept<View>>();
493     }
494 };
495 
496 /// \ingroup PixelImageViewConcept
497 /// \brief GIL's 2-dimensional view over mutable GIL pixels
498 ///
499 /// \code
500 /// concept MutableImageViewConcept<ImageViewConcept View>
501 ///     : MutableRandomAccess2DImageViewConcept<View> {};
502 /// \endcode
503 template <typename View>
504 struct MutableImageViewConcept
505 {
constraintsboost::gil::MutableImageViewConcept506     void constraints()
507     {
508         gil_function_requires<ImageViewConcept<View>>();
509         gil_function_requires<detail::PixelImageViewIsMutableConcept<View>>();
510     }
511 };
512 
513 /// \brief Returns whether two views are compatible
514 ///
515 /// Views are compatible if their pixels are compatible.
516 /// Compatible views can be assigned and copy constructed from one another.
517 ///
518 /// \tparam V1 Models ImageViewConcept
519 /// \tparam V2 Models ImageViewConcept
520 ///
521 template <typename V1, typename V2>
522 struct views_are_compatible
523     : pixels_are_compatible<typename V1::value_type, typename V2::value_type>
524 {
525 };
526 
527 /// \ingroup ImageViewConcept
528 /// \brief Views are compatible if they have the same color spaces and compatible channel values.
529 ///
530 /// Constness and layout are not important for compatibility.
531 ///
532 /// \code
533 /// concept ViewsCompatibleConcept<ImageViewConcept V1, ImageViewConcept V2>
534 /// {
535 ///     where PixelsCompatibleConcept<V1::value_type, P2::value_type>;
536 /// };
537 /// \endcode
538 template <typename V1, typename V2>
539 struct ViewsCompatibleConcept
540 {
constraintsboost::gil::ViewsCompatibleConcept541     void constraints()
542     {
543         static_assert(views_are_compatible<V1, V2>::value, "");
544     }
545 };
546 
547 }} // namespace boost::gil
548 
549 #if defined(BOOST_CLANG)
550 #pragma clang diagnostic pop
551 #endif
552 
553 #if defined(BOOST_GCC) && (BOOST_GCC >= 40900)
554 #pragma GCC diagnostic pop
555 #endif
556 
557 #endif
558