-/*
- Copyright 2005-2007 Adobe Systems Incorporated
-
- Use, modification and distribution are subject to the Boost Software License,
- Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
- http://www.boost.org/LICENSE_1_0.txt).
+//
+// Copyright 2005-2007 Adobe Systems Incorporated
+//
+// Distributed under the Boost Software License, Version 1.0
+// See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt
+//
+#ifndef BOOST_GIL_IMAGE_VIEW_HPP
+#define BOOST_GIL_IMAGE_VIEW_HPP
- See http://opensource.adobe.com/gil for most recent version including documentation.
-*/
-/*************************************************************************************************/
+#include <boost/gil/dynamic_step.hpp>
+#include <boost/gil/iterator_from_2d.hpp>
-#ifndef GIL_IMAGE_VIEW_H
-#define GIL_IMAGE_VIEW_H
-
-////////////////////////////////////////////////////////////////////////////////////////
-/// \file
-/// \brief image view class
-/// \author Lubomir Bourdev and Hailin Jin \n
-/// Adobe Systems Incorporated
-/// \date 2005-2007 \n Last updated on February 12, 2007
-///
-////////////////////////////////////////////////////////////////////////////////////////
+#include <boost/assert.hpp>
#include <cstddef>
#include <iterator>
-#include "gil_config.hpp"
-#include "iterator_from_2d.hpp"
-
-//#ifdef _MSC_VER
-//#pragma warning(push)
-//#pragma warning(disable : 4244) // conversion from 'gil::image<V,Alloc>::coord_t' to 'int', possible loss of data (visual studio compiler doesn't realize that the two types are the same)
-//#endif
namespace boost { namespace gil {
/// that don't own the pixels. It is the user's responsibility that the underlying data remains
/// valid for the lifetime of the image view.
///
-/// Similar to iterators and ranges, constness of views does not extend to constness of pixels.
-/// A const \p image_view does not allow changing its location in memory (resizing, moving) but does
+/// Similar to iterators and ranges, constness of views does not extend to constness of pixels.
+/// A const \p image_view does not allow changing its location in memory (resizing, moving) but does
/// not prevent one from changing the pixels. The latter requires an image view whose value_type
/// is const.
///
///
////////////////////////////////////////////////////////////////////////////////////////
template <typename Loc> // Models 2D Pixel Locator
-class image_view {
+class image_view
+{
public:
-
-// typedefs required by ConstRandomAccessNDImageViewConcept
+ // aliases required by ConstRandomAccessNDImageViewConcept
static const std::size_t num_dimensions=2;
- typedef typename Loc::value_type value_type;
- typedef typename Loc::reference reference; // result of dereferencing
- typedef typename Loc::coord_t coord_t; // 1D difference type (same for all dimensions)
- typedef coord_t difference_type; // result of operator-(1d_iterator,1d_iterator)
- typedef typename Loc::point_t point_t;
- typedef Loc locator;
- typedef image_view<typename Loc::const_t> const_t; // same as this type, but over const values
- template <std::size_t D> struct axis {
- typedef typename Loc::template axis<D>::coord_t coord_t; // difference_type along each dimension
- typedef typename Loc::template axis<D>::iterator iterator; // 1D iterator type along each dimension
+ using value_type = typename Loc::value_type;
+ using reference = typename Loc::reference; // result of dereferencing
+ using coord_t = typename Loc::coord_t; // 1D difference type (same for all dimensions)
+ using difference_type = coord_t; // result of operator-(1d_iterator,1d_iterator)
+ using point_t = typename Loc::point_t;
+ using locator = Loc;
+ using const_t = image_view<typename Loc::const_t>; // same as this type, but over const values
+ template <std::size_t D> struct axis
+ {
+ using coord_t = typename Loc::template axis<D>::coord_t; // difference_type along each dimension
+ using iterator = typename Loc::template axis<D>::iterator; // 1D iterator type along each dimension
};
- typedef iterator_from_2d<Loc> iterator; // 1D iterator type for each pixel left-to-right inside top-to-bottom
- typedef std::reverse_iterator<iterator> reverse_iterator;
- typedef std::size_t size_type;
-
-// typedefs required by ConstRandomAccess2DImageViewConcept
- typedef locator xy_locator;
- typedef typename xy_locator::x_iterator x_iterator; // pixel iterator along a row
- typedef typename xy_locator::y_iterator y_iterator; // pixel iterator along a column
- typedef typename xy_locator::x_coord_t x_coord_t;
- typedef typename xy_locator::y_coord_t y_coord_t;
-
- template <typename Deref> struct add_deref {
- typedef image_view<typename Loc::template add_deref<Deref>::type> type;
- static type make(const image_view<Loc>& iv, const Deref& d) { return type(iv.dimensions(), Loc::template add_deref<Deref>::make(iv.pixels(),d)); }
+ using iterator = iterator_from_2d<Loc>; // 1D iterator type for each pixel left-to-right inside top-to-bottom
+ using const_iterator = typename const_t::iterator; // may be used to examine, but not to modify values
+ using const_reference = typename const_t::reference; // behaves as a const reference
+ using pointer = typename std::iterator_traits<iterator>::pointer; // behaves as a pointer to the value type
+ using reverse_iterator = std::reverse_iterator<iterator>;
+ using size_type = std::size_t;
+
+ // aliases required by ConstRandomAccess2DImageViewConcept
+ using xy_locator = locator;
+ using x_iterator = typename xy_locator::x_iterator; // pixel iterator along a row
+ using y_iterator = typename xy_locator::y_iterator; // pixel iterator along a column
+ using x_coord_t = typename xy_locator::x_coord_t;
+ using y_coord_t = typename xy_locator::y_coord_t;
+
+ template <typename Deref>
+ struct add_deref
+ {
+ using type = image_view<typename Loc::template add_deref<Deref>::type>;
+ static type make(image_view<Loc> const& view, Deref const& d)
+ {
+ return type(view.dimensions(), Loc::template add_deref<Deref>::make(view.pixels(), d));
+ }
};
image_view() : _dimensions(0,0) {}
- template <typename View> image_view(const View& iv) : _dimensions(iv.dimensions()), _pixels(iv.pixels()) {}
-
- template <typename L2> image_view(const point_t& sz , const L2& loc) : _dimensions(sz), _pixels(loc) {}
- template <typename L2> image_view(coord_t width, coord_t height, const L2& loc) : _dimensions(x_coord_t(width),y_coord_t(height)), _pixels(loc) {}
-
- template <typename View> image_view& operator=(const View& iv) { _pixels=iv.pixels(); _dimensions=iv.dimensions(); return *this; }
- image_view& operator=(const image_view& iv) { _pixels=iv.pixels(); _dimensions=iv.dimensions(); return *this; }
-
- template <typename View> bool operator==(const View& v) const { return pixels()==v.pixels() && dimensions()==v.dimensions(); }
- template <typename View> bool operator!=(const View& v) const { return !(*this==v); }
-
- template <typename L2> friend void swap(image_view<L2>& x, image_view<L2>& y);
-
- const point_t& dimensions() const { return _dimensions; }
- const locator& pixels() const { return _pixels; }
- x_coord_t width() const { return dimensions().x; }
- y_coord_t height() const { return dimensions().y; }
- std::size_t num_channels() const { return gil::num_channels<value_type>::value; }
- bool is_1d_traversable() const { return _pixels.is_1d_traversable(width()); }
+ image_view(image_view const& img_view)
+ : _dimensions(img_view.dimensions()), _pixels(img_view.pixels())
+ {}
+
+ template <typename View>
+ image_view(View const& view) : _dimensions(view.dimensions()), _pixels(view.pixels()) {}
+
+ template <typename L2>
+ image_view(point_t const& dims, L2 const& loc) : _dimensions(dims), _pixels(loc) {}
+
+ template <typename L2>
+ image_view(coord_t width, coord_t height, L2 const& loc)
+ : _dimensions(x_coord_t(width), y_coord_t(height)), _pixels(loc)
+ {}
+
+ template <typename View>
+ image_view& operator=(View const& view)
+ {
+ _pixels = view.pixels();
+ _dimensions = view.dimensions();
+ return *this;
+ }
+
+ image_view& operator=(image_view const& view)
+ {
+ // TODO: Self-assignment protection?
+ _pixels = view.pixels();
+ _dimensions = view.dimensions();
+ return *this;
+ }
+
+ template <typename View>
+ bool operator==(View const &view) const
+ {
+ return pixels() == view.pixels() && dimensions() == view.dimensions();
+ }
+
+ template <typename View>
+ bool operator!=(View const& view) const
+ {
+ return !(*this == view);
+ }
+
+ template <typename L2>
+ friend void swap(image_view<L2> &lhs, image_view<L2> &rhs);
+
+ /// \brief Exchanges the elements of the current view with those of \a other
+ /// in constant time.
+ ///
+ /// \note Required by the Collection concept
+ /// \see https://www.boost.org/libs/utility/Collection.html
+ void swap(image_view<Loc>& other)
+ {
+ using boost::gil::swap;
+ swap(*this, other);
+ }
+
+ auto dimensions() const -> point_t const&
+ {
+ return _dimensions;
+ }
+
+ auto pixels() const -> locator const&
+ {
+ return _pixels;
+ }
+
+ auto width() const -> x_coord_t
+ {
+ return dimensions().x;
+ }
+
+ auto height() const -> y_coord_t
+ {
+ return dimensions().y;
+ }
+
+ auto num_channels() const -> std::size_t
+ {
+ return gil::num_channels<value_type>::value;
+ }
+
+ bool is_1d_traversable() const
+ {
+ return _pixels.is_1d_traversable(width());
+ }
+
+ /// \brief Returns true if the view has no elements, false otherwise.
+ ///
+ /// \note Required by the Collection concept
+ /// \see https://www.boost.org/libs/utility/Collection.html
+ bool empty() const
+ {
+ return !(width() > 0 && height() > 0);
+ }
+
+ /// \brief Returns a reference to the first element in raster order.
+ ///
+ /// \note Required by the ForwardCollection, since view model the concept.
+ /// \see https://www.boost.org/libs/utility/Collection.html
+ auto front() const -> reference
+ {
+ BOOST_ASSERT(!empty());
+ return *begin();
+ }
+
+ /// \brief Returns a reference to the last element in raster order.
+ ///
+ /// \note Required by the ForwardCollection, since view model the concept.
+ /// \see https://www.boost.org/libs/utility/Collection.html
+ auto back() const -> reference
+ {
+ BOOST_ASSERT(!empty());
+ return *rbegin();
+ }
//\{@
/// \name 1D navigation
- size_type size() const { return width()*height(); }
- iterator begin() const { return iterator(_pixels,_dimensions.x); }
- iterator end() const { return begin()+(difference_type)size(); } // potential performance problem!
- reverse_iterator rbegin() const { return reverse_iterator(end()); }
- reverse_iterator rend() const { return reverse_iterator(begin()); }
- reference operator[](difference_type i) const { return begin()[i]; } // potential performance problem!
- iterator at(difference_type i)const { return begin()+i; }
- iterator at(const point_t& p) const { return begin()+p.y*width()+p.x; }
- iterator at(x_coord_t x, y_coord_t y)const { return begin()+y*width()+x; }
-
+ auto size() const -> size_type
+ {
+ return width() * height();
+ }
+
+ auto begin() const -> iterator
+ {
+ return iterator(_pixels, _dimensions.x);
+ }
+
+ auto end() const -> iterator
+ {
+ // potential performance problem!
+ return begin() + static_cast<difference_type>(size());
+ }
+
+ auto rbegin() const -> reverse_iterator
+ {
+ return reverse_iterator(end());
+ }
+
+ auto rend() const -> reverse_iterator
+ {
+ return reverse_iterator(begin());
+ }
+
+ auto operator[](difference_type i) const -> reference
+ {
+ BOOST_ASSERT(i < static_cast<difference_type>(size()));
+ return begin()[i]; // potential performance problem!
+ }
+
+ auto at(difference_type i) const ->iterator
+ {
+ BOOST_ASSERT(i < size());
+ return begin() + i;
+ }
+
+ auto at(point_t const& p) const -> iterator
+ {
+ BOOST_ASSERT(0 <= p.x && p.x < width());
+ BOOST_ASSERT(0 <= p.y && p.y < height());
+ return begin() + p.y * width() + p.x;
+ }
+
+ auto at(x_coord_t x, y_coord_t y) const -> iterator
+ {
+ BOOST_ASSERT(0 <= x && x < width());
+ BOOST_ASSERT(0 <= y && y < height());
+ return begin() + y * width() + x;
+ }
//\}@
//\{@
/// \name 2-D navigation
- reference operator()(const point_t& p) const { return _pixels(p.x,p.y); }
- reference operator()(x_coord_t x, y_coord_t y)const { return _pixels(x,y); }
- template <std::size_t D> typename axis<D>::iterator axis_iterator(const point_t& p) const { return _pixels.axis_iterator<D>(p); }
- xy_locator xy_at(x_coord_t x, y_coord_t y) const { return _pixels+point_t(x_coord_t(x),y_coord_t(y)); }
- locator xy_at(const point_t& p) const { return _pixels+p; }
+ auto operator()(point_t const& p) const -> reference
+ {
+ BOOST_ASSERT(0 <= p.x && p.x < width());
+ BOOST_ASSERT(0 <= p.y && p.y < height());
+ return _pixels(p.x, p.y);
+ }
+
+ auto operator()(x_coord_t x, y_coord_t y) const -> reference
+ {
+ BOOST_ASSERT(0 <= x && x < width());
+ BOOST_ASSERT(0 <= y && y < height());
+ return _pixels(x, y);
+ }
+
+ template <std::size_t D>
+ auto axis_iterator(point_t const& p) const -> typename axis<D>::iterator
+ {
+ // allow request for iterators from inclusive range of [begin, end]
+ BOOST_ASSERT(0 <= p.x && p.x <= width());
+ BOOST_ASSERT(0 <= p.y && p.y <= height());
+ return _pixels.template axis_iterator<D>(p);
+ }
+
+ auto xy_at(x_coord_t x, y_coord_t y) const -> xy_locator
+ {
+ // TODO: Are relative locations of neighbors with negative offsets valid? Sampling?
+ BOOST_ASSERT(x < width());
+ BOOST_ASSERT(y < height());
+ return _pixels + point_t(x, y);
+ }
+
+ auto xy_at(point_t const& p) const -> locator
+ {
+ // TODO: Are relative locations of neighbors with negative offsets valid? Sampling?
+ BOOST_ASSERT(p.x < width());
+ BOOST_ASSERT(p.y < height());
+ return _pixels + p;
+ }
//\}@
//\{@
/// \name X navigation
- x_iterator x_at(x_coord_t x, y_coord_t y) const { return _pixels.x_at(x,y); }
- x_iterator x_at(const point_t& p) const { return _pixels.x_at(p); }
- x_iterator row_begin(y_coord_t y) const { return x_at(0,y); }
- x_iterator row_end(y_coord_t y) const { return x_at(width(),y); }
+ auto x_at(x_coord_t x, y_coord_t y) const -> x_iterator
+ {
+ BOOST_ASSERT(0 <= x && x <= width()); // allow request for [begin, end] inclusive
+ BOOST_ASSERT(0 <= y && y < height());
+ return _pixels.x_at(x, y);
+ }
+
+ auto x_at(point_t const& p) const -> x_iterator
+ {
+ BOOST_ASSERT(0 <= p.x && p.x <= width()); // allow request for [begin, end] inclusive
+ BOOST_ASSERT(0 <= p.y && p.y < height());
+ return _pixels.x_at(p);
+ }
+
+ auto row_begin(y_coord_t y) const -> x_iterator
+ {
+ BOOST_ASSERT(0 <= y && y < height());
+ return x_at(0, y);
+ }
+
+ auto row_end(y_coord_t y) const -> x_iterator
+ {
+ BOOST_ASSERT(0 <= y && y < height());
+ return x_at(width(), y);
+ }
//\}@
//\{@
/// \name Y navigation
- y_iterator y_at(x_coord_t x, y_coord_t y) const { return xy_at(x,y).y(); }
- y_iterator y_at(const point_t& p) const { return xy_at(p).y(); }
- y_iterator col_begin(x_coord_t x) const { return y_at(x,0); }
- y_iterator col_end(x_coord_t x) const { return y_at(x,height()); }
+ auto y_at(x_coord_t x, y_coord_t y) const -> y_iterator
+ {
+ BOOST_ASSERT(0 <= x && x < width());
+ BOOST_ASSERT(0 <= y && y <= height()); // allow request for [begin, end] inclusive
+ return xy_at(x, y).y();
+ }
+
+ auto y_at(point_t const& p) const -> y_iterator
+ {
+ BOOST_ASSERT(0 <= p.x && p.x < width());
+ BOOST_ASSERT(0 <= p.y && p.y <= height()); // allow request for [begin, end] inclusive
+ return xy_at(p).y();
+ }
+
+ auto col_begin(x_coord_t x) const -> y_iterator
+ {
+ BOOST_ASSERT(0 <= x && x < width());
+ return y_at(x, 0);
+ }
+
+ auto col_end(x_coord_t x) const -> y_iterator
+ {
+ BOOST_ASSERT(0 <= x && x < width());
+ return y_at(x, height());
+ }
//\}@
private:
- template <typename L2> friend class image_view;
+ template <typename L2>
+ friend class image_view;
point_t _dimensions;
xy_locator _pixels;
};
-template <typename L2>
-inline void swap(image_view<L2>& x, image_view<L2>& y) {
+template <typename L2>
+inline void swap(image_view<L2>& x, image_view<L2>& y) {
using std::swap;
- swap(x._dimensions,y._dimensions);
+ swap(x._dimensions,y._dimensions);
swap(x._pixels, y._pixels); // TODO: Extend further
}
/////////////////////////////
template <typename L>
-struct channel_type<image_view<L> > : public channel_type<L> {};
+struct channel_type<image_view<L> > : public channel_type<L> {};
template <typename L>
-struct color_space_type<image_view<L> > : public color_space_type<L> {};
+struct color_space_type<image_view<L> > : public color_space_type<L> {};
template <typename L>
-struct channel_mapping_type<image_view<L> > : public channel_mapping_type<L> {};
+struct channel_mapping_type<image_view<L> > : public channel_mapping_type<L> {};
template <typename L>
-struct is_planar<image_view<L> > : public is_planar<L> {};
+struct is_planar<image_view<L> > : public is_planar<L> {};
/////////////////////////////
// HasDynamicXStepTypeConcept
/////////////////////////////
template <typename L>
-struct dynamic_x_step_type<image_view<L> > {
- typedef image_view<typename dynamic_x_step_type<L>::type> type;
+struct dynamic_x_step_type<image_view<L>>
+{
+ using type = image_view<typename gil::dynamic_x_step_type<L>::type>;
};
/////////////////////////////
/////////////////////////////
template <typename L>
-struct dynamic_y_step_type<image_view<L> > {
- typedef image_view<typename dynamic_y_step_type<L>::type> type;
+struct dynamic_y_step_type<image_view<L>>
+{
+ using type = image_view<typename gil::dynamic_y_step_type<L>::type>;
};
/////////////////////////////
/////////////////////////////
template <typename L>
-struct transposed_type<image_view<L> > {
- typedef image_view<typename transposed_type<L>::type> type;
+struct transposed_type<image_view<L>>
+{
+ using type = image_view<typename transposed_type<L>::type>;
};
-} } // namespace boost::gil
-
-//#ifdef _MSC_VER
-//#pragma warning(pop)
-//#endif
+}} // namespace boost::gil
#endif