Imported Upstream version 1.72.0
[platform/upstream/boost.git] / boost / gil / image_view.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_IMAGE_VIEW_HPP
9 #define BOOST_GIL_IMAGE_VIEW_HPP
10
11 #include <boost/gil/dynamic_step.hpp>
12 #include <boost/gil/iterator_from_2d.hpp>
13
14 #include <boost/assert.hpp>
15
16 #include <cstddef>
17 #include <iterator>
18
19 namespace boost { namespace gil {
20
21 ////////////////////////////////////////////////////////////////////////////////////////
22 /// \class image_view
23 /// \ingroup ImageViewModel PixelBasedModel
24 /// \brief A lightweight object that interprets memory as a 2D array of pixels. Models ImageViewConcept,PixelBasedConcept,HasDynamicXStepTypeConcept,HasDynamicYStepTypeConcept,HasTransposedTypeConcept
25 ///
26 /// Image view consists of a pixel 2D locator (defining the mechanism for navigating in 2D)
27 /// and the image dimensions.
28 ///
29 /// Image views to images are what ranges are to STL containers. They are lightweight objects,
30 /// that don't own the pixels. It is the user's responsibility that the underlying data remains
31 /// valid for the lifetime of the image view.
32 ///
33 /// Similar to iterators and ranges, constness of views does not extend to constness of pixels.
34 /// A const \p image_view does not allow changing its location in memory (resizing, moving) but does
35 /// not prevent one from changing the pixels. The latter requires an image view whose value_type
36 /// is const.
37 ///
38 /// Images have interfaces consistent with STL 1D random access containers, so they can be used
39 /// directly in STL algorithms like:
40 /// \code
41 ///  std::fill(img.begin(), img.end(), red_pixel);
42 /// \endcode
43 ///
44 /// In addition, horizontal, vertical and 2D random access iterators are provided.
45 ///
46 /// Note also that \p image_view does not require that its element type be a pixel. It could be
47 /// instantiated with a locator whose \p value_type models only \p Regular. In this case the image
48 /// view models the weaker RandomAccess2DImageViewConcept, and does not model PixelBasedConcept.
49 /// Many generic algorithms don't require the elements to be pixels.
50 ///
51 ////////////////////////////////////////////////////////////////////////////////////////
52 template <typename Loc>     // Models 2D Pixel Locator
53 class image_view
54 {
55 public:
56     // aliases required by ConstRandomAccessNDImageViewConcept
57     static const std::size_t num_dimensions=2;
58     using value_type = typename Loc::value_type;
59     using reference = typename Loc::reference;       // result of dereferencing
60     using coord_t = typename Loc::coord_t;      // 1D difference type (same for all dimensions)
61     using difference_type = coord_t; // result of operator-(1d_iterator,1d_iterator)
62     using point_t = typename Loc::point_t;
63     using locator = Loc;
64     using const_t = image_view<typename Loc::const_t>;      // same as this type, but over const values
65     template <std::size_t D> struct axis
66     {
67         using coord_t = typename Loc::template axis<D>::coord_t; // difference_type along each dimension
68         using iterator = typename Loc::template axis<D>::iterator; // 1D iterator type along each dimension
69     };
70     using iterator = iterator_from_2d<Loc>;       // 1D iterator type for each pixel left-to-right inside top-to-bottom
71     using const_iterator = typename const_t::iterator;  // may be used to examine, but not to modify values
72     using const_reference = typename const_t::reference; // behaves as a const reference
73     using pointer = typename std::iterator_traits<iterator>::pointer; // behaves as a pointer to the value type
74     using reverse_iterator = std::reverse_iterator<iterator>;
75     using size_type = std::size_t;
76
77     // aliases required by ConstRandomAccess2DImageViewConcept
78     using xy_locator = locator;
79     using x_iterator = typename xy_locator::x_iterator;     // pixel iterator along a row
80     using y_iterator = typename xy_locator::y_iterator;     // pixel iterator along a column
81     using x_coord_t = typename xy_locator::x_coord_t;
82     using y_coord_t = typename xy_locator::y_coord_t;
83
84     template <typename Deref>
85     struct add_deref
86     {
87         using type = image_view<typename Loc::template add_deref<Deref>::type>;
88         static type make(image_view<Loc> const& view, Deref const& d)
89         {
90             return type(view.dimensions(), Loc::template add_deref<Deref>::make(view.pixels(), d));
91         }
92     };
93
94     image_view() : _dimensions(0,0) {}
95     image_view(image_view const& img_view)
96         : _dimensions(img_view.dimensions()), _pixels(img_view.pixels())
97     {}
98
99     template <typename View>
100     image_view(View const& view) : _dimensions(view.dimensions()), _pixels(view.pixels()) {}
101
102     template <typename L2>
103     image_view(point_t const& dims, L2 const& loc) : _dimensions(dims), _pixels(loc) {}
104
105     template <typename L2>
106     image_view(coord_t width, coord_t height, L2 const& loc)
107         : _dimensions(x_coord_t(width), y_coord_t(height)), _pixels(loc)
108     {}
109
110     template <typename View>
111     image_view& operator=(View const& view)
112     {
113         _pixels = view.pixels();
114         _dimensions = view.dimensions();
115         return *this;
116     }
117
118     image_view& operator=(image_view const& view)
119     {
120         // TODO: Self-assignment protection?
121         _pixels = view.pixels();
122         _dimensions = view.dimensions();
123         return *this;
124     }
125
126     template <typename View>
127     bool operator==(View const &view) const
128     {
129         return pixels() == view.pixels() && dimensions() == view.dimensions();
130     }
131
132     template <typename View>
133     bool operator!=(View const& view) const
134     {
135         return !(*this == view);
136     }
137
138     template <typename L2>
139     friend void swap(image_view<L2> &lhs, image_view<L2> &rhs);
140
141     /// \brief Exchanges the elements of the current view with those of \a other
142     ///       in constant time.
143     ///
144     /// \note Required by the Collection concept
145     /// \see  https://www.boost.org/libs/utility/Collection.html
146     void swap(image_view<Loc>& other)
147     {
148         using boost::gil::swap;
149         swap(*this, other);
150     }
151
152     auto dimensions() const -> point_t const&
153     {
154         return _dimensions;
155     }
156
157     auto pixels() const -> locator const&
158     {
159         return _pixels;
160     }
161
162     auto width() const -> x_coord_t
163     {
164         return dimensions().x;
165     }
166
167     auto height() const -> y_coord_t
168     {
169         return dimensions().y;
170     }
171
172     auto num_channels() const -> std::size_t
173     {
174         return gil::num_channels<value_type>::value;
175     }
176
177     bool is_1d_traversable() const
178     {
179         return _pixels.is_1d_traversable(width());
180     }
181
182     /// \brief Returns true if the view has no elements, false otherwise.
183     ///
184     /// \note Required by the Collection concept
185     /// \see  https://www.boost.org/libs/utility/Collection.html
186     bool empty() const
187     {
188         return !(width() > 0 && height() > 0);
189     }
190
191     /// \brief Returns a reference to the first element in raster order.
192     ///
193     /// \note Required by the ForwardCollection, since view model the concept.
194     /// \see  https://www.boost.org/libs/utility/Collection.html
195     auto front() const -> reference
196     {
197         BOOST_ASSERT(!empty());
198         return *begin();
199     }
200
201     /// \brief Returns a reference to the last element in raster order.
202     ///
203     /// \note Required by the ForwardCollection, since view model the concept.
204     /// \see  https://www.boost.org/libs/utility/Collection.html
205     auto back() const -> reference
206     {
207         BOOST_ASSERT(!empty());
208         return *rbegin();
209     }
210
211     //\{@
212     /// \name 1D navigation
213     auto size() const -> size_type
214     {
215         return width() * height();
216     }
217
218     auto begin() const -> iterator
219     {
220         return iterator(_pixels, _dimensions.x);
221     }
222
223     auto end() const -> iterator
224     {
225         // potential performance problem!
226         return begin() + static_cast<difference_type>(size());
227     }
228
229     auto rbegin() const -> reverse_iterator
230     {
231         return reverse_iterator(end());
232     }
233
234     auto rend() const -> reverse_iterator
235     {
236         return reverse_iterator(begin());
237     }
238
239     auto operator[](difference_type i) const -> reference
240     {
241         BOOST_ASSERT(i < static_cast<difference_type>(size()));
242         return begin()[i]; // potential performance problem!
243     }
244
245     auto at(difference_type i) const ->iterator
246     {
247         BOOST_ASSERT(i < size());
248         return begin() + i;
249     }
250
251     auto at(point_t const& p) const -> iterator
252     {
253         BOOST_ASSERT(0 <= p.x && p.x < width());
254         BOOST_ASSERT(0 <= p.y && p.y < height());
255         return begin() + p.y * width() + p.x;
256     }
257
258     auto at(x_coord_t x, y_coord_t y) const -> iterator
259     {
260         BOOST_ASSERT(0 <= x && x < width());
261         BOOST_ASSERT(0 <= y && y < height());
262         return begin() + y * width() + x;
263     }
264     //\}@
265
266     //\{@
267     /// \name 2-D navigation
268     auto operator()(point_t const& p) const -> reference
269     {
270         BOOST_ASSERT(0 <= p.x && p.x < width());
271         BOOST_ASSERT(0 <= p.y && p.y < height());
272         return _pixels(p.x, p.y);
273     }
274
275     auto operator()(x_coord_t x, y_coord_t y) const -> reference
276     {
277         BOOST_ASSERT(0 <= x && x < width());
278         BOOST_ASSERT(0 <= y && y < height());
279         return _pixels(x, y);
280     }
281
282     template <std::size_t D>
283     auto axis_iterator(point_t const& p) const -> typename axis<D>::iterator
284     {
285         // allow request for iterators from inclusive range of [begin, end]
286         BOOST_ASSERT(0 <= p.x && p.x <= width());
287         BOOST_ASSERT(0 <= p.y && p.y <= height());
288         return _pixels.template axis_iterator<D>(p);
289     }
290
291     auto xy_at(x_coord_t x, y_coord_t y) const -> xy_locator
292     {
293         // TODO: Are relative locations of neighbors with negative offsets valid? Sampling?
294         BOOST_ASSERT(x < width());
295         BOOST_ASSERT(y < height());
296         return _pixels + point_t(x, y);
297     }
298
299     auto xy_at(point_t const& p) const -> locator
300     {
301         // TODO: Are relative locations of neighbors with negative offsets valid? Sampling?
302         BOOST_ASSERT(p.x < width());
303         BOOST_ASSERT(p.y < height());
304         return _pixels + p;
305     }
306     //\}@
307
308     //\{@
309     /// \name X navigation
310     auto x_at(x_coord_t x, y_coord_t y) const -> x_iterator
311     {
312         BOOST_ASSERT(0 <= x && x <= width()); // allow request for [begin, end] inclusive
313         BOOST_ASSERT(0 <= y && y < height());
314         return _pixels.x_at(x, y);
315     }
316
317     auto x_at(point_t const& p) const -> x_iterator
318     {
319         BOOST_ASSERT(0 <= p.x && p.x <= width()); // allow request for [begin, end] inclusive
320         BOOST_ASSERT(0 <= p.y && p.y < height());
321         return _pixels.x_at(p);
322     }
323
324     auto row_begin(y_coord_t y) const -> x_iterator
325     {
326         BOOST_ASSERT(0 <= y && y < height());
327         return x_at(0, y);
328     }
329
330     auto row_end(y_coord_t y) const -> x_iterator
331     {
332         BOOST_ASSERT(0 <= y && y < height());
333         return x_at(width(), y);
334     }
335     //\}@
336
337     //\{@
338     /// \name Y navigation
339     auto y_at(x_coord_t x, y_coord_t y) const -> y_iterator
340     {
341         BOOST_ASSERT(0 <= x && x < width());
342         BOOST_ASSERT(0 <= y && y <= height()); // allow request for [begin, end] inclusive
343         return xy_at(x, y).y();
344     }
345
346     auto y_at(point_t const& p) const -> y_iterator
347     {
348         BOOST_ASSERT(0 <= p.x && p.x < width());
349         BOOST_ASSERT(0 <= p.y && p.y <= height()); // allow request for [begin, end] inclusive
350         return xy_at(p).y();
351     }
352
353     auto col_begin(x_coord_t x) const -> y_iterator
354     {
355         BOOST_ASSERT(0 <= x && x < width());
356         return y_at(x, 0);
357     }
358
359     auto col_end(x_coord_t x) const -> y_iterator
360     {
361         BOOST_ASSERT(0 <= x && x < width());
362         return y_at(x, height());
363     }
364     //\}@
365
366 private:
367     template <typename L2>
368     friend class image_view;
369
370     point_t    _dimensions;
371     xy_locator _pixels;
372 };
373
374 template <typename L2>
375 inline void swap(image_view<L2>& x, image_view<L2>& y) {
376     using std::swap;
377     swap(x._dimensions,y._dimensions);
378     swap(x._pixels, y._pixels);            // TODO: Extend further
379 }
380
381 /////////////////////////////
382 //  PixelBasedConcept
383 /////////////////////////////
384
385 template <typename L>
386 struct channel_type<image_view<L> > : public channel_type<L> {};
387
388 template <typename L>
389 struct color_space_type<image_view<L> > : public color_space_type<L> {};
390
391 template <typename L>
392 struct channel_mapping_type<image_view<L> > : public channel_mapping_type<L> {};
393
394 template <typename L>
395 struct is_planar<image_view<L> > : public is_planar<L> {};
396
397 /////////////////////////////
398 //  HasDynamicXStepTypeConcept
399 /////////////////////////////
400
401 template <typename L>
402 struct dynamic_x_step_type<image_view<L>>
403 {
404     using type = image_view<typename gil::dynamic_x_step_type<L>::type>;
405 };
406
407 /////////////////////////////
408 //  HasDynamicYStepTypeConcept
409 /////////////////////////////
410
411 template <typename L>
412 struct dynamic_y_step_type<image_view<L>>
413 {
414     using type = image_view<typename gil::dynamic_y_step_type<L>::type>;
415 };
416
417 /////////////////////////////
418 //  HasTransposedTypeConcept
419 /////////////////////////////
420
421 template <typename L>
422 struct transposed_type<image_view<L>>
423 {
424     using type = image_view<typename transposed_type<L>::type>;
425 };
426
427 }}  // namespace boost::gil
428
429 #endif