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