From 2ad6747dd0472cef7c67b3438b847f347ce45212 Mon Sep 17 00:00:00 2001 From: Lubomir Bourdev Date: Mon, 17 Sep 2007 08:12:19 +0000 Subject: [PATCH] GIL 2.0 to 2.1 (see http://opensource.adobe.com/gil/gil2.1_changes.pdf). GIL 2.1 to 2.1.1 (see http://sourceforge.net/forum/forum.php?thread_id=1824588&forum_id=648138) [SVN r39339] --- example/Makefile | 10 +- example/convolution.cpp | 56 ++- example/dynamic_image.cpp | 12 + example/histogram.cpp | 12 + example/interleaved_ptr.cpp | 16 +- example/interleaved_ptr.hpp | 31 +- example/interleaved_ref.hpp | 33 +- example/packed_pixel.cpp | 52 ++- example/resize.cpp | 17 + example/x_gradient.cpp | 12 + include/boost/gil/algorithm.hpp | 87 +++-- .../boost/gil/bit_aligned_pixel_iterator.hpp | 190 ++++++++++ .../boost/gil/bit_aligned_pixel_reference.hpp | 297 ++++++++++++++++ include/boost/gil/channel.hpp | 280 ++++++++++----- include/boost/gil/channel_algorithm.hpp | 334 +++++++++++++----- include/boost/gil/color_base.hpp | 78 ++-- include/boost/gil/color_base_algorithm.hpp | 279 +++++++++++---- include/boost/gil/color_convert.hpp | 28 +- include/boost/gil/deprecated.hpp | 16 +- include/boost/gil/gil_all.hpp | 1 + include/boost/gil/gil_concept.hpp | 104 +++--- include/boost/gil/gil_config.hpp | 2 +- include/boost/gil/image.hpp | 39 +- include/boost/gil/image_view_factory.hpp | 94 +++-- include/boost/gil/iterator_from_2d.hpp | 46 +-- include/boost/gil/locator.hpp | 99 +++--- include/boost/gil/metafunctions.hpp | 202 +++++++++-- include/boost/gil/packed_pixel.hpp | 206 ++++++----- include/boost/gil/pixel.hpp | 46 ++- include/boost/gil/pixel_iterator.hpp | 74 ++-- include/boost/gil/pixel_iterator_adaptor.hpp | 35 +- include/boost/gil/planar_pixel_iterator.hpp | 50 ++- include/boost/gil/planar_pixel_reference.hpp | 29 ++ include/boost/gil/position_iterator.hpp | 2 +- include/boost/gil/step_iterator.hpp | 128 +++---- include/boost/gil/typedefs.hpp | 28 +- include/boost/gil/utilities.hpp | 46 ++- test/Makefile | 12 +- test/channel.cpp | 59 ++-- test/gil_reference_checksums.txt | 47 ++- test/image.cpp | 67 +++- test/performance.cpp | 18 +- test/pixel.cpp | 59 ++-- test/pixel_iterator.cpp | 65 +++- 44 files changed, 2497 insertions(+), 901 deletions(-) create mode 100644 include/boost/gil/bit_aligned_pixel_iterator.hpp create mode 100644 include/boost/gil/bit_aligned_pixel_reference.hpp diff --git a/example/Makefile b/example/Makefile index 521fd701a4..bcf8820ca2 100644 --- a/example/Makefile +++ b/example/Makefile @@ -1,9 +1,11 @@ +.SUFFIXES: .cpp +#CXX=/usr/local/gcc-411/bin/g++ CXX=g++ CXX_FLAGS=-Wall -O2 -DNDEBUG -DBOOST_GIL_USE_CONCEPT_CHECK -BOOST_INCLUDE_PATH=-I../../.. -LIBJPEG_INCLUDE_PATH=-I../../../boost/gil/lib/libjpeg -LIBJPEG_LIB_PATH=-L../../../boost/gil/lib/libjpeg +BOOST_INCLUDE_PATH=-I../../.. -I../../../../boost_libraries +LIBJPEG_INCLUDE_PATH=-I../../../../lib/libjpeg +LIBJPEG_LIB_PATH=-L../../../../lib/libjpeg all: resize affine convolution mandelbrot x_gradient histogram dynamic_image interleaved_ptr packed_pixel .cpp.o: @@ -11,7 +13,7 @@ all: resize affine convolution mandelbrot x_gradient histogram dynamic_image int clean: -rm -f *.o *.exe -rm -f out-affine.jpg out-resize.jpg out-convolution.jpg out-convolution2.jpg out-mandelbrot.jpg - -rm -f out-interleaved_ptr.jpg out-x_gradient.jpg out-histogram.txt out-packed_pixel.jpg out-dynamic_image.jpg + -rm -f out-interleaved_ptr.jpg out-x_gradient.jpg out-histogram.txt out-packed_pixel_bgr772.jpg out-packed_pixel_gray1.jpg out-dynamic_image.jpg resize: resize.o ${CXX} -o resize ${CXX_FLAGS} resize.o ${LIBJPEG_LIB_PATH} -ljpeg affine: affine.o diff --git a/example/convolution.cpp b/example/convolution.cpp index 796cad1896..0ed18e5f32 100644 --- a/example/convolution.cpp +++ b/example/convolution.cpp @@ -1,3 +1,20 @@ +/* + 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). + + See http://opensource.adobe.com/gil for most recent version including documentation. +*/ + +/*************************************************************************************************/ + +/////////////////////// +//// NOTE: This sample file uses the numeric extension, which does not come with the Boost distribution. +//// You may download it from http://opensource.adobe.com/gil +/////////////////////// + /// \file /// \brief Test file for convolve_rows() and convolve_cols() in the numeric extension /// \author Lubomir Bourdev and Hailin Jin @@ -18,17 +35,48 @@ int main() { // Convolve the rows and the columns of the image with a fixed kernel rgb8_image_t convolved(img); - float gaussian[]={0.00022923296f,0.0059770769f,0.060597949f,0.24173197f,0.38292751f, - 0.24173197f,0.060597949f,0.0059770769f,0.00022923296f}; + // radius-1 Gaussian kernel, size 9 + float gaussian_1[]={0.00022923296f,0.0059770769f,0.060597949f,0.24173197f,0.38292751f, + 0.24173197f,0.060597949f,0.0059770769f,0.00022923296f}; + /* + // radius-2 Gaussian kernel, size 15 + float gaussian_2[]={ + 0.00048869418f,0.0024031631f,0.0092463447f, + 0.027839607f,0.065602221f,0.12099898f,0.17469721f, + 0.19744757f, + 0.17469721f,0.12099898f,0.065602221f,0.027839607f, + 0.0092463447f,0.0024031631f,0.00048869418f + }; + //radius-3 Gaussian kernel, size 23 + float gaussian_3[]={ + 0.00016944126f,0.00053842377f,0.0015324751f,0.0039068931f, + 0.0089216027f,0.018248675f,0.033434924f,0.054872241f, + 0.080666073f,0.10622258f,0.12529446f, + 0.13238440f, + 0.12529446f,0.10622258f,0.080666073f, + 0.054872241f,0.033434924f,0.018248675f,0.0089216027f, + 0.0039068931f,0.0015324751f,0.00053842377f,0.00016944126f + }; + //radius-4 Gaussian kernel, size 29 + float gaussian_4[]={ + 0.00022466264f,0.00052009715f,0.0011314391f,0.0023129794f, + 0.0044433107f,0.0080211498f,0.013606987f,0.021691186f, + 0.032493830f,0.045742013f,0.060509924f,0.075220309f, + 0.087870099f,0.096459411f,0.099505201f,0.096459411f,0.087870099f, + 0.075220309f,0.060509924f,0.045742013f,0.032493830f, + 0.021691186f,0.013606987f,0.0080211498f,0.0044433107f, + 0.0023129794f,0.0011314391f,0.00052009715f,0.00022466264f, + }; + */ - kernel_1d_fixed kernel(gaussian,4); + kernel_1d_fixed kernel(gaussian_1,4); convolve_rows_fixed(const_view(convolved),kernel,view(convolved)); convolve_cols_fixed(const_view(convolved),kernel,view(convolved)); jpeg_write_view("out-convolution.jpg", view(convolved)); // This is how to use a resizable kernel - kernel_1d kernel2(gaussian,9,4); + kernel_1d kernel2(gaussian_1,9,4); convolve_rows(const_view(img),kernel2,view(img)); convolve_cols(const_view(img),kernel2,view(img)); jpeg_write_view("out-convolution2.jpg", view(img)); diff --git a/example/dynamic_image.cpp b/example/dynamic_image.cpp index 3721af67df..4bc7a4dedd 100644 --- a/example/dynamic_image.cpp +++ b/example/dynamic_image.cpp @@ -1,3 +1,15 @@ +/* + 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). + + See http://opensource.adobe.com/gil for most recent version including documentation. +*/ + +/*************************************************************************************************/ + /// \file /// \brief Test file for using dynamic images /// \author Lubomir Bourdev and Hailin Jin diff --git a/example/histogram.cpp b/example/histogram.cpp index 1a68e65d52..7ecfafb206 100644 --- a/example/histogram.cpp +++ b/example/histogram.cpp @@ -1,3 +1,15 @@ +/* + 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). + + See http://opensource.adobe.com/gil for most recent version including documentation. +*/ + +/*************************************************************************************************/ + /// \file /// \brief Example file to demonstrate a way to compute histogram /// \author Lubomir Bourdev and Hailin Jin diff --git a/example/interleaved_ptr.cpp b/example/interleaved_ptr.cpp index edd1022b48..995e7e7ff5 100644 --- a/example/interleaved_ptr.cpp +++ b/example/interleaved_ptr.cpp @@ -1,3 +1,15 @@ +/* + 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). + + See http://opensource.adobe.com/gil for most recent version including documentation. +*/ + +/*************************************************************************************************/ + /// \file /// \brief Example file to demonstrate how to create a model of a pixel iterator /// \author Lubomir Bourdev and Hailin Jin @@ -32,7 +44,7 @@ int main(int argc, unsigned char* argv[]) boost::function_requires >(); boost::function_requires >(); - boost::function_requires > >(); + boost::function_requires > >(); boost::function_requires >(); boost::function_requires >(); @@ -51,7 +63,7 @@ int main(int argc, unsigned char* argv[]) // Construct a view from it, without casting it to rgb8_pixel_t* rgb8_interleaved_view_t src_view=interleaved_view(img.width(),img.height(),rgb8_interleaved_ptr(raw_ptr), - view(img).pixels().row_bytes()); + view(img).pixels().row_size()); // Apply view transformations and algorithms on it jpeg_write_view("out-interleaved_ptr.jpg",nth_channel_view(flipped_up_down_view(src_view),1)); diff --git a/example/interleaved_ptr.hpp b/example/interleaved_ptr.hpp index dd2690c6a9..8013b21c46 100644 --- a/example/interleaved_ptr.hpp +++ b/example/interleaved_ptr.hpp @@ -1,8 +1,13 @@ /* Copyright 2005-2007 Adobe Systems Incorporated - Distributed under the MIT License (see accompanying file LICENSE_1_0_0.txt - or a copy at http://opensource.adobe.com/licenses.html) + + 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). + + See http://opensource.adobe.com/gil for most recent version including documentation. */ + /*************************************************************************************************/ //////////////////////////////////////////////////////////////////////////////////////// @@ -69,7 +74,7 @@ struct interleaved_ptr : public boost::iterator_facade() const { return **this; } @@ -152,32 +157,32 @@ struct channel_type > { ///////////////////////////// template -inline std::ptrdiff_t byte_step(const interleaved_ptr&) { +inline std::ptrdiff_t memunit_step(const interleaved_ptr&) { return sizeof(typename std::iterator_traits::value_type)* // size of each channel in bytes interleaved_ptr::num_channels; // times the number of channels } template -inline std::ptrdiff_t byte_distance(const interleaved_ptr& p1, const interleaved_ptr& p2) { - return byte_distance(p1.channels(),p2.channels()); +inline std::ptrdiff_t memunit_distance(const interleaved_ptr& p1, const interleaved_ptr& p2) { + return memunit_distance(p1.channels(),p2.channels()); } template -inline void byte_advance(interleaved_ptr& p, std::ptrdiff_t byte_diff) { - byte_advance(p.channels(), byte_diff); +inline void memunit_advance(interleaved_ptr& p, std::ptrdiff_t diff) { + memunit_advance(p.channels(), diff); } template -inline interleaved_ptr byte_advanced(const interleaved_ptr& p, std::ptrdiff_t byteDiff) { +inline interleaved_ptr memunit_advanced(const interleaved_ptr& p, std::ptrdiff_t diff) { interleaved_ptr ret=p; - byte_advance(ret, byteDiff); + memunit_advance(ret, diff); return ret; } template -inline typename interleaved_ptr::reference byte_advanced_ref(const interleaved_ptr& p, std::ptrdiff_t byteDiff) { +inline typename interleaved_ptr::reference memunit_advanced_ref(const interleaved_ptr& p, std::ptrdiff_t diff) { interleaved_ptr ret=p; - byte_advance(ret, byteDiff); + memunit_advance(ret, diff); return *ret; } @@ -187,7 +192,7 @@ inline typename interleaved_ptr::reference byte_advanced_ref( template struct dynamic_x_step_type > { - typedef byte_addressable_step_iterator > type; + typedef memory_based_step_iterator > type; }; } } // namespace boost::gil diff --git a/example/interleaved_ref.hpp b/example/interleaved_ref.hpp index a7ad5a94a9..e8f25da561 100644 --- a/example/interleaved_ref.hpp +++ b/example/interleaved_ref.hpp @@ -1,10 +1,16 @@ /* Copyright 2005-2007 Adobe Systems Incorporated - Distributed under the MIT License (see accompanying file LICENSE_1_0_0.txt - or a copy at http://opensource.adobe.com/licenses.html) + + 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). + + See http://opensource.adobe.com/gil for most recent version including documentation. */ + /*************************************************************************************************/ + //////////////////////////////////////////////////////////////////////////////////////// /// \file /// \brief Example on how to create a new model of a pixel reference @@ -53,10 +59,6 @@ struct interleaved_ref { // Required by ColorBaseConcept typedef Layout layout_t; - // Type of each channel, and the result of constant and mutable at_c(*this); - template struct kth_element_type { typedef channel_t type; }; - template struct kth_element_const_reference_type { typedef channel_reference_t type; }; - // Copy construction from a compatible type. The copy constructor of references is shallow. The channels themselves are not copied. interleaved_ref(const interleaved_ref& p) : _channels(p._channels) {} template interleaved_ref(const P& p) : _channels(p._channels) { check_compatible

(); } @@ -65,7 +67,6 @@ struct interleaved_ref { template bool operator!=(const P& p) const { return !(*this==p); } // Required by MutableColorBaseConcept - template struct kth_element_reference_type { typedef channel_reference_t type; }; // Assignment from a compatible type const interleaved_ref& operator=(const interleaved_ref& p) const { static_copy(p,*this); return *this; } @@ -90,6 +91,24 @@ struct interleaved_ref { template static void check_compatible() { gil_function_requires >(); } }; +// Required by ColorBaseConcept +template +struct kth_element_type,K> { + typedef ChannelReference type; +}; + +template +struct kth_element_reference_type,K> { + typedef ChannelReference type; +}; + +template +struct kth_element_const_reference_type,K> { + typedef ChannelReference type; +// typedef typename channel_traits::const_reference type; +}; + + // Required by ColorBaseConcept template typename element_reference_type >::type diff --git a/example/packed_pixel.cpp b/example/packed_pixel.cpp index f5fbcaf626..3a234ba095 100644 --- a/example/packed_pixel.cpp +++ b/example/packed_pixel.cpp @@ -1,3 +1,15 @@ +/* + 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). + + See http://opensource.adobe.com/gil for most recent version including documentation. +*/ + +/*************************************************************************************************/ + /// \file /// \brief Example file to show how to deal with packed pixels /// \author Lubomir Bourdev and Hailin Jin @@ -12,6 +24,12 @@ /// We read a regular 8-bit RGB image, convert it to packed BGR772, convert it back to 8-bit RGB and save it to a file. /// Since the red channel is only two bits the color loss should be observable in the result /// +/// This test file also demonstrates how to use bit-aligned images - these are images whose pixels themselves are not byte aligned. +/// For example, an rgb222 image has a pixel whose size is 6 bits. Bit-aligned images are more complicated than packed images. They +/// require a special proxy class to represent pixel reference and pixel iterator (packed images use C++ reference and C pointer respectively). +/// The alignment parameter in the constructor of bit-aligned images is in bit units. For example, if you want your bit-aligned image to have 4-byte +/// alignment of its rows use alignment of 32, not 4. +/// /// To demonstrate that image view transformations work on packed images, we save the result transposed. #include @@ -20,27 +38,31 @@ using namespace boost; using namespace boost::gil; - -// define a bgr772 image -typedef const packed_channel_reference bgr772_channel0_t; -typedef const packed_channel_reference bgr772_channel1_t; -typedef const packed_channel_reference bgr772_channel2_t; -typedef heterogeneous_packed_pixel, bgr_layout_t> bgr772_pixel_t; -typedef image bgr772_image_t; - int main() { - boost::function_requires >(); - BOOST_STATIC_ASSERT((sizeof(bgr772_pixel_t)==2)); - bgr8_image_t img; jpeg_read_image("test.jpg",img); - bgr772_image_t img_packed1(img.dimensions()); - copy_and_convert_pixels(const_view(img),view(img_packed1)); + //////////////////////////////// + // define a bgr772 image. It is a "packed" image - its channels are not byte-aligned, but its pixels are. + //////////////////////////////// + + typedef packed_image3_type::type bgr772_image_t; + bgr772_image_t bgr772_img(img.dimensions()); + copy_and_convert_pixels(const_view(img),view(bgr772_img)); + + // Save the result. JPEG I/O does not support the packed pixel format, so convert it back to 8-bit RGB + jpeg_write_view("out-packed_pixel_bgr772.jpg",color_converted_view(transposed_view(const_view(bgr772_img)))); + + //////////////////////////////// + // define a gray1 image (one-bit per pixel). It is a "bit-aligned" image - its pixels are not byte aligned. + //////////////////////////////// + + typedef bit_aligned_image1_type<1, gray_layout_t>::type gray1_image_t; + gray1_image_t gray1_img(img.dimensions()); + copy_and_convert_pixels(const_view(img),view(gray1_img)); // Save the result. JPEG I/O does not support the packed pixel format, so convert it back to 8-bit RGB - jpeg_write_view("out-packed_pixel.jpg",color_converted_view(transposed_view(const_view(img_packed1)))); + jpeg_write_view("out-packed_pixel_gray1.jpg",color_converted_view(transposed_view(const_view(gray1_img)))); return 0; } diff --git a/example/resize.cpp b/example/resize.cpp index a7f4c7584a..50dd03e924 100644 --- a/example/resize.cpp +++ b/example/resize.cpp @@ -1,8 +1,25 @@ +/* + 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). + + See http://opensource.adobe.com/gil for most recent version including documentation. +*/ + +/*************************************************************************************************/ + /// \file /// \brief Test file for resize_view() in the numeric extension /// \author Lubomir Bourdev and Hailin Jin /// \date February 27, 2007 +/////////////////////// +//// NOTE: This sample file uses the numeric extension, which does not come with the Boost distribution. +//// You may download it from http://opensource.adobe.com/gil +/////////////////////// + #include #include #include diff --git a/example/x_gradient.cpp b/example/x_gradient.cpp index 5608591b92..4cafe4583f 100644 --- a/example/x_gradient.cpp +++ b/example/x_gradient.cpp @@ -1,3 +1,15 @@ +/* + 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). + + See http://opensource.adobe.com/gil for most recent version including documentation. +*/ + +/*************************************************************************************************/ + /// \file /// \brief Example file to demonstrate a way to compute gradients along x-axis /// \author Lubomir Bourdev and Hailin Jin diff --git a/include/boost/gil/algorithm.hpp b/include/boost/gil/algorithm.hpp index 347ed9a556..f55369a7ed 100644 --- a/include/boost/gil/algorithm.hpp +++ b/include/boost/gil/algorithm.hpp @@ -24,6 +24,7 @@ #include "color_base_algorithm.hpp" #include "image_view.hpp" #include "image_view_factory.hpp" +#include "bit_aligned_pixel_iterator.hpp" //////////////////////////////////////////////////////////////////////////////////////// /// \file @@ -45,9 +46,9 @@ namespace boost { namespace gil { template struct planar_pixel_iterator; template -class byte_addressable_step_iterator; +class memory_based_step_iterator; template -class byte_addressable_2d_locator; +class memory_based_2d_locator; // a tag denoting incompatible arguments struct error_t {}; @@ -245,31 +246,39 @@ struct copier_n,iterator_from_2d

    > { } } }; -} // namespace detail -} } // namespace boost::gil -namespace std { -/// \ingroup STLOptimizations -/// \brief std::copy(I1,I1,I2) with I1 and I2 being a iterator_from_2d -template -GIL_FORCEINLINE boost::gil::iterator_from_2d
      copy(boost::gil::iterator_from_2d first, boost::gil::iterator_from_2d last, boost::gil::iterator_from_2d
        dst) { - boost::gil::gil_function_requires >(); - boost::gil::gil_function_requires >(); - typedef typename boost::gil::iterator_from_2d::difference_type diff_t; - diff_t n=diff_t(last-first); +template +GIL_FORCEINLINE DstIterator copy_with_2d_iterators(SrcIterator first, SrcIterator last, DstIterator dst) { + typedef typename SrcIterator::x_iterator src_x_iterator; + typedef typename DstIterator::x_iterator dst_x_iterator; + + typename SrcIterator::difference_type n = last - first; + if (first.is_1d_traversable()) { if (dst.is_1d_traversable()) - boost::gil::detail::copier_n()(first.x(),n, dst.x()); + copier_n()(first.x(),n, dst.x()); else - boost::gil::detail::copier_n >()(first.x(),n, dst); + copier_n()(first.x(),n, dst); } else { if (dst.is_1d_traversable()) - boost::gil::detail::copier_n,typename OL::x_iterator>()(first,n, dst.x()); + copier_n()(first,n, dst.x()); else - boost::gil::detail::copier_n,boost::gil::iterator_from_2d
          >()(first,n,dst); + copier_n()(first,n,dst); } return dst+n; } + +} // namespace detail +} } // namespace boost::gil + +namespace std { +/// \ingroup STLOptimizations +/// \brief std::copy(I1,I1,I2) with I1 and I2 being a iterator_from_2d +template +GIL_FORCEINLINE boost::gil::iterator_from_2d
            copy1(boost::gil::iterator_from_2d first, boost::gil::iterator_from_2d last, boost::gil::iterator_from_2d
              dst) { + return boost::gil::detail::copy_with_2d_iterators(first,last,dst); +} + } // namespace std namespace boost { namespace gil { @@ -280,7 +289,7 @@ namespace boost { namespace gil { template GIL_FORCEINLINE void copy_pixels(const View1& src, const View2& dst) { assert(src.dimensions()==dst.dimensions()); - std::copy(src.begin(),src.end(),dst.begin()); // std::copy will choose the optimal method (see stl_override.h) + detail::copy_with_2d_iterators(src.begin(),src.end(),dst.begin()); } ////////////////////////////////////////////////////////////////////////////////////// @@ -426,8 +435,8 @@ void fill_pixels(const View& img_view, const Value& val) { namespace detail { -template -void destruct_range(It first, It last) { +template GIL_FORCEINLINE +void destruct_range_impl(It first, It last, mpl::true_) { typedef typename std::iterator_traits::value_type value_t; if (boost::has_trivial_destructor::value) return; @@ -436,6 +445,13 @@ void destruct_range(It first, It last) { ++first; } } +template GIL_FORCEINLINE +void destruct_range_impl(It first, It last, mpl::false_) {} + +template GIL_FORCEINLINE +void destruct_range(It first, It last) { + destruct_range_impl(first,last,typename is_pointer::type()); +} struct std_destruct_t { template void operator()(It first, It last) const { destruct_range(first,last); } @@ -549,25 +565,26 @@ void uninitialized_fill_pixels(const View& img_view, const Value& val) { namespace detail { -template -GIL_FORCEINLINE -void default_construct_range(It first, It last) { +template GIL_FORCEINLINE +void default_construct_range_impl(It first, It last, mpl::true_) { typedef typename std::iterator_traits::value_type value_t; - if (boost::is_pointer::value) { - It first1=first; - try { - while (first!=last) { - new (first) value_t(); - ++first; - } - } catch (...) { - destruct_range(first1,first); - throw; + It first1=first; + try { + while (first!=last) { + new (first) value_t(); + ++first; } - } else - std::uninitialized_fill(first,last,value_t()); + } catch (...) { + destruct_range(first1,first); + throw; + } } +template GIL_FORCEINLINE +void default_construct_range_impl(It first, It last, mpl::false_) {} + +template GIL_FORCEINLINE +void default_construct_range(It first, It last) { default_construct_range_impl(first, last, typename is_pointer::type()); } /// uninitialized_default_construct for planar iterators template diff --git a/include/boost/gil/bit_aligned_pixel_iterator.hpp b/include/boost/gil/bit_aligned_pixel_iterator.hpp new file mode 100644 index 0000000000..297dbca446 --- /dev/null +++ b/include/boost/gil/bit_aligned_pixel_iterator.hpp @@ -0,0 +1,190 @@ +/* + 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). + + See http://opensource.adobe.com/gil for most recent version including documentation. +*/ + +/*************************************************************************************************/ + +#ifndef GIL_BIT_ALIGNED_PIXEL_ITERATOR_HPP +#define GIL_BIT_ALIGNED_PIXEL_ITERATOR_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file +/// \brief A model of a heterogeneous pixel that is not byte aligned. Examples are bitmap (1-bit pixels) or 6-bit RGB (222) +/// \author Lubomir Bourdev and Hailin Jin \n +/// Adobe Systems Incorporated +/// \date 2005-2007 \n Last updated on September 28, 2006 +/// +//////////////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include "gil_config.hpp" +#include "bit_aligned_pixel_reference.hpp" + +namespace boost { namespace gil { + +/// \defgroup PixelIteratorNonAlignedPixelIterator bit_aligned_pixel_iterator +/// \ingroup PixelIteratorModel +/// \brief An iterator over non-byte-aligned pixels. Models PixelIteratorConcept, PixelBasedConcept, MemoryBasedIteratorConcept, HasDynamicXStepTypeConcept + +//////////////////////////////////////////////////////////////////////////////////////// +/// \brief An iterator over non-byte-aligned pixels. Models PixelIteratorConcept, PixelBasedConcept, MemoryBasedIteratorConcept, HasDynamicXStepTypeConcept +/// +/// An iterator over pixels that correspond to non-byte-aligned bit ranges. Examples of such pixels are single bit grayscale pixel, or a 6-bit RGB 222 pixel. +/// +/// \ingroup PixelIteratorNonAlignedPixelIterator PixelBasedModel + +template +struct bit_aligned_pixel_iterator : public iterator_facade, + typename NonAlignedPixelReference::value_type, + random_access_traversal_tag, + const NonAlignedPixelReference, + typename NonAlignedPixelReference::bit_range_t::difference_type> { +private: + typedef iterator_facade, + typename NonAlignedPixelReference::value_type, + random_access_traversal_tag, + const NonAlignedPixelReference, + typename NonAlignedPixelReference::bit_range_t::difference_type> parent_t; + template friend struct bit_aligned_pixel_iterator; + + typedef typename NonAlignedPixelReference::bit_range_t bit_range_t; +public: + typedef typename parent_t::difference_type difference_type; + typedef typename parent_t::reference reference; + + bit_aligned_pixel_iterator() {} + bit_aligned_pixel_iterator(const bit_aligned_pixel_iterator& p) : _bit_range(p._bit_range) {} + bit_aligned_pixel_iterator& operator=(const bit_aligned_pixel_iterator& p) { _bit_range=p._bit_range; return *this; } + + template bit_aligned_pixel_iterator(const bit_aligned_pixel_iterator& p) : _bit_range(p._bit_range) {} + + bit_aligned_pixel_iterator(reference* ref) : _bit_range(ref->bit_range()) {} + explicit bit_aligned_pixel_iterator(typename bit_range_t::byte_t* data, int bit_offset=0) : _bit_range(data,bit_offset) {} + + /// For some reason operator[] provided by iterator_adaptor returns a custom class that is convertible to reference + /// We require our own reference because it is registered in iterator_traits + reference operator[](difference_type d) const { bit_aligned_pixel_iterator it=*this; it.advance(d); return *it; } + + reference operator->() const { return **this; } + const bit_range_t& bit_range() const { return _bit_range; } + bit_range_t& bit_range() { return _bit_range; } +private: + bit_range_t _bit_range; + BOOST_STATIC_CONSTANT(int, bit_size = NonAlignedPixelReference::bit_size); + + friend class boost::iterator_core_access; + reference dereference() const { return NonAlignedPixelReference(_bit_range); } + void increment() { ++_bit_range; } + void decrement() { --_bit_range; } + void advance(difference_type d) { _bit_range.bit_advance(d*bit_size); } + + difference_type distance_to(const bit_aligned_pixel_iterator& it) const { return _bit_range.bit_distance_to(it._bit_range) / bit_size; } + bool equal(const bit_aligned_pixel_iterator& it) const { return _bit_range==it._bit_range; } +}; + +template +struct const_iterator_type > { + typedef bit_aligned_pixel_iterator type; +}; + +template +struct iterator_is_mutable > : public mpl::bool_ {}; + +template +struct is_iterator_adaptor > : public mpl::false_ {}; + +///////////////////////////// +// PixelBasedConcept +///////////////////////////// + +template +struct color_space_type > : public color_space_type {}; + +template +struct channel_mapping_type > : public channel_mapping_type {}; + +template +struct is_planar > : public is_planar {}; // == false + +///////////////////////////// +// MemoryBasedIteratorConcept +///////////////////////////// + +template +struct byte_to_memunit > : public mpl::int_<8> {}; + +template +inline std::ptrdiff_t memunit_step(const bit_aligned_pixel_iterator&) { + return NonAlignedPixelReference::bit_size; +} + +template +inline std::ptrdiff_t memunit_distance(const bit_aligned_pixel_iterator& p1, const bit_aligned_pixel_iterator& p2) { + return (p2.bit_range().current_byte() - p1.bit_range().current_byte())*8 + p2.bit_range().bit_offset() - p1.bit_range().bit_offset(); +} + +template +inline void memunit_advance(bit_aligned_pixel_iterator& p, std::ptrdiff_t diff) { + p.bit_range().bit_advance(diff); +} + +template +inline bit_aligned_pixel_iterator memunit_advanced(const bit_aligned_pixel_iterator& p, std::ptrdiff_t diff) { + bit_aligned_pixel_iterator ret=p; + memunit_advance(ret, diff); + return ret; +} + +template inline +NonAlignedPixelReference memunit_advanced_ref(bit_aligned_pixel_iterator it, std::ptrdiff_t diff) { + return *memunit_advanced(it,diff); +} +///////////////////////////// +// HasDynamicXStepTypeConcept +///////////////////////////// + +template +struct dynamic_x_step_type > { + typedef memory_based_step_iterator > type; +}; + +///////////////////////////// +// iterator_type_from_pixel +///////////////////////////// + +template +struct iterator_type_from_pixel,false,false,false> { + typedef bit_aligned_pixel_iterator > type; +}; + +template +struct iterator_type_from_pixel,false,false,true> { + typedef bit_aligned_pixel_iterator > type; +}; + +template +struct iterator_type_from_pixel,IsPlanar,IsStep,IsMutable> + : public iterator_type_from_pixel,IsPlanar,IsStep,IsMutable> {}; + +} } // namespace boost::gil + +namespace std { + +// It is important to provide an overload of uninitialized_copy for bit_aligned_pixel_iterator. The default STL implementation calls placement new, +// which is not defined for bit_aligned_pixel_iterator. +template +boost::gil::bit_aligned_pixel_iterator uninitialized_copy(boost::gil::bit_aligned_pixel_iterator first, + boost::gil::bit_aligned_pixel_iterator last, + boost::gil::bit_aligned_pixel_iterator dst) { + return std::copy(first,last,dst); +} + +} // namespace std +#endif diff --git a/include/boost/gil/bit_aligned_pixel_reference.hpp b/include/boost/gil/bit_aligned_pixel_reference.hpp new file mode 100644 index 0000000000..9a2cd79c55 --- /dev/null +++ b/include/boost/gil/bit_aligned_pixel_reference.hpp @@ -0,0 +1,297 @@ +/* + 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). + + See http://opensource.adobe.com/gil for most recent version including documentation. +*/ + +/*************************************************************************************************/ + +#ifndef GIL_BIT_ALIGNED_PIXEL_REFERENCE_HPP +#define GIL_BIT_ALIGNED_PIXEL_REFERENCE_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file +/// \brief A model of a heterogeneous pixel that is not byte aligned. Examples are bitmap (1-bit pixels) or 6-bit RGB (222) +/// \author Lubomir Bourdev and Hailin Jin \n +/// Adobe Systems Incorporated +/// \date 2005-2007 \n Last updated on September 28, 2006 +/// +//////////////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include +#include +#include +#include +#include "gil_config.hpp" +#include "pixel.hpp" +#include "channel.hpp" + +namespace boost { namespace gil { + +///////////////////////////// +// bit_range +// +// Represents a range of bits that can span multiple consecutive bytes. The range has a size fixed at compile time, but the offset is specified at run time. +///////////////////////////// + +template +class bit_range { +public: + typedef typename mpl::if_c::type byte_t; + typedef std::ptrdiff_t difference_type; + template friend class bit_range; +private: + byte_t* _current_byte; // the starting byte of the bit range + int _bit_offset; // offset from the beginning of the current byte. 0<=_bit_offset<=7 + +public: + bit_range() : _current_byte(NULL), _bit_offset(0) {} + bit_range(byte_t* current_byte, int bit_offset) : _current_byte(current_byte), _bit_offset(bit_offset) { assert(bit_offset>=0 && bit_offset<8); } + + bit_range(const bit_range& br) : _current_byte(br._current_byte), _bit_offset(br._bit_offset) {} + template bit_range(const bit_range& br) : _current_byte(br._current_byte), _bit_offset(br._bit_offset) {} + + bit_range& operator=(const bit_range& br) { _current_byte = br._current_byte; _bit_offset=br._bit_offset; return *this; } + bool operator==(const bit_range& br) const { return _current_byte==br._current_byte && _bit_offset==br._bit_offset; } + + bit_range& operator++() { + _current_byte += (_bit_offset+RangeSize) / 8; + _bit_offset = (_bit_offset+RangeSize) % 8; + return *this; + } + bit_range& operator--() { bit_advance(-RangeSize); return *this; } + + void bit_advance(difference_type num_bits) { + int new_offset = int(_bit_offset+num_bits); + _current_byte += new_offset / 8; + _bit_offset = new_offset % 8; + if (_bit_offset<0) { + _bit_offset+=8; + --_current_byte; + } + } + difference_type bit_distance_to(const bit_range& b) const { + return (b.current_byte() - current_byte())*8 + b.bit_offset()-bit_offset(); + } + byte_t* current_byte() const { return _current_byte; } + int bit_offset() const { return _bit_offset; } +}; + + +/// \defgroup ColorBaseModelNonAlignedPixel bit_aligned_pixel_reference +/// \ingroup ColorBaseModel +/// \brief A heterogeneous color base representing pixel that may not be byte aligned, i.e. it may correspond to a bit range that does not start/end at a byte boundary. Models ColorBaseConcept. + +/** +\defgroup PixelModelNonAlignedPixel bit_aligned_pixel_reference +\ingroup PixelModel +\brief A heterogeneous pixel reference used to represent non-byte-aligned pixels. Models PixelConcept + +Example: +\code +unsigned char data=0; + +// A mutable reference to a 6-bit BGR pixel in "123" format (1 bit for red, 2 bits for green, 3 bits for blue) +typedef const bit_aligned_pixel_reference, rgb_layout_t, true> rgb123_ref_t; + +// create the pixel reference at bit offset 2 +// (i.e. red = [2], green = [3,4], blue = [5,6,7] bits) +rgb123_ref_t ref(&data, 2); +get_color(ref, red_t()) = 1; +assert(data == 0x04); +get_color(ref, green_t()) = 3; +assert(data == 0x1C); +get_color(ref, blue_t()) = 7; +assert(data == 0xFC); +\endcode +*/ +/// \ingroup ColorBaseModelNonAlignedPixel PixelModelNonAlignedPixel PixelBasedModel +/// \brief Heterogeneous pixel reference corresponding to non-byte-aligned bit range. Models ColorBaseConcept, PixelConcept, PixelBasedConcept +template + typename Layout, + bool IsMutable> +struct bit_aligned_pixel_reference { + BOOST_STATIC_CONSTANT(int, bit_size = (mpl::accumulate, mpl::plus >::type::value)); + typedef bit_range bit_range_t; + typedef typename detail::min_fast_uint::type bitfield_t; + typedef typename mpl::if_c::type data_ptr_t; + + typedef Layout layout_t; + + typedef typename packed_pixel_type::type value_type; + typedef const bit_aligned_pixel_reference reference; + typedef const bit_aligned_pixel_reference const_reference; + + BOOST_STATIC_CONSTANT(bool, is_mutable = IsMutable); + + bit_aligned_pixel_reference(){} + bit_aligned_pixel_reference(data_ptr_t data_ptr, int bit_offset) : _bit_range(data_ptr, bit_offset) {} + explicit bit_aligned_pixel_reference(const bit_range_t& bit_range) : _bit_range(bit_range) {} + template bit_aligned_pixel_reference(const bit_aligned_pixel_reference& p) : _bit_range(p._bit_range) {} + + // Grayscale references can be constructed from the channel reference + explicit bit_aligned_pixel_reference(const typename kth_element_type::type channel0) : _bit_range(static_cast(&channel0), channel0.first_bit()) { + BOOST_STATIC_ASSERT((num_channels::value==1)); + } + + // Construct from another compatible pixel type + bit_aligned_pixel_reference(const bit_aligned_pixel_reference& p) : _bit_range(p._bit_range) {} + template bit_aligned_pixel_reference(packed_pixel& p) : _bit_range(static_cast(&at_c<0>(p)), at_c<0>(p).first_bit()) { + check_compatible >(); + } + + template const bit_aligned_pixel_reference& operator=(const P& p) const { check_compatible

              (); static_copy(p,*this); return *this; } + const bit_aligned_pixel_reference& operator=(const bit_aligned_pixel_reference& p) const { static_copy(p,*this); return *this; } + + template bool operator==(const P& p) const { check_compatible

              (); return static_equal(*this,p); } + template bool operator!=(const P& p) const { return !(*this==p); } + + const bit_aligned_pixel_reference* operator->() const { return this; } + + const bit_range_t& bit_range() const { return _bit_range; } +private: + mutable bit_range_t _bit_range; + template friend struct bit_aligned_pixel_reference; + + template static void check_compatible() { gil_function_requires >(); } +}; + +///////////////////////////// +// ColorBasedConcept +///////////////////////////// + +template +struct kth_element_type, K> { +private: + typedef typename bit_aligned_pixel_reference::bitfield_t bitfield_t; +public: + typedef const packed_dynamic_channel_reference::type::value, IsMutable> type; +}; + +template +struct kth_element_reference_type, K> + : public kth_element_type, K> {}; + +template +struct kth_element_const_reference_type, K> + : public kth_element_type, K> {}; + + +namespace detail { + // returns sum of IntegralVector[0] ... IntegralVector[K-1] + template + struct sum_k : public mpl::plus, typename mpl::at_c::type > {}; + + template struct sum_k : public mpl::int_<0> {}; +} + +// at_c required by MutableColorBaseConcept +template inline +typename kth_element_reference_type,K>::type +at_c(const bit_aligned_pixel_reference& p) { + typedef bit_aligned_pixel_reference pixel_t; + typedef typename kth_element_reference_type::type channel_t; + typedef typename pixel_t::bit_range_t bit_range_t; + + bit_range_t bit_range(p.bit_range()); + bit_range.bit_advance(detail::sum_k::value); + + return channel_t(bit_range.current_byte(), bit_range.bit_offset()); +} + +///////////////////////////// +// PixelConcept +///////////////////////////// + +/// Metafunction predicate that flags bit_aligned_pixel_reference as a model of PixelConcept. Required by PixelConcept +template +struct is_pixel > : public mpl::true_{}; + +///////////////////////////// +// PixelBasedConcept +///////////////////////////// + +template +struct color_space_type > { + typedef typename L::color_space_t type; +}; + +template +struct channel_mapping_type > { + typedef typename L::channel_mapping_t type; +}; + +template +struct is_planar > : mpl::false_ {}; + +///////////////////////////// +// pixel_reference_type +///////////////////////////// + +namespace detail { + // returns a vector containing K copies of the type T + template struct k_copies; + template struct k_copies<0,T> { + typedef mpl::vector0<> type; + }; + template struct k_copies : public mpl::push_back::type, T> {}; +} + +// Constructs a homogeneous bit_aligned_pixel_reference given a channel reference +// Note: BitField must be the same type as pixel_reference_type<...>::type::bitfield_t, but it is too complicated to ensure this +template +struct pixel_reference_type, Layout, false, false> { +private: + typedef typename mpl::size::type size_t; + typedef typename detail::k_copies >::type channel_bit_sizes_t; +public: + typedef bit_aligned_pixel_reference type; +}; + +// Same but for the mutable case. We cannot combine the mutable and read-only cases because this triggers ambiguity +// Note: BitField must be the same type as pixel_reference_type<...>::type::bitfield_t, but it is too complicated to ensure this +template +struct pixel_reference_type, Layout, false, true> { +private: + typedef typename mpl::size::type size_t; + typedef typename detail::k_copies >::type channel_bit_sizes_t; +public: + typedef bit_aligned_pixel_reference type; +}; + +} } // namespace boost::gil + +namespace std { +// We are forced to define swap inside std namespace because on some platforms (Visual Studio 8) STL calls swap qualified. +// swap with 'left bias': +// - swap between proxy and anything +// - swap between value type and proxy +// - swap between proxy and proxy +// Having three overloads allows us to swap between different (but compatible) models of PixelConcept + +template inline +void swap(boost::gil::bit_aligned_pixel_reference x, R& y) { + boost::gil::swap_proxy::value_type>(x,y); +} + + +template inline +void swap(typename boost::gil::bit_aligned_pixel_reference::value_type& x, boost::gil::bit_aligned_pixel_reference y) { + boost::gil::swap_proxy::value_type>(x,y); +} + + +template inline +void swap(boost::gil::bit_aligned_pixel_reference x, boost::gil::bit_aligned_pixel_reference y) { + boost::gil::swap_proxy::value_type>(x,y); +} +} // namespace std +#endif diff --git a/include/boost/gil/channel.hpp b/include/boost/gil/channel.hpp index 50a9516b59..d7e62e0803 100644 --- a/include/boost/gil/channel.hpp +++ b/include/boost/gil/channel.hpp @@ -51,8 +51,7 @@ namespace boost { namespace gil { namespace detail { template struct channel_traits_impl; - /// \brief channel traits for custom class - /// \ingroup ChannelModel + // channel traits for custom class template struct channel_traits_impl { typedef typename T::value_type value_type; @@ -65,8 +64,7 @@ namespace detail { static value_type max_value() { return T::max_value(); } }; - /// \brief channel traits implementation for built-in scalar or floating point channel type - /// \ingroup ChannelModel + // channel traits implementation for built-in integral or floating point channel type template struct channel_traits_impl { typedef T value_type; @@ -79,8 +77,7 @@ namespace detail { static value_type max_value() { return (std::numeric_limits::max)(); } }; - /// \brief channel traits implementation for constant built-in scalar or floating point type - /// \ingroup ChannelModel + // channel traits implementation for constant built-in scalar or floating point type template struct channel_traits_impl : public channel_traits_impl { typedef const T& reference; @@ -89,15 +86,31 @@ namespace detail { }; } +/** +\ingroup ChannelModel +\brief Traits for channels. Contains the following members: +\code +template +struct channel_traits { + typedef ... value_type; + typedef ... reference; + typedef ... pointer; + typedef ... const_reference; + typedef ... const_pointer; + + static const bool is_mutable; + static value_type min_value(); + static value_type max_value(); +}; +\endcode +*/ template struct channel_traits : public detail::channel_traits_impl::value> {}; -/// \ingroup ChannelModel -/// \brief Channel traits for C++ reference type - remove the reference +// Channel traits for C++ reference type - remove the reference template struct channel_traits< T&> : public channel_traits {}; -/// \ingroup ChannelModel -/// \brief Channel traits for constant C++ reference type +// Channel traits for constant C++ reference type template struct channel_traits : public channel_traits { typedef typename channel_traits::const_reference reference; typedef typename channel_traits::const_pointer pointer; @@ -110,9 +123,25 @@ template struct channel_traits : public channel_traits //// /////////////////////////////////////////// -/// \defgroup ScopedChannelValue scoped_channel_value -/// \ingroup ChannelModel -/// \brief A channel adaptor that modifies the range of the source channel. Models: ChannelValueConcept +/** +\defgroup ScopedChannelValue scoped_channel_value +\ingroup ChannelModel +\brief A channel adaptor that modifies the range of the source channel. Models: ChannelValueConcept + +Example: +\code +// Create a double channel with range [-0.5 .. 0.5] +struct double_minus_half { static double apply() { return -0.5; } }; +struct double_plus_half { static double apply() { return 0.5; } }; +typedef scoped_channel_value bits64custom_t; + +// channel_convert its maximum should map to the maximum +bits64custom_t x = channel_traits::max_value(); +assert(x == 0.5); +bits16 y = channel_convert(x); +assert(y == 65535); +\endcode +*/ /// \ingroup ScopedChannelValue /// \brief A channel adaptor that modifies the range of the source channel. Models: ChannelValueConcept @@ -167,14 +196,33 @@ struct float_one { static float apply() { return 1.0f; } }; namespace detail { // returns the smallest fast unsigned integral type that has at least NumBits bits template - struct min_fast_uint : public mpl::if_c< (NumBits<8), + struct min_fast_uint : public mpl::if_c< (NumBits<=8), uint_least8_t, - typename mpl::if_c< (NumBits<16), uint_least16_t, - uint_least32_t>::type > {}; + typename mpl::if_c< (NumBits<=16), + uint_least16_t, + typename mpl::if_c< (NumBits<=32), + uint_least32_t, + uintmax_t + >::type + >::type + > {}; } -/// \defgroup PackedChannelValueModel packed_channel_value -/// \ingroup ChannelModel -/// \brief Represents the value of an unsigned integral channel operating over a bit range. Models: ChannelValueConcept + +/** +\defgroup PackedChannelValueModel packed_channel_value +\ingroup ChannelModel +\brief Represents the value of an unsigned integral channel operating over a bit range. Models: ChannelValueConcept +Example: +\code +// A 4-bit unsigned integral channel. +typedef packed_channel_value<4> bits4; + +assert(channel_traits::min_value()==0); +assert(channel_traits::max_value()==15); +assert(sizeof(bits4)==1); +BOOST_STATIC_ASSERT((boost::is_integral::value)); +\endcode +*/ /// \ingroup PackedChannelValueModel /// \brief The value of a subbyte channel. Models: ChannelValueConcept @@ -208,24 +256,25 @@ namespace detail { template class packed_channel_reference_base { protected: - typedef typename mpl::if_c::type data_ref_t; - data_ref_t _data; - - static const BitField max_val = (1<::type data_ptr_t; public: + data_ptr_t _data_ptr; // void* pointer to the first byte of the bit range + typedef packed_channel_value value_type; typedef const Derived reference; typedef value_type* pointer; typedef const value_type* const_pointer; + BOOST_STATIC_CONSTANT(int, num_bits=NumBits); BOOST_STATIC_CONSTANT(bool, is_mutable=Mutable); static value_type min_value() { return channel_traits::min_value(); } static value_type max_value() { return channel_traits::max_value(); } + typedef BitField bitfield_t; typedef typename value_type::integer_t integer_t; - packed_channel_reference_base(data_ref_t data) : _data(data) {} - packed_channel_reference_base(const packed_channel_reference_base& ref) : _data(ref._data) {} + packed_channel_reference_base(data_ptr_t data_ptr) : _data_ptr(data_ptr) {} + packed_channel_reference_base(const packed_channel_reference_base& ref) : _data_ptr(ref._data_ptr) {} const Derived& operator=(integer_t v) const { set(v); return derived(); } const Derived& operator++() const { set(get()+1); return derived(); } @@ -240,7 +289,11 @@ class packed_channel_reference_base { template const Derived& operator/=(Scalar2 v) const { set(get()/v); return derived(); } operator integer_t() const { return get(); } - BitField* operator &() const {return &_data;} + data_ptr_t operator &() const {return _data_ptr;} +protected: + static const integer_t max_val = (1<(_data_ptr); } + bitfield_t& data() const { return *static_cast< bitfield_t*>(_data_ptr); } private: void set(integer_t value) const { // can this be done faster?? const integer_t num_values = max_val+1; @@ -251,34 +304,54 @@ class packed_channel_reference_base { }; } // namespace detail -/// \defgroup PackedChannelReferenceModel packed_channel_reference -/// \ingroup ChannelModel -/// \brief Represents a reference proxy to a channel operating over a bit range whose offset is fixed at compile time. Models ChannelConcept +/** +\defgroup PackedChannelReferenceModel packed_channel_reference +\ingroup ChannelModel +\brief Represents a reference proxy to a channel operating over a bit range whose offset is fixed at compile time. Models ChannelConcept +Example: +\code +// Reference to a 2-bit channel starting at bit 1 (i.e. the second bit) +typedef const packed_channel_reference bits2_1_ref_t; + +uint16_t data=0; +bits2_1_ref_t channel_ref(&data); +channel_ref = channel_traits::max_value(); // == 3 +assert(data == 6); // == 3<<1 == 6 +\endcode +*/ -template // true if the reference is mutable class packed_channel_reference; +template // true if the reference is mutable +class packed_dynamic_channel_reference; + /// \ingroup PackedChannelReferenceModel /// \brief A constant subbyte channel reference whose bit offset is fixed at compile time. Models ChannelConcept template class packed_channel_reference : public detail::packed_channel_reference_base,BitField,NumBits,false> { typedef detail::packed_channel_reference_base,BitField,NumBits,false> parent_t; - static const BitField channel_mask = parent_t::max_val< mutable_reference; friend class packed_channel_reference; + + static const BitField channel_mask = parent_t::max_val< const_reference; + typedef const packed_channel_reference mutable_reference; + typedef typename parent_t::integer_t integer_t; + + explicit packed_channel_reference(const void* data_ptr) : parent_t(data_ptr) {} + packed_channel_reference(const packed_channel_reference& ref) : parent_t(ref._data_ptr) {} + packed_channel_reference(const mutable_reference& ref) : parent_t(ref._data_ptr) {} - explicit packed_channel_reference(const BitField& data) : parent_t(data) {} - packed_channel_reference(const packed_channel_reference& ref) : parent_t(ref._data) {} - packed_channel_reference(const mutable_reference& ref) : parent_t(ref._data) {} + unsigned first_bit() const { return FirstBit; } - integer_t get() const { return (this->_data&(parent_t::max_val<> FirstBit; } + integer_t get() const { return integer_t((this->const_data()&channel_mask) >> FirstBit); } }; /// \ingroup PackedChannelReferenceModel @@ -287,24 +360,30 @@ template class packed_channel_reference : public detail::packed_channel_reference_base,BitField,NumBits,true> { typedef detail::packed_channel_reference_base,BitField,NumBits,true> parent_t; - static const BitField channel_mask = parent_t::max_val<; + + static const BitField channel_mask = parent_t::max_val< const_reference; + typedef const packed_channel_reference const_reference; + typedef const packed_channel_reference mutable_reference; + typedef typename parent_t::integer_t integer_t; - explicit packed_channel_reference(BitField& data) : parent_t(data) {} - packed_channel_reference(const packed_channel_reference& ref) : parent_t(ref._data) {} + explicit packed_channel_reference(void* data_ptr) : parent_t(data_ptr) {} + packed_channel_reference(const packed_channel_reference& ref) : parent_t(ref._data_ptr) {} const packed_channel_reference& operator=(integer_t value) const { assert(value<=parent_t::max_val); set_unsafe(value); return *this; } - const packed_channel_reference& operator=(const packed_channel_reference& ref) const { set_from_reference(ref._data); return *this; } - const packed_channel_reference& operator=(const const_reference& ref) const { set_from_reference(ref._data); return *this; } + const packed_channel_reference& operator=(const mutable_reference& ref) const { set_from_reference(ref.data()); return *this; } + const packed_channel_reference& operator=(const const_reference& ref) const { set_from_reference(ref.const_data()); return *this; } + + template + const packed_channel_reference& operator=(const packed_dynamic_channel_reference& ref) const { set_unsafe(ref.get()); return *this; } - integer_t get() const { return (this->_data&channel_mask) >> FirstBit; } - void set_unsafe(integer_t value) const { this->_data = (this->_data & ~channel_mask) | (value<const_data()&channel_mask) >> FirstBit); } + void set_unsafe(integer_t value) const { this->data() = (this->const_data() & ~channel_mask) | (value<_data = (this->_data & ~channel_mask) | (data & channel_mask); } + void set_from_reference(const BitField& other_bits) const { this->data() = (this->const_data() & ~channel_mask) | (other_bits & channel_mask); } }; } } // namespace boost::gil @@ -342,16 +421,22 @@ void swap(boost::gil::packed_channel_reference x, boost::gil::packed namespace boost { namespace gil { - - -/// \defgroup PackedChannelDynamicReferenceModel packed_dynamic_channel_reference -/// \ingroup ChannelModel -/// \brief Represents a reference proxy to a channel operating over a bit range whose offset is specified at run time. Models ChannelConcept - -template // true if the reference is mutable -class packed_dynamic_channel_reference; +/** +\defgroup PackedChannelDynamicReferenceModel packed_dynamic_channel_reference +\ingroup ChannelModel +\brief Represents a reference proxy to a channel operating over a bit range whose offset is specified at run time. Models ChannelConcept + +Example: +\code +// Reference to a 2-bit channel whose offset is specified at construction time +typedef const packed_dynamic_channel_reference bits2_dynamic_ref_t; + +uint16_t data=0; +bits2_dynamic_ref_t channel_ref(&data,1); +channel_ref = channel_traits::max_value(); // == 3 +assert(data == 6); // == (3<<1) == 6 +\endcode +*/ /// \brief Models a constant subbyte channel reference whose bit offset is a runtime parameter. Models ChannelConcept /// Same as packed_channel_reference, except that the offset is a runtime parameter @@ -360,20 +445,25 @@ template class packed_dynamic_channel_reference : public detail::packed_channel_reference_base,BitField,NumBits,false> { typedef detail::packed_channel_reference_base,BitField,NumBits,false> parent_t; - int _first_bit; + friend class packed_dynamic_channel_reference; - typedef packed_dynamic_channel_reference mutable_reference; - typedef typename parent_t::integer_t integer_t; + unsigned _first_bit; // 0..7 + + void operator=(const packed_dynamic_channel_reference&); public: - typedef packed_dynamic_channel_reference const_reference; + typedef const packed_dynamic_channel_reference const_reference; + typedef const packed_dynamic_channel_reference mutable_reference; + typedef typename parent_t::integer_t integer_t; + + packed_dynamic_channel_reference(const void* data_ptr, unsigned first_bit) : parent_t(data_ptr), _first_bit(first_bit) {} + packed_dynamic_channel_reference(const const_reference& ref) : parent_t(ref._data_ptr), _first_bit(ref._first_bit) {} + packed_dynamic_channel_reference(const mutable_reference& ref) : parent_t(ref._data_ptr), _first_bit(ref._first_bit) {} - packed_dynamic_channel_reference(typename parent_t::data_ref_t data, int first_bit) : parent_t(data), _first_bit(first_bit) {} - packed_dynamic_channel_reference(const packed_dynamic_channel_reference& ref) : parent_t(ref._data), _first_bit(ref._first_bit) {} - packed_dynamic_channel_reference(const mutable_reference& ref) : parent_t(ref._data), _first_bit(ref._first_bit) {} + unsigned first_bit() const { return _first_bit; } integer_t get() const { const BitField channel_mask = parent_t::max_val<<_first_bit; - return (this->_data&channel_mask) >> _first_bit; + return (this->const_data()&channel_mask) >> _first_bit; } }; @@ -384,26 +474,35 @@ template class packed_dynamic_channel_reference : public detail::packed_channel_reference_base,BitField,NumBits,true> { typedef detail::packed_channel_reference_base,BitField,NumBits,true> parent_t; - int _first_bit; + friend class packed_dynamic_channel_reference; + + unsigned _first_bit; - typedef typename parent_t::integer_t integer_t; public: - typedef packed_dynamic_channel_reference const_reference; + typedef const packed_dynamic_channel_reference const_reference; + typedef const packed_dynamic_channel_reference mutable_reference; + typedef typename parent_t::integer_t integer_t; - packed_dynamic_channel_reference(typename parent_t::data_ref_t data, int first_bit) : parent_t(data), _first_bit(first_bit) {} - packed_dynamic_channel_reference(const packed_dynamic_channel_reference& ref) : parent_t(ref._data), _first_bit(ref._first_bit) {} + packed_dynamic_channel_reference(void* data_ptr, unsigned first_bit) : parent_t((((char*)data_ptr)+first_bit/8)), _first_bit(first_bit%8) {} + packed_dynamic_channel_reference(const packed_dynamic_channel_reference& ref) : parent_t(ref._data_ptr), _first_bit(ref._first_bit) {} const packed_dynamic_channel_reference& operator=(integer_t value) const { assert(value<=parent_t::max_val); set_unsafe(value); return *this; } - const packed_dynamic_channel_reference& operator=(const packed_dynamic_channel_reference& ref) const { set_unsafe(ref.get()); return *this; } - const packed_dynamic_channel_reference& operator=(const const_reference& ref) const { set_unsafe(ref.get()); return *this; } + const packed_dynamic_channel_reference& operator=(const mutable_reference& ref) const { set_unsafe(ref.get()); return *this; } + const packed_dynamic_channel_reference& operator=(const const_reference& ref) const { set_unsafe(ref.get()); return *this; } + + template + const packed_dynamic_channel_reference& operator=(const packed_channel_reference& ref) const + { set_unsafe(ref.get()); return *this; } + + unsigned first_bit() const { return _first_bit; } integer_t get() const { const BitField channel_mask = parent_t::max_val<<_first_bit; - return (this->_data&channel_mask) >> _first_bit; + return (this->const_data()&channel_mask) >> _first_bit; } void set_unsafe(integer_t value) const { const BitField channel_mask = parent_t::max_val<<_first_bit; - this->_data = (this->_data & ~channel_mask) | value<<_first_bit; + this->data() = (this->const_data() & ~channel_mask) | value<<_first_bit; } }; } } // namespace boost::gil @@ -449,42 +548,42 @@ namespace boost { namespace gil { /// \defgroup bits8 bits8 /// \ingroup ChannelModel -/// \brief 8-bit unsigned integral channel type. Models ChannelValueConcept +/// \brief 8-bit unsigned integral channel type (typedef from uint8_t). Models ChannelValueConcept /// \ingroup bits8 typedef uint8_t bits8; /// \defgroup bits16 bits16 /// \ingroup ChannelModel -/// \brief 16-bit unsigned integral channel type. Models ChannelValueConcept +/// \brief 16-bit unsigned integral channel type (typedef from uint16_t). Models ChannelValueConcept /// \ingroup bits16 typedef uint16_t bits16; /// \defgroup bits32 bits32 /// \ingroup ChannelModel -/// \brief 32-bit unsigned integral channel type. Models ChannelValueConcept +/// \brief 32-bit unsigned integral channel type (typedef from uint32_t). Models ChannelValueConcept /// \ingroup bits32 typedef uint32_t bits32; /// \defgroup bits8s bits8s /// \ingroup ChannelModel -/// \brief 8-bit signed integral channel type. Models ChannelValueConcept +/// \brief 8-bit signed integral channel type (typedef from int8_t). Models ChannelValueConcept /// \ingroup bits8s typedef int8_t bits8s; /// \defgroup bits16s bits16s /// \ingroup ChannelModel -/// \brief 16-bit signed integral channel type. Models ChannelValueConcept +/// \brief 16-bit signed integral channel type (typedef from int16_t). Models ChannelValueConcept /// \ingroup bits16s typedef int16_t bits16s; /// \defgroup bits32s bits32s /// \ingroup ChannelModel -/// \brief 32-bit signed integral channel type. Models ChannelValueConcept +/// \brief 32-bit signed integral channel type (typedef from int32_t). Models ChannelValueConcept /// \ingroup bits32s typedef int32_t bits32s; @@ -498,5 +597,20 @@ typedef scoped_channel_value bits32f; } } // namespace boost::gil +namespace boost { + +template +struct is_integral > : public mpl::true_ {}; + +template +struct is_integral > : public mpl::true_ {}; + +template +struct is_integral > : public mpl::true_ {}; + +template +struct is_integral > : public is_integral {}; + +} #endif diff --git a/include/boost/gil/channel_algorithm.hpp b/include/boost/gil/channel_algorithm.hpp index 6f7562bb3f..44a328071a 100644 --- a/include/boost/gil/channel_algorithm.hpp +++ b/include/boost/gil/channel_algorithm.hpp @@ -25,9 +25,59 @@ #include "gil_config.hpp" #include "channel.hpp" +#include +#include +#include +#include namespace boost { namespace gil { +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4309) // disable truncation of constant value warning (using -1 to get the max value of an integral) +#endif + +namespace detail { + +// some forward declarations +template struct channel_converter_unsigned_impl; +template struct channel_converter_unsigned_integral; +template struct channel_converter_unsigned_integral_impl; +template struct channel_converter_unsigned_integral_nondivisible; + +////////////////////////////////////// +//// unsigned_integral_max_value - given an unsigned integral channel type, returns its maximum value as an MPL integral constant +////////////////////////////////////// + + +template +struct unsigned_integral_max_value : public mpl::integral_c {}; + +template <> +struct unsigned_integral_max_value : public mpl::integral_c {}; +template <> +struct unsigned_integral_max_value : public mpl::integral_c {}; +template <> +struct unsigned_integral_max_value : public mpl::integral_c {}; + + +template +struct unsigned_integral_max_value > + : public mpl::integral_c::integer_t, (1< {}; + +////////////////////////////////////// +//// unsigned_integral_num_bits - given an unsigned integral channel type, returns the minimum number of bits needed to represent it +////////////////////////////////////// + +template +struct unsigned_integral_num_bits : public mpl::int_ {}; + +template +struct unsigned_integral_num_bits > + : public mpl::int_ {}; + +} // namespace detail + /** \defgroup ChannelConvertAlgorithm channel_convert \brief Converting from one channel type to another @@ -39,8 +89,19 @@ One implication of this is that the value 0 of signed channels may not be preser When creating new channel models, it is often a good idea to provide specializations for the channel conversion algorithms, for example, for performance optimizations. If the new model is an integral type that can be signed, it is easier to define the conversion -only for the unsigned type (\p channel_converter_unsigned) and provide specializations of \p channel_convert_to_unsigned and \p channel_convert_to_signed -to convert between the signed and unsigned type. +only for the unsigned type (\p channel_converter_unsigned) and provide specializations of \p detail::channel_convert_to_unsigned +and \p detail::channel_convert_from_unsigned to convert between the signed and unsigned type. + +Example: +\code +// bits32f is a floating point channel with range [0.0f ... 1.0f] +bits32f src_channel = channel_traits::max_value(); +assert(src_channel == 1); + +// bits8 is 8-bit unsigned integral channel (typedef-ed from unsigned char) +bits8 dst_channel = channel_convert(src_channel); +assert(dst_channel == 255); // max value goes to max value +\endcode */ /** @@ -50,11 +111,31 @@ to convert between the signed and unsigned type. @{ */ -/// \brief This is the default implementation. Performance specializatons are provided +////////////////////////////////////// +//// channel_converter_unsigned +////////////////////////////////////// + template // Model ChannelValueConcept -struct channel_converter_unsigned : public std::unary_function { +struct channel_converter_unsigned + : public detail::channel_converter_unsigned_impl::value,is_integral::value> {}; + + +/// \brief Converting a channel to itself - identity operation +template struct channel_converter_unsigned : public detail::identity {}; + + +namespace detail { + +////////////////////////////////////// +//// channel_converter_unsigned_impl +////////////////////////////////////// + +/// \brief This is the default implementation. Performance specializatons are provided +template +struct channel_converter_unsigned_impl : public std::unary_function { DstChannelV operator()(SrcChannelV src) const { - return DstChannelV(src / channel_range() * channel_range()); + return DstChannelV(channel_traits::min_value() + + (src - channel_traits::min_value()) / channel_range() * channel_range()); } private: template @@ -63,54 +144,139 @@ struct channel_converter_unsigned : public std::unary_function struct channel_converter_unsigned : public detail::identity {}; +// When both the source and the destination are integral channels, perform a faster conversion +template +struct channel_converter_unsigned_impl + : public channel_converter_unsigned_integral,unsigned_integral_max_value >::value > {}; -/// \brief 8 bit <-> 16 bit channel conversion -template <> struct channel_converter_unsigned : public std::unary_function { - bits8 operator()(bits16 x) const { return static_cast(x/257); } -}; -/// \brief 8 bit <-> 16 bit channel conversion -template <> struct channel_converter_unsigned : public std::unary_function { - bits16 operator()(bits8 x) const { return static_cast(x*257); } + +////////////////////////////////////// +//// channel_converter_unsigned_integral +////////////////////////////////////// + +template +struct channel_converter_unsigned_integral + : public channel_converter_unsigned_integral_impl::value % unsigned_integral_max_value::value) > {}; + +template +struct channel_converter_unsigned_integral + : public channel_converter_unsigned_integral_impl::value % unsigned_integral_max_value::value) > {}; + + +////////////////////////////////////// +//// channel_converter_unsigned_integral_impl +////////////////////////////////////// + +// Both source and destination are unsigned integral channels, +// the src max value is less than the dst max value, +// and the dst max value is divisible by the src max value +template +struct channel_converter_unsigned_integral_impl { + DstChannelV operator()(SrcChannelV src) const { + typedef typename unsigned_integral_max_value::value_type integer_t; + static const integer_t mul = unsigned_integral_max_value::value / unsigned_integral_max_value::value; + return DstChannelV(src * mul); + } }; -/// \brief 8 bit <-> 32 bit channel conversion -template <> struct channel_converter_unsigned : public std::unary_function { - bits8 operator()(bits32 x) const { return static_cast(x/16843009); } +// Both source and destination are unsigned integral channels, +// the dst max value is less than (or equal to) the src max value, +// and the src max value is divisible by the dst max value +template +struct channel_converter_unsigned_integral_impl { + DstChannelV operator()(SrcChannelV src) const { + typedef typename unsigned_integral_max_value::value_type integer_t; + static const integer_t div = unsigned_integral_max_value::value / unsigned_integral_max_value::value; + static const integer_t div2 = div/2; + return DstChannelV((src + div2) / div); + } }; -/// \brief 8 bit <-> 32 bit channel conversion -template <> struct channel_converter_unsigned : public std::unary_function { - bits32 operator()(bits8 x) const { return static_cast(x*16843009); } + +// Prevent overflow for the largest integral type +template +struct channel_converter_unsigned_integral_impl { + DstChannelV operator()(uintmax_t src) const { + static const uintmax_t div = unsigned_integral_max_value::value / unsigned_integral_max_value::value; + static const uintmax_t div2 = div/2; + if (src > unsigned_integral_max_value::value - div2) + return unsigned_integral_max_value::value; + return DstChannelV((src + div2) / div); + } }; -/// \brief 8 bit <-> float0..1 channel conversion -template <> struct channel_converter_unsigned : public std::unary_function { - bits8 operator()(bits32f x) const { return static_cast(x*255+0.5f); } +// Both source and destination are unsigned integral channels, +// and the dst max value is not divisible by the src max value +// See if you can represent the expression (src * dst_max) / src_max in integral form +template +struct channel_converter_unsigned_integral_impl + : public channel_converter_unsigned_integral_nondivisible,unsigned_integral_num_bits >, + unsigned_integral_num_bits + >::value> {}; + + +// Both source and destination are unsigned integral channels, +// the src max value is less than the dst max value, +// and the dst max value is not divisible by the src max value +// The expression (src * dst_max) / src_max fits in an integer +template +struct channel_converter_unsigned_integral_nondivisible { + DstChannelV operator()(SrcChannelV src) const { + typedef typename detail::min_fast_uint::value+unsigned_integral_num_bits::value>::type integer_t; + return DstChannelV(integer_t(src * unsigned_integral_max_value::value) / unsigned_integral_max_value::value); + } }; -/// \brief 8 bit <-> float0..1 channel conversion -template <> struct channel_converter_unsigned : public std::unary_function { - bits32f operator()(bits8 x) const { return static_cast(x/255.0f); } + +// Both source and destination are unsigned integral channels, +// the src max value is less than the dst max value, +// and the dst max value is not divisible by the src max value +// The expression (src * dst_max) / src_max cannot fit in an integer (overflows). Use a double +template +struct channel_converter_unsigned_integral_nondivisible { + DstChannelV operator()(SrcChannelV src) const { + static const double mul = unsigned_integral_max_value::value / double(unsigned_integral_max_value::value); + return DstChannelV(src * mul); + } }; -/// \brief 16 bit <-> float0..1 channel conversion -template <> struct channel_converter_unsigned : public std::unary_function { - bits16 operator()(bits32f x) const { return static_cast(x*65535+0.5f); } + +// Both source and destination are unsigned integral channels, +// the dst max value is less than (or equal to) the src max value, +// and the src max value is not divisible by the dst max value +template +struct channel_converter_unsigned_integral_nondivisible { + DstChannelV operator()(SrcChannelV src) const { + typedef typename unsigned_integral_max_value::value_type integer_t; + + static const double div = unsigned_integral_max_value::value / double(unsigned_integral_max_value::value); + static const integer_t div2 = integer_t(div/2); + return DstChannelV((src + div2) / div); + } }; -/// \brief 16 bit <-> float0..1 channel conversion -template <> struct channel_converter_unsigned : public std::unary_function { - bits32f operator()(bits16 x) const { return static_cast(x/65535.0f); } + +} // namespace detail + +///////////////////////////////////////////////////// +/// bits32f conversion +///////////////////////////////////////////////////// + +template struct channel_converter_unsigned : public std::unary_function { + DstChannelV operator()(bits32f x) const { return DstChannelV(x*channel_traits::max_value()+0.5f); } }; -/// \brief 16 bit <-> 32 bit channel conversion -template <> struct channel_converter_unsigned : public std::unary_function { - bits16 operator()(bits32 x) const { return static_cast(x/65537); } +template struct channel_converter_unsigned : public std::unary_function { + bits32f operator()(SrcChannelV x) const { return bits32f(x/float(channel_traits::max_value())); } }; -/// \brief 16 bit <-> 32 bit channel conversion -template <> struct channel_converter_unsigned : public std::unary_function { - bits32 operator()(bits16 x) const { return static_cast(x*65537); } + +template <> struct channel_converter_unsigned : public std::unary_function { + bits32f operator()(bits32f x) const { return x; } }; + /// \brief 32 bit <-> float channel conversion template <> struct channel_converter_unsigned : public std::unary_function { bits32f operator()(bits32 x) const { @@ -127,85 +293,66 @@ template <> struct channel_converter_unsigned : public std::unar return bits32(x * channel_traits::max_value() + 0.5f); } }; -/// @} -/** -\defgroup ChannelConvertToUnsignedAlgorithm channel_convert_to_unsigned -\brief Convert signed channel to unsigned. By default it is an identity operation. Specializations are provided for signed integral channels -\ingroup ChannelConvertAlgorithm - -@{ -*/ +/// @} -/// \brief Converting from signed to unsigned integral channel. -/// It is both a unary function, and a metafunction (thus requires the 'type' nested typedef, which equals result_type) +namespace detail { +// Converting from signed to unsigned integral channel. +// It is both a unary function, and a metafunction (thus requires the 'type' nested typedef, which equals result_type) template // Model ChannelValueConcept struct channel_convert_to_unsigned : public detail::identity { typedef ChannelValue type; }; -/// \brief Converting from 8-bit signed to 8-bit unsigned integral channel template <> struct channel_convert_to_unsigned : public std::unary_function { typedef bits8 type; type operator()(bits8s val) const { return val+128; } }; -/// \brief Converting from 16-bit signed to 16-bit unsigned integral channel template <> struct channel_convert_to_unsigned : public std::unary_function { typedef bits16 type; type operator()(bits16s val) const { return val+32768; } }; -/// \brief Converting from 32-bit signed to 32-bit unsigned integral channel template <> struct channel_convert_to_unsigned : public std::unary_function { typedef bits32 type; type operator()(bits32s x) const { return static_cast(x+(1<<31)); } }; -/// @} -/** -\defgroup ChannelConvertToSignedAlgorithm channel_convert_to_signed -\brief Convert unsigned channel to signed. By default it is an identity operation. Specializations are provided for signed integral channels -\ingroup ChannelConvertAlgorithm - -@{ -*/ -/// \brief Converting from unsigned to signed integral channel -/// It is both a unary function, and a metafunction (thus requires the 'type' nested typedef, which equals result_type) +// Converting from unsigned to signed integral channel +// It is both a unary function, and a metafunction (thus requires the 'type' nested typedef, which equals result_type) template // Model ChannelValueConcept -struct channel_convert_to_signed : public detail::identity { +struct channel_convert_from_unsigned : public detail::identity { typedef ChannelValue type; }; -/// \brief Converting from 8-bit unsigned to 8-bit signed integral channel -template <> struct channel_convert_to_signed : public std::unary_function { +template <> struct channel_convert_from_unsigned : public std::unary_function { typedef bits8s type; type operator()(bits8 val) const { return val-128; } }; -/// \brief Converting from 16-bit unsigned to 16-bit signed integral channel -template <> struct channel_convert_to_signed : public std::unary_function { +template <> struct channel_convert_from_unsigned : public std::unary_function { typedef bits16s type; type operator()(bits16 val) const { return val-32768; } }; -/// \brief Converting from 32-bit unsigned to 32-bit signed integral channel -template <> struct channel_convert_to_signed : public std::unary_function { +template <> struct channel_convert_from_unsigned : public std::unary_function { typedef bits32s type; type operator()(bits32 x) const { return static_cast(x-(1<<31)); } }; -/// @} + +} // namespace detail /// \ingroup ChannelConvertAlgorithm /// \brief A unary function object converting between channel types template // Model ChannelValueConcept struct channel_converter : public std::unary_function { DstChannelV operator()(SrcChannelV src) const { - typedef channel_convert_to_unsigned to_unsigned; - typedef channel_convert_to_signed to_signed; - typedef channel_converter_unsigned converter_unsigned; - return to_signed()(converter_unsigned()(to_unsigned()(src))); + typedef detail::channel_convert_to_unsigned to_unsigned; + typedef detail::channel_convert_from_unsigned from_unsigned; + typedef channel_converter_unsigned converter_unsigned; + return from_unsigned()(converter_unsigned()(to_unsigned()(src))); } }; @@ -236,9 +383,19 @@ namespace detail { inline uint32_t div32768(uint32_t in) { return (in+16384)>>15; } } -/// \defgroup ChannelMultiplyAlgorithm channel_multiply -/// \ingroup ChannelAlgorithm -/// \brief Multiplying unsigned channel values of the same type. Performs scaled multiplication result = a * b / max_value +/** +\defgroup ChannelMultiplyAlgorithm channel_multiply +\ingroup ChannelAlgorithm +\brief Multiplying unsigned channel values of the same type. Performs scaled multiplication result = a * b / max_value + +Example: +\code +bits8 x=128; +bits8 y=128; +bits8 mul = channel_multiply(x,y); +assert(mul == 64); // 64 = 128 * 128 / 255 +\endcode +*/ /// @{ /// \brief This is the default implementation. Performance specializatons are provided @@ -268,10 +425,10 @@ template<> struct channel_multiplier_unsigned : public std::binary_func template struct channel_multiplier : public std::binary_function { ChannelValue operator()(ChannelValue a, ChannelValue b) const { - typedef channel_convert_to_unsigned to_unsigned; - typedef channel_convert_to_signed to_signed; + typedef detail::channel_convert_to_unsigned to_unsigned; + typedef detail::channel_convert_from_unsigned from_unsigned; typedef channel_multiplier_unsigned multiplier_unsigned; - return to_signed()(multiplier_unsigned()(to_unsigned()(a), to_unsigned()(b))); + return from_unsigned()(multiplier_unsigned()(to_unsigned()(a), to_unsigned()(b))); } }; @@ -282,9 +439,19 @@ inline typename channel_traits::value_type channel_multiply(Channel a, } /// @} -/// \defgroup ChannelInvertAlgorithm channel_invert -/// \ingroup ChannelAlgorithm -/// \brief Returns the inverse of a channel. result = max_value - x + min_value +/** +\defgroup ChannelInvertAlgorithm channel_invert +\ingroup ChannelAlgorithm +\brief Returns the inverse of a channel. result = max_value - x + min_value + +Example: +\code +// bits8 == uint8_t == unsigned char +bits8 x=255; +bits8 inv = channel_invert(x); +assert(inv == 0); +\endcode +*/ /// \brief Default implementation. Provide overloads for performance /// \ingroup ChannelInvertAlgorithm channel_invert @@ -293,6 +460,9 @@ inline typename channel_traits::value_type channel_invert(Channel x) { return channel_traits::max_value()-x + channel_traits::min_value(); } +#ifdef _MSC_VER +#pragma warning(pop) +#endif } } // namespace boost::gil diff --git a/include/boost/gil/color_base.hpp b/include/boost/gil/color_base.hpp index f5ff1481db..97764ea436 100644 --- a/include/boost/gil/color_base.hpp +++ b/include/boost/gil/color_base.hpp @@ -44,6 +44,12 @@ typename kth_semantic_element_const_reference_type::type semantic_a // Forward declare element_reference_type template struct element_reference_type; template struct element_const_reference_type; +template struct kth_element_type; +template struct kth_element_type : public kth_element_type {}; +template struct kth_element_reference_type; +template struct kth_element_reference_type : public kth_element_reference_type {}; +template struct kth_element_const_reference_type; +template struct kth_element_const_reference_type : public kth_element_const_reference_type {}; namespace detail { @@ -59,25 +65,14 @@ struct mapping_transform /// If the element type models Regular, this class models HomogeneousColorBaseValueConcept. -template -struct homogeneous_color_base_impl { - typedef Layout layout_t; - - template struct kth_element_type { typedef Element type; }; - template struct kth_element_reference_type : public add_reference {}; - template struct kth_element_const_reference_type : public add_reference::type> {}; -}; - - -template struct homogeneous_color_base; - /// \brief A homogeneous color base holding one color element. Models HomogeneousColorBaseConcept or HomogeneousColorBaseValueConcept /// \ingroup ColorBaseModelHomogeneous template -struct homogeneous_color_base : public homogeneous_color_base_impl { +struct homogeneous_color_base { private: Element _v0; public: + typedef Layout layout_t; typename element_reference_type::type at(mpl::int_<0>) { return _v0; } typename element_const_reference_type::type at(mpl::int_<0>) const { return _v0; } @@ -94,10 +89,11 @@ struct homogeneous_color_base : public homogeneous_color_base_ /// \brief A homogeneous color base holding two color elements. Models HomogeneousColorBaseConcept or HomogeneousColorBaseValueConcept /// \ingroup ColorBaseModelHomogeneous template -struct homogeneous_color_base : public homogeneous_color_base_impl { +struct homogeneous_color_base { private: Element _v0, _v1; public: + typedef Layout layout_t; typename element_reference_type::type at(mpl::int_<0>) { return _v0; } typename element_const_reference_type::type at(mpl::int_<0>) const { return _v0; } typename element_reference_type::type at(mpl::int_<1>) { return _v1; } @@ -126,8 +122,8 @@ struct homogeneous_color_base : public homogeneous_color_base_ // Support for planar_pixel_reference offset constructor template homogeneous_color_base(const Ptr& ptr, std::ptrdiff_t diff) - : _v0(*byte_advanced(semantic_at_c<0>(ptr),diff)), - _v1(*byte_advanced(semantic_at_c<1>(ptr),diff)) {} + : _v0(*memunit_advanced(semantic_at_c<0>(ptr),diff)), + _v1(*memunit_advanced(semantic_at_c<1>(ptr),diff)) {} // Support for planar_pixel_reference operator[] Element at_c_dynamic(size_t i) const { @@ -139,10 +135,11 @@ struct homogeneous_color_base : public homogeneous_color_base_ /// \brief A homogeneous color base holding three color elements. Models HomogeneousColorBaseConcept or HomogeneousColorBaseValueConcept /// \ingroup ColorBaseModelHomogeneous template -struct homogeneous_color_base : public homogeneous_color_base_impl { +struct homogeneous_color_base { private: Element _v0, _v1, _v2; public: + typedef Layout layout_t; typename element_reference_type::type at(mpl::int_<0>) { return _v0; } typename element_const_reference_type::type at(mpl::int_<0>) const { return _v0; } typename element_reference_type::type at(mpl::int_<1>) { return _v1; } @@ -177,9 +174,9 @@ struct homogeneous_color_base : public homogeneous_color_base_ // Support for planar_pixel_reference offset constructor template homogeneous_color_base(const Ptr& ptr, std::ptrdiff_t diff) - : _v0(*byte_advanced(semantic_at_c<0>(ptr),diff)), - _v1(*byte_advanced(semantic_at_c<1>(ptr),diff)), - _v2(*byte_advanced(semantic_at_c<2>(ptr),diff)) {} + : _v0(*memunit_advanced(semantic_at_c<0>(ptr),diff)), + _v1(*memunit_advanced(semantic_at_c<1>(ptr),diff)), + _v2(*memunit_advanced(semantic_at_c<2>(ptr),diff)) {} // Support for planar_pixel_reference operator[] Element at_c_dynamic(size_t i) const { @@ -194,10 +191,11 @@ struct homogeneous_color_base : public homogeneous_color_base_ /// \brief A homogeneous color base holding four color elements. Models HomogeneousColorBaseConcept or HomogeneousColorBaseValueConcept /// \ingroup ColorBaseModelHomogeneous template -struct homogeneous_color_base : public homogeneous_color_base_impl { +struct homogeneous_color_base { private: Element _v0, _v1, _v2, _v3; public: + typedef Layout layout_t; typename element_reference_type::type at(mpl::int_<0>) { return _v0; } typename element_const_reference_type::type at(mpl::int_<0>) const { return _v0; } typename element_reference_type::type at(mpl::int_<1>) { return _v1; } @@ -238,10 +236,10 @@ struct homogeneous_color_base : public homogeneous_color_base_ // Support for planar_pixel_reference offset constructor template homogeneous_color_base(const Ptr& ptr, std::ptrdiff_t diff) - : _v0(*byte_advanced(semantic_at_c<0>(ptr),diff)), - _v1(*byte_advanced(semantic_at_c<1>(ptr),diff)), - _v2(*byte_advanced(semantic_at_c<2>(ptr),diff)), - _v3(*byte_advanced(semantic_at_c<3>(ptr),diff)) {} + : _v0(*memunit_advanced(semantic_at_c<0>(ptr),diff)), + _v1(*memunit_advanced(semantic_at_c<1>(ptr),diff)), + _v2(*memunit_advanced(semantic_at_c<2>(ptr),diff)), + _v3(*memunit_advanced(semantic_at_c<3>(ptr),diff)) {} // Support for planar_pixel_reference operator[] Element at_c_dynamic(size_t i) const { @@ -257,10 +255,11 @@ struct homogeneous_color_base : public homogeneous_color_base_ /// \brief A homogeneous color base holding five color elements. Models HomogeneousColorBaseConcept or HomogeneousColorBaseValueConcept /// \ingroup ColorBaseModelHomogeneous template -struct homogeneous_color_base : public homogeneous_color_base_impl { +struct homogeneous_color_base { private: Element _v0, _v1, _v2, _v3, _v4; public: + typedef Layout layout_t; typename element_reference_type::type at(mpl::int_<0>) { return _v0; } typename element_const_reference_type::type at(mpl::int_<0>) const { return _v0; } typename element_reference_type::type at(mpl::int_<1>) { return _v1; } @@ -307,11 +306,11 @@ struct homogeneous_color_base : public homogeneous_color_base_ // Support for planar_pixel_reference offset constructor template homogeneous_color_base(const Ptr& ptr, std::ptrdiff_t diff) - : _v0(*byte_advanced(semantic_at_c<0>(ptr),diff)), - _v1(*byte_advanced(semantic_at_c<1>(ptr),diff)), - _v2(*byte_advanced(semantic_at_c<2>(ptr),diff)), - _v3(*byte_advanced(semantic_at_c<3>(ptr),diff)), - _v4(*byte_advanced(semantic_at_c<4>(ptr),diff)) {} + : _v0(*memunit_advanced(semantic_at_c<0>(ptr),diff)), + _v1(*memunit_advanced(semantic_at_c<1>(ptr),diff)), + _v2(*memunit_advanced(semantic_at_c<2>(ptr),diff)), + _v3(*memunit_advanced(semantic_at_c<3>(ptr),diff)), + _v4(*memunit_advanced(semantic_at_c<4>(ptr),diff)) {} // Support for planar_pixel_reference operator[] Element at_c_dynamic(size_t i) const { @@ -366,17 +365,28 @@ dynamic_at_c(const homogeneous_color_base& cb, std::siz } // namespace detail +template +struct kth_element_type, K> { + typedef Element type; +}; + +template +struct kth_element_reference_type, K> : public add_reference {}; + +template +struct kth_element_const_reference_type, K> : public add_reference::type> {}; + /// \brief Provides mutable access to the K-th element, in physical order /// \ingroup ColorBaseModelHomogeneous template inline typename add_reference::type -at_c( detail::homogeneous_color_base& p) { return p.at(mpl::int_()); }; +at_c( detail::homogeneous_color_base& p) { return p.at(mpl::int_()); } /// \brief Provides constant access to the K-th element, in physical order /// \ingroup ColorBaseModelHomogeneous template inline typename add_reference::type>::type -at_c(const detail::homogeneous_color_base& p) { return p.at(mpl::int_()); }; +at_c(const detail::homogeneous_color_base& p) { return p.at(mpl::int_()); } namespace detail { struct swap_fn { @@ -389,7 +399,7 @@ namespace detail { template inline void swap(detail::homogeneous_color_base& x, detail::homogeneous_color_base& y) { static_for_each(x,y,detail::swap_fn()); -}; +} } } // namespace boost::gil diff --git a/include/boost/gil/color_base_algorithm.hpp b/include/boost/gil/color_base_algorithm.hpp index 22aee8930b..8215a2e2ba 100644 --- a/include/boost/gil/color_base_algorithm.hpp +++ b/include/boost/gil/color_base_algorithm.hpp @@ -40,9 +40,17 @@ namespace boost { namespace gil { /// /////////////////////////////////////// -/// \defgroup ColorBaseAlgorithmSize size -/// \ingroup ColorBaseAlgorithm -/// \brief Returns an MPL integral type specifying the number of elements in a color base +/** +\defgroup ColorBaseAlgorithmSize size +\ingroup ColorBaseAlgorithm +\brief Returns an MPL integral type specifying the number of elements in a color base + +Example: +\code +BOOST_STATIC_ASSERT((size::value == 3)); +BOOST_STATIC_ASSERT((size::value == 4)); +\endcode +*/ /// \brief Returns an MPL integral type specifying the number of elements in a color base /// \ingroup ColorBaseAlgorithmSize @@ -55,25 +63,44 @@ struct size : public mpl::size {}; /// /////////////////////////////////////// -/// \defgroup ColorBaseAlgorithmSemanticAtC kth_semantic_element_type, kth_semantic_element_reference_type, kth_semantic_element_const_reference_type, semantic_at_c -/// \ingroup ColorBaseAlgorithm -/// \brief Support for accessing the elements of a color base by semantic index -/// The semantic index of an element is the index of its color in the color space. Semantic indexing allows for proper pairing of elements of color bases -/// independent on their layout. For example, red is the first semantic element of a color base regardless of whether it has an RGB layout or a BGR layout. -/// All GIL color base algorithms taking multiple color bases use semantic indexing to access their elements. +/** +\defgroup ColorBaseAlgorithmSemanticAtC kth_semantic_element_type, kth_semantic_element_reference_type, kth_semantic_element_const_reference_type, semantic_at_c +\ingroup ColorBaseAlgorithm +\brief Support for accessing the elements of a color base by semantic index + +The semantic index of an element is the index of its color in the color space. Semantic indexing allows for proper pairing of elements of color bases +independent on their layout. For example, red is the first semantic element of a color base regardless of whether it has an RGB layout or a BGR layout. +All GIL color base algorithms taking multiple color bases use semantic indexing to access their elements. + +Example: +\code +// 16-bit BGR pixel, 4 bits for the blue, 3 bits for the green, 2 bits for the red channel and 7 unused bits +typedef packed_pixel_type, bgr_layout_t>::type bgr432_pixel_t; + +// A reference to its red channel. Although the red channel is the third, its semantic index is 0 in the RGB color space +typedef kth_semantic_element_reference_type::type red_channel_reference_t; + +// Initialize the pixel to black +bgr432_pixel_t red_pixel(0,0,0); +// Set the red channel to 100% +red_channel_reference_t red_channel = semantic_at_c<0>(red_pixel); +red_channel = channel_traits::max_value(); + +\endcode +*/ /// \brief Specifies the type of the K-th semantic element of a color base /// \ingroup ColorBaseAlgorithmSemanticAtC template struct kth_semantic_element_type { BOOST_STATIC_CONSTANT(int, semantic_index = (mpl::at_c::type::value)); - typedef typename ColorBase::template kth_element_type::type type; + typedef typename kth_element_type::type type; }; /// \brief Specifies the return type of the mutable semantic_at_c(color_base); /// \ingroup ColorBaseAlgorithmSemanticAtC template struct kth_semantic_element_reference_type { BOOST_STATIC_CONSTANT(int, semantic_index = (mpl::at_c::type::value)); - typedef typename ColorBase::template kth_element_reference_type::type type; + typedef typename kth_element_reference_type::type type; static type get(ColorBase& cb) { return at_c(cb); } }; @@ -81,7 +108,7 @@ template struct kth_semantic_element_reference_type /// \ingroup ColorBaseAlgorithmSemanticAtC template struct kth_semantic_element_const_reference_type { BOOST_STATIC_CONSTANT(int, semantic_index = (mpl::at_c::type::value)); - typedef typename ColorBase::template kth_element_const_reference_type::type type; + typedef typename kth_element_const_reference_type::type type; static type get(const ColorBase& cb) { return at_c(cb); } }; @@ -91,7 +118,7 @@ template inline typename disable_if,typename kth_semantic_element_reference_type::type>::type semantic_at_c(ColorBase& p) { return kth_semantic_element_reference_type::get(p); -}; +} /// \brief A constant accessor to the K-th semantic element of a color base /// \ingroup ColorBaseAlgorithmSemanticAtC @@ -99,7 +126,7 @@ template inline typename kth_semantic_element_const_reference_type::type semantic_at_c(const ColorBase& p) { return kth_semantic_element_const_reference_type::get(p); -}; +} /////////////////////////////////////// /// @@ -107,40 +134,60 @@ semantic_at_c(const ColorBase& p) { /// /////////////////////////////////////// -/// \defgroup ColorBaseAlgorithmColor color_element_type, color_element_reference_type, color_element_const_reference_type, get_color -/// \ingroup ColorBaseAlgorithm -/// \brief Support for accessing the elements of a color base by color name +/** +\defgroup ColorBaseAlgorithmColor color_element_type, color_element_reference_type, color_element_const_reference_type, get_color, contains_color +\ingroup ColorBaseAlgorithm +\brief Support for accessing the elements of a color base by color name + +Example: A function that takes a generic pixel containing a red channel and sets it to 100%: + +\code +template +void set_red_to_max(Pixel& pixel) { + boost::function_requires >(); + BOOST_STATIC_ASSERT((contains_color::value)); + + typedef typename color_element_type::type red_channel_t; + get_color(pixel, red_t()) = channel_traits::max_value(); +} +\endcode +*/ + +/// \brief A predicate metafunction determining whether a given color base contains a given color +/// \ingroup ColorBaseAlgorithmColor +template +struct contains_color : public mpl::contains {}; template struct color_index_type : public detail::type_to_index {}; /// \brief Specifies the type of the element associated with a given color tag /// \ingroup ColorBaseAlgorithmColor -template +template struct color_element_type : public kth_semantic_element_type::value> {}; /// \brief Specifies the return type of the mutable element accessor by color name, get_color(color_base, Color()); /// \ingroup ColorBaseAlgorithmColor -template +template struct color_element_reference_type : public kth_semantic_element_reference_type::value> {}; /// \brief Specifies the return type of the constant element accessor by color name, get_color(color_base, Color()); /// \ingroup ColorBaseAlgorithmColor -template +template struct color_element_const_reference_type : public kth_semantic_element_const_reference_type::value> {}; /// \brief Mutable accessor to the element associated with a given color name /// \ingroup ColorBaseAlgorithmColor -template -typename color_element_reference_type::type get_color(CB& cb, Color=Color()) { - return color_element_reference_type::get(cb); +template +typename color_element_reference_type::type get_color(ColorBase& cb, Color=Color()) { + return color_element_reference_type::get(cb); } /// \brief Constant accessor to the element associated with a given color name /// \ingroup ColorBaseAlgorithmColor -template -typename color_element_const_reference_type::type get_color(const CB& cb, Color=Color()) { - return color_element_const_reference_type::get(cb); +template +typename color_element_const_reference_type::type get_color(const ColorBase& cb, Color=Color()) { + return color_element_const_reference_type::get(cb); } /////////////////////////////////////// @@ -149,24 +196,31 @@ typename color_element_const_reference_type::type get_color(const CB& /// /////////////////////////////////////// -/// \defgroup ColorBaseAlgorithmHomogeneous element_type, element_reference_type, element_const_reference_type -/// \ingroup ColorBaseAlgorithm -/// \brief Types for homogeneous color bases +/** +\defgroup ColorBaseAlgorithmHomogeneous element_type, element_reference_type, element_const_reference_type +\ingroup ColorBaseAlgorithm +\brief Types for homogeneous color bases +Example: +\code +typedef element_type::type element_t; +BOOST_STATIC_ASSERT((boost::is_same::value)); +\endcode +*/ /// \brief Specifies the element type of a homogeneous color base /// \ingroup ColorBaseAlgorithmHomogeneous template -struct element_type : public ColorBase::template kth_element_type<0> {}; +struct element_type : public kth_element_type {}; /// \brief Specifies the return type of the mutable element accessor at_c of a homogeneous color base /// \ingroup ColorBaseAlgorithmHomogeneous template -struct element_reference_type : public ColorBase::template kth_element_reference_type<0> {}; +struct element_reference_type : public kth_element_reference_type {}; /// \brief Specifies the return type of the constant element accessor at_c of a homogeneous color base /// \ingroup ColorBaseAlgorithmHomogeneous template -struct element_const_reference_type : public ColorBase::template kth_element_const_reference_type<0> {}; +struct element_const_reference_type : public kth_element_const_reference_type {}; namespace detail { @@ -391,10 +445,20 @@ struct min_max_recur<1> { } // namespace detail -/// \defgroup ColorBaseAlgorithmMinMax static_min, static_max -/// \ingroup ColorBaseAlgorithm -/// \brief Equivalents to std::min_element and std::max_element for homogeneous color bases -/// \{ +/** +\defgroup ColorBaseAlgorithmMinMax static_min, static_max +\ingroup ColorBaseAlgorithm +\brief Equivalents to std::min_element and std::max_element for homogeneous color bases + +Example: +\code +rgb8_pixel_t pixel(10,20,30); +assert(pixel[2] == 30); +static_max(pixel) = static_min(pixel); +assert(pixel[2] == 10); +\endcode +\{ +*/ template GIL_FORCEINLINE @@ -413,10 +477,22 @@ GIL_FORCEINLINE typename element_reference_type

              ::type static_min( P& p) { return detail::min_max_recur::value>::min_(p); } /// \} -/// \defgroup ColorBaseAlgorithmEqual static_equal -/// \ingroup ColorBaseAlgorithm -/// \brief Equivalent to std::equal. Pairs the elements semantically -/// \{ +/** +\defgroup ColorBaseAlgorithmEqual static_equal +\ingroup ColorBaseAlgorithm +\brief Equivalent to std::equal. Pairs the elements semantically + +Example: +\code +rgb8_pixel_t rgb_red(255,0,0); +bgr8_pixel_t bgr_red(0,0,255); +assert(rgb_red[0]==255 && bgr_red[0]==0); + +assert(static_equal(rgb_red,bgr_red)); +assert(rgb_red==bgr_red); // operator== invokes static_equal +\endcode +\{ +*/ template GIL_FORCEINLINE @@ -424,10 +500,22 @@ bool static_equal(const P1& p1, const P2& p2) { return detail::element_recursion /// \} -/// \defgroup ColorBaseAlgorithmCopy static_copy -/// \ingroup ColorBaseAlgorithm -/// \brief Equivalent to std::copy. Pairs the elements semantically -/// \{ +/** +\defgroup ColorBaseAlgorithmCopy static_copy +\ingroup ColorBaseAlgorithm +\brief Equivalent to std::copy. Pairs the elements semantically + +Example: +\code +rgb8_pixel_t rgb_red(255,0,0); +bgr8_pixel_t bgr_red; +static_copy(rgb_red, bgr_red); // same as bgr_red = rgb_red + +assert(rgb_red[0] == 255 && bgr_red[0] == 0); +assert(rgb_red == bgr_red); +\endcode +\{ +*/ template GIL_FORCEINLINE @@ -435,30 +523,77 @@ void static_copy(const Src& src, Dst& dst) { detail::element_recursion GIL_FORCEINLINE void static_fill(P& p, const V& v) { detail::element_recursion::value>::static_fill(p,v); } /// \} -/// \defgroup ColorBaseAlgorithmGenerate static_generate -/// \ingroup ColorBaseAlgorithm -/// \brief Equivalent to std::generate. -/// \{ +/** +\defgroup ColorBaseAlgorithmGenerate static_generate +\ingroup ColorBaseAlgorithm +\brief Equivalent to std::generate. + +Example: Set each channel of a pixel to its semantic index. The channels must be assignable from an integer. +\code +struct consecutive_fn { + int& _current; + consecutive_fn(int& start) : _current(start) {} + int operator()() { return _current++; } +}; +rgb8_pixel_t p; +int start=0; +static_generate(p, consecutive_fn(start)); +assert(p == rgb8_pixel_t(0,1,2)); +\endcode + +\{ +*/ template GIL_FORCEINLINE void static_generate(P1& dst,Op op) { detail::element_recursion::value>::static_generate(dst,op); } /// \} -/// \defgroup ColorBaseAlgorithmTransform static_transform -/// \ingroup ColorBaseAlgorithm -/// \brief Equivalent to std::transform. Pairs the elements semantically -/// \{ +/** +\defgroup ColorBaseAlgorithmTransform static_transform +\ingroup ColorBaseAlgorithm +\brief Equivalent to std::transform. Pairs the elements semantically + +Example: Write a generic function that adds two pixels into a homogeneous result pixel. +\code +template +struct my_plus { + template + Result operator()(T1 f1, T2 f2) const { return f1+f2; } +}; + +template +void sum_channels(const Pixel1& p1, const Pixel2& p2, Pixel3& result) { + typedef typename channel_type::type result_channel_t; + static_transform(p1,p2,result,my_plus()); +} + +rgb8_pixel_t p1(1,2,3); +bgr8_pixel_t p2(3,2,1); +rgb8_pixel_t result; +sum_channels(p1,p2,result); +assert(result == rgb8_pixel_t(2,4,6)); +\endcode +\{ +*/ //static_transform with one source template @@ -482,10 +617,32 @@ GIL_FORCEINLINE Op static_transform(const P2& p2,const P3& p3,Dst& dst,Op op) { return detail::element_recursion::value>::static_transform(p2,p3,dst,op); } /// \} -/// \defgroup ColorBaseAlgorithmForEach static_for_each -/// \ingroup ColorBaseAlgorithm -/// \brief Equivalent to std::for_each. Pairs the elements semantically -/// \{ +/** +\defgroup ColorBaseAlgorithmForEach static_for_each +\ingroup ColorBaseAlgorithm +\brief Equivalent to std::for_each. Pairs the elements semantically + +Example: Use static_for_each to increment a planar pixel iterator +\code +struct increment { + template + void operator()(Incrementable& x) const { ++x; } +}; + +template +void increment_elements(ColorBase& cb) { + static_for_each(cb, increment()); +} + +bits8 red[2], green[2], blue[2]; +rgb8c_planar_ptr_t p1(red,green,blue); +rgb8c_planar_ptr_t p2=p1; +increment_elements(p1); +++p2; +assert(p1 == p2); +\endcode +\{ +*/ //static_for_each with one source template diff --git a/include/boost/gil/color_convert.hpp b/include/boost/gil/color_convert.hpp index 55e904c786..7d4db74084 100644 --- a/include/boost/gil/color_convert.hpp +++ b/include/boost/gil/color_convert.hpp @@ -102,11 +102,11 @@ struct default_color_converter_impl { template void operator()(const P1& src, P2& dst) const { get_color(dst,red_t()) = - channel_convert::type>(get_color(src,gray_color_t())); + channel_convert::type>(get_color(src,gray_color_t())); get_color(dst,green_t())= - channel_convert::type>(get_color(src,gray_color_t())); + channel_convert::type>(get_color(src,gray_color_t())); get_color(dst,blue_t()) = - channel_convert::type>(get_color(src,gray_color_t())); + channel_convert::type>(get_color(src,gray_color_t())); } }; @@ -117,13 +117,13 @@ struct default_color_converter_impl { template void operator()(const P1& src, P2& dst) const { get_color(dst,cyan_t())= - channel_traits::type>::min_value(); + channel_traits::type>::min_value(); get_color(dst,magenta_t())= - channel_traits::type>::min_value(); + channel_traits::type>::min_value(); get_color(dst,yellow_t())= - channel_traits::type>::min_value(); + channel_traits::type>::min_value(); get_color(dst,black_t())= - channel_convert::type>(get_color(src,gray_color_t())); + channel_convert::type>(get_color(src,gray_color_t())); } }; @@ -134,7 +134,7 @@ struct default_color_converter_impl { template void operator()(const P1& src, P2& dst) const { get_color(dst,gray_color_t()) = - detail::rgb_to_luminance::type>( + detail::rgb_to_luminance::type>( get_color(src,red_t()), get_color(src,green_t()), get_color(src,blue_t()) ); } @@ -183,17 +183,17 @@ struct default_color_converter_impl { void operator()(const P1& src, P2& dst) const { typedef typename channel_type::type T1; get_color(dst,red_t()) = - channel_convert::type>( + channel_convert::type>( channel_invert( (std::min)(channel_traits::max_value(), T1(get_color(src,cyan_t())*channel_invert(get_color(src,black_t()))+get_color(src,black_t()))))); get_color(dst,green_t())= - channel_convert::type>( + channel_convert::type>( channel_invert( (std::min)(channel_traits::max_value(), T1(get_color(src,magenta_t())*channel_invert(get_color(src,black_t()))+get_color(src,black_t()))))); get_color(dst,blue_t()) = - channel_convert::type>( + channel_convert::type>( channel_invert( (std::min)(channel_traits::max_value(), T1(get_color(src,yellow_t())*channel_invert(get_color(src,black_t()))+get_color(src,black_t()))))); @@ -210,10 +210,10 @@ struct default_color_converter_impl { template void operator()(const P1& src, P2& dst) const { get_color(dst,gray_color_t())= - channel_convert::type>( + channel_convert::type>( channel_multiply( channel_invert( - detail::rgb_to_luminance::type>( + detail::rgb_to_luminance::type>( get_color(src,cyan_t()), get_color(src,magenta_t()), get_color(src,yellow_t()) @@ -308,7 +308,7 @@ struct default_color_converter { template inline void color_convert(const SrcP& src, DstP& dst) { default_color_converter()(src,dst); -}; +} } } // namespace boost::gil diff --git a/include/boost/gil/deprecated.hpp b/include/boost/gil/deprecated.hpp index 1dd2e14009..f157a698c2 100644 --- a/include/boost/gil/deprecated.hpp +++ b/include/boost/gil/deprecated.hpp @@ -27,8 +27,8 @@ #define planar_ptr planar_pixel_iterator #define planar_ref planar_pixel_reference -#define membased_2d_locator byte_addressable_2d_locator -#define pixel_step_iterator byte_addressable_step_iterator +#define membased_2d_locator memory_based_2d_locator +#define pixel_step_iterator memory_based_step_iterator #define pixel_image_iterator iterator_from_2d #define equal_channels static_equal @@ -61,5 +61,17 @@ template std::size_t get_num_channels(const T& a) { return a.num_ch #define ADOBE_GIL_NAMESPACE_BEGIN namespace boost { namespace gil { #define ADOBE_GIL_NAMESPACE_END } } +#define ByteAdvancableIteratorConcept MemoryBasedIteratorConcept +#define byte_advance memunit_advance +#define byte_advanced memunit_advanced +#define byte_step memunit_step +#define byte_distance memunit_distance + +#define byte_addressable_step_iterator memory_based_step_iterator +#define byte_addressable_2d_locator memory_based_2d_locator + +// These are members of memory-based locators +//#define row_bytes row_size // commented out because row_bytes is commonly used +#define pix_bytestep pixel_size #endif diff --git a/include/boost/gil/gil_all.hpp b/include/boost/gil/gil_all.hpp index 86accd40a6..17065b967f 100644 --- a/include/boost/gil/gil_all.hpp +++ b/include/boost/gil/gil_all.hpp @@ -39,6 +39,7 @@ #include "color_convert.hpp" #include "device_n.hpp" #include "virtual_locator.hpp" +#include "bit_aligned_pixel_iterator.hpp" // Uncomment this line to help in porting your code from an older version of GIL //#include "deprecated.hpp" diff --git a/include/boost/gil/gil_concept.hpp b/include/boost/gil/gil_concept.hpp index 2a1192bc2e..497228fdfd 100644 --- a/include/boost/gil/gil_concept.hpp +++ b/include/boost/gil/gil_concept.hpp @@ -39,6 +39,9 @@ typename channel_traits::value_type channel_convert(srcT val); template class point2; template const T& axis_value(const point2& p); template T& axis_value( point2& p); +template struct kth_element_type; +template struct kth_element_reference_type; +template struct kth_element_const_reference_type; template struct kth_semantic_element_reference_type; template struct kth_semantic_element_const_reference_type; template struct size; @@ -65,14 +68,20 @@ template typename add_reference::type>::type at_c(const detail::homogeneous_color_base& p); #if !defined(_MSC_VER) || _MSC_VER > 1310 -template struct heterogeneous_packed_pixel; +template struct packed_pixel; template -typename heterogeneous_packed_pixel::template kth_element_reference_type::type -at_c(heterogeneous_packed_pixel& p); +typename kth_element_reference_type, K>::type +at_c(packed_pixel& p); template -typename heterogeneous_packed_pixel::template kth_element_const_reference_type::type -at_c(const heterogeneous_packed_pixel& p); +typename kth_element_const_reference_type,K>::type +at_c(const packed_pixel& p); + +template struct bit_aligned_pixel_reference; + +template inline +typename kth_element_reference_type, K>::type +at_c(const bit_aligned_pixel_reference& p); #endif // Forward-declare semantic_at_c @@ -91,10 +100,10 @@ void initialize_it(T& x) {} } // namespace detail template -struct remove_const_and_reference : public remove_reference::type> {}; +struct remove_const_and_reference : public remove_const::type> {}; #ifdef BOOST_GIL_USE_CONCEPT_CHECK - #define GIL_CLASS_REQUIRE(type_var, ns, concept) BOOST_CLASS_REQUIRE(type_var, ns, concept) + #define GIL_CLASS_REQUIRE(type_var, ns, concept) BOOST_CLASS_REQUIRE(type_var, ns, concept); template void gil_function_requires() { function_requires(); } #else #define GIL_CLASS_REQUIRE(T,NS,C) @@ -227,14 +236,13 @@ struct Metafunction { } }; //////////////////////////////////////////////////////////////////////////////////////// -/// +// // POINT CONCEPTS -/// +// //////////////////////////////////////////////////////////////////////////////////////// /// \brief N-dimensional point concept /// \ingroup PointConcept - /** \code concept PointNDConcept : Regular { @@ -337,9 +345,9 @@ namespace detail { } // namespace detail //////////////////////////////////////////////////////////////////////////////////////// -/// -/// COLOR SPACE CONCEPTS -/// +// +// COLOR SPACE CONCEPTS +// //////////////////////////////////////////////////////////////////////////////////////// /// \brief Color space type concept @@ -488,9 +496,16 @@ struct ChannelValueConcept { /// \brief Predicate metafunction returning whether two channels are compatible +/// \ingroup ChannelAlgorithm /// -/// Channels are considered compatible if their value types (ignoring constness and references) are the same -/// \ingroup ChannelModel +/// Channels are considered compatible if their value types (ignoring constness and references) are the same. +/** +Example: + +\code +BOOST_STATIC_ASSERT((channels_are_compatible::value)); +\endcode +*/ template // Models GIL Pixel struct channels_are_compatible : public is_same::value_type, typename channel_traits::value_type> {}; @@ -599,8 +614,8 @@ struct ColorBaseConcept { static const std::size_t num_elements = size::value; - typedef typename ColorBase::template kth_element_type::type TN; - typedef typename ColorBase::template kth_element_const_reference_type::type CR; + typedef typename kth_element_type::type TN; + typedef typename kth_element_const_reference_type::type CR; #if !defined(_MSC_VER) || _MSC_VER > 1310 CR cr=at_c(cb); ignore_unused_variable_warning(cr); @@ -623,7 +638,7 @@ struct ColorBaseConcept { concept MutableColorBaseConcept : Assignable, Swappable { template struct kth_element_reference_type; where Metafunction; - template kth_element_reference_type::type>::type at_c(T); + template kth_element_reference_type::type>::type at_c(T); template where { ColorBasesCompatibleConcept } T& operator=(T&, const T2&); @@ -637,7 +652,7 @@ struct MutableColorBaseConcept { gil_function_requires< Assignable >(); gil_function_requires< Swappable >(); - typedef typename ColorBase::template kth_element_reference_type<0>::type CR; + typedef typename kth_element_reference_type::type CR; #if !defined(_MSC_VER) || _MSC_VER > 1310 CR r=at_c<0>(cb); @@ -670,8 +685,8 @@ struct ColorBaseValueConcept { \code concept HomogeneousColorBaseConcept { // For all K in [0 ... size::value-1): - // where SameType::type, kth_element_type::type>; - kth_element_const_reference_type<0>::type dynamic_at_c(const CB&, std::size_t n) const; + // where SameType::type, kth_element_type::type>; + kth_element_const_reference_type::type dynamic_at_c(const CB&, std::size_t n) const; }; \endcode */ @@ -683,11 +698,11 @@ struct HomogeneousColorBaseConcept { static const std::size_t num_elements = size::value; - typedef typename ColorBase::template kth_element_type<0>::type T0; - typedef typename ColorBase::template kth_element_type::type TN; + typedef typename kth_element_type::type T0; + typedef typename kth_element_type::type TN; BOOST_STATIC_ASSERT((is_same::value)); // better than nothing - typedef typename ColorBase::template kth_element_const_reference_type<0>::type CR0; + typedef typename kth_element_const_reference_type::type CR0; CR0 e0=dynamic_at_c(cb,0); } ColorBase cb; @@ -699,7 +714,7 @@ struct HomogeneousColorBaseConcept { \code concept MutableHomogeneousColorBaseConcept : HomogeneousColorBaseConcept { - kth_element_reference_type<0>::type dynamic_at_c(CB&, std::size_t n); + kth_element_reference_type::type dynamic_at_c(CB&, std::size_t n); }; \endcode */ @@ -709,7 +724,7 @@ struct MutableHomogeneousColorBaseConcept { void constraints() { gil_function_requires< ColorBaseConcept >(); gil_function_requires< HomogeneousColorBaseConcept >(); - typedef typename ColorBase::template kth_element_reference_type<0>::type R0; + typedef typename kth_element_reference_type::type R0; R0 x=dynamic_at_c(cb,0); dynamic_at_c(cb,0) = dynamic_at_c(cb,0); } @@ -848,7 +863,7 @@ struct HomogeneousPixelBasedConcept { concept PixelConcept : ColorBaseConcept

              , PixelBasedConcept

              { where is_pixel

              ::type::value==true; // where for each K [0..size

              ::value-1]: - // ChannelConcept >; + // ChannelConcept >; typename P::value_type; where PixelValueConcept; typename P::reference; where PixelConcept; @@ -990,7 +1005,7 @@ namespace detail { /// \brief Returns whether two pixels are compatible /// /// Pixels are compatible if their channels and color space types are compatible. Compatible pixels can be assigned and copy constructed from one another. -/// \ingroup PixelModel +/// \ingroup PixelAlgorithm template // Models GIL Pixel struct pixels_are_compatible : public mpl::and_::type, @@ -1232,15 +1247,15 @@ struct MutablePixelIteratorConcept { }; namespace detail { - // Iterators that can be used as the base of byte_addressable_step_iterator require some additional functions + // Iterators that can be used as the base of memory_based_step_iterator require some additional functions template // Preconditions: Iterator Models boost_concepts::RandomAccessTraversalConcept - struct RandomAccessIteratorIsByteAdvanceableConcept { + struct RandomAccessIteratorIsMemoryBasedConcept { void constraints() { - std::ptrdiff_t bs=byte_step(it); ignore_unused_variable_warning(bs); - it=byte_advanced(it,3); - std::ptrdiff_t bd=byte_distance(it,it); ignore_unused_variable_warning(bd); - byte_advance(it,3); - // for performace you may also provide a customized implementation of byte_advanced_ref + std::ptrdiff_t bs=memunit_step(it); ignore_unused_variable_warning(bs); + it=memunit_advanced(it,3); + std::ptrdiff_t bd=memunit_distance(it,it); ignore_unused_variable_warning(bd); + memunit_advance(it,3); + // for performace you may also provide a customized implementation of memunit_advanced_ref } Iterator it; }; @@ -1250,24 +1265,25 @@ namespace detail { /// \ingroup PixelIteratorConcept /// \brief Iterator that advances by a specified step -/// \brief Concept of a random-access iterator that can be advanced in bytes +/// \brief Concept of a random-access iterator that can be advanced in memory units (bytes or bits) /// \ingroup PixelIteratorConceptStepIterator /** \code -concept ByteAdvanceableIteratorConcept { - std::ptrdiff_t byte_step(const Iterator&); - std::ptrdiff_t byte_distance(const Iterator& , const Iterator&); - void byte_advance(Iterator&, std::ptrdiff_t byteDiff); - Iterator byte_advanced(const Iterator& p, std::ptrdiff_t byteDiff) { Iterator tmp; byte_advance(tmp,pyteDiff); return tmp; } - Iterator::reference byte_advanced_ref(const Iterator& p, std::ptrdiff_t byteDiff) { return *byte_advanced(p,byteDiff); } +concept MemoryBasedIteratorConcept { + typename byte_to_memunit; where metafunction >; + std::ptrdiff_t memunit_step(const Iterator&); + std::ptrdiff_t memunit_distance(const Iterator& , const Iterator&); + void memunit_advance(Iterator&, std::ptrdiff_t diff); + Iterator memunit_advanced(const Iterator& p, std::ptrdiff_t diff) { Iterator tmp; memunit_advance(tmp,diff); return tmp; } + Iterator::reference memunit_advanced_ref(const Iterator& p, std::ptrdiff_t diff) { return *memunit_advanced(p,diff); } }; \endcode */ template -struct ByteAdvanceableIteratorConcept { +struct MemoryBasedIteratorConcept { void constraints() { gil_function_requires >(); - gil_function_requires >(); + gil_function_requires >(); } }; diff --git a/include/boost/gil/gil_config.hpp b/include/boost/gil/gil_config.hpp index bd3d64d541..502a7ddfcd 100644 --- a/include/boost/gil/gil_config.hpp +++ b/include/boost/gil/gil_config.hpp @@ -23,7 +23,7 @@ #include -#define GIL_VERSION 2.0 +#define GIL_VERSION "2.1.1" #ifdef _DEBUG # define GIL_FORCEINLINE inline diff --git a/include/boost/gil/image.hpp b/include/boost/gil/image.hpp index 3609501504..fc6d20a13d 100644 --- a/include/boost/gil/image.hpp +++ b/include/boost/gil/image.hpp @@ -188,39 +188,44 @@ class image { } void deallocate(const point_t& dimensions) { - if (_memory) _alloc.deallocate(_memory, total_allocated_size(dimensions)); + if (_memory) _alloc.deallocate(_memory, total_allocated_size_in_bytes(dimensions)); } - std::size_t total_allocated_size(const point_t& dimensions) const { - return _total_allocated_size(dimensions, mpl::bool_()); + std::size_t total_allocated_size_in_bytes(const point_t& dimensions) const { + std::size_t size_in_units = _total_allocated_size(dimensions, mpl::bool_()); + // return the size rounded up to the nearest byte + return (size_in_units + byte_to_memunit::value - 1) / byte_to_memunit::value; + } + + std::size_t get_row_size(x_coord_t width) const { // number of units per row + return align(width*memunit_step(typename view_t::x_iterator()),_align); } std::size_t _total_allocated_size(const point_t& dimensions,mpl::false_) const { - std::size_t row_bytes=align(dimensions.x*sizeof(value_type),_align); - return row_bytes*dimensions.y+_align-1; + return get_row_size(dimensions.x)*dimensions.y+_align-1; } std::size_t _total_allocated_size(const point_t& dimensions,mpl::true_) const { - std::size_t row_bytes=align(dimensions.x*sizeof(typename channel_type::type),_align); - std::size_t plane_bytes=row_bytes*dimensions.y; - return plane_bytes*num_channels::value+_align-1; + std::size_t plane_size=get_row_size(dimensions.x)*dimensions.y; + return plane_size*num_channels::value+_align-1; } void allocate_(const point_t& dimensions, mpl::false_) { // if it throws and _memory!=0 the client must deallocate _memory - std::size_t row_bytes=align(dimensions.x*sizeof(value_type),_align); - _memory=_alloc.allocate(total_allocated_size(dimensions)); + _memory=_alloc.allocate(total_allocated_size_in_bytes(dimensions)); unsigned char* tmp=(unsigned char*)align((std::size_t)_memory,_align); - _view=view_t(dimensions,typename view_t::locator(typename view_t::x_iterator(tmp),row_bytes)); + _view=view_t(dimensions,typename view_t::locator(typename view_t::x_iterator(tmp),get_row_size(dimensions.x))); } void allocate_(const point_t& dimensions, mpl::true_) { // if it throws and _memory!=0 the client must deallocate _memory - std::size_t row_bytes=align(dimensions.x*sizeof(typename channel_type::type),_align); - std::size_t plane_bytes=row_bytes*dimensions.y; - _memory=_alloc.allocate(total_allocated_size(dimensions)); + std::size_t row_size=get_row_size(dimensions.x); + std::size_t plane_size=row_size*dimensions.y; + _memory=_alloc.allocate(total_allocated_size_in_bytes(dimensions)); unsigned char* tmp=(unsigned char*)align((std::size_t)_memory,_align); typename view_t::x_iterator first; - for (int i=0; i::value; ++i) - dynamic_at_c(first,i) = (typename channel_type::type*)(tmp + plane_bytes*i); - _view=view_t(dimensions, typename view_t::locator(first, dimensions.x*sizeof(typename channel_type::type))); + for (int i=0; i::value; ++i) { + dynamic_at_c(first,i) = (typename channel_type::type*)tmp; + memunit_advance(dynamic_at_c(first,i), plane_size*i); + } + _view=view_t(dimensions, typename view_t::locator(first, row_size)); } }; diff --git a/include/boost/gil/image_view_factory.hpp b/include/boost/gil/image_view_factory.hpp index 4f67052992..9a50bd692b 100644 --- a/include/boost/gil/image_view_factory.hpp +++ b/include/boost/gil/image_view_factory.hpp @@ -31,9 +31,9 @@ #include "gray.hpp" #include "color_convert.hpp" -/// \defgroup ImageViewConstructors Image View Constructors +/// \defgroup ImageViewConstructors Image View From Raw Data /// \ingroup ImageViewAlgorithm -/// \brief Methods for constructing image views from raw data +/// \brief Methods for constructing image views from raw data and for getting raw data from views /// \defgroup ImageViewTransformations Image View Transformations /// \ingroup ImageViewAlgorithm @@ -77,6 +77,42 @@ interleaved_view(point2 dim, return RView(dim, typename RView::locator(pixels, rowsize_in_bytes)); } +///////////////////////////// +// interleaved_view_get_raw_data, planar_view_get_raw_data - return pointers to the raw data (the channels) of a basic homogeneous view. +///////////////////////////// + +namespace detail { + template struct channel_pointer_type_impl; + + template struct channel_pointer_type_impl { + typedef typename channel_type::type* type; + }; + template struct channel_pointer_type_impl { + typedef const typename channel_type::type* type; + }; + + template struct channel_pointer_type + : public channel_pointer_type_impl::value> {}; +}; + +/// \ingroup ImageViewConstructors +/// \brief Returns C pointer to the the channels of an interleaved homogeneous view. +template +typename detail::channel_pointer_type::type interleaved_view_get_raw_data(const HomogeneousView& view) { + BOOST_STATIC_ASSERT((!is_planar::value && view_is_basic::value)); + BOOST_STATIC_ASSERT((boost::is_pointer::value)); + + return &at_c<0>(view(0,0)); +} + +/// \ingroup ImageViewConstructors +/// \brief Returns C pointer to the the channels of a given color plane of a planar homogeneous view. +template +typename detail::channel_pointer_type::type planar_view_get_raw_data(const HomogeneousView& view, int plane_index) { + BOOST_STATIC_ASSERT((is_planar::value && view_is_basic::value)); + return dynamic_at_c(view.row_begin(0),plane_index); +} + /// \defgroup ImageViewTransformationsColorConvert color_converted_view /// \ingroup ImageViewTransformations @@ -87,23 +123,15 @@ interleaved_view(point2 dim, /// /// Useful in constructing a color converted view over a given image view template // const_reference to the source pixel and destination pixel value -class color_convert_deref_fn { +class color_convert_deref_fn : public deref_base, DstP, DstP, const DstP&, SrcConstRefP, DstP, false> { private: CC _cc; // color-converter public: - typedef color_convert_deref_fn const_t; - typedef DstP value_type; - typedef value_type reference; // read-only dereferencing - typedef const value_type& const_reference; - typedef SrcConstRefP argument_type; - typedef reference result_type; - BOOST_STATIC_CONSTANT(bool, is_mutable=false); - color_convert_deref_fn() {} color_convert_deref_fn(CC cc_in) : _cc(cc_in) {} - result_type operator()(argument_type srcP) const { - result_type dstP; + DstP operator()(SrcConstRefP srcP) const { + DstP dstP; _cc(srcP,dstP); return dstP; } @@ -137,7 +165,7 @@ struct color_converted_view_type : public detail::_color_converted_view_type { - GIL_CLASS_REQUIRE(DstP, boost::gil, MutablePixelConcept);//why does it have to be mutable??? + GIL_CLASS_REQUIRE(DstP, boost::gil, MutablePixelConcept)//why does it have to be mutable??? }; @@ -274,8 +302,8 @@ namespace detail { typedef typename type::xy_locator locator_t; typedef typename type::x_iterator x_iterator_t; typedef typename iterator_adaptor_get_base::type x_iterator_base_t; - x_iterator_t sit(x_iterator_base_t(&(src(0,0)[n])),src.pixels().pix_bytestep()); - return type(src.dimensions(),locator_t(sit, src.pixels().row_bytes())); + x_iterator_t sit(x_iterator_base_t(&(src(0,0)[n])),src.pixels().pixel_size()); + return type(src.dimensions(),locator_t(sit, src.pixels().row_size())); } }; @@ -285,7 +313,7 @@ namespace detail { typedef typename view_type::type, gray_layout_t, false, false, view_is_mutable::value>::type type; static type make(const View& src, int n) { typedef typename type::x_iterator x_iterator_t; - return interleaved_view(src.width(),src.height(),(x_iterator_t)&(src(0,0)[n]), src.pixels().row_bytes()); + return interleaved_view(src.width(),src.height(),(x_iterator_t)&(src(0,0)[n]), src.pixels().row_size()); } }; @@ -317,19 +345,19 @@ namespace detail { template // SrcP is a reference to PixelConcept (could be pixel value or const/non-const reference) // Examples: pixel, pixel&, const pixel&, planar_pixel_reference, planar_pixel_reference struct nth_channel_deref_fn { - BOOST_STATIC_CONSTANT(bool, is_mutable=is_pixel_reference::value && pixel_reference_is_mutable::value); + BOOST_STATIC_CONSTANT(bool, is_mutable=pixel_is_reference::value && pixel_reference_is_mutable::value); private: typedef typename remove_reference::type src_pixel_t; typedef typename channel_type::type channel_t; typedef typename src_pixel_t::const_reference const_ref_t; typedef typename pixel_reference_type::type ref_t; public: - typedef nth_channel_deref_fn const_t; - typedef pixel value_type; + typedef nth_channel_deref_fn const_t; + typedef typename pixel_value_type::type value_type; typedef typename pixel_reference_type::type const_reference; - typedef SrcP argument_type; - typedef typename mpl::if_c::type reference; - typedef reference result_type; + typedef SrcP argument_type; + typedef typename mpl::if_c::type reference; + typedef reference result_type; nth_channel_deref_fn(int n=0) : _n(n) {} template nth_channel_deref_fn(const nth_channel_deref_fn

              & d) : _n(d._n) {} @@ -362,7 +390,7 @@ namespace detail { template struct nth_channel_view_type { private: - GIL_CLASS_REQUIRE(View, boost::gil, ImageViewConcept); + GIL_CLASS_REQUIRE(View, boost::gil, ImageViewConcept) typedef detail::__nth_channel_view::value> VB; public: typedef typename VB::type type; @@ -394,7 +422,7 @@ namespace detail { template struct __kth_channel_view_basic { private: - typedef typename View::value_type::template kth_element_type::type channel_t; + typedef typename kth_element_type::type channel_t; public: typedef typename view_type::value>::type type; @@ -402,8 +430,8 @@ namespace detail { typedef typename type::xy_locator locator_t; typedef typename type::x_iterator x_iterator_t; typedef typename iterator_adaptor_get_base::type x_iterator_base_t; - x_iterator_t sit(x_iterator_base_t(&at_c(src(0,0))),src.pixels().pix_bytestep()); - return type(src.dimensions(),locator_t(sit, src.pixels().row_bytes())); + x_iterator_t sit(x_iterator_base_t(&at_c(src(0,0))),src.pixels().pixel_size()); + return type(src.dimensions(),locator_t(sit, src.pixels().row_size())); } }; @@ -411,12 +439,12 @@ namespace detail { template struct __kth_channel_view_basic { private: - typedef typename View::value_type::template kth_element_type::type channel_t; + typedef typename kth_element_type::type channel_t; public: typedef typename view_type::value>::type type; static type make(const View& src) { typedef typename type::x_iterator x_iterator_t; - return interleaved_view(src.width(),src.height(),(x_iterator_t)&at_c(src(0,0)), src.pixels().row_bytes()); + return interleaved_view(src.width(),src.height(),(x_iterator_t)&at_c(src(0,0)), src.pixels().row_size()); } }; @@ -448,15 +476,15 @@ namespace detail { template // SrcP is a reference to PixelConcept (could be pixel value or const/non-const reference) // Examples: pixel, pixel&, const pixel&, planar_pixel_reference, planar_pixel_reference struct kth_channel_deref_fn { - BOOST_STATIC_CONSTANT(bool, is_mutable=is_pixel_reference::value && pixel_reference_is_mutable::value); + BOOST_STATIC_CONSTANT(bool, is_mutable=pixel_is_reference::value && pixel_reference_is_mutable::value); private: typedef typename remove_reference::type src_pixel_t; - typedef typename src_pixel_t::template kth_element_type::type channel_t; + typedef typename kth_element_type::type channel_t; typedef typename src_pixel_t::const_reference const_ref_t; typedef typename pixel_reference_type::type ref_t; public: typedef kth_channel_deref_fn const_t; - typedef pixel value_type; + typedef typename pixel_value_type::type value_type; typedef typename pixel_reference_type::type const_reference; typedef SrcP argument_type; typedef typename mpl::if_c::type reference; @@ -491,7 +519,7 @@ namespace detail { template struct kth_channel_view_type { private: - GIL_CLASS_REQUIRE(View, boost::gil, ImageViewConcept); + GIL_CLASS_REQUIRE(View, boost::gil, ImageViewConcept) typedef detail::__kth_channel_view::value> VB; public: typedef typename VB::type type; diff --git a/include/boost/gil/iterator_from_2d.hpp b/include/boost/gil/iterator_from_2d.hpp index 51cd0f47d0..9fa3d09be1 100644 --- a/include/boost/gil/iterator_from_2d.hpp +++ b/include/boost/gil/iterator_from_2d.hpp @@ -54,7 +54,7 @@ class iterator_from_2d : public iterator_facade, random_access_traversal_tag, typename Loc2::reference, typename Loc2::coord_t> { - GIL_CLASS_REQUIRE(Loc2, boost::gil, PixelLocatorConcept); + GIL_CLASS_REQUIRE(Loc2, boost::gil, PixelLocatorConcept) public: typedef iterator_facade, typename Loc2::value_type, @@ -67,7 +67,8 @@ class iterator_from_2d : public iterator_facade, typedef typename Loc2::point_t point_t; int width() const { return _width; } // number of pixels per image row - int x_pos() const { return _x; } // current x position + int x_pos() const { return _coords.x; } // current x position + int y_pos() const { return _coords.y; } // current y position /// For some reason operator[] provided by iterator_adaptor returns a custom class that is convertible to reference /// We require our own reference because it is registered in iterator_traits @@ -77,27 +78,29 @@ class iterator_from_2d : public iterator_facade, x_iterator& x() { return _p.x(); } iterator_from_2d(){} - iterator_from_2d(const Loc2& p, int width, int x=0) : _x(x), _width(width), _p(p) {} - iterator_from_2d(const iterator_from_2d& pit) : _x(pit._x), _width(pit._width), _p(pit._p) {} - template iterator_from_2d(const iterator_from_2d& pit) : _x(pit._x), _width(pit._width), _p(pit._p) {} + iterator_from_2d(const Loc2& p, int width, int x=0, int y=0) : _coords(x,y), _width(width), _p(p) {} + iterator_from_2d(const iterator_from_2d& pit) : _coords(pit._coords), _width(pit._width), _p(pit._p) {} + template iterator_from_2d(const iterator_from_2d& pit) : _coords(pit._coords), _width(pit._width), _p(pit._p) {} private: template friend class iterator_from_2d; friend class boost::iterator_core_access; reference dereference() const { return *_p; } void increment() { - ++_x; + ++_coords.x; ++_p.x(); - if (_x>=_width) { - _x=0; + if (_coords.x>=_width) { + _coords.x=0; + ++_coords.y; _p+=point_t(-_width,1); } } void decrement() { - --_x; + --_coords.x; --_p.x(); - if (_x<0) { - _x=_width-1; + if (_coords.x<0) { + _coords.x=_width-1; + --_coords.y; _p+=point_t(_width,-1); } } @@ -105,29 +108,30 @@ class iterator_from_2d : public iterator_facade, GIL_FORCEINLINE void advance(difference_type d) { if (_width==0) return; // unfortunately we need to check for that. Default-constructed images have width of 0 and the code below will throw if executed. point_t delta; - if (_x+d>=0) { // not going back to a previous row? - delta.x=(_x+(int)d)%_width - _x; - delta.y=(_x+(int)d)/_width; + if (_coords.x+d>=0) { // not going back to a previous row? + delta.x=(_coords.x+(int)d)%_width - _coords.x; + delta.y=(_coords.x+(int)d)/_width; } else { - delta.x=(_x+(int)d*(1-_width))%_width -_x; - delta.y=-(_width-_x-(int)d-1)/_width; + delta.x=(_coords.x+(int)d*(1-_width))%_width -_coords.x; + delta.y=-(_width-_coords.x-(int)d-1)/_width; } _p+=delta; - _x+=delta.x; + _coords.x+=delta.x; + _coords.y+=delta.y; } difference_type distance_to(const iterator_from_2d& it) const { if (_width==0) return 0; - int xd=it.x_pos()-_x; - return _p.y_distance_to(it._p,xd)*_width+xd; + return (it.y_pos()-_coords.y)*_width + (it.x_pos()-_coords.x); } bool equal(const iterator_from_2d& it) const { assert(_width==it.width()); // they must belong to the same image - return _p==it._p; + return _coords==it._coords && _p==it._p; } - int _x,_width; + point2 _coords; + int _width; Loc2 _p; }; diff --git a/include/boost/gil/locator.hpp b/include/boost/gil/locator.hpp index 32c14a6930..bae5c883d7 100644 --- a/include/boost/gil/locator.hpp +++ b/include/boost/gil/locator.hpp @@ -35,9 +35,9 @@ namespace boost { namespace gil { //forward declarations -template ptrdiff_t byte_step(const P*); -template P* byte_advanced(const P* p, ptrdiff_t byteDiff); -template P& byte_advanced_ref(P* p, ptrdiff_t byteDiff); +template ptrdiff_t memunit_step(const P*); +template P* memunit_advanced(const P* p, ptrdiff_t diff); +template P& memunit_advanced_ref(P* p, ptrdiff_t diff); template struct iterator_add_deref; template class point2; namespace detail { @@ -50,6 +50,7 @@ template struct dynamic_y_step_type; template struct channel_type; template struct color_space_type; template struct channel_mapping_type; +template struct is_planar; template struct num_channels; // The type of a locator or a view that has X and Y swapped. By default it is the same @@ -77,7 +78,7 @@ template struct transposed_type { /// Also 2D difference between two locators cannot be computed without knowledge of the X position within the image. /// /// This base class provides most of the methods and typedefs needed to create a model of a locator. GIL provides two -/// locator models as subclasses of \p pixel_2d_locator_base. A memory-based locator, \p byte_addressable_2d_locator and a virtual +/// locator models as subclasses of \p pixel_2d_locator_base. A memory-based locator, \p memory_based_2d_locator and a virtual /// locator, \p virtual_2d_locator. /// The minimum functionality a subclass must provide is this: /// \code @@ -215,7 +216,7 @@ struct channel_mapping_type > : public channe template struct is_planar > : public is_planar {}; -/// \class byte_addressable_2d_locator +/// \class memory_based_2d_locator /// \brief Memory-based pixel locator. Models: PixelLocatorConcept,HasDynamicXStepTypeConcept,HasDynamicYStepTypeConcept,HasTransposedTypeConcept /// \ingroup PixelLocatorModel PixelBasedModel /// @@ -230,19 +231,19 @@ struct is_planar > : public is_planar {} /// one std::ptrdiff_t for the horizontal step of two and a CMYK planar_pixel_iterator consisting of 4 pointers (24 bytes). /// In this case ++locator.x() results in four native pointer additions. /// -/// Note also that \p byte_addressable_2d_locator does not require that its element type be a pixel. It could be +/// Note also that \p memory_based_2d_locator does not require that its element type be a pixel. It could be /// instantiated with an iterator whose \p value_type models only \p Regular. In this case the locator /// models the weaker RandomAccess2DLocatorConcept, and does not model PixelBasedConcept. /// Many generic algorithms don't require the elements to be pixels. //////////////////////////////////////////////////////////////////////////////////////// template -class byte_addressable_2d_locator : public pixel_2d_locator_base, typename iterator_adaptor_get_base::type, StepIterator> { - typedef byte_addressable_2d_locator this_t; - GIL_CLASS_REQUIRE(StepIterator, boost::gil, StepIteratorConcept); +class memory_based_2d_locator : public pixel_2d_locator_base, typename iterator_adaptor_get_base::type, StepIterator> { + typedef memory_based_2d_locator this_t; + GIL_CLASS_REQUIRE(StepIterator, boost::gil, StepIteratorConcept) public: - typedef pixel_2d_locator_base, typename iterator_adaptor_get_base::type, StepIterator> parent_t; - typedef byte_addressable_2d_locator::type> const_t; // same as this type, but over const values + typedef pixel_2d_locator_base, typename iterator_adaptor_get_base::type, StepIterator> parent_t; + typedef memory_based_2d_locator::type> const_t; // same as this type, but over const values typedef typename parent_t::coord_t coord_t; typedef typename parent_t::x_coord_t x_coord_t; @@ -253,22 +254,22 @@ class byte_addressable_2d_locator : public pixel_2d_locator_base struct add_deref { - typedef byte_addressable_2d_locator::type> type; - static type make(const byte_addressable_2d_locator& loc, const Deref& nderef) { + typedef memory_based_2d_locator::type> type; + static type make(const memory_based_2d_locator& loc, const Deref& nderef) { return type(iterator_add_deref::make(loc.y(),nderef)); } }; - byte_addressable_2d_locator() {} - byte_addressable_2d_locator(const StepIterator& yit) : _p(yit) {} - template byte_addressable_2d_locator(const byte_addressable_2d_locator& loc, coord_t y_step) : _p(loc.x(), loc.row_bytes()*y_step) {} - template byte_addressable_2d_locator(const byte_addressable_2d_locator& loc, coord_t x_step, coord_t y_step, bool transpose=false) - : _p(make_step_iterator(loc.x(),(transpose ? loc.row_bytes() : loc.pix_bytestep())*x_step), - (transpose ? loc.pix_bytestep() : loc.row_bytes())*y_step ) {} + memory_based_2d_locator() {} + memory_based_2d_locator(const StepIterator& yit) : _p(yit) {} + template memory_based_2d_locator(const memory_based_2d_locator& loc, coord_t y_step) : _p(loc.x(), loc.row_size()*y_step) {} + template memory_based_2d_locator(const memory_based_2d_locator& loc, coord_t x_step, coord_t y_step, bool transpose=false) + : _p(make_step_iterator(loc.x(),(transpose ? loc.row_size() : loc.pixel_size())*x_step), + (transpose ? loc.pixel_size() : loc.row_size())*y_step ) {} - byte_addressable_2d_locator(x_iterator xit, std::ptrdiff_t row_bytes) : _p(xit,row_bytes) {} - template byte_addressable_2d_locator(const byte_addressable_2d_locator& pl) : _p(pl._p) {} - byte_addressable_2d_locator(const byte_addressable_2d_locator& pl) : _p(pl._p) {} + memory_based_2d_locator(x_iterator xit, std::ptrdiff_t row_bytes) : _p(xit,row_bytes) {} + template memory_based_2d_locator(const memory_based_2d_locator& pl) : _p(pl._p) {} + memory_based_2d_locator(const memory_based_2d_locator& pl) : _p(pl._p) {} bool operator==(const this_t& p) const { return _p==p._p; } @@ -278,37 +279,37 @@ class byte_addressable_2d_locator : public pixel_2d_locator_base friend class byte_addressable_2d_locator; - std::ptrdiff_t byte_offset(x_coord_t x, y_coord_t y) const { return y*row_bytes() + x*pix_bytestep(); } + template friend class memory_based_2d_locator; + std::ptrdiff_t offset(x_coord_t x, y_coord_t y) const { return y*row_size() + x*pixel_size(); } StepIterator _p; }; @@ -317,19 +318,19 @@ class byte_addressable_2d_locator : public pixel_2d_locator_base -struct color_space_type > : public color_space_type::parent_t> { +struct color_space_type > : public color_space_type::parent_t> { }; template -struct channel_mapping_type > : public channel_mapping_type::parent_t> { +struct channel_mapping_type > : public channel_mapping_type::parent_t> { }; template -struct is_planar > : public is_planar::parent_t> { +struct is_planar > : public is_planar::parent_t> { }; template -struct channel_type > : public channel_type::parent_t> { +struct channel_type > : public channel_type::parent_t> { }; ///////////////////////////// @@ -338,13 +339,13 @@ struct channel_type > : public channel_type -struct dynamic_x_step_type > { +struct dynamic_x_step_type > { private: typedef typename iterator_adaptor_get_base::type base_iterator_t; typedef typename dynamic_x_step_type::type base_iterator_step_t; typedef typename iterator_adaptor_rebind::type dynamic_step_base_t; public: - typedef byte_addressable_2d_locator type; + typedef memory_based_2d_locator type; }; ///////////////////////////// @@ -352,8 +353,8 @@ struct dynamic_x_step_type > { ///////////////////////////// template -struct dynamic_y_step_type > { - typedef byte_addressable_2d_locator type; +struct dynamic_y_step_type > { + typedef memory_based_2d_locator type; }; } } // namespace boost::gil diff --git a/include/boost/gil/metafunctions.hpp b/include/boost/gil/metafunctions.hpp index 119494d212..a476bd9ed3 100644 --- a/include/boost/gil/metafunctions.hpp +++ b/include/boost/gil/metafunctions.hpp @@ -24,20 +24,28 @@ //////////////////////////////////////////////////////////////////////////////////////// #include -#include +#include +#include #include +#include +#include +#include +#include +#include #include #include "gil_config.hpp" #include "gil_concept.hpp" +#include "channel.hpp" namespace boost { namespace gil { // forward declarations template struct pixel; +template struct packed_pixel; template struct planar_pixel_reference; template struct planar_pixel_iterator; -template class byte_addressable_step_iterator; -template class byte_addressable_2d_locator; +template class memory_based_step_iterator; +template class memory_based_2d_locator; template class image_view; template class image; template struct channel_type; @@ -45,7 +53,7 @@ template struct color_space_type; template struct channel_mapping_type; template struct is_iterator_adaptor; template struct iterator_adaptor_get_base; - +template struct bit_aligned_pixel_reference; ////////////////////////////////////////////////// /// @@ -73,7 +81,7 @@ template struct pixel_reference_is_basic struct iterator_is_basic : public mpl::false_ {}; @@ -86,19 +94,19 @@ struct iterator_is_basic > : public mpl::true template // immutable planar struct iterator_is_basic > : public mpl::true_ {}; template // mutable interleaved step -struct iterator_is_basic*> > : public mpl::true_ {}; +struct iterator_is_basic*> > : public mpl::true_ {}; template // immutable interleaved step -struct iterator_is_basic*> > : public mpl::true_ {}; +struct iterator_is_basic*> > : public mpl::true_ {}; template // mutable planar step -struct iterator_is_basic > > : public mpl::true_ {}; +struct iterator_is_basic > > : public mpl::true_ {}; template // immutable planar step -struct iterator_is_basic > > : public mpl::true_ {}; +struct iterator_is_basic > > : public mpl::true_ {}; /// \ingroup GILIsBasic /// \brief Determines if a given locator is basic. A basic locator is memory-based and has basic x_iterator and y_iterator template struct locator_is_basic : public mpl::false_ {}; -template struct locator_is_basic > > : public iterator_is_basic {}; +template struct locator_is_basic > > : public iterator_is_basic {}; /// \ingroup GILIsBasic /// \brief Basic views must be over basic locators @@ -152,6 +160,18 @@ template struct view_is_step_in_x : public locator_is_step_in_x struct view_is_step_in_y : public locator_is_step_in_y {}; +/// \brief Determines whether the given pixel reference is a proxy class or a native C++ reference +/// \ingroup TypeAnalysis +template +struct pixel_reference_is_proxy + : public mpl::not_::type, + typename remove_const_and_reference::type::value_type> > {}; + +/// \brief Given a model of a pixel, determines whether the model represents a pixel reference (as opposed to pixel value) +/// \ingroup TypeAnalysis +template +struct pixel_is_reference : public mpl::or_, pixel_reference_is_proxy > {}; + /// \defgroup GILIsMutable xxx_is_mutable /// \ingroup TypeAnalysis /// \brief Determines if the given pixel reference/iterator/locator/view is mutable (i.e. its pixels can be changed) @@ -160,11 +180,9 @@ template struct view_is_step_in_y : public locator_is_step_in_y struct pixel_reference_is_mutable : public mpl::bool_::type::is_mutable> {}; -template struct pixel_reference_is_mutable< pixel&> : public mpl::true_ {}; -template struct pixel_reference_is_mutable&> : public mpl::false_ {}; -template struct pixel_reference_is_mutable< planar_pixel_reference > : public mpl::bool_< channel_traits::is_mutable > {}; -template struct pixel_reference_is_mutable > : public mpl::bool_< channel_traits::is_mutable > {}; +template struct pixel_reference_is_mutable : public mpl::bool_::type::is_mutable> {}; +template struct pixel_reference_is_mutable + : public mpl::and_, pixel_reference_is_mutable > {}; /// \ingroup GILIsMutable /// \brief Determines if the given locator is mutable (i.e. its pixels can be changed) @@ -174,10 +192,6 @@ template struct locator_is_mutable : public iterator_is_mutable struct view_is_mutable : public iterator_is_mutable {}; -/// \brief Determines if the given object is a GIL pixel reference (as opposed to a pixel value or anything else). Custom models of references must provide specializations. -/// \ingroup TypeAnalysis -template struct is_pixel_reference : public pixel_reference_is_basic {}; - ////////////////////////////////////////////////// /// /// TYPE FACTORY METAFUNCTIONS @@ -216,6 +230,9 @@ template struct iterator_type_from_pixel template struct iterator_type_from_pixel { typedef planar_pixel_iterator::type>::const_pointer,typename color_space_type::type> type; }; +template struct iterator_type_from_pixel { + typedef memory_based_step_iterator::type> type; +}; /// \ingroup TypeFactoryFromElements /// \brief Returns the type of a homogeneous iterator given the channel type, layout, whether it operates on planar data, whether it is a step iterator, and whether it is mutable @@ -225,18 +242,159 @@ template struct iterator_type { template struct iterator_type { typedef planar_pixel_iterator type; }; // TODO: Assert M=identity template struct iterator_type { typedef planar_pixel_iterator type; }; // TODO: Assert M=identity template struct iterator_type { - typedef byte_addressable_step_iterator::type> type; + typedef memory_based_step_iterator::type> type; }; /// \brief Given a pixel iterator defining access to pixels along a row, returns the types of the corresponding built-in step_iterator, xy_locator, image_view /// \ingroup TypeFactory template struct type_from_x_iterator { - typedef byte_addressable_step_iterator step_iterator_t; - typedef byte_addressable_2d_locator xy_locator_t; + typedef memory_based_step_iterator step_iterator_t; + typedef memory_based_2d_locator xy_locator_t; typedef image_view view_t; }; +namespace detail { + template + struct packed_channel_reference_type { + typedef const packed_channel_reference type; + }; + + template + class packed_channel_references_vector_type { + // If ChannelBitSizesVector is mpl::vector + // Then first_bits_vector will be mpl::vector + typedef typename mpl::accumulate >, + mpl::push_back, mpl::_2> > >::type first_bits_vector; + public: + typedef typename mpl::transform::type, ChannelBitSizesVector, + packed_channel_reference_type >::type type; + }; + +} + +/// \ingroup TypeFactoryFromElements +/// \brief Returns the type of a packed pixel given its bitfield type, the bit size of its channels and its layout. +/// +/// A packed pixel has channels that cover bit ranges but itself is byte aligned. RGB565 pixel is an example. +/// +/// The size of ChannelBitSizeVector must equal the number of channels in the given layout +/// The sum of bit sizes for all channels must be less than or equal to the number of bits in BitField (and cannot exceed 64). +/// If it is less than the number of bits in BitField, the last bits will be unused. +template +struct packed_pixel_type { + typedef packed_pixel::type, Layout> type; +}; + +/// \defgroup TypeFactoryPacked packed_image_type,bit_aligned_image_type +/// \ingroup TypeFactoryFromElements +/// \brief Returns the type of an image whose channels are not byte-aligned. +/// +/// A packed image is an image whose pixels are byte aligned, such as "rgb565".
              +/// A bit-aligned image is an image whose pixels are not byte aligned, such as "rgb222".
              +/// +/// The sum of the bit sizes of all channels cannot exceed 64. + +/// \ingroup TypeFactoryPacked +/// \brief Returns the type of an interleaved packed image: an image whose channels may not be byte-aligned, but whose pixels are byte aligned. +template > +struct packed_image_type { + typedef image::type,false,Alloc> type; +}; + +/// \ingroup TypeFactoryPacked +/// \brief Returns the type of a single-channel image given its bitfield type, the bit size of its channel and its layout +template > +struct packed_image1_type : public packed_image_type, Layout, Alloc> {}; + +/// \ingroup TypeFactoryPacked +/// \brief Returns the type of a two channel image given its bitfield type, the bit size of its channels and its layout +template > +struct packed_image2_type : public packed_image_type, Layout, Alloc> {}; + +/// \ingroup TypeFactoryPacked +/// \brief Returns the type of a three channel image given its bitfield type, the bit size of its channels and its layout +template > +struct packed_image3_type : public packed_image_type, Layout, Alloc> {}; + +/// \ingroup TypeFactoryPacked +/// \brief Returns the type of a four channel image given its bitfield type, the bit size of its channels and its layout +template > +struct packed_image4_type : public packed_image_type, Layout, Alloc> {}; + +/// \ingroup TypeFactoryPacked +/// \brief Returns the type of a five channel image given its bitfield type, the bit size of its channels and its layout +template > +struct packed_image5_type : public packed_image_type, Layout, Alloc> {}; + + +/// \ingroup TypeFactoryPacked +/// \brief Returns the type of a packed image whose pixels may not be byte aligned. For example, an "rgb222" image is bit-aligned because its pixel spans six bits. +/// +/// Note that the alignment parameter in the constructor of bit-aligned images is in bit units. For example, if you want to construct a bit-aligned +/// image whose rows are byte-aligned, use 8 as the alignment parameter, not 1. + +template > +struct bit_aligned_image_type { +private: + typedef const bit_aligned_pixel_reference bit_alignedref_t; +public: + typedef image type; +}; + +/// \ingroup TypeFactoryPacked +/// \brief Returns the type of a single-channel bit-aligned image given the bit size of its channel and its layout +template > +struct bit_aligned_image1_type : public bit_aligned_image_type, Layout, Alloc> {}; + +/// \ingroup TypeFactoryPacked +/// \brief Returns the type of a two channel bit-aligned image given the bit size of its channels and its layout +template > +struct bit_aligned_image2_type : public bit_aligned_image_type, Layout, Alloc> {}; + +/// \ingroup TypeFactoryPacked +/// \brief Returns the type of a three channel bit-aligned image given the bit size of its channels and its layout +template > +struct bit_aligned_image3_type : public bit_aligned_image_type, Layout, Alloc> {}; + +/// \ingroup TypeFactoryPacked +/// \brief Returns the type of a four channel bit-aligned image given the bit size of its channels and its layout +template > +struct bit_aligned_image4_type : public bit_aligned_image_type, Layout, Alloc> {}; + +/// \ingroup TypeFactoryPacked +/// \brief Returns the type of a five channel bit-aligned image given the bit size of its channels and its layout +template > +struct bit_aligned_image5_type : public bit_aligned_image_type, Layout, Alloc> {}; + + + +/// \ingroup TypeFactoryFromElements +/// \brief Returns the type of a homogeneous pixel given the channel type and layout +template +struct pixel_value_type { + typedef pixel type; // by default use gil::pixel. Specializations are provided for +}; + +// Specializations for packed channels +template +struct pixel_value_type< packed_dynamic_channel_reference,Layout> : + public packed_pixel_type, Layout> {}; +template +struct pixel_value_type,Layout> : + public packed_pixel_type, Layout> {}; + +template +struct pixel_value_type< packed_channel_reference,Layout> : + public packed_pixel_type, Layout> {}; +template +struct pixel_value_type,Layout> : + public packed_pixel_type, Layout> {}; + +template +struct pixel_value_type,Layout> : + public packed_pixel_type::type, mpl::vector1_c, Layout> {}; + /// \ingroup TypeFactoryFromElements /// \brief Returns the type of a homogeneous locator given the channel type, layout, whether it operates on planar data and whether it has a step horizontally diff --git a/include/boost/gil/packed_pixel.hpp b/include/boost/gil/packed_pixel.hpp index 68d99ac1b5..cb8a4aa9d7 100644 --- a/include/boost/gil/packed_pixel.hpp +++ b/include/boost/gil/packed_pixel.hpp @@ -31,91 +31,140 @@ namespace boost { namespace gil { -/// \defgroup ColorBaseModelPackedPixel heterogeneous_packed_pixel +/// \defgroup ColorBaseModelPackedPixel packed_pixel /// \ingroup ColorBaseModel /// \brief A heterogeneous color base whose elements are reference proxies to channels in a pixel. Models ColorBaseValueConcept. This class is used to model packed pixels, such as 16-bit packed RGB. -/// \defgroup PixelModelPackedPixel heterogeneous_packed_pixel -/// \ingroup PixelModel -/// \brief A heterogeneous pixel used to represent packed pixels with non-byte-aligned channels. Models PixelValueConcept +/** +\defgroup PixelModelPackedPixel packed_pixel +\ingroup PixelModel +\brief A heterogeneous pixel used to represent packed pixels with non-byte-aligned channels. Models PixelValueConcept + +Example: +\code +typedef packed_pixel_type, rgb_layout_t>::type rgb565_pixel_t; +BOOST_STATIC_ASSERT((sizeof(rgb565_pixel_t)==2)); + +rgb565_pixel_t r565; +get_color(r565,red_t()) = 31; +get_color(r565,green_t()) = 63; +get_color(r565,blue_t()) = 31; +assert(r565 == rgb565_pixel_t((uint16_t)0xFFFF)); +\endcode +*/ /// \ingroup ColorBaseModelPackedPixel PixelModelPackedPixel PixelBasedModel -/// \brief Heterogeneous pixel value whose channel references can be constructed from the pixel data and their index. Models ColorBaseValueConcept, PixelValueConcept, PixelBasedConcept +/// \brief Heterogeneous pixel value whose channel references can be constructed from the pixel bitfield and their index. Models ColorBaseValueConcept, PixelValueConcept, PixelBasedConcept /// Typical use for this is a model of a packed pixel (like 565 RGB) -template -struct heterogeneous_packed_pixel { - PixelData _data; - - // required by ColorBaseConcept, MutableColorBaseConcept - typedef Layout layout_t; - template struct kth_element_type : public mpl::at_c {}; - template struct kth_element_reference_type : public mpl::at_c {}; - template struct kth_element_const_reference_type { - typedef typename channel_traits::type>::const_reference type; - }; - - typedef heterogeneous_packed_pixel value_type; - typedef value_type& reference; - typedef const value_type& const_reference; +template // Layout defining the color space and ordering of the channels. Example value: rgb_layout_t +struct packed_pixel { + BitField _bitfield; + + typedef Layout layout_t; + typedef packed_pixel value_type; + typedef value_type& reference; + typedef const value_type& const_reference; BOOST_STATIC_CONSTANT(bool, is_mutable = channel_traits::type>::is_mutable); - heterogeneous_packed_pixel(){} - heterogeneous_packed_pixel(const PixelData& data) : _data(data) {} + packed_pixel(){} + explicit packed_pixel(const BitField& bitfield) : _bitfield(bitfield) {} // Construct from another compatible pixel type - heterogeneous_packed_pixel(const heterogeneous_packed_pixel& p) : _data(p._data) {} - template heterogeneous_packed_pixel(const P& p) { check_compatible

              (); static_copy(p,*this); } - - template heterogeneous_packed_pixel& operator=(const P& p) { check_compatible

              (); static_copy(p,*this); return *this; } - heterogeneous_packed_pixel& operator=(const heterogeneous_packed_pixel& p) { _data=p._data; return *this; } - - template bool operator==(const P& p) const { check_compatible

              (); return static_equal(*this,p); } - template bool operator!=(const P& p) const { return !(*this==p); } + packed_pixel(const packed_pixel& p) : _bitfield(p._bitfield) {} + template packed_pixel(const P& p, typename enable_if_c::value>::type* d=0) { check_compatible

              (); static_copy(p,*this); } + packed_pixel(int chan0, int chan1) : _bitfield(0) { + BOOST_STATIC_ASSERT((num_channels::value==2)); + at_c<0>(*this)=chan0; at_c<1>(*this)=chan1; + } + packed_pixel(int chan0, int chan1, int chan2) : _bitfield(0) { + BOOST_STATIC_ASSERT((num_channels::value==3)); + at_c<0>(*this)=chan0; at_c<1>(*this)=chan1; at_c<2>(*this)=chan2; + } + packed_pixel(int chan0, int chan1, int chan2, int chan3) : _bitfield(0) { + BOOST_STATIC_ASSERT((num_channels::value==4)); + at_c<0>(*this)=chan0; at_c<1>(*this)=chan1; at_c<2>(*this)=chan2; at_c<2>(*this)=chan3; + } + packed_pixel(int chan0, int chan1, int chan2, int chan3, int chan4) : _bitfield(0) { + BOOST_STATIC_ASSERT((num_channels::value==5)); + at_c<0>(*this)=chan0; at_c<1>(*this)=chan1; at_c<2>(*this)=chan2; at_c<2>(*this)=chan3; at_c<3>(*this)=chan4; + } + + packed_pixel& operator=(const packed_pixel& p) { _bitfield=p._bitfield; return *this; } + + template packed_pixel& operator=(const P& p) { assign(p, mpl::bool_::value>()); return *this; } + template bool operator==(const P& p) const { return equal(p, mpl::bool_::value>()); } + + template bool operator!=(const P& p) const { return !(*this==p); } private: - template static void check_compatible() { gil_function_requires >(); } + template static void check_compatible() { gil_function_requires >(); } + template void assign(const Pixel& p, mpl::true_) { check_compatible(); static_copy(p,*this); } + template bool equal(const Pixel& p, mpl::true_) const { check_compatible(); return static_equal(*this,p); } + +// Support for assignment/equality comparison of a channel with a grayscale pixel + static void check_gray() { BOOST_STATIC_ASSERT((is_same::value)); } + template void assign(const Channel& chan, mpl::false_) { check_gray(); at_c<0>(*this)=chan; } + template bool equal (const Channel& chan, mpl::false_) const { check_gray(); return at_c<0>(*this)==chan; } +public: + packed_pixel& operator= (int chan) { check_gray(); at_c<0>(*this)=chan; return *this; } + bool operator==(int chan) const { check_gray(); return at_c<0>(*this)==chan; } }; -/// \brief Metafunction predicate that flags heterogeneous_packed_pixel as a model of PixelConcept. Required by PixelConcept -/// \ingroup PixelModelPackedPixel -template -struct is_pixel > : public mpl::true_{}; +///////////////////////////// +// ColorBasedConcept +///////////////////////////// + +template +struct kth_element_type,K> : public mpl::at_c {}; + +template +struct kth_element_reference_type,K> : public mpl::at_c {}; + +template +struct kth_element_const_reference_type,K> { + typedef typename channel_traits::type>::const_reference type; +}; -/// \brief mutable at_c required by MutableColorBaseConcept -/// \ingroup ColorBaseModelPackedPixel template inline -typename heterogeneous_packed_pixel::template kth_element_reference_type::type -at_c(heterogeneous_packed_pixel& p) { - return typename heterogeneous_packed_pixel::template kth_element_reference_type::type(p._data); +typename kth_element_reference_type, K>::type +at_c(packed_pixel& p) { + return typename kth_element_reference_type, K>::type(&p._bitfield); } -/// \brief constant at_c required by ColorBaseConcept -/// \ingroup ColorBaseModelPackedPixel template inline -typename heterogeneous_packed_pixel::template kth_element_const_reference_type::type -at_c(const heterogeneous_packed_pixel& p) { - return typename heterogeneous_packed_pixel::template kth_element_const_reference_type::type(p._data); +typename kth_element_const_reference_type, K>::type +at_c(const packed_pixel& p) { + return typename kth_element_const_reference_type, K>::type(&p._bitfield); } -/// \brief Specifies the color space type of a heterogeneous packed pixel. Required by PixelBasedConcept -/// \ingroup PixelModelPackedPixel +///////////////////////////// +// PixelConcept +///////////////////////////// + +// Metafunction predicate that flags packed_pixel as a model of PixelConcept. Required by PixelConcept +template +struct is_pixel > : public mpl::true_{}; + +///////////////////////////// +// PixelBasedConcept +///////////////////////////// + template -struct color_space_type > { +struct color_space_type > { typedef typename Layout::color_space_t type; }; -/// \brief Specifies the channel mapping of a heterogeneous packed pixel. Required by PixelBasedConcept -/// \ingroup PixelModelPackedPixel template -struct channel_mapping_type > { +struct channel_mapping_type > { typedef typename Layout::channel_mapping_t type; }; -/// \brief Specifies that the heterogeneous packed pixel is not planar. Required by PixelBasedConcept -/// \ingroup PixelModelPackedPixel template -struct is_planar > : mpl::false_ {}; +struct is_planar > : mpl::false_ {}; + //////////////////////////////////////////////////////////////////////////////// /// @@ -123,61 +172,22 @@ struct is_planar > : mpl::false_ {}; /// //////////////////////////////////////////////////////////////////////////////// -/// \defgroup PixelIteratorModelPackedInterleavedPtr Pointer to heterogeneous_packed_pixel +/// \defgroup PixelIteratorModelPackedInterleavedPtr Pointer to packed_pixel /// \ingroup PixelIteratorModel /// \brief Iterators over interleaved pixels. -/// The pointer heterogeneous_packed_pixel* is used as an iterator over interleaved pixels of packed format. Models PixelIteratorConcept, HasDynamicXStepTypeConcept, ByteAdvanceableIteratorConcept +/// The pointer packed_pixel* is used as an iterator over interleaved pixels of packed format. Models PixelIteratorConcept, HasDynamicXStepTypeConcept, MemoryBasedIteratorConcept template -struct iterator_is_mutable*> : public mpl::bool_::is_mutable> {}; +struct iterator_is_mutable*> : public mpl::bool_::is_mutable> {}; template -struct iterator_is_mutable*> : public mpl::false_ {}; - -///////////////////////////// -// HasDynamicXStepTypeConcept -///////////////////////////// - -/// \ingroup PixelIteratorModelPackedInterleavedPtr -template -struct dynamic_x_step_type*> { - typedef byte_addressable_step_iterator*> type; -}; - -/// \ingroup PixelIteratorModelPackedInterleavedPtr -template -struct dynamic_x_step_type*> { - typedef byte_addressable_step_iterator*> type; -}; - - -///////////////////////////// -// PixelBasedConcept -///////////////////////////// - -template -struct color_space_type*> : public color_space_type > {}; - -template -struct channel_mapping_type*> : public channel_mapping_type > {}; - -template -struct is_planar*> : public is_planar > {}; - - -template -struct color_space_type*> : public color_space_type > {}; - -template -struct channel_mapping_type*> : public channel_mapping_type > {}; +struct iterator_is_mutable*> : public mpl::false_ {}; -template -struct is_planar*> : public is_planar > {}; } } // namespace boost::gil namespace boost { template - struct has_trivial_constructor > : public has_trivial_constructor

              {}; + struct has_trivial_constructor > : public has_trivial_constructor

              {}; } #endif diff --git a/include/boost/gil/pixel.hpp b/include/boost/gil/pixel.hpp index 47af2dc8ae..45c6fceaaa 100644 --- a/include/boost/gil/pixel.hpp +++ b/include/boost/gil/pixel.hpp @@ -58,6 +58,22 @@ template struct is_pixel : public is_pixel {}; template struct num_channels : public mpl::size::type> {}; +/** +\addtogroup PixelBasedAlgorithm + +Example: +\code +BOOST_STATIC_ASSERT((num_channels::value==3)); +BOOST_STATIC_ASSERT((num_channels::value==4)); + +BOOST_STATIC_ASSERT((is_planar::value)); +BOOST_STATIC_ASSERT((is_same::type, rgb_t>::value)); +BOOST_STATIC_ASSERT((is_same::type, + channel_mapping_type::type>::value)); +BOOST_STATIC_ASSERT((is_same::type, bits8>::value)); +\endcode +*/ + /// \defgroup ColorBaseModelPixel pixel /// \ingroup ColorBaseModel /// \brief A homogeneous color base whose element is a channel value. Models HomogeneousColorBaseValueConcept @@ -134,8 +150,34 @@ struct pixel : public detail::homogeneous_color_base(*this)==chan; } }; -/// \brief Metafunction predicate that flags pixel as a model of PixelConcept. Required by PixelConcept -/// \ingroup PixelModelPixel +///////////////////////////// +// ColorBasedConcept +///////////////////////////// + +template +struct kth_element_type, K> { + typedef ChannelValue type; +}; + +template +struct kth_element_reference_type, K> { + typedef typename channel_traits::reference type; +}; + +template +struct kth_element_reference_type, K> { + typedef typename channel_traits::const_reference type; +}; + +template +struct kth_element_const_reference_type, K> { + typedef typename channel_traits::const_reference type; +}; + +///////////////////////////// +// PixelConcept +///////////////////////////// + template struct is_pixel > : public mpl::true_{}; diff --git a/include/boost/gil/pixel_iterator.hpp b/include/boost/gil/pixel_iterator.hpp index 11d7a9a7db..5d41722735 100644 --- a/include/boost/gil/pixel_iterator.hpp +++ b/include/boost/gil/pixel_iterator.hpp @@ -32,7 +32,7 @@ namespace boost { namespace gil { //forwarded declaration (as this file is included in step_iterator.hpp) template -class byte_addressable_step_iterator; +class memory_based_step_iterator; template struct dynamic_x_step_type; @@ -66,10 +66,10 @@ struct iterator_is_mutable{}; template struct iterator_is_mutable< T*> : public mpl::true_{}; template struct iterator_is_mutable : public mpl::false_{}; -/// \defgroup PixelIteratorModelInterleavedPtr Pointer to pixel +/// \defgroup PixelIteratorModelInterleavedPtr C pointer to a pixel /// \ingroup PixelIteratorModel /// \brief Iterators over interleaved pixels. -/// The pointer pixel* is used as an iterator over interleaved pixels. Models PixelIteratorConcept, HomogeneousPixelBasedConcept, HasDynamicXStepTypeConcept, ByteAdvanceableIteratorConcept +/// A C pointer to a model of PixelValueConcept is used as an iterator over interleaved pixels. Models PixelIteratorConcept, HomogeneousPixelBasedConcept, HasDynamicXStepTypeConcept, MemoryBasedIteratorConcept @@ -78,15 +78,15 @@ template struct iterator_is_mutable : public mpl::false_{ ///////////////////////////// /// \ingroup PixelIteratorModelInterleavedPtr -template -struct dynamic_x_step_type*> { - typedef byte_addressable_step_iterator*> type; +template +struct dynamic_x_step_type { + typedef memory_based_step_iterator type; }; /// \ingroup PixelIteratorModelInterleavedPtr -template -struct dynamic_x_step_type*> { - typedef byte_addressable_step_iterator*> type; +template +struct dynamic_x_step_type { + typedef memory_based_step_iterator type; }; @@ -94,71 +94,63 @@ struct dynamic_x_step_type*> { // PixelBasedConcept ///////////////////////////// -template -struct color_space_type*> { - typedef typename L::color_space_t type; -}; +template struct color_space_type< Pixel*> : public color_space_type {}; +template struct color_space_type : public color_space_type {}; -template -struct channel_mapping_type*> { - typedef typename L::channel_mapping_t type; -}; +template struct channel_mapping_type< Pixel*> : public channel_mapping_type {}; +template struct channel_mapping_type : public channel_mapping_type {}; -template -struct is_planar*> : public mpl::false_ {}; +template struct is_planar< Pixel*> : public is_planar {}; +template struct is_planar : public is_planar {}; ///////////////////////////// // HomogeneousPixelBasedConcept ///////////////////////////// -template -struct channel_type*> { - typedef T type; -}; - -template struct color_space_type*> : public color_space_type*> {}; -template struct channel_mapping_type*> : public channel_mapping_type*> {}; -template struct is_planar*> : public is_planar*> {}; -template struct channel_type*> : public channel_type*> {}; +template struct channel_type : public channel_type {}; +template struct channel_type : public channel_type {}; //////////////////////////////////////////////////////////////////////////////////////// /// -/// Support for pixel iterator movement measured in raw bytes (as opposed to pixel type). \n +/// Support for pixel iterator movement measured in memory units (bytes or bits) as opposed to pixel type. \n /// Necessary to handle image row alignment and channel plane alignment. /// //////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////// -// ByteAdvanceableIteratorConcept +// MemoryBasedIteratorConcept ///////////////////////////// +template +struct byte_to_memunit : public mpl::int_<1> {}; + template -inline std::ptrdiff_t byte_step(const P*) { return sizeof(P); } +inline std::ptrdiff_t memunit_step(const P*) { return sizeof(P); } template -inline std::ptrdiff_t byte_distance(const P* p1, const P* p2) { +inline std::ptrdiff_t memunit_distance(const P* p1, const P* p2) { return (gil_reinterpret_cast_c(p2)-gil_reinterpret_cast_c(p1)); } -template P* byte_advanced(const P* p, std::ptrdiff_t byteDiff); +template P* memunit_advanced(const P* p, std::ptrdiff_t diff); template -inline void byte_advance(P* &p, std::ptrdiff_t byteDiff) { - p=(P*)((unsigned char*)(p)+byteDiff); +inline void memunit_advance(P* &p, std::ptrdiff_t diff) { + p=(P*)((unsigned char*)(p)+diff); } template -inline P* byte_advanced(const P* p, std::ptrdiff_t byteDiff) { - return (P*)((unsigned char*)(p)+byteDiff); +inline P* memunit_advanced(const P* p, std::ptrdiff_t diff) { + return (P*)((unsigned char*)(p)+diff); } -// byte_advanced_ref -// (shortcut to advancing a pointer by a given number of bytes and taking the reference in case the compiler is not smart enough) +// memunit_advanced_ref +// (shortcut to advancing a pointer by a given number of memunits and taking the reference in case the compiler is not smart enough) template -inline P& byte_advanced_ref(P* p, std::ptrdiff_t byteDiff) { - return *byte_advanced(p,byteDiff); +inline P& memunit_advanced_ref(P* p, std::ptrdiff_t diff) { + return *memunit_advanced(p,diff); } } } // namespace boost::gil diff --git a/include/boost/gil/pixel_iterator_adaptor.hpp b/include/boost/gil/pixel_iterator_adaptor.hpp index 8d673fd891..9c01fc962c 100644 --- a/include/boost/gil/pixel_iterator_adaptor.hpp +++ b/include/boost/gil/pixel_iterator_adaptor.hpp @@ -129,42 +129,45 @@ struct channel_type > : public channel_type< ///////////////////////////// -// ByteAdvanceableIteratorConcept +// MemoryBasedIteratorConcept ///////////////////////////// +template +struct byte_to_memunit > : public byte_to_memunit {}; + template inline typename std::iterator_traits::difference_type -byte_step(const dereference_iterator_adaptor& p) { - return byte_step(p.base()); +memunit_step(const dereference_iterator_adaptor& p) { + return memunit_step(p.base()); } template inline typename std::iterator_traits::difference_type -byte_distance(const dereference_iterator_adaptor& p1, +memunit_distance(const dereference_iterator_adaptor& p1, const dereference_iterator_adaptor& p2) { - return byte_distance(p1.base(),p2.base()); + return memunit_distance(p1.base(),p2.base()); } template -inline void byte_advance(dereference_iterator_adaptor& p, - typename std::iterator_traits::difference_type byteDiff) { - byte_advance(p.base(), byteDiff); +inline void memunit_advance(dereference_iterator_adaptor& p, + typename std::iterator_traits::difference_type diff) { + memunit_advance(p.base(), diff); } template inline dereference_iterator_adaptor -byte_advanced(const dereference_iterator_adaptor& p, - typename std::iterator_traits::difference_type byteDiff) { - return dereference_iterator_adaptor(byte_advanced(p.base(), byteDiff), p.deref_fn()); +memunit_advanced(const dereference_iterator_adaptor& p, + typename std::iterator_traits::difference_type diff) { + return dereference_iterator_adaptor(memunit_advanced(p.base(), diff), p.deref_fn()); } template inline typename std::iterator_traits >::reference -byte_advanced_ref(const dereference_iterator_adaptor& p, - typename std::iterator_traits::difference_type byteDiff) { - return *byte_advanced(p, byteDiff); +memunit_advanced_ref(const dereference_iterator_adaptor& p, + typename std::iterator_traits::difference_type diff) { + return *memunit_advanced(p, diff); } ///////////////////////////// @@ -180,7 +183,7 @@ struct dynamic_x_step_type > { /// \ingroup PixelIteratorModelDerefPtr template struct iterator_add_deref { - GIL_CLASS_REQUIRE(Deref, boost::gil, PixelDereferenceAdaptorConcept); + GIL_CLASS_REQUIRE(Deref, boost::gil, PixelDereferenceAdaptorConcept) typedef dereference_iterator_adaptor type; @@ -191,7 +194,7 @@ struct iterator_add_deref { /// \brief For dereference iterator adaptors, compose the new function object after the old one template struct iterator_add_deref,Deref> { - GIL_CLASS_REQUIRE(Deref, boost::gil, PixelDereferenceAdaptorConcept); +// GIL_CLASS_REQUIRE(Deref, boost::gil, PixelDereferenceAdaptorConcept) typedef dereference_iterator_adaptor > type; diff --git a/include/boost/gil/planar_pixel_iterator.hpp b/include/boost/gil/planar_pixel_iterator.hpp index 24c70aa13a..3ffbfe36b4 100644 --- a/include/boost/gil/planar_pixel_iterator.hpp +++ b/include/boost/gil/planar_pixel_iterator.hpp @@ -42,10 +42,10 @@ struct planar_pixel_reference; /// \defgroup PixelIteratorModelPlanarPtr planar_pixel_iterator /// \ingroup PixelIteratorModel -/// \brief An iterator over planar pixels. Models PixelIteratorConcept, HomogeneousPixelBasedConcept, ByteAdvanceableIteratorConcept, HasDynamicXStepTypeConcept +/// \brief An iterator over planar pixels. Models PixelIteratorConcept, HomogeneousPixelBasedConcept, MemoryBasedIteratorConcept, HasDynamicXStepTypeConcept //////////////////////////////////////////////////////////////////////////////////////// -/// \brief An iterator over planar pixels. Models HomogeneousColorBaseConcept, PixelIteratorConcept, HomogeneousPixelBasedConcept, ByteAdvanceableIteratorConcept, HasDynamicXStepTypeConcept +/// \brief An iterator over planar pixels. Models HomogeneousColorBaseConcept, PixelIteratorConcept, HomogeneousPixelBasedConcept, MemoryBasedIteratorConcept, HasDynamicXStepTypeConcept /// /// Planar pixels have channel data that is not consecutive in memory. /// To abstract this we use classes to represent references and pointers to planar pixels. @@ -104,7 +104,7 @@ struct planar_pixel_iterator : public iterator_facade() const { return **this; } @@ -140,6 +140,21 @@ struct const_iterator_type > { template struct iterator_is_mutable > : public detail::channel_iterator_is_mutable {}; +///////////////////////////// +// ColorBasedConcept +///////////////////////////// + +template +struct kth_element_type, K> { + typedef IC type; +}; + +template +struct kth_element_reference_type, K> : public add_reference {}; + +template +struct kth_element_const_reference_type, K> : public add_reference::type> {}; + ///////////////////////////// // HomogeneousPixelBasedConcept ///////////////////////////// @@ -161,41 +176,40 @@ struct channel_type > { }; ///////////////////////////// -// ByteAdvanceableIteratorConcept +// MemoryBasedIteratorConcept ///////////////////////////// template -inline std::ptrdiff_t byte_step(const planar_pixel_iterator&) { return sizeof(typename std::iterator_traits::value_type); } +inline std::ptrdiff_t memunit_step(const planar_pixel_iterator&) { return sizeof(typename std::iterator_traits::value_type); } template -inline std::ptrdiff_t byte_distance(const planar_pixel_iterator& p1, const planar_pixel_iterator& p2) { - return byte_distance(at_c<0>(p1),at_c<0>(p2)); +inline std::ptrdiff_t memunit_distance(const planar_pixel_iterator& p1, const planar_pixel_iterator& p2) { + return memunit_distance(at_c<0>(p1),at_c<0>(p2)); } template -struct byte_advance_fn { - byte_advance_fn(std::ptrdiff_t byte_diff) : _byte_diff(byte_diff) {} - IC operator()(const IC& p) const { return byte_advanced(p,_byte_diff); } +struct memunit_advance_fn { + memunit_advance_fn(std::ptrdiff_t diff) : _diff(diff) {} + IC operator()(const IC& p) const { return memunit_advanced(p,_diff); } - std::ptrdiff_t _byte_diff; + std::ptrdiff_t _diff; }; template -inline void byte_advance(planar_pixel_iterator& p, std::ptrdiff_t byte_diff) { - static_transform(p, p, byte_advance_fn(byte_diff)); +inline void memunit_advance(planar_pixel_iterator& p, std::ptrdiff_t diff) { + static_transform(p, p, memunit_advance_fn(diff)); } template -inline planar_pixel_iterator byte_advanced(const planar_pixel_iterator& p, std::ptrdiff_t byteDiff) { +inline planar_pixel_iterator memunit_advanced(const planar_pixel_iterator& p, std::ptrdiff_t diff) { planar_pixel_iterator ret=p; - byte_advance(ret, byteDiff); + memunit_advance(ret, diff); return ret; } -// Advancing a planar pixel iterator by a given number of bytes and taking the reference template inline planar_pixel_reference::reference,ColorSpace> - byte_advanced_ref(const planar_pixel_iterator& ptr, std::ptrdiff_t diff) { + memunit_advanced_ref(const planar_pixel_iterator& ptr, std::ptrdiff_t diff) { return planar_pixel_reference::reference,ColorSpace>(ptr, diff); } @@ -205,7 +219,7 @@ inline planar_pixel_reference::referen template struct dynamic_x_step_type > { - typedef byte_addressable_step_iterator > type; + typedef memory_based_step_iterator > type; }; } } // namespace boost::gil diff --git a/include/boost/gil/planar_pixel_reference.hpp b/include/boost/gil/planar_pixel_reference.hpp index febeaf8b78..6344864432 100644 --- a/include/boost/gil/planar_pixel_reference.hpp +++ b/include/boost/gil/planar_pixel_reference.hpp @@ -89,11 +89,40 @@ struct planar_pixel_reference template static void check_compatible() { gil_function_requires >(); } }; +///////////////////////////// +// ColorBasedConcept +///////////////////////////// + +template +struct kth_element_type, K> { + typedef ChannelReference type; +}; + +template +struct kth_element_reference_type, K> { + typedef ChannelReference type; +}; + +template +struct kth_element_const_reference_type, K> + : public add_reference::type> +{ +// typedef typename channel_traits::const_reference type; +}; + +///////////////////////////// +// PixelConcept +///////////////////////////// + /// \brief Metafunction predicate that flags planar_pixel_reference as a model of PixelConcept. Required by PixelConcept /// \ingroup PixelModelPlanarRef template struct is_pixel< planar_pixel_reference > : public mpl::true_{}; +///////////////////////////// +// HomogeneousPixelBasedConcept +///////////////////////////// + /// \brief Specifies the color space type of a planar pixel reference. Required by PixelBasedConcept /// \ingroup PixelModelPlanarRef template diff --git a/include/boost/gil/position_iterator.hpp b/include/boost/gil/position_iterator.hpp index 7b83380881..542f7df0ba 100644 --- a/include/boost/gil/position_iterator.hpp +++ b/include/boost/gil/position_iterator.hpp @@ -78,7 +78,7 @@ struct position_iterator : public iterator_facade, void decrement() { _p[Dim]-=_step[Dim]; } void advance(difference_type d) { _p[Dim]+=d*_step[Dim]; } - ptrdiff_t distance_to(const position_iterator& it) const { return (it._p[Dim]-_p[Dim])/_step[Dim]; } + difference_type distance_to(const position_iterator& it) const { return (it._p[Dim]-_p[Dim])/_step[Dim]; } bool equal(const position_iterator& it) const { return _p==it._p; } }; diff --git a/include/boost/gil/step_iterator.hpp b/include/boost/gil/step_iterator.hpp index 0556a24db6..99b1c7eada 100644 --- a/include/boost/gil/step_iterator.hpp +++ b/include/boost/gil/step_iterator.hpp @@ -108,15 +108,15 @@ bool operator!=(const step_iterator_adaptor& p1, const step_iter } // namespace detail //////////////////////////////////////////////////////////////////////////////////////// -/// BYTE-ADDRESSABLE STEP ITERATOR +/// MEMORY-BASED STEP ITERATOR //////////////////////////////////////////////////////////////////////////////////////// -/// \class byte_addressable_step_iterator +/// \class memory_based_step_iterator /// \ingroup PixelIteratorModelStepPtr PixelBasedModel -/// \brief Iterator with dynamically specified step in bytes. Models StepIteratorConcept, IteratorAdaptorConcept, ByteAdvanceableIteratorConcept, PixelIteratorConcept, HasDynamicXStepTypeConcept +/// \brief Iterator with dynamically specified step in memory units (bytes or bits). Models StepIteratorConcept, IteratorAdaptorConcept, MemoryBasedIteratorConcept, PixelIteratorConcept, HasDynamicXStepTypeConcept /// /// A refinement of step_iterator_adaptor that uses a dynamic parameter for the step -/// which is specified in bytes +/// which is specified in memory units, such as bytes or bits /// /// Pixel step iterators are used to provide iteration over non-adjacent pixels. /// Common use is a vertical traversal, where the step is the row stride. @@ -128,59 +128,59 @@ bool operator!=(const step_iterator_adaptor& p1, const step_iter //////////////////////////////////////////////////////////////////////////////////////// /// \ingroup PixelIteratorModelStepPtr -/// \brief function object that returns the byte distance between two iterators and advances a given iterator a given number of bytes +/// \brief function object that returns the memory unit distance between two iterators and advances a given iterator a given number of mem units (bytes or bits) template -struct byte_step_fn { +struct memunit_step_fn { typedef std::ptrdiff_t difference_type; - byte_step_fn(difference_type step=byte_step(Iterator())) : _step(step) {} + memunit_step_fn(difference_type step=memunit_step(Iterator())) : _step(step) {} - difference_type difference(const Iterator& it1, const Iterator& it2) const { return byte_distance(it1,it2)/_step; } - void advance(Iterator& it, difference_type d) const { byte_advance(it,d*_step); } - difference_type step() const { return _step; } + difference_type difference(const Iterator& it1, const Iterator& it2) const { return memunit_distance(it1,it2)/_step; } + void advance(Iterator& it, difference_type d) const { memunit_advance(it,d*_step); } + difference_type step() const { return _step; } void set_step(std::ptrdiff_t step) { _step=step; } private: - GIL_CLASS_REQUIRE(Iterator, boost::gil, ByteAdvanceableIteratorConcept); + GIL_CLASS_REQUIRE(Iterator, boost::gil, MemoryBasedIteratorConcept); difference_type _step; }; template -class byte_addressable_step_iterator : public detail::step_iterator_adaptor, +class memory_based_step_iterator : public detail::step_iterator_adaptor, Iterator, - byte_step_fn > { - GIL_CLASS_REQUIRE(Iterator, boost::gil, ByteAdvanceableIteratorConcept); + memunit_step_fn > { + GIL_CLASS_REQUIRE(Iterator, boost::gil, MemoryBasedIteratorConcept); public: - typedef detail::step_iterator_adaptor, + typedef detail::step_iterator_adaptor, Iterator, - byte_step_fn > parent_t; + memunit_step_fn > parent_t; typedef typename parent_t::reference reference; typedef typename parent_t::difference_type difference_type; typedef Iterator x_iterator; - byte_addressable_step_iterator() : parent_t(Iterator()) {} - byte_addressable_step_iterator(Iterator it, std::ptrdiff_t byte_step) : parent_t(it, byte_step_fn(byte_step)) {} + memory_based_step_iterator() : parent_t(Iterator()) {} + memory_based_step_iterator(Iterator it, std::ptrdiff_t memunit_step) : parent_t(it, memunit_step_fn(memunit_step)) {} template - byte_addressable_step_iterator(const byte_addressable_step_iterator& it) - : parent_t(it.base(), byte_step_fn(it.step())) {} + memory_based_step_iterator(const memory_based_step_iterator& it) + : parent_t(it.base(), memunit_step_fn(it.step())) {} /// For some reason operator[] provided by iterator_adaptor returns a custom class that is convertible to reference /// We require our own reference because it is registered in iterator_traits reference operator[](difference_type d) const { return *(*this+d); } - void set_step(std::ptrdiff_t byte_step) { this->_step_fn.set_step(byte_step); } + void set_step(std::ptrdiff_t memunit_step) { this->_step_fn.set_step(memunit_step); } x_iterator& base() { return parent_t::base_reference(); } x_iterator const& base() const { return parent_t::base_reference(); } }; template -struct const_iterator_type > { - typedef byte_addressable_step_iterator::type> type; +struct const_iterator_type > { + typedef memory_based_step_iterator::type> type; }; template -struct iterator_is_mutable > : public iterator_is_mutable {}; +struct iterator_is_mutable > : public iterator_is_mutable {}; ///////////////////////////// @@ -188,16 +188,16 @@ struct iterator_is_mutable > : public i ///////////////////////////// template -struct is_iterator_adaptor > : public mpl::true_{}; +struct is_iterator_adaptor > : public mpl::true_{}; template -struct iterator_adaptor_get_base > { +struct iterator_adaptor_get_base > { typedef Iterator type; }; template -struct iterator_adaptor_rebind,NewBaseIterator> { - typedef byte_addressable_step_iterator type; +struct iterator_adaptor_rebind,NewBaseIterator> { + typedef memory_based_step_iterator type; }; ///////////////////////////// @@ -205,48 +205,50 @@ struct iterator_adaptor_rebind,NewBaseI ///////////////////////////// template -struct color_space_type > : public color_space_type {}; +struct color_space_type > : public color_space_type {}; template -struct channel_mapping_type > : public channel_mapping_type {}; +struct channel_mapping_type > : public channel_mapping_type {}; template -struct is_planar > : public is_planar {}; +struct is_planar > : public is_planar {}; template -struct channel_type > : public channel_type {}; +struct channel_type > : public channel_type {}; ///////////////////////////// -// ByteAdvanceableIteratorConcept +// MemoryBasedIteratorConcept ///////////////////////////// +template +struct byte_to_memunit > : public byte_to_memunit {}; template -inline std::ptrdiff_t byte_step(const byte_addressable_step_iterator& p) { return p.step(); } +inline std::ptrdiff_t memunit_step(const memory_based_step_iterator& p) { return p.step(); } template -inline std::ptrdiff_t byte_distance(const byte_addressable_step_iterator& p1, - const byte_addressable_step_iterator& p2) { - return byte_distance(p1.base(),p2.base()); +inline std::ptrdiff_t memunit_distance(const memory_based_step_iterator& p1, + const memory_based_step_iterator& p2) { + return memunit_distance(p1.base(),p2.base()); } template -inline void byte_advance(byte_addressable_step_iterator& p, - std::ptrdiff_t byteDiff) { - byte_advance(p.base(), byteDiff); +inline void memunit_advance(memory_based_step_iterator& p, + std::ptrdiff_t diff) { + memunit_advance(p.base(), diff); } template -inline byte_addressable_step_iterator -byte_advanced(const byte_addressable_step_iterator& p, - std::ptrdiff_t byteDiff) { - return byte_addressable_step_iterator(byte_advanced(p.base(), byteDiff),p.step()); +inline memory_based_step_iterator +memunit_advanced(const memory_based_step_iterator& p, + std::ptrdiff_t diff) { + return memory_based_step_iterator(memunit_advanced(p.base(), diff),p.step()); } template inline typename std::iterator_traits::reference -byte_advanced_ref(const byte_addressable_step_iterator& p, - std::ptrdiff_t byteDiff) { - return byte_advanced_ref(p.base(), byteDiff); +memunit_advanced_ref(const memory_based_step_iterator& p, + std::ptrdiff_t diff) { + return memunit_advanced_ref(p.base(), diff); } ///////////////////////////// @@ -254,18 +256,18 @@ byte_advanced_ref(const byte_addressable_step_iterator& p, ///////////////////////////// template -struct dynamic_x_step_type > { - typedef byte_addressable_step_iterator type; +struct dynamic_x_step_type > { + typedef memory_based_step_iterator type; }; // For step iterators, pass the function object to the base template -struct iterator_add_deref,Deref> { +struct iterator_add_deref,Deref> { GIL_CLASS_REQUIRE(Deref, boost::gil, PixelDereferenceAdaptorConcept); - typedef byte_addressable_step_iterator::type> type; + typedef memory_based_step_iterator::type> type; - static type make(const byte_addressable_step_iterator& it, const Deref& d) { return type(iterator_add_deref::make(it.base(),d),it.step()); } + static type make(const memory_based_step_iterator& it, const Deref& d) { return type(iterator_add_deref::make(it.base(),d),it.step()); } }; //////////////////////////////////////////////////////////////////////////////////////// @@ -276,10 +278,10 @@ template typename dynamic_x_step_type::type make_step_iterator(c namespace detail { -// if the iterator is a plain base iterator (non-adaptor), wraps it in byte_addressable_step_iterator +// if the iterator is a plain base iterator (non-adaptor), wraps it in memory_based_step_iterator template typename dynamic_x_step_type::type make_step_iterator_impl(const I& it, std::ptrdiff_t step, mpl::false_) { - return byte_addressable_step_iterator(it, step); + return memory_based_step_iterator(it, step); } // If the iterator is compound, put the step in its base @@ -288,27 +290,27 @@ typename dynamic_x_step_type::type make_step_iterator_impl(const I& it, std:: return make_step_iterator(it.base(), step); } -// If the iterator is byte_addressable_step_iterator, change the step +// If the iterator is memory_based_step_iterator, change the step template -byte_addressable_step_iterator make_step_iterator_impl(const byte_addressable_step_iterator& it, std::ptrdiff_t step, mpl::true_) { - return byte_addressable_step_iterator(it.base(), step); +memory_based_step_iterator make_step_iterator_impl(const memory_based_step_iterator& it, std::ptrdiff_t step, mpl::true_) { + return memory_based_step_iterator(it.base(), step); } } /// \brief Constructs a step iterator from a base iterator and a step. /// /// To construct a step iterator from a given iterator Iterator and a given step, if Iterator does not -/// already have a dynamic step, we wrap it in a byte_addressable_step_iterator. Otherwise we +/// already have a dynamic step, we wrap it in a memory_based_step_iterator. Otherwise we /// do a compile-time traversal of the chain of iterator adaptors to locate the step iterator /// and then set it step to the new one. /// -/// The step iterator of Iterator is not always byte_addressable_step_iterator. For example, Iterator may -/// already be a byte_addressable_step_iterator, in which case it will be inefficient to stack them; +/// The step iterator of Iterator is not always memory_based_step_iterator. For example, Iterator may +/// already be a memory_based_step_iterator, in which case it will be inefficient to stack them; /// we can obtain the same result by multiplying their steps. Note that for Iterator to be a -/// step iterator it does not necessarily have to have the form byte_addressable_step_iterator. +/// step iterator it does not necessarily have to have the form memory_based_step_iterator. /// The step iterator can be wrapped inside another iterator. Also, it may not have the -/// type byte_addressable_step_iterator, but it could be a user-provided type. -template // Models ByteAdvanceableIteratorConcept, HasDynamicXStepTypeConcept +/// type memory_based_step_iterator, but it could be a user-provided type. +template // Models MemoryBasedIteratorConcept, HasDynamicXStepTypeConcept typename dynamic_x_step_type::type make_step_iterator(const I& it, std::ptrdiff_t step) { return detail::make_step_iterator_impl(it, step, typename is_iterator_adaptor::type()); } diff --git a/include/boost/gil/typedefs.hpp b/include/boost/gil/typedefs.hpp index 41b4b87d66..f33c06d9ee 100644 --- a/include/boost/gil/typedefs.hpp +++ b/include/boost/gil/typedefs.hpp @@ -36,9 +36,9 @@ template struct pixel; \ template struct planar_pixel_reference; \ template struct planar_pixel_iterator; \ - template class byte_addressable_step_iterator; \ + template class memory_based_step_iterator; \ template class point2; \ - template class byte_addressable_2d_locator; \ + template class memory_based_2d_locator; \ template class image_view; \ template class image; \ typedef pixel CS##T##_pixel_t; \ @@ -47,12 +47,12 @@ typedef const pixel& CS##T##c_ref_t; \ typedef CS##T##_pixel_t* CS##T##_ptr_t; \ typedef CS##T##c_pixel_t* CS##T##c_ptr_t; \ - typedef byte_addressable_step_iterator CS##T##_step_ptr_t; \ - typedef byte_addressable_step_iterator CS##T##c_step_ptr_t; \ - typedef byte_addressable_2d_locator > CS##T##_loc_t; \ - typedef byte_addressable_2d_locator > CS##T##c_loc_t; \ - typedef byte_addressable_2d_locator > CS##T##_step_loc_t; \ - typedef byte_addressable_2d_locator > CS##T##c_step_loc_t; \ + typedef memory_based_step_iterator CS##T##_step_ptr_t; \ + typedef memory_based_step_iterator CS##T##c_step_ptr_t; \ + typedef memory_based_2d_locator > CS##T##_loc_t; \ + typedef memory_based_2d_locator > CS##T##c_loc_t; \ + typedef memory_based_2d_locator > CS##T##_step_loc_t; \ + typedef memory_based_2d_locator > CS##T##c_step_loc_t; \ typedef image_view CS##T##_view_t; \ typedef image_view CS##T##c_view_t; \ typedef image_view CS##T##_step_view_t; \ @@ -66,12 +66,12 @@ typedef planar_pixel_reference CS##T##c_planar_ref_t; \ typedef planar_pixel_iterator CS##T##_planar_ptr_t; \ typedef planar_pixel_iterator CS##T##c_planar_ptr_t; \ - typedef byte_addressable_step_iterator CS##T##_planar_step_ptr_t; \ - typedef byte_addressable_step_iterator CS##T##c_planar_step_ptr_t; \ - typedef byte_addressable_2d_locator > CS##T##_planar_loc_t; \ - typedef byte_addressable_2d_locator > CS##T##c_planar_loc_t; \ - typedef byte_addressable_2d_locator > CS##T##_planar_step_loc_t; \ - typedef byte_addressable_2d_locator > CS##T##c_planar_step_loc_t; \ + typedef memory_based_step_iterator CS##T##_planar_step_ptr_t; \ + typedef memory_based_step_iterator CS##T##c_planar_step_ptr_t; \ + typedef memory_based_2d_locator > CS##T##_planar_loc_t; \ + typedef memory_based_2d_locator > CS##T##c_planar_loc_t; \ + typedef memory_based_2d_locator > CS##T##_planar_step_loc_t; \ + typedef memory_based_2d_locator > CS##T##c_planar_step_loc_t; \ typedef image_view CS##T##_planar_view_t; \ typedef image_view CS##T##c_planar_view_t; \ typedef image_view CS##T##_planar_step_view_t; \ diff --git a/include/boost/gil/utilities.hpp b/include/boost/gil/utilities.hpp index f04c08e8d3..da1582bc9f 100644 --- a/include/boost/gil/utilities.hpp +++ b/include/boost/gil/utilities.hpp @@ -32,12 +32,25 @@ /// \brief Various utilities not specific to the image library. Some are non-standard STL extensions or generic iterator adaptors /// \author Lubomir Bourdev and Hailin Jin \n /// Adobe Systems Incorporated +/// \date 2005-2007 \n Last updated on August 14, 2007 /// /// //////////////////////////////////////////////////////////////////////////////////////// namespace boost { namespace gil { +/** +\addtogroup PointModel + +Example: +\code +point2 p(3,2); +assert((p[0] == p.x) && (p[1] == p.y)); +assert(axis_value<0>(p) == 3); +assert(axis_value<1>(p) == 2); +\endcode +*/ + //////////////////////////////////////////////////////////////////////////////////////// // CLASS point2 /// @@ -125,6 +138,15 @@ inline int ifloor(double x) { return static_cast(std::floor(x)); } inline int iceil(float x ) { return static_cast(std::ceil(x)); } inline int iceil(double x) { return static_cast(std::ceil(x)); } +/** +\addtogroup PointAlgorithm + +Example: +\code +assert(iround(point2(3.1, 3.9)) == point2(3,4)); +\endcode +*/ + /// \ingroup PointAlgorithm inline point2 iround(const point2& p) { return point2(iround(p.x),iround(p.y)); } /// \ingroup PointAlgorithm @@ -149,22 +171,34 @@ inline T align(T val, std::size_t alignment) { return val+(alignment - val%alignment)%alignment; } +/// \brief Helper base class for pixel dereference adaptors. +/// \ingroup PixelDereferenceAdaptorModel +/// +template +struct deref_base : public std::unary_function { + typedef ConstT const_t; + typedef Value value_type; + typedef Reference reference; + typedef ConstReference const_reference; + BOOST_STATIC_CONSTANT(bool, is_mutable = IsMutable); +}; + /// \brief Composes two dereference function objects. Similar to std::unary_compose but needs to pull some typedefs from the component types. Models: PixelDereferenceAdaptorConcept /// \ingroup PixelDereferenceAdaptorModel /// template -class deref_compose { +class deref_compose : public deref_base< + deref_compose, + typename D1::value_type, typename D1::reference, typename D1::const_reference, + typename D2::argument_type, typename D1::result_type, D1::is_mutable && D2::is_mutable> +{ public: D1 _fn1; D2 _fn2; - typedef deref_compose const_t; - typedef typename D1::value_type value_type; - typedef typename D1::reference reference; - typedef typename D1::const_reference const_reference; typedef typename D2::argument_type argument_type; typedef typename D1::result_type result_type; - BOOST_STATIC_CONSTANT(bool, is_mutable=D1::is_mutable && D2::is_mutable); deref_compose() {} deref_compose(const D1& x, const D2& y) : _fn1(x), _fn2(y) {} diff --git a/test/Makefile b/test/Makefile index 83977e7899..50d8f907c6 100644 --- a/test/Makefile +++ b/test/Makefile @@ -7,15 +7,25 @@ CXX=g++ CXX_FLAGS=-Wall -DBOOST_GIL_USE_CONCEPT_CHECK #-DNDEBUG CXX_CHECKSUM_FLAGS=-Wall -DBOOST_GIL_NO_IO -DBOOST_GIL_USE_CONCEPT_CHECK #-DNDEBUG -BOOST_INCLUDE_PATH=-I../../.. +BOOST_INCLUDE_PATH=-I../../.. -I../../../../boost_libraries +LIBJPEG_INCLUDE_PATH=-I../../../../lib/libjpeg +LIBJPEG_LIB_PATH=-L../../../../lib/libjpeg +LIBTIFF_INCLUDE_PATH=-I../../../../lib/libtiff +LIBTIFF_LIB_PATH=-L../../../../lib/libtiff +LIBPNG_INCLUDE_PATH=-I../../../../lib/libpng +LIBPNG_LIB_PATH=-L../../../../lib/libpng +LIBZ_LIB_PATH=-L../../../../lib/zlib ALL_OBJECTS=main.o channel.o pixel.o pixel_iterator.o image.o image_io.o sample_image.o all: performance checksum .cpp.o: +# ${CXX} ${CXX_FLAGS} ${BOOST_INCLUDE_PATH} ${LIBJPEG_INCLUDE_PATH} ${LIBTIFF_INCLUDE_PATH} ${LIBPNG_INCLUDE_PATH} -c $< ${CXX} ${CXX_CHECKSUM_FLAGS} ${BOOST_INCLUDE_PATH} -c $< clean: -rm -f *.o *.exe performance: performance.o ${CXX} -o performance ${CXX_FLAGS} performance.o +test: ${ALL_OBJECTS} + ${CXX} -o test ${CXX_FLAGS} ${ALL_OBJECTS} ${LIBJPEG_LIB_PATH} -ljpeg ${LIBTIFF_LIB_PATH} -ltiff ${LIBPNG_LIB_PATH} -lpng ${LIBZ_LIB_PATH} -lz checksum: ${ALL_OBJECTS} ${CXX} -o test ${CXX_CHECKSUM_FLAGS} ${ALL_OBJECTS} diff --git a/test/channel.cpp b/test/channel.cpp index 040ce0518c..6bda11f7f1 100644 --- a/test/channel.cpp +++ b/test/channel.cpp @@ -179,16 +179,17 @@ class reference_core : public value_core::va }; // For subbyte channel references we need to store the bit buffers somewhere -template +template class packed_reference_core { protected: typedef ChannelSubbyteRef channel_t; + typedef typename channel_t::integer_t integer_t; channel_t _min_v, _max_v; - BitBuffer _min_buf, _max_buf; + integer_t _min_buf, _max_buf; - packed_reference_core() : _min_v(_min_buf), _max_v(_max_buf) { - ChannelMutableRef b1(_min_buf), b2(_max_buf); + packed_reference_core() : _min_v(&_min_buf), _max_v(&_max_buf) { + ChannelMutableRef b1(&_min_buf), b2(&_max_buf); b1 = channel_traits::min_value(); b2 = channel_traits::max_value(); @@ -196,16 +197,16 @@ class packed_reference_core { } }; -template +template class packed_dynamic_reference_core { protected: typedef ChannelSubbyteRef channel_t; channel_t _min_v, _max_v; - BitBuffer _min_buf, _max_buf; + typename channel_t::integer_t _min_buf, _max_buf; - packed_dynamic_reference_core(int first_bit1=1, int first_bit2=2) : _min_v(_min_buf,first_bit1), _max_v(_max_buf,first_bit2) { - ChannelMutableRef b1(_min_buf,1), b2(_max_buf,2); + packed_dynamic_reference_core(int first_bit1=1, int first_bit2=2) : _min_v(&_min_buf,first_bit1), _max_v(&_max_buf,first_bit2) { + ChannelMutableRef b1(&_min_buf,1), b2(&_max_buf,2); b1 = channel_traits::min_value(); b2 = channel_traits::max_value(); @@ -224,24 +225,24 @@ void test_channel_reference() { do_test >().test_all(); } -template +template void test_packed_channel_reference() { - do_test >().test_all(); + do_test >().test_all(); } -template +template void test_const_packed_channel_reference() { - do_test >().test_all(); + do_test >().test_all(); } -template +template void test_packed_dynamic_channel_reference() { - do_test >().test_all(); + do_test >().test_all(); } -template +template void test_const_packed_dynamic_channel_reference() { - do_test >().test_all(); + do_test >().test_all(); } template @@ -304,38 +305,38 @@ channel_value_archetype channel_archetype::max_value() { return channel_value_ar void test_packed_channel_reference() { typedef packed_channel_reference channel16_0_5_reference_t; typedef packed_channel_reference channel16_5_6_reference_t; - typedef packed_channel_reference channel16_11_5_reference_t; + typedef packed_channel_reference channel16_11_5_reference_t; boost::uint16_t data=0; - channel16_0_5_reference_t channel1(data); - channel16_5_6_reference_t channel2(data); - channel16_11_5_reference_t channel3(data); + channel16_0_5_reference_t channel1(&data); + channel16_5_6_reference_t channel2(&data); + channel16_11_5_reference_t channel3(&data); channel1=channel_traits::max_value(); channel2=channel_traits::max_value(); channel3=channel_traits::max_value(); error_if(data!=65535); - test_packed_channel_reference(); - test_packed_channel_reference(); - test_packed_channel_reference(); + test_packed_channel_reference(); + test_packed_channel_reference(); + test_packed_channel_reference(); } void test_packed_dynamic_channel_reference() { - typedef packed_dynamic_channel_reference channel16_5_reference_t; - typedef packed_dynamic_channel_reference channel16_6_reference_t; + typedef packed_dynamic_channel_reference channel16_5_reference_t; + typedef packed_dynamic_channel_reference channel16_6_reference_t; boost::uint16_t data=0; - channel16_5_reference_t channel1(data,0); - channel16_6_reference_t channel2(data,5); - channel16_5_reference_t channel3(data,11); + channel16_5_reference_t channel1(&data,0); + channel16_6_reference_t channel2(&data,5); + channel16_5_reference_t channel3(&data,11); channel1=channel_traits::max_value(); channel2=channel_traits::max_value(); channel3=channel_traits::max_value(); error_if(data!=65535); - test_packed_dynamic_channel_reference(); + test_packed_dynamic_channel_reference(); } void test_channel() { diff --git a/test/gil_reference_checksums.txt b/test/gil_reference_checksums.txt index 39ecf497fd..ca123231d1 100644 --- a/test/gil_reference_checksums.txt +++ b/test/gil_reference_checksums.txt @@ -1,7 +1,23 @@ +bgr121_basic_red_x 7f6e24e7 +bgr121_basic_white_x e4aaa1d3 +bgr121_histogram_histogram ca580192 +bgr121_views_0th_k_channel daa9f7e3 +bgr121_views_90ccw c64d6d20 +bgr121_views_90cw 8565efd8 +bgr121_views_cropped 43305e15 +bgr121_views_flipped_lr 2d68e448 +bgr121_views_flipped_ud 8f7f7d00 +bgr121_views_gray8 bbabe219 +bgr121_views_my_gray8 3086d22f +bgr121_views_original 7e5bb87d +bgr121_views_rot180 68f37202 +bgr121_views_subsampled ac6ca178 +bgr121_views_transpose da2ff80 bgr8_basic_red_x 7f6e24e7 bgr8_basic_white_x e4aaa1d3 -bgr8_histogram_histogram 7b256ba4 -bgr8_views_0th_channel 4638e58d +bgr8_histogram_histogram badcdd58 +bgr8_views_0th_k_channel 4638e58d +bgr8_views_0th_n_channel 4638e58d bgr8_views_90ccw 8c4980e5 bgr8_views_90cw e4c69665 bgr8_views_cropped ff56b05e @@ -13,7 +29,8 @@ bgr8_views_original 423f1dde bgr8_views_rot180 150f1206 bgr8_views_subsampled 92439ee7 bgr8_views_transpose c9a890a0 -color_converted_0th_channel 3817178f +color_converted_0th_k_channel 3817178f +color_converted_0th_n_channel 3817178f color_converted_90ccw dc403b3 color_converted_90cw c6fc34de color_converted_cropped 666252a @@ -32,8 +49,9 @@ dynamic_subimage a974d099 dynamic_subimage_subsampled180rot 4055263a gray8_basic_red_x ab461c6a gray8_basic_white_x be81c274 -gray8_histogram_histogram 7b256ba4 -gray8_views_0th_channel 3817178f +gray8_histogram_histogram badcdd58 +gray8_views_0th_k_channel 3817178f +gray8_views_0th_n_channel 3817178f gray8_views_90ccw dc403b3 gray8_views_90cw c6fc34de gray8_views_cropped 666252a @@ -46,11 +64,11 @@ gray8_views_rot180 b5d0763b gray8_views_subsampled 28286169 gray8_views_transpose 366b8392 mandelLuminosityGradient 4ebf3906 -packed565 175358bb planarrgb8_basic_red_x 7f6e24e7 planarrgb8_basic_white_x e4aaa1d3 -planarrgb8_histogram_histogram 7b256ba4 -planarrgb8_views_0th_channel 1f48996f +planarrgb8_histogram_histogram badcdd58 +planarrgb8_views_0th_k_channel 1f48996f +planarrgb8_views_0th_n_channel 1f48996f planarrgb8_views_90ccw 8c4980e5 planarrgb8_views_90cw e4c69665 planarrgb8_views_cropped ff56b05e @@ -64,8 +82,9 @@ planarrgb8_views_subsampled 92439ee7 planarrgb8_views_transpose c9a890a0 rgb8_basic_red_x 7f6e24e7 rgb8_basic_white_x e4aaa1d3 -rgb8_histogram_histogram 7b256ba4 -rgb8_views_0th_channel 1f48996f +rgb8_histogram_histogram badcdd58 +rgb8_views_0th_k_channel 1f48996f +rgb8_views_0th_n_channel 1f48996f rgb8_views_90ccw 8c4980e5 rgb8_views_90cw e4c69665 rgb8_views_cropped ff56b05e @@ -77,7 +96,8 @@ rgb8_views_original 423f1dde rgb8_views_rot180 150f1206 rgb8_views_subsampled 92439ee7 rgb8_views_transpose c9a890a0 -subsampled_0th_channel 2c19afc1 +subsampled_0th_k_channel 2c19afc1 +subsampled_0th_n_channel 2c19afc1 subsampled_90ccw d4649279 subsampled_90cw e74f0f0e subsampled_cropped a5f07581 @@ -89,14 +109,15 @@ subsampled_original 64cf9a6b subsampled_rot180 6059029b subsampled_subsampled 59aef23b subsampled_transpose ec4b368a -virtual_0th_channel 79bca658 +virtual_0th_k_channel 79bca658 +virtual_0th_n_channel 79bca658 virtual_90ccw 965db1f7 virtual_90cw a81d80e3 virtual_cropped ffb4af2c virtual_flipped_lr 9d1478c2 virtual_flipped_ud 18dc9b78 virtual_gray8 962f6f6f -virtual_histogram 7b256ba4 +virtual_histogram 8deb06eb virtual_my_gray8 150bb50d virtual_original 927686d4 virtual_rot180 4dee193e diff --git a/test/image.cpp b/test/image.cpp index 204d088301..d5a31d9df7 100644 --- a/test/image.cpp +++ b/test/image.cpp @@ -10,6 +10,12 @@ // image_test.cpp : // +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4244) // conversion from 'gil::image::coord_t' to 'int', possible loss of data (visual studio compiler doesn't realize that the two types are the same) +#pragma warning(disable : 4503) // decorated name length exceeded, name was truncated +#endif + #include #include #include @@ -18,7 +24,6 @@ #include #include #include - #include #include @@ -76,7 +81,7 @@ struct my_color_converter { // Models a Unary Function template // Models PixelValueConcept struct mandelbrot_fn { - typedef point2 point_t; + typedef point2 point_t; typedef mandelbrot_fn const_t; typedef P value_type; @@ -128,8 +133,16 @@ void x_gradient(const T& src, const gray8s_view_t& dst) { } } +// A quick test whether a view is homogeneous +template +struct pixel_is_homogeneous : public mpl::true_ {}; +template +struct pixel_is_homogeneous > : public mpl::false_ {}; + +template +struct view_is_homogeneous : public pixel_is_homogeneous {}; //////////////////////////////////////////////////// @@ -155,6 +168,8 @@ class image_test { private: template void basic_test(const string& prefix); template void view_transformations_test(const View& img_view, const string& prefix); + template void homogeneous_view_transformations_test(const View& img_view, const string& prefix, mpl::true_); + template void homogeneous_view_transformations_test(const View& img_view, const string& prefix, mpl::false_) {} template void histogram_test(const View& img_view, const string& prefix); void virtual_view_test(); void packed_image_test(); @@ -224,10 +239,10 @@ template void image_test::histogram_test(const View& img_view, const string& prefix) { // vector histogram(255,0); // get_hist(cropped,histogram.begin()); - bits32s histogram[256]; + unsigned char histogram[256]; fill(histogram,histogram+256,0); get_hist(img_view,histogram); - gray32sc_view_t hist_view=interleaved_view(256,1,(const gray32s_pixel_t*)histogram,256); + gray8c_view_t hist_view=interleaved_view(256,1,(const gray8_pixel_t*)histogram,256); check_view(hist_view,prefix+"histogram"); } @@ -245,9 +260,14 @@ void image_test::view_transformations_test(const View& img_view, const string& p check_view(rotated90ccw_view(img_view),prefix+"90ccw"); check_view(flipped_up_down_view(img_view),prefix+"flipped_ud"); check_view(flipped_left_right_view(img_view),prefix+"flipped_lr"); - check_view(subsampled_view(img_view,typename View::point_t(2,1)),prefix+"subsampled"); - check_view(nth_channel_view(img_view,0),prefix+"0th_channel"); - check_view(kth_channel_view<0>(img_view),prefix+"0th_channel"); + check_view(subsampled_view(img_view,typename View::point_t(2,1)),prefix+"subsampled"); + check_view(kth_channel_view<0>(img_view),prefix+"0th_k_channel"); + homogeneous_view_transformations_test(img_view, prefix, view_is_homogeneous()); +} + +template +void image_test::homogeneous_view_transformations_test(const View& img_view, const string& prefix, mpl::true_) { + check_view(nth_channel_view(img_view,0),prefix+"0th_n_channel"); } @@ -273,15 +293,7 @@ void image_test::virtual_view_test() { } void image_test::packed_image_test() { - // define an rgb565 pixel - typedef const packed_channel_reference rgb565_channel0_t; - typedef const packed_channel_reference rgb565_channel1_t; - typedef const packed_channel_reference rgb565_channel2_t; - - typedef heterogeneous_packed_pixel, rgb_layout_t> rgb565_pixel_t; - - typedef image rgb565_image_t; + typedef packed_image3_type::type rgb565_image_t; rgb565_image_t img565(sample_view.dimensions()); copy_and_convert_pixels(sample_view, view(img565)); @@ -328,6 +340,10 @@ void image_test::run() { image_all_test("planarrgb8_"); image_all_test("gray8_"); + typedef const bit_aligned_pixel_reference, bgr_layout_t, true> bgr121_ref_t; + typedef image bgr121_image_t; + image_all_test("bgr121_"); + // TODO: Remove? view_transformations_test(subsampled_view(sample_view,point2(1,2)),"subsampled_"); view_transformations_test(color_converted_view(sample_view),"color_converted_"); @@ -504,6 +520,21 @@ void static_checks() { BOOST_STATIC_ASSERT((boost::is_same::type, cmyk8c_planar_step_view_t>::value)); BOOST_STATIC_ASSERT((boost::is_same::type, rgb16c_planar_step_view_t>::value)); BOOST_STATIC_ASSERT((boost::is_same::type, rgb8c_step_view_t>::value)); + + // test view get raw data (mostly compile-time test) + { + rgb8_image_t rgb8(100,100); + unsigned char* data=interleaved_view_get_raw_data(view(rgb8)); + const unsigned char* cdata=interleaved_view_get_raw_data(const_view(rgb8)); + error_if(data!=cdata); + } + + { + rgb16s_planar_image_t rgb8(100,100); + short* data=planar_view_get_raw_data(view(rgb8),1); + const short* cdata=planar_view_get_raw_data(const_view(rgb8),1); + error_if(data!=cdata); + } } #ifdef BOOST_GIL_NO_IO @@ -528,7 +559,9 @@ void test_image(const char* ref_checksum) { static_checks(); } - +#ifdef _MSC_VER +#pragma warning(pop) +#endif diff --git a/test/performance.cpp b/test/performance.cpp index 72dfdd306d..40cfd9be51 100644 --- a/test/performance.cpp +++ b/test/performance.cpp @@ -1,3 +1,15 @@ +/* + 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). + + See http://opensource.adobe.com/gil for most recent version including documentation. +*/ + +/*************************************************************************************************/ + /// \file /// \brief GIL performance test suite /// \date 2007 \n Last updated on February 12, 2007 @@ -47,9 +59,9 @@ double measure_time(Op op, std::size_t num_loops) { std::size_t width=1000, height=400; // macros for standard GIL views -#define RGB_VIEW(T) image_view*> > > -#define BGR_VIEW(T) image_view*> > > -#define RGB_PLANAR_VIEW(T) image_view > > > +#define RGB_VIEW(T) image_view*> > > +#define BGR_VIEW(T) image_view*> > > +#define RGB_PLANAR_VIEW(T) image_view > > > template struct fill_gil_t { diff --git a/test/pixel.cpp b/test/pixel.cpp index 4037887307..db56132b91 100644 --- a/test/pixel.cpp +++ b/test/pixel.cpp @@ -28,6 +28,8 @@ #include #include #include +#include +#include // Testing pixel references and values, pixel operations, color conversion @@ -239,34 +241,24 @@ void test_color_convert() { for_each(ccv1()); } -void test_packed_pixel() { - // define an rgb565 pixel - typedef const packed_channel_reference rgb565_channel0_t; - typedef const packed_channel_reference rgb565_channel1_t; - typedef const packed_channel_reference rgb565_channel2_t; +void test_packed_pixel() { + typedef packed_pixel_type, rgb_layout_t>::type rgb565_pixel_t; - typedef heterogeneous_packed_pixel, rgb_layout_t> rgb565_pixel_t; boost::function_requires >(); BOOST_STATIC_ASSERT((sizeof(rgb565_pixel_t)==2)); // define a bgr556 pixel - typedef const packed_channel_reference bgr556_channel0_t; - typedef const packed_channel_reference bgr556_channel1_t; - typedef const packed_channel_reference bgr556_channel2_t; - - typedef heterogeneous_packed_pixel, bgr_layout_t> bgr556_pixel_t; - boost::function_requires >(); + typedef packed_pixel_type, bgr_layout_t>::type bgr556_pixel_t; + boost::function_requires >(); // Create a zero packed pixel and a full regular unpacked pixel. rgb565_pixel_t r565;//((uint16_t)0); rgb8_pixel_t rgb_full(255,255,255); // Convert all channels of the unpacked pixel to the packed one & assert the packed one is full - get_color(r565,red_t()) = channel_convert(get_color(rgb_full,red_t())); - get_color(r565,green_t()) = channel_convert(get_color(rgb_full,green_t())); - get_color(r565,blue_t()) = channel_convert(get_color(rgb_full,blue_t())); + get_color(r565,red_t()) = channel_convert::type>(get_color(rgb_full,red_t())); + get_color(r565,green_t()) = channel_convert::type>(get_color(rgb_full,green_t())); + get_color(r565,blue_t()) = channel_convert::type>(get_color(rgb_full,blue_t())); error_if(r565 != rgb565_pixel_t((uint16_t)65535)); // rgb565 is compatible with bgr556. Test interoperability @@ -274,9 +266,36 @@ void test_packed_pixel() { do_basic_test, value_core >(r565).test_heterogeneous(); - // Color conversion works, but there are warnings - // color_convert(r565,rgb_full); - // color_convert(rgb_full,r565); + color_convert(r565,rgb_full); + color_convert(rgb_full,r565); + + // Test bit-aligned pixel reference + typedef const bit_aligned_pixel_reference, bgr_layout_t, true> bgr121_ref_t; + typedef const bit_aligned_pixel_reference, rgb_layout_t, true> rgb121_ref_t; + typedef rgb121_ref_t::value_type rgb121_pixel_t; + rgb121_pixel_t p121; + do_basic_test, reference_core >(p121).test_heterogeneous(); + do_basic_test, reference_core >(p121).test_heterogeneous(); + + BOOST_STATIC_ASSERT((pixel_reference_is_proxy::value)); + BOOST_STATIC_ASSERT((pixel_reference_is_proxy::value)); + + BOOST_STATIC_ASSERT(!(pixel_reference_is_proxy::value)); + BOOST_STATIC_ASSERT(!(pixel_reference_is_proxy::value)); + BOOST_STATIC_ASSERT(!(pixel_reference_is_proxy::value)); + + BOOST_STATIC_ASSERT( (pixel_reference_is_mutable< rgb8_pixel_t&>::value)); + BOOST_STATIC_ASSERT(!(pixel_reference_is_mutable::value)); + + BOOST_STATIC_ASSERT((pixel_reference_is_mutable::value)); + BOOST_STATIC_ASSERT((pixel_reference_is_mutable< rgb8_planar_ref_t >::value)); + + BOOST_STATIC_ASSERT(!(pixel_reference_is_mutable::value)); + BOOST_STATIC_ASSERT(!(pixel_reference_is_mutable< rgb8c_planar_ref_t >::value)); + + BOOST_STATIC_ASSERT( (pixel_reference_is_mutable::value)); + BOOST_STATIC_ASSERT(!(pixel_reference_is_mutable::value)); + } void test_pixel() { diff --git a/test/pixel_iterator.cpp b/test/pixel_iterator.cpp index ff5d217e1b..b59eb8b605 100644 --- a/test/pixel_iterator.cpp +++ b/test/pixel_iterator.cpp @@ -16,10 +16,13 @@ #include #include #include +#include +#include #include #include #include #include +#include using namespace boost::gil; using namespace std; @@ -38,7 +41,15 @@ void test_pixel_iterator() { boost::function_requires >(); boost::function_requires >(); - boost::function_requires > >(); + boost::function_requires > >(); + + typedef const bit_aligned_pixel_reference, bgr_layout_t, true> bgr121_ref_t; + typedef bit_aligned_pixel_iterator bgr121_ptr_t; + + boost::function_requires >(); + boost::function_requires >(); + boost::function_requires >(); + boost::function_requires >(); // TEST dynamic_step_t BOOST_STATIC_ASSERT(( boost::is_same::type>::value )); @@ -69,10 +80,32 @@ void test_pixel_iterator() { BOOST_STATIC_ASSERT(iterator_is_step< rgb2gray_step_ptr1 >::value); BOOST_STATIC_ASSERT(( boost::is_same< rgb2gray_step_ptr1, dynamic_x_step_type::type >::value)); - typedef byte_addressable_step_iterator > rgb2gray_step_ptr2; + typedef memory_based_step_iterator > rgb2gray_step_ptr2; BOOST_STATIC_ASSERT(iterator_is_step< rgb2gray_step_ptr2 >::value); BOOST_STATIC_ASSERT(( boost::is_same< rgb2gray_step_ptr2, dynamic_x_step_type::type >::value)); make_step_iterator(rgb2gray_step_ptr2(),2); + +// bit_aligned iterators test + + // Mutable reference to a BGR232 pixel + typedef const bit_aligned_pixel_reference, bgr_layout_t, true> bgr232_ref_t; + + // A mutable iterator over BGR232 pixels + typedef bit_aligned_pixel_iterator bgr232_ptr_t; + + // BGR232 pixel value. It is a packed_pixel of size 1 byte. (The last bit is unused) + typedef std::iterator_traits::value_type bgr232_pixel_t; + BOOST_STATIC_ASSERT((sizeof(bgr232_pixel_t)==1)); + + bgr232_pixel_t red(0,0,3); // = 0RRGGGBB, = 01100000 + + // a buffer of 7 bytes fits exactly 8 BGR232 pixels. + unsigned char pix_buffer[7]; + std::fill(pix_buffer,pix_buffer+7,0); + bgr232_ptr_t pix_it(&pix_buffer[0],0); // start at bit 0 of the first pixel + for (int i=0; i<8; ++i) { + *pix_it++ = red; + } } // TODO: Make better tests. Use some code from below. @@ -91,17 +124,17 @@ void test_pixel_iterator() { rgba8_pixel_t rgba8; rgb8_ptr_t ptr1=&rgb8; - byte_advance(ptr1, 3); - const rgb8_ptr_t ptr2=byte_advanced(ptr1,10); + memunit_advance(ptr1, 3); + const rgb8_ptr_t ptr2=memunit_advanced(ptr1,10); - byte_distance(ptr1,ptr2); - const rgb8_pixel_t& ref=byte_advanced_ref(ptr1,10); ignore_unused_variable_warning(ref); + memunit_distance(ptr1,ptr2); + const rgb8_pixel_t& ref=memunit_advanced_ref(ptr1,10); ignore_unused_variable_warning(ref); rgb8_planar_ptr_t planarPtr1(&rgb8); rgb8_planar_ptr_t planarPtr2(&rgb8); - byte_advance(planarPtr1,10); - byte_distance(planarPtr1,planarPtr2); - rgb8_planar_ptr_t planarPtr3=byte_advanced(planarPtr1,10); + memunit_advance(planarPtr1,10); + memunit_distance(planarPtr1,planarPtr2); + rgb8_planar_ptr_t planarPtr3=memunit_advanced(planarPtr1,10); // planarPtr2=&rgba8; @@ -112,7 +145,7 @@ void test_pixel_iterator() { assert(*(planarPtr1+5)==planarPtr1[5]); - rgb8_planar_ref_t planarRef=byte_advanced_ref(planarPtr1,10); + rgb8_planar_ref_t planarRef=memunit_advanced_ref(planarPtr1,10); rgb8_step_ptr_t stepIt(&rgb8,5); stepIt++; @@ -122,7 +155,7 @@ void test_pixel_iterator() { rgb8_step_ptr_t stepIt3(&rgb8,5); rgb8_pixel_t& ref1=stepIt3[5]; -// bool v=boost::is_POD >::value_type>::value; +// bool v=boost::is_POD >::value_type>::value; // v=boost::is_POD::value; // v=boost::is_POD::value; @@ -177,12 +210,12 @@ void test_pixel_iterator() { - // byte_addressable_step_iterator stepIt3Err=stepIt+10; // error: non-const from const iterator + // memory_based_step_iterator stepIt3Err=stepIt+10; // error: non-const from const iterator - byte_addressable_2d_locator xy_locator(ptr,27); + memory_based_2d_locator xy_locator(ptr,27); xy_locator.x()++; -// byte_addressable_step_iterator& yit=xy_locator.y(); +// memory_based_step_iterator& yit=xy_locator.y(); xy_locator.y()++; xy_locator+=point2(3,4); // *xy_locator=(xy_locator(-1,0)+xy_locator(0,1))/2; @@ -252,7 +285,7 @@ ignore_unused_variable_warning(rgb8_const_ptr_err); *rgb8_pptr=rgb8; *rgb8_pptr=crgb8; - byte_advance(rgb8_pptr,3); - byte_advance(rgb8_pptr,-3); + memunit_advance(rgb8_pptr,3); + memunit_advance(rgb8_pptr,-3); } */