|
Boost-Commit : |
From: lbourdev_at_[hidden]
Date: 2007-11-11 14:29:07
Author: lbourdev
Date: 2007-11-11 14:29:06 EST (Sun, 11 Nov 2007)
New Revision: 41013
URL: http://svn.boost.org/trac/boost/changeset/41013
Log:
GIL: Documentation
Added:
trunk/libs/gil/doc/adobe_logo.gif (contents, props changed)
trunk/libs/gil/doc/adobe_source.css (contents, props changed)
trunk/libs/gil/doc/boost.png (contents, props changed)
trunk/libs/gil/doc/example/
trunk/libs/gil/doc/example/affine.cpp (contents, props changed)
trunk/libs/gil/doc/example/convolution.cpp (contents, props changed)
trunk/libs/gil/doc/example/dynamic_image.cpp (contents, props changed)
trunk/libs/gil/doc/example/histogram.cpp (contents, props changed)
trunk/libs/gil/doc/example/interleaved_ptr.cpp (contents, props changed)
trunk/libs/gil/doc/example/interleaved_ptr.hpp (contents, props changed)
trunk/libs/gil/doc/example/interleaved_ref.hpp (contents, props changed)
trunk/libs/gil/doc/example/mandelbrot.cpp (contents, props changed)
trunk/libs/gil/doc/example/packed_pixel.cpp (contents, props changed)
trunk/libs/gil/doc/example/resize.cpp (contents, props changed)
trunk/libs/gil/doc/example/x_gradient.cpp (contents, props changed)
trunk/libs/gil/doc/html/
trunk/libs/gil/doc/html/adobe_source.css (contents, props changed)
trunk/libs/gil/doc/html/doxygen.png (contents, props changed)
trunk/libs/gil/doc/html/gildesignguide.html (contents, props changed)
trunk/libs/gil/doc/html/giltutorial.html (contents, props changed)
trunk/libs/gil/doc/html/interleaved.jpg (contents, props changed)
trunk/libs/gil/doc/html/mandel.jpg (contents, props changed)
trunk/libs/gil/doc/html/monkey_steps.jpg (contents, props changed)
trunk/libs/gil/doc/html/planar.jpg (contents, props changed)
trunk/libs/gil/doc/html/step_iterator.gif (contents, props changed)
Added: trunk/libs/gil/doc/adobe_logo.gif
==============================================================================
Binary file. No diff available.
Added: trunk/libs/gil/doc/adobe_source.css
==============================================================================
--- (empty file)
+++ trunk/libs/gil/doc/adobe_source.css 2007-11-11 14:29:06 EST (Sun, 11 Nov 2007)
@@ -0,0 +1,330 @@
+BODY,H1,H2,H3,H4,H5,H6,P,CENTER,TD,TH,UL,DL,DIV {
+ font-family: Verdana, Arial, Helvetica, sans-serif;
+ font-size: 12px;
+}
+
+CODE {
+ font-family: Monaco, Courier New, Fixed, monospace;
+ font-size: 12px;
+}
+
+BODY,TD {
+ font-size: 12px;
+ margin: 0;
+ padding: 0;
+ background: white;
+ color: black;
+}
+
+TABLE {
+ margin: 0;
+ padding: 0;
+ border-spacing: 0;
+}
+
+H1 {
+ text-align: center;
+ font-size: 18px;
+}
+
+H2 {
+ font-size: 16px;
+ border-top: 1px dotted #666666;
+ border-bottom: 1px dotted #666666;
+}
+
+H3 {
+ font-size: 14px;
+ border-top: 1px dotted #666666;
+ border-bottom: 1px dotted #666666;
+}
+
+CAPTION {
+ font-weight: bold
+}
+
+DIV.qindex {
+ width: 100%;
+ background-color: #e8eef2;
+ border: 1px solid #84b0c7;
+ text-align: center;
+ margin: 2px;
+ padding: 2px;
+ line-height: 140%;
+}
+
+DIV.nav {
+ display: none;
+ width: 100%;
+ text-align: center;
+ margin: 2px;
+ padding: 2px;
+ line-height: 140%;
+}
+
+DIV.navtab {
+ background-color: #e8eef2;
+ border: 1px solid #84b0c7;
+ text-align: center;
+ margin: 2px;
+ margin-right: 15px;
+ padding: 2px;
+}
+
+TD.navtab {
+ font-size: 12px;
+}
+
+A.qindex, A.qindex:visited {
+ text-decoration: none;
+ font-weight: bold;
+ color: #1A419D;
+}
+
+A.qindex:hover {
+ text-decoration: none;
+ background-color: #ddddff;
+}
+
+A.qindexHL {
+ text-decoration: none;
+ font-weight: bold;
+ background-color: #6666cc;
+ color: #ffffff;
+ border: 1px double #9295C2;
+}
+
+A.qindexHL:hover {
+ text-decoration: none;
+ background-color: #6666cc;
+ color: #ffffff;
+}
+
+A.qindexHL:visited {
+ text-decoration: none;
+ background-color: #6666cc;
+ color: #ffffff
+}
+
+A.el {
+ text-decoration: none;
+}
+
+A.elRef {
+}
+
+A.code:link, A.code:visited {
+ border-bottom: 1px dotted darkred;
+ color: darkred;
+}
+
+A.codeRef:link, A.codeRef:visited {
+ color: darkred;
+ border-bottom: 1px dotted darkred;
+}
+
+A:link, A:visited {
+ text-decoration: none;
+ color: red;
+ border-bottom: 1px solid red;
+}
+
+A:link:hover, A:visited:hover {
+ text-decoration: none;
+ color: darkred;
+ border-bottom: 1px solid darkred;
+}
+
+DL.el {
+ margin-left: -1cm
+}
+
+.fragment {
+ font-family: Monaco, Courier New, Fixed, monospace;
+ font-size: 10px;
+}
+
+PRE.fragment {
+ border: 1px solid lightgrey;
+ margin: 4px;
+ padding: 4px;
+ line-height: 150%;
+}
+
+DIV.ah {
+ background-color: black;
+ color: white;
+ margin-bottom: 3px;
+ margin-top: 3px
+}
+
+TD.md {
+ font-family: Monaco, Courier New, Fixed, monospace;
+ background: transparent;
+}
+
+TD.mdPrefix {
+ font-family: Monaco, Courier New, Fixed, monospace;
+ color: #555555;
+ font-size: 12px;
+ background: transparent;
+}
+
+TD.mdname1 {
+ color: darkred;
+ background: transparent;
+}
+
+TD.mdname {
+ color: darkred;
+ white-space: nowrap;
+ background: transparent;
+}
+
+DIV.groupHeader {
+ margin-left: 16px;
+ margin-top: 12px;
+ margin-bottom: 6px;
+ font-weight: bold;
+}
+
+DIV.groupText { margin-left: 16px; font-style: italic; font-size: 12px }
+
+TD.indexkey {
+ padding : 10px;
+ margin: 0px;
+ border-bottom: 1px solid #666666;
+}
+
+TD.indexvalue {
+ font-style: italic;
+ padding : 10px;
+ margin: 0px;
+ border-bottom: 1px solid #666666;
+}
+
+TR.memlist {
+ line-height: 150%;
+}
+
+TR.memlist td, TR.memlist a {
+ font-family: Monaco, Courier New, Fixed, monospace;
+}
+
+P.formulaDsp { text-align: center; }
+
+IMG.formulaDsp { }
+IMG.formulaInl { vertical-align: middle; }
+IMG {
+ border: none;
+}
+
+.footerdiv {
+ background-color: #eeeeee;
+}
+
+.footerdiv, .footerdiv a, .footerdiv p, .footerdiv ul , .footerdiv ul li {
+ font-size: 9px;
+ color: grey;
+ border: none;
+ margin: 0;
+ padding: 0;
+ margin-bottom: 3px;
+}
+
+.footerdiv ul {
+ list-style: none;
+ display: table;
+ margin: 0;
+ padding: 0;
+}
+
+.footerdiv ul li {
+ float: left;
+}
+
+SPAN.keyword { color: mediumblue }
+SPAN.keywordtype { color: mediumblue }
+SPAN.keywordflow { color: mediumblue }
+SPAN.comment { color: darkgreen }
+SPAN.preprocessor { color: mediumblue }
+SPAN.stringliteral { color: maroon }
+SPAN.charliteral { color: maroon }
+
+.mdTable {
+ border: 1px solid #666666;
+ background-color: lavender;
+ padding: 10px;
+ width: 100%;
+}
+
+.mdRow {
+ background: lavender;
+}
+
+.mdescLeft {
+ font-style: italic;
+ border: none;
+ margin: 0px;
+}
+
+.mdescRight {
+ font-style: italic;
+ border: none;
+ margin: 0px;
+}
+
+.memItemLeft {
+ font-family: Monaco, Courier New, Fixed, monospace;
+ padding: 4px;
+ border: none;
+ border-top: 1px solid lightgray;
+}
+
+.memItemRight {
+ font-family: Monaco, Courier New, Fixed, monospace;
+ padding: 4px;
+ border: none;
+ border-top: 1px solid lightgray;
+}
+
+.memTemplItemLeft {
+ font-family: Monaco, Courier New, Fixed, monospace;
+ padding: 4px;
+ border: none;
+}
+
+.memTemplItemRight {
+ font-family: Monaco, Courier New, Fixed, monospace;
+ padding: 4px;
+ border: none;
+}
+
+.memTemplParams {
+ font-family: Monaco, Courier New, Fixed, monospace;
+ padding: 4px;
+ border: none;
+ border-top: 1px solid lightgray;
+ color: #666666;
+}
+
+TD.tiny {
+ font-size: 10px;
+}
+
+.dirtab {
+ padding: 4px;
+ border-collapse: collapse;
+ border: 1px solid #84b0c7;
+}
+
+TH.dirtab {
+ background: #e8eef2;
+ font-weight: bold;
+}
+
+HR {
+ height: 1px;
+ border: none;
+ border-top: 1px solid black;
+}
Added: trunk/libs/gil/doc/boost.png
==============================================================================
Binary file. No diff available.
Added: trunk/libs/gil/doc/example/affine.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/gil/doc/example/affine.cpp 2007-11-11 14:29:06 EST (Sun, 11 Nov 2007)
@@ -0,0 +1,46 @@
+/*
+ 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 resample_pixels() in the numeric extension
+/// \author Lubomir Bourdev and Hailin Jin
+/// \date February 27, 2007
+
+#include <boost/gil/image.hpp>
+#include <boost/gil/typedefs.hpp>
+#include <boost/gil/extension/io/jpeg_io.hpp>
+#include <boost/gil/extension/numeric/sampler.hpp>
+#include <boost/gil/extension/numeric/resample.hpp>
+
+int main() {
+ using namespace boost::gil;
+
+ rgb8_image_t img;
+ jpeg_read_image("test.jpg",img);
+
+ // test resample_pixels
+ // Transform the image by an arbitrary affine transformation using nearest-neighbor resampling
+ rgb8_image_t transf(rgb8_image_t::point_t(view(img).dimensions()*2));
+ fill_pixels(view(transf),rgb8_pixel_t(255,0,0)); // the background is red
+
+ matrix3x2<double> mat = matrix3x2<double>::get_translate(-point2<double>(200,250)) *
+ matrix3x2<double>::get_rotate(-15*3.14/180.0);
+ resample_pixels(const_view(img), view(transf), mat, nearest_neighbor_sampler());
+ jpeg_write_view("out-affine.jpg", view(transf));
+
+ return 0;
+}
Added: trunk/libs/gil/doc/example/convolution.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/gil/doc/example/convolution.cpp 2007-11-11 14:29:06 EST (Sun, 11 Nov 2007)
@@ -0,0 +1,85 @@
+/*
+ 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
+/// \date February 27, 2007
+
+#include <boost/gil/image.hpp>
+#include <boost/gil/typedefs.hpp>
+#include <boost/gil/extension/io/jpeg_io.hpp>
+#include <boost/gil/extension/numeric/kernel.hpp>
+#include <boost/gil/extension/numeric/convolve.hpp>
+
+int main() {
+ using namespace boost::gil;
+
+ rgb8_image_t img;
+ jpeg_read_image("test.jpg",img);
+
+ // Convolve the rows and the columns of the image with a fixed kernel
+ rgb8_image_t convolved(img);
+
+ // 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<float,9> kernel(gaussian_1,4);
+
+ convolve_rows_fixed<rgb32f_pixel_t>(const_view(convolved),kernel,view(convolved));
+ convolve_cols_fixed<rgb32f_pixel_t>(const_view(convolved),kernel,view(convolved));
+ jpeg_write_view("out-convolution.jpg", view(convolved));
+
+ // This is how to use a resizable kernel
+ kernel_1d<float> kernel2(gaussian_1,9,4);
+ convolve_rows<rgb32f_pixel_t>(const_view(img),kernel2,view(img));
+ convolve_cols<rgb32f_pixel_t>(const_view(img),kernel2,view(img));
+ jpeg_write_view("out-convolution2.jpg", view(img));
+
+ return 0;
+}
Added: trunk/libs/gil/doc/example/dynamic_image.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/gil/doc/example/dynamic_image.cpp 2007-11-11 14:29:06 EST (Sun, 11 Nov 2007)
@@ -0,0 +1,34 @@
+/*
+ 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
+/// \date February 27, 2007
+
+#include <boost/mpl/vector.hpp>
+#include <boost/gil/extension/dynamic_image/any_image.hpp>
+#include <boost/gil/extension/io/jpeg_dynamic_io.hpp>
+
+int main() {
+ using namespace boost::gil;
+
+ typedef boost::mpl::vector<gray8_image_t, rgb8_image_t, gray16_image_t, rgb16_image_t> my_images_t;
+
+ any_image<my_images_t> dynamic_img;
+ jpeg_read_image("test.jpg",dynamic_img);
+
+ // Save the image upside down, preserving its native color space and channel depth
+ jpeg_write_view("out-dynamic_image.jpg",flipped_up_down_view(const_view(dynamic_img)));
+
+ return 0;
+}
Added: trunk/libs/gil/doc/example/histogram.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/gil/doc/example/histogram.cpp 2007-11-11 14:29:06 EST (Sun, 11 Nov 2007)
@@ -0,0 +1,53 @@
+/*
+ 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
+/// \date February 27, 2007
+
+#include <algorithm>
+#include <fstream>
+#include <boost/gil/image.hpp>
+#include <boost/gil/typedefs.hpp>
+#include <boost/gil/color_convert.hpp>
+#include <boost/gil/extension/io/jpeg_io.hpp>
+
+using namespace boost::gil;
+
+template <typename GrayView, typename R>
+void gray_image_hist(const GrayView& img_view, R& hist) {
+// for_each_pixel(img_view,++lambda::var(hist)[lambda::_1]);
+ for (typename GrayView::iterator it=img_view.begin(); it!=img_view.end(); ++it)
+ ++hist[*it];
+}
+
+template <typename V, typename R>
+void get_hist(const V& img_view, R& hist) {
+ gray_image_hist(color_converted_view<gray8_pixel_t>(img_view), hist);
+}
+
+int main() {
+ rgb8_image_t img;
+ jpeg_read_image("test.jpg",img);
+
+ int histogram[256];
+ std::fill(histogram,histogram+256,0);
+ get_hist(const_view(img),histogram);
+
+ std::fstream histo_file("out-histogram.txt",std::ios::out);
+ for(std::size_t ii=0;ii<256;++ii)
+ histo_file << histogram[ii] << std::endl;
+ histo_file.close();
+
+ return 0;
+}
Added: trunk/libs/gil/doc/example/interleaved_ptr.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/gil/doc/example/interleaved_ptr.cpp 2007-11-11 14:29:06 EST (Sun, 11 Nov 2007)
@@ -0,0 +1,74 @@
+/*
+ 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
+/// \date February 27, 2007
+
+#ifdef WIN32
+#define _CRT_SECURE_NO_DEPRECATE 1
+#pragma warning(disable : 4244) //
+#pragma warning(disable : 4996) // MSFT declared it deprecated
+#endif
+
+// gcc doesn't compile unless we forward-declare at_c before we include gil...
+namespace boost { namespace gil {
+ template <typename ChannelReference, typename Layout> struct interleaved_ref;
+ template <typename ColorBase> struct element_reference_type;
+
+ template <int K, typename ChannelReference, typename Layout>
+ typename element_reference_type<interleaved_ref<ChannelReference,Layout> >::type
+ at_c(const interleaved_ref<ChannelReference,Layout>& p);
+} }
+
+#include <iostream>
+#include <boost/gil/extension/io/jpeg_dynamic_io.hpp>
+#include "interleaved_ptr.hpp"
+
+int main(int argc, unsigned char* argv[])
+{
+ using namespace boost::gil;
+
+ typedef interleaved_ptr<unsigned char*, rgb_layout_t> rgb8_interleaved_ptr;
+ typedef interleaved_ptr<const unsigned char*, rgb_layout_t> rgb8c_interleaved_ptr;
+
+ boost::function_requires<MutablePixelIteratorConcept<rgb8_interleaved_ptr> >();
+ boost::function_requires<PixelIteratorConcept<rgb8c_interleaved_ptr> >();
+ boost::function_requires<MemoryBasedIteratorConcept<memory_based_step_iterator<rgb8_interleaved_ptr> > >();
+
+ boost::function_requires<MutablePixelConcept<rgb8_interleaved_ptr::value_type> >();
+ boost::function_requires<PixelConcept<rgb8c_interleaved_ptr::value_type> >();
+
+ typedef type_from_x_iterator<rgb8_interleaved_ptr >::view_t rgb8_interleaved_view_t;
+ typedef type_from_x_iterator<rgb8c_interleaved_ptr>::view_t rgb8c_interleaved_view_t;
+
+ boost::function_requires<MutableImageViewConcept<rgb8_interleaved_view_t> >();
+ boost::function_requires<ImageViewConcept<rgb8c_interleaved_view_t> >();
+
+ rgb8_image_t img;
+ jpeg_read_image("test.jpg", img);
+
+ // Get a raw pointer to the RGB buffer
+ unsigned char* raw_ptr=&view(img)[0][0];
+
+ // 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_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));
+
+ return 0;
+}
+
+
Added: trunk/libs/gil/doc/example/interleaved_ptr.hpp
==============================================================================
--- (empty file)
+++ trunk/libs/gil/doc/example/interleaved_ptr.hpp 2007-11-11 14:29:06 EST (Sun, 11 Nov 2007)
@@ -0,0 +1,200 @@
+/*
+ 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 on how to create a pixel iterator
+/// \author Lubomir Bourdev and Hailin Jin \n
+/// Adobe Systems Incorporated
+/// \date 2005-2007 \n Last updated on February 26, 2007
+///
+/// Definitions of standard GIL channel models
+///
+////////////////////////////////////////////////////////////////////////////////////////
+
+#ifndef GIL_INTERLEAVED_PTR_HPP
+#define GIL_INTERLEAVED_PTR_HPP
+
+#include <boost/gil/pixel_iterator.hpp>
+#include "interleaved_ref.hpp"
+
+namespace boost { namespace gil {
+
+/////////////////////////////////////////////////////////////////////////
+///
+/// A model of an interleaved pixel iterator. Contains an iterator to the first channel of the current pixel
+///
+/// Models:
+/// MutablePixelIteratorConcept
+/// PixelIteratorConcept
+/// boost_concepts::RandomAccessTraversalConcept
+/// PixelBasedConcept
+/// HomogeneousPixelBasedConcept
+/// PixelBasedConcept
+/// ByteAdvanceableConcept
+/// HasDynamicXStepTypeConcept
+///
+/////////////////////////////////////////////////////////////////////////
+
+template <typename ChannelPtr, // Models Channel Iterator (examples: unsigned char* or const unsigned char*)
+ typename Layout> // A layout (includes the color space and channel ordering)
+struct interleaved_ptr : public boost::iterator_facade<interleaved_ptr<ChannelPtr,Layout>,
+ pixel<typename std::iterator_traits<ChannelPtr>::value_type,Layout>,
+ boost::random_access_traversal_tag,
+ const interleaved_ref<typename std::iterator_traits<ChannelPtr>::reference,Layout> >
+{
+private:
+ typedef boost::iterator_facade<interleaved_ptr<ChannelPtr,Layout>,
+ pixel<typename std::iterator_traits<ChannelPtr>::value_type,Layout>,
+ boost::random_access_traversal_tag,
+ const interleaved_ref<typename std::iterator_traits<ChannelPtr>::reference,Layout> > parent_t;
+ typedef typename std::iterator_traits<ChannelPtr>::value_type channel_t;
+public:
+ typedef typename parent_t::reference reference;
+ typedef typename parent_t::difference_type difference_type;
+
+ interleaved_ptr() {}
+ interleaved_ptr(const interleaved_ptr& ptr) : _channels(ptr._channels) {}
+ template <typename CP> interleaved_ptr(const interleaved_ptr<CP,Layout>& ptr) : _channels(ptr._channels) {}
+
+ interleaved_ptr(const ChannelPtr& channels) : _channels(channels) {}
+
+ // Construct from a pointer to the reference type. Not required by concepts but important
+ interleaved_ptr(reference* pix) : _channels(&((*pix)[0])) {}
+ interleaved_ptr& operator=(reference* pix) { _channels=&((*pix)[0]); return *this; }
+
+ /// For some reason operator[] provided by boost::iterator_facade 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 memunit_advanced_ref(*this,d*sizeof(channel_t));}
+
+ // Put this for every iterator whose reference is a proxy type
+ reference operator->() const { return **this; }
+
+ // Channels accessor (not required by any concept)
+ const ChannelPtr& channels() const { return _channels; }
+ ChannelPtr& channels() { return _channels; }
+
+ // Not required by concepts but useful
+ static const std::size_t num_channels = mpl::size<typename Layout::color_space_t>::value;
+private:
+ ChannelPtr _channels;
+ friend class boost::iterator_core_access;
+ template <typename CP, typename L> friend struct interleaved_ptr;
+
+ void increment() { _channels+=num_channels; }
+ void decrement() { _channels-=num_channels; }
+ void advance(ptrdiff_t d) { _channels+=num_channels*d; }
+
+ ptrdiff_t distance_to(const interleaved_ptr& it) const { return (it._channels-_channels)/num_channels; }
+ bool equal(const interleaved_ptr& it) const { return _channels==it._channels; }
+
+ reference dereference() const { return reference(_channels); }
+};
+
+/////////////////////////////
+// PixelIteratorConcept
+/////////////////////////////
+
+// To get from the channel pointer a channel pointer to const, we have to go through the channel traits, which take a model of channel
+// So we can get a model of channel from the channel pointer via iterator_traits. Notice that we take the iterator_traits::reference and not
+// iterator_traits::value_type. This is because sometimes multiple reference and pointer types share the same value type. An example of this is
+// GIL's planar reference and iterator ("planar_pixel_reference" and "planar_pixel_iterator") which share the class "pixel" as the value_type. The
+// class "pixel" is also the value type for interleaved pixel references. Here we are dealing with channels, not pixels, but the principles still apply.
+template <typename ChannelPtr, typename Layout>
+struct const_iterator_type<interleaved_ptr<ChannelPtr,Layout> > {
+private:
+ typedef typename std::iterator_traits<ChannelPtr>::reference channel_ref_t;
+ typedef typename channel_traits<channel_ref_t>::const_pointer channel_const_ptr_t;
+public:
+ typedef interleaved_ptr<channel_const_ptr_t,Layout> type;
+};
+
+template <typename ChannelPtr, typename Layout>
+struct iterator_is_mutable<interleaved_ptr<ChannelPtr,Layout> > : public boost::mpl::true_ {};
+template <typename Channel, typename Layout>
+struct iterator_is_mutable<interleaved_ptr<const Channel*,Layout> > : public boost::mpl::false_ {};
+
+template <typename ChannelPtr, typename Layout>
+struct is_iterator_adaptor<interleaved_ptr<ChannelPtr,Layout> > : public boost::mpl::false_ {};
+
+/////////////////////////////
+// PixelBasedConcept
+/////////////////////////////
+
+template <typename ChannelPtr, typename Layout>
+struct color_space_type<interleaved_ptr<ChannelPtr,Layout> > {
+ typedef typename Layout::color_space_t type;
+};
+
+template <typename ChannelPtr, typename Layout>
+struct channel_mapping_type<interleaved_ptr<ChannelPtr,Layout> > {
+ typedef typename Layout::channel_mapping_t type;
+};
+
+template <typename ChannelPtr, typename Layout>
+struct is_planar<interleaved_ptr<ChannelPtr,Layout> > : public mpl::false_ {};
+
+/////////////////////////////
+// HomogeneousPixelBasedConcept
+/////////////////////////////
+
+template <typename ChannelPtr, typename Layout>
+struct channel_type<interleaved_ptr<ChannelPtr,Layout> > {
+ typedef typename std::iterator_traits<ChannelPtr>::value_type type;
+};
+
+/////////////////////////////
+// ByteAdvanceableConcept
+/////////////////////////////
+
+template <typename ChannelPtr, typename Layout>
+inline std::ptrdiff_t memunit_step(const interleaved_ptr<ChannelPtr,Layout>&) {
+ return sizeof(typename std::iterator_traits<ChannelPtr>::value_type)* // size of each channel in bytes
+ interleaved_ptr<ChannelPtr,Layout>::num_channels; // times the number of channels
+}
+
+template <typename ChannelPtr, typename Layout>
+inline std::ptrdiff_t memunit_distance(const interleaved_ptr<ChannelPtr,Layout>& p1, const interleaved_ptr<ChannelPtr,Layout>& p2) {
+ return memunit_distance(p1.channels(),p2.channels());
+}
+
+template <typename ChannelPtr, typename Layout>
+inline void memunit_advance(interleaved_ptr<ChannelPtr,Layout>& p, std::ptrdiff_t diff) {
+ memunit_advance(p.channels(), diff);
+}
+
+template <typename ChannelPtr, typename Layout>
+inline interleaved_ptr<ChannelPtr,Layout> memunit_advanced(const interleaved_ptr<ChannelPtr,Layout>& p, std::ptrdiff_t diff) {
+ interleaved_ptr<ChannelPtr,Layout> ret=p;
+ memunit_advance(ret, diff);
+ return ret;
+}
+
+template <typename ChannelPtr, typename Layout>
+inline typename interleaved_ptr<ChannelPtr,Layout>::reference memunit_advanced_ref(const interleaved_ptr<ChannelPtr,Layout>& p, std::ptrdiff_t diff) {
+ interleaved_ptr<ChannelPtr,Layout> ret=p;
+ memunit_advance(ret, diff);
+ return *ret;
+}
+
+/////////////////////////////
+// HasDynamicXStepTypeConcept
+/////////////////////////////
+
+template <typename ChannelPtr, typename Layout>
+struct dynamic_x_step_type<interleaved_ptr<ChannelPtr,Layout> > {
+ typedef memory_based_step_iterator<interleaved_ptr<ChannelPtr,Layout> > type;
+};
+
+} } // namespace boost::gil
+
+#endif
Added: trunk/libs/gil/doc/example/interleaved_ref.hpp
==============================================================================
--- (empty file)
+++ trunk/libs/gil/doc/example/interleaved_ref.hpp 2007-11-11 14:29:06 EST (Sun, 11 Nov 2007)
@@ -0,0 +1,165 @@
+/*
+ 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 on how to create a new model of a pixel reference
+/// \author Lubomir Bourdev and Hailin Jin \n
+/// Adobe Systems Incorporated
+/// \date 2005-2007 \n Last updated on February 26, 2007
+//////
+////////////////////////////////////////////////////////////////////////////////////////
+
+#ifndef GIL_INTERLEAVED_REF_HPP
+#define GIL_INTERLEAVED_REF_HPP
+
+#include <boost/mpl/range_c.hpp>
+#include <boost/mpl/vector_c.hpp>
+#include <boost/gil/extension/dynamic_image/dynamic_image_all.hpp>
+
+namespace boost { namespace gil {
+
+
+/////////////////////////////////////////////////////////////////////////
+///
+/// A model of an interleaved pixel reference. Holds a pointer to the first channel
+/// MODELS:
+/// MutableHomogeneousPixelConcept
+/// MutableHomogeneousColorBaseConcept
+/// MutableColorBaseConcept
+/// HomogeneousColorBaseConcept
+/// ColorBaseConcept
+/// HomogeneousPixelBasedConcept
+/// PixelBasedConcept
+///
+/// For planar reference proxies to work properly, all of their methods must be const-qualified
+/// and their iterator's reference type must be const-qualified.
+/// Mutability of the reference proxy is part of its type (in this case, depends on the mutability of ChannelReference)
+/////////////////////////////////////////////////////////////////////////
+
+template <typename ChannelReference, // Models ChannelConcept. A channel reference, unsigned char& or const unsigned char&
+ typename Layout> // A layout (includes the color space and channel ordering)
+struct interleaved_ref {
+private:
+ typedef typename channel_traits<ChannelReference>::value_type channel_t;
+ typedef typename channel_traits<ChannelReference>::reference channel_reference_t;
+ typedef typename channel_traits<ChannelReference>::const_reference channel_const_reference_t;
+ typedef typename channel_traits<ChannelReference>::pointer channel_pointer_t;
+public:
+// Required by ColorBaseConcept
+ typedef Layout layout_t;
+
+ // 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 <typename P> interleaved_ref(const P& p) : _channels(p._channels) { check_compatible<P>(); }
+
+ template <typename P> bool operator==(const P& p) const { check_compatible<P>(); return static_equal(*this,p); }
+ template <typename P> bool operator!=(const P& p) const { return !(*this==p); }
+
+// Required by MutableColorBaseConcept
+
+ // Assignment from a compatible type
+ const interleaved_ref& operator=(const interleaved_ref& p) const { static_copy(p,*this); return *this; }
+ template <typename P> const interleaved_ref& operator=(const P& p) const { check_compatible<P>(); static_copy(p,*this); return *this; }
+
+// Required by PixelConcept
+ typedef pixel<channel_t, layout_t> value_type;
+ typedef interleaved_ref reference;
+ typedef interleaved_ref<channel_const_reference_t, layout_t> const_reference;
+ static const bool is_mutable = channel_traits<ChannelReference>::is_mutable;
+
+// Required by HomogeneousPixelConcept
+ ChannelReference operator[](std::size_t i) const { return _channels[i]; }
+
+// Custom constructor (not part of any concept)
+ explicit interleaved_ref(channel_pointer_t channels) : _channels(channels) {}
+// This is needed for the reference proxy to work properly
+ const interleaved_ref* operator->() const { return this; }
+private:
+ channel_pointer_t _channels;
+
+ template <typename Pixel> static void check_compatible() { gil_function_requires<PixelsCompatibleConcept<Pixel,interleaved_ref> >(); }
+};
+
+// Required by ColorBaseConcept
+template <typename ChannelReference, typename Layout, int K>
+struct kth_element_type<interleaved_ref<ChannelReference,Layout>,K> {
+ typedef ChannelReference type;
+};
+
+template <typename ChannelReference, typename Layout, int K>
+struct kth_element_reference_type<interleaved_ref<ChannelReference,Layout>,K> {
+ typedef ChannelReference type;
+};
+
+template <typename ChannelReference, typename Layout, int K>
+struct kth_element_const_reference_type<interleaved_ref<ChannelReference,Layout>,K> {
+ typedef typename channel_traits<ChannelReference>::const_reference type;
+};
+
+
+// Required by ColorBaseConcept
+template <int K, typename ChannelReference, typename Layout>
+typename element_reference_type<interleaved_ref<ChannelReference,Layout> >::type
+at_c(const interleaved_ref<ChannelReference,Layout>& p) { return p[K]; };
+
+// Required by HomogeneousColorBaseConcept
+template <typename ChannelReference, typename Layout>
+typename element_reference_type<interleaved_ref<ChannelReference,Layout> >::type
+dynamic_at_c(const interleaved_ref<ChannelReference,Layout>& p, std::size_t n) { return p[n]; };
+
+namespace detail {
+ struct swap_fn_t {
+ template <typename T> void operator()(T& x, T& y) const {
+ using std::swap;
+ swap(x,y);
+ }
+ };
+}
+
+// Required by MutableColorBaseConcept. The default std::swap does not do the right thing for proxy references - it swaps the references, not the values
+template <typename ChannelReference, typename Layout>
+void swap(interleaved_ref<ChannelReference,Layout>& x, interleaved_ref<ChannelReference,Layout>& y) {
+ static_for_each(x,y,detail::swap_fn_t());
+};
+
+// Required by PixelConcept
+template <typename ChannelReference, typename Layout>
+struct is_pixel<interleaved_ref<ChannelReference,Layout> > : public boost::mpl::true_ {};
+
+
+// Required by PixelBasedConcept
+template <typename ChannelReference, typename Layout>
+struct color_space_type<interleaved_ref<ChannelReference,Layout> > {
+ typedef typename Layout::color_space_t type;
+};
+
+// Required by PixelBasedConcept
+template <typename ChannelReference, typename Layout>
+struct channel_mapping_type<interleaved_ref<ChannelReference,Layout> > {
+ typedef typename Layout::channel_mapping_t type;
+};
+
+// Required by PixelBasedConcept
+template <typename ChannelReference, typename Layout>
+struct is_planar<interleaved_ref<ChannelReference,Layout> > : mpl::false_ {};
+
+// Required by HomogeneousPixelBasedConcept
+template <typename ChannelReference, typename Layout>
+struct channel_type<interleaved_ref<ChannelReference,Layout> > {
+ typedef typename channel_traits<ChannelReference>::value_type type;
+};
+
+} } // namespace boost::gil
+
+#endif
Added: trunk/libs/gil/doc/example/mandelbrot.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/gil/doc/example/mandelbrot.cpp 2007-11-11 14:29:06 EST (Sun, 11 Nov 2007)
@@ -0,0 +1,83 @@
+/*
+ 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 convolve_rows() and convolve_cols() in the numeric extension
+/// \author Lubomir Bourdev and Hailin Jin
+/// \date February 27, 2007
+
+#include <boost/gil/image.hpp>
+#include <boost/gil/typedefs.hpp>
+#include <boost/gil/extension/io/jpeg_io.hpp>
+
+using namespace boost::gil;
+
+// Models a Unary Function
+template <typename P> // Models PixelValueConcept
+struct mandelbrot_fn {
+ typedef point2<ptrdiff_t> point_t;
+
+ typedef mandelbrot_fn const_t;
+ typedef P value_type;
+ typedef value_type reference;
+ typedef value_type const_reference;
+ typedef point_t argument_type;
+ typedef reference result_type;
+ BOOST_STATIC_CONSTANT(bool, is_mutable=false);
+
+ value_type _in_color,_out_color;
+ point_t _img_size;
+ static const int MAX_ITER=100; // max number of iterations
+
+ mandelbrot_fn() {}
+ mandelbrot_fn(const point_t& sz, const value_type& in_color, const value_type& out_color) : _in_color(in_color), _out_color(out_color), _img_size(sz) {}
+
+ result_type operator()(const point_t& p) const {
+ // normalize the coords to (-2..1, -1.5..1.5)
+ // (actually make y -1.0..2 so it is asymmetric, so we can verify some view factory methods)
+ double t=get_num_iter(point2<double>(p.x/(double)_img_size.x*3-2, p.y/(double)_img_size.y*3-1.0f));//1.5f));
+ t=pow(t,0.2);
+
+ value_type ret;
+ for (int k=0; k<num_channels<P>::value; ++k)
+ ret[k]=(typename channel_type<P>::type)(_in_color[k]*t + _out_color[k]*(1-t));
+ return ret;
+ }
+
+private:
+ double get_num_iter(const point2<double>& p) const {
+ point2<double> Z(0,0);
+ for (int i=0; i<MAX_ITER; ++i) {
+ Z = point2<double>(Z.x*Z.x - Z.y*Z.y + p.x, 2*Z.x*Z.y + p.y);
+ if (Z.x*Z.x + Z.y*Z.y > 4)
+ return i/(double)MAX_ITER;
+ }
+ return 0;
+ }
+};
+
+int main() {
+ typedef mandelbrot_fn<rgb8_pixel_t> deref_t;
+ typedef deref_t::point_t point_t;
+ typedef virtual_2d_locator<deref_t,false> locator_t;
+ typedef image_view<locator_t> my_virt_view_t;
+
+ boost::function_requires<PixelLocatorConcept<locator_t> >();
+ gil_function_requires<StepIteratorConcept<locator_t::x_iterator> >();
+
+ point_t dims(200,200);
+ my_virt_view_t mandel(dims, locator_t(point_t(0,0), point_t(1,1), deref_t(dims, rgb8_pixel_t(255,0,255), rgb8_pixel_t(0,255,0))));
+ jpeg_write_view("out-mandelbrot.jpg",mandel);
+
+ return 0;
+}
+
Added: trunk/libs/gil/doc/example/packed_pixel.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/gil/doc/example/packed_pixel.cpp 2007-11-11 14:29:06 EST (Sun, 11 Nov 2007)
@@ -0,0 +1,68 @@
+/*
+ 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
+/// \date February 27, 2007
+///
+/// This test file demonstrates how to use packed pixel formats in GIL.
+/// A "packed" pixel is a pixel whose channels are bit ranges.
+/// Here we create an RGB image whose pixel has 16-bits, such as:
+/// bits [0..6] are the blue channel
+/// bits [7..13] are the green channel
+/// bits [14..15] are the red channel
+/// 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 <algorithm>
+#include <boost/gil/extension/io/jpeg_io.hpp>
+
+using namespace boost;
+using namespace boost::gil;
+
+int main() {
+ bgr8_image_t img;
+ jpeg_read_image("test.jpg",img);
+
+ ////////////////////////////////
+ // define a bgr772 image. It is a "packed" image - its channels are not byte-aligned, but its pixels are.
+ ////////////////////////////////
+
+ typedef packed_image3_type<uint16_t, 7,7,2, bgr_layout_t>::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<bgr8_pixel_t>(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_gray1.jpg",color_converted_view<gray8_pixel_t>(transposed_view(const_view(gray1_img))));
+
+ return 0;
+}
Added: trunk/libs/gil/doc/example/resize.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/gil/doc/example/resize.cpp 2007-11-11 14:29:06 EST (Sun, 11 Nov 2007)
@@ -0,0 +1,42 @@
+/*
+ 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 <boost/gil/image.hpp>
+#include <boost/gil/typedefs.hpp>
+#include <boost/gil/extension/io/jpeg_io.hpp>
+#include <boost/gil/extension/numeric/sampler.hpp>
+#include <boost/gil/extension/numeric/resample.hpp>
+
+int main() {
+ using namespace boost::gil;
+
+ rgb8_image_t img;
+ jpeg_read_image("test.jpg",img);
+
+ // test resize_view
+ // Scale the image to 100x100 pixels using bilinear resampling
+ rgb8_image_t square100x100(100,100);
+ resize_view(const_view(img), view(square100x100), bilinear_sampler());
+ jpeg_write_view("out-resize.jpg",const_view(square100x100));
+
+ return 0;
+}
Added: trunk/libs/gil/doc/example/x_gradient.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/gil/doc/example/x_gradient.cpp 2007-11-11 14:29:06 EST (Sun, 11 Nov 2007)
@@ -0,0 +1,62 @@
+/*
+ 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
+/// \date October 19, 2006
+
+#include <boost/gil/extension/io/jpeg_dynamic_io.hpp>
+
+using namespace boost::gil;
+
+template <typename Out>
+struct halfdiff_cast_channels {
+ template <typename T> Out operator()(const T& in1, const T& in2) const {
+ return Out((in2-in1)/2);
+ }
+};
+
+
+template <typename SrcView, typename DstView>
+void x_gradient(const SrcView& src, const DstView& dst) {
+ typedef typename channel_type<DstView>::type dst_channel_t;
+
+ for (int y=0; y<src.height(); ++y) {
+ typename SrcView::x_iterator src_it = src.row_begin(y);
+ typename DstView::x_iterator dst_it = dst.row_begin(y);
+
+ for (int x=1; x<src.width()-1; ++x) {
+ static_transform(src_it[x-1], src_it[x+1], dst_it[x],
+ halfdiff_cast_channels<dst_channel_t>());
+ }
+ }
+}
+
+template <typename SrcView, typename DstView>
+void x_luminosity_gradient(const SrcView& src, const DstView& dst) {
+ typedef pixel<typename channel_type<SrcView>::type, gray_layout_t> gray_pixel_t;
+ x_gradient(color_converted_view<gray_pixel_t>(src), dst);
+}
+
+int main() {
+ rgb8_image_t img;
+ jpeg_read_image("test.jpg",img);
+
+ gray8s_image_t img_out(img.dimensions());
+ fill_pixels(view(img_out),bits8s(0));
+
+ x_luminosity_gradient(const_view(img), view(img_out));
+ jpeg_write_view("out-x_gradient.jpg",color_converted_view<gray8_pixel_t>(const_view(img_out)));
+
+ return 0;
+}
Added: trunk/libs/gil/doc/html/adobe_source.css
==============================================================================
--- (empty file)
+++ trunk/libs/gil/doc/html/adobe_source.css 2007-11-11 14:29:06 EST (Sun, 11 Nov 2007)
@@ -0,0 +1,421 @@
+BODY,H1,H2,H3,H4,H5,H6,P,CENTER,TD,TH,UL,DL,DIV {
+ font-family: Verdana, Arial, Helvetica, sans-serif;
+ font-size: 12px;
+}
+
+CODE {
+ font-family: Monaco, Courier New, Fixed, monospace;
+ font-size: 12px;
+}
+
+BODY,TD {
+ font-size: 12px;
+ margin: 0;
+ padding: 0;
+ background: transparent;
+ color: black;
+}
+
+#content {
+ padding-top: 20px;
+ width: 1000px;
+ margin-right: auto;
+ margin-left: auto;
+}
+
+TABLE {
+ margin: 0;
+ padding: 0;
+ border-spacing: 0;
+}
+
+H1 {
+ text-align: center;
+ font-size: 18px;
+}
+
+H2 {
+ font-size: 16px;
+ #border-top: 1px dotted #666666;
+ border-bottom: 1px dotted #666666;
+}
+
+H3 {
+ font-size: 14px;
+ #border-top: 1px dotted #666666;
+ border-bottom: 1px dotted #666666;
+}
+
+CAPTION {
+ font-weight: bold
+}
+
+#maintable {
+ padding: 10px;
+ padding-top: 0px;
+ #border: 1px solid grey;
+ background-color: white;
+}
+
+#navtable {
+ padding-top: 3px;
+ padding-left: 3px;
+ background: url('navbkg.png');
+ background-repeat: no-repeat;
+ background-color: white;
+ width: 150px;
+}
+
+#navtable h4 {
+ text-align: center;
+ border: none;
+}
+
+#navtable a {
+ font-size: 11px;
+}
+
+#opensource_banner {
+ width: 1000px;
+ background-color: white;
+ #border: 1px solid grey;
+ margin-bottom: 20px;
+}
+
+DIV.qindex {
+ width: 100%;
+ background-color: #e8eef2;
+ border: 1px solid #84b0c7;
+ text-align: center;
+ margin: 2px;
+ padding: 2px;
+ line-height: 140%;
+}
+
+DIV.nav {
+ display: none;
+ width: 100%;
+ text-align: center;
+ margin: 2px;
+ padding: 2px;
+ line-height: 140%;
+}
+
+DIV.navtab {
+ background-color: #e8eef2;
+ border: 1px solid #84b0c7;
+ text-align: center;
+ margin: 2px;
+ margin-right: 15px;
+ padding: 2px;
+}
+
+TD.navtab {
+ font-size: 12px;
+}
+
+A.qindex, A.qindex:visited {
+ text-decoration: none;
+ font-weight: bold;
+ color: #1A419D;
+}
+
+A.qindex:hover {
+ text-decoration: none;
+ background-color: #ddddff;
+}
+
+A.qindexHL {
+ text-decoration: none;
+ font-weight: bold;
+ background-color: #6666cc;
+ color: #ffffff;
+ border: 1px double #9295C2;
+}
+
+A.qindexHL:hover {
+ text-decoration: none;
+ background-color: #6666cc;
+ color: #ffffff;
+}
+
+A.qindexHL:visited {
+ text-decoration: none;
+ background-color: #6666cc;
+ color: #ffffff
+}
+
+A.el {
+ text-decoration: none;
+}
+
+A.elRef {
+}
+
+A.code:link, A.code:visited {
+ border-bottom: 1px dotted darkred;
+ color: darkred;
+}
+
+A.codeRef:link, A.codeRef:visited {
+ color: darkred;
+ border-bottom: 1px dotted darkred;
+}
+
+A:link, A:visited {
+ text-decoration: none;
+ color: #cc0000;
+ border-bottom: 1px solid #cc0000;
+}
+
+DL.el {
+ margin-left: -1cm
+}
+
+.fragment {
+ font-family: Monaco, Courier New, Fixed, monospace;
+ font-size: 12px;
+}
+
+PRE.fragment {
+ border: 1px solid lightgrey;
+ margin: 4px;
+ padding: 4px;
+ line-height: 150%;
+}
+
+DIV.ah {
+ background-color: black;
+ color: transparent;
+ margin-bottom: 3px;
+ margin-top: 3px
+}
+
+DIV.groupHeader {
+ margin-left: 16px;
+ margin-top: 12px;
+ margin-bottom: 6px;
+ font-weight: bold;
+}
+
+DIV.groupText { margin-left: 16px; font-style: italic; font-size: 12px }
+
+TD.indexkey {
+ padding : 10px;
+ margin: 0px;
+ border-bottom: 1px solid #666666;
+}
+
+TD.indexvalue {
+ font-style: italic;
+ padding : 10px;
+ margin: 0px;
+ border-bottom: 1px solid #666666;
+}
+
+TR.memlist {
+ line-height: 150%;
+}
+
+TR.memlist td, TR.memlist a {
+ font-family: Monaco, Courier New, Fixed, monospace;
+}
+
+P.formulaDsp { text-align: center; }
+
+IMG.formulaDsp { }
+IMG.formulaInl { vertical-align: middle; }
+IMG {
+ border: none;
+}
+
+.footerdiv, .footerdiv a, .footerdiv p, .footerdiv ul , .footerdiv ul li {
+ font-size: 9px;
+ color: grey;
+ border: none;
+ margin: 0;
+ padding: 0;
+ margin-bottom: 3px;
+}
+
+.footerdiv {
+ width: 1000px;
+ margin: 0;
+ padding: 0;
+ margin-top: 30px;
+ margin-right: auto;
+ margin-left: auto;
+}
+
+.footerdiv ul {
+ list-style: none;
+ display: table;
+ margin: 0;
+ padding: 0;
+}
+
+.footerdiv ul li {
+ float: left;
+}
+
+SPAN.keyword { color: mediumblue }
+SPAN.keywordtype { color: mediumblue }
+SPAN.keywordflow { color: mediumblue }
+SPAN.comment { color: darkgreen }
+SPAN.preprocessor { color: mediumblue }
+SPAN.stringliteral { color: maroon }
+SPAN.charliteral { color: maroon }
+
+.mdescLeft {
+ font-style: italic;
+ border: none;
+ margin: 0px;
+}
+
+.mdescRight {
+ font-style: italic;
+ border: none;
+ margin: 0px;
+}
+
+.memItemLeft {
+ font-family: Monaco, Courier New, Fixed, monospace;
+ font-size: 11px;
+ padding: 4px;
+ border: none;
+ border-top: 1px solid lightgray;
+}
+
+.memItemRight {
+ font-family: Monaco, Courier New, Fixed, monospace;
+ font-size: 11px;
+ padding: 4px;
+ border: none;
+ border-top: 1px solid lightgray;
+}
+
+.memTemplItemLeft {
+ font-family: Monaco, Courier New, Fixed, monospace;
+ font-size: 11px;
+ padding: 4px;
+ border: none;
+}
+
+.memTemplItemRight {
+ font-family: Monaco, Courier New, Fixed, monospace;
+ font-size: 11px;
+ padding: 4px;
+ border: none;
+}
+
+.memTemplParams {
+ font-family: Monaco, Courier New, Fixed, monospace;
+ font-size: 11px;
+ padding: 4px;
+ border: none;
+ border-top: 1px solid lightgray;
+ color: #666666;
+}
+
+TD.tiny {
+ font-size: 10px;
+}
+
+.dirtab {
+ padding: 4px;
+ border-collapse: collapse;
+ border: 1px solid #84b0c7;
+}
+
+TH.dirtab {
+ background: #e8eef2;
+ font-weight: bold;
+}
+
+HR {
+ height: 1px;
+ border: none;
+ border-top: 1px solid black;
+}
+
+/* Style for detailed member documentation */
+
+.memtemplate {
+ font-family: Monaco, Courier New, Fixed, monospace;
+ color: #606060;
+ font-weight: normal;
+ font-size: 11px;
+}
+
+.memnav {
+ background-color: #e8eef2;
+ border: 1px solid #84b0c7;
+ text-align: center;
+ margin: 2px;
+ margin-right: 15px;
+ padding: 2px;
+ font-size: 11px;
+}
+
+.memitem {
+ padding: 0;
+ padding-bottom: 15px;
+ font-size: 11px;
+}
+
+.memname {
+ font-family: Monaco, Courier New, Fixed, monospace;
+ font-size: 11px;
+ white-space: nowrap;
+}
+
+.memname td {
+ vertical-align: bottom;
+ font-size: 11px;
+}
+
+.memdoc{
+ padding-left: 10px;
+}
+
+.memproto {
+ border: 1px solid gray;
+ background-color: lavender;
+ padding: 5px;
+ -moz-border-radius: 8px 8px 8px 8px;
+}
+
+.paramkey {
+ font-family: Monaco, Courier New, Fixed, monospace;
+ font-size: 11px;
+ text-align: right;
+}
+
+.paramtype {
+ font-family: Monaco, Courier New, Fixed, monospace;
+ font-size: 11px;
+ white-space: nowrap;
+}
+
+.paramname {
+ font-family: Monaco, Courier New, Fixed, monospace;
+ font-size: 11px;
+}
+/* End Styling for detailed member documentation */
+
+/* for the tree view */
+
+.ftvtree {
+ font-family: sans-serif;
+ margin:0.5em;
+}
+
+.directory { font-size: 10px; font-weight: bold; }
+.directory h3 { margin: 0px; margin-top: 1em; font-size: 11px; }
+.directory > h3 { margin-top: 0; }
+.directory p {
+ margin: 0px;
+ white-space: nowrap;
+}
+.directory div { display: none; margin: 0px; }
+.directory img { vertical-align: -30%; }
Added: trunk/libs/gil/doc/html/doxygen.png
==============================================================================
Binary file. No diff available.
Added: trunk/libs/gil/doc/html/gildesignguide.html
==============================================================================
--- (empty file)
+++ trunk/libs/gil/doc/html/gildesignguide.html 2007-11-11 14:29:06 EST (Sun, 11 Nov 2007)
@@ -0,0 +1,1929 @@
+<!--
+ 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)
+
+ Some files are held under additional license.
+ Please see "http://opensource.adobe.com/licenses.html" for more information.
+-->
+
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
+
+<head>
+ <TITLE>Generic Image Library : Generic Image Library Design Guide</TITLE>
+ <META HTTP-EQUIV="content-type" CONTENT="text/html;charset=ISO-8859-1"/>
+ <LINK TYPE="text/css" REL="stylesheet" HREF="adobe_source.css"/>
+ <LINK REL="alternate" TITLE="opensource.adobe.com RSS" HREF="http://sourceforge.net/export/rss2_projnews.php?group_id=132417&rss_fulltext=1" TYPE="application/rss+xml"/>
+ <script src="http://www.google-analytics.com/urchin.js" type="text/javascript">
+ </script>
+</head>
+<body>
+<table border="0" cellspacing="0" cellpadding="0" style='width: 100%; margin: 0; padding: 0'><tr>
+<td width="100%" valign="top" style='padding-left: 10px; padding-right: 10px; padding-bottom: 10px'>
+<!-- End Header -->
+<!-- Generated by Doxygen 1.4.4 -->
+<h1><a class="anchor" name="GILDesignGuide">Generic Image Library Design Guide</a></h1><dl compact><dt><b>Author:</b></dt><dd>Lubomir Bourdev (<a href="mailto:lbourdev_at_[hidden]">lbourdev_at_[hidden]</a>) and Hailin Jin (<a href="mailto:hljin_at_[hidden]">hljin_at_[hidden]</a>) <br>
+ Adobe Systems Incorporated </dd></dl>
+<dl compact><dt><b>Version:</b></dt><dd>2.1 </dd></dl>
+<dl compact><dt><b>Date:</b></dt><dd>September 15, 2007</dd></dl>
+<p>
+This document describes the design of the Generic Image Library, a C++ image-processing library that abstracts image representation from algorithms on images. It covers more than you need to know for a causal use of GIL. You can find a quick, jump-start GIL tutorial on the main GIL page at http://opensource.adobe.com/gil<p>
+<ul>
+<li><a class="el" href="gildesignguide.html#OverviewSectionDG">1. Overview</a></li><li><a class="el" href="gildesignguide.html#ConceptsSectionDG">2. About Concepts</a></li><li><a class="el" href="gildesignguide.html#PointSectionDG">3. Point</a></li><li><a class="el" href="gildesignguide.html#ChannelSectionDG">4. Channel</a></li><li><a class="el" href="gildesignguide.html#ColorSpaceSectionDG">5. Color Space and Layout</a></li><li><a class="el" href="gildesignguide.html#ColorBaseSectionDG">6. Color Base</a></li><li><a class="el" href="gildesignguide.html#PixelSectionDG">7. Pixel</a></li><li><a class="el" href="gildesignguide.html#PixelIteratorSectionDG">8. Pixel Iterator</a><ul>
+<li><a class="el" href="gildesignguide.html#FundamentalIteratorDG">Fundamental Iterator</a></li><li><a class="el" href="gildesignguide.html#IteratorAdaptorDG">Iterator Adaptor</a></li><li><a class="el" href="gildesignguide.html#PixelDereferenceAdaptorAG">Pixel Dereference Adaptor</a></li><li><a class="el" href="gildesignguide.html#StepIteratorDG">Step Iterator</a></li><li><a class="el" href="gildesignguide.html#LocatorDG">Pixel Locator</a></li><li><a class="el" href="gildesignguide.html#IteratorFrom2DDG">Iterator over 2D image</a></li></ul>
+</li><li><a class="el" href="gildesignguide.html#ImageViewSectionDG">9. Image View</a><ul>
+<li><a class="el" href="gildesignguide.html#ImageViewFrowRawDG">Creating Views from Raw Pixels</a></li><li><a class="el" href="gildesignguide.html#ImageViewFrowImageViewDG">Creating Image Views from Other Image Views</a></li></ul>
+</li><li><a class="el" href="gildesignguide.html#ImageSectionDG">10. Image</a></li><li><a class="el" href="gildesignguide.html#VariantSecDG">11. Run-time specified images and image views</a></li><li><a class="el" href="gildesignguide.html#MetafunctionsDG">12. Useful Metafunctions and Typedefs</a></li><li><a class="el" href="gildesignguide.html#IO_DG">13. I/O Extension</a></li><li><a class="el" href="gildesignguide.html#SampleImgCodeDG">14. Sample Code</a><ul>
+<li><a class="el" href="gildesignguide.html#PixelLevelExampleDG">Pixel-level Sample Code</a></li><li><a class="el" href="gildesignguide.html#SafeAreaExampleDG">Creating a Copy of an Image with a Safe Buffer</a></li><li><a class="el" href="gildesignguide.html#HistogramExampleDG">Histogram</a></li><li><a class="el" href="gildesignguide.html#ImageViewsExampleDG">Using Image Views</a></li></ul>
+</li><li><a class="el" href="gildesignguide.html#ExtendingGIL_DG">15. Extending the Generic Image Library</a><ul>
+<li><a class="el" href="gildesignguide.html#NewColorSpacesDG">Defining New Color Spaces</a></li><li><a class="el" href="gildesignguide.html#NewColorConversionDG">Overloading Color Conversion</a></li><li><a class="el" href="gildesignguide.html#NewChannelsDG">Defining New Channel Types</a></li><li><a class="el" href="gildesignguide.html#NewImagesDG">Defining New Image Views</a></li></ul>
+</li><li><a class="el" href="gildesignguide.html#TechnicalitiesDG">16. Technicalities</a></li><li><a class="el" href="gildesignguide.html#ConclusionDG">17. Conclusion</a></li></ul>
+<p>
+<br>
+ <hr>
+ <h2><a class="anchor" name="OverviewSectionDG">
+1. Overview</a></h2>
+Images are essential in any image processing, vision and video project, and yet the variability in image representations makes it difficult to write imaging algorithms that are both generic and efficient. In this section we will describe some of the challenges that we would like to address.<p>
+In the following discussion an <em>image</em> is a 2D array of pixels. A <em>pixel</em> is a set of color channels that represents the color at a given point in an image. Each <em>channel</em> represents the value of a color component. There are two common memory structures for an image. <em>Interleaved</em> images are represented by grouping the pixels together in memory and interleaving all channels together, whereas <em>planar</em> images keep the channels in separate color planes. Here is a 4x3 RGB image in which the second pixel of the first row is marked in red, in interleaved form:<p>
+<div align="center">
+<img src="interleaved.jpg" alt="interleaved.jpg">
+</div>
+ and in planar form:<p>
+<div align="center">
+<img src="planar.jpg" alt="planar.jpg">
+</div>
+<p>
+Note also that rows may optionally be aligned resulting in a potential padding at the end of rows. <p>
+The Generic Image Library (GIL) provides models for images that vary in:<ul>
+<li>Structure (planar vs. interleaved)</li><li>Color space and presence of alpha (RGB, RGBA, CMYK, etc.)</li><li>Channel depth (8-bit, 16-bit, etc.)</li><li>Order of channels (RGB vs. BGR, etc.)</li><li>Row alignment policy (no alignment, word-alignment, etc.)</li></ul>
+<p>
+It also supports user-defined models of images, and images whose parameters are specified at run-time. GIL abstracts image representation from algorithms applied on images and allows us to write the algorithm once and have it work on any of the above image variations while generating code that is comparable in speed to that of hand-writing the algorithm for a specific image type.<p>
+This document follows bottom-up design. Each section defines concepts that build on top of concepts defined in previous sections. It is recommended to read the sections in order.<p>
+<hr>
+ <h2><a class="anchor" name="ConceptsSectionDG">
+2. About Concepts</a></h2>
+All constructs in GIL are models of GIL concepts. A <em>concept</em> is a set of requirements that a type (or a set of related types) must fulfill to be used correctly in generic algorithms. The requirements include syntactic and algorithming guarantees. For example, GIL's class <code>pixel</code> is a model of GIL's <code>PixelConcept</code>. The user may substitute the pixel class with one of their own, and, as long as it satisfies the requirements of <code>PixelConcept</code>, all other GIL classes and algorithms can be used with it. See more about concepts here: http://www.generic-programming.org/languages/conceptcpp/<p>
+In this document we will use a syntax for defining concepts that is described in a proposal for a Concepts extension to C++0x specified here: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2081.pdf<p>
+Here are some common concepts that will be used in GIL. Most of them are defined here: http://www.generic-programming.org/languages/conceptcpp/concept_web.php<p>
+<div class="fragment"><pre class="fragment"><span class="keyword">auto</span> concept DefaultConstructible<typename T> {
+ T::T();
+};
+
+<span class="keyword">auto</span> concept CopyConstructible<typename T> {
+ T::T(T);
+ T::~T();
+};
+
+<span class="keyword">auto</span> concept Assignable<typename T, typename U = T> {
+ <span class="keyword">typename</span> result_type;
+ result_type operator=(T&, U);
+};
+
+<span class="keyword">auto</span> concept EqualityComparable<typename T, typename U = T> {
+ <span class="keywordtype">bool</span> operator==(T x, T y);
+ <span class="keywordtype">bool</span> operator!=(T x, T y) { <span class="keywordflow">return</span> !(x==y); }
+};
+
+concept SameType<typename T, typename U> { unspecified };
+<span class="keyword">template</span><<span class="keyword">typename</span> T> concept_map SameType<T, T> { unspecified };
+
+<span class="keyword">auto</span> concept Swappable<typename T> {
+ <span class="keywordtype">void</span> swap(T& t, T& u);
+};
+</pre></div><p>
+Here are some additional basic concepts that GIL needs:<p>
+<div class="fragment"><pre class="fragment"><span class="keyword">auto</span> concept Regular<typename T> : DefaultConstructible<T>, CopyConstructible<T>, EqualityComparable<T>, Assignable<T>, Swappable<T> {};
+
+<span class="keyword">auto</span> concept Metafunction<typename T> {
+ <span class="keyword">typename</span> type;
+};
+</pre></div><h2><a class="anchor" name="PointSectionDG">
+3. Point</a></h2>
+A point defines the location of a pixel inside an image. It can also be used to describe the dimensions of an image. In most general terms, points are N-dimensional and model the following concept:<p>
+<div class="fragment"><pre class="fragment">concept PointNDConcept<typename T> : Regular<T> {
+ <span class="comment">// the type of a coordinate along each axis</span>
+ <span class="keyword">template</span> <size_t K> <span class="keyword">struct </span>axis; where Metafunction<axis>;
+
+ <span class="keyword">const</span> size_t num_dimensions;
+
+ <span class="comment">// accessor/modifier of the value of each axis.</span>
+ <span class="keyword">template</span> <size_t K> <span class="keyword">const</span> <span class="keyword">typename</span> axis<K>::type& T::axis_value() <span class="keyword">const</span>;
+ <span class="keyword">template</span> <size_t K> <span class="keyword">typename</span> axis<K>::type& T::axis_value();
+};
+</pre></div><p>
+GIL uses a two-dimensional point, which is a refinement of <code>PointNDConcept</code> in which both dimensions are of the same type:<p>
+<div class="fragment"><pre class="fragment">concept Point2DConcept<typename T> : PointNDConcept<T> {
+ where num_dimensions == 2;
+ where SameType<axis<0>::type, axis<1>::type>;
+
+ <span class="keyword">typename</span> value_type = axis<0>::type;
+
+ <span class="keyword">const</span> value_type& operator[](<span class="keyword">const</span> T&, size_t i);
+ value_type& operator[]( T&, size_t i);
+
+ value_type x,y;
+};
+</pre></div><p>
+<b>Related Concepts:</b><p>
+<ul>
+<li>PointNDConcept<T></li><li>Point2DConcept<T></li></ul>
+<p>
+<b>Models:</b><p>
+GIL provides a model of <code>Point2DConcept</code>, <code>point2<T></code> where <code>T</code> is the coordinate type.<p>
+<hr>
+ <h2><a class="anchor" name="ChannelSectionDG">
+4. Channel</a></h2>
+A channel indicates the intensity of a color component (for example, the red channel in an RGB pixel). Typical channel operations are getting, comparing and setting the channel values. Channels have associated minimum and maximum value. GIL channels model the following concept:<p>
+<div class="fragment"><pre class="fragment">concept ChannelConcept<typename T> : EqualityComparable<T> {
+ <span class="keyword">typename</span> value_type = T; <span class="comment">// use channel_traits<T>::value_type to access it</span>
+ where ChannelValueConcept<value_type>;
+ <span class="keyword">typename</span> reference = T&; <span class="comment">// use channel_traits<T>::reference to access it</span>
+ <span class="keyword">typename</span> pointer = T*; <span class="comment">// use channel_traits<T>::pointer to access it</span>
+ <span class="keyword">typename</span> const_reference = <span class="keyword">const</span> T&; <span class="comment">// use channel_traits<T>::const_reference to access it</span>
+ <span class="keyword">typename</span> const_pointer = <span class="keyword">const</span> T*; <span class="comment">// use channel_traits<T>::const_pointer to access it</span>
+ <span class="keyword">static</span> <span class="keyword">const</span> <span class="keywordtype">bool</span> is_mutable; <span class="comment">// use channel_traits<T>::is_mutable to access it</span>
+
+ <span class="keyword">static</span> T min_value(); <span class="comment">// use channel_traits<T>::min_value to access it</span>
+ <span class="keyword">static</span> T max_value(); <span class="comment">// use channel_traits<T>::min_value to access it</span>
+};
+
+concept MutableChannelConcept<ChannelConcept T> : Swappable<T>, Assignable<T> {};
+
+concept ChannelValueConcept<ChannelConcept T> : Regular<T> {};
+</pre></div><p>
+GIL allows built-in integral and floating point types to be channels. Therefore the associated types and range information are defined in <code>channel_traits</code> with the following default implementation:<p>
+<div class="fragment"><pre class="fragment"><span class="keyword">template</span> <<span class="keyword">typename</span> T>
+<span class="keyword">struct </span>channel_traits {
+ <span class="keyword">typedef</span> T value_type;
+ <span class="keyword">typedef</span> T& reference;
+ <span class="keyword">typedef</span> T* pointer;
+ <span class="keyword">typedef</span> T& <span class="keyword">const</span> const_reference;
+ <span class="keyword">typedef</span> T* <span class="keyword">const</span> const_pointer;
+
+ <span class="keyword">static</span> value_type min_value() { <span class="keywordflow">return</span> std::numeric_limits<T>::min(); }
+ <span class="keyword">static</span> value_type max_value() { <span class="keywordflow">return</span> std::numeric_limits<T>::max(); }
+};
+</pre></div><p>
+Two channel types are <em>compatible</em> if they have the same value type:<p>
+<div class="fragment"><pre class="fragment">concept ChannelsCompatibleConcept<ChannelConcept T1, ChannelConcept T2> {
+ where SameType<T1::value_type, T2::value_type>;
+};
+</pre></div><p>
+A channel may be <em>convertible</em> to another channel:<p>
+<div class="fragment"><pre class="fragment"><span class="keyword">template</span> <ChannelConcept Src, ChannelValueConcept Dst>
+concept ChannelConvertibleConcept {
+ Dst <a class="code" href="http://opensource.adobe.com/gil/html/group___channel_convert_algorithm.html#ga0">channel_convert</a>(Src);
+};
+</pre></div><p>
+Note that <code>ChannelConcept</code> and <code>MutableChannelConcept</code> do not require a default constructor. Channels that also support default construction (and thus are regular types) model <code>ChannelValueConcept</code>. To understand the motivation for this distinction, consider a 16-bit RGB pixel in a "565" bit pattern. Its channels correspond to bit ranges. To support such channels, we need to create a custom proxy class corresponding to a reference to a subbyte channel. Such a proxy reference class models only <code>ChannelConcept</code>, because, similar to native C++ references, it may not have a default constructor.<p>
+Note also that algorithms may impose additional requirements on channels, such as support for arithmentic operations.<p>
+<b>Related Concepts:</b><p>
+<ul>
+<li>ChannelConcept<T></li><li>ChannelValueConcept<T></li><li>MutableChannelConcept<T></li><li>ChannelsCompatibleConcept<T1,T2></li><li>ChannelConvertibleConcept<SrcChannel,DstChannel></li></ul>
+<p>
+<b>Models:</b><p>
+All built-in integral and floating point types are valid channels. GIL provides standard typedefs for some integral channels:<p>
+<div class="fragment"><pre class="fragment"><span class="keyword">typedef</span> boost::uint8_t bits8;
+<span class="keyword">typedef</span> boost::uint16_t bits16;
+<span class="keyword">typedef</span> boost::uint32_t bits32;
+<span class="keyword">typedef</span> boost::int8_t bits8s;
+<span class="keyword">typedef</span> boost::int16_t bits16s;
+<span class="keyword">typedef</span> boost::int32_t bits32s;
+</pre></div><p>
+The minimum and maximum values of a channel modeled by a built-in type correspond to the minimum and maximum physical range of the built-in type, as specified by its <code>std::numeric_limits</code>. Sometimes the physical range is not appropriate. GIL provides <code>scoped_channel_value</code>, a model for a channel adapter that allows for specifying a custom range. We use it to define a [0..1] floating point channel type as follows:<p>
+<div class="fragment"><pre class="fragment"><span class="keyword">struct </span>float_zero { <span class="keyword">static</span> <span class="keywordtype">float</span> apply() { <span class="keywordflow">return</span> 0.0f; } };
+<span class="keyword">struct </span>float_one { <span class="keyword">static</span> <span class="keywordtype">float</span> apply() { <span class="keywordflow">return</span> 1.0f; } };
+<span class="keyword">typedef</span> scoped_channel_value<float,float_zero,float_one> bits32f;
+</pre></div><p>
+GIL also provides models for channels corresponding to ranges of bits:<p>
+<div class="fragment"><pre class="fragment"><span class="comment">// Value of a channel defined over NumBits bits. Models ChannelValueConcept</span>
+<span class="keyword">template</span> <<span class="keywordtype">int</span> NumBits> <span class="keyword">class </span>packed_channel_value;
+
+<span class="comment">// Reference to a channel defined over NumBits bits. Models ChannelConcept</span>
+<span class="keyword">template</span> <<span class="keywordtype">int</span> FirstBit,
+ <span class="keywordtype">int</span> NumBits, <span class="comment">// Defines the sequence of bits in the data value that contain the channel </span>
+ <span class="keywordtype">bool</span> Mutable> <span class="comment">// true if the reference is mutable </span>
+<span class="keyword">class </span>packed_channel_reference;
+
+<span class="comment">// Reference to a channel defined over NumBits bits. Its FirstBit is a run-time parameter. Models ChannelConcept</span>
+<span class="keyword">template</span> <<span class="keywordtype">int</span> NumBits, <span class="comment">// Defines the sequence of bits in the data value that contain the channel </span>
+ <span class="keywordtype">bool</span> Mutable> <span class="comment">// true if the reference is mutable </span>
+<span class="keyword">class </span>packed_dynamic_channel_reference;
+</pre></div><p>
+Note that there are two models of a reference proxy which differ based on whether the offset of the channel range is specified as a template or a run-time parameter. The first model is faster and more compact while the second model is more flexible. For example, the second model allows us to construct an iterator over bitrange channels.<p>
+<b>Algorithms:</b><p>
+Here is how to construct the three channels of a 16-bit "565" pixel and set them to their maximum value:<p>
+<div class="fragment"><pre class="fragment"><span class="keyword">typedef</span> packed_channel_reference<0,5,true> channel16_0_5_reference_t;
+<span class="keyword">typedef</span> packed_channel_reference<5,6,true> channel16_5_6_reference_t;
+<span class="keyword">typedef</span> packed_channel_reference<11,5,true> 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);
+
+channel1=channel_traits<channel16_0_5_reference_t>::max_value();
+channel2=channel_traits<channel16_5_6_reference_t>::max_value();
+channel3=channel_traits<channel16_11_5_reference_t>::max_value();
+assert(data==65535);
+</pre></div><p>
+Assignment, equality comparison and copy construction are defined only between compatible channels:<p>
+<div class="fragment"><pre class="fragment">packed_channel_value<5> channel_6bit = channel1;
+channel_6bit = channel3;
+
+<span class="comment">//channel_6bit = channel2; // compile error: Assignment between incompatible channels.</span>
+</pre></div><p>
+All channel models provided by GIL are pairwise convertible:<p>
+<div class="fragment"><pre class="fragment">channel1 = channel_traits<channel16_0_5_reference_t>::max_value();
+assert(channel1 == 31);
+
+bits16 chan16 = channel_convert<bits16>(channel1);
+assert(chan16 == 65535);
+</pre></div><p>
+Channel conversion is a lossy operation. GIL's channel conversion is a linear transformation between the ranges of the source and destination channel. It maps precisely the minimum to the minimum and the maximum to the maximum. (For example, to convert from uint8_t to uint16_t GIL does not do a bit shift because it will not properly match the maximum values. Instead GIL multiplies the source by 257).<p>
+All channel models that GIL provides are convertible from/to an integral or floating point type. Thus they support arithmetic operations. Here are the channel-level algorithms that GIL provides:<p>
+<div class="fragment"><pre class="fragment"><span class="comment">// Converts a source channel value into a destrination channel. Linearly maps the value of the source</span>
+<span class="comment">// into the range of the destination</span>
+<span class="keyword">template</span> <<span class="keyword">typename</span> DstChannel, <span class="keyword">typename</span> SrcChannel>
+<span class="keyword">typename</span> channel_traits<DstChannel>::value_type <a class="code" href="http://opensource.adobe.com/gil/html/group___channel_convert_algorithm.html#ga0">channel_convert</a>(SrcChannel src);
+
+<span class="comment">// returns max_value - x + min_value</span>
+<span class="keyword">template</span> <<span class="keyword">typename</span> Channel>
+<span class="keyword">typename</span> channel_traits<Channel>::value_type <a class="code" href="http://opensource.adobe.com/gil/html/group___channel_invert_algorithm.html#ga0">channel_invert</a>(Channel x);
+
+<span class="comment">// returns a * b / max_value</span>
+<span class="keyword">template</span> <<span class="keyword">typename</span> Channel>
+<span class="keyword">typename</span> channel_traits<Channel>::value_type <a class="code" href="http://opensource.adobe.com/gil/html/group___channel_multiply_algorithm.html#ga0">channel_multiply</a>(Channel a, Channel b);
+</pre></div><p>
+<hr>
+ <h2><a class="anchor" name="ColorSpaceSectionDG">
+5. Color Space and Layout</a></h2>
+A color space captures the set and interpretation of channels comprising a pixel. It is an MPL random access sequence containing the types of all elements in the color space. Two color spaces are considered <em>compatible</em> if they are equal (i.e. have the same set of colors in the same order).<p>
+<b>Related Concepts:</b><p>
+<ul>
+<li>ColorSpaceConcept<ColorSpace></li><li>ColorSpacesCompatibleConcept<ColorSpace1,ColorSpace2></li><li>ChannelMappingConcept<Mapping></li></ul>
+<p>
+<b>Models:</b><p>
+GIL currently provides the following color spaces: <code>gray_t</code>, <code>rgb_t</code>, <code>rgba_t</code>, and <code>cmyk_t</code>. It also provides unnamed N-channel color spaces of two to five channels, <code>devicen_t<2></code>, <code>devicen_t<3></code>, <code>devicen_t<4></code>, <code>devicen_t<5></code>. Besides the standard layouts, it provides <code>bgr_layout_t</code>, <code>bgra_layout_t</code>, <code>abgr_layout_t</code> and <code>argb_layout_t</code>.<p>
+As an example, here is how GIL defines the RGBA color space:<p>
+<div class="fragment"><pre class="fragment"><span class="keyword">struct </span>red_t{};
+<span class="keyword">struct </span>green_t{};
+<span class="keyword">struct </span>blue_t{};
+<span class="keyword">struct </span>alpha_t{};
+<span class="keyword">typedef</span> mpl::vector4<red_t,green_t,blue_t,alpha_t> rgba_t;
+</pre></div><p>
+The ordering of the channels in the color space definition specifies their semantic order. For example, <code>red_t</code> is the first semantic channel of <code>rgba_t</code>. While there is a unique semantic ordering of the channels in a color space, channels may vary in their physical ordering in memory. The mapping of channels is specified by <code>ChannelMappingConcept</code>, which is an MPL random access sequence of integral types. A color space and its associated mapping are often used together. Thus they are grouped in GIL's layout:<p>
+<div class="fragment"><pre class="fragment"><span class="keyword">template</span> <<span class="keyword">typename</span> ColorSpace,
+ <span class="keyword">typename</span> ChannelMapping = mpl::range_c<int,0,mpl::size<ColorSpace>::value> >
+<span class="keyword">struct </span>layout {
+ <span class="keyword">typedef</span> ColorSpace color_space_t;
+ <span class="keyword">typedef</span> ChannelMapping channel_mapping_t;
+};
+</pre></div><p>
+Here is how to create layouts for the RGBA color space:<p>
+<div class="fragment"><pre class="fragment"><span class="keyword">typedef</span> layout<rgba_t> rgba_layout_t; <span class="comment">// default ordering is 0,1,2,3...</span>
+<span class="keyword">typedef</span> layout<rgba_t, mpl::vector4_c<int,2,1,0,3> > bgra_layout_t;
+<span class="keyword">typedef</span> layout<rgba_t, mpl::vector4_c<int,1,2,3,0> > argb_layout_t;
+<span class="keyword">typedef</span> layout<rgba_t, mpl::vector4_c<int,3,2,1,0> > abgr_layout_t;
+</pre></div><p>
+<hr>
+ <h2><a class="anchor" name="ColorBaseSectionDG">
+6. Color Base</a></h2>
+A color base is a container of color elements. The most common use of color base is in the implementation of a pixel, in which case the color elements are channel values. The color base concept, however, can be used in other scenarios. For example, a planar pixel has channels that are not contiguous in memory. Its reference is a proxy class that uses a color base whose elements are channel references. Its iterator uses a color base whose elements are channel iterators.<p>
+Color base models must satisfy the following concepts:<p>
+<div class="fragment"><pre class="fragment">concept ColorBaseConcept<typename T> : CopyConstructible<T>, EqualityComparable<T> {
+ <span class="comment">// a GIL layout (the color space and element permutation)</span>
+ <span class="keyword">typename</span> layout_t;
+
+ <span class="comment">// The type of K-th element</span>
+ <span class="keyword">template</span> <<span class="keywordtype">int</span> K> <span class="keyword">struct </span>kth_element_type;
+ where Metafunction<kth_element_type>;
+
+ <span class="comment">// The result of at_c</span>
+ <span class="keyword">template</span> <<span class="keywordtype">int</span> K> <span class="keyword">struct </span>kth_element_const_reference_type;
+ where Metafunction<kth_element_const_reference_type>;
+
+ <span class="keyword">template</span> <<span class="keywordtype">int</span> K> kth_element_const_reference_type<T,K>::type at_c(T);
+
+ <span class="keyword">template</span> <ColorBaseConcept T2> where { ColorBasesCompatibleConcept<T,T2> }
+ T::T(T2);
+ <span class="keyword">template</span> <ColorBaseConcept T2> where { ColorBasesCompatibleConcept<T,T2> }
+ <span class="keywordtype">bool</span> operator==(<span class="keyword">const</span> T&, <span class="keyword">const</span> T2&);
+ <span class="keyword">template</span> <ColorBaseConcept T2> where { ColorBasesCompatibleConcept<T,T2> }
+ <span class="keywordtype">bool</span> operator!=(<span class="keyword">const</span> T&, <span class="keyword">const</span> T2&);
+
+};
+
+concept MutableColorBaseConcept<ColorBaseConcept T> : Assignable<T>, Swappable<T> {
+ <span class="keyword">template</span> <<span class="keywordtype">int</span> K> <span class="keyword">struct </span>kth_element_reference_type;
+ where Metafunction<kth_element_reference_type>;
+
+ <span class="keyword">template</span> <<span class="keywordtype">int</span> K> kth_element_reference_type<T,K>::type at_c(T);
+
+ <span class="keyword">template</span> <ColorBaseConcept T2> where { ColorBasesCompatibleConcept<T,T2> }
+ T& operator=(T&, <span class="keyword">const</span> T2&);
+};
+
+concept ColorBaseValueConcept<typename T> : MutableColorBaseConcept<T>, Regular<T> {
+};
+
+concept HomogeneousColorBaseConcept<ColorBaseConcept CB> {
+ <span class="comment">// For all K in [0 ... size<C1>::value-1):</span>
+ <span class="comment">// where SameType<kth_element_type<K>::type, kth_element_type<K+1>::type>; </span>
+ kth_element_const_reference_type<0>::type dynamic_at_c(<span class="keyword">const</span> CB&, std::size_t n) <span class="keyword">const</span>;
+};
+
+concept MutableHomogeneousColorBaseConcept<MutableColorBaseConcept CB> : HomogeneousColorBaseConcept<CB> {
+ kth_element_reference_type<0>::type dynamic_at_c(<span class="keyword">const</span> CB&, std::size_t n);
+};
+
+concept HomogeneousColorBaseValueConcept<typename T> : MutableHomogeneousColorBaseConcept<T>, Regular<T> {
+};
+
+concept ColorBasesCompatibleConcept<ColorBaseConcept C1, ColorBaseConcept C2> {
+ where SameType<C1::layout_t::color_space_t, C2::layout_t::color_space_t>;
+ <span class="comment">// also, for all K in [0 ... size<C1>::value):</span>
+ <span class="comment">// where Convertible<kth_semantic_element_type<C1,K>::type, kth_semantic_element_type<C2,K>::type>;</span>
+ <span class="comment">// where Convertible<kth_semantic_element_type<C2,K>::type, kth_semantic_element_type<C1,K>::type>;</span>
+};
+</pre></div><p>
+A color base must have an associated layout (which consists of a color space, as well as an ordering of the channels). There are two ways to index the elements of a color base: A physical index corresponds to the way they are ordered in memory, and a semantic index corresponds to the way the elements are ordered in their color space. For example, in the RGB color space the elements are ordered as {red_t, green_t, blue_t}. For a color base with a BGR layout, the first element in physical ordering is the blue element, whereas the first semantic element is the red one. Models of <code>ColorBaseConcept</code> are required to provide the <code>at_c<K>(ColorBase)</code> function, which allows for accessing the elements based on their physical order. GIL provides a <code>semantic_at_c<K>(ColorBase)</code> function (described later) which can operate on any model of ColorBaseConcept and returns the corresponding semantic element.<p>
+Two color bases are <em>compatible</em> if they have the same color space and their elements (paired semantically) are convertible to each other.<p>
+<b>Models:</b><p>
+GIL provides a model for a homogeneous color base (a color base whose elements all have the same type).<p>
+<div class="fragment"><pre class="fragment"><span class="keyword">namespace </span>detail {
+ <span class="keyword">template</span> <<span class="keyword">typename</span> Element, <span class="keyword">typename</span> Layout, <span class="keywordtype">int</span> K> <span class="keyword">struct </span>homogeneous_color_base;
+}
+</pre></div><p>
+It is used in the implementation of GIL's pixel, planar pixel reference and planar pixel iterator. Another model of <code>ColorBaseConcept</code> is <code>packed_pixel</code> - it is a pixel whose channels are bit ranges. See the <a class="el" href="gildesignguide.html#PixelSectionDG">7. Pixel</a> section for more.<p>
+<b>Algorithms:</b><p>
+GIL provides the following functions and metafunctions operating on color bases:<p>
+<div class="fragment"><pre class="fragment"><span class="comment">// Metafunction returning an mpl::int_ equal to the number of elements in the color base</span>
+<span class="keyword">template</span> <<span class="keyword">class</span> ColorBase> <span class="keyword">struct </span>size;
+
+<span class="comment">// Returns the type of the return value of semantic_at_c<K>(color_base)</span>
+<span class="keyword">template</span> <<span class="keyword">class</span> ColorBase, <span class="keywordtype">int</span> K> <span class="keyword">struct </span>kth_semantic_element_reference_type;
+<span class="keyword">template</span> <<span class="keyword">class</span> ColorBase, <span class="keywordtype">int</span> K> <span class="keyword">struct </span>kth_semantic_element_const_reference_type;
+
+<span class="comment">// Returns a reference to the element with K-th semantic index.</span>
+<span class="keyword">template</span> <<span class="keyword">class</span> ColorBase, <span class="keywordtype">int</span> K>
+<span class="keyword">typename</span> kth_semantic_element_reference_type<ColorBase,K>::type <a class="code" href="http://opensource.adobe.com/gil/html/group___color_base_algorithm_semantic_at_c.html#ga0">semantic_at_c</a>(ColorBase& p)
+<span class="keyword">template</span> <<span class="keyword">class</span> ColorBase, <span class="keywordtype">int</span> K>
+<span class="keyword">typename</span> kth_semantic_element_const_reference_type<ColorBase,K>::type <a class="code" href="http://opensource.adobe.com/gil/html/group___color_base_algorithm_semantic_at_c.html#ga0">semantic_at_c</a>(<span class="keyword">const</span> ColorBase& p)
+
+<span class="comment">// Returns the type of the return value of get_color<Color>(color_base)</span>
+<span class="keyword">template</span> <<span class="keyword">typename</span> Color, <span class="keyword">typename</span> ColorBase> <span class="keyword">struct </span>color_reference_t;
+<span class="keyword">template</span> <<span class="keyword">typename</span> Color, <span class="keyword">typename</span> ColorBase> <span class="keyword">struct </span>color_const_reference_t;
+
+<span class="comment">// Returns a reference to the element corresponding to the given color</span>
+<span class="keyword">template</span> <<span class="keyword">typename</span> ColorBase, <span class="keyword">typename</span> Color>
+<span class="keyword">typename</span> color_reference_t<Color,ColorBase>::type <a class="code" href="http://opensource.adobe.com/gil/html/group___color_base_algorithm_color.html#ga0">get_color</a>(ColorBase& cb, Color=Color());
+<span class="keyword">template</span> <<span class="keyword">typename</span> ColorBase, <span class="keyword">typename</span> Color>
+<span class="keyword">typename</span> color_const_reference_t<Color,ColorBase>::type <a class="code" href="http://opensource.adobe.com/gil/html/group___color_base_algorithm_color.html#ga0">get_color</a>(<span class="keyword">const</span> ColorBase& cb, Color=Color());
+
+<span class="comment">// Returns the element type of the color base. Defined for homogeneous color bases only</span>
+<span class="keyword">template</span> <<span class="keyword">typename</span> ColorBase> <span class="keyword">struct </span>element_type;
+<span class="keyword">template</span> <<span class="keyword">typename</span> ColorBase> <span class="keyword">struct </span>element_reference_type;
+<span class="keyword">template</span> <<span class="keyword">typename</span> ColorBase> <span class="keyword">struct </span>element_const_reference_type;
+</pre></div><p>
+GIL also provides the following algorithms which operate on color bases. Note that they all pair the elements semantically:<p>
+<div class="fragment"><pre class="fragment"><span class="comment">// Equivalents to std::equal, std::copy, std::fill, std::generate</span>
+<span class="keyword">template</span> <<span class="keyword">typename</span> CB1,<span class="keyword">typename</span> CB2> <span class="keywordtype">bool</span> static_equal(<span class="keyword">const</span> CB1& p1, <span class="keyword">const</span> CB2& p2);
+<span class="keyword">template</span> <<span class="keyword">typename</span> Src,<span class="keyword">typename</span> Dst> <span class="keywordtype">void</span> static_copy(<span class="keyword">const</span> Src& src, Dst& dst);
+<span class="keyword">template</span> <<span class="keyword">typename</span> CB, <span class="keyword">typename</span> Op> <span class="keywordtype">void</span> static_generate(CB& dst,Op op);
+
+<span class="comment">// Equivalents to std::transform</span>
+<span class="keyword">template</span> <<span class="keyword">typename</span> CB , <span class="keyword">typename</span> Dst,<span class="keyword">typename</span> Op> Op static_transform( CB&,Dst&,Op);
+<span class="keyword">template</span> <<span class="keyword">typename</span> CB , <span class="keyword">typename</span> Dst,<span class="keyword">typename</span> Op> Op static_transform(<span class="keyword">const</span> CB&,Dst&,Op);
+<span class="keyword">template</span> <<span class="keyword">typename</span> CB1,<span class="keyword">typename</span> CB2,<span class="keyword">typename</span> Dst,<span class="keyword">typename</span> Op> Op static_transform( CB1&, CB2&,Dst&,Op);
+<span class="keyword">template</span> <<span class="keyword">typename</span> CB1,<span class="keyword">typename</span> CB2,<span class="keyword">typename</span> Dst,<span class="keyword">typename</span> Op> Op static_transform(<span class="keyword">const</span> CB1&, CB2&,Dst&,Op);
+<span class="keyword">template</span> <<span class="keyword">typename</span> CB1,<span class="keyword">typename</span> CB2,<span class="keyword">typename</span> Dst,<span class="keyword">typename</span> Op> Op static_transform( CB1&,<span class="keyword">const</span> CB2&,Dst&,Op);
+<span class="keyword">template</span> <<span class="keyword">typename</span> CB1,<span class="keyword">typename</span> CB2,<span class="keyword">typename</span> Dst,<span class="keyword">typename</span> Op> Op static_transform(<span class="keyword">const</span> CB1&,<span class="keyword">const</span> CB2&,Dst&,Op);
+
+<span class="comment">// Equivalents to std::for_each</span>
+<span class="keyword">template</span> <<span class="keyword">typename</span> CB1, <span class="keyword">typename</span> Op> Op static_for_each( CB1&,Op);
+<span class="keyword">template</span> <<span class="keyword">typename</span> CB1, <span class="keyword">typename</span> Op> Op static_for_each(<span class="keyword">const</span> CB1&,Op);
+<span class="keyword">template</span> <<span class="keyword">typename</span> CB1,<span class="keyword">typename</span> CB2, <span class="keyword">typename</span> Op> Op static_for_each( CB1&, CB2&,Op);
+<span class="keyword">template</span> <<span class="keyword">typename</span> CB1,<span class="keyword">typename</span> CB2, <span class="keyword">typename</span> Op> Op static_for_each( CB1&,<span class="keyword">const</span> CB2&,Op);
+<span class="keyword">template</span> <<span class="keyword">typename</span> CB1,<span class="keyword">typename</span> CB2, <span class="keyword">typename</span> Op> Op static_for_each(<span class="keyword">const</span> CB1&, CB2&,Op);
+<span class="keyword">template</span> <<span class="keyword">typename</span> CB1,<span class="keyword">typename</span> CB2, <span class="keyword">typename</span> Op> Op static_for_each(<span class="keyword">const</span> CB1&,<span class="keyword">const</span> CB2&,Op);
+<span class="keyword">template</span> <<span class="keyword">typename</span> CB1,<span class="keyword">typename</span> CB2,<span class="keyword">typename</span> CB3,<span class="keyword">typename</span> Op> Op static_for_each( CB1&, CB2&, CB3&,Op);
+<span class="keyword">template</span> <<span class="keyword">typename</span> CB1,<span class="keyword">typename</span> CB2,<span class="keyword">typename</span> CB3,<span class="keyword">typename</span> Op> Op static_for_each( CB1&, CB2&,<span class="keyword">const</span> CB3&,Op);
+<span class="keyword">template</span> <<span class="keyword">typename</span> CB1,<span class="keyword">typename</span> CB2,<span class="keyword">typename</span> CB3,<span class="keyword">typename</span> Op> Op static_for_each( CB1&,<span class="keyword">const</span> CB2&, CB3&,Op);
+<span class="keyword">template</span> <<span class="keyword">typename</span> CB1,<span class="keyword">typename</span> CB2,<span class="keyword">typename</span> CB3,<span class="keyword">typename</span> Op> Op static_for_each( CB1&,<span class="keyword">const</span> CB2&,<span class="keyword">const</span> CB3&,Op);
+<span class="keyword">template</span> <<span class="keyword">typename</span> CB1,<span class="keyword">typename</span> CB2,<span class="keyword">typename</span> CB3,<span class="keyword">typename</span> Op> Op static_for_each(<span class="keyword">const</span> CB1&, CB2&, CB3&,Op);
+<span class="keyword">template</span> <<span class="keyword">typename</span> CB1,<span class="keyword">typename</span> CB2,<span class="keyword">typename</span> CB3,<span class="keyword">typename</span> Op> Op static_for_each(<span class="keyword">const</span> CB1&, CB2&,<span class="keyword">const</span> CB3&,Op);
+<span class="keyword">template</span> <<span class="keyword">typename</span> CB1,<span class="keyword">typename</span> CB2,<span class="keyword">typename</span> CB3,<span class="keyword">typename</span> Op> Op static_for_each(<span class="keyword">const</span> CB1&,<span class="keyword">const</span> CB2&, CB3&,Op);
+<span class="keyword">template</span> <<span class="keyword">typename</span> CB1,<span class="keyword">typename</span> CB2,<span class="keyword">typename</span> CB3,<span class="keyword">typename</span> Op> Op static_for_each(<span class="keyword">const</span> CB1&,<span class="keyword">const</span> CB2&,<span class="keyword">const</span> CB3&,Op);
+
+<span class="comment">// The following algorithms are only defined for homogeneous color bases:</span>
+<span class="comment">// Equivalent to std::fill</span>
+<span class="keyword">template</span> <<span class="keyword">typename</span> HCB, <span class="keyword">typename</span> Element> <span class="keywordtype">void</span> static_fill(HCB& p, <span class="keyword">const</span> Element& v);
+
+<span class="comment">// Equivalents to std::min_element and std::max_element</span>
+<span class="keyword">template</span> <<span class="keyword">typename</span> HCB> <span class="keyword">typename</span> element_const_reference_type<HCB>::type static_min(<span class="keyword">const</span> HCB&);
+<span class="keyword">template</span> <<span class="keyword">typename</span> HCB> <span class="keyword">typename</span> element_reference_type<HCB>::type static_min( HCB&);
+<span class="keyword">template</span> <<span class="keyword">typename</span> HCB> <span class="keyword">typename</span> element_const_reference_type<HCB>::type static_max(<span class="keyword">const</span> HCB&);
+<span class="keyword">template</span> <<span class="keyword">typename</span> HCB> <span class="keyword">typename</span> element_reference_type<HCB>::type static_max( HCB&);
+</pre></div><p>
+These algorithms are designed after the corresponding STL algorithms, except that instead of ranges they take color bases and operate on their elements. In addition, they are implemented with a compile-time recursion (thus the prefix "static_"). Finally, they pair the elements semantically instead of based on their physical order in memory. For example, here is the implementation of <code>static_equal:</code> <p>
+<div class="fragment"><pre class="fragment"><span class="keyword">namespace </span>detail {
+<span class="keyword">template</span> <<span class="keywordtype">int</span> K> <span class="keyword">struct </span>element_recursion {
+ <span class="keyword">template</span> <<span class="keyword">typename</span> P1,<span class="keyword">typename</span> P2>
+ <span class="keyword">static</span> <span class="keywordtype">bool</span> static_equal(<span class="keyword">const</span> P1& p1, <span class="keyword">const</span> P2& p2) {
+ <span class="keywordflow">return</span> element_recursion<K-1>::static_equal(p1,p2) &&
+ <a class="code" href="http://opensource.adobe.com/gil/html/group___color_base_algorithm_semantic_at_c.html#ga0">semantic_at_c</a><K-1>(p1)==<a class="code" href="http://opensource.adobe.com/gil/html/group___color_base_algorithm_semantic_at_c.html#ga0">semantic_at_c</a><N-1>(p2);
+ }
+};
+<span class="keyword">template</span> <> <span class="keyword">struct </span>element_recursion<0> {
+ <span class="keyword">template</span> <<span class="keyword">typename</span> P1,<span class="keyword">typename</span> P2>
+ <span class="keyword">static</span> <span class="keywordtype">bool</span> static_equal(<span class="keyword">const</span> P1&, <span class="keyword">const</span> P2&) { <span class="keywordflow">return</span> <span class="keyword">true</span>; }
+};
+}
+
+<span class="keyword">template</span> <<span class="keyword">typename</span> P1,<span class="keyword">typename</span> P2>
+<span class="keywordtype">bool</span> static_equal(<span class="keyword">const</span> P1& p1, <span class="keyword">const</span> P2& p2) {
+ gil_function_requires<ColorSpacesCompatibleConcept<P1::layout_t::color_space_t,P2::layout_t::color_space_t> >();
+ <span class="keywordflow">return</span> detail::element_recursion<size<P1>::value>::static_equal(p1,p2);
+}
+</pre></div><p>
+This algorithm is used when invoking <code>operator==</code> on two pixels, for example. By using semantic accessors we are properly comparing an RGB pixel to a BGR pixel. Notice also that all of the above algorithms taking more than one color base require that they all have the same color space.<p>
+<hr>
+ <h2><a class="anchor" name="PixelSectionDG">
+7. Pixel</a></h2>
+A pixel is a set of channels defining the color at a given point in an image. Conceptually, a pixel is little more than a color base whose elements model <code>ChannelConcept</code>. All properties of pixels inherit from color bases: pixels may be <em>homogeneous</em> if all of their channels have the same type; otherwise they are called <em>heterogeneous</em>. The channels of a pixel may be addressed using semantic or physical indexing, or by color; all color-base algorithms work on pixels as well. Two pixels are <em>compatible</em> if their color spaces are the same and their channels, paired semantically, are compatible. Note that constness, memory organization and reference/value are ignored. For example, an 8-bit RGB planar reference is compatible to a constant 8-bit BGR interleaved pixel value. Most pairwise pixel operations (copy construction, assignment, equality, etc.) are only defined for compatible pixels.<p>
+Pixels (as well as other GIL constructs built on pixels, such as iterators, locators, views and images) must provide metafunctions to access their color space, channel mapping, number of channels, and (for homogeneous pixels) the channel type:<p>
+<div class="fragment"><pre class="fragment">concept PixelBasedConcept<typename T> {
+ <span class="keyword">typename</span> color_space_type<T>;
+ where Metafunction<color_space_type<T> >;
+ where ColorSpaceConcept<color_space_type<T>::type>;
+ <span class="keyword">typename</span> channel_mapping_type<T>;
+ where Metafunction<channel_mapping_type<T> >;
+ where ChannelMappingConcept<channel_mapping_type<T>::type>;
+ <span class="keyword">typename</span> is_planar<T>;
+ where Metafunction<is_planar<T> >;
+ where SameType<is_planar<T>::type, <span class="keywordtype">bool</span>>;
+};
+
+concept HomogeneousPixelBasedConcept<PixelBasedConcept T> {
+ <span class="keyword">typename</span> channel_type<T>;
+ where Metafunction<channel_type<T> >;
+ where ChannelConcept<channel_type<T>::type>;
+};
+</pre></div><p>
+Pixels model the following concepts:<p>
+<div class="fragment"><pre class="fragment">concept PixelConcept<typename P> : ColorBaseConcept<P>, PixelBasedConcept<P> {
+ where is_pixel<P>::type::value==<span class="keyword">true</span>;
+ <span class="comment">// where for each K [0..size<P>::value-1]:</span>
+ <span class="comment">// ChannelConcept<kth_element_type<K> >;</span>
+
+ <span class="keyword">typename</span> value_type; where PixelValueConcept<value_type>;
+ <span class="keyword">typename</span> reference; where PixelConcept<reference>;
+ <span class="keyword">typename</span> const_reference; where PixelConcept<const_reference>;
+ <span class="keyword">static</span> <span class="keyword">const</span> <span class="keywordtype">bool</span> P::is_mutable;
+
+ <span class="keyword">template</span> <PixelConcept P2> where { PixelConcept<P,P2> }
+ P::P(P2);
+ <span class="keyword">template</span> <PixelConcept P2> where { PixelConcept<P,P2> }
+ <span class="keywordtype">bool</span> operator==(<span class="keyword">const</span> P&, <span class="keyword">const</span> P2&);
+ <span class="keyword">template</span> <PixelConcept P2> where { PixelConcept<P,P2> }
+ <span class="keywordtype">bool</span> operator!=(<span class="keyword">const</span> P&, <span class="keyword">const</span> P2&);
+};
+
+concept MutablePixelConcept<typename P> : PixelConcept<P>, MutableColorBaseConcept<P> {
+ where is_mutable==<span class="keyword">true</span>;
+};
+
+concept HomogeneousPixelConcept<PixelConcept P> : HomogeneousColorBaseConcept<P>, HomogeneousPixelBasedConcept<P> {
+ P::template element_const_reference_type<P>::type operator[](P p, std::size_t i)<span class="keyword"> const </span>{ <span class="keywordflow">return</span> dynamic_at_c(P,i); }
+};
+
+concept MutableHomogeneousPixelConcept<MutablePixelConcept P> : MutableHomogeneousColorBaseConcept<P> {
+ P::template element_reference_type<P>::type operator[](P p, std::size_t i) { <span class="keywordflow">return</span> dynamic_at_c(p,i); }
+};
+
+concept PixelValueConcept<typename P> : PixelConcept<P>, Regular<P> {
+ where SameType<value_type,P>;
+};
+
+concept PixelsCompatibleConcept<PixelConcept P1, PixelConcept P2> : ColorBasesCompatibleConcept<P1,P2> {
+ <span class="comment">// where for each K [0..size<P1>::value):</span>
+ <span class="comment">// ChannelsCompatibleConcept<kth_semantic_element_type<P1,K>::type, kth_semantic_element_type<P2,K>::type>;</span>
+};
+</pre></div><p>
+A pixel is <em>convertible</em> to a second pixel if it is possible to approximate its color in the form of the second pixel. Conversion is an explicit, non-symmetric and often lossy operation (due to both channel and color space approximation). Convertability requires modeling the following concept:<p>
+<div class="fragment"><pre class="fragment"><span class="keyword">template</span> <PixelConcept SrcPixel, MutablePixelConcept DstPixel>
+concept PixelConvertibleConcept {
+ <span class="keywordtype">void</span> <a class="code" href="http://opensource.adobe.com/gil/html/group___pixel_algorithm.html#ga0">color_convert</a>(<span class="keyword">const</span> SrcPixel&, DstPixel&);
+};
+</pre></div><p>
+The distinction between <code>PixelConcept</code> and <code>PixelValueConcept</code> is analogous to that for channels and color bases - pixel reference proxies model both, but only pixel values model the latter.<p>
+<b>Related Concepts:</b><p>
+<ul>
+<li>PixelBasedConcept<P></li><li>PixelConcept<Pixel></li><li>MutablePixelConcept<Pixel></li><li>PixelValueConcept<Pixel></li><li>HomogeneousPixelConcept<Pixel></li><li>MutableHomogeneousPixelConcept<Pixel></li><li>HomogeneousPixelValueConcept<Pixel></li><li>PixelsCompatibleConcept<Pixel1,Pixel2></li><li>PixelConvertibleConcept<SrcPixel,DstPixel></li></ul>
+<p>
+<b>Models:</b><p>
+The most commonly used pixel is a homogeneous pixel whose values are together in memory. For this purpose GIL provides the struct <code>pixel</code>, templated over the channel value and layout:<p>
+<div class="fragment"><pre class="fragment"><span class="comment">// models HomogeneousPixelValueConcept</span>
+<span class="keyword">template</span> <<span class="keyword">typename</span> ChannelValue, <span class="keyword">typename</span> Layout> <span class="keyword">struct </span>pixel;
+
+<span class="comment">// Those typedefs are already provided by GIL</span>
+<span class="keyword">typedef</span> pixel<bits8, rgb_layout_t> rgb8_pixel_t;
+<span class="keyword">typedef</span> pixel<bits8, bgr_layout_t> bgr8_pixel_t;
+
+bgr8_pixel_t bgr8(255,0,0); <span class="comment">// pixels can be initialized with the channels directly</span>
+rgb8_pixel_t rgb8(bgr8); <span class="comment">// compatible pixels can also be copy-constructed</span>
+
+rgb8 = bgr8; <span class="comment">// assignment and equality is defined between compatible pixels</span>
+assert(rgb8 == bgr8); <span class="comment">// assignment and equality operate on the semantic channels</span>
+
+<span class="comment">// The first physical channels of the two pixels are different</span>
+assert(at_c<0>(rgb8) != at_c<0>(bgr8));
+assert(dynamic_at_c(bgr8,0) != dynamic_at_c(rgb8,0));
+assert(rgb8[0] != bgr8[0]); <span class="comment">// same as above (but operator[] is defined for pixels only)</span>
+</pre></div><p>
+Planar pixels have their channels distributed in memory. While they share the same value type (<code>pixel</code>) with interleaved pixels, their reference type is a proxy class containing references to each of the channels. This is implemented with the struct <code>planar_pixel_reference:</code> <p>
+<div class="fragment"><pre class="fragment"><span class="comment">// models HomogeneousPixel</span>
+<span class="keyword">template</span> <<span class="keyword">typename</span> ChannelReference, <span class="keyword">typename</span> ColorSpace> <span class="keyword">struct </span>planar_pixel_reference;
+
+<span class="comment">// Define the type of a mutable and read-only reference. (These typedefs are already provided by GIL)</span>
+<span class="keyword">typedef</span> planar_pixel_reference< bits8&,rgb_t> rgb8_planar_ref_t;
+<span class="keyword">typedef</span> planar_pixel_reference<const bits8&,rgb_t> rgb8c_planar_ref_t;
+</pre></div><p>
+Note that, unlike the <code>pixel</code> struct, planar pixel references are templated over the color space, not over the pixel layout. They always use a cannonical channel ordering. Ordering of their elements is unnecessary because their elements are references to the channels.<p>
+Sometimes the channels of a pixel may not be byte-aligned. For example an RGB pixel in '5-5-6' format is a 16-bit pixel whose red, green and blue channels occupy bits [0..4],[5..9] and [10..15] respectively. GIL provides a model for such packed pixel formats:<p>
+<div class="fragment"><pre class="fragment"><span class="comment">// define an rgb565 pixel</span>
+<span class="keyword">typedef</span> packed_pixel_type<uint16_t, mpl::vector3_c<unsigned,5,6,5>, rgb_layout_t>::type rgb565_pixel_t;
+
+function_requires<PixelValueConcept<rgb565_pixel_t> >();
+BOOST_STATIC_ASSERT((<span class="keyword">sizeof</span>(rgb565_pixel_t)==2));
+
+<span class="comment">// define a bgr556 pixel</span>
+<span class="keyword">typedef</span> packed_pixel_type<uint16_t, mpl::vector3_c<unsigned,5,6,5>, bgr_layout_t>::type bgr556_pixel_t;
+
+function_requires<PixelValueConcept<bgr556_pixel_t> >();
+
+<span class="comment">// rgb565 is compatible with bgr556.</span>
+function_requires<PixelsCompatibleConcept<rgb565_pixel_t,bgr556_pixel_t> >();
+</pre></div><p>
+In some cases, the pixel itself may not be byte aligned. For example, consider an RGB pixel in '2-3-2' format. Its size is 7 bits. GIL refers to such pixels, pixel iterators and images as "bit-aligned". Bit-aligned pixels (and images) are more complex than packed ones. Since packed pixels are byte-aligned, we can use a C++ reference as the reference type to a packed pixel, and a C pointer as an x_iterator over a row of packed pixels. For bit-aligned constructs we need a special reference proxy class (bit_aligned_pixel_reference) and iterator class (bit_aligned_pixel_iterator). The value type of bit-aligned pixels is a packed_pixel. Here is how to use bit_aligned pixels and pixel iterators:<p>
+<div class="fragment"><pre class="fragment"><span class="comment">// Mutable reference to a BGR232 pixel</span>
+<span class="keyword">typedef</span> <span class="keyword">const</span> bit_aligned_pixel_reference<mpl::vector3_c<unsigned,2,3,2>, bgr_layout_t, <span class="keyword">true</span>> bgr232_ref_t;
+
+<span class="comment">// A mutable iterator over BGR232 pixels</span>
+<span class="keyword">typedef</span> bit_aligned_pixel_iterator<bgr232_ref_t> bgr232_ptr_t;
+
+<span class="comment">// BGR232 pixel value. It is a packed_pixel of size 1 byte. (The last bit is unused)</span>
+<span class="keyword">typedef</span> std::iterator_traits<bgr232_ptr_t>::value_type bgr232_pixel_t;
+BOOST_STATIC_ASSERT((<span class="keyword">sizeof</span>(bgr232_pixel_t)==1));
+
+bgr232_pixel_t red(0,0,3); <span class="comment">// = 0RRGGGBB, = 01100000 = 0x60</span>
+
+<span class="comment">// a buffer of 7 bytes fits exactly 8 BGR232 pixels.</span>
+<span class="keywordtype">unsigned</span> <span class="keywordtype">char</span> pix_buffer[7];
+<a class="code" href="http://opensource.adobe.com/gil/html/group___s_t_l_optimizations.html#ga4">std::fill</a>(pix_buffer,pix_buffer+7,0);
+
+<span class="comment">// Fill the 8 pixels with red</span>
+bgr232_ptr_t pix_it(&pix_buffer[0],0); <span class="comment">// start at bit 0 of the first pixel</span>
+<span class="keywordflow">for</span> (<span class="keywordtype">int</span> i=0; i<8; ++i) {
+ *pix_it++ = red;
+}
+<span class="comment">// Result: 0x60 0x30 0x11 0x0C 0x06 0x83 0xC1</span>
+</pre></div><p>
+<b>Algorithms:</b><p>
+Since pixels model <code>ColorBaseConcept</code> and <code>PixelBasedConcept</code> all algorithms and metafunctions of color bases can work with them as well:<p>
+<div class="fragment"><pre class="fragment"><span class="comment">// This is how to access the first semantic channel (red)</span>
+assert(semantic_at_c<0>(rgb8) == semantic_at_c<0>(bgr8));
+
+<span class="comment">// This is how to access the red channel by name</span>
+assert(get_color<red_t>(rgb8) == get_color<red_t>(bgr8));
+
+<span class="comment">// This is another way of doing it (some compilers don't like the first one)</span>
+assert(<a class="code" href="http://opensource.adobe.com/gil/html/group___color_base_algorithm_color.html#ga0">get_color</a>(rgb8,red_t()) == <a class="code" href="http://opensource.adobe.com/gil/html/group___color_base_algorithm_color.html#ga0">get_color</a>(bgr8,red_t()));
+
+<span class="comment">// This is how to use the PixelBasedConcept metafunctions</span>
+BOOST_MPL_ASSERT(num_channels<rgb8_pixel_t>::value == 3);
+BOOST_MPL_ASSERT((is_same<channel_type<rgb8_pixel_t>::type, bits8>));
+BOOST_MPL_ASSERT((is_same<color_space_type<bgr8_pixel_t>::type, rgb_t> ));
+BOOST_MPL_ASSERT((is_same<channel_mapping_type<bgr8_pixel_t>::type, mpl::vector3_c<int,2,1,0> > ));
+
+<span class="comment">// Pixels contain just the three channels and nothing extra</span>
+BOOST_MPL_ASSERT(<span class="keyword">sizeof</span>(rgb8_pixel_t)==3);
+
+rgb8_planar_ref_t ref(bgr8); <span class="comment">// copy construction is allowed from a compatible mutable pixel type</span>
+
+get_color<red_t>(ref) = 10; <span class="comment">// assignment is ok because the reference is mutable</span>
+assert(get_color<red_t>(bgr8)==10); <span class="comment">// references modify the value they are bound to</span>
+
+<span class="comment">// Create a zero packed pixel and a full regular unpacked pixel.</span>
+rgb565_pixel_t r565;
+rgb8_pixel_t rgb_full(255,255,255);
+
+<span class="comment">// Convert all channels of the unpacked pixel to the packed one & assert the packed one is full</span>
+<a class="code" href="http://opensource.adobe.com/gil/html/group___color_base_algorithm_color.html#ga0">get_color</a>(r565,red_t()) = channel_convert<rgb565_channel0_t>(<a class="code" href="http://opensource.adobe.com/gil/html/group___color_base_algorithm_color.html#ga0">get_color</a>(rgb_full,red_t()));
+<a class="code" href="http://opensource.adobe.com/gil/html/group___color_base_algorithm_color.html#ga0">get_color</a>(r565,green_t()) = channel_convert<rgb565_channel1_t>(<a class="code" href="http://opensource.adobe.com/gil/html/group___color_base_algorithm_color.html#ga0">get_color</a>(rgb_full,green_t()));
+<a class="code" href="http://opensource.adobe.com/gil/html/group___color_base_algorithm_color.html#ga0">get_color</a>(r565,blue_t()) = channel_convert<rgb565_channel2_t>(<a class="code" href="http://opensource.adobe.com/gil/html/group___color_base_algorithm_color.html#ga0">get_color</a>(rgb_full,blue_t()));
+assert(r565 == rgb565_pixel_t((uint16_t)65535));
+</pre></div><p>
+GIL also provides the <code>color_convert</code> algorithm to convert between pixels of different color spaces and channel types:<p>
+<div class="fragment"><pre class="fragment">rgb8_pixel_t red_in_rgb8(255,0,0);
+cmyk16_pixel_t red_in_cmyk16;
+<a class="code" href="http://opensource.adobe.com/gil/html/group___pixel_algorithm.html#ga0">color_convert</a>(red_in_rgb8,red_in_cmyk16);
+</pre></div><p>
+<hr>
+ <h2><a class="anchor" name="PixelIteratorSectionDG">
+8. Pixel Iterator</a></h2>
+<h2><a class="anchor" name="FundamentalIteratorDG">
+Fundamental Iterator</a></h2>
+Pixel iterators are random traversal iterators whose <code>value_type</code> models <code>PixelValueConcept</code>. Pixel iterators provide metafunctions to determine whether they are mutable (i.e. whether they allow for modifying the pixel they refer to), to get the immutable (read-only) type of the iterator, and to determine whether they are plain iterators or adaptors over another pixel iterator:<p>
+<div class="fragment"><pre class="fragment">concept PixelIteratorConcept<RandomAccessTraversalIteratorConcept Iterator> : PixelBasedConcept<Iterator> {
+ where PixelValueConcept<value_type>;
+ <span class="keyword">typename</span> const_iterator_type<It>::type;
+ where PixelIteratorConcept<const_iterator_type<It>::type>;
+ <span class="keyword">static</span> <span class="keyword">const</span> <span class="keywordtype">bool</span> iterator_is_mutable<It>::type::value;
+ <span class="keyword">static</span> <span class="keyword">const</span> <span class="keywordtype">bool</span> is_iterator_adaptor<It>::type::value; <span class="comment">// is it an iterator adaptor</span>
+};
+
+<span class="keyword">template</span> <<span class="keyword">typename</span> Iterator>
+concept MutablePixelIteratorConcept : PixelIteratorConcept<Iterator>, MutableRandomAccessIteratorConcept<Iterator> {};
+</pre></div><p>
+<b>Related Concepts:</b><p>
+<ul>
+<li>PixelIteratorConcept<Iterator></li><li>MutablePixelIteratorConcept<Iterator></li></ul>
+<p>
+<b>Models:</b><p>
+A built-in pointer to pixel, <code>pixel<ChannelValue,Layout>*</code>, is GIL's model for pixel iterator over interleaved homogeneous pixels. Similarly, <code>packed_pixel<PixelData,ChannelRefVec,Layout>*</code> is GIL's model for an iterator over interleaved packed pixels.<p>
+For planar homogeneous pixels, GIL provides the class <code>planar_pixel_iterator</code>, templated over a channel iterator and color space. Here is how the standard mutable and read-only planar RGB iterators over unsigned char are defined:<p>
+<div class="fragment"><pre class="fragment"><span class="keyword">template</span> <<span class="keyword">typename</span> ChannelPtr, <span class="keyword">typename</span> ColorSpace> <span class="keyword">struct </span>planar_pixel_iterator;
+
+<span class="comment">// GIL provided typedefs</span>
+<span class="keyword">typedef</span> planar_pixel_iterator<const bits8*, rgb_t> rgb8c_planar_ptr_t;
+<span class="keyword">typedef</span> planar_pixel_iterator< bits8*, rgb_t> rgb8_planar_ptr_t;
+</pre></div><p>
+<code>planar_pixel_iterator</code> also models <code>HomogeneousColorBaseConcept</code> (it subclasses from <code>homogeneous_color_base</code>) and, as a result, all color base algorithms apply to it. The element type of its color base is a channel iterator. For example, GIL implements <code>operator++</code> of planar iterators approximately like this:<p>
+<div class="fragment"><pre class="fragment"><span class="keyword">template</span> <<span class="keyword">typename</span> T>
+<span class="keyword">struct </span>inc : <span class="keyword">public</span> std::unary_function<T,T> {
+ T operator()(T x)<span class="keyword"> const </span>{ <span class="keywordflow">return</span> ++x; }
+};
+
+<span class="keyword">template</span> <<span class="keyword">typename</span> ChannelPtr, <span class="keyword">typename</span> ColorSpace>
+planar_pixel_iterator<ChannelPtr,ColorSpace>&
+planar_pixel_iterator<ChannelPtr,ColorSpace>::operator++() {
+ static_transform(*<span class="keyword">this</span>,*<span class="keyword">this</span>,inc<ChannelPtr>());
+ <span class="keywordflow">return</span> *<span class="keyword">this</span>;
+}
+</pre></div><p>
+Since <code>static_transform</code> uses compile-time recursion, incrementing an instance of <code>rgb8_planar_ptr_t</code> amounts to three pointer increments. GIL also uses the class bit_aligned_pixel_iterator as a model for a pixel iterator over bit-aligned pixels. Internally it keeps track of the current byte and the bit offset.<h2><a class="anchor" name="IteratorAdaptorDG">
+Iterator Adaptor</a></h2>
+Iterator adaptor is an iterator that wraps around another iterator. Its <code>is_iterator_adaptor</code> metafunction must evaluate to true, and it needs to provide a member method to return the base iterator, a metafunction to get its type, and a metafunction to rebind to another base iterator:<p>
+<div class="fragment"><pre class="fragment">concept IteratorAdaptorConcept<RandomAccessTraversalIteratorConcept Iterator> {
+ where SameType<is_iterator_adaptor<Iterator>::type, mpl::true_>;
+
+ <span class="keyword">typename</span> iterator_adaptor_get_base<Iterator>;
+ where Metafunction<iterator_adaptor_get_base<Iterator> >;
+ where boost_concepts::ForwardTraversalConcept<iterator_adaptor_get_base<Iterator>::type>;
+
+ <span class="keyword">typename</span> another_iterator;
+ <span class="keyword">typename</span> iterator_adaptor_rebind<Iterator,another_iterator>::type;
+ where boost_concepts::ForwardTraversalConcept<another_iterator>;
+ where IteratorAdaptorConcept<iterator_adaptor_rebind<Iterator,another_iterator>::type>;
+
+ <span class="keyword">const</span> iterator_adaptor_get_base<Iterator>::type& Iterator::base() <span class="keyword">const</span>;
+};
+
+<span class="keyword">template</span> <boost_concepts::Mutable_ForwardIteratorConcept Iterator>
+concept MutableIteratorAdaptorConcept : IteratorAdaptorConcept<Iterator> {};
+</pre></div><p>
+<b>Related Concepts:</b><p>
+<ul>
+<li>IteratorAdaptorConcept<Iterator></li><li>MutableIteratorAdaptorConcept<Iterator></li></ul>
+<p>
+<b>Models:</b><p>
+GIL provides several models of IteratorAdaptorConcept:<ul>
+<li><code>memory_based_step_iterator<Iterator></code>: An iterator adaptor that changes the fundamental step of the base iterator (see <a class="el" href="gildesignguide.html#StepIteratorDG">Step Iterator</a>)</li><li><code>dereference_iterator_adaptor<Iterator</code>,Fn>: An iterator that applies a unary function <code>Fn</code> upon dereferencing. It is used, for example, for on-the-fly color conversion. It can be used to construct a shallow image "view" that pretends to have a different color space or channel depth. See <a class="el" href="gildesignguide.html#ImageViewFrowImageViewDG">Creating Image Views from Other Image Views</a> for more. The unary function <code>Fn</code> must model <code>PixelDereferenceAdaptorConcept</code> (see below).</li></ul>
+<h2><a class="anchor" name="PixelDereferenceAdaptorAG">
+Pixel Dereference Adaptor</a></h2>
+Pixel dereference adaptor is a unary function that can be applied upon dereferencing a pixel iterator. Its argument type could be anything (usually a <code>PixelConcept</code>) and the result type must be convertible to <code>PixelConcept</code> <p>
+<div class="fragment"><pre class="fragment"><span class="keyword">template</span> <boost::UnaryFunctionConcept D>
+concept PixelDereferenceAdaptorConcept : DefaultConstructibleConcept<D>, CopyConstructibleConcept<D>, AssignableConcept<D> {
+ <span class="keyword">typename</span> const_t; where PixelDereferenceAdaptorConcept<const_t>;
+ <span class="keyword">typename</span> value_type; where PixelValueConcept<value_type>;
+ <span class="keyword">typename</span> reference; where PixelConcept<remove_reference<reference>::type>; <span class="comment">// may be mutable</span>
+ <span class="keyword">typename</span> const_reference; <span class="comment">// must not be mutable</span>
+ <span class="keyword">static</span> <span class="keyword">const</span> <span class="keywordtype">bool</span> D::is_mutable;
+
+ where Convertible<value_type, result_type>;
+};
+</pre></div><p>
+<b>Models:</b><p>
+GIL provides several models of <code>PixelDereferenceAdaptorConcept</code> <ul>
+<li><code>color_convert_deref_fn:</code> a function object that performs color conversion</li><li><code>detail::nth_channel_deref_fn:</code> a function object that returns a grayscale pixel corresponding to the n-th channel of a given pixel</li><li><code>deref_compose:</code> a function object that composes two models of <code>PixelDereferenceAdaptorConcept</code>. Similar to <code>std::unary_compose</code>, except it needs to pull the additional typedefs required by <code>PixelDereferenceAdaptorConcept</code> </li></ul>
+<p>
+GIL uses pixel dereference adaptors to implement image views that perform color conversion upon dereferencing, or that return the N-th channel of the underlying pixel. They can be used to model virtual image views that perform an arbitrary function upon dereferencing, for example a view of the Mandelbrot set. <code>dereference_iterator_adaptor<Iterator,Fn></code> is an iterator wrapper over a pixel iterator <code>Iterator</code> that invokes the given dereference iterator adaptor <code>Fn</code> upon dereferencing.<h2><a class="anchor" name="StepIteratorDG">
+Step Iterator</a></h2>
+Sometimes we want to traverse pixels with a unit step other than the one provided by the fundamental pixel iterators. Examples where this would be useful:<ul>
+<li>a single-channel view of the red channel of an RGB interleaved image</li><li>left-to-right flipped image (step = -fundamental_step)</li><li>subsampled view, taking every N-th pixel (step = N*fundamental_step)</li><li>traversal in vertical direction (step = number of bytes per row)</li><li>any combination of the above (steps are multiplied)</li></ul>
+<p>
+Step iterators are forward traversal iterators that allow changing the step between adjacent values:<p>
+<div class="fragment"><pre class="fragment">concept StepIteratorConcept<boost_concepts::ForwardTraversalConcept Iterator> {
+ <span class="keyword">template</span> <Integral D> <span class="keywordtype">void</span> Iterator::set_step(D step);
+};
+
+concept MutableStepIteratorConcept<boost_concepts::Mutable_ForwardIteratorConcept Iterator> : StepIteratorConcept<Iterator> {};
+</pre></div><p>
+GIL currently provides a step iterator whose <code>value_type</code> models <code>PixelValueConcept</code>. In addition, the step is specified in memory units (which are bytes or bits). This is necessary, for example, when implementing an iterator navigating along a column of pixels - the size of a row of pixels may sometimes not be divisible by the size of a pixel; for example rows may be word-aligned.<p>
+To advance in bytes/bits, the base iterator must model MemoryBasedIteratorConcept. A memory-based iterator has an inherent memory unit, which is either a bit or a byte. It must supply functions returning the number of bits per memory unit (1 or 8), the current step in memory units, the memory-unit distance between two iterators, and a reference a given distance in memunits away. It must also supply a function that advances an iterator a given distance in memory units. <code>memunit_advanced</code> and <code>memunit_advanced_ref</code> have a default implementation but some iterators may supply a more efficient version:<p>
+<div class="fragment"><pre class="fragment">concept MemoryBasedIteratorConcept<boost_concepts::RandomAccessTraversalConcept Iterator> {
+ <span class="keyword">typename</span> byte_to_memunit<Iterator>; where metafunction<byte_to_memunit<Iterator> >;
+ std::ptrdiff_t memunit_step(<span class="keyword">const</span> Iterator&);
+ std::ptrdiff_t memunit_distance(<span class="keyword">const</span> Iterator& , <span class="keyword">const</span> Iterator&);
+ <span class="keywordtype">void</span> memunit_advance(Iterator&, std::ptrdiff_t diff);
+ Iterator memunit_advanced(<span class="keyword">const</span> Iterator& p, std::ptrdiff_t diff) { Iterator tmp; memunit_advance(tmp,diff); <span class="keywordflow">return</span> tmp; }
+ Iterator::reference memunit_advanced_ref(<span class="keyword">const</span> Iterator& p, std::ptrdiff_t diff) { <span class="keywordflow">return</span> *memunit_advanced(p,diff); }
+};
+</pre></div><p>
+It is useful to be able to construct a step iterator over another iterator. More generally, given a type, we want to be able to construct an equivalent type that allows for dynamically specified horizontal step:<p>
+<div class="fragment"><pre class="fragment">concept HasDynamicXStepTypeConcept<typename T> {
+ <span class="keyword">typename</span> dynamic_x_step_type<T>;
+ where Metafunction<dynamic_x_step_type<T> >;
+};
+</pre></div><p>
+All models of pixel iterators, locators and image views that GIL provides support <code>HasDynamicXStepTypeConcept</code>.<p>
+<b>Related Concepts:</b><p>
+<ul>
+<li>StepIteratorConcept<Iterator></li><li>MutableStepIteratorConcept<Iterator></li><li>MemoryBasedIteratorConcept<Iterator></li><li>HasDynamicXStepTypeConcept<T></li></ul>
+<p>
+<b>Models:</b><p>
+All standard memory-based iterators GIL currently provides model <code>MemoryBasedIteratorConcept</code>. GIL provides the class <code>memory_based_step_iterator</code> which models <code>PixelIteratorConcept</code>, <code>StepIteratorConcept</code>, and <code>MemoryBasedIteratorConcept</code>. It takes the base iterator as a template parameter (which must model <code>PixelIteratorConcept</code> and <code>MemoryBasedIteratorConcept</code>) and allows changing the step dynamically. GIL's implementation contains the base iterator and a <code>ptrdiff_t</code> denoting the number of memory units (bytes or bits) to skip for a unit step. It may also be used with a negative number. GIL provides a function to create a step iterator from a base iterator and a step:<p>
+<div class="fragment"><pre class="fragment"><span class="keyword">template</span> <<span class="keyword">typename</span> I> <span class="comment">// Models MemoryBasedIteratorConcept, HasDynamicXStepTypeConcept</span>
+<span class="keyword">typename</span> dynamic_x_step_type<I>::type make_step_iterator(<span class="keyword">const</span> I& it, std::ptrdiff_t step);
+</pre></div><p>
+GIL also provides a model of an iterator over a virtual array of pixels, <code>position_iterator</code>. It is a step iterator that keeps track of the pixel position and invokes a function object to get the value of the pixel upon dereferencing. It models <code>PixelIteratorConcept</code> and <code>StepIteratorConcept</code> but not <code>MemoryBasedIteratorConcept</code>.<h2><a class="anchor" name="LocatorDG">
+Pixel Locator</a></h2>
+A Locator allows for navigation in two or more dimensions. Locators are N-dimensional iterators in spirit, but we use a different name because they don't satisfy all the requirements of iterators. For example, they don't supply increment and decrement operators because it is unclear which dimension the operators should advance along. N-dimensional locators model the following concept:<p>
+<div class="fragment"><pre class="fragment">concept RandomAccessNDLocatorConcept<Regular Loc> {
+ <span class="keyword">typename</span> value_type; <span class="comment">// value over which the locator navigates</span>
+ <span class="keyword">typename</span> reference; <span class="comment">// result of dereferencing</span>
+ <span class="keyword">typename</span> difference_type; where PointNDConcept<difference_type>; <span class="comment">// return value of operator-.</span>
+ <span class="keyword">typename</span> const_t; <span class="comment">// same as Loc, but operating over immutable values</span>
+ <span class="keyword">typename</span> cached_location_t; <span class="comment">// type to store relative location (for efficient repeated access)</span>
+ <span class="keyword">typename</span> point_t = difference_type;
+
+ <span class="keyword">static</span> <span class="keyword">const</span> size_t num_dimensions; <span class="comment">// dimensionality of the locator</span>
+ where num_dimensions = point_t::num_dimensions;
+
+ <span class="comment">// The difference_type and iterator type along each dimension. The iterators may only differ in </span>
+ <span class="comment">// difference_type. Their value_type must be the same as Loc::value_type</span>
+ <span class="keyword">template</span> <size_t D> <span class="keyword">struct </span>axis {
+ <span class="keyword">typename</span> coord_t = point_t::axis<D>::coord_t;
+ <span class="keyword">typename</span> iterator; where RandomAccessTraversalConcept<iterator>; <span class="comment">// iterator along D-th axis.</span>
+ where iterator::value_type == value_type;
+ };
+
+ <span class="comment">// Defines the type of a locator similar to this type, except it invokes Deref upon dereferencing</span>
+ <span class="keyword">template</span> <PixelDereferenceAdaptorConcept Deref> <span class="keyword">struct </span>add_deref {
+ <span class="keyword">typename</span> type; where RandomAccessNDLocatorConcept<type>;
+ <span class="keyword">static</span> type make(<span class="keyword">const</span> Loc& loc, <span class="keyword">const</span> Deref& deref);
+ };
+
+ Loc& operator+=(Loc&, <span class="keyword">const</span> difference_type&);
+ Loc& operator-=(Loc&, <span class="keyword">const</span> difference_type&);
+ Loc operator+(<span class="keyword">const</span> Loc&, <span class="keyword">const</span> difference_type&);
+ Loc operator-(<span class="keyword">const</span> Loc&, <span class="keyword">const</span> difference_type&);
+
+ reference operator*(<span class="keyword">const</span> Loc&);
+ reference operator[](<span class="keyword">const</span> Loc&, <span class="keyword">const</span> difference_type&);
+
+ <span class="comment">// Storing relative location for faster repeated access and accessing it </span>
+ cached_location_t Loc::cache_location(<span class="keyword">const</span> difference_type&) <span class="keyword">const</span>;
+ reference operator[](<span class="keyword">const</span> Loc&,<span class="keyword">const</span> cached_location_t&);
+
+ <span class="comment">// Accessing iterators along a given dimension at the current location or at a given offset</span>
+ <span class="keyword">template</span> <size_t D> axis<D>::iterator& Loc::axis_iterator();
+ <span class="keyword">template</span> <size_t D> axis<D>::iterator <span class="keyword">const</span>& Loc::axis_iterator() <span class="keyword">const</span>;
+ <span class="keyword">template</span> <size_t D> axis<D>::iterator Loc::axis_iterator(<span class="keyword">const</span> difference_type&) <span class="keyword">const</span>;
+};
+
+<span class="keyword">template</span> <<span class="keyword">typename</span> Loc>
+concept MutableRandomAccessNDLocatorConcept : RandomAccessNDLocatorConcept<Loc> {
+ where Mutable<reference>;
+};
+</pre></div><p>
+Two-dimensional locators have additional requirements:<p>
+<div class="fragment"><pre class="fragment">concept RandomAccess2DLocatorConcept<RandomAccessNDLocatorConcept Loc> {
+ where num_dimensions==2;
+ where Point2DConcept<point_t>;
+
+ <span class="keyword">typename</span> x_iterator = axis<0>::iterator;
+ <span class="keyword">typename</span> y_iterator = axis<1>::iterator;
+ <span class="keyword">typename</span> x_coord_t = axis<0>::coord_t;
+ <span class="keyword">typename</span> y_coord_t = axis<1>::coord_t;
+
+ <span class="comment">// Only available to locators that have dynamic step in Y</span>
+ <span class="comment">//Loc::Loc(const Loc& loc, y_coord_t);</span>
+
+ <span class="comment">// Only available to locators that have dynamic step in X and Y</span>
+ <span class="comment">//Loc::Loc(const Loc& loc, x_coord_t, y_coord_t, bool transposed=false);</span>
+
+ x_iterator& Loc::x();
+ x_iterator <span class="keyword">const</span>& Loc::x() <span class="keyword">const</span>;
+ y_iterator& Loc::y();
+ y_iterator <span class="keyword">const</span>& Loc::y() <span class="keyword">const</span>;
+
+ x_iterator Loc::x_at(<span class="keyword">const</span> difference_type&) <span class="keyword">const</span>;
+ y_iterator Loc::y_at(<span class="keyword">const</span> difference_type&) <span class="keyword">const</span>;
+ Loc Loc::xy_at(<span class="keyword">const</span> difference_type&) <span class="keyword">const</span>;
+
+ <span class="comment">// x/y versions of all methods that can take difference type</span>
+ x_iterator Loc::x_at(x_coord_t, y_coord_t) <span class="keyword">const</span>;
+ y_iterator Loc::y_at(x_coord_t, y_coord_t) <span class="keyword">const</span>;
+ Loc Loc::xy_at(x_coord_t, y_coord_t) <span class="keyword">const</span>;
+ reference operator()(<span class="keyword">const</span> Loc&, x_coord_t, y_coord_t);
+ cached_location_t Loc::cache_location(x_coord_t, y_coord_t) <span class="keyword">const</span>;
+
+ <span class="keywordtype">bool</span> Loc::is_1d_traversable(x_coord_t width) <span class="keyword">const</span>;
+ y_coord_t Loc::y_distance_to(<span class="keyword">const</span> Loc& loc2, x_coord_t x_diff) <span class="keyword">const</span>;
+};
+
+concept MutableRandomAccess2DLocatorConcept<RandomAccess2DLocatorConcept Loc> : MutableRandomAccessNDLocatorConcept<Loc> {};
+</pre></div><p>
+2D locators can have a dynamic step not just horizontally, but also vertically. This gives rise to the Y equivalent of <code>HasDynamicXStepTypeConcept:</code> <p>
+<div class="fragment"><pre class="fragment">concept HasDynamicYStepTypeConcept<typename T> {
+ <span class="keyword">typename</span> dynamic_y_step_type<T>;
+ where Metafunction<dynamic_y_step_type<T> >;
+};
+</pre></div><p>
+All locators and image views that GIL provides model <code>HasDynamicYStepTypeConcept</code>.<p>
+Sometimes it is necessary to swap the meaning of X and Y for a given locator or image view type (for example, GIL provides a function to transpose an image view). Such locators and views must be transposable:<p>
+<div class="fragment"><pre class="fragment">concept HasTransposedTypeConcept<typename T> {
+ <span class="keyword">typename</span> transposed_type<T>;
+ where Metafunction<transposed_type<T> >;
+};
+</pre></div><p>
+All GIL provided locators and views model <code>HasTransposedTypeConcept</code>.<p>
+The locators GIL uses operate over models of <code>PixelConcept</code> and their x and y dimension types are the same. They model the following concept:<p>
+<div class="fragment"><pre class="fragment">concept PixelLocatorConcept<RandomAccess2DLocatorConcept Loc> {
+ where PixelValueConcept<value_type>;
+ where PixelIteratorConcept<x_iterator>;
+ where PixelIteratorConcept<y_iterator>;
+ where x_coord_t == y_coord_t;
+
+ <span class="keyword">typename</span> coord_t = x_coord_t;
+};
+
+concept MutablePixelLocatorConcept<PixelLocatorConcept Loc> : MutableRandomAccess2DLocatorConcept<Loc> {};
+</pre></div><p>
+<b>Related Concepts:</b><p>
+<ul>
+<li>HasDynamicYStepTypeConcept<T></li><li>HasTransposedTypeConcept<T></li><li>RandomAccessNDLocatorConcept<Locator></li><li>MutableRandomAccessNDLocatorConcept<Locator></li><li>RandomAccess2DLocatorConcept<Locator></li><li>MutableRandomAccess2DLocatorConcept<Locator></li><li>PixelLocatorConcept<Locator></li><li>MutablePixelLocatorConcept<Locator></li></ul>
+<p>
+<b>Models:</b><p>
+GIL provides two models of <code>PixelLocatorConcept</code> - a memory-based locator, <code>memory_based_2d_locator</code> and a virtual locator <code>virtual_2d_locator</code>.<p>
+<code>memory_based_2d_locator</code> is a locator over planar or interleaved images that have their pixels in memory. It takes a model of <code>StepIteratorConcept</code> over pixels as a template parameter. (When instantiated with a model of <code>MutableStepIteratorConcept</code>, it models <code>MutablePixelLocatorConcept</code>).<p>
+<div class="fragment"><pre class="fragment"><span class="keyword">template</span> <<span class="keyword">typename</span> StepIterator> <span class="comment">// Models StepIteratorConcept, MemoryBasedIteratorConcept</span>
+<span class="keyword">class </span>memory_based_2d_locator;
+</pre></div><p>
+The step of <code>StepIterator</code> must be the number of memory units (bytes or bits) per row (thus it must be memunit advanceable). The class <code>memory_based_2d_locator</code> is a wrapper around <code>StepIterator</code> and uses it to navigate vertically, while its base iterator is used to navigate horizontally.<p>
+Combining fundamental and step iterators allows us to create locators that describe complex pixel memory organizations. First, we have a choice of iterator to use for horizontal direction, i.e. for iterating over the pixels on the same row. Using the fundamental and step iterators gives us four choices:<ul>
+<li><code>pixel<T,C>*</code> (for interleaved images)</li><li><code>planar_pixel_iterator<T*,C></code> (for planar images)</li><li><code>memory_based_step_iterator<pixel<T,C>*></code> (for interleaved images with non-standard step)</li><li><code> memory_based_step_iterator<planar_pixel_iterator<T*,C> > </code> (for planar images with non-standard step)</li></ul>
+<p>
+Of course, one could provide their own custom x-iterator. One such example described later is an iterator adaptor that performs color conversion when dereferenced.<p>
+Given a horizontal iterator <code>XIterator</code>, we could choose the <em>y-iterator</em>, the iterator that moves along a column, as <code>memory_based_step_iterator<XIterator></code> with a step equal to the number of memory units (bytes or bits) per row. Again, one is free to provide their own y-iterator.<p>
+Then we can instantiate <code>memory_based_2d_locator<memory_based_step_iterator<XIterator></code> > to obtain a 2D pixel locator, as the diagram indicates: <div align="center">
+<img src="step_iterator.gif" alt="step_iterator.gif">
+</div>
+<p>
+<code>virtual_2d_locator</code> is a locator that is instantiated with a function object invoked upon dereferencing a pixel. It returns the value of a pixel given its X,Y coordiantes. Virtual locators can be used to implement virtual image views that can model any user-defined function. See the GIL tutorial for an example of using virtual locators to create a view of the Mandelbrot set.<p>
+Both the virtual and the memory-based locators subclass from <code>pixel_2d_locator_base</code>, a base class that provides most of the interface required by <code>PixelLocatorConcept</code>. Users may find this base class useful if they need to provide other models of <code>PixelLocatorConcept</code>.<p>
+Here is some sample code using locators:<p>
+<div class="fragment"><pre class="fragment">loc=img.xy_at(10,10); <span class="comment">// start at pixel (x=10,y=10)</span>
+above=loc.cache_location(0,-1); <span class="comment">// remember relative locations of neighbors above and below</span>
+below=loc.cache_location(0, 1);
+++loc.x(); <span class="comment">// move to (11,10)</span>
+loc.y()+=15; <span class="comment">// move to (11,25)</span>
+loc-=point2<std::ptrdiff_t>(1,1);<span class="comment">// move to (10,24)</span>
+*loc=(loc(0,-1)+loc(0,1))/2; <span class="comment">// set pixel (10,24) to the average of (10,23) and (10,25) (grayscale pixels only)</span>
+*loc=(loc[above]+loc[below])/2; <span class="comment">// the same, but faster using cached relative neighbor locations</span>
+</pre></div><p>
+The standard GIL locators are fast and lightweight objects. For example, the locator for a simple interleaved image consists of one raw pointer to the pixel location plus one integer for the row size in bytes, for a total of 8 bytes. <code> ++loc.x() </code> amounts to incrementing a raw pointer (or N pointers for planar images). Computing 2D offsets is slower as it requires multiplication and addition. Filters, for example, need to access the same neighbors for every pixel in the image, in which case the relative positions can be cached into a raw byte difference using <code>cache_location</code>. In the above example <code> loc[above]</code> for simple interleaved images amounts to a raw array index operator.<h2><a class="anchor" name="IteratorFrom2DDG">
+Iterator over 2D image</a></h2>
+Sometimes we want to perform the same, location-independent operation over all pixels of an image. In such a case it is useful to represent the pixels as a one-dimensional array. GIL's <code>iterator_from_2d</code> is a random access traversal iterator that visits all pixels in an image in the natural memory-friendly order left-to-right inside top-to-bottom. It takes a locator, the width of the image and the current X position. This is sufficient information for it to determine when to do a "carriage return". Synopsis:<p>
+<div class="fragment"><pre class="fragment"><span class="keyword">template</span> <<span class="keyword">typename</span> Locator> <span class="comment">// Models PixelLocatorConcept</span>
+<span class="keyword">class </span>iterator_from_2d {
+<span class="keyword">public</span>:
+ iterator_from_2d(<span class="keyword">const</span> Locator& loc, <span class="keywordtype">int</span> x, <span class="keywordtype">int</span> width);
+
+ iterator_from_2d& operator++(); <span class="comment">// if (++_x<_width) ++_p.x(); else _p+=point_t(-_width,1);</span>
+
+ ...
+private:
+ <span class="keywordtype">int</span> _x, _width;
+ Locator _p;
+};
+</pre></div><p>
+Iterating through the pixels in an image using <code>iterator_from_2d</code> is slower than going through all rows and using the x-iterator at each row. This is because two comparisons are done per iteration step - one for the end condition of the loop using the iterators, and one inside <code>iterator_from_2d::operator++</code> to determine whether we are at the end of a row. For fast operations, such as pixel copy, this second check adds about 15% performance delay (measured for interleaved images on Intel platform). GIL overrides some STL algorithms, such as <code><a class="el" href="http://opensource.adobe.com/gil/html/group___s_t_l_optimizations.html#ga2">std::copy</a></code> and <code><a class="el" href="http://opensource.adobe.com/gil/html/group___s_t_l_optimizations.html#ga4">std::fill</a></code>, when invoked with <code>iterator_from_2d-s</code>, to go through each row using their base x-iterators, and, if the image has no padding (i.e. <code>iterator_from_2d::is_1d_traversable()</code> returns tru
e) to simply iterate using the x-iterators directly.<p>
+<hr>
+ <h2><a class="anchor" name="ImageViewSectionDG">
+9. Image View</a></h2>
+An image view is a generalization of STL's range concept to multiple dimensions. Similar to ranges (and iterators), image views are shallow, don't own the underlying data and don't propagate their constness over the data. For example, a constant image view cannot be resized, but may allow modifying the pixels. For pixel-immutable operations, use constant-value image view (also called non-mutable image view). Most general N-dimensional views satisfy the following concept:<p>
+<div class="fragment"><pre class="fragment">concept RandomAccessNDImageViewConcept<Regular View> {
+ <span class="keyword">typename</span> value_type; <span class="comment">// for pixel-based views, the pixel type</span>
+ <span class="keyword">typename</span> reference; <span class="comment">// result of dereferencing</span>
+ <span class="keyword">typename</span> difference_type; <span class="comment">// result of operator-(iterator,iterator) (1-dimensional!)</span>
+ <span class="keyword">typename</span> const_t; where RandomAccessNDImageViewConcept<View>; <span class="comment">// same as View, but over immutable values</span>
+ <span class="keyword">typename</span> point_t; where PointNDConcept<point_t>; <span class="comment">// N-dimensional point</span>
+ <span class="keyword">typename</span> locator; where RandomAccessNDLocatorConcept<locator>; <span class="comment">// N-dimensional locator.</span>
+ <span class="keyword">typename</span> iterator; where RandomAccessTraversalConcept<iterator>; <span class="comment">// 1-dimensional iterator over all values</span>
+ <span class="keyword">typename</span> reverse_iterator; where RandomAccessTraversalConcept<reverse_iterator>;
+ <span class="keyword">typename</span> size_type; <span class="comment">// the return value of size()</span>
+
+ <span class="comment">// Equivalent to RandomAccessNDLocatorConcept::axis</span>
+ <span class="keyword">template</span> <size_t D> <span class="keyword">struct </span>axis {
+ <span class="keyword">typename</span> coord_t = point_t::axis<D>::coord_t;
+ <span class="keyword">typename</span> iterator; where RandomAccessTraversalConcept<iterator>; <span class="comment">// iterator along D-th axis.</span>
+ where SameType<coord_t, iterator::difference_type>;
+ where SameType<iterator::value_type,value_type>;
+ };
+
+ <span class="comment">// Defines the type of a view similar to this type, except it invokes Deref upon dereferencing</span>
+ <span class="keyword">template</span> <PixelDereferenceAdaptorConcept Deref> <span class="keyword">struct </span>add_deref {
+ <span class="keyword">typename</span> type; where RandomAccessNDImageViewConcept<type>;
+ <span class="keyword">static</span> type make(<span class="keyword">const</span> View& v, <span class="keyword">const</span> Deref& deref);
+ };
+
+ <span class="keyword">static</span> <span class="keyword">const</span> size_t num_dimensions = point_t::num_dimensions;
+
+ <span class="comment">// Create from a locator at the top-left corner and dimensions</span>
+ View::View(<span class="keyword">const</span> locator&, <span class="keyword">const</span> point_type&);
+
+ size_type View::size() <span class="keyword">const</span>; <span class="comment">// total number of elements</span>
+ reference operator[](View, <span class="keyword">const</span> difference_type&) <span class="keyword">const</span>; <span class="comment">// 1-dimensional reference</span>
+ iterator View::begin() <span class="keyword">const</span>;
+ iterator View::end() <span class="keyword">const</span>;
+ reverse_iterator View::rbegin() <span class="keyword">const</span>;
+ reverse_iterator View::rend() <span class="keyword">const</span>;
+ iterator View::at(<span class="keyword">const</span> point_t&);
+ point_t View::dimensions() <span class="keyword">const</span>; <span class="comment">// number of elements along each dimension</span>
+ <span class="keywordtype">bool</span> View::is_1d_traversable() <span class="keyword">const</span>; <span class="comment">// Does an iterator over the first dimension visit each value?</span>
+
+ <span class="comment">// iterator along a given dimension starting at a given point</span>
+ <span class="keyword">template</span> <size_t D> View::axis<D>::iterator View::axis_iterator(<span class="keyword">const</span> point_t&) <span class="keyword">const</span>;
+
+ reference operator()(View,<span class="keyword">const</span> point_t&) <span class="keyword">const</span>;
+};
+
+concept MutableRandomAccessNDImageViewConcept<RandomAccessNDImageViewConcept View> {
+ where Mutable<reference>;
+};
+</pre></div><p>
+Two-dimensional image views have the following extra requirements:<p>
+<div class="fragment"><pre class="fragment">concept RandomAccess2DImageViewConcept<RandomAccessNDImageViewConcept View> {
+ where num_dimensions==2;
+
+ <span class="keyword">typename</span> x_iterator = axis<0>::iterator;
+ <span class="keyword">typename</span> y_iterator = axis<1>::iterator;
+ <span class="keyword">typename</span> x_coord_t = axis<0>::coord_t;
+ <span class="keyword">typename</span> y_coord_t = axis<1>::coord_t;
+ <span class="keyword">typename</span> xy_locator = locator;
+
+ x_coord_t View::width() <span class="keyword">const</span>;
+ y_coord_t View::height() <span class="keyword">const</span>;
+
+ <span class="comment">// X-navigation</span>
+ x_iterator View::x_at(<span class="keyword">const</span> point_t&) <span class="keyword">const</span>;
+ x_iterator View::row_begin(y_coord_t) <span class="keyword">const</span>;
+ x_iterator View::row_end (y_coord_t) <span class="keyword">const</span>;
+
+ <span class="comment">// Y-navigation</span>
+ y_iterator View::y_at(<span class="keyword">const</span> point_t&) <span class="keyword">const</span>;
+ y_iterator View::col_begin(x_coord_t) <span class="keyword">const</span>;
+ y_iterator View::col_end (x_coord_t) <span class="keyword">const</span>;
+
+ <span class="comment">// navigating in 2D</span>
+ xy_locator View::xy_at(<span class="keyword">const</span> point_t&) <span class="keyword">const</span>;
+
+ <span class="comment">// (x,y) versions of all methods taking point_t </span>
+ View::View(x_coord_t,y_coord_t,<span class="keyword">const</span> locator&);
+ iterator View::at(x_coord_t,y_coord_t) <span class="keyword">const</span>;
+ reference operator()(View,x_coord_t,y_coord_t) <span class="keyword">const</span>;
+ xy_locator View::xy_at(x_coord_t,y_coord_t) <span class="keyword">const</span>;
+ x_iterator View::x_at(x_coord_t,y_coord_t) <span class="keyword">const</span>;
+ y_iterator View::y_at(x_coord_t,y_coord_t) <span class="keyword">const</span>;
+};
+
+concept MutableRandomAccess2DImageViewConcept<RandomAccess2DImageViewConcept View>
+ : MutableRandomAccessNDImageViewConcept<View> {};
+</pre></div><p>
+Image views that GIL typically uses operate on value types that model <code>PixelValueConcept</code> and have some additional requirements:<p>
+<div class="fragment"><pre class="fragment">concept ImageViewConcept<RandomAccess2DImageViewConcept View> {
+ where PixelValueConcept<value_type>;
+ where PixelIteratorConcept<x_iterator>;
+ where PixelIteratorConcept<y_iterator>;
+ where x_coord_t == y_coord_t;
+
+ <span class="keyword">typename</span> coord_t = x_coord_t;
+
+ std::size_t View::num_channels() <span class="keyword">const</span>;
+};
+
+
+concept MutableImageViewConcept<ImageViewConcept View> : MutableRandomAccess2DImageViewConcept<View> {};
+</pre></div><p>
+Two image views are compatible if they have compatible pixels and the same number of dimensions: <div class="fragment"><pre class="fragment">concept ViewsCompatibleConcept<ImageViewConcept V1, ImageViewConcept V2> {
+ where PixelsCompatibleConcept<V1::value_type, V2::value_type>;
+ where V1::num_dimensions == V2::num_dimensions;
+};
+</pre></div><p>
+Compatible views must also have the same dimensions (i.e. the same width and height). Many algorithms taking multiple views require that they be pairwise compatible.<p>
+<b>Related Concepts:</b><p>
+<ul>
+<li>RandomAccessNDImageViewConcept<View></li><li>MutableRandomAccessNDImageViewConcept<View></li><li>RandomAccess2DImageViewConcept<View></li><li>MutableRandomAccess2DImageViewConcept<View></li><li>ImageViewConcept<View></li><li>MutableImageViewConcept<View></li><li>ViewsCompatibleConcept<View1,View2></li></ul>
+<p>
+<b>Models:</b><p>
+GIL provides a model for <code>ImageViewConcept</code> called <code>image_view</code>. It is templated over a model of <code>PixelLocatorConcept</code>. (If instantiated with a model of <code>MutablePixelLocatorConcept</code>, it models <code>MutableImageViewConcept</code>). Synopsis:<p>
+<div class="fragment"><pre class="fragment"><span class="keyword">template</span> <<span class="keyword">typename</span> Locator> <span class="comment">// Models PixelLocatorConcept (could be MutablePixelLocatorConcept)</span>
+<span class="keyword">class </span>image_view {
+<span class="keyword">public</span>:
+ <span class="keyword">typedef</span> Locator xy_locator;
+ <span class="keyword">typedef</span> iterator_from_2d<Locator> iterator;
+ ...
+private:
+ xy_locator _pixels; <span class="comment">// 2D pixel locator at the top left corner of the image view range</span>
+ point_t _dimensions; <span class="comment">// width and height</span>
+};
+</pre></div><p>
+Image views are lightweight objects. A regular interleaved view is typically 16 bytes long - two integers for the width and height (inside dimensions) one for the number of bytes between adjacent rows (inside the locator) and one pointer to the beginning of the pixel block.<p>
+<b>Algorithms:</b><h3><a class="anchor" name="ImageViewFrowRawDG">
+Creating Views from Raw Pixels</a></h3>
+Standard image views can be constructed from raw data of any supported color space, bit depth, channel ordering or planar vs. interleaved structure. Interleaved views are constructed using <code>interleaved_view</code>, supplying the image dimensions, number of bytes per row, and a pointer to the first pixel:<p>
+<div class="fragment"><pre class="fragment"><span class="keyword">template</span> <<span class="keyword">typename</span> Iterator> <span class="comment">// Models pixel iterator (like rgb8_ptr_t or rgb8c_ptr_t)</span>
+image_view<...> <a class="code" href="http://opensource.adobe.com/gil/html/group___image_view_constructors.html#ga5">interleaved_view</a>(ptrdiff_t width, ptrdiff_t height, Iterator pixels, ptrdiff_t rowsize)
+</pre></div><p>
+Planar views are defined for every color space and take each plane separately. Here is the RGB one:<p>
+<div class="fragment"><pre class="fragment"><span class="keyword">template</span> <<span class="keyword">typename</span> IC> <span class="comment">// Models channel iterator (like bits8* or const bits8*)</span>
+image_view<...> <a class="code" href="http://opensource.adobe.com/gil/html/group___image_view_constructors.html#ga9">planar_rgb_view</a>(ptrdiff_t width, ptrdiff_t height,
+ IC r, IC g, IC b, ptrdiff_t rowsize);
+</pre></div><p>
+Note that the supplied pixel/channel iterators could be constant (read-only), in which case the returned view is a constant-value (immutable) view.<h3><a class="anchor" name="ImageViewFrowImageViewDG">
+Creating Image Views from Other Image Views</a></h3>
+It is possible to construct one image view from another by changing some policy of how image data is interpreted. The result could be a view whose type is derived from the type of the source. GIL uses the following metafunctions to get the derived types:<p>
+<div class="fragment"><pre class="fragment"><span class="comment">// Some result view types</span>
+<span class="keyword">template</span> <<span class="keyword">typename</span> View>
+<span class="keyword">struct </span>dynamic_xy_step_type : <span class="keyword">public</span> dynamic_y_step_type<typename dynamic_x_step_type<View>::type> {};
+
+<span class="keyword">template</span> <<span class="keyword">typename</span> View>
+<span class="keyword">struct </span>dynamic_xy_step_transposed_type : <span class="keyword">public</span> dynamic_xy_step_type<typename transposed_type<View>::type> {};
+
+<span class="comment">// color and bit depth converted view to match pixel type P</span>
+<span class="keyword">template</span> <<span class="keyword">typename</span> SrcView, <span class="comment">// Models ImageViewConcept</span>
+ <span class="keyword">typename</span> DstP, <span class="comment">// Models PixelConcept</span>
+ <span class="keyword">typename</span> ColorConverter=gil::default_color_converter>
+<span class="keyword">struct </span>color_converted_view_type {
+ <span class="keyword">typedef</span> ... type; <span class="comment">// image view adaptor with value type DstP, over SrcView</span>
+};
+
+<span class="comment">// single-channel view of the N-th channel of a given view</span>
+<span class="keyword">template</span> <<span class="keyword">typename</span> SrcView>
+<span class="keyword">struct </span>nth_channel_view_type {
+ <span class="keyword">typedef</span> ... type;
+};
+</pre></div><p>
+GIL Provides the following view transformations:<p>
+<div class="fragment"><pre class="fragment"><span class="comment">// flipped upside-down, left-to-right, transposed view</span>
+<span class="keyword">template</span> <<span class="keyword">typename</span> View> <span class="keyword">typename</span> dynamic_y_step_type<View>::type flipped_up_down_view(<span class="keyword">const</span> View& src);
+<span class="keyword">template</span> <<span class="keyword">typename</span> View> <span class="keyword">typename</span> dynamic_x_step_type<View>::type flipped_left_right_view(<span class="keyword">const</span> View& src);
+<span class="keyword">template</span> <<span class="keyword">typename</span> View> <span class="keyword">typename</span> dynamic_xy_step_transposed_type<View>::type transposed_view(<span class="keyword">const</span> View& src);
+
+<span class="comment">// rotations</span>
+<span class="keyword">template</span> <<span class="keyword">typename</span> View> <span class="keyword">typename</span> dynamic_xy_step_type<View>::type rotated180_view(<span class="keyword">const</span> View& src);
+<span class="keyword">template</span> <<span class="keyword">typename</span> View> <span class="keyword">typename</span> dynamic_xy_step_transposed_type<View>::type rotated90cw_view(<span class="keyword">const</span> View& src);
+<span class="keyword">template</span> <<span class="keyword">typename</span> View> <span class="keyword">typename</span> dynamic_xy_step_transposed_type<View>::type rotated90ccw_view(<span class="keyword">const</span> View& src);
+
+<span class="comment">// view of an axis-aligned rectangular area within an image</span>
+<span class="keyword">template</span> <<span class="keyword">typename</span> View> View subimage_view(<span class="keyword">const</span> View& src,
+ <span class="keyword">const</span> View::point_t& top_left, <span class="keyword">const</span> View::point_t& dimensions);
+
+<span class="comment">// subsampled view (skipping pixels in X and Y)</span>
+<span class="keyword">template</span> <<span class="keyword">typename</span> View> <span class="keyword">typename</span> dynamic_xy_step_type<View>::type subsampled_view(<span class="keyword">const</span> View& src,
+ <span class="keyword">const</span> View::point_t& step);
+
+<span class="keyword">template</span> <<span class="keyword">typename</span> View, <span class="keyword">typename</span> P>
+color_converted_view_type<View,P>::type <a class="code" href="http://opensource.adobe.com/gil/html/group___image_view_transformations_color_convert.html#ga0">color_converted_view</a>(<span class="keyword">const</span> View& src);
+<span class="keyword">template</span> <<span class="keyword">typename</span> View, <span class="keyword">typename</span> P, <span class="keyword">typename</span> CCV> <span class="comment">// with a custom color converter</span>
+color_converted_view_type<View,P,CCV>::type <a class="code" href="http://opensource.adobe.com/gil/html/group___image_view_transformations_color_convert.html#ga0">color_converted_view</a>(<span class="keyword">const</span> View& src);
+
+<span class="keyword">template</span> <<span class="keyword">typename</span> View>
+nth_channel_view_type<View>::view_t nth_channel_view(<span class="keyword">const</span> View& <a class="code" href="http://opensource.adobe.com/gil/html/group___image_model.html#ga0">view</a>, <span class="keywordtype">int</span> n);
+</pre></div><p>
+The implementations of most of these view factory methods are straightforward. Here is, for example, how the flip views are implemented. The flip upside-down view creates a view whose first pixel is the bottom left pixel of the original view and whose y-step is the negated step of the source.<p>
+<div class="fragment"><pre class="fragment"><span class="keyword">template</span> <<span class="keyword">typename</span> View>
+<span class="keyword">typename</span> dynamic_y_step_type<View>::type flipped_up_down_view(<span class="keyword">const</span> View& src) {
+ gil_function_requires<ImageViewConcept<View> >();
+ <span class="keyword">typedef</span> <span class="keyword">typename</span> dynamic_y_step_type<View>::type RView;
+ <span class="keywordflow">return</span> RView(src.dimensions(),<span class="keyword">typename</span> RView::xy_locator(src.xy_at(0,src.height()-1),-1));
+}
+</pre></div><p>
+The call to <code>gil_function_requires</code> ensures (at compile time) that the template parameter is a valid model of <code>ImageViewConcept</code>. Using it generates easier to track compile errors, creates no extra code and has no run-time performance impact. We are using the <code>boost::concept_check</code> library, but wrapping it in <code>gil_function_requires</code>, which performs the check if the <code>BOOST_GIL_USE_CONCEPT_CHECK</code> is set. It is unset by default, because there is a significant increase in compile time when using concept checks. We will skip <code>gil_function_requires</code> in the code examples in this guide for the sake of succinctness.<p>
+Image views can be freely composed (see section <a class="el" href="gildesignguide.html#MetafunctionsDG">12. Useful Metafunctions and Typedefs</a> for the typedefs <code>rgb16_image_t</code> and <code>gray16_step_view_t</code>):<p>
+<div class="fragment"><pre class="fragment">rgb16_image_t img(100,100); <span class="comment">// an RGB interleaved image</span>
+
+<span class="comment">// grayscale view over the green (index 1) channel of img</span>
+gray16_step_view_t green=nth_channel_view(<a class="code" href="http://opensource.adobe.com/gil/html/group___image_model.html#ga0">view</a>(img),1);
+
+<span class="comment">// 50x50 view of the green channel of img, upside down and taking every other pixel in X and in Y</span>
+gray16_step_view_t ud_fud=flipped_up_down_view(subsampled_view(green,2,2));
+</pre></div><p>
+As previously stated, image views are fast, constant-time, shallow views over the pixel data. The above code does not copy any pixels; it operates on the pixel data allocated when <code>img</code> was created.<h3><a class="anchor" name="ImageViewAlgorithmsDG">
+STL-Style Algorithms on Image Views</a></h3>
+Image views provide 1D iteration of their pixels via begin() and end() methods, which makes it possible to use STL algorithms with them. However, using nested loops over X and Y is in many cases more efficient. The algorithms in this section resemble STL algorithms, but they abstract away the nested loops and take views (as opposed to ranges) as input.<p>
+<div class="fragment"><pre class="fragment"><span class="comment">// Equivalents of std::copy and std::uninitialized_copy</span>
+<span class="comment">// where ImageViewConcept<V1>, MutableImageViewConcept<V2>, ViewsCompatibleConcept<V1,V2></span>
+<span class="keyword">template</span> <<span class="keyword">typename</span> V1, <span class="keyword">typename</span> V2>
+<span class="keywordtype">void</span> <a class="code" href="http://opensource.adobe.com/gil/html/group___image_view_s_t_l_algorithms_copy_pixels.html#ga0">copy_pixels</a>(<span class="keyword">const</span> V1& src, <span class="keyword">const</span> V2& dst);
+<span class="keyword">template</span> <<span class="keyword">typename</span> V1, <span class="keyword">typename</span> V2>
+<span class="keywordtype">void</span> <a class="code" href="http://opensource.adobe.com/gil/html/group___image_view_s_t_l_algorithms_uninitialized_copy_pixels.html#ga0">uninitialized_copy_pixels</a>(<span class="keyword">const</span> V1& src, <span class="keyword">const</span> V2& dst);
+
+<span class="comment">// Equivalents of std::fill and std::uninitialized_fill</span>
+<span class="comment">// where MutableImageViewConcept<V>, PixelConcept<Value>, PixelsCompatibleConcept<Value,V::value_type></span>
+<span class="keyword">template</span> <<span class="keyword">typename</span> V, <span class="keyword">typename</span> Value>
+<span class="keywordtype">void</span> <a class="code" href="http://opensource.adobe.com/gil/html/group___image_view_s_t_l_algorithms_fill_pixels.html#ga0">fill_pixels</a>(<span class="keyword">const</span> V& dst, <span class="keyword">const</span> Value& val);
+<span class="keyword">template</span> <<span class="keyword">typename</span> V, <span class="keyword">typename</span> Value>
+<span class="keywordtype">void</span> <a class="code" href="http://opensource.adobe.com/gil/html/group___image_view_s_t_l_algorithms_uninitialized_fill_pixels.html#ga0">uninitialized_fill_pixels</a>(<span class="keyword">const</span> V& dst, <span class="keyword">const</span> Value& val);
+
+<span class="comment">// Equivalent of std::for_each</span>
+<span class="comment">// where ImageViewConcept<V>, boost::UnaryFunctionConcept<F></span>
+<span class="comment">// where PixelsCompatibleConcept<V::reference, F::argument_type></span>
+<span class="keyword">template</span> <<span class="keyword">typename</span> V, <span class="keyword">typename</span> F>
+F for_each_pixel(<span class="keyword">const</span> V& <a class="code" href="http://opensource.adobe.com/gil/html/group___image_model.html#ga0">view</a>, F fun);
+<span class="keyword">template</span> <<span class="keyword">typename</span> V, <span class="keyword">typename</span> F>
+F for_each_pixel_position(<span class="keyword">const</span> V& <a class="code" href="http://opensource.adobe.com/gil/html/group___image_model.html#ga0">view</a>, F fun);
+
+<span class="comment">// Equivalent of std::generate</span>
+<span class="comment">// where MutableImageViewConcept<V>, boost::UnaryFunctionConcept<F></span>
+<span class="comment">// where PixelsCompatibleConcept<V::reference, F::argument_type></span>
+<span class="keyword">template</span> <<span class="keyword">typename</span> V, <span class="keyword">typename</span> F>
+<span class="keywordtype">void</span> <a class="code" href="http://opensource.adobe.com/gil/html/group___image_view_s_t_l_algorithms_generate_pixels.html#ga0">generate_pixels</a>(<span class="keyword">const</span> V& dst, F fun);
+
+<span class="comment">// Equivalent of std::transform with one source</span>
+<span class="comment">// where ImageViewConcept<V1>, MutableImageViewConcept<V2></span>
+<span class="comment">// where boost::UnaryFunctionConcept<F></span>
+<span class="comment">// where PixelsCompatibleConcept<V1::const_reference, F::argument_type></span>
+<span class="comment">// where PixelsCompatibleConcept<F::result_type, V2::reference></span>
+<span class="keyword">template</span> <<span class="keyword">typename</span> V1, <span class="keyword">typename</span> V2, <span class="keyword">typename</span> F>
+F <a class="code" href="http://opensource.adobe.com/gil/html/group___image_view_s_t_l_algorithms_transform_pixels.html#ga0">transform_pixels</a>(<span class="keyword">const</span> V1& src, <span class="keyword">const</span> V2& dst, F fun);
+<span class="keyword">template</span> <<span class="keyword">typename</span> V1, <span class="keyword">typename</span> V2, <span class="keyword">typename</span> F>
+F <a class="code" href="http://opensource.adobe.com/gil/html/group___image_view_s_t_l_algorithms_transform_pixel_positions.html#ga0">transform_pixel_positions</a>(<span class="keyword">const</span> V1& src, <span class="keyword">const</span> V2& dst, F fun);
+
+<span class="comment">// Equivalent of std::transform with two sources</span>
+<span class="comment">// where ImageViewConcept<V1>, ImageViewConcept<V2>, MutableImageViewConcept<V3></span>
+<span class="comment">// where boost::BinaryFunctionConcept<F></span>
+<span class="comment">// where PixelsCompatibleConcept<V1::const_reference, F::first_argument_type></span>
+<span class="comment">// where PixelsCompatibleConcept<V2::const_reference, F::second_argument_type></span>
+<span class="comment">// where PixelsCompatibleConcept<F::result_type, V3::reference></span>
+<span class="keyword">template</span> <<span class="keyword">typename</span> V1, <span class="keyword">typename</span> V2, <span class="keyword">typename</span> V3, <span class="keyword">typename</span> F>
+F <a class="code" href="http://opensource.adobe.com/gil/html/group___image_view_s_t_l_algorithms_transform_pixels.html#ga0">transform_pixels</a>(<span class="keyword">const</span> V1& src1, <span class="keyword">const</span> V2& src2, <span class="keyword">const</span> V3& dst, F fun);
+<span class="keyword">template</span> <<span class="keyword">typename</span> V1, <span class="keyword">typename</span> V2, <span class="keyword">typename</span> V3, <span class="keyword">typename</span> F>
+F <a class="code" href="http://opensource.adobe.com/gil/html/group___image_view_s_t_l_algorithms_transform_pixel_positions.html#ga0">transform_pixel_positions</a>(<span class="keyword">const</span> V1& src1, <span class="keyword">const</span> V2& src2, <span class="keyword">const</span> V3& dst, F fun);
+
+<span class="comment">// Copies a view into another, color converting the pixels if needed, with the default or user-defined color converter</span>
+<span class="comment">// where ImageViewConcept<V1>, MutableImageViewConcept<V2></span>
+<span class="comment">// V1::value_type must be convertible to V2::value_type.</span>
+<span class="keyword">template</span> <<span class="keyword">typename</span> V1, <span class="keyword">typename</span> V2>
+<span class="keywordtype">void</span> copy_and_convert_pixels(<span class="keyword">const</span> V1& src, <span class="keyword">const</span> V2& dst);
+<span class="keyword">template</span> <<span class="keyword">typename</span> V1, <span class="keyword">typename</span> V2, <span class="keyword">typename</span> ColorConverter>
+<span class="keywordtype">void</span> copy_and_convert_pixels(<span class="keyword">const</span> V1& src, <span class="keyword">const</span> V2& dst, ColorConverter ccv);
+
+<span class="comment">// Equivalent of std::equal</span>
+<span class="comment">// where ImageViewConcept<V1>, ImageViewConcept<V2>, ViewsCompatibleConcept<V1,V2></span>
+<span class="keyword">template</span> <<span class="keyword">typename</span> V1, <span class="keyword">typename</span> V2>
+<span class="keywordtype">bool</span> <a class="code" href="http://opensource.adobe.com/gil/html/group___image_view_s_t_l_algorithms_equal_pixels.html#ga0">equal_pixels</a>(<span class="keyword">const</span> V1& view1, <span class="keyword">const</span> V2& view2);
+</pre></div><p>
+Algorithms that take multiple views require that they have the same dimensions. <code>for_each_pixel_position</code> and <code>transform_pixel_positions</code> pass pixel locators, as opposed to pixel references, to their function objects. This allows for writing algorithms that use pixel neighbors, as the tutorial demonstrates.<p>
+Most of these algorithms check whether the image views are 1D-traversable. A 1D-traversable image view has no gaps at the end of the rows. In other words, if an x_iterator of that view is advanced past the last pixel in a row it will move to the first pixel of the next row. When image views are 1D-traversable, the algorithms use a single loop and run more efficiently. If one or more of the input views are not 1D-traversable, the algorithms fall-back to an X-loop nested inside a Y-loop.<p>
+The algorithms typically delegate the work to their corresponding STL algorithms. For example, <code>copy_pixels</code> calls <code><a class="el" href="http://opensource.adobe.com/gil/html/group___s_t_l_optimizations.html#ga2">std::copy</a></code> either for each row, or, when the images are 1D-traversable, once for all pixels.<p>
+In addition, overloads are sometimes provided for the STL algorithms. For example, <code><a class="el" href="http://opensource.adobe.com/gil/html/group___s_t_l_optimizations.html#ga2">std::copy</a></code> for planar iterators is overloaded to perform <code><a class="el" href="http://opensource.adobe.com/gil/html/group___s_t_l_optimizations.html#ga2">std::copy</a></code> for each of the planes. <code><a class="el" href="http://opensource.adobe.com/gil/html/group___s_t_l_optimizations.html#ga2">std::copy</a></code> over bitwise-copiable pixels results in <code><a class="el" href="http://opensource.adobe.com/gil/html/group___s_t_l_optimizations.html#ga2">std::copy</a></code> over unsigned char, which STL typically implements via <code>memmove</code>.<p>
+As a result <code>copy_pixels</code> may result in a single call to <code>memmove</code> for interleaved 1D-traversable views, or one per each plane of planar 1D-traversable views, or one per each row of interleaved non-1D-traversable images, etc.<p>
+GIL also provides some beta-versions of image processing algorithms, such as resampling and convolution in a numerics extension available on http://opensource.adobe.com/gil/download.html. This code is in early stage of development and is not optimized for speed<p>
+<hr>
+ <h2><a class="anchor" name="ImageSectionDG">
+10. Image</a></h2>
+An image is a container that owns the pixels of a given image view. It allocates them in its constructor and deletes them in the destructor. It has a deep assignment operator and copy constructor. Images are used rarely, just when data ownership is important. Most STL algorithms operate on ranges, not containers. Similarly most GIL algorithms operate on image views (which images provide).<p>
+In the most general form images are N-dimensional and satisfy the following concept:<p>
+<div class="fragment"><pre class="fragment">concept RandomAccessNDImageConcept<typename Img> : Regular<Img> {
+ <span class="keyword">typename</span> view_t; where MutableRandomAccessNDImageViewConcept<view_t>;
+ <span class="keyword">typename</span> const_view_t = view_t::const_t;
+ <span class="keyword">typename</span> point_t = view_t::point_t;
+ <span class="keyword">typename</span> value_type = view_t::value_type;
+ <span class="keyword">typename</span> allocator_type;
+
+ Img::Img(point_t dims, std::size_t alignment=1);
+ Img::Img(point_t dims, value_type fill_value, std::size_t alignment);
+
+ <span class="keywordtype">void</span> Img::recreate(point_t new_dims, std::size_t alignment=1);
+ <span class="keywordtype">void</span> Img::recreate(point_t new_dims, value_type fill_value, std::size_t alignment);
+
+ <span class="keyword">const</span> point_t& Img::dimensions() <span class="keyword">const</span>;
+ <span class="keyword">const</span> const_view_t& <a class="code" href="http://opensource.adobe.com/gil/html/group___image_model.html#ga3">const_view</a>(<span class="keyword">const</span> Img&);
+ <span class="keyword">const</span> view_t& <a class="code" href="http://opensource.adobe.com/gil/html/group___image_model.html#ga0">view</a>(Img&);
+};
+</pre></div><p>
+Two-dimensional images have additional requirements:<p>
+<div class="fragment"><pre class="fragment">concept RandomAccess2DImageConcept<RandomAccessNDImageConcept Img> {
+ <span class="keyword">typename</span> x_coord_t = const_view_t::x_coord_t;
+ <span class="keyword">typename</span> y_coord_t = const_view_t::y_coord_t;
+
+ Img::Img(x_coord_t width, y_coord_t height, std::size_t alignment=1);
+ Img::Img(x_coord_t width, y_coord_t height, value_type fill_value, std::size_t alignment);
+
+ x_coord_t Img::width() <span class="keyword">const</span>;
+ y_coord_t Img::height() <span class="keyword">const</span>;
+
+ <span class="keywordtype">void</span> Img::recreate(x_coord_t width, y_coord_t height, std::size_t alignment=1);
+ <span class="keywordtype">void</span> Img::recreate(x_coord_t width, y_coord_t height, value_type fill_value, std::size_t alignment);
+};
+</pre></div><p>
+GIL's images have views that model <code>ImageViewConcept</code> and operate on pixels.<p>
+<div class="fragment"><pre class="fragment">concept ImageConcept<RandomAccess2DImageConcept Img> {
+ where MutableImageViewConcept<view_t>;
+ <span class="keyword">typename</span> coord_t = view_t::coord_t;
+};
+</pre></div><p>
+Images, unlike locators and image views, don't have 'mutable' set of concepts because immutable images are not very useful.<p>
+<b>Related Concepts:</b><p>
+<ul>
+<li>RandomAccessNDImageConcept<Image></li><li>RandomAccess2DImageConcept<Image></li><li>ImageConcept<Image></li></ul>
+<p>
+<b>Models:</b><p>
+GIL provides a class, <code>image</code>, which is templated over the value type (the pixel) and models <code>ImageConcept</code>.<p>
+<div class="fragment"><pre class="fragment"><span class="keyword">template</span> <<span class="keyword">typename</span> Pixel, \\ Models PixelValueConcept
+ <span class="keywordtype">bool</span> IsPlanar, \\ planar or interleaved image
+ <span class="keyword">typename</span> A=std::allocator<unsigned char> >
+<span class="keyword">class </span>image;
+</pre></div><p>
+By default images have 1 memory unit (no) alignment - i.e. there is no padding at the end of rows. Many operations are faster using such 1D-traversable images <code>image_view::x_iterator</code> can be used to traverse the pixels, instead of the more complicated <code>image_view::iterator</code>. The image constructor takes an alignment parameter which allows for constructing images that are word-aligned or 8-byte aligned. Beware that the alignment parameter is in memory units, which is usually but not always bytes. Specifically, for bit-aligned images the memory unit is a bit.<p>
+<hr>
+ <h2><a class="anchor" name="VariantSecDG">
+11. Run-time specified images and image views</a></h2>
+The color space, channel depth, channel ordering, and interleaved/planar structure of an image are defined by the type of its template argument, which makes them compile-time bound. Often some of these parameters are available only at run time. Consider, for example, writing a module that opens the image at a given file path, rotates it and saves it back in its original color space and channel depth. How can we possibly write this using our generic image? What type is the image loading code supposed to return?<p>
+GIL's dynamic_image extension allows for images, image views or any GIL constructs to have their parameters defined at run time. Here is an example: <div class="fragment"><pre class="fragment"><span class="preprocessor">#include <<a class="code" href="dynamic__image__all_8hpp.html">boost/gil/extension/dynamic_image/dynamic_image_all.hpp</a>></span>
+<span class="keyword">using</span> <span class="keyword">namespace </span>boost;
+
+<span class="preprocessor">#define ASSERT_SAME(A,B) BOOST_STATIC_ASSERT((is_same< A,B >::value))</span>
+<span class="preprocessor"></span>
+<span class="comment">// Define the set of allowed images</span>
+<span class="keyword">typedef</span> mpl::vector<rgb8_image_t, cmyk16_planar_image_t> my_images_t;
+
+<span class="comment">// Create any_image class (or any_image_view) class</span>
+<span class="keyword">typedef</span> any_image<my_images_t> my_any_image_t;
+
+<span class="comment">// Associated view types are available (equivalent to the ones in image_t)</span>
+<span class="keyword">typedef</span> any_image_view<mpl::vector2<rgb8_view_t, cmyk16_planar_view_t > > AV;
+ASSERT_SAME(my_any_image_t::view_t, AV);
+
+<span class="keyword">typedef</span> any_image_view<mpl::vector2<rgb8c_view_t, cmyk16c_planar_view_t> > CAV;
+ASSERT_SAME(my_any_image_t::const_view_t, CAV);
+ASSERT_SAME(my_any_image_t::const_view_t, my_any_image_t::view_t::const_t);
+
+<span class="keyword">typedef</span> any_image_view<mpl::vector2<rgb8_step_view_t, cmyk16_planar_step_view_t> > SAV;
+ASSERT_SAME(<span class="keyword">typename</span> dynamic_x_step_type<my_any_image_t::view_t>::type, SAV);
+
+<span class="comment">// Assign it a concrete image at run time:</span>
+my_any_image_t myImg = my_any_image_t(rgb8_image_t(100,100));
+
+<span class="comment">// Change it to another at run time. The previous image gets destroyed</span>
+myImg = cmyk16_planar_image_t(200,100);
+
+<span class="comment">// Assigning to an image not in the allowed set throws an exception</span>
+myImg = gray8_image_t(); <span class="comment">// will throw std::bad_cast</span>
+</pre></div><p>
+<code>any_image</code> and <code>any_image_view</code> subclass from GIL's <code>variant</code> class, which breaks down the instantiated type into a non-templated underlying base type and a unique instantiation type identifier. The underlying base instance is represented as a block of bytes. The block is large enough to hold the largest of the specified types.<p>
+GIL's variant is similar to <code>boost::variant</code> in spirit (hence we borrow the name from there) but it differs in several ways from the current boost implementation. Perhaps the biggest difference is that GIL's variant always takes a single argument, which is a model of MPL Random Access Sequence enumerating the allowed types. Having a single interface allows GIL's variant to be used easier in generic code. Synopsis:<p>
+<div class="fragment"><pre class="fragment"><span class="keyword">template</span> <<span class="keyword">typename</span> Types> <span class="comment">// models MPL Random Access Container</span>
+<span class="keyword">class </span>variant {
+ ... _bits;
+ std::size_t _index;
+<span class="keyword">public</span>:
+ <span class="keyword">typedef</span> Types types_t;
+
+ variant();
+ variant(<span class="keyword">const</span> variant& v);
+ <span class="keyword">virtual</span> ~variant();
+
+ variant& operator=(<span class="keyword">const</span> variant& v);
+ <span class="keyword">template</span> <<span class="keyword">typename</span> TS> <span class="keyword">friend</span> <span class="keywordtype">bool</span> operator==(<span class="keyword">const</span> variant<TS>& x, <span class="keyword">const</span> variant<TS>& y);
+ <span class="keyword">template</span> <<span class="keyword">typename</span> TS> <span class="keyword">friend</span> <span class="keywordtype">bool</span> operator!=(<span class="keyword">const</span> variant<TS>& x, <span class="keyword">const</span> variant<TS>& y);
+
+ <span class="comment">// Construct/assign to type T. Throws std::bad_cast if T is not in Types</span>
+ <span class="keyword">template</span> <<span class="keyword">typename</span> T> <span class="keyword">explicit</span> variant(<span class="keyword">const</span> T& obj);
+ <span class="keyword">template</span> <<span class="keyword">typename</span> T> variant& operator=(<span class="keyword">const</span> T& obj);
+
+ <span class="comment">// Construct/assign by swapping T with its current instance. Only possible if they are swappable</span>
+ <span class="keyword">template</span> <<span class="keyword">typename</span> T> <span class="keyword">explicit</span> variant(T& obj, <span class="keywordtype">bool</span> do_swap);
+ <span class="keyword">template</span> <<span class="keyword">typename</span> T> <span class="keywordtype">void</span> move_in(T& obj);
+
+ <span class="keyword">template</span> <<span class="keyword">typename</span> T> <span class="keyword">static</span> <span class="keywordtype">bool</span> has_type();
+
+ <span class="keyword">template</span> <<span class="keyword">typename</span> T> <span class="keyword">const</span> T& _dynamic_cast() <span class="keyword">const</span>;
+ <span class="keyword">template</span> <<span class="keyword">typename</span> T> T& _dynamic_cast();
+
+ <span class="keyword">template</span> <<span class="keyword">typename</span> T> <span class="keywordtype">bool</span> current_type_is() <span class="keyword">const</span>;
+};
+
+<span class="keyword">template</span> <<span class="keyword">typename</span> UOP, <span class="keyword">typename</span> Types>
+ UOP::result_type <a class="code" href="http://opensource.adobe.com/gil/html/group___variant.html#ga0">apply_operation</a>(variant<Types>& v, UOP op);
+<span class="keyword">template</span> <<span class="keyword">typename</span> UOP, <span class="keyword">typename</span> Types>
+ UOP::result_type <a class="code" href="http://opensource.adobe.com/gil/html/group___variant.html#ga0">apply_operation</a>(<span class="keyword">const</span> variant<Types>& v, UOP op);
+
+<span class="keyword">template</span> <<span class="keyword">typename</span> BOP, <span class="keyword">typename</span> Types1, <span class="keyword">typename</span> Types2>
+ BOP::result_type <a class="code" href="http://opensource.adobe.com/gil/html/group___variant.html#ga0">apply_operation</a>( variant<Types1>& v1, variant<Types2>& v2, UOP op);
+
+<span class="keyword">template</span> <<span class="keyword">typename</span> BOP, <span class="keyword">typename</span> Types1, <span class="keyword">typename</span> Types2>
+ BOP::result_type <a class="code" href="http://opensource.adobe.com/gil/html/group___variant.html#ga0">apply_operation</a>(<span class="keyword">const</span> variant<Types1>& v1, variant<Types2>& v2, UOP op);
+
+<span class="keyword">template</span> <<span class="keyword">typename</span> BOP, <span class="keyword">typename</span> Types1, <span class="keyword">typename</span> Types2>
+ BOP::result_type <a class="code" href="http://opensource.adobe.com/gil/html/group___variant.html#ga0">apply_operation</a>(<span class="keyword">const</span> variant<Types1>& v1, <span class="keyword">const</span> variant<Types2>& v2, UOP op);
+</pre></div><p>
+GIL's <code>any_image_view</code> and <code>any_image</code> are subclasses of <code>variant:</code> <p>
+<div class="fragment"><pre class="fragment"><span class="keyword">template</span> <<span class="keyword">typename</span> ImageViewTypes>
+<span class="keyword">class </span>any_image_view : <span class="keyword">public</span> variant<ImageViewTypes> {
+<span class="keyword">public</span>:
+ <span class="keyword">typedef</span> ... const_t; <span class="comment">// immutable equivalent of this</span>
+ <span class="keyword">typedef</span> std::ptrdiff_t x_coord_t;
+ <span class="keyword">typedef</span> std::ptrdiff_t y_coord_t;
+ <span class="keyword">typedef</span> point2<std::ptrdiff_t> point_t;
+
+ any_image_view();
+ <span class="keyword">template</span> <<span class="keyword">typename</span> T> <span class="keyword">explicit</span> any_image_view(<span class="keyword">const</span> T& obj);
+ any_image_view(<span class="keyword">const</span> any_image_view& v);
+
+ <span class="keyword">template</span> <<span class="keyword">typename</span> T> any_image_view& operator=(<span class="keyword">const</span> T& obj);
+ any_image_view& operator=(<span class="keyword">const</span> any_image_view& v);
+
+ <span class="comment">// parameters of the currently instantiated view</span>
+ std::size_t num_channels() <span class="keyword">const</span>;
+ point_t dimensions() <span class="keyword">const</span>;
+ x_coord_t width() <span class="keyword">const</span>;
+ y_coord_t height() <span class="keyword">const</span>;
+};
+
+<span class="keyword">template</span> <<span class="keyword">typename</span> ImageTypes>
+<span class="keyword">class </span>any_image : <span class="keyword">public</span> variant<ImageTypes> {
+ <span class="keyword">typedef</span> variant<ImageTypes> parent_t;
+<span class="keyword">public</span>:
+ <span class="keyword">typedef</span> ... const_view_t;
+ <span class="keyword">typedef</span> ... view_t;
+ <span class="keyword">typedef</span> std::ptrdiff_t x_coord_t;
+ <span class="keyword">typedef</span> std::ptrdiff_t y_coord_t;
+ <span class="keyword">typedef</span> point2<std::ptrdiff_t> point_t;
+
+ any_image();
+ <span class="keyword">template</span> <<span class="keyword">typename</span> T> <span class="keyword">explicit</span> any_image(<span class="keyword">const</span> T& obj);
+ <span class="keyword">template</span> <<span class="keyword">typename</span> T> <span class="keyword">explicit</span> any_image(T& obj, <span class="keywordtype">bool</span> do_swap);
+ any_image(<span class="keyword">const</span> any_image& v);
+
+ <span class="keyword">template</span> <<span class="keyword">typename</span> T> any_image& operator=(<span class="keyword">const</span> T& obj);
+ any_image& operator=(<span class="keyword">const</span> any_image& v);
+
+ <span class="keywordtype">void</span> recreate(<span class="keyword">const</span> point_t& dims, <span class="keywordtype">unsigned</span> alignment=1);
+ <span class="keywordtype">void</span> recreate(x_coord_t width, y_coord_t height, <span class="keywordtype">unsigned</span> alignment=1);
+
+ std::size_t num_channels() <span class="keyword">const</span>;
+ point_t dimensions() <span class="keyword">const</span>;
+ x_coord_t width() <span class="keyword">const</span>;
+ y_coord_t height() <span class="keyword">const</span>;
+};
+</pre></div><p>
+Operations are invoked on variants via <code>apply_operation</code> passing a function object to perform the operation. The code for every allowed type in the variant is instantiated and the appropriate instantiation is selected via a switch statement. Since image view algorithms typically have time complexity at least linear on the number of pixels, the single switch statement of image view variant adds practically no measurable performance overhead compared to templated image views.<p>
+Variants behave like the underlying type. Their copy constructor will invoke the copy constructor of the underlying instance. Equality operator will check if the two instances are of the same type and then invoke their operator==, etc. The default constructor of a variant will default-construct the first type. That means that <code>any_image_view</code> has shallow default-constructor, copy-constructor, assigment and equaty comparison, whereas <code>any_image</code> has deep ones.<p>
+It is important to note that even though <code>any_image_view</code> and <code>any_image</code> resemble the static <code>image_view</code> and <code>image</code>, they do not model the full requirements of <code>ImageViewConcept</code> and <code>ImageConcept</code>. In particular they don't provide access to the pixels. There is no "any_pixel" or "any_pixel_iterator" in GIL. Such constructs could be provided via the <code>variant</code> mechanism, but doing so would result in inefficient algorithms, since the type resolution would have to be performed per pixel. Image-level algorithms should be implemented via <code>apply_operation</code>. That said, many common operations are shared between the static and dynamic types. In addition, all of the image view transformations and many STL-like image view algorithms have overloads operating on <code>any_image_view</code>, as illustrated with <code>copy_pixels:</code> <p>
+<div class="fragment"><pre class="fragment">rgb8_view_t v1(...); <span class="comment">// concrete image view</span>
+bgr8_view_t v2(...); <span class="comment">// concrete image view compatible with v1 and of the same size</span>
+any_image_view<Types> av(...); <span class="comment">// run-time specified image view</span>
+
+<span class="comment">// Copies the pixels from v1 into v2. </span>
+<span class="comment">// If the pixels are incompatible triggers compile error </span>
+<a class="code" href="http://opensource.adobe.com/gil/html/group___image_view_s_t_l_algorithms_copy_pixels.html#ga0">copy_pixels</a>(v1,v2);
+
+<span class="comment">// The source or destination (or both) may be run-time instantiated.</span>
+<span class="comment">// If they happen to be incompatible, throws std::bad_cast</span>
+<a class="code" href="http://opensource.adobe.com/gil/html/group___image_view_s_t_l_algorithms_copy_pixels.html#ga0">copy_pixels</a>(v1, av);
+<a class="code" href="http://opensource.adobe.com/gil/html/group___image_view_s_t_l_algorithms_copy_pixels.html#ga0">copy_pixels</a>(av, v2);
+<a class="code" href="http://opensource.adobe.com/gil/html/group___image_view_s_t_l_algorithms_copy_pixels.html#ga0">copy_pixels</a>(av, av);
+</pre></div><p>
+By having algorithm overloads supporting dynamic constructs, we create a base upon which it is possible to write algorithms that can work with either compile-time or runtime images or views. The following code, for example, uses the GIL I/O extension to turn an image on disk upside down:<p>
+<div class="fragment"><pre class="fragment"><span class="preprocessor">#include <<a class="code" href="jpeg__dynamic__io_8hpp.html">boost\gil\extension\io\jpeg_dynamic_io.hpp</a>></span>
+
+<span class="keyword">template</span> <<span class="keyword">typename</span> Image> <span class="comment">// Could be rgb8_image_t or any_image<...></span>
+<span class="keywordtype">void</span> save_180rot(<span class="keyword">const</span> std::string& file_name) {
+ Image img;
+ <a class="code" href="http://opensource.adobe.com/gil/html/group___j_p_e_g___i_o.html#ga0">jpeg_read_image</a>(file_name, img);
+ <a class="code" href="http://opensource.adobe.com/gil/html/group___j_p_e_g___i_o.html#ga2">jpeg_write_view</a>(file_name, rotated180_view(<a class="code" href="http://opensource.adobe.com/gil/html/group___image_model.html#ga0">view</a>(img)));
+}
+</pre></div><p>
+It can be instantiated with either a compile-time or a runtime image because all functions it uses have overloads taking runtime constructs. For example, here is how <code>rotated180_view</code> is implemented:<p>
+<div class="fragment"><pre class="fragment"><span class="comment">// implementation using templated view</span>
+<span class="keyword">template</span> <<span class="keyword">typename</span> View>
+<span class="keyword">typename</span> dynamic_xy_step_type<View>::type rotated180_view(<span class="keyword">const</span> View& src) { ... }
+
+<span class="keyword">namespace </span>detail {
+ <span class="comment">// the function, wrapped inside a function object</span>
+ <span class="keyword">template</span> <<span class="keyword">typename</span> Result> <span class="keyword">struct </span>rotated180_view_fn {
+ <span class="keyword">typedef</span> Result result_type;
+ <span class="keyword">template</span> <<span class="keyword">typename</span> View> result_type operator()(<span class="keyword">const</span> View& src)<span class="keyword"> const </span>{
+ <span class="keywordflow">return</span> result_type(rotated180_view(src));
+ }
+ };
+}
+
+<span class="comment">// overloading of the function using variant. Takes and returns run-time bound view.</span>
+<span class="comment">// The returned view has a dynamic step</span>
+<span class="keyword">template</span> <<span class="keyword">typename</span> ViewTypes> <span class="keyword">inline</span> <span class="comment">// Models MPL Random Access Container of models of ImageViewConcept</span>
+<span class="keyword">typename</span> dynamic_xy_step_type<any_image_view<ViewTypes> >::type rotated180_view(<span class="keyword">const</span> any_image_view<ViewTypes>& src) {
+ <span class="keywordflow">return</span> <a class="code" href="http://opensource.adobe.com/gil/html/group___variant.html#ga0">apply_operation</a>(src,detail::rotated180_view_fn<<span class="keyword">typename</span> dynamic_xy_step_type<any_image_view<ViewTypes> >::type>());
+}
+</pre></div><p>
+Variants should be used with caution (especially algorithms that take more than one variant) because they instantiate the algorithm for every possible model that the variant can take. This can take a toll on compile time and executable size. Despite these limitations, <code>variant</code> is a powerful technique that allows us to combine the speed of compile-time resolution with the flexibility of run-time resolution. It allows us to treat images of different parameters uniformly as a collection and store them in the same container.<p>
+<hr>
+ <h2><a class="anchor" name="MetafunctionsDG">
+12. Useful Metafunctions and Typedefs</a></h2>
+Flexibility comes at a price. GIL types can be very long and hard to read. To address this problem, GIL provides typedefs to refer to any standard image, pixel iterator, pixel locator, pixel reference or pixel value. They follow this pattern: <p>
+<em>ColorSpace</em> + <em>BitDepth</em> + ["s|f"] + ["c"] + ["_planar"] + ["_step"] + <em>ClassType</em> + "_t" <p>
+Where <em>ColorSpace</em> also indicates the ordering of components. Examples are <code>rgb</code>, <code>bgr</code>, <code>cmyk</code>, <code>rgba</code>. <em>BitDepth</em> can be, for example, <code>8</code>,<code>16</code>,<code>32</code>. By default the bits are unsigned integral type. Append <code>s</code> to the bit depth to indicate signed integral, or <code>f</code> to indicate floating point. <code>c</code> indicates object whose associated pixel reference is immutable. <code>_planar</code> indicates planar organization (as opposed to interleaved). <code>_step</code> indicates the type has a dynamic step and <em>ClassType</em> is <code>_image</code> (image, using a standard allocator), <code>_view</code> (image view), <code>_loc</code> (pixel locator), <code>_ptr</code> (pixel iterator), <code>_ref</code> (pixel reference), <code>_pixel</code> (pixel value). Here are examples:<p>
+<div class="fragment"><pre class="fragment">bgr8_image_t i; <span class="comment">// 8-bit unsigned (unsigned char) interleaved BGR image</span>
+cmyk16_pixel_t; x; <span class="comment">// 16-bit unsigned (unsigned short) CMYK pixel value;</span>
+cmyk16sc_planar_ref_t p(x); <span class="comment">// const reference to a 16-bit signed integral (signed short) planar CMYK pixel x.</span>
+rgb32f_planar_step_ptr_t ii; <span class="comment">// step iterator to a floating point 32-bit (float) planar RGB pixel.</span>
+</pre></div><p>
+GIL provides the metafunctions that return the types of standard homogeneous memory-based GIL constructs given a channel type, a layout, and whether the construct is planar, has a step along the X direction, and is mutable:<p>
+<div class="fragment"><pre class="fragment"><span class="keyword">template</span> <<span class="keyword">typename</span> ChannelValue, <span class="keyword">typename</span> Layout, <span class="keywordtype">bool</span> IsPlanar=false, <span class="keywordtype">bool</span> IsMutable=true>
+<span class="keyword">struct </span>pixel_reference_type { <span class="keyword">typedef</span> ... type; };
+
+<span class="keyword">template</span> <<span class="keyword">typename</span> Channel, <span class="keyword">typename</span> Layout>
+<span class="keyword">struct </span>pixel_value_type { <span class="keyword">typedef</span> ... type; };
+
+<span class="keyword">template</span> <<span class="keyword">typename</span> ChannelValue, <span class="keyword">typename</span> Layout, <span class="keywordtype">bool</span> IsPlanar=false, <span class="keywordtype">bool</span> IsStep=false, <span class="keywordtype">bool</span> IsMutable=true>
+<span class="keyword">struct </span>iterator_type { <span class="keyword">typedef</span> ... type; };
+
+<span class="keyword">template</span> <<span class="keyword">typename</span> ChannelValue, <span class="keyword">typename</span> Layout, <span class="keywordtype">bool</span> IsPlanar=false, <span class="keywordtype">bool</span> IsXStep=false, <span class="keywordtype">bool</span> IsMutable=true>
+<span class="keyword">struct </span>locator_type { <span class="keyword">typedef</span> ... type; };
+
+<span class="keyword">template</span> <<span class="keyword">typename</span> ChannelValue, <span class="keyword">typename</span> Layout, <span class="keywordtype">bool</span> IsPlanar=false, <span class="keywordtype">bool</span> IsXStep=false, <span class="keywordtype">bool</span> IsMutable=true>
+<span class="keyword">struct </span>view_type { <span class="keyword">typedef</span> ... type; };
+
+<span class="keyword">template</span> <<span class="keyword">typename</span> ChannelValue, <span class="keyword">typename</span> Layout, <span class="keywordtype">bool</span> IsPlanar=false, <span class="keyword">typename</span> Alloc=std::allocator<<span class="keywordtype">unsigned</span> <span class="keywordtype">char</span>> >
+<span class="keyword">struct </span>image_type { <span class="keyword">typedef</span> ... type; };
+
+<span class="keyword">template</span> <<span class="keyword">typename</span> BitField, <span class="keyword">typename</span> ChannelBitSizeVector, <span class="keyword">typename</span> Layout, <span class="keyword">typename</span> Alloc=std::allocator<<span class="keywordtype">unsigned</span> <span class="keywordtype">char</span>> >
+<span class="keyword">struct </span>packed_image_type { <span class="keyword">typedef</span> ... type; };
+
+<span class="keyword">template</span> <<span class="keyword">typename</span> ChannelBitSizeVector, <span class="keyword">typename</span> Layout, <span class="keyword">typename</span> Alloc=std::allocator<<span class="keywordtype">unsigned</span> <span class="keywordtype">char</span>> >
+<span class="keyword">struct </span>bit_aligned_image_type { <span class="keyword">typedef</span> ... type; };
+</pre></div><p>
+There are also helper metafunctions to construct packed and bit-aligned images with up to five channels:<p>
+<div class="fragment"><pre class="fragment"><span class="keyword">template</span> <<span class="keyword">typename</span> BitField, <span class="keywordtype">unsigned</span> Size1,
+ <span class="keyword">typename</span> Layout, <span class="keyword">typename</span> Alloc=std::allocator<unsigned char> >
+<span class="keyword">struct </span>packed_image1_type { <span class="keyword">typedef</span> ... type; };
+
+<span class="keyword">template</span> <<span class="keyword">typename</span> BitField, <span class="keywordtype">unsigned</span> Size1, <span class="keywordtype">unsigned</span> Size2,
+ <span class="keyword">typename</span> Layout, <span class="keyword">typename</span> Alloc=std::allocator<unsigned char> >
+<span class="keyword">struct </span>packed_image2_type { <span class="keyword">typedef</span> ... type; };
+
+<span class="keyword">template</span> <<span class="keyword">typename</span> BitField, <span class="keywordtype">unsigned</span> Size1, <span class="keywordtype">unsigned</span> Size2, <span class="keywordtype">unsigned</span> Size3,
+ <span class="keyword">typename</span> Layout, <span class="keyword">typename</span> Alloc=std::allocator<unsigned char> >
+<span class="keyword">struct </span>packed_image3_type { <span class="keyword">typedef</span> ... type; };
+
+<span class="keyword">template</span> <<span class="keyword">typename</span> BitField, <span class="keywordtype">unsigned</span> Size1, <span class="keywordtype">unsigned</span> Size2, <span class="keywordtype">unsigned</span> Size3, <span class="keywordtype">unsigned</span> Size4,
+ <span class="keyword">typename</span> Layout, <span class="keyword">typename</span> Alloc=std::allocator<unsigned char> >
+<span class="keyword">struct </span>packed_image4_type { <span class="keyword">typedef</span> ... type; };
+
+<span class="keyword">template</span> <<span class="keyword">typename</span> BitField, <span class="keywordtype">unsigned</span> Size1, <span class="keywordtype">unsigned</span> Size2, <span class="keywordtype">unsigned</span> Size3, <span class="keywordtype">unsigned</span> Size4, <span class="keywordtype">unsigned</span> Size5,
+ <span class="keyword">typename</span> Layout, <span class="keyword">typename</span> Alloc=std::allocator<unsigned char> >
+<span class="keyword">struct </span>packed_image5_type { <span class="keyword">typedef</span> ... type; };
+
+<span class="keyword">template</span> <<span class="keywordtype">unsigned</span> Size1,
+ <span class="keyword">typename</span> Layout, <span class="keyword">typename</span> Alloc=std::allocator<unsigned char> >
+<span class="keyword">struct </span>bit_aligned_image1_type { <span class="keyword">typedef</span> ... type; };
+
+<span class="keyword">template</span> <<span class="keywordtype">unsigned</span> Size1, <span class="keywordtype">unsigned</span> Size2,
+ <span class="keyword">typename</span> Layout, <span class="keyword">typename</span> Alloc=std::allocator<unsigned char> >
+<span class="keyword">struct </span>bit_aligned_image2_type { <span class="keyword">typedef</span> ... type; };
+
+<span class="keyword">template</span> <<span class="keywordtype">unsigned</span> Size1, <span class="keywordtype">unsigned</span> Size2, <span class="keywordtype">unsigned</span> Size3,
+ <span class="keyword">typename</span> Layout, <span class="keyword">typename</span> Alloc=std::allocator<unsigned char> >
+<span class="keyword">struct </span>bit_aligned_image3_type { <span class="keyword">typedef</span> ... type; };
+
+<span class="keyword">template</span> <<span class="keywordtype">unsigned</span> Size1, <span class="keywordtype">unsigned</span> Size2, <span class="keywordtype">unsigned</span> Size3, <span class="keywordtype">unsigned</span> Size4,
+ <span class="keyword">typename</span> Layout, <span class="keyword">typename</span> Alloc=std::allocator<unsigned char> >
+<span class="keyword">struct </span>bit_aligned_image4_type { <span class="keyword">typedef</span> ... type; };
+
+<span class="keyword">template</span> <<span class="keywordtype">unsigned</span> Size1, <span class="keywordtype">unsigned</span> Size2, <span class="keywordtype">unsigned</span> Size3, <span class="keywordtype">unsigned</span> Size4, <span class="keywordtype">unsigned</span> Size5,
+ <span class="keyword">typename</span> Layout, <span class="keyword">typename</span> Alloc=std::allocator<unsigned char> >
+<span class="keyword">struct </span>bit_aligned_image5_type { <span class="keyword">typedef</span> ... type; };
+</pre></div><p>
+Here <code>ChannelValue</code> models <code>ChannelValueConcept</code>. We don't need <code>IsYStep</code> because GIL's memory-based locator and view already allow the vertical step to be specified dynamically. Iterators and views can be constructed from a pixel type:<p>
+<div class="fragment"><pre class="fragment"><span class="keyword">template</span> <<span class="keyword">typename</span> Pixel, <span class="keywordtype">bool</span> IsPlanar=false, <span class="keywordtype">bool</span> IsStep=false, <span class="keywordtype">bool</span> IsMutable=true>
+<span class="keyword">struct </span>iterator_type_from_pixel { <span class="keyword">typedef</span> ... type; };
+
+<span class="keyword">template</span> <<span class="keyword">typename</span> Pixel, <span class="keywordtype">bool</span> IsPlanar=false, <span class="keywordtype">bool</span> IsStepX=false, <span class="keywordtype">bool</span> IsMutable=true>
+<span class="keyword">struct </span>view_type_from_pixel { <span class="keyword">typedef</span> ... type; };
+</pre></div><p>
+Using a heterogeneous pixel type will result in heterogeneous iterators and views. Types can also be constructed from horizontal iterator:<p>
+<div class="fragment"><pre class="fragment"><span class="keyword">template</span> <<span class="keyword">typename</span> XIterator>
+<span class="keyword">struct </span>type_from_x_iterator {
+ <span class="keyword">typedef</span> ... step_iterator_t;
+ <span class="keyword">typedef</span> ... xy_locator_t;
+ <span class="keyword">typedef</span> ... view_t;
+};
+</pre></div><p>
+There are metafunctions to construct the type of a construct from an existing type by changing one or more of its properties:<p>
+<div class="fragment"><pre class="fragment"><span class="keyword">template</span> <<span class="keyword">typename</span> PixelReference,
+ <span class="keyword">typename</span> ChannelValue, <span class="keyword">typename</span> Layout, <span class="keyword">typename</span> IsPlanar, <span class="keyword">typename</span> IsMutable>
+<span class="keyword">struct </span>derived_pixel_reference_type {
+ <span class="keyword">typedef</span> ... type; <span class="comment">// Models PixelConcept</span>
+};
+
+<span class="keyword">template</span> <<span class="keyword">typename</span> Iterator,
+ <span class="keyword">typename</span> ChannelValue, <span class="keyword">typename</span> Layout, <span class="keyword">typename</span> IsPlanar, <span class="keyword">typename</span> IsStep, <span class="keyword">typename</span> IsMutable>
+<span class="keyword">struct </span>derived_iterator_type {
+ <span class="keyword">typedef</span> ... type; <span class="comment">// Models PixelIteratorConcept</span>
+};
+
+<span class="keyword">template</span> <<span class="keyword">typename</span> View,
+ <span class="keyword">typename</span> ChannelValue, <span class="keyword">typename</span> Layout, <span class="keyword">typename</span> IsPlanar, <span class="keyword">typename</span> IsXStep, <span class="keyword">typename</span> IsMutable>
+<span class="keyword">struct </span>derived_view_type {
+ <span class="keyword">typedef</span> ... type; <span class="comment">// Models ImageViewConcept</span>
+};
+
+<span class="keyword">template</span> <<span class="keyword">typename</span> Image,
+ <span class="keyword">typename</span> ChannelValue, <span class="keyword">typename</span> Layout, <span class="keyword">typename</span> IsPlanar>
+<span class="keyword">struct </span>derived_image_type {
+ <span class="keyword">typedef</span> ... type; <span class="comment">// Models ImageConcept</span>
+};
+</pre></div><p>
+You can replace one or more of its properties and use <code>boost::use_default</code> for the rest. In this case <code>IsPlanar</code>, <code>IsStep</code> and <code>IsMutable</code> are MPL boolean constants. For example, here is how to create the type of a view just like <code>View</code>, but being grayscale and planar:<p>
+<div class="fragment"><pre class="fragment"><span class="keyword">typedef</span> <span class="keyword">typename</span> derived_view_type<View, boost::use_default, gray_t, mpl::true_>::type VT;
+</pre></div><p>
+You can get pixel-related types of any pixel-based GIL constructs (pixels, iterators, locators and views) using the following metafunctions provided by PixelBasedConcept, HomogeneousPixelBasedConcept and metafunctions built on top of them:<p>
+<div class="fragment"><pre class="fragment"><span class="keyword">template</span> <<span class="keyword">typename</span> T> <span class="keyword">struct </span>color_space_type { <span class="keyword">typedef</span> ... type; };
+<span class="keyword">template</span> <<span class="keyword">typename</span> T> <span class="keyword">struct </span>channel_mapping_type { <span class="keyword">typedef</span> ... type; };
+<span class="keyword">template</span> <<span class="keyword">typename</span> T> <span class="keyword">struct </span>is_planar { <span class="keyword">typedef</span> ... type; };
+
+<span class="comment">// Defined by homogeneous constructs</span>
+<span class="keyword">template</span> <<span class="keyword">typename</span> T> <span class="keyword">struct </span>channel_type { <span class="keyword">typedef</span> ... type; };
+<span class="keyword">template</span> <<span class="keyword">typename</span> T> <span class="keyword">struct </span>num_channels { <span class="keyword">typedef</span> ... type; };
+</pre></div><p>
+These are metafunctions, some of which return integral types which can be evaluated like this:<p>
+<div class="fragment"><pre class="fragment">BOOST_STATIC_ASSERT(is_planar<rgb8_planar_view_t>::value == <span class="keyword">true</span>);
+</pre></div><p>
+GIL also supports type analysis metafunctions of the form: [pixel_reference/iterator/locator/view/image] + <code>"_is_"</code> + [basic/mutable/step]. For example:<p>
+<div class="fragment"><pre class="fragment"><span class="keywordflow">if</span> (view_is_mutable<View>::value) {
+ ...
+}
+</pre></div><p>
+A <em>basic</em> GIL construct is a memory-based construct that uses the built-in GIL classes and does not have any function object to invoke upon dereferencing. For example, a simple planar or interleaved, step or non-step RGB image view is basic, but a color converted view or a virtual view is not.<p>
+<hr>
+ <h2><a class="anchor" name="IO_DG">
+13. I/O Extension</a></h2>
+GIL's I/O extension provides low level image i/o utilities. It supports loading and saving several image formats, each of which requires linking against the corresponding library:<p>
+<ul>
+<li><b>JPEG</b>: To use JPEG files, include the file <code>gil/extension/io/jpeg_io.hpp</code>. If you are using run-time images, you need to include <code>gil/extension/io/jpeg_dynamic_io.hpp</code> instead. You need to compile and link against libjpeg.lib (available at http://www.ijg.org). You need to have <code>jpeglib.h</code> in your include path.</li></ul>
+<p>
+<ul>
+<li><b>TIFF</b>: To use TIFF files, include the file <code>gil/extension/io/tiff_io.hpp</code>. If you are using run-time images, you need to include <code>gil/extension/io/tiff_dynamic_io.hpp</code> instead. You need to compile and link against libtiff.lib (available at http://www.libtiff.org). You need to have <code>tiffio.h</code> in your include path.</li></ul>
+<p>
+<ul>
+<li><b>PNG</b>: To use PNG files, include the file <code>gil/extension/io/png_io.hpp</code>. If you are using run-time images, you need to include <code>gil/extension/io/png_dynamic_io.hpp</code> instead. You need to compile and link against libpng.lib (available at http://wwwlibpng.org). You need to have <code>png.h</code> in your include path.</li></ul>
+<p>
+You don't need to install all these libraries; just the ones you will use. Here are the I/O APIs for JPEG files (replace <code>"jpeg"</code> with <code>"tiff"</code> or <code>"png"</code> for the APIs of the other libraries):<p>
+<div class="fragment"><pre class="fragment"><span class="comment">// Returns the width and height of the JPEG file at the specified location.</span>
+<span class="comment">// Throws std::ios_base::failure if the location does not correspond to a valid JPEG file</span>
+point2<std::ptrdiff_t> <a class="code" href="http://opensource.adobe.com/gil/html/group___j_p_e_g___i_o.html#ga4">jpeg_read_dimensions</a>(<span class="keyword">const</span> <span class="keywordtype">char</span>*);
+
+<span class="comment">// Allocates a new image whose dimensions are determined by the given jpeg image file, and loads the pixels into it.</span>
+<span class="comment">// Triggers a compile assert if the image color space or channel depth are not supported by the JPEG library or by the I/O extension.</span>
+<span class="comment">// Throws std::ios_base::failure if the file is not a valid JPEG file, or if its color space or channel depth are not </span>
+<span class="comment">// compatible with the ones specified by Image</span>
+<span class="keyword">template</span> <<span class="keyword">typename</span> Img> <span class="keywordtype">void</span> <a class="code" href="http://opensource.adobe.com/gil/html/group___j_p_e_g___i_o.html#ga0">jpeg_read_image</a>(<span class="keyword">const</span> <span class="keywordtype">char</span>*, Img&);
+
+<span class="comment">// Allocates a new image whose dimensions are determined by the given jpeg image file, and loads the pixels into it,</span>
+<span class="comment">// color-converting and channel-converting if necessary.</span>
+<span class="comment">// Triggers a compile assert if the image color space or channel depth are not supported by the JPEG library or by the I/O extension.</span>
+<span class="comment">// Throws std::ios_base::failure if the file is not a valid JPEG file or if it fails to read it.</span>
+<span class="keyword">template</span> <<span class="keyword">typename</span> Img> <span class="keywordtype">void</span> <a class="code" href="http://opensource.adobe.com/gil/html/group___j_p_e_g___i_o.html#ga14">jpeg_read_and_convert_image</a>(<span class="keyword">const</span> <span class="keywordtype">char</span>*, Img&);
+<span class="keyword">template</span> <<span class="keyword">typename</span> Img, <span class="keyword">typename</span> CCV> <span class="keywordtype">void</span> <a class="code" href="http://opensource.adobe.com/gil/html/group___j_p_e_g___i_o.html#ga14">jpeg_read_and_convert_image</a>(<span class="keyword">const</span> <span class="keywordtype">char</span>*, Img&, CCV color_converter);
+
+<span class="comment">// Loads the image specified by the given jpeg image file name into the given view.</span>
+<span class="comment">// Triggers a compile assert if the view color space and channel depth are not supported by the JPEG library or by the I/O extension.</span>
+<span class="comment">// Throws std::ios_base::failure if the file is not a valid JPEG file, or if its color space or channel depth are not </span>
+<span class="comment">// compatible with the ones specified by View, or if its dimensions don't match the ones of the view.</span>
+<span class="keyword">template</span> <<span class="keyword">typename</span> View> <span class="keywordtype">void</span> <a class="code" href="http://opensource.adobe.com/gil/html/group___j_p_e_g___i_o.html#ga6">jpeg_read_view</a>(<span class="keyword">const</span> <span class="keywordtype">char</span>*, <span class="keyword">const</span> View&);
+
+<span class="comment">// Loads the image specified by the given jpeg image file name into the given view and color-converts (and channel-converts) it if necessary.</span>
+<span class="comment">// Triggers a compile assert if the view color space and channel depth are not supported by the JPEG library or by the I/O extension.</span>
+<span class="comment">// Throws std::ios_base::failure if the file is not a valid JPEG file, or if its dimensions don't match the ones of the view.</span>
+<span class="keyword">template</span> <<span class="keyword">typename</span> View> <span class="keywordtype">void</span> <a class="code" href="http://opensource.adobe.com/gil/html/group___j_p_e_g___i_o.html#ga10">jpeg_read_and_convert_view</a>(<span class="keyword">const</span> <span class="keywordtype">char</span>*, <span class="keyword">const</span> View&);
+<span class="keyword">template</span> <<span class="keyword">typename</span> View, <span class="keyword">typename</span> CCV> <span class="keywordtype">void</span> <a class="code" href="http://opensource.adobe.com/gil/html/group___j_p_e_g___i_o.html#ga10">jpeg_read_and_convert_view</a>(<span class="keyword">const</span> <span class="keywordtype">char</span>*, <span class="keyword">const</span> View&, CCV color_converter);
+
+<span class="comment">// Saves the view to a jpeg file specified by the given jpeg image file name.</span>
+<span class="comment">// Triggers a compile assert if the view color space and channel depth are not supported by the JPEG library or by the I/O extension.</span>
+<span class="comment">// Throws std::ios_base::failure if it fails to create the file.</span>
+<span class="keyword">template</span> <<span class="keyword">typename</span> View> <span class="keywordtype">void</span> <a class="code" href="http://opensource.adobe.com/gil/html/group___j_p_e_g___i_o.html#ga2">jpeg_write_view</a>(<span class="keyword">const</span> <span class="keywordtype">char</span>*, <span class="keyword">const</span> View&);
+
+<span class="comment">// Determines whether the given view type is supported for reading</span>
+<span class="keyword">template</span> <<span class="keyword">typename</span> View> <span class="keyword">struct </span>jpeg_read_support {
+ <span class="keyword">static</span> <span class="keyword">const</span> <span class="keywordtype">bool</span> value = ...;
+};
+
+<span class="comment">// Determines whether the given view type is supported for writing</span>
+<span class="keyword">template</span> <<span class="keyword">typename</span> View> <span class="keyword">struct </span>jpeg_write_support {
+ <span class="keyword">static</span> <span class="keyword">const</span> <span class="keywordtype">bool</span> value = ...;
+};
+</pre></div><p>
+If you use the dynamic image extension, make sure to include <code>"jpeg_dynamic_io.hpp"</code> instead of <code>"jpeg_io.hpp"</code>. In addition to the above methods, you have the following overloads dealing with dynamic images:<p>
+<div class="fragment"><pre class="fragment"><span class="comment">// Opens the given JPEG file name, selects the first type in Images whose color space and channel are compatible to those of the image file</span>
+<span class="comment">// and creates a new image of that type with the dimensions specified by the image file.</span>
+<span class="comment">// Throws std::ios_base::failure if none of the types in Images are compatible with the type on disk.</span>
+<span class="keyword">template</span> <<span class="keyword">typename</span> Images> <span class="keywordtype">void</span> <a class="code" href="http://opensource.adobe.com/gil/html/group___j_p_e_g___i_o.html#ga0">jpeg_read_image</a>(<span class="keyword">const</span> <span class="keywordtype">char</span>*, any_image<Images>&);
+
+<span class="comment">// Saves the currently instantiated view to a jpeg file specified by the given jpeg image file name.</span>
+<span class="comment">// Throws std::ios_base::failure if the currently instantiated view type is not supported for writing by the I/O extension </span>
+<span class="comment">// or if it fails to create the file.</span>
+<span class="keyword">template</span> <<span class="keyword">typename</span> Views> <span class="keywordtype">void</span> <a class="code" href="http://opensource.adobe.com/gil/html/group___j_p_e_g___i_o.html#ga2">jpeg_write_view</a>(<span class="keyword">const</span> <span class="keywordtype">char</span>*, any_image_view<Views>&);
+</pre></div><p>
+All of the above methods have overloads taking <code>std::string</code> instead of <code>const char*</code><p>
+<hr>
+ <h2><a class="anchor" name="SampleImgCodeDG">
+14. Sample Code</a></h2>
+<h3><a class="anchor" name="PixelLevelExampleDG">
+Pixel-level Sample Code</a></h3>
+Here are some operations you can do with pixel values, pointers and references:<p>
+<div class="fragment"><pre class="fragment">rgb8_pixel_t p1(255,0,0); <span class="comment">// make a red RGB pixel</span>
+bgr8_pixel_t p2 = p1; <span class="comment">// RGB and BGR are compatible and the channels will be properly mapped. </span>
+assert(p1==p2); <span class="comment">// p2 will also be red.</span>
+assert(p2[0]!=p1[0]); <span class="comment">// operator[] gives physical channel order (as laid down in memory)</span>
+assert(semantic_at_c<0>(p1)==semantic_at_c<0>(p2)); <span class="comment">// this is how to compare the two red channels</span>
+<a class="code" href="http://opensource.adobe.com/gil/html/group___color_base_algorithm_color.html#ga0">get_color</a>(p1,green_t()) = <a class="code" href="http://opensource.adobe.com/gil/html/group___color_base_algorithm_color.html#ga0">get_color</a>(p2,blue_t()); <span class="comment">// channels can also be accessed by name</span>
+
+<span class="keyword">const</span> <span class="keywordtype">unsigned</span> <span class="keywordtype">char</span>* r;
+<span class="keyword">const</span> <span class="keywordtype">unsigned</span> <span class="keywordtype">char</span>* g;
+<span class="keyword">const</span> <span class="keywordtype">unsigned</span> <span class="keywordtype">char</span>* b;
+rgb8c_planar_ptr_t ptr(r,g,b); <span class="comment">// constructing const planar pointer from const pointers to each plane</span>
+
+rgb8c_planar_ref_t ref=*ptr; <span class="comment">// just like built-in reference, dereferencing a planar pointer returns a planar reference</span>
+
+p2=ref; p2=p1; p2=ptr[7]; p2=rgb8_pixel_t(1,2,3); <span class="comment">// planar/interleaved references and values to RGB/BGR can be freely mixed</span>
+
+<span class="comment">//rgb8_planar_ref_t ref2; // compile error: References have no default constructors</span>
+<span class="comment">//ref2=*ptr; // compile error: Cannot construct non-const reference by dereferencing const pointer</span>
+<span class="comment">//ptr[3]=p1; // compile error: Cannot set the fourth pixel through a const pointer</span>
+<span class="comment">//p1 = pixel<float, rgb_layout_t>();// compile error: Incompatible channel depth</span>
+<span class="comment">//p1 = pixel<bits8, rgb_layout_t>();// compile error: Incompatible color space (even though it has the same number of channels)</span>
+<span class="comment">//p1 = pixel<bits8,rgba_layout_t>();// compile error: Incompatible color space (even though it contains red, green and blue channels)</span>
+</pre></div><p>
+Here is how to use pixels in generic code:<p>
+<div class="fragment"><pre class="fragment"><span class="keyword">template</span> <<span class="keyword">typename</span> GrayPixel, <span class="keyword">typename</span> RGBPixel>
+<span class="keywordtype">void</span> gray_to_rgb(<span class="keyword">const</span> GrayPixel& src, RGBPixel& dst) {
+ gil_function_requires<PixelConcept<GrayPixel> >();
+ gil_function_requires<MutableHomogeneousPixelConcept<RGBPixel> >();
+
+ <span class="keyword">typedef</span> <span class="keyword">typename</span> color_space_type<GrayPixel>::type gray_cs_t;
+ BOOST_STATIC_ASSERT((boost::is_same<gray_cs_t,gray_t>::value));
+
+ <span class="keyword">typedef</span> <span class="keyword">typename</span> color_space_type<RGBPixel>::type rgb_cs_t;
+ BOOST_STATIC_ASSERT((boost::is_same<rgb_cs_t,rgb_t>::value));
+
+ <span class="keyword">typedef</span> <span class="keyword">typename</span> channel_type<GrayPixel>::type gray_channel_t;
+ <span class="keyword">typedef</span> <span class="keyword">typename</span> channel_type<RGBPixel>::type rgb_channel_t;
+
+ gray_channel_t gray = <a class="code" href="http://opensource.adobe.com/gil/html/group___color_base_algorithm_color.html#ga0">get_color</a>(src,gray_color_t());
+ static_fill(dst, channel_convert<rgb_channel_t>(gray));
+}
+
+<span class="comment">// example use patterns:</span>
+
+<span class="comment">// converting gray l-value to RGB and storing at (5,5) in a 16-bit BGR interleaved image:</span>
+bgr16_view_t b16(...);
+gray_to_rgb(gray8_pixel_t(33), b16(5,5));
+
+<span class="comment">// storing the first pixel of an 8-bit grayscale image as the 5-th pixel of 32-bit planar RGB image:</span>
+rgb32f_planar_view_t rpv32;
+gray8_view_t gv8(...);
+gray_to_rgb(*gv8.begin(), rpv32[5]);
+</pre></div><p>
+As the example shows, both the source and the destination can be references or values, planar or interleaved, as long as they model <code>PixelConcept</code> and <code>MutablePixelConcept</code> respectively.<h3><a class="anchor" name="SafeAreaExampleDG">
+Creating a Copy of an Image with a Safe Buffer</a></h3>
+Suppose we want to convolve an image with multiple kernels, the largest of which is 2K+1 x 2K+1 pixels. It may be worth creating a margin of K pixels around the image borders. Here is how to do it:<p>
+<div class="fragment"><pre class="fragment"><span class="keyword">template</span> <<span class="keyword">typename</span> SrcView, <span class="comment">// Models ImageViewConcept (the source view)</span>
+ <span class="keyword">typename</span> DstImage> <span class="comment">// Models ImageConcept (the returned image)</span>
+<span class="keywordtype">void</span> create_with_margin(<span class="keyword">const</span> SrcView& src, <span class="keywordtype">int</span> k, DstImage& result) {
+ gil_function_requires<ImageViewConcept<SrcView> >();
+ gil_function_requires<ImageConcept<DstImage> >();
+ gil_function_requires<ViewsCompatibleConcept<SrcView, typename DstImage::view_t> >();
+
+ result=DstImage(src.width()+2*k, src.height()+2*k);
+ <span class="keyword">typename</span> DstImage::view_t centerImg=subimage_view(<a class="code" href="http://opensource.adobe.com/gil/html/group___image_model.html#ga0">view</a>(result), k,k,src.width(),src.height());
+ <a class="code" href="http://opensource.adobe.com/gil/html/group___s_t_l_optimizations.html#ga0">std::copy</a>(src.begin(), src.end(), centerImg.begin());
+}
+</pre></div><p>
+We allocated a larger image, then we used <code>subimage_view</code> to create a shallow image of its center area of top left corner at (k,k) and of identical size as <code>src</code>, and finally we copied <code>src</code> into that center image. If the margin needs initialization, we could have done it with <code>fill_pixels</code>. Here is how to simplify this code using the <code>copy_pixels</code> algorithm:<p>
+<div class="fragment"><pre class="fragment"><span class="keyword">template</span> <<span class="keyword">typename</span> SrcView, <span class="keyword">typename</span> DstImage>
+<span class="keywordtype">void</span> create_with_margin(<span class="keyword">const</span> SrcView& src, <span class="keywordtype">int</span> k, DstImage& result) {
+ result.recreate(src.width()+2*k, src.height()+2*k);
+ <a class="code" href="http://opensource.adobe.com/gil/html/group___image_view_s_t_l_algorithms_copy_pixels.html#ga0">copy_pixels</a>(src, subimage_view(<a class="code" href="http://opensource.adobe.com/gil/html/group___image_model.html#ga0">view</a>(result), k,k,src.width(),src.height()));
+}
+</pre></div><p>
+(Note also that <code>image::recreate</code> is more efficient than <code>operator=</code>, as the latter will do an unnecessary copy construction). Not only does the above example work for planar and interleaved images of any color space and pixel depth; it is also optimized. GIL overrides <code><a class="el" href="http://opensource.adobe.com/gil/html/group___s_t_l_optimizations.html#ga2">std::copy</a></code> - when called on two identical interleaved images with no padding at the end of rows, it simply does a <code>memmove</code>. For planar images it does <code>memmove</code> for each channel. If one of the images has padding, (as in our case) it will try to do <code>memmove</code> for each row. When an image has no padding, it will use its lightweight horizontal iterator (as opposed to the more complex 1D image iterator that has to check for the end of rows). It choses the fastest method, taking into account both static and run-time parameters.<h3><a class="anchor" name="HistogramExampleDG">
+Histogram</a></h3>
+The histogram can be computed by counting the number of pixel values that fall in each bin. The following method takes a grayscale (one-dimensional) image view, since only grayscale pixels are convertible to integers: <div class="fragment"><pre class="fragment"><span class="keyword">template</span> <<span class="keyword">typename</span> GrayView, <span class="keyword">typename</span> R>
+<span class="keywordtype">void</span> grayimage_histogram(<span class="keyword">const</span> GrayView& img, R& hist) {
+ <span class="keywordflow">for</span> (<span class="keyword">typename</span> GrayView::iterator it=img.begin(); it!=img.end(); ++it)
+ ++hist[*it];
+}
+</pre></div><p>
+Using <code>boost::lambda</code> and GIL's <code>for_each_pixel</code> algorithm, we can write this more compactly:<p>
+<div class="fragment"><pre class="fragment"><span class="keyword">template</span> <<span class="keyword">typename</span> GrayView, <span class="keyword">typename</span> R>
+<span class="keywordtype">void</span> grayimage_histogram(<span class="keyword">const</span> GrayView& v, R& hist) {
+ for_each_pixel(v, ++var(hist)[_1]);
+}
+</pre></div><p>
+Where <code>for_each_pixel</code> invokes <code>std::for_each</code> and <code>var</code> and <code>_1</code> are <code>boost::lambda</code> constructs. To compute the luminosity histogram, we call the above method using the grayscale view of an image:<p>
+<div class="fragment"><pre class="fragment"><span class="keyword">template</span> <<span class="keyword">typename</span> View, <span class="keyword">typename</span> R>
+<span class="keywordtype">void</span> luminosity_histogram(<span class="keyword">const</span> View& v, R& hist) {
+ grayimage_histogram(color_converted_view<gray8_pixel_t>(v),hist);
+}
+</pre></div><p>
+This is how to invoke it:<p>
+<div class="fragment"><pre class="fragment"><span class="keywordtype">unsigned</span> <span class="keywordtype">char</span> hist[256];
+<a class="code" href="http://opensource.adobe.com/gil/html/group___s_t_l_optimizations.html#ga4">std::fill</a>(hist,hist+256,0);
+luminosity_histogram(my_view,hist);
+</pre></div><p>
+If we want to view the histogram of the second channel of the image in the top left 100x100 area, we call:<p>
+<div class="fragment"><pre class="fragment">grayimage_histogram(nth_channel_view(subimage_view(img,0,0,100,100),1),hist);
+</pre></div><p>
+No pixels are copied and no extra memory is allocated - the code operates directly on the source pixels, which could be in any supported color space and channel depth. They could be either planar or interleaved.<h3><a class="anchor" name="ImageViewsExampleDG">
+Using Image Views</a></h3>
+The following code illustrates the power of using image views:<p>
+<div class="fragment"><pre class="fragment"><a class="code" href="http://opensource.adobe.com/gil/html/group___j_p_e_g___i_o.html#ga0">jpeg_read_image</a>(<span class="stringliteral">"monkey.jpg"</span>, img);
+step1=<a class="code" href="http://opensource.adobe.com/gil/html/group___image_model.html#ga0">view</a>(img);
+step2=subimage_view(step1, 200,300, 150,150);
+step3=color_converted_view<rgb8_view_t,gray8_pixel_t>(step2);
+step4=rotated180_view(step3);
+step5=subsampled_view(step4, 2,1);
+<a class="code" href="http://opensource.adobe.com/gil/html/group___j_p_e_g___i_o.html#ga2">jpeg_write_view</a>(<span class="stringliteral">"monkey_transform.jpg"</span>, step5);
+</pre></div><p>
+The intermediate images are shown here: <div align="center">
+<img src="monkey_steps.jpg" alt="monkey_steps.jpg">
+</div>
+<p>
+Notice that no pixels are ever copied. All the work is done inside <code>jpeg_write_view</code>. If we call our <code>luminosity_histogram</code> with <code>step5</code> it will do the right thing.<p>
+<hr>
+ <h2><a class="anchor" name="ExtendingGIL_DG">
+15. Extending the Generic Image Library</a></h2>
+You can define your own pixel iterators, locators, image views, images, channel types, color spaces and algorithms. You can make virtual images that live on the disk, inside a jpeg file, somewhere on the internet, or even fully-synthetic images such as the Mandelbrot set. As long as they properly model the corresponding concepts, they will work with any existing GIL code. Most such extensions require no changes to the library and can thus be supplied in another module.<h3><a class="anchor" name="NewColorSpacesDG">
+Defining New Color Spaces</a></h3>
+Each color space is in a separate file. To add a new color space, just copy one of the existing ones (like <a class="el" href="rgb_8hpp.html">rgb.hpp</a>) and change it accordingly. If you want color conversion support, you will have to provide methods to convert between it and the existing color spaces (see color_convert.h). For convenience you may want to provide useful typedefs for pixels, pointers, references and images with the new color space (see typedefs.h).<h3><a class="anchor" name="NewChannelsDG">
+Defining New Channel Types</a></h3>
+Most of the time you don't need to do anything special to use a new channel type. You can just use it:<p>
+<div class="fragment"><pre class="fragment"><span class="keyword">typedef</span> pixel<double,rgb_layout_t> rgb64_pixel_t; <span class="comment">// 64 bit RGB pixel </span>
+<span class="keyword">typedef</span> rgb64_pixel* rgb64_pixel_ptr_t;<span class="comment">// pointer to 64-bit interleaved data</span>
+<span class="keyword">typedef</span> image_type<double,rgb_layout_t>::type rgb64_image_t; <span class="comment">// 64-bit interleaved image</span>
+</pre></div><p>
+If you want to use your own channel class, you will need to provide a specialization of <code>channel_traits</code> for it (see <a class="el" href="channel_8hpp.html">channel.hpp</a>). If you want to do conversion between your and existing channel types, you will need to provide an overload of <code>channel_convert</code>.<h3><a class="anchor" name="NewColorConversionDG">
+Overloading Color Conversion</a></h3>
+Suppose you want to provide your own color conversion. For example, you may want to implement higher quality color conversion using color profiles. Typically you may want to redefine color conversion only in some instances and default to GIL's color conversion in all other cases. Here is, for example, how to overload color conversion so that color conversion to gray inverts the result but everything else remains the same:<p>
+<div class="fragment"><pre class="fragment"><span class="comment">// make the default use GIL's default</span>
+<span class="keyword">template</span> <<span class="keyword">typename</span> SrcColorSpace, <span class="keyword">typename</span> DstColorSpace>
+<span class="keyword">struct </span>my_color_converter_impl
+ : <span class="keyword">public</span> default_color_converter_impl<SrcColorSpace,DstColorSpace> {};
+
+<span class="comment">// provide specializations only for cases you care about</span>
+<span class="comment">// (in this case, if the destination is grayscale, invert it)</span>
+<span class="keyword">template</span> <<span class="keyword">typename</span> SrcColorSpace>
+<span class="keyword">struct </span>my_color_converter_impl<SrcColorSpace,gray_t> {
+ <span class="keyword">template</span> <<span class="keyword">typename</span> SrcP, <span class="keyword">typename</span> DstP> <span class="comment">// Model PixelConcept</span>
+ <span class="keywordtype">void</span> operator()(<span class="keyword">const</span> SrcP& src, DstP& dst)<span class="keyword"> const </span>{
+ default_color_converter_impl<SrcColorSpace,gray_t>()(src,dst);
+ <a class="code" href="http://opensource.adobe.com/gil/html/group___color_base_algorithm_color.html#ga0">get_color</a>(dst,gray_color_t())=<a class="code" href="http://opensource.adobe.com/gil/html/group___channel_invert_algorithm.html#ga0">channel_invert</a>(<a class="code" href="http://opensource.adobe.com/gil/html/group___color_base_algorithm_color.html#ga0">get_color</a>(dst,gray_color_t()));
+ }
+};
+
+<span class="comment">// create a color converter object that dispatches to your own implementation</span>
+<span class="keyword">struct </span>my_color_converter {
+ <span class="keyword">template</span> <<span class="keyword">typename</span> SrcP, <span class="keyword">typename</span> DstP> <span class="comment">// Model PixelConcept</span>
+ <span class="keywordtype">void</span> operator()(<span class="keyword">const</span> SrcP& src,DstP& dst)<span class="keyword"> const </span>{
+ <span class="keyword">typedef</span> <span class="keyword">typename</span> color_space_type<SrcP>::type SrcColorSpace;
+ <span class="keyword">typedef</span> <span class="keyword">typename</span> color_space_type<DstP>::type DstColorSpace;
+ my_color_converter_impl<SrcColorSpace,DstColorSpace>()(src,dst);
+ }
+};
+</pre></div><p>
+GIL's color conversion functions take the color converter as an optional parameter. You can pass your own color converter:<p>
+<div class="fragment"><pre class="fragment">color_converted_view<gray8_pixel_t>(img_view,my_color_converter());
+</pre></div><h3><a class="anchor" name="NewImagesDG">
+Defining New Image Views</a></h3>
+You can provide your own pixel iterators, locators and views, overriding either the mechanism for getting from one pixel to the next or doing an arbitrary pixel transformation on dereference. For example, let's look at the implementation of <code>color_converted_view</code> (an image factory method that, given any image view, returns a new, otherwise identical view, except that color conversion is performed on pixel access). First we need to define a model of <code>PixelDereferenceAdaptorConcept</code>; a function object that will be called when we dereference a pixel iterator. It will call <code>color_convert</code> to convert to the destination pixel type:<p>
+<div class="fragment"><pre class="fragment"><span class="keyword">template</span> <<span class="keyword">typename</span> SrcConstRefP, <span class="comment">// const reference to the source pixel</span>
+ <span class="keyword">typename</span> DstP> <span class="comment">// Destination pixel value (models PixelValueConcept)</span>
+<span class="keyword">class </span>color_convert_deref_fn {
+<span class="keyword">public</span>:
+ <span class="keyword">typedef</span> color_convert_deref_fn const_t;
+ <span class="keyword">typedef</span> DstP value_type;
+ <span class="keyword">typedef</span> value_type reference; <span class="comment">// read-only dereferencing</span>
+ <span class="keyword">typedef</span> <span class="keyword">const</span> value_type& const_reference;
+ <span class="keyword">typedef</span> SrcConstRefP argument_type;
+ <span class="keyword">typedef</span> reference result_type;
+ BOOST_STATIC_CONSTANT(<span class="keywordtype">bool</span>, is_mutable=<span class="keyword">false</span>);
+
+ result_type operator()(argument_type srcP)<span class="keyword"> const </span>{
+ result_type dstP;
+ <a class="code" href="http://opensource.adobe.com/gil/html/group___pixel_algorithm.html#ga0">color_convert</a>(srcP,dstP);
+ <span class="keywordflow">return</span> dstP;
+ }
+};
+</pre></div><p>
+We then use the <code>add_deref</code> member struct of image views to construct the type of a view that invokes a given function object (<code>deref_t</code>) upon dereferencing. In our case, it performs color conversion:<p>
+<div class="fragment"><pre class="fragment"><span class="keyword">template</span> <<span class="keyword">typename</span> SrcView, <span class="keyword">typename</span> DstP>
+<span class="keyword">struct </span>color_converted_view_type {
+<span class="keyword">private</span>:
+ <span class="keyword">typedef</span> <span class="keyword">typename</span> SrcView::const_t::reference src_pix_ref; <span class="comment">// const reference to pixel in SrcView</span>
+ <span class="keyword">typedef</span> color_convert_deref_fn<src_pix_ref, DstP> deref_t; <span class="comment">// the dereference adaptor that performs color conversion</span>
+ <span class="keyword">typedef</span> <span class="keyword">typename</span> SrcView::template add_deref<deref_t> add_ref_t;
+<span class="keyword">public</span>:
+ <span class="keyword">typedef</span> <span class="keyword">typename</span> add_ref_t::type type; <span class="comment">// the color converted view type</span>
+ <span class="keyword">static</span> type make(<span class="keyword">const</span> SrcView& sv) { <span class="keywordflow">return</span> add_ref_t::make(sv, deref_t()); }
+};
+</pre></div><p>
+Finally our <code>color_converted_view</code> code simply creates color-converted view from the source view:<p>
+<div class="fragment"><pre class="fragment"><span class="keyword">template</span> <<span class="keyword">typename</span> DstP, <span class="keyword">typename</span> View> <span class="keyword">inline</span>
+<span class="keyword">typename</span> color_converted_view_type<View,DstP>::type color_convert_view(<span class="keyword">const</span> View& src) {
+ <span class="keywordflow">return</span> color_converted_view_type<View,DstP>::make(src);
+}
+</pre></div><p>
+(The actual color convert view transformation is slightly more complicated, as it takes an optional color conversion object, which allows users to specify their own color conversion methods). See the GIL tutorial for an example of creating a virtual image view that defines the Mandelbrot set.<p>
+<hr>
+ <h2><a class="anchor" name="TechnicalitiesDG">
+16. Technicalities</a></h2>
+<h3><a class="anchor" name="CreatingReferenceProxyDG">
+Creating a reference proxy</a></h3>
+Sometimes it is necessary to create a proxy class that represents a reference to a given object. Examples of these are GIL's reference to a planar pixel (<code>planar_pixel_reference</code>) and GIL's subbyte channel references. Writing a reference proxy class can be tricky. One problem is that the proxy reference is constructed as a temporary object and returned by value upon dereferencing the iterator:<p>
+<div class="fragment"><pre class="fragment"><span class="keyword">struct </span>rgb_planar_pixel_iterator {
+ <span class="keyword">typedef</span> my_reference_proxy<T> reference;
+ reference operator*()<span class="keyword"> const </span>{ <span class="keywordflow">return</span> reference(red,green,blue); }
+};
+</pre></div><p>
+The problem arises when an iterator is dereferenced directly into a function that takes a mutable pixel:<p>
+<div class="fragment"><pre class="fragment"><span class="keyword">template</span> <<span class="keyword">typename</span> Pixel> <span class="comment">// Models MutablePixelConcept</span>
+<span class="keywordtype">void</span> invert_pixel(Pixel& p);
+
+rgb_planar_pixel_iterator myIt;
+invert_pixel(*myIt); <span class="comment">// compile error!</span>
+</pre></div><p>
+C++ does not allow for matching a temporary object against a non-constant reference. The solution is to:<ul>
+<li>Use const qualifier on all members of the reference proxy object:</li></ul>
+<p>
+<div class="fragment"><pre class="fragment"><span class="keyword">template</span> <<span class="keyword">typename</span> T>
+<span class="keyword">struct </span>my_reference_proxy {
+ <span class="keyword">const</span> my_reference_proxy& operator=(<span class="keyword">const</span> my_reference_proxy& p) <span class="keyword">const</span>;
+ <span class="keyword">const</span> my_reference_proxy* operator->()<span class="keyword"> const </span>{ <span class="keywordflow">return</span> <span class="keyword">this</span>; }
+ ...
+};
+</pre></div><p>
+<ul>
+<li>Use different classes to denote mutable and constant reference (maybe based on the constness of the template parameter)</li></ul>
+<p>
+<ul>
+<li>Define the reference type of your iterator with const qualifier:</li></ul>
+<p>
+<div class="fragment"><pre class="fragment"><span class="keyword">struct </span>iterator_traits<rgb_planar_pixel_iterator> {
+ <span class="keyword">typedef</span> <span class="keyword">const</span> my_reference_proxy<T> reference;
+};
+</pre></div><p>
+A second important issue is providing an overload for <code>swap</code> for your reference class. The default <code>std::swap</code> will not work correctly. You must use a real value type as the temporary. A further complication is that in some implementations of the STL the <code>swap</code> function is incorreclty called qualified, as <code>std::swap</code>. The only way for these STL algorithms to use your overload is if you define it in the <code>std</code> namespace: <div class="fragment"><pre class="fragment"><span class="keyword">namespace </span>std {
+ <span class="keyword">template</span> <<span class="keyword">typename</span> T>
+ <span class="keywordtype">void</span> swap(my_reference_proxy<T>& x, my_reference_proxy<T>& y) {
+ my_value<T> tmp=x;
+ x=y;
+ y=tmp;
+ }
+}
+</pre></div><p>
+Lastly, remember that constructors and copy-constructors of proxy references are always shallow and assignment operators are deep.<p>
+We are grateful to Dave Abrahams, Sean Parent and Alex Stepanov for suggesting the above solution.<p>
+<hr>
+ <h2><a class="anchor" name="ConclusionDG">
+17. Conclusion</a></h2>
+The Generic Image Library is designed with the following five goals in mind:<p>
+<ul>
+<li><b> Generality.</b> Abstracts image representations from algorithms on images. It allows for writing code once and have it work for any image type. </li>
+<li><b> Performance.</b> Speed has been instrumental to the design of the library. The generic algorithms provided in the library are in many cases comparable in speed to hand-coding the algorithm for a specific image type. </li>
+<li><b> Flexibility.</b> Compile-type parameter resolution results in faster code, but severely limits code flexibility. The library allows for any image parameter to be specified at run time, at a minor performance cost. </li>
+<li><b> Extensibility.</b> Virtually every construct in GIL can be extended - new channel types, color spaces, layouts, iterators, locators, image views and images can be provided by modeling the corresponding GIL concepts. </li>
+<li><b> Compatibility.</b> The library is designed as an STL complement. Generic STL algorithms can be used for pixel manipulation, and they are specifically targeted for optimization. The library works with existing raw pixel data from another image library.</li>
+</ul>
+ <hr size="1"><address style="align: right;"><small>Generated on Thu Nov 8 21:53:19 2007 for Generic Image Library by
+<a href="http://www.doxygen.org/index.html">
+<img src="doxygen.png" alt="doxygen" align="middle" border="0"></a> 1.4.4 </small></address>
+</body>
+</html>
Added: trunk/libs/gil/doc/html/giltutorial.html
==============================================================================
--- (empty file)
+++ trunk/libs/gil/doc/html/giltutorial.html 2007-11-11 14:29:06 EST (Sun, 11 Nov 2007)
@@ -0,0 +1,461 @@
+<!--
+ 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)
+
+ Some files are held under additional license.
+ Please see "http://opensource.adobe.com/licenses.html" for more information.
+-->
+
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
+
+<head>
+ <TITLE>Generic Image Library : Generic Image Library Tutorial</TITLE>
+ <META HTTP-EQUIV="content-type" CONTENT="text/html;charset=ISO-8859-1"/>
+ <LINK TYPE="text/css" REL="stylesheet" HREF="adobe_source.css"/>
+ <LINK REL="alternate" TITLE="opensource.adobe.com RSS" HREF="http://sourceforge.net/export/rss2_projnews.php?group_id=132417&rss_fulltext=1" TYPE="application/rss+xml"/>
+ <script src="http://www.google-analytics.com/urchin.js" type="text/javascript">
+ </script>
+</head>
+<body>
+<table border="0" cellspacing="0" cellpadding="0" style='width: 100%; margin: 0; padding: 0'><tr>
+<td width="100%" valign="top" style='padding-left: 10px; padding-right: 10px; padding-bottom: 10px'>
+<!-- End Header -->
+<!-- Generated by Doxygen 1.4.4 -->
+<h1><a class="anchor" name="GILTutorial">Generic Image Library Tutorial</a></h1><dl compact><dt><b>Author:</b></dt><dd>Lubomir Bourdev (<a href="mailto:lbourdev_at_[hidden]">lbourdev_at_[hidden]</a>) and Hailin Jin (<a href="mailto:hljin_at_[hidden]">hljin_at_[hidden]</a>) <br>
+ Adobe Systems Incorporated</dd></dl>
+<dl compact><dt><b>Version:</b></dt><dd>2.1 </dd></dl>
+<dl compact><dt><b>Date:</b></dt><dd>September 15, 2007</dd></dl>
+The Generic Image Library (GIL) is a C++ library that abstracts image representations from algorithms and allows writing code that can work on a variety of images with performance similar to hand-writing for a specific image type. <p>
+This document will give you a jump-start in using GIL. It does not discuss the underlying design of the library and does not cover all aspects of it. You can find a detailed library design document on the main GIL web page at http://opensource.adobe.com/gil<p>
+<ul>
+<li><a class="el" href="giltutorial.html#InstallSec">Installation</a></li><li><a class="el" href="giltutorial.html#ExampleSec">Example - Computing the Image Gradient</a><ul>
+<li><a class="el" href="giltutorial.html#InterfaceSec">Interface and Glue Code</a></li><li><a class="el" href="giltutorial.html#FirstImplementationSec">First Implementation</a></li><li><a class="el" href="giltutorial.html#LocatorsSec">Using Locators</a></li><li><a class="el" href="giltutorial.html#GenericVersionSec">Creating a Generic Version of GIL Algorithms</a></li><li><a class="el" href="giltutorial.html#ImageViewTransformationSec">Image View Transformations</a></li><li><a class="el" href="giltutorial.html#OneDIteratorsSec">1D pixel iterators</a></li><li><a class="el" href="giltutorial.html#STLEquivalentsSec">STL Equivalent Algorithms</a></li><li><a class="el" href="giltutorial.html#ColorConversionSec">Color Conversion</a></li><li><a class="el" href="giltutorial.html#ImagesSec">Image</a></li><li><a class="el" href="giltutorial.html#VirtualViewSec">Virtual Image Views</a></li><li><a class="el" href="giltutorial.html#DynamicImageSec">Run-Time Specified Images and Image Views</a></li><li><a class="el" href
="giltutorial.html#ConclusionSec">Conclusion</a></li></ul>
+</li><li><a class="el" href="giltutorial.html#AppendixSec">Appendix</a><ul>
+<li><a class="el" href="giltutorial.html#AppendixConventionSec">Naming convention for GIL concrete types</a></li></ul>
+</li></ul>
+<h2><a class="anchor" name="InstallSec">
+Installation</a></h2>
+The latest version of GIL can be downloaded from GIL's web page, at http://opensource.adobe.com/gil. GIL is approved for integration into Boost and in the future will be installed simply by installing Boost from http://www.boost.org. GIL consists of header files only and does not require any libraries to link against. It does not require Boost to be built. Including <code>boost/gil/gil_all</code>.hpp will be sufficient for most projects.<h2><a class="anchor" name="ExampleSec">
+Example - Computing the Image Gradient</a></h2>
+This tutorial will walk through an example of using GIL to compute the image gradients. We will start with some very simple and non-generic code and make it more generic as we go along. Let us start with a horizontal gradient and use the simplest possible approximation to a gradient - central difference. The gradient at pixel x can be approximated with the half-difference of its two neighboring pixels: D[x] = (I[x-1] - I[x+1]) / 2<p>
+For simplicity, we will also ignore the boundary cases - the pixels along the edges of the image for which one of the neighbors is not defined. The focus of this document is how to use GIL, not how to create a good gradient generation algorithm.<h3><a class="anchor" name="InterfaceSec">
+Interface and Glue Code</a></h3>
+Let us first start with 8-bit unsigned grayscale image as the input and 8-bit signed grayscale image as the output. Here is how the interface to our algorithm looks like:<p>
+<div class="fragment"><pre class="fragment"><span class="preprocessor">#include <<a class="code" href="gil__all_8hpp.html">boost/gil/gil_all.hpp</a>></span>
+<span class="keyword">using</span> <span class="keyword">namespace </span>boost::gil;
+
+<span class="keywordtype">void</span> x_gradient(<span class="keyword">const</span> gray8c_view_t& src, <span class="keyword">const</span> gray8s_view_t& dst) {
+ assert(src.dimensions() == dst.dimensions());
+ ... <span class="comment">// compute the gradient</span>
+}
+</pre></div><p>
+<code>gray8c_view_t</code> is the type of the source image view - an 8-bit grayscale view, whose pixels are read-only (denoted by the <code>"c"</code>). The output is a grayscale view with a 8-bit signed (denoted by the <code>"s"</code>) integer channel type. See Appendix 1 for the complete convension GIL uses to name concrete types.<p>
+GIL makes a distinction between an image and an image view. A GIL <em>image view</em>, is a shallow, lightweight view of a rectangular grid of pixels. It provides access to the pixels but does not own the pixels. Copy-constructing a view does not deep-copy the pixels. Image views do not propagate their constness to the pixels and should always be taken by a const reference. Whether a view is mutable or read-only (immutable) is a property of the view type.<p>
+A GIL <em>image</em>, on the other hand, is a view with associated ownership. It is a container of pixels; its constructor/destructor allocates/deallocates the pixels, its copy-constructor performs deep-copy of the pixels and its operator== performs deep-compare of the pixels. Images also propagate their constness to their pixels - a constant reference to an image will not allow for modifying its pixels.<p>
+Most GIL algorithms operate on image views; images are rarely needed. GIL's design is very similar to that of the STL. The STL equivalent of GIL's image is a container, like <code>std::vector</code>, whereas GIL's image view corresponds to STL's range, which is often represented with a pair of iterators. STL algorithms operate on ranges, just like GIL algorithms operate on image views.<p>
+GIL's image views can be constructed from raw data - the dimensions, the number of bytes per row and the pixels, which for chunky views are represented with one pointer. Here is how to provide the glue between your code and GIL:<p>
+<div class="fragment"><pre class="fragment"><span class="keywordtype">void</span> ComputeXGradientGray8(<span class="keyword">const</span> <span class="keywordtype">unsigned</span> <span class="keywordtype">char</span>* src_pixels, ptrdiff_t src_row_bytes, <span class="keywordtype">int</span> w, <span class="keywordtype">int</span> h,
+ <span class="keywordtype">signed</span> <span class="keywordtype">char</span>* dst_pixels, ptrdiff_t dst_row_bytes) {
+ gray8c_view_t src = <a class="code" href="http://opensource.adobe.com/gil/html/group___image_view_constructors.html#ga5">interleaved_view</a>(w, h, (<span class="keyword">const</span> gray8_pixel_t*)src_pixels,src_row_bytes);
+ gray8s_view_t dst = <a class="code" href="http://opensource.adobe.com/gil/html/group___image_view_constructors.html#ga5">interleaved_view</a>(w, h, ( gray8s_pixel_t*)dst_pixels,dst_row_bytes);
+ x_gradient(src,dst);
+}
+</pre></div><p>
+This glue code is very fast and views are lightweight - in the above example the views have a size of 16 bytes. They consist of a pointer to the top left pixel and three integers - the width, height, and number of bytes per row.<h3><a class="anchor" name="FirstImplementationSec">
+First Implementation</a></h3>
+Focusing on simplicity at the expense of speed, we can compute the horizontal gradient like this:<p>
+<div class="fragment"><pre class="fragment"><span class="keywordtype">void</span> x_gradient(<span class="keyword">const</span> gray8c_view_t& src, <span class="keyword">const</span> gray8s_view_t& dst) {
+ <span class="keywordflow">for</span> (<span class="keywordtype">int</span> y=0; y<src.height(); ++y)
+ <span class="keywordflow">for</span> (<span class="keywordtype">int</span> x=1; x<src.width()-1; ++x)
+ dst(x,y) = (src(x-1,y) - src(x+1,y)) / 2;
+}
+</pre></div><p>
+We use image view's <code>operator(x,y)</code> to get a reference to the pixel at a given location and we set it to the half-difference of its left and right neighbors. operator() returns a reference to a grayscale pixel. A grayscale pixel is convertible to its channel type (<code>unsigned char</code> for <code>src</code>) and it can be copy-constructed from a channel. (This is only true for grayscale pixels). While the above code is easy to read, it is not very fast, because the binary <code>operator()</code> computes the location of the pixel in a 2D grid, which involves addition and multiplication. Here is a faster version of the above:<p>
+<div class="fragment"><pre class="fragment"><span class="keywordtype">void</span> x_gradient(<span class="keyword">const</span> gray8c_view_t& src, <span class="keyword">const</span> gray8s_view_t& dst) {
+ <span class="keywordflow">for</span> (<span class="keywordtype">int</span> y=0; y<src.height(); ++y) {
+ gray8c_view_t::x_iterator src_it = src.row_begin(y);
+ gray8s_view_t::x_iterator dst_it = dst.row_begin(y);
+
+ <span class="keywordflow">for</span> (<span class="keywordtype">int</span> x=1; x<src.width()-1; ++x)
+ dst_it[x] = (src_it[x-1] - src_it[x+1]) / 2;
+ }
+}
+</pre></div><p>
+We use pixel iterators initialized at the beginning of each row. GIL's iterators are Random Access Traversal iterators. If you are not familiar with random access iterators, think of them as if they were pointers. In fact, in the above example the two iterator types are raw C pointers and their <code>operator[]</code> is a fast pointer indexing operator.<p>
+The code to compute gradient in the vertical direction is very similar:<p>
+<div class="fragment"><pre class="fragment"><span class="keywordtype">void</span> y_gradient(<span class="keyword">const</span> gray8c_view_t& src, <span class="keyword">const</span> gray8s_view_t& dst) {
+ <span class="keywordflow">for</span> (<span class="keywordtype">int</span> x=0; x<src.width(); ++x) {
+ gray8c_view_t::y_iterator src_it = src.col_begin(x);
+ gray8s_view_t::y_iterator dst_it = dst.col_begin(x);
+
+ <span class="keywordflow">for</span> (<span class="keywordtype">int</span> y=1; y<src.height()-1; ++y)
+ dst_it[y] = (src_it[y-1] - src_it[y+1])/2;
+ }
+}
+</pre></div><p>
+Instead of looping over the rows, we loop over each column and create a <code>y_iterator</code>, an iterator moving vertically. In this case a simple pointer cannot be used because the distance between two adjacent pixels equals the number of bytes in each row of the image. GIL uses here a special step iterator class whose size is 8 bytes - it contains a raw C pointer and a step. Its <code>operator[]</code> multiplies the index by its step.<p>
+The above version of <code>y_gradient</code>, however, is much slower (easily an order of magnitude slower) than <code>x_gradient</code> because of the memory access pattern; traversing an image vertically results in lots of cache misses. A much more efficient and cache-friendly version will iterate over the columns in the inner loop:<p>
+<div class="fragment"><pre class="fragment"><span class="keywordtype">void</span> y_gradient(<span class="keyword">const</span> gray8c_view_t& src, <span class="keyword">const</span> gray8s_view_t& dst) {
+ <span class="keywordflow">for</span> (<span class="keywordtype">int</span> y=1; y<src.height()-1; ++y) {
+ gray8c_view_t::x_iterator src1_it = src.row_begin(y-1);
+ gray8c_view_t::x_iterator src2_it = src.row_begin(y+1);
+ gray8s_view_t::x_iterator dst_it = dst.row_begin(y);
+
+ <span class="keywordflow">for</span> (<span class="keywordtype">int</span> x=0; x<src.width(); ++x) {
+ *dst_it = ((*src1_it) - (*src2_it))/2;
+ ++dst_it;
+ ++src1_it;
+ ++src2_it;
+ }
+ }
+}
+</pre></div><p>
+This sample code also shows an alternative way of using pixel iterators - instead of <code>operator[]</code> one could use increments and dereferences.<h3><a class="anchor" name="LocatorsSec">
+Using Locators</a></h3>
+Unfortunately this cache-friendly version requires the extra hassle of maintaining two separate iterators in the source view. For every pixel, we want to access its neighbors above and below it. Such relative access can be done with GIL locators:<p>
+<div class="fragment"><pre class="fragment"><span class="keywordtype">void</span> y_gradient(<span class="keyword">const</span> gray8c_view_t& src, <span class="keyword">const</span> gray8s_view_t& dst) {
+ gray8c_view_t::xy_locator src_loc = src.xy_at(0,1);
+ <span class="keywordflow">for</span> (<span class="keywordtype">int</span> y=1; y<src.height()-1; ++y) {
+ gray8s_view_t::x_iterator dst_it = dst.row_begin(y);
+
+ <span class="keywordflow">for</span> (<span class="keywordtype">int</span> x=0; x<src.width(); ++x) {
+ (*dst_it) = (src_loc(0,-1) - src_loc(0,1)) / 2;
+ ++dst_it;
+ ++src_loc.x(); <span class="comment">// each dimension can be advanced separately</span>
+ }
+ src_loc+=point2<std::ptrdiff_t>(-src.width(),1); <span class="comment">// carriage return</span>
+ }
+}
+</pre></div><p>
+The first line creates a locator pointing to the first pixel of the second row of the source view. A GIL pixel locator is very similar to an iterator, except that it can move both horizontally and vertically. <code>src_loc.x()</code> and <code>src_loc.y()</code> return references to a horizontal and a vertical iterator respectively, which can be used to move the locator along the desired dimension, as shown above. Additionally, the locator can be advanced in both dimensions simultaneously using its <code>operator+=</code> and <code>operator-=</code>. Similar to image views, locators provide binary <code>operator()</code> which returns a reference to a pixel with a relative offset to the current locator position. For example, <code>src_loc(0,1)</code> returns a reference to the neighbor below the current pixel. Locators are very lightweight objects - in the above example the locator has a size of 8 bytes - it consists of a raw pointer to the current pixel and an int indicating the number of bytes from one ro
w to the next (which is the step when moving vertically). The call to <code>++src_loc</code>.x() corresponds to a single C pointer increment. However, the example above performs more computations than necessary. The code src_loc(0,1) has to compute the offset of the pixel in two dimensions, which is slow. Notice though that the offset of the two neighbors is the same, regardless of the pixel location. To improve the performance, GIL can cache and reuse this offset:<p>
+<div class="fragment"><pre class="fragment"><span class="keywordtype">void</span> y_gradient(<span class="keyword">const</span> gray8c_view_t& src, <span class="keyword">const</span> gray8s_view_t& dst) {
+ gray8c_view_t::xy_locator src_loc = src.xy_at(0,1);
+ gray8c_view_t::xy_locator::cached_location_t above = src_loc.cache_location(0,-1);
+ gray8c_view_t::xy_locator::cached_location_t below = src_loc.cache_location(0, 1);
+
+ <span class="keywordflow">for</span> (<span class="keywordtype">int</span> y=1; y<src.height()-1; ++y) {
+ gray8s_view_t::x_iterator dst_it = dst.row_begin(y);
+
+ <span class="keywordflow">for</span> (<span class="keywordtype">int</span> x=0; x<src.width(); ++x) {
+ (*dst_it) = (src_loc[above] - src_loc[below])/2;
+ ++dst_it;
+ ++src_loc.x();
+ }
+ src_loc+=point2<std::ptrdiff_t>(-src.width(),1);
+ }
+}
+</pre></div><p>
+In this example <code>"src_loc[above]"</code> corresponds to a fast pointer indexing operation and the code is efficient.<h3><a class="anchor" name="GenericVersionSec">
+Creating a Generic Version of GIL Algorithms</a></h3>
+Let us make our <code>x_gradient</code> more generic. It should work with any image views, as long as they have the same number of channels. The gradient operation is to be computed for each channel independently. Here is how the new interface looks like:<p>
+<div class="fragment"><pre class="fragment"><span class="keyword">template</span> <<span class="keyword">typename</span> SrcView, <span class="keyword">typename</span> DstView>
+<span class="keywordtype">void</span> x_gradient(<span class="keyword">const</span> SrcView& src, <span class="keyword">const</span> DstView& dst) {
+ gil_function_requires<ImageViewConcept<SrcView> >();
+ gil_function_requires<MutableImageViewConcept<DstView> >();
+ gil_function_requires<ColorSpacesCompatibleConcept<
+ <span class="keyword">typename</span> color_space_type<SrcView>::type,
+ <span class="keyword">typename</span> color_space_type<DstView>::type> >();
+
+ ... <span class="comment">// compute the gradient</span>
+}
+</pre></div><p>
+The new algorithm now takes the types of the input and output image views as template parameters. That allows using both built-in GIL image views, as well as any user-defined image view classes. The first three lines are optional; they use <code>boost::concept_check</code> to ensure that the two arguments are valid GIL image views, that the second one is mutable and that their color spaces are compatible (i.e. have the same set of channels).<p>
+GIL does not require using its own built-in constructs. You are free to use your own channels, color spaces, iterators, locators, views and images. However, to work with the rest of GIL they have to satisfy a set of requirements; in other words, they have to <em>model</em> the corresponding GIL <em>concept</em>. GIL's concepts are defined in the user guide.<p>
+One of the biggest drawbacks of using templates and generic programming in C++ is that compile errors can be very difficult to comprehend. This is a side-effect of the lack of early type checking - a generic argument may not satisfy the requirements of a function, but the incompatibility may be triggered deep into a nested call, in code unfamiliar and hardly related to the problem. GIL uses <code>boost::concept_check</code> to mitigate this problem. The above three lines of code check whether the template parameters are valid models of their corresponding concepts. If a model is incorrect, the compile error will be inside <code>gil_function_requires</code>, which is much closer to the problem and easier to track. Furthermore, such checks get compiled out and have zero performance overhead. The disadvantage of using concept checks is the sometimes severe impact they have on compile time. This is why GIL performs concept checks only in debug mode, and only if <code>BOOST_GIL_USE_CONCEPT_CHECK</code> is define
d (off by default).<p>
+The body of the generic function is very similar to that of the concrete one. The biggest difference is that we need to loop over the channels of the pixel and compute the gradient for each channel:<p>
+<div class="fragment"><pre class="fragment"><span class="keyword">template</span> <<span class="keyword">typename</span> SrcView, <span class="keyword">typename</span> DstView>
+<span class="keywordtype">void</span> x_gradient(<span class="keyword">const</span> SrcView& src, <span class="keyword">const</span> DstView& dst) {
+ <span class="keywordflow">for</span> (<span class="keywordtype">int</span> y=0; y<src.height(); ++y) {
+ <span class="keyword">typename</span> SrcView::x_iterator src_it = src.row_begin(y);
+ <span class="keyword">typename</span> DstView::x_iterator dst_it = dst.row_begin(y);
+
+ <span class="keywordflow">for</span> (<span class="keywordtype">int</span> x=1; x<src.width()-1; ++x)
+ <span class="keywordflow">for</span> (<span class="keywordtype">int</span> c=0; c<num_channels<SrcView>::value; ++c)
+ dst_it[x][c] = (src_it[x-1][c]- src_it[x+1][c])/2;
+ }
+}
+</pre></div><p>
+Having an explicit loop for each channel could be a performance problem. GIL allows us to abstract out such per-channel operations:<p>
+<div class="fragment"><pre class="fragment"><span class="keyword">template</span> <<span class="keyword">typename</span> Out>
+<span class="keyword">struct </span>halfdiff_cast_channels {
+ <span class="keyword">template</span> <<span class="keyword">typename</span> T> Out operator()(<span class="keyword">const</span> T& in1, <span class="keyword">const</span> T& in2)<span class="keyword"> const </span>{
+ <span class="keywordflow">return</span> Out((in1-in2)/2);
+ }
+};
+
+<span class="keyword">template</span> <<span class="keyword">typename</span> SrcView, <span class="keyword">typename</span> DstView>
+<span class="keywordtype">void</span> x_gradient(<span class="keyword">const</span> SrcView& src, <span class="keyword">const</span> DstView& dst) {
+ <span class="keyword">typedef</span> <span class="keyword">typename</span> channel_type<DstView>::type dst_channel_t;
+
+ <span class="keywordflow">for</span> (<span class="keywordtype">int</span> y=0; y<src.height(); ++y) {
+ <span class="keyword">typename</span> SrcView::x_iterator src_it = src.row_begin(y);
+ <span class="keyword">typename</span> DstView::x_iterator dst_it = dst.row_begin(y);
+
+ <span class="keywordflow">for</span> (<span class="keywordtype">int</span> x=1; x<src.width()-1; ++x)
+ static_transform(src_it[x-1], src_it[x+1], dst_it[x],
+ halfdiff_cast_channels<dst_channel_t>());
+ }
+}
+</pre></div><p>
+<code>static_transform</code> is an example of a channel-level GIL algorithm. Other such algorithms are <code>static_generate</code>, <code>static_fill</code> and <code>static_for_each</code>. They are the channel-level equivalents of STL's <code>generate</code>, <code>transform</code>, <code>fill</code> and <code>for_each</code> respectively. GIL channel algorithms use static recursion to unroll the loops; they never loop over the channels explicitly. Note that sometimes modern compilers (at least Visual Studio 8) already unroll channel-level loops, such as the one above. However, another advantage of using GIL's channel-level algorithms is that they pair the channels semantically, not based on their order in memory. For example, the above example will properly match an RGB source with a BGR destination.<p>
+Here is how we can use our generic version with images of different types:<p>
+<div class="fragment"><pre class="fragment"><span class="comment">// Calling with 16-bit grayscale data</span>
+<span class="keywordtype">void</span> XGradientGray16_Gray32(<span class="keyword">const</span> <span class="keywordtype">unsigned</span> <span class="keywordtype">short</span>* src_pixels, ptrdiff_t src_row_bytes, <span class="keywordtype">int</span> w, <span class="keywordtype">int</span> h,
+ <span class="keywordtype">signed</span> <span class="keywordtype">int</span>* dst_pixels, ptrdiff_t dst_row_bytes) {
+ gray16c_view_t src=<a class="code" href="http://opensource.adobe.com/gil/html/group___image_view_constructors.html#ga5">interleaved_view</a>(w,h,(<span class="keyword">const</span> gray16_pixel_t*)src_pixels,src_row_bytes);
+ gray32s_view_t dst=<a class="code" href="http://opensource.adobe.com/gil/html/group___image_view_constructors.html#ga5">interleaved_view</a>(w,h,( gray32s_pixel_t*)dst_pixels,dst_row_bytes);
+ x_gradient(src,dst);
+}
+
+<span class="comment">// Calling with 8-bit RGB data into 16-bit BGR</span>
+<span class="keywordtype">void</span> XGradientRGB8_BGR16(<span class="keyword">const</span> <span class="keywordtype">unsigned</span> <span class="keywordtype">char</span>* src_pixels, ptrdiff_t src_row_bytes, <span class="keywordtype">int</span> w, <span class="keywordtype">int</span> h,
+ <span class="keywordtype">signed</span> <span class="keywordtype">short</span>* dst_pixels, ptrdiff_t dst_row_bytes) {
+ rgb8c_view_t src = <a class="code" href="http://opensource.adobe.com/gil/html/group___image_view_constructors.html#ga5">interleaved_view</a>(w,h,(<span class="keyword">const</span> rgb8_pixel_t*)src_pixels,src_row_bytes);
+ rgb16s_view_t dst = <a class="code" href="http://opensource.adobe.com/gil/html/group___image_view_constructors.html#ga5">interleaved_view</a>(w,h,( rgb16s_pixel_t*)dst_pixels,dst_row_bytes);
+ x_gradient(src,dst);
+}
+
+<span class="comment">// Either or both the source and the destination could be planar - the gradient code does not change</span>
+<span class="keywordtype">void</span> XGradientPlanarRGB8_RGB32(
+ <span class="keyword">const</span> <span class="keywordtype">unsigned</span> <span class="keywordtype">short</span>* src_r, <span class="keyword">const</span> <span class="keywordtype">unsigned</span> <span class="keywordtype">short</span>* src_g, <span class="keyword">const</span> <span class="keywordtype">unsigned</span> <span class="keywordtype">short</span>* src_b,
+ ptrdiff_t src_row_bytes, <span class="keywordtype">int</span> w, <span class="keywordtype">int</span> h,
+ <span class="keywordtype">signed</span> <span class="keywordtype">int</span>* dst_pixels, ptrdiff_t dst_row_bytes) {
+ rgb16c_planar_view_t src=<a class="code" href="http://opensource.adobe.com/gil/html/group___image_view_constructors.html#ga9">planar_rgb_view</a> (w,h, src_r,src_g,src_b, src_row_bytes);
+ rgb32s_view_t dst=<a class="code" href="http://opensource.adobe.com/gil/html/group___image_view_constructors.html#ga5">interleaved_view</a>(w,h,(rgb32s_pixel_t*)dst_pixels,dst_row_bytes);
+ x_gradient(src,dst);
+}
+</pre></div><p>
+As these examples illustrate, both the source and the destination can be interleaved or planar, of any channel depth (assuming the destination channel is assignable to the source), and of any compatible color spaces.<p>
+GIL 2.1 can also natively represent images whose channels are not byte-aligned, such as 6-bit RGB222 image or a 1-bit Gray1 image. GIL algorithms apply to these images natively. See the design guide or sample files for more on using such images.<h3><a class="anchor" name="ImageViewTransformationSec">
+Image View Transformations</a></h3>
+One way to compute the y-gradient is to rotate the image by 90 degrees, compute the x-gradient and rotate the result back. Here is how to do this in GIL:<p>
+<div class="fragment"><pre class="fragment"><span class="keyword">template</span> <<span class="keyword">typename</span> SrcView, <span class="keyword">typename</span> DstView>
+<span class="keywordtype">void</span> y_gradient(<span class="keyword">const</span> SrcView& src, <span class="keyword">const</span> DstView& dst) {
+ x_gradient(rotated90ccw_view(src), rotated90ccw_view(dst));
+}
+</pre></div><p>
+<code>rotated90ccw_view</code> takes an image view and returns an image view representing 90-degrees counter-clockwise rotation of its input. It is an example of a GIL view transformation function. GIL provides a variety of transformation functions that can perform any axis-aligned rotation, transpose the view, flip it vertically or horizontally, extract a rectangular subimage, perform color conversion, subsample view, etc. The view transformation functions are fast and shallow - they don't copy the pixels, they just change the "coordinate system" of accessing the pixels. <code>rotated90cw_view</code>, for example, returns a view whose horizontal iterators are the vertical iterators of the original view. The above code to compute <code>y_gradient</code> is slow because of the memory access pattern; using <code>rotated90cw_view</code> does not make it any slower.<p>
+Another example: suppose we want to compute the gradient of the N-th channel of a color image. Here is how to do that:<p>
+<div class="fragment"><pre class="fragment"><span class="keyword">template</span> <<span class="keyword">typename</span> SrcView, <span class="keyword">typename</span> DstView>
+<span class="keywordtype">void</span> nth_channel_x_gradient(<span class="keyword">const</span> SrcView& src, <span class="keywordtype">int</span> n, <span class="keyword">const</span> DstView& dst) {
+ x_gradient(nth_channel_view(src, n), dst);
+}
+</pre></div><p>
+<code>nth_channel_view</code> is a view transformation function that takes any view and returns a single-channel (grayscale) view of its N-th channel. For interleaved RGB view, for example, the returned view is a step view - a view whose horizontal iterator skips over two channels when incremented. If applied on a planar RGB view, the returned type is a simple grayscale view whose horizontal iterator is a C pointer. Image view transformation functions can be piped together. For example, to compute the y gradient of the second channel of the even pixels in the view, use:<p>
+<div class="fragment"><pre class="fragment">y_gradient(subsampled_view(nth_channel_view(src, 1), 2,2), dst);
+</pre></div><p>
+GIL can sometimes simplify piped views. For example, two nested subsampled views (views that skip over pixels in X and in Y) can be represented as a single subsampled view whose step is the product of the steps of the two views.<h3><a class="anchor" name="OneDIteratorsSec">
+1D pixel iterators</a></h3>
+Let's go back to <code>x_gradient</code> one more time. Many image view algorithms apply the same operation for each pixel and GIL provides an abstraction to handle them. However, our algorithm has an unusual access pattern, as it skips the first and the last column. It would be nice and instructional to see how we can rewrite it in canonical form. The way to do that in GIL is to write a version that works for every pixel, but apply it only on the subimage that excludes the first and last column:<p>
+<div class="fragment"><pre class="fragment"><span class="keywordtype">void</span> x_gradient_unguarded(<span class="keyword">const</span> gray8c_view_t& src, <span class="keyword">const</span> gray8s_view_t& dst) {
+ <span class="keywordflow">for</span> (<span class="keywordtype">int</span> y=0; y<src.height(); ++y) {
+ gray8c_view_t::x_iterator src_it = src.row_begin(y);
+ gray8s_view_t::x_iterator dst_it = dst.row_begin(y);
+
+ <span class="keywordflow">for</span> (<span class="keywordtype">int</span> x=0; x<src.width(); ++x)
+ dst_it[x] = (src_it[x-1] - src_it[x+1]) / 2;
+ }
+}
+
+<span class="keywordtype">void</span> x_gradient(<span class="keyword">const</span> gray8c_view_t& src, <span class="keyword">const</span> gray8s_view_t& dst) {
+ assert(src.width()>=2);
+ x_gradient_unguarded(subimage_view(src, 1, 0, src.width()-2, src.height()),
+ subimage_view(dst, 1, 0, src.width()-2, src.height()));
+}
+</pre></div><p>
+<code>subimage_view</code> is another example of a GIL view transformation function. It takes a source view and a rectangular region (in this case, defined as x_min,y_min,width,height) and returns a view operating on that region of the source view. The above implementation has no measurable performance degradation from the version that operates on the original views.<p>
+Now that <code>x_gradient_unguarded</code> operates on every pixel, we can rewrite it more compactly:<p>
+<div class="fragment"><pre class="fragment"><span class="keywordtype">void</span> x_gradient_unguarded(<span class="keyword">const</span> gray8c_view_t& src, <span class="keyword">const</span> gray8s_view_t& dst) {
+ gray8c_view_t::iterator src_it = src.begin();
+ <span class="keywordflow">for</span> (gray8s_view_t::iterator dst_it = dst.begin(); dst_it!=dst.end(); ++dst_it, ++src_it)
+ *dst_it = (src_it.x()[-1] - src_it.x()[1]) / 2;
+}
+</pre></div><p>
+GIL image views provide <code>begin()</code> and <code>end()</code> methods that return one dimensional pixel iterators which iterate over each pixel in the view, left to right and top to bottom. They do a proper "carriage return" - they skip any unused bytes at the end of a row. As such, they are slightly suboptimal, because they need to keep track of their current position with respect to the end of the row. Their increment operator performs one extra check (are we at the end of the row?), a check that is avoided if two nested loops are used instead. These iterators have a method <code>x()</code> which returns the more lightweight horizontal iterator that we used previously. Horizontal iterators have no notion of the end of rows. In this case, the horizontal iterators are raw C pointers. In our example, we must use the horizontal iterators to access the two neighbors properly, since they could reside outside the image view.<h3><a class="anchor" name="STLEquivalentsSec">
+STL Equivalent Algorithms</a></h3>
+GIL provides STL equivalents of many algorithms. For example, <code>std::transform</code> is an STL algorithm that sets each element in a destination range the result of a generic function taking the corresponding element of the source range. In our example, we want to assign to each destination pixel the value of the half-difference of the horizontal neighbors of the corresponding source pixel. If we abstract that operation in a function object, we can use GIL's <code>transform_pixel_positions</code> to do that:<p>
+<div class="fragment"><pre class="fragment"><span class="keyword">struct </span>half_x_difference {
+ <span class="keywordtype">int</span> operator()(<span class="keyword">const</span> gray8c_loc_t& src_loc)<span class="keyword"> const </span>{
+ <span class="keywordflow">return</span> (src_loc.x()[-1] - src_loc.x()[1]) / 2;
+ }
+};
+
+<span class="keywordtype">void</span> x_gradient_unguarded(<span class="keyword">const</span> gray8c_view_t& src, <span class="keyword">const</span> gray8s_view_t& dst) {
+ <a class="code" href="http://opensource.adobe.com/gil/html/group___image_view_s_t_l_algorithms_transform_pixel_positions.html#ga0">transform_pixel_positions</a>(src, dst, half_x_difference());
+}
+</pre></div><p>
+GIL provides the algorithms <code>for_each_pixel</code> and <code>transform_pixels</code> which are image view equivalents of STL's <code>std::for_each</code> and <code>std::transform</code>. It also provides <code>for_each_pixel_position</code> and <code>transform_pixel_positions</code>, which instead of references to pixels, pass to the generic function pixel locators. This allows for more powerful functions that can use the pixel neighbors through the passed locators. GIL algorithms iterate through the pixels using the more efficient two nested loops (as opposed to the single loop using 1-D iterators)<h3><a class="anchor" name="ColorConversionSec">
+Color Conversion</a></h3>
+Instead of computing the gradient of each color plane of an image, we often want to compute the gradient of the luminosity. In other words, we want to convert the color image to grayscale and compute the gradient of the result. Here how to compute the luminosity gradient of a 32-bit float RGB image:<p>
+<div class="fragment"><pre class="fragment"><span class="keywordtype">void</span> x_gradient_rgb_luminosity(<span class="keyword">const</span> rgb32fc_view_t& src, <span class="keyword">const</span> gray8s_view_t& dst) {
+ x_gradient(color_converted_view<gray8_pixel_t>(src), dst);
+}
+</pre></div><p>
+<code>color_converted_view</code> is a GIL view transformation function that takes any image view and returns a view in a target color space and channel depth (specified as template parameters). In our example, it constructs an 8-bit integer grayscale view over 32-bit float RGB pixels. Like all other view transformation functions, <code>color_converted_view</code> is very fast and shallow. It doesn't copy the data or perform any color conversion. Instead it returns a view that performs color conversion every time its pixels are accessed.<p>
+In the generic version of this algorithm we might like to convert the color space to grayscale, but keep the channel depth the same. We do that by constructing the type of a GIL grayscale pixel with the same channel as the source, and color convert to that pixel type:<p>
+<div class="fragment"><pre class="fragment"><span class="keyword">template</span> <<span class="keyword">typename</span> SrcView, <span class="keyword">typename</span> DstView>
+<span class="keywordtype">void</span> x_luminosity_gradient(<span class="keyword">const</span> SrcView& src, <span class="keyword">const</span> DstView& dst) {
+ <span class="keyword">typedef</span> pixel<typename channel_type<SrcView>::type, gray_layout_t> gray_pixel_t;
+ x_gradient(color_converted_view<gray_pixel_t>(src), dst);
+}
+</pre></div><p>
+When the destination color space and channel type happens to be the same as the source one, color conversion is unnecessary. GIL detects this case and avoids calling the color conversion code at all - i.e. <code>color_converted_view</code> returns back the source view unchanged.<h3><a class="anchor" name="ImagesSec">
+Image</a></h3>
+The above example has a performance problem - <code>x_gradient</code> dereferences most source pixels twice, which will cause the above code to perform color conversion twice. Sometimes it may be more efficient to copy the color converted image into a temporary buffer and use it to compute the gradient - that way color conversion is invoked once per pixel. Using our non-generic version we can do it like this:<p>
+<div class="fragment"><pre class="fragment"><span class="keywordtype">void</span> x_luminosity_gradient(<span class="keyword">const</span> rgb32fc_view_t& src, <span class="keyword">const</span> gray8s_view_t& dst) {
+ gray8_image_t ccv_image(src.dimensions());
+ <a class="code" href="http://opensource.adobe.com/gil/html/group___image_view_s_t_l_algorithms_copy_pixels.html#ga0">copy_pixels</a>(color_converted_view<gray8_pixel_t>(src), <a class="code" href="http://opensource.adobe.com/gil/html/group___image_model.html#ga0">view</a>(ccv_image));
+
+ x_gradient(<a class="code" href="http://opensource.adobe.com/gil/html/group___image_model.html#ga3">const_view</a>(ccv_image), dst);
+}
+</pre></div><p>
+First we construct an 8-bit grayscale image with the same dimensions as our source. Then we copy a color-converted view of the source into the temporary image. Finally we use a read-only view of the temporary image in our <code>x_gradient</code> algorithm. As the example shows, GIL provides global functions <code>view</code> and <code>const_view</code> that take an image and return a mutable or an immutable view of its pixels.<p>
+Creating a generic version of the above is a bit trickier:<p>
+<div class="fragment"><pre class="fragment"><span class="keyword">template</span> <<span class="keyword">typename</span> SrcView, <span class="keyword">typename</span> DstView>
+<span class="keywordtype">void</span> x_luminosity_gradient(<span class="keyword">const</span> SrcView& src, <span class="keyword">const</span> DstView& dst) {
+ <span class="keyword">typedef</span> <span class="keyword">typename</span> channel_type<DstView>::type d_channel_t;
+ <span class="keyword">typedef</span> <span class="keyword">typename</span> channel_convert_to_unsigned<d_channel_t>::type channel_t;
+ <span class="keyword">typedef</span> pixel<channel_t, gray_layout_t> gray_pixel_t;
+ <span class="keyword">typedef</span> image<gray_pixel_t, false> gray_image_t;
+
+ gray_image_t ccv_image(src.dimensions());
+ <a class="code" href="http://opensource.adobe.com/gil/html/group___image_view_s_t_l_algorithms_copy_pixels.html#ga0">copy_pixels</a>(color_converted_view<gray_pixel_t>(src), <a class="code" href="http://opensource.adobe.com/gil/html/group___image_model.html#ga0">view</a>(ccv_image));
+ x_gradient(<a class="code" href="http://opensource.adobe.com/gil/html/group___image_model.html#ga3">const_view</a>(ccv_image), dst);
+}
+</pre></div><p>
+First we use the <code>channel_type</code> metafunction to get the channel type of the destination view. A metafunction is a function operating on types. In GIL metafunctions are structs which take their parameters as template parameters and return their result in a nested typedef called <code>type</code>. In this case, <code>channel_type</code> is a unary metafunction which in this example is called with the type of an image view and returns the type of the channel associated with that image view.<p>
+GIL constructs that have an associated pixel type, such as pixels, pixel iterators, locators, views and images, all model <code>PixelBasedConcept</code>, which means that they provide a set of metafunctions to query the pixel properties, such as <code>channel_type</code>, <code>color_space_type</code>, <code>channel_mapping_type</code>, and <code>num_channels</code>.<p>
+After we get the channel type of the destination view, we use another metafunction to remove its sign (if it is a signed integral type) and then use it to generate the type of a grayscale pixel. From the pixel type we create the image type. GIL's image class is templated over the pixel type and a boolean indicating whether the image should be planar or interleaved. Single-channel (grayscale) images in GIL must always be interleaved. There are multiple ways of constructing types in GIL. Instead of instantiating the classes directly we could have used type factory metafunctions. The following code is equivalent:<p>
+<div class="fragment"><pre class="fragment"><span class="keyword">template</span> <<span class="keyword">typename</span> SrcView, <span class="keyword">typename</span> DstView>
+<span class="keywordtype">void</span> x_luminosity_gradient(<span class="keyword">const</span> SrcView& src, <span class="keyword">const</span> DstView& dst) {
+ <span class="keyword">typedef</span> <span class="keyword">typename</span> channel_type<DstView>::type d_channel_t;
+ <span class="keyword">typedef</span> <span class="keyword">typename</span> channel_convert_to_unsigned<d_channel_t>::type channel_t;
+ <span class="keyword">typedef</span> <span class="keyword">typename</span> image_type<channel_t, gray_layout_t>::type gray_image_t;
+ <span class="keyword">typedef</span> <span class="keyword">typename</span> gray_image_t::value_type gray_pixel_t;
+
+ gray_image_t ccv_image(src.dimensions());
+ copy_and_convert_pixels(src, <a class="code" href="http://opensource.adobe.com/gil/html/group___image_model.html#ga0">view</a>(ccv_image));
+ x_gradient(<a class="code" href="http://opensource.adobe.com/gil/html/group___image_model.html#ga3">const_view</a>(ccv_image), dst);
+}
+</pre></div><p>
+GIL provides a set of metafunctions that generate GIL types - <code>image_type</code> is one such meta-function that constructs the type of an image from a given channel type, color layout, and planar/interleaved option (the default is interleaved). There are also similar meta-functions to construct the types of pixel references, iterators, locators and image views. GIL also has metafunctions <code>derived_pixel_reference_type</code>, <code>derived_iterator_type</code>, <code>derived_view_type</code> and <code>derived_image_type</code> that construct the type of a GIL construct from a given source one by changing one or more properties of the type and keeping the rest.<p>
+From the image type we can use the nested typedef <code>value_type</code> to obtain the type of a pixel. GIL images, image views and locators have nested typedefs <code>value_type</code> and <code>reference</code> to obtain the type of the pixel and a reference to the pixel. If you have a pixel iterator, you can get these types from its <code>iterator_traits</code>. Note also the algorithm <code>copy_and_convert_pixels</code>, which is an abbreviated version of <code>copy_pixels</code> with a color converted source view.<h3><a class="anchor" name="VirtualViewSec">
+Virtual Image Views</a></h3>
+So far we have been dealing with images that have pixels stored in memory. GIL allows you to create an image view of an arbitrary image, including a synthetic function. To demonstrate this, let us create a view of the Mandelbrot set. First, we need to create a function object that computes the value of the Mandelbrot set at a given location (x,y) in the image: <div class="fragment"><pre class="fragment"><span class="comment">// models PixelDereferenceAdaptorConcept</span>
+<span class="keyword">struct </span>mandelbrot_fn {
+ <span class="keyword">typedef</span> point2<ptrdiff_t> point_t;
+
+ <span class="keyword">typedef</span> mandelbrot_fn const_t;
+ <span class="keyword">typedef</span> gray8_pixel_t value_type;
+ <span class="keyword">typedef</span> value_type reference;
+ <span class="keyword">typedef</span> value_type const_reference;
+ <span class="keyword">typedef</span> point_t argument_type;
+ <span class="keyword">typedef</span> reference result_type;
+ BOOST_STATIC_CONSTANT(<span class="keywordtype">bool</span>, is_mutable=<span class="keyword">false</span>);
+
+ mandelbrot_fn() {}
+ mandelbrot_fn(<span class="keyword">const</span> point_t& sz) : _img_size(sz) {}
+
+ result_type operator()(<span class="keyword">const</span> point_t& p)<span class="keyword"> const </span>{
+ <span class="comment">// normalize the coords to (-2..1, -1.5..1.5)</span>
+ <span class="keywordtype">double</span> t=get_num_iter(point2<double>(p.x/(<span class="keywordtype">double</span>)_img_size.x*3-2, p.y/(<span class="keywordtype">double</span>)_img_size.y*3-1.5f));
+ <span class="keywordflow">return</span> value_type((bits8)(pow(t,0.2)*255)); <span class="comment">// raise to power suitable for viewing</span>
+ }
+<span class="keyword">private</span>:
+ point_t _img_size;
+
+ <span class="keywordtype">double</span> get_num_iter(<span class="keyword">const</span> point2<double>& p)<span class="keyword"> const </span>{
+ point2<double> Z(0,0);
+ <span class="keywordflow">for</span> (<span class="keywordtype">int</span> i=0; i<100; ++i) { <span class="comment">// 100 iterations</span>
+ Z = point2<double>(Z.x*Z.x - Z.y*Z.y + p.x, 2*Z.x*Z.y + p.y);
+ <span class="keywordflow">if</span> (Z.x*Z.x + Z.y*Z.y > 4)
+ <span class="keywordflow">return</span> i/(double)100;
+ }
+ <span class="keywordflow">return</span> 0;
+ }
+};
+</pre></div><p>
+We can now use GIL's <code>virtual_2d_locator</code> with this function object to construct a Mandelbrot view of size 200x200 pixels: <div class="fragment"><pre class="fragment"><span class="keyword">typedef</span> mandelbrot_fn::point_t point_t;
+<span class="keyword">typedef</span> virtual_2d_locator<mandelbrot_fn,false> locator_t;
+<span class="keyword">typedef</span> image_view<locator_t> my_virt_view_t;
+
+point_t dims(200,200);
+
+<span class="comment">// Construct a Mandelbrot view with a locator, taking top-left corner (0,0) and step (1,1)</span>
+my_virt_view_t mandel(dims, locator_t(point_t(0,0), point_t(1,1), mandelbrot_fn(dims)));
+</pre></div><p>
+We can treat the synthetic view just like a real one. For example, let's invoke our <code>x_gradient</code> algorithm to compute the gradient of the 90-degree rotated view of the Mandelbrot set and save the original and the result:<p>
+<div class="fragment"><pre class="fragment">gray8s_image_t img(dims);
+x_gradient(rotated90cw_view(mandel), <a class="code" href="http://opensource.adobe.com/gil/html/group___image_model.html#ga0">view</a>(img));
+
+<span class="comment">// Save the Mandelbrot set and its 90-degree rotated gradient (jpeg cannot save signed char; must convert to unsigned char)</span>
+<a class="code" href="http://opensource.adobe.com/gil/html/group___j_p_e_g___i_o.html#ga2">jpeg_write_view</a>(<span class="stringliteral">"mandel.jpg"</span>,mandel);
+<a class="code" href="http://opensource.adobe.com/gil/html/group___j_p_e_g___i_o.html#ga2">jpeg_write_view</a>(<span class="stringliteral">"mandel_grad.jpg"</span>,color_converted_view<gray8_pixel_t>(<a class="code" href="http://opensource.adobe.com/gil/html/group___image_model.html#ga3">const_view</a>(img)));
+</pre></div><p>
+Here is what the two files look like:<p>
+<div align="center">
+<img src="mandel.jpg" alt="mandel.jpg">
+</div>
+<h3><a class="anchor" name="DynamicImageSec">
+Run-Time Specified Images and Image Views</a></h3>
+So far we have created a generic function that computes the image gradient of a templated image view. Sometimes, however, the properties of an image view, such as its color space and channel depth, may not be available at compile time. GIL's <code>dynamic_image</code> extension allows for working with GIL constructs that are specified at run time, also called <em>variants</em>. GIL provides models of a run-time instantiated image, <code>any_image</code>, and a run-time instantiated image view, <code>any_image_view</code>. The mechanisms are in place to create other variants, such as <code>any_pixel</code>, <code>any_pixel_iterator</code>, etc. Most of GIL's algorithms and all of the view transformation functions also work with run-time instantiated image views and binary algorithms, such as <code>copy_pixels</code> can have either or both arguments be variants.<p>
+Lets make our <code>x_luminosity_gradient</code> algorithm take a variant image view. For simplicity, let's assume that only the source view can be a variant. (As an example of using multiple variants, see GIL's image view algorithm overloads taking multiple variants.)<p>
+First, we need to make a function object that contains the templated destination view and has an application operator taking a templated source view:<p>
+<div class="fragment"><pre class="fragment"><span class="preprocessor">#include <<a class="code" href="dynamic__image__all_8hpp.html">boost/gil/extension/dynamic_image/dynamic_image_all.hpp</a>></span>
+
+<span class="keyword">template</span> <<span class="keyword">typename</span> DstView>
+<span class="keyword">struct </span>x_gradient_obj {
+ <span class="keyword">typedef</span> <span class="keywordtype">void</span> result_type; <span class="comment">// required typedef</span>
+
+ <span class="keyword">const</span> DstView& _dst;
+ x_gradient_obj(<span class="keyword">const</span> DstView& dst) : _dst(dst) {}
+
+ <span class="keyword">template</span> <<span class="keyword">typename</span> SrcView>
+ <span class="keywordtype">void</span> operator()(<span class="keyword">const</span> SrcView& src)<span class="keyword"> const </span>{ x_luminosity_gradient(src, _dst); }
+};
+</pre></div><p>
+The second step is to provide an overload of <code>x_luminosity_gradient</code> that takes image view variant and calls GIL's <code>apply_operation</code> passing it the function object:<p>
+<div class="fragment"><pre class="fragment"><span class="keyword">template</span> <<span class="keyword">typename</span> SrcViews, <span class="keyword">typename</span> DstView>
+<span class="keywordtype">void</span> x_luminosity_gradient(<span class="keyword">const</span> any_image_view<SrcViews>& src, <span class="keyword">const</span> DstView& dst) {
+ <a class="code" href="http://opensource.adobe.com/gil/html/group___variant.html#ga0">apply_operation</a>(src, x_gradient_obj<DstView>(dst));
+}
+</pre></div><p>
+<code>any_image_view<SrcViews></code> is the image view variant. It is templated over <code>SrcViews</code>, an enumeration of all possible view types the variant can take. <code>src</code> contains inside an index of the currently instantiated type, as well as a block of memory containing the instance. <code>apply_operation</code> goes through a switch statement over the index, each case of which casts the memory to the correct view type and invokes the function object with it. Invoking an algorithm on a variant has the overhead of one switch statement. Algorithms that perform an operation for each pixel in an image view have practically no performance degradation when used with a variant.<p>
+Here is how we can construct a variant and invoke the algorithm:<p>
+<div class="fragment"><pre class="fragment"><span class="preprocessor">#include <boost/mpl/vector.hpp></span>
+<span class="preprocessor">#include <<a class="code" href="jpeg__dynamic__io_8hpp.html">boost/gil/extension/io/jpeg_dynamic_io.hpp</a>></span>
+
+<span class="keyword">typedef</span> mpl::vector<gray8_image_t, gray16_image_t, rgb8_image_t, rgb16_image_t> my_img_types;
+any_image<my_img_types> runtime_image;
+<a class="code" href="http://opensource.adobe.com/gil/html/group___j_p_e_g___i_o.html#ga0">jpeg_read_image</a>(<span class="stringliteral">"input.jpg"</span>, runtime_image);
+
+gray8s_image_t gradient(runtime_image.dimensions());
+x_luminosity_gradient(<a class="code" href="http://opensource.adobe.com/gil/html/group___image_model.html#ga3">const_view</a>(runtime_image), <a class="code" href="http://opensource.adobe.com/gil/html/group___image_model.html#ga0">view</a>(gradient));
+<a class="code" href="http://opensource.adobe.com/gil/html/group___j_p_e_g___i_o.html#ga2">jpeg_write_view</a>(<span class="stringliteral">"x_gradient.jpg"</span>, color_converted_view<gray8_pixel_t>(<a class="code" href="http://opensource.adobe.com/gil/html/group___image_model.html#ga3">const_view</a>(gradient)));
+</pre></div><p>
+In this example, we create an image variant that could be 8-bit or 16-bit RGB or grayscale image. We then use GIL's I/O extension to load the image from file in its native color space and channel depth. If none of the allowed image types matches the image on disk, an exception will be thrown. We then construct a 8 bit signed (i.e. <code>char</code>) image to store the gradient and invoke <code>x_gradient</code> on it. Finally we save the result into another file. We save the view converted to 8-bit unsigned, because JPEG I/O does not support signed char.<p>
+Note how free functions and methods such as <code>jpeg_read_image</code>, <code>dimensions</code>, <code>view</code> and <code>const_view</code> work on both templated and variant types. For templated images <code>view(img)</code> returns a templated view, whereas for image variants it returns a view variant. For example, the return type of <code>view(runtime_image)</code> is <code>any_image_view<Views></code> where <code>Views</code> enumerates four views corresponding to the four image types. <code>const_view(runtime_image)</code> returns a <code>any_image_view</code> of the four read-only view types, etc.<p>
+A warning about using variants: instantiating an algorithm with a variant effectively instantiates it with every possible type the variant can take. For binary algorithms, the algorithm is instantiated with every possible combination of the two input types! This can take a toll on both the compile time and the executable size.<h2><a class="anchor" name="ConclusionSec">
+Conclusion</a></h2>
+This tutorial provides a glimpse at the challenges associated with writing generic and efficient image processing algorithms in GIL. We have taken a simple algorithm and shown how to make it work with image representations that vary in bit depth, color space, ordering of the channels, and planar/interleaved structure. We have demonstrated that the algorithm can work with fully abstracted virtual images, and even images whose type is specified at run time. The associated video presentation also demonstrates that even for complex scenarios the generated assembly is comparable to that of a C version of the algorithm, hand-written for the specific image types.<p>
+Yet, even for such a simple algorithm, we are far from making a fully generic and optimized code. In particular, the presented algorithms work on homogeneous images, i.e. images whose pixels have channels that are all of the same type. There are examples of images, such as a packed 565 RGB format, which contain channels of different types. While GIL provides concepts and algorithms operating on heterogeneous pixels, we leave the task of extending x_gradient as an exercise for the reader. Second, after computing the value of the gradient we are simply casting it to the destination channel type. This may not always be the desired operation. For example, if the source channel is a float with range [0..1] and the destination is unsigned char, casting the half-difference to unsigned char will result in either 0 or 1. Instead, what we might want to do is scale the result into the range of the destination channel. GIL's channel-level algorithms might be useful in such cases. For example, <code>channel_convert</cod
e> converts between channels by linearly scaling the source channel value into the range of the destination channel.<p>
+There is a lot to be done in improving the performance as well. Channel-level operations, such as the half-difference, could be abstracted out into atomic channel-level algorithms and performance overloads could be provided for concrete channel types. Processor-specific operations could be used, for example, to perform the operation over an entire row of pixels simultaneously, or the data could be prefetched. All of these optimizations can be realized as performance specializations of the generic algorithm. Finally, compilers, while getting better over time, are still failing to fully optimize generic code in some cases, such as failing to inline some functions or put some variables into registers. If performance is an issue, it might be worth trying your code with different compilers.<h2><a class="anchor" name="AppendixSec">
+Appendix</a></h2>
+<h3><a class="anchor" name="AppendixConventionSec">
+Naming convention for GIL concrete types</a></h3>
+Concrete (non-generic) GIL types follow this naming convention:<p>
+<em>ColorSpace</em> + <em>BitDepth</em> + [<code>f</code> | <code>s</code>]+ [<code>c</code>] + [<code>_planar</code>] + [<code>_step</code>] + <em>ClassType</em> + <code>_t</code> <p>
+Where <em>ColorSpace</em> also indicates the ordering of components. Examples are <code>rgb</code>, <code>bgr</code>, <code>cmyk</code>, <code>rgba</code>. <em>BitDepth</em> indicates the bit depth of the color channel. Examples are <code>8</code>,<code>16</code>,<code>32</code>. By default the type of channel is unsigned integral; using <code>s</code> indicates signed integral and <code>f</code> - a floating point type, which is always signed. <code>c</code> indicates object operating over immutable pixels. <code>_planar</code> indicates planar organization (as opposed to interleaved). <code>_step</code> indicates special image views, locators and iterators which traverse the data in non-trivial way (for example, backwards or every other pixel). <em>ClassType</em> is <code>_image</code> (image), <code>_view</code> (image view), <code>_loc</code> (pixel 2D locator) <code>_ptr</code> (pixel iterator), <code>_ref</code> (pixel reference), <code>_pixel</code> (pixel value).<p>
+<div class="fragment"><pre class="fragment">bgr8_image_t a; <span class="comment">// 8-bit interleaved BGR image</span>
+cmyk16_pixel_t; b; <span class="comment">// 16-bit CMYK pixel value;</span>
+cmyk16c_planar_ref_t c(b); <span class="comment">// const reference to a 16-bit planar CMYK pixel x.</span>
+rgb32f_planar_step_ptr_t d; <span class="comment">// step pointer to a 32-bit planar RGB pixel.</span>
+</pre></div><p>
+<hr size="1"><address style="align: right;"><small>Generated on Thu Nov 8 21:53:19 2007 for Generic Image Library by
+<a href="http://www.doxygen.org/index.html">
+<img src="doxygen.png" alt="doxygen" align="middle" border="0"></a> 1.4.4 </small></address>
+</body>
+</html>
Added: trunk/libs/gil/doc/html/interleaved.jpg
==============================================================================
Binary file. No diff available.
Added: trunk/libs/gil/doc/html/mandel.jpg
==============================================================================
Binary file. No diff available.
Added: trunk/libs/gil/doc/html/monkey_steps.jpg
==============================================================================
Binary file. No diff available.
Added: trunk/libs/gil/doc/html/planar.jpg
==============================================================================
Binary file. No diff available.
Added: trunk/libs/gil/doc/html/step_iterator.gif
==============================================================================
Binary file. No diff available.
Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk