2
0
mirror of https://github.com/boostorg/gil.git synced 2026-01-25 18:22:16 +00:00
Files
gil/develop/doc/html/design_guide.html

2555 lines
378 KiB
HTML

<!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">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Design Guide - Boost.GIL 1.0 documentation</title>
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
<link rel="stylesheet" href="_static/style.css" type="text/css" />
<script type="text/javascript">
var DOCUMENTATION_OPTIONS = {
URL_ROOT: './',
VERSION: '1.0',
COLLAPSE_MODINDEX: false,
FILE_SUFFIX: '.html'
};
</script>
<script type="text/javascript" src="_static/jquery.js"></script>
<script type="text/javascript" src="_static/underscore.js"></script>
<script type="text/javascript" src="_static/doctools.js"></script>
<link rel="index" title="Index" href="genindex.html" />
<link rel="search" title="Search" href="search.html" />
<link rel="top" title="Boost.GIL 1.0 documentation" href="index.html" />
<link rel="prev" title="Numeric extension" href="numeric.html" />
</head>
<body>
<div class="header">
<table border="0" cellpadding="7" cellspacing="0" width="100%" summary=
"header">
<tr>
<td valign="top" width="300">
<h3><a href="index.html"><img
alt="C++ Boost" src="_static/gil.png" border="0"></a></h3>
</td>
<td >
<h1 align="center"><a href="index.html"></a></h1>
</td>
<td>
<div id="searchbox" style="display: none">
<form class="search" action="search.html" method="get">
<input type="text" name="q" size="18" />
<input type="submit" value="Search" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
</div>
<script type="text/javascript">$('#searchbox').show(0);</script>
</td>
</tr>
</table>
</div>
<hr/>
<div class="content">
<div class="navbar" style="text-align:right;">
<a class="prev" title="Numeric extension" href="numeric.html"><img src="_static/prev.png" alt="prev"/></a>
</div>
<div class="section" id="design-guide">
<h1>Design Guide</h1>
<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 <a class="reference external" href="http://stlab.adobe.com/gil">http://stlab.adobe.com/gil</a></p>
<div class="contents local topic" id="contents">
<ul class="simple">
<li><a class="reference internal" href="#overview" id="id1">Overview</a></li>
<li><a class="reference internal" href="#about-concepts" id="id2">About Concepts</a></li>
<li><a class="reference internal" href="#point" id="id3">Point</a></li>
<li><a class="reference internal" href="#channel" id="id4">Channel</a></li>
<li><a class="reference internal" href="#color-space-and-layout" id="id5">Color Space and Layout</a></li>
<li><a class="reference internal" href="#color-base" id="id6">Color Base</a></li>
<li><a class="reference internal" href="#pixel" id="id7">Pixel</a></li>
<li><a class="reference internal" href="#pixel-iterator" id="id8">Pixel Iterator</a><ul>
<li><a class="reference internal" href="#fundamental-iterator" id="id9">Fundamental Iterator</a></li>
<li><a class="reference internal" href="#iterator-adaptor" id="id10">Iterator Adaptor</a></li>
<li><a class="reference internal" href="#pixel-dereference-adaptor" id="id11">Pixel Dereference Adaptor</a></li>
<li><a class="reference internal" href="#step-iterator" id="id12">Step Iterator</a></li>
<li><a class="reference internal" href="#pixel-locator" id="id13">Pixel Locator</a></li>
<li><a class="reference internal" href="#iterator-over-2d-image" id="id14">Iterator over 2D image</a></li>
</ul>
</li>
<li><a class="reference internal" href="#image-view" id="id15">Image View</a><ul>
<li><a class="reference internal" href="#creating-views-from-raw-pixels" id="id16">Creating Views from Raw Pixels</a></li>
<li><a class="reference internal" href="#creating-image-views-from-other-image-views" id="id17">Creating Image Views from Other Image Views</a></li>
<li><a class="reference internal" href="#stl-style-algorithms-on-image-views" id="id18">STL-Style Algorithms on Image Views</a></li>
</ul>
</li>
<li><a class="reference internal" href="#image" id="id19">Image</a></li>
<li><a class="reference internal" href="#run-time-specified-images-and-image-views" id="id20">Run-time specified images and image views</a></li>
<li><a class="reference internal" href="#useful-metafunctions-and-typedefs" id="id21">Useful Metafunctions and Typedefs</a></li>
<li><a class="reference internal" href="#i-o-extension" id="id22">I/O Extension</a></li>
<li><a class="reference internal" href="#sample-code" id="id23">Sample Code</a><ul>
<li><a class="reference internal" href="#pixel-level-sample-code" id="id24">Pixel-level Sample Code</a></li>
<li><a class="reference internal" href="#creating-a-copy-of-an-image-with-a-safe-buffer" id="id25">Creating a Copy of an Image with a Safe Buffer</a></li>
<li><a class="reference internal" href="#histogram" id="id26">Histogram</a></li>
<li><a class="reference internal" href="#using-image-views" id="id27">Using Image Views</a></li>
</ul>
</li>
<li><a class="reference internal" href="#extending-the-generic-image-library" id="id28">Extending the Generic Image Library</a><ul>
<li><a class="reference internal" href="#defining-new-color-spaces" id="id29">Defining New Color Spaces</a></li>
<li><a class="reference internal" href="#defining-new-channel-types" id="id30">Defining New Channel Types</a></li>
<li><a class="reference internal" href="#overloading-color-conversion" id="id31">Overloading Color Conversion</a></li>
<li><a class="reference internal" href="#defining-new-image-views" id="id32">Defining New Image Views</a></li>
</ul>
</li>
<li><a class="reference internal" href="#technicalities" id="id33">Technicalities</a><ul>
<li><a class="reference internal" href="#creating-a-reference-proxy" id="id34">Creating a reference proxy</a></li>
</ul>
</li>
<li><a class="reference internal" href="#conclusion" id="id35">Conclusion</a></li>
</ul>
</div>
<div class="section" id="overview">
<h2><a class="toc-backref" href="#id1">Overview</a></h2>
<p>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>
<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>
<img alt="_images/interleaved.jpg" src="_images/interleaved.jpg" />
<p>and in planar form:</p>
<img alt="_images/planar.jpg" src="_images/planar.jpg" />
<p>Note also that rows may optionally be aligned resulting in a potential padding at the end of rows.</p>
<p>The Generic Image Library (GIL) provides models for images that vary in:
- Structure (planar vs. interleaved)
- Color space and presence of alpha (RGB, RGBA, CMYK, etc.)
- Channel depth (8-bit, 16-bit, etc.)
- Order of channels (RGB vs. BGR, etc.)
- Row alignment policy (no alignment, word-alignment, etc.)</p>
<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>
<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>
</div>
<div class="section" id="about-concepts">
<h2><a class="toc-backref" href="#id2">About Concepts</a></h2>
<p>All constructs in GIL are models of GIL concepts. A em concept 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 algorithmic guarantees.
For example, GIL&#8217;s class <tt class="docutils literal"><span class="pre">pixel</span></tt> is a model of GIL&#8217;s <tt class="docutils literal"><span class="pre">PixelConcept</span></tt>. The user may substitute the pixel class with one of their own, and, as long as
it satisfies the requirements of <tt class="docutils literal"><span class="pre">PixelConcept</span></tt>, all other GIL classes and algorithms can be used with it. See more about concepts here:
<a class="reference external" href="http://www.generic-programming.org/languages/conceptcpp/">http://www.generic-programming.org/languages/conceptcpp/</a></p>
<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:
<a class="reference external" href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2081.pdf">http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2081.pdf</a></p>
<p>Here are some common concepts that will be used in GIL. Most of them are defined here:
<a class="reference external" href="http://www.generic-programming.org/languages/conceptcpp/concept_web.php">http://www.generic-programming.org/languages/conceptcpp/concept_web.php</a></p>
<div class="highlight-c++"><div class="highlight"><pre><span class="k">auto</span> <span class="n">concept</span> <span class="n">DefaultConstructible</span><span class="o">&lt;</span><span class="k">typename</span> <span class="n">T</span><span class="o">&gt;</span>
<span class="p">{</span>
<span class="n">T</span><span class="o">::</span><span class="n">T</span><span class="p">();</span>
<span class="p">};</span>
<span class="k">auto</span> <span class="n">concept</span> <span class="n">CopyConstructible</span><span class="o">&lt;</span><span class="k">typename</span> <span class="n">T</span><span class="o">&gt;</span>
<span class="p">{</span>
<span class="n">T</span><span class="o">::</span><span class="n">T</span><span class="p">(</span><span class="n">T</span><span class="p">);</span>
<span class="n">T</span><span class="o">::~</span><span class="n">T</span><span class="p">();</span>
<span class="p">};</span>
<span class="k">auto</span> <span class="n">concept</span> <span class="n">Assignable</span><span class="o">&lt;</span><span class="k">typename</span> <span class="n">T</span><span class="p">,</span> <span class="k">typename</span> <span class="n">U</span> <span class="o">=</span> <span class="n">T</span><span class="o">&gt;</span>
<span class="p">{</span>
<span class="k">typename</span> <span class="n">result_type</span><span class="p">;</span>
<span class="n">result_type</span> <span class="k">operator</span><span class="o">=</span><span class="p">(</span><span class="n">T</span><span class="o">&amp;</span><span class="p">,</span> <span class="n">U</span><span class="p">);</span>
<span class="p">};</span>
<span class="k">auto</span> <span class="n">concept</span> <span class="n">EqualityComparable</span><span class="o">&lt;</span><span class="k">typename</span> <span class="n">T</span><span class="p">,</span> <span class="k">typename</span> <span class="n">U</span> <span class="o">=</span> <span class="n">T</span><span class="o">&gt;</span>
<span class="p">{</span>
<span class="kt">bool</span> <span class="k">operator</span><span class="o">==</span><span class="p">(</span><span class="n">T</span> <span class="n">x</span><span class="p">,</span> <span class="n">T</span> <span class="n">y</span><span class="p">);</span>
<span class="kt">bool</span> <span class="k">operator</span><span class="o">!=</span><span class="p">(</span><span class="n">T</span> <span class="n">x</span><span class="p">,</span> <span class="n">T</span> <span class="n">y</span><span class="p">)</span> <span class="p">{</span> <span class="k">return</span> <span class="o">!</span><span class="p">(</span><span class="n">x</span><span class="o">==</span><span class="n">y</span><span class="p">);</span> <span class="p">}</span>
<span class="p">};</span>
<span class="n">concept</span> <span class="n">SameType</span><span class="o">&lt;</span><span class="k">typename</span> <span class="n">T</span><span class="p">,</span> <span class="k">typename</span> <span class="n">U</span><span class="o">&gt;</span> <span class="p">{</span> <span class="cm">/* unspecified */</span> <span class="p">};</span>
<span class="k">template</span><span class="o">&lt;</span><span class="k">typename</span> <span class="n">T</span><span class="o">&gt;</span> <span class="n">concept_map</span> <span class="n">SameType</span><span class="o">&lt;</span><span class="n">T</span><span class="p">,</span> <span class="n">T</span><span class="o">&gt;</span> <span class="p">{</span> <span class="cm">/* unspecified */</span> <span class="p">};</span>
<span class="k">auto</span> <span class="n">concept</span> <span class="n">Swappable</span><span class="o">&lt;</span><span class="k">typename</span> <span class="n">T</span><span class="o">&gt;</span>
<span class="p">{</span>
<span class="kt">void</span> <span class="n">swap</span><span class="p">(</span><span class="n">T</span><span class="o">&amp;</span> <span class="n">t</span><span class="p">,</span> <span class="n">T</span><span class="o">&amp;</span> <span class="n">u</span><span class="p">);</span>
<span class="p">};</span>
</pre></div>
</div>
<p>Here are some additional basic concepts that GIL needs:</p>
<div class="highlight-c++"><div class="highlight"><pre><span class="k">auto</span> <span class="n">concept</span> <span class="n">Regular</span><span class="o">&lt;</span><span class="k">typename</span> <span class="n">T</span><span class="o">&gt;</span> <span class="o">:</span> <span class="n">DefaultConstructible</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span><span class="p">,</span> <span class="n">CopyConstructible</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span><span class="p">,</span> <span class="n">EqualityComparable</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span><span class="p">,</span> <span class="n">Assignable</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span><span class="p">,</span> <span class="n">Swappable</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span> <span class="p">{};</span>
<span class="k">auto</span> <span class="n">concept</span> <span class="n">Metafunction</span><span class="o">&lt;</span><span class="k">typename</span> <span class="n">T</span><span class="o">&gt;</span>
<span class="p">{</span>
<span class="k">typename</span> <span class="n">type</span><span class="p">;</span>
<span class="p">};</span>
</pre></div>
</div>
</div>
<div class="section" id="point">
<h2><a class="toc-backref" href="#id3">Point</a></h2>
<p>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="highlight-c++"><div class="highlight"><pre><span class="n">concept</span> <span class="n">PointNDConcept</span><span class="o">&lt;</span><span class="k">typename</span> <span class="n">T</span><span class="o">&gt;</span> <span class="o">:</span> <span class="n">Regular</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span>
<span class="p">{</span>
<span class="c1">// the type of a coordinate along each axis</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="kt">size_t</span> <span class="n">K</span><span class="o">&gt;</span> <span class="k">struct</span> <span class="n">axis</span><span class="p">;</span> <span class="n">where</span> <span class="n">Metafunction</span><span class="o">&lt;</span><span class="n">axis</span><span class="o">&gt;</span><span class="p">;</span>
<span class="k">const</span> <span class="kt">size_t</span> <span class="n">num_dimensions</span><span class="p">;</span>
<span class="c1">// accessor/modifier of the value of each axis.</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="kt">size_t</span> <span class="n">K</span><span class="o">&gt;</span> <span class="k">const</span> <span class="k">typename</span> <span class="n">axis</span><span class="o">&lt;</span><span class="n">K</span><span class="o">&gt;::</span><span class="n">type</span><span class="o">&amp;</span> <span class="n">T</span><span class="o">::</span><span class="n">axis_value</span><span class="p">()</span> <span class="k">const</span><span class="p">;</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="kt">size_t</span> <span class="n">K</span><span class="o">&gt;</span> <span class="k">typename</span> <span class="n">axis</span><span class="o">&lt;</span><span class="n">K</span><span class="o">&gt;::</span><span class="n">type</span><span class="o">&amp;</span> <span class="n">T</span><span class="o">::</span><span class="n">axis_value</span><span class="p">();</span>
<span class="p">};</span>
</pre></div>
</div>
<p>GIL uses a two-dimensional point, which is a refinement of <tt class="docutils literal"><span class="pre">PointNDConcept</span></tt> in which both dimensions are of the same type:</p>
<div class="highlight-c++"><div class="highlight"><pre><span class="n">concept</span> <span class="n">Point2DConcept</span><span class="o">&lt;</span><span class="k">typename</span> <span class="n">T</span><span class="o">&gt;</span> <span class="o">:</span> <span class="n">PointNDConcept</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span>
<span class="p">{</span>
<span class="n">where</span> <span class="n">num_dimensions</span> <span class="o">==</span> <span class="mi">2</span><span class="p">;</span>
<span class="n">where</span> <span class="n">SameType</span><span class="o">&lt;</span><span class="n">axis</span><span class="o">&lt;</span><span class="mi">0</span><span class="o">&gt;::</span><span class="n">type</span><span class="p">,</span> <span class="n">axis</span><span class="o">&lt;</span><span class="mi">1</span><span class="o">&gt;::</span><span class="n">type</span><span class="o">&gt;</span><span class="p">;</span>
<span class="k">typename</span> <span class="n">value_type</span> <span class="o">=</span> <span class="n">axis</span><span class="o">&lt;</span><span class="mi">0</span><span class="o">&gt;::</span><span class="n">type</span><span class="p">;</span>
<span class="k">const</span> <span class="n">value_type</span><span class="o">&amp;</span> <span class="k">operator</span><span class="p">[](</span><span class="k">const</span> <span class="n">T</span><span class="o">&amp;</span><span class="p">,</span> <span class="kt">size_t</span> <span class="n">i</span><span class="p">);</span>
<span class="n">value_type</span><span class="o">&amp;</span> <span class="k">operator</span><span class="p">[](</span> <span class="n">T</span><span class="o">&amp;</span><span class="p">,</span> <span class="kt">size_t</span> <span class="n">i</span><span class="p">);</span>
<span class="n">value_type</span> <span class="n">x</span><span class="p">,</span><span class="n">y</span><span class="p">;</span>
<span class="p">};</span>
</pre></div>
</div>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name" colspan="2">Related Concepts:</th></tr>
<tr class="field-odd field"><td>&nbsp;</td><td class="field-body"><ul class="first simple">
<li><tt class="docutils literal"><span class="pre">PointNDConcept</span></tt></li>
<li><tt class="docutils literal"><span class="pre">Point2DConcept</span></tt></li>
</ul>
</td>
</tr>
<tr class="field-even field"><th class="field-name">Models:</th><td class="field-body"><p class="first last">GIL provides a model of <tt class="docutils literal"><span class="pre">Point2DConcept</span></tt>, <tt class="docutils literal"><span class="pre">point2&lt;T&gt;</span></tt> where <tt class="docutils literal"><span class="pre">T</span></tt> is the coordinate type.</p>
</td>
</tr>
</tbody>
</table>
</div>
<div class="section" id="channel">
<h2><a class="toc-backref" href="#id4">Channel</a></h2>
<p>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="highlight-c++"><div class="highlight"><pre><span class="n">concept</span> <span class="n">ChannelConcept</span><span class="o">&lt;</span><span class="k">typename</span> <span class="n">T</span><span class="o">&gt;</span> <span class="o">:</span> <span class="n">EqualityComparable</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span>
<span class="p">{</span>
<span class="k">typename</span> <span class="n">value_type</span> <span class="o">=</span> <span class="n">T</span><span class="p">;</span> <span class="c1">// use channel_traits&lt;T&gt;::value_type to access it</span>
<span class="n">where</span> <span class="n">ChannelValueConcept</span><span class="o">&lt;</span><span class="n">value_type</span><span class="o">&gt;</span><span class="p">;</span>
<span class="k">typename</span> <span class="n">reference</span> <span class="o">=</span> <span class="n">T</span><span class="o">&amp;</span><span class="p">;</span> <span class="c1">// use channel_traits&lt;T&gt;::reference to access it</span>
<span class="k">typename</span> <span class="n">pointer</span> <span class="o">=</span> <span class="n">T</span><span class="o">*</span><span class="p">;</span> <span class="c1">// use channel_traits&lt;T&gt;::pointer to access it</span>
<span class="k">typename</span> <span class="n">const_reference</span> <span class="o">=</span> <span class="k">const</span> <span class="n">T</span><span class="o">&amp;</span><span class="p">;</span> <span class="c1">// use channel_traits&lt;T&gt;::const_reference to access it</span>
<span class="k">typename</span> <span class="n">const_pointer</span> <span class="o">=</span> <span class="k">const</span> <span class="n">T</span><span class="o">*</span><span class="p">;</span> <span class="c1">// use channel_traits&lt;T&gt;::const_pointer to access it</span>
<span class="k">static</span> <span class="k">const</span> <span class="kt">bool</span> <span class="n">is_mutable</span><span class="p">;</span> <span class="c1">// use channel_traits&lt;T&gt;::is_mutable to access it</span>
<span class="k">static</span> <span class="n">T</span> <span class="nf">min_value</span><span class="p">();</span> <span class="c1">// use channel_traits&lt;T&gt;::min_value to access it</span>
<span class="k">static</span> <span class="n">T</span> <span class="nf">max_value</span><span class="p">();</span> <span class="c1">// use channel_traits&lt;T&gt;::min_value to access it</span>
<span class="p">};</span>
<span class="n">concept</span> <span class="n">MutableChannelConcept</span><span class="o">&lt;</span><span class="n">ChannelConcept</span> <span class="n">T</span><span class="o">&gt;</span> <span class="o">:</span> <span class="n">Swappable</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span><span class="p">,</span> <span class="n">Assignable</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span> <span class="p">{};</span>
<span class="n">concept</span> <span class="n">ChannelValueConcept</span><span class="o">&lt;</span><span class="n">ChannelConcept</span> <span class="n">T</span><span class="o">&gt;</span> <span class="o">:</span> <span class="n">Regular</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span> <span class="p">{};</span>
</pre></div>
</div>
<p>GIL allows built-in integral and floating point types to be channels. Therefore the associated types and range information
are defined in <tt class="docutils literal"><span class="pre">channel_traits</span></tt> with the following default implementation:</p>
<div class="highlight-c++"><div class="highlight"><pre><span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">T</span><span class="o">&gt;</span>
<span class="k">struct</span> <span class="n">channel_traits</span>
<span class="p">{</span>
<span class="k">typedef</span> <span class="n">T</span> <span class="n">value_type</span><span class="p">;</span>
<span class="k">typedef</span> <span class="n">T</span><span class="o">&amp;</span> <span class="n">reference</span><span class="p">;</span>
<span class="k">typedef</span> <span class="n">T</span><span class="o">*</span> <span class="n">pointer</span><span class="p">;</span>
<span class="k">typedef</span> <span class="n">T</span><span class="o">&amp;</span> <span class="k">const</span> <span class="n">const_reference</span><span class="p">;</span>
<span class="k">typedef</span> <span class="n">T</span><span class="o">*</span> <span class="k">const</span> <span class="n">const_pointer</span><span class="p">;</span>
<span class="k">static</span> <span class="n">value_type</span> <span class="nf">min_value</span><span class="p">()</span> <span class="p">{</span> <span class="k">return</span> <span class="n">std</span><span class="o">::</span><span class="n">numeric_limits</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;::</span><span class="n">min</span><span class="p">();</span> <span class="p">}</span>
<span class="k">static</span> <span class="n">value_type</span> <span class="nf">max_value</span><span class="p">()</span> <span class="p">{</span> <span class="k">return</span> <span class="n">std</span><span class="o">::</span><span class="n">numeric_limits</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;::</span><span class="n">max</span><span class="p">();</span> <span class="p">}</span>
<span class="p">};</span>
</pre></div>
</div>
<p>Two channel types are <em>compatible</em> if they have the same value type:</p>
<div class="highlight-c++"><div class="highlight"><pre><span class="n">concept</span> <span class="n">ChannelsCompatibleConcept</span><span class="o">&lt;</span><span class="n">ChannelConcept</span> <span class="n">T1</span><span class="p">,</span> <span class="n">ChannelConcept</span> <span class="n">T2</span><span class="o">&gt;</span>
<span class="p">{</span>
<span class="n">where</span> <span class="n">SameType</span><span class="o">&lt;</span><span class="n">T1</span><span class="o">::</span><span class="n">value_type</span><span class="p">,</span> <span class="n">T2</span><span class="o">::</span><span class="n">value_type</span><span class="o">&gt;</span><span class="p">;</span>
<span class="p">};</span>
</pre></div>
</div>
<p>A channel may be <em>convertible</em> to another channel:</p>
<div class="highlight-c++"><div class="highlight"><pre><span class="k">template</span> <span class="o">&lt;</span><span class="n">ChannelConcept</span> <span class="n">Src</span><span class="p">,</span> <span class="n">ChannelValueConcept</span> <span class="n">Dst</span><span class="o">&gt;</span>
<span class="n">concept</span> <span class="n">ChannelConvertibleConcept</span>
<span class="p">{</span>
<span class="n">Dst</span> <span class="n">channel_convert</span><span class="p">(</span><span class="n">Src</span><span class="p">);</span>
<span class="p">};</span>
</pre></div>
</div>
<p>Note that <tt class="docutils literal"><span class="pre">ChannelConcept</span></tt> and <tt class="docutils literal"><span class="pre">MutableChannelConcept</span></tt> do not require a default constructor. Channels that also
support default construction (and thus are regular types) model <tt class="docutils literal"><span class="pre">ChannelValueConcept</span></tt>. To understand the motivation
for this distinction, consider a 16-bit RGB pixel in a &#8220;565&#8221; 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 sub-byte channel.
Such a proxy reference class models only <tt class="docutils literal"><span class="pre">ChannelConcept</span></tt>, because, similar to native C++ references, it
may not have a default constructor.</p>
<p>Note also that algorithms may impose additional requirements on channels, such as support for arithmetic operations.</p>
<p>&lt;b&gt;Related Concepts:&lt;/b&gt;</p>
<ul class="simple">
<li>ChannelConcept&lt;T&gt;</li>
<li>ChannelValueConcept&lt;T&gt;</li>
<li>MutableChannelConcept&lt;T&gt;</li>
<li>ChannelsCompatibleConcept&lt;T1,T2&gt;</li>
<li>ChannelConvertibleConcept&lt;SrcChannel,DstChannel&gt;</li>
</ul>
<p>&lt;b&gt;Models:&lt;/b&gt;</p>
<p>All built-in integral and floating point types are valid channels. GIL provides standard type aliases for some integral channels:</p>
<div class="highlight-c++"><div class="highlight"><pre><span class="k">typedef</span> <span class="n">boost</span><span class="o">::</span><span class="kt">uint8_t</span> <span class="n">bits8</span><span class="p">;</span>
<span class="k">typedef</span> <span class="n">boost</span><span class="o">::</span><span class="kt">uint16_t</span> <span class="n">bits16</span><span class="p">;</span>
<span class="k">typedef</span> <span class="n">boost</span><span class="o">::</span><span class="kt">uint32_t</span> <span class="n">bits32</span><span class="p">;</span>
<span class="k">typedef</span> <span class="n">boost</span><span class="o">::</span><span class="kt">int8_t</span> <span class="n">bits8s</span><span class="p">;</span>
<span class="k">typedef</span> <span class="n">boost</span><span class="o">::</span><span class="kt">int16_t</span> <span class="n">bits16s</span><span class="p">;</span>
<span class="k">typedef</span> <span class="n">boost</span><span class="o">::</span><span class="kt">int32_t</span> <span class="n">bits32s</span><span class="p">;</span>
</pre></div>
</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 <tt class="docutils literal"><span class="pre">std::numeric_limits</span></tt>. Sometimes the physical range is not appropriate. GIL provides <tt class="docutils literal"><span class="pre">scoped_channel_value</span></tt>, 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="highlight-c++"><div class="highlight"><pre><span class="k">struct</span> <span class="n">float_zero</span> <span class="p">{</span> <span class="k">static</span> <span class="kt">float</span> <span class="n">apply</span><span class="p">()</span> <span class="p">{</span> <span class="k">return</span> <span class="mf">0.0f</span><span class="p">;</span> <span class="p">}</span> <span class="p">};</span>
<span class="k">struct</span> <span class="n">float_one</span> <span class="p">{</span> <span class="k">static</span> <span class="kt">float</span> <span class="n">apply</span><span class="p">()</span> <span class="p">{</span> <span class="k">return</span> <span class="mf">1.0f</span><span class="p">;</span> <span class="p">}</span> <span class="p">};</span>
<span class="k">typedef</span> <span class="n">scoped_channel_value</span><span class="o">&lt;</span><span class="kt">float</span><span class="p">,</span><span class="n">float_zero</span><span class="p">,</span><span class="n">float_one</span><span class="o">&gt;</span> <span class="n">bits32f</span><span class="p">;</span>
</pre></div>
</div>
<p>GIL also provides models for channels corresponding to ranges of bits:</p>
<div class="highlight-c++"><div class="highlight"><pre><span class="c1">// Value of a channel defined over NumBits bits. Models ChannelValueConcept</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="kt">int</span> <span class="n">NumBits</span><span class="o">&gt;</span> <span class="k">class</span> <span class="nc">packed_channel_value</span><span class="p">;</span>
<span class="c1">// Reference to a channel defined over NumBits bits. Models ChannelConcept</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="kt">int</span> <span class="n">FirstBit</span><span class="p">,</span>
<span class="kt">int</span> <span class="n">NumBits</span><span class="p">,</span> <span class="c1">// Defines the sequence of bits in the data value that contain the channel</span>
<span class="kt">bool</span> <span class="n">Mutable</span><span class="o">&gt;</span> <span class="c1">// true if the reference is mutable</span>
<span class="k">class</span> <span class="nc">packed_channel_reference</span><span class="p">;</span>
<span class="c1">// Reference to a channel defined over NumBits bits. Its FirstBit is a run-time parameter. Models ChannelConcept</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="kt">int</span> <span class="n">NumBits</span><span class="p">,</span> <span class="c1">// Defines the sequence of bits in the data value that contain the channel</span>
<span class="kt">bool</span> <span class="n">Mutable</span><span class="o">&gt;</span> <span class="c1">// true if the reference is mutable</span>
<span class="k">class</span> <span class="nc">packed_dynamic_channel_reference</span><span class="p">;</span>
</pre></div>
</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 bit range channels.</p>
<p>&lt;b&gt;Algorithms:&lt;/b&gt;</p>
<p>Here is how to construct the three channels of a 16-bit &#8220;565&#8221; pixel and set them to their maximum value:</p>
<div class="highlight-c++"><div class="highlight"><pre><span class="k">typedef</span> <span class="n">packed_channel_reference</span><span class="o">&lt;</span><span class="mi">0</span><span class="p">,</span><span class="mi">5</span><span class="p">,</span><span class="nb">true</span><span class="o">&gt;</span> <span class="kt">channel16_0_5_reference_t</span><span class="p">;</span>
<span class="k">typedef</span> <span class="n">packed_channel_reference</span><span class="o">&lt;</span><span class="mi">5</span><span class="p">,</span><span class="mi">6</span><span class="p">,</span><span class="nb">true</span><span class="o">&gt;</span> <span class="kt">channel16_5_6_reference_t</span><span class="p">;</span>
<span class="k">typedef</span> <span class="n">packed_channel_reference</span><span class="o">&lt;</span><span class="mi">11</span><span class="p">,</span><span class="mi">5</span><span class="p">,</span><span class="nb">true</span><span class="o">&gt;</span> <span class="kt">channel16_11_5_reference_t</span><span class="p">;</span>
<span class="n">boost</span><span class="o">::</span><span class="kt">uint16_t</span> <span class="n">data</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span>
<span class="kt">channel16_0_5_reference_t</span> <span class="nf">channel1</span><span class="p">(</span><span class="o">&amp;</span><span class="n">data</span><span class="p">);</span>
<span class="kt">channel16_5_6_reference_t</span> <span class="nf">channel2</span><span class="p">(</span><span class="o">&amp;</span><span class="n">data</span><span class="p">);</span>
<span class="kt">channel16_11_5_reference_t</span> <span class="nf">channel3</span><span class="p">(</span><span class="o">&amp;</span><span class="n">data</span><span class="p">);</span>
<span class="n">channel1</span><span class="o">=</span><span class="n">channel_traits</span><span class="o">&lt;</span><span class="kt">channel16_0_5_reference_t</span><span class="o">&gt;::</span><span class="n">max_value</span><span class="p">();</span>
<span class="n">channel2</span><span class="o">=</span><span class="n">channel_traits</span><span class="o">&lt;</span><span class="kt">channel16_5_6_reference_t</span><span class="o">&gt;::</span><span class="n">max_value</span><span class="p">();</span>
<span class="n">channel3</span><span class="o">=</span><span class="n">channel_traits</span><span class="o">&lt;</span><span class="kt">channel16_11_5_reference_t</span><span class="o">&gt;::</span><span class="n">max_value</span><span class="p">();</span>
<span class="n">assert</span><span class="p">(</span><span class="n">data</span><span class="o">==</span><span class="mi">65535</span><span class="p">);</span>
</pre></div>
</div>
<p>Assignment, equality comparison and copy construction are defined only between compatible channels:</p>
<div class="highlight-c++"><div class="highlight"><pre><span class="n">packed_channel_value</span><span class="o">&lt;</span><span class="mi">5</span><span class="o">&gt;</span> <span class="n">channel_6bit</span> <span class="o">=</span> <span class="n">channel1</span><span class="p">;</span>
<span class="n">channel_6bit</span> <span class="o">=</span> <span class="n">channel3</span><span class="p">;</span>
<span class="c1">//channel_6bit = channel2; // compile error: Assignment between incompatible channels.</span>
</pre></div>
</div>
<p>All channel models provided by GIL are pairwise convertible:</p>
<div class="highlight-c++"><div class="highlight"><pre><span class="n">channel1</span> <span class="o">=</span> <span class="n">channel_traits</span><span class="o">&lt;</span><span class="kt">channel16_0_5_reference_t</span><span class="o">&gt;::</span><span class="n">max_value</span><span class="p">();</span>
<span class="n">assert</span><span class="p">(</span><span class="n">channel1</span> <span class="o">==</span> <span class="mi">31</span><span class="p">);</span>
<span class="n">bits16</span> <span class="n">chan16</span> <span class="o">=</span> <span class="n">channel_convert</span><span class="o">&lt;</span><span class="n">bits16</span><span class="o">&gt;</span><span class="p">(</span><span class="n">channel1</span><span class="p">);</span>
<span class="n">assert</span><span class="p">(</span><span class="n">chan16</span> <span class="o">==</span> <span class="mi">65535</span><span class="p">);</span>
</pre></div>
</div>
<p>Channel conversion is a lossy operation. GIL&#8217;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>
<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="highlight-c++"><div class="highlight"><pre><span class="c1">// Converts a source channel value into a destination channel. Linearly maps the value of the source</span>
<span class="c1">// into the range of the destination</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">DstChannel</span><span class="p">,</span> <span class="k">typename</span> <span class="n">SrcChannel</span><span class="o">&gt;</span>
<span class="k">typename</span> <span class="n">channel_traits</span><span class="o">&lt;</span><span class="n">DstChannel</span><span class="o">&gt;::</span><span class="n">value_type</span> <span class="n">channel_convert</span><span class="p">(</span><span class="n">SrcChannel</span> <span class="n">src</span><span class="p">);</span>
<span class="c1">// returns max_value - x + min_value</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">Channel</span><span class="o">&gt;</span>
<span class="k">typename</span> <span class="n">channel_traits</span><span class="o">&lt;</span><span class="n">Channel</span><span class="o">&gt;::</span><span class="n">value_type</span> <span class="n">channel_invert</span><span class="p">(</span><span class="n">Channel</span> <span class="n">x</span><span class="p">);</span>
<span class="c1">// returns a * b / max_value</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">Channel</span><span class="o">&gt;</span>
<span class="k">typename</span> <span class="n">channel_traits</span><span class="o">&lt;</span><span class="n">Channel</span><span class="o">&gt;::</span><span class="n">value_type</span> <span class="n">channel_multiply</span><span class="p">(</span><span class="n">Channel</span> <span class="n">a</span><span class="p">,</span> <span class="n">Channel</span> <span class="n">b</span><span class="p">);</span>
</pre></div>
</div>
</div>
<div class="section" id="color-space-and-layout">
<h2><a class="toc-backref" href="#id5">Color Space and Layout</a></h2>
<p>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>
<p>&lt;b&gt;Related Concepts:&lt;/b&gt;</p>
<ul class="simple">
<li>ColorSpaceConcept&lt;ColorSpace&gt;</li>
<li>ColorSpacesCompatibleConcept&lt;ColorSpace1,ColorSpace2&gt;</li>
<li>ChannelMappingConcept&lt;Mapping&gt;</li>
</ul>
<p>&lt;b&gt;Models:&lt;/b&gt;</p>
<p>GIL currently provides the following color spaces: <tt class="docutils literal"><span class="pre">gray_t</span></tt>, <tt class="docutils literal"><span class="pre">rgb_t</span></tt>, <tt class="docutils literal"><span class="pre">rgba_t</span></tt>, and <tt class="docutils literal"><span class="pre">cmyk_t</span></tt>. It also provides unnamed
N-channel color spaces of two to five channels, <tt class="docutils literal"><span class="pre">devicen_t&lt;2&gt;</span></tt>,
<tt class="docutils literal"><span class="pre">devicen_t&lt;3&gt;</span></tt>, <tt class="docutils literal"><span class="pre">devicen_t&lt;4&gt;</span></tt>, <tt class="docutils literal"><span class="pre">devicen_t&lt;5&gt;</span></tt>. Besides the standard layouts, it provides <tt class="docutils literal"><span class="pre">bgr_layout_t</span></tt>, <tt class="docutils literal"><span class="pre">bgra_layout_t</span></tt>, <tt class="docutils literal"><span class="pre">abgr_layout_t</span></tt>
and <tt class="docutils literal"><span class="pre">argb_layout_t</span></tt>.</p>
<p>As an example, here is how GIL defines the RGBA color space:</p>
<div class="highlight-c++"><div class="highlight"><pre><span class="k">struct</span> <span class="kt">red_t</span><span class="p">{};</span>
<span class="k">struct</span> <span class="kt">green_t</span><span class="p">{};</span>
<span class="k">struct</span> <span class="kt">blue_t</span><span class="p">{};</span>
<span class="k">struct</span> <span class="kt">alpha_t</span><span class="p">{};</span>
<span class="k">typedef</span> <span class="n">mpl</span><span class="o">::</span><span class="n">vector4</span><span class="o">&lt;</span><span class="kt">red_t</span><span class="p">,</span><span class="kt">green_t</span><span class="p">,</span><span class="kt">blue_t</span><span class="p">,</span><span class="kt">alpha_t</span><span class="o">&gt;</span> <span class="kt">rgba_t</span><span class="p">;</span>
</pre></div>
</div>
<p>The ordering of the channels in the color space definition specifies their semantic order. For example, <tt class="docutils literal"><span class="pre">red_t</span></tt> is the first semantic channel of <tt class="docutils literal"><span class="pre">rgba_t</span></tt>.
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 <tt class="docutils literal"><span class="pre">ChannelMappingConcept</span></tt>, 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&#8217;s layout:</p>
<div class="highlight-c++"><div class="highlight"><pre><span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">ColorSpace</span><span class="p">,</span>
<span class="k">typename</span> <span class="n">ChannelMapping</span> <span class="o">=</span> <span class="n">mpl</span><span class="o">::</span><span class="n">range_c</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">,</span><span class="mi">0</span><span class="p">,</span><span class="n">mpl</span><span class="o">::</span><span class="n">size</span><span class="o">&lt;</span><span class="n">ColorSpace</span><span class="o">&gt;::</span><span class="n">value</span><span class="o">&gt;</span> <span class="o">&gt;</span>
<span class="k">struct</span> <span class="n">layout</span>
<span class="p">{</span>
<span class="k">typedef</span> <span class="n">ColorSpace</span> <span class="kt">color_space_t</span><span class="p">;</span>
<span class="k">typedef</span> <span class="n">ChannelMapping</span> <span class="kt">channel_mapping_t</span><span class="p">;</span>
<span class="p">};</span>
</pre></div>
</div>
<p>Here is how to create layouts for the RGBA color space:</p>
<div class="highlight-c++"><div class="highlight"><pre><span class="k">typedef</span> <span class="n">layout</span><span class="o">&lt;</span><span class="kt">rgba_t</span><span class="o">&gt;</span> <span class="kt">rgba_layout_t</span><span class="p">;</span> <span class="c1">// default ordering is 0,1,2,3...</span>
<span class="k">typedef</span> <span class="n">layout</span><span class="o">&lt;</span><span class="kt">rgba_t</span><span class="p">,</span> <span class="n">mpl</span><span class="o">::</span><span class="n">vector4_c</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">1</span><span class="p">,</span><span class="mi">0</span><span class="p">,</span><span class="mi">3</span><span class="o">&gt;</span> <span class="o">&gt;</span> <span class="kt">bgra_layout_t</span><span class="p">;</span>
<span class="k">typedef</span> <span class="n">layout</span><span class="o">&lt;</span><span class="kt">rgba_t</span><span class="p">,</span> <span class="n">mpl</span><span class="o">::</span><span class="n">vector4_c</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">,</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">3</span><span class="p">,</span><span class="mi">0</span><span class="o">&gt;</span> <span class="o">&gt;</span> <span class="kt">argb_layout_t</span><span class="p">;</span>
<span class="k">typedef</span> <span class="n">layout</span><span class="o">&lt;</span><span class="kt">rgba_t</span><span class="p">,</span> <span class="n">mpl</span><span class="o">::</span><span class="n">vector4_c</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">,</span><span class="mi">3</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">1</span><span class="p">,</span><span class="mi">0</span><span class="o">&gt;</span> <span class="o">&gt;</span> <span class="kt">abgr_layout_t</span><span class="p">;</span>
</pre></div>
</div>
</div>
<div class="section" id="color-base">
<h2><a class="toc-backref" href="#id6">Color Base</a></h2>
<p>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>
<p>Color base models must satisfy the following concepts:</p>
<div class="highlight-c++"><div class="highlight"><pre><span class="n">concept</span> <span class="n">ColorBaseConcept</span><span class="o">&lt;</span><span class="k">typename</span> <span class="n">T</span><span class="o">&gt;</span> <span class="o">:</span> <span class="n">CopyConstructible</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span><span class="p">,</span> <span class="n">EqualityComparable</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span>
<span class="p">{</span>
<span class="c1">// a GIL layout (the color space and element permutation)</span>
<span class="k">typename</span> <span class="kt">layout_t</span><span class="p">;</span>
<span class="c1">// The type of K-th element</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="kt">int</span> <span class="n">K</span><span class="o">&gt;</span> <span class="k">struct</span> <span class="n">kth_element_type</span><span class="p">;</span>
<span class="n">where</span> <span class="n">Metafunction</span><span class="o">&lt;</span><span class="n">kth_element_type</span><span class="o">&gt;</span><span class="p">;</span>
<span class="c1">// The result of at_c</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="kt">int</span> <span class="n">K</span><span class="o">&gt;</span> <span class="k">struct</span> <span class="n">kth_element_const_reference_type</span><span class="p">;</span>
<span class="n">where</span> <span class="n">Metafunction</span><span class="o">&lt;</span><span class="n">kth_element_const_reference_type</span><span class="o">&gt;</span><span class="p">;</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="kt">int</span> <span class="n">K</span><span class="o">&gt;</span> <span class="n">kth_element_const_reference_type</span><span class="o">&lt;</span><span class="n">T</span><span class="p">,</span><span class="n">K</span><span class="o">&gt;::</span><span class="n">type</span> <span class="n">at_c</span><span class="p">(</span><span class="n">T</span><span class="p">);</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="n">ColorBaseConcept</span> <span class="n">T2</span><span class="o">&gt;</span> <span class="n">where</span> <span class="p">{</span> <span class="n">ColorBasesCompatibleConcept</span><span class="o">&lt;</span><span class="n">T</span><span class="p">,</span><span class="n">T2</span><span class="o">&gt;</span> <span class="p">}</span>
<span class="n">T</span><span class="o">::</span><span class="n">T</span><span class="p">(</span><span class="n">T2</span><span class="p">);</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="n">ColorBaseConcept</span> <span class="n">T2</span><span class="o">&gt;</span> <span class="n">where</span> <span class="p">{</span> <span class="n">ColorBasesCompatibleConcept</span><span class="o">&lt;</span><span class="n">T</span><span class="p">,</span><span class="n">T2</span><span class="o">&gt;</span> <span class="p">}</span>
<span class="kt">bool</span> <span class="k">operator</span><span class="o">==</span><span class="p">(</span><span class="k">const</span> <span class="n">T</span><span class="o">&amp;</span><span class="p">,</span> <span class="k">const</span> <span class="n">T2</span><span class="o">&amp;</span><span class="p">);</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="n">ColorBaseConcept</span> <span class="n">T2</span><span class="o">&gt;</span> <span class="n">where</span> <span class="p">{</span> <span class="n">ColorBasesCompatibleConcept</span><span class="o">&lt;</span><span class="n">T</span><span class="p">,</span><span class="n">T2</span><span class="o">&gt;</span> <span class="p">}</span>
<span class="kt">bool</span> <span class="k">operator</span><span class="o">!=</span><span class="p">(</span><span class="k">const</span> <span class="n">T</span><span class="o">&amp;</span><span class="p">,</span> <span class="k">const</span> <span class="n">T2</span><span class="o">&amp;</span><span class="p">);</span>
<span class="p">};</span>
<span class="n">concept</span> <span class="n">MutableColorBaseConcept</span><span class="o">&lt;</span><span class="n">ColorBaseConcept</span> <span class="n">T</span><span class="o">&gt;</span> <span class="o">:</span> <span class="n">Assignable</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span><span class="p">,</span> <span class="n">Swappable</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span>
<span class="p">{</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="kt">int</span> <span class="n">K</span><span class="o">&gt;</span> <span class="k">struct</span> <span class="n">kth_element_reference_type</span><span class="p">;</span>
<span class="n">where</span> <span class="n">Metafunction</span><span class="o">&lt;</span><span class="n">kth_element_reference_type</span><span class="o">&gt;</span><span class="p">;</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="kt">int</span> <span class="n">K</span><span class="o">&gt;</span> <span class="n">kth_element_reference_type</span><span class="o">&lt;</span><span class="n">T</span><span class="p">,</span><span class="n">K</span><span class="o">&gt;::</span><span class="n">type</span> <span class="n">at_c</span><span class="p">(</span><span class="n">T</span><span class="p">);</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="n">ColorBaseConcept</span> <span class="n">T2</span><span class="o">&gt;</span> <span class="n">where</span> <span class="p">{</span> <span class="n">ColorBasesCompatibleConcept</span><span class="o">&lt;</span><span class="n">T</span><span class="p">,</span><span class="n">T2</span><span class="o">&gt;</span> <span class="p">}</span>
<span class="n">T</span><span class="o">&amp;</span> <span class="k">operator</span><span class="o">=</span><span class="p">(</span><span class="n">T</span><span class="o">&amp;</span><span class="p">,</span> <span class="k">const</span> <span class="n">T2</span><span class="o">&amp;</span><span class="p">);</span>
<span class="p">};</span>
<span class="n">concept</span> <span class="n">ColorBaseValueConcept</span><span class="o">&lt;</span><span class="k">typename</span> <span class="n">T</span><span class="o">&gt;</span> <span class="o">:</span> <span class="n">MutableColorBaseConcept</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span><span class="p">,</span> <span class="n">Regular</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span>
<span class="p">{</span>
<span class="p">};</span>
<span class="n">concept</span> <span class="n">HomogeneousColorBaseConcept</span><span class="o">&lt;</span><span class="n">ColorBaseConcept</span> <span class="n">CB</span><span class="o">&gt;</span>
<span class="p">{</span>
<span class="c1">// For all K in [0 ... size&lt;C1&gt;::value-1):</span>
<span class="c1">// where SameType&lt;kth_element_type&lt;K&gt;::type, kth_element_type&lt;K+1&gt;::type&gt;;</span>
<span class="n">kth_element_const_reference_type</span><span class="o">&lt;</span><span class="mi">0</span><span class="o">&gt;::</span><span class="n">type</span> <span class="n">dynamic_at_c</span><span class="p">(</span><span class="k">const</span> <span class="n">CB</span><span class="o">&amp;</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="kt">size_t</span> <span class="n">n</span><span class="p">)</span> <span class="k">const</span><span class="p">;</span>
<span class="p">};</span>
<span class="n">concept</span> <span class="n">MutableHomogeneousColorBaseConcept</span><span class="o">&lt;</span><span class="n">MutableColorBaseConcept</span> <span class="n">CB</span><span class="o">&gt;</span> <span class="o">:</span> <span class="n">HomogeneousColorBaseConcept</span><span class="o">&lt;</span><span class="n">CB</span><span class="o">&gt;</span>
<span class="p">{</span>
<span class="n">kth_element_reference_type</span><span class="o">&lt;</span><span class="mi">0</span><span class="o">&gt;::</span><span class="n">type</span> <span class="n">dynamic_at_c</span><span class="p">(</span><span class="k">const</span> <span class="n">CB</span><span class="o">&amp;</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="kt">size_t</span> <span class="n">n</span><span class="p">);</span>
<span class="p">};</span>
<span class="n">concept</span> <span class="n">HomogeneousColorBaseValueConcept</span><span class="o">&lt;</span><span class="k">typename</span> <span class="n">T</span><span class="o">&gt;</span> <span class="o">:</span> <span class="n">MutableHomogeneousColorBaseConcept</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span><span class="p">,</span> <span class="n">Regular</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span>
<span class="p">{</span>
<span class="p">};</span>
<span class="n">concept</span> <span class="n">ColorBasesCompatibleConcept</span><span class="o">&lt;</span><span class="n">ColorBaseConcept</span> <span class="n">C1</span><span class="p">,</span> <span class="n">ColorBaseConcept</span> <span class="n">C2</span><span class="o">&gt;</span>
<span class="p">{</span>
<span class="n">where</span> <span class="n">SameType</span><span class="o">&lt;</span><span class="n">C1</span><span class="o">::</span><span class="kt">layout_t</span><span class="o">::</span><span class="kt">color_space_t</span><span class="p">,</span> <span class="n">C2</span><span class="o">::</span><span class="kt">layout_t</span><span class="o">::</span><span class="kt">color_space_t</span><span class="o">&gt;</span><span class="p">;</span>
<span class="c1">// also, for all K in [0 ... size&lt;C1&gt;::value):</span>
<span class="c1">// where Convertible&lt;kth_semantic_element_type&lt;C1,K&gt;::type, kth_semantic_element_type&lt;C2,K&gt;::type&gt;;</span>
<span class="c1">// where Convertible&lt;kth_semantic_element_type&lt;C2,K&gt;::type, kth_semantic_element_type&lt;C1,K&gt;::type&gt;;</span>
<span class="p">};</span>
</pre></div>
</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 <tt class="docutils literal"><span class="pre">ColorBaseConcept</span></tt> are required to provide the <tt class="docutils literal"><span class="pre">at_c&lt;K&gt;(ColorBase)</span></tt> function, which allows for accessing the elements based on their
physical order. GIL provides a <tt class="docutils literal"><span class="pre">semantic_at_c&lt;K&gt;(ColorBase)</span></tt> function (described later) which can operate on any model of ColorBaseConcept and returns
the corresponding semantic element.</p>
<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>
<p>&lt;b&gt;Models:&lt;/b&gt;</p>
<p>GIL provides a model for a homogeneous color base (a color base whose elements all have the same type).</p>
<div class="highlight-c++"><div class="highlight"><pre><span class="k">namespace</span> <span class="n">detail</span>
<span class="p">{</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">Element</span><span class="p">,</span> <span class="k">typename</span> <span class="n">Layout</span><span class="p">,</span> <span class="kt">int</span> <span class="n">K</span><span class="o">&gt;</span> <span class="k">struct</span> <span class="n">homogeneous_color_base</span><span class="p">;</span>
<span class="p">}</span>
</pre></div>
</div>
<p>It is used in the implementation of GIL&#8217;s pixel, planar pixel reference and planar pixel iterator.
Another model of <tt class="docutils literal"><span class="pre">ColorBaseConcept</span></tt> is <tt class="docutils literal"><span class="pre">packed_pixel</span></tt> - it is a pixel whose channels are bit ranges. See the ref PixelSectionDG
section for more.</p>
<p>&lt;b&gt;Algorithms:&lt;/b&gt;</p>
<p>GIL provides the following functions and metafunctions operating on color bases:</p>
<div class="highlight-c++"><div class="highlight"><pre><span class="c1">// Metafunction returning an mpl::int_ equal to the number of elements in the color base</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">class</span> <span class="nc">ColorBase</span><span class="o">&gt;</span> <span class="k">struct</span> <span class="n">size</span><span class="p">;</span>
<span class="c1">// Returns the type of the return value of semantic_at_c&lt;K&gt;(color_base)</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">class</span> <span class="nc">ColorBase</span><span class="p">,</span> <span class="kt">int</span> <span class="n">K</span><span class="o">&gt;</span> <span class="k">struct</span> <span class="n">kth_semantic_element_reference_type</span><span class="p">;</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">class</span> <span class="nc">ColorBase</span><span class="p">,</span> <span class="kt">int</span> <span class="n">K</span><span class="o">&gt;</span> <span class="k">struct</span> <span class="n">kth_semantic_element_const_reference_type</span><span class="p">;</span>
<span class="c1">// Returns a reference to the element with K-th semantic index.</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">class</span> <span class="nc">ColorBase</span><span class="p">,</span> <span class="kt">int</span> <span class="n">K</span><span class="o">&gt;</span>
<span class="k">typename</span> <span class="n">kth_semantic_element_reference_type</span><span class="o">&lt;</span><span class="n">ColorBase</span><span class="p">,</span><span class="n">K</span><span class="o">&gt;::</span><span class="n">type</span> <span class="n">semantic_at_c</span><span class="p">(</span><span class="n">ColorBase</span><span class="o">&amp;</span> <span class="n">p</span><span class="p">)</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">class</span> <span class="nc">ColorBase</span><span class="p">,</span> <span class="kt">int</span> <span class="n">K</span><span class="o">&gt;</span>
<span class="k">typename</span> <span class="n">kth_semantic_element_const_reference_type</span><span class="o">&lt;</span><span class="n">ColorBase</span><span class="p">,</span><span class="n">K</span><span class="o">&gt;::</span><span class="n">type</span> <span class="n">semantic_at_c</span><span class="p">(</span><span class="k">const</span> <span class="n">ColorBase</span><span class="o">&amp;</span> <span class="n">p</span><span class="p">)</span>
<span class="c1">// Returns the type of the return value of get_color&lt;Color&gt;(color_base)</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">Color</span><span class="p">,</span> <span class="k">typename</span> <span class="n">ColorBase</span><span class="o">&gt;</span> <span class="k">struct</span> <span class="kt">color_reference_t</span><span class="p">;</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">Color</span><span class="p">,</span> <span class="k">typename</span> <span class="n">ColorBase</span><span class="o">&gt;</span> <span class="k">struct</span> <span class="kt">color_const_reference_t</span><span class="p">;</span>
<span class="c1">// Returns a reference to the element corresponding to the given color</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">ColorBase</span><span class="p">,</span> <span class="k">typename</span> <span class="n">Color</span><span class="o">&gt;</span>
<span class="k">typename</span> <span class="kt">color_reference_t</span><span class="o">&lt;</span><span class="n">Color</span><span class="p">,</span><span class="n">ColorBase</span><span class="o">&gt;::</span><span class="n">type</span> <span class="n">get_color</span><span class="p">(</span><span class="n">ColorBase</span><span class="o">&amp;</span> <span class="n">cb</span><span class="p">,</span> <span class="n">Color</span><span class="o">=</span><span class="n">Color</span><span class="p">());</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">ColorBase</span><span class="p">,</span> <span class="k">typename</span> <span class="n">Color</span><span class="o">&gt;</span>
<span class="k">typename</span> <span class="kt">color_const_reference_t</span><span class="o">&lt;</span><span class="n">Color</span><span class="p">,</span><span class="n">ColorBase</span><span class="o">&gt;::</span><span class="n">type</span> <span class="n">get_color</span><span class="p">(</span><span class="k">const</span> <span class="n">ColorBase</span><span class="o">&amp;</span> <span class="n">cb</span><span class="p">,</span> <span class="n">Color</span><span class="o">=</span><span class="n">Color</span><span class="p">());</span>
<span class="c1">// Returns the element type of the color base. Defined for homogeneous color bases only</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">ColorBase</span><span class="o">&gt;</span> <span class="k">struct</span> <span class="n">element_type</span><span class="p">;</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">ColorBase</span><span class="o">&gt;</span> <span class="k">struct</span> <span class="n">element_reference_type</span><span class="p">;</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">ColorBase</span><span class="o">&gt;</span> <span class="k">struct</span> <span class="n">element_const_reference_type</span><span class="p">;</span>
</pre></div>
</div>
<p>GIL also provides the following algorithms which operate on color bases. Note that they all pair the elements semantically:</p>
<div class="highlight-c++"><div class="highlight"><pre><span class="c1">// Equivalents to std::equal, std::copy, std::fill, std::generate</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">CB1</span><span class="p">,</span><span class="k">typename</span> <span class="n">CB2</span><span class="o">&gt;</span> <span class="kt">bool</span> <span class="n">static_equal</span><span class="p">(</span><span class="k">const</span> <span class="n">CB1</span><span class="o">&amp;</span> <span class="n">p1</span><span class="p">,</span> <span class="k">const</span> <span class="n">CB2</span><span class="o">&amp;</span> <span class="n">p2</span><span class="p">);</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">Src</span><span class="p">,</span><span class="k">typename</span> <span class="n">Dst</span><span class="o">&gt;</span> <span class="kt">void</span> <span class="n">static_copy</span><span class="p">(</span><span class="k">const</span> <span class="n">Src</span><span class="o">&amp;</span> <span class="n">src</span><span class="p">,</span> <span class="n">Dst</span><span class="o">&amp;</span> <span class="n">dst</span><span class="p">);</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">CB</span><span class="p">,</span> <span class="k">typename</span> <span class="n">Op</span><span class="o">&gt;</span> <span class="kt">void</span> <span class="n">static_generate</span><span class="p">(</span><span class="n">CB</span><span class="o">&amp;</span> <span class="n">dst</span><span class="p">,</span><span class="n">Op</span> <span class="n">op</span><span class="p">);</span>
<span class="c1">// Equivalents to std::transform</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">CB</span> <span class="p">,</span> <span class="k">typename</span> <span class="n">Dst</span><span class="p">,</span><span class="k">typename</span> <span class="n">Op</span><span class="o">&gt;</span> <span class="n">Op</span> <span class="n">static_transform</span><span class="p">(</span> <span class="n">CB</span><span class="o">&amp;</span><span class="p">,</span><span class="n">Dst</span><span class="o">&amp;</span><span class="p">,</span><span class="n">Op</span><span class="p">);</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">CB</span> <span class="p">,</span> <span class="k">typename</span> <span class="n">Dst</span><span class="p">,</span><span class="k">typename</span> <span class="n">Op</span><span class="o">&gt;</span> <span class="n">Op</span> <span class="n">static_transform</span><span class="p">(</span><span class="k">const</span> <span class="n">CB</span><span class="o">&amp;</span><span class="p">,</span><span class="n">Dst</span><span class="o">&amp;</span><span class="p">,</span><span class="n">Op</span><span class="p">);</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">CB1</span><span class="p">,</span><span class="k">typename</span> <span class="n">CB2</span><span class="p">,</span><span class="k">typename</span> <span class="n">Dst</span><span class="p">,</span><span class="k">typename</span> <span class="n">Op</span><span class="o">&gt;</span> <span class="n">Op</span> <span class="n">static_transform</span><span class="p">(</span> <span class="n">CB1</span><span class="o">&amp;</span><span class="p">,</span> <span class="n">CB2</span><span class="o">&amp;</span><span class="p">,</span><span class="n">Dst</span><span class="o">&amp;</span><span class="p">,</span><span class="n">Op</span><span class="p">);</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">CB1</span><span class="p">,</span><span class="k">typename</span> <span class="n">CB2</span><span class="p">,</span><span class="k">typename</span> <span class="n">Dst</span><span class="p">,</span><span class="k">typename</span> <span class="n">Op</span><span class="o">&gt;</span> <span class="n">Op</span> <span class="n">static_transform</span><span class="p">(</span><span class="k">const</span> <span class="n">CB1</span><span class="o">&amp;</span><span class="p">,</span> <span class="n">CB2</span><span class="o">&amp;</span><span class="p">,</span><span class="n">Dst</span><span class="o">&amp;</span><span class="p">,</span><span class="n">Op</span><span class="p">);</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">CB1</span><span class="p">,</span><span class="k">typename</span> <span class="n">CB2</span><span class="p">,</span><span class="k">typename</span> <span class="n">Dst</span><span class="p">,</span><span class="k">typename</span> <span class="n">Op</span><span class="o">&gt;</span> <span class="n">Op</span> <span class="n">static_transform</span><span class="p">(</span> <span class="n">CB1</span><span class="o">&amp;</span><span class="p">,</span><span class="k">const</span> <span class="n">CB2</span><span class="o">&amp;</span><span class="p">,</span><span class="n">Dst</span><span class="o">&amp;</span><span class="p">,</span><span class="n">Op</span><span class="p">);</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">CB1</span><span class="p">,</span><span class="k">typename</span> <span class="n">CB2</span><span class="p">,</span><span class="k">typename</span> <span class="n">Dst</span><span class="p">,</span><span class="k">typename</span> <span class="n">Op</span><span class="o">&gt;</span> <span class="n">Op</span> <span class="n">static_transform</span><span class="p">(</span><span class="k">const</span> <span class="n">CB1</span><span class="o">&amp;</span><span class="p">,</span><span class="k">const</span> <span class="n">CB2</span><span class="o">&amp;</span><span class="p">,</span><span class="n">Dst</span><span class="o">&amp;</span><span class="p">,</span><span class="n">Op</span><span class="p">);</span>
<span class="c1">// Equivalents to std::for_each</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">CB1</span><span class="p">,</span> <span class="k">typename</span> <span class="n">Op</span><span class="o">&gt;</span> <span class="n">Op</span> <span class="n">static_for_each</span><span class="p">(</span> <span class="n">CB1</span><span class="o">&amp;</span><span class="p">,</span><span class="n">Op</span><span class="p">);</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">CB1</span><span class="p">,</span> <span class="k">typename</span> <span class="n">Op</span><span class="o">&gt;</span> <span class="n">Op</span> <span class="n">static_for_each</span><span class="p">(</span><span class="k">const</span> <span class="n">CB1</span><span class="o">&amp;</span><span class="p">,</span><span class="n">Op</span><span class="p">);</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">CB1</span><span class="p">,</span><span class="k">typename</span> <span class="n">CB2</span><span class="p">,</span> <span class="k">typename</span> <span class="n">Op</span><span class="o">&gt;</span> <span class="n">Op</span> <span class="n">static_for_each</span><span class="p">(</span> <span class="n">CB1</span><span class="o">&amp;</span><span class="p">,</span> <span class="n">CB2</span><span class="o">&amp;</span><span class="p">,</span><span class="n">Op</span><span class="p">);</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">CB1</span><span class="p">,</span><span class="k">typename</span> <span class="n">CB2</span><span class="p">,</span> <span class="k">typename</span> <span class="n">Op</span><span class="o">&gt;</span> <span class="n">Op</span> <span class="n">static_for_each</span><span class="p">(</span> <span class="n">CB1</span><span class="o">&amp;</span><span class="p">,</span><span class="k">const</span> <span class="n">CB2</span><span class="o">&amp;</span><span class="p">,</span><span class="n">Op</span><span class="p">);</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">CB1</span><span class="p">,</span><span class="k">typename</span> <span class="n">CB2</span><span class="p">,</span> <span class="k">typename</span> <span class="n">Op</span><span class="o">&gt;</span> <span class="n">Op</span> <span class="n">static_for_each</span><span class="p">(</span><span class="k">const</span> <span class="n">CB1</span><span class="o">&amp;</span><span class="p">,</span> <span class="n">CB2</span><span class="o">&amp;</span><span class="p">,</span><span class="n">Op</span><span class="p">);</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">CB1</span><span class="p">,</span><span class="k">typename</span> <span class="n">CB2</span><span class="p">,</span> <span class="k">typename</span> <span class="n">Op</span><span class="o">&gt;</span> <span class="n">Op</span> <span class="n">static_for_each</span><span class="p">(</span><span class="k">const</span> <span class="n">CB1</span><span class="o">&amp;</span><span class="p">,</span><span class="k">const</span> <span class="n">CB2</span><span class="o">&amp;</span><span class="p">,</span><span class="n">Op</span><span class="p">);</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">CB1</span><span class="p">,</span><span class="k">typename</span> <span class="n">CB2</span><span class="p">,</span><span class="k">typename</span> <span class="n">CB3</span><span class="p">,</span><span class="k">typename</span> <span class="n">Op</span><span class="o">&gt;</span> <span class="n">Op</span> <span class="n">static_for_each</span><span class="p">(</span> <span class="n">CB1</span><span class="o">&amp;</span><span class="p">,</span> <span class="n">CB2</span><span class="o">&amp;</span><span class="p">,</span> <span class="n">CB3</span><span class="o">&amp;</span><span class="p">,</span><span class="n">Op</span><span class="p">);</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">CB1</span><span class="p">,</span><span class="k">typename</span> <span class="n">CB2</span><span class="p">,</span><span class="k">typename</span> <span class="n">CB3</span><span class="p">,</span><span class="k">typename</span> <span class="n">Op</span><span class="o">&gt;</span> <span class="n">Op</span> <span class="n">static_for_each</span><span class="p">(</span> <span class="n">CB1</span><span class="o">&amp;</span><span class="p">,</span> <span class="n">CB2</span><span class="o">&amp;</span><span class="p">,</span><span class="k">const</span> <span class="n">CB3</span><span class="o">&amp;</span><span class="p">,</span><span class="n">Op</span><span class="p">);</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">CB1</span><span class="p">,</span><span class="k">typename</span> <span class="n">CB2</span><span class="p">,</span><span class="k">typename</span> <span class="n">CB3</span><span class="p">,</span><span class="k">typename</span> <span class="n">Op</span><span class="o">&gt;</span> <span class="n">Op</span> <span class="n">static_for_each</span><span class="p">(</span> <span class="n">CB1</span><span class="o">&amp;</span><span class="p">,</span><span class="k">const</span> <span class="n">CB2</span><span class="o">&amp;</span><span class="p">,</span> <span class="n">CB3</span><span class="o">&amp;</span><span class="p">,</span><span class="n">Op</span><span class="p">);</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">CB1</span><span class="p">,</span><span class="k">typename</span> <span class="n">CB2</span><span class="p">,</span><span class="k">typename</span> <span class="n">CB3</span><span class="p">,</span><span class="k">typename</span> <span class="n">Op</span><span class="o">&gt;</span> <span class="n">Op</span> <span class="n">static_for_each</span><span class="p">(</span> <span class="n">CB1</span><span class="o">&amp;</span><span class="p">,</span><span class="k">const</span> <span class="n">CB2</span><span class="o">&amp;</span><span class="p">,</span><span class="k">const</span> <span class="n">CB3</span><span class="o">&amp;</span><span class="p">,</span><span class="n">Op</span><span class="p">);</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">CB1</span><span class="p">,</span><span class="k">typename</span> <span class="n">CB2</span><span class="p">,</span><span class="k">typename</span> <span class="n">CB3</span><span class="p">,</span><span class="k">typename</span> <span class="n">Op</span><span class="o">&gt;</span> <span class="n">Op</span> <span class="n">static_for_each</span><span class="p">(</span><span class="k">const</span> <span class="n">CB1</span><span class="o">&amp;</span><span class="p">,</span> <span class="n">CB2</span><span class="o">&amp;</span><span class="p">,</span> <span class="n">CB3</span><span class="o">&amp;</span><span class="p">,</span><span class="n">Op</span><span class="p">);</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">CB1</span><span class="p">,</span><span class="k">typename</span> <span class="n">CB2</span><span class="p">,</span><span class="k">typename</span> <span class="n">CB3</span><span class="p">,</span><span class="k">typename</span> <span class="n">Op</span><span class="o">&gt;</span> <span class="n">Op</span> <span class="n">static_for_each</span><span class="p">(</span><span class="k">const</span> <span class="n">CB1</span><span class="o">&amp;</span><span class="p">,</span> <span class="n">CB2</span><span class="o">&amp;</span><span class="p">,</span><span class="k">const</span> <span class="n">CB3</span><span class="o">&amp;</span><span class="p">,</span><span class="n">Op</span><span class="p">);</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">CB1</span><span class="p">,</span><span class="k">typename</span> <span class="n">CB2</span><span class="p">,</span><span class="k">typename</span> <span class="n">CB3</span><span class="p">,</span><span class="k">typename</span> <span class="n">Op</span><span class="o">&gt;</span> <span class="n">Op</span> <span class="n">static_for_each</span><span class="p">(</span><span class="k">const</span> <span class="n">CB1</span><span class="o">&amp;</span><span class="p">,</span><span class="k">const</span> <span class="n">CB2</span><span class="o">&amp;</span><span class="p">,</span> <span class="n">CB3</span><span class="o">&amp;</span><span class="p">,</span><span class="n">Op</span><span class="p">);</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">CB1</span><span class="p">,</span><span class="k">typename</span> <span class="n">CB2</span><span class="p">,</span><span class="k">typename</span> <span class="n">CB3</span><span class="p">,</span><span class="k">typename</span> <span class="n">Op</span><span class="o">&gt;</span> <span class="n">Op</span> <span class="n">static_for_each</span><span class="p">(</span><span class="k">const</span> <span class="n">CB1</span><span class="o">&amp;</span><span class="p">,</span><span class="k">const</span> <span class="n">CB2</span><span class="o">&amp;</span><span class="p">,</span><span class="k">const</span> <span class="n">CB3</span><span class="o">&amp;</span><span class="p">,</span><span class="n">Op</span><span class="p">);</span>
<span class="c1">// The following algorithms are only defined for homogeneous color bases:</span>
<span class="c1">// Equivalent to std::fill</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">HCB</span><span class="p">,</span> <span class="k">typename</span> <span class="n">Element</span><span class="o">&gt;</span> <span class="kt">void</span> <span class="n">static_fill</span><span class="p">(</span><span class="n">HCB</span><span class="o">&amp;</span> <span class="n">p</span><span class="p">,</span> <span class="k">const</span> <span class="n">Element</span><span class="o">&amp;</span> <span class="n">v</span><span class="p">);</span>
<span class="c1">// Equivalents to std::min_element and std::max_element</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">HCB</span><span class="o">&gt;</span> <span class="k">typename</span> <span class="n">element_const_reference_type</span><span class="o">&lt;</span><span class="n">HCB</span><span class="o">&gt;::</span><span class="n">type</span> <span class="n">static_min</span><span class="p">(</span><span class="k">const</span> <span class="n">HCB</span><span class="o">&amp;</span><span class="p">);</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">HCB</span><span class="o">&gt;</span> <span class="k">typename</span> <span class="n">element_reference_type</span><span class="o">&lt;</span><span class="n">HCB</span><span class="o">&gt;::</span><span class="n">type</span> <span class="n">static_min</span><span class="p">(</span> <span class="n">HCB</span><span class="o">&amp;</span><span class="p">);</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">HCB</span><span class="o">&gt;</span> <span class="k">typename</span> <span class="n">element_const_reference_type</span><span class="o">&lt;</span><span class="n">HCB</span><span class="o">&gt;::</span><span class="n">type</span> <span class="n">static_max</span><span class="p">(</span><span class="k">const</span> <span class="n">HCB</span><span class="o">&amp;</span><span class="p">);</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">HCB</span><span class="o">&gt;</span> <span class="k">typename</span> <span class="n">element_reference_type</span><span class="o">&lt;</span><span class="n">HCB</span><span class="o">&gt;::</span><span class="n">type</span> <span class="n">static_max</span><span class="p">(</span> <span class="n">HCB</span><span class="o">&amp;</span><span class="p">);</span>
</pre></div>
</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 &#8220;static_&#8221;). Finally, they pair the elements semantically instead of based
on their physical order in memory. For example, here is the implementation of <tt class="docutils literal"><span class="pre">static_equal</span></tt>:</p>
<div class="highlight-c++"><div class="highlight"><pre><span class="k">namespace</span> <span class="n">detail</span>
<span class="p">{</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="kt">int</span> <span class="n">K</span><span class="o">&gt;</span> <span class="k">struct</span> <span class="n">element_recursion</span>
<span class="p">{</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">P1</span><span class="p">,</span><span class="k">typename</span> <span class="n">P2</span><span class="o">&gt;</span>
<span class="k">static</span> <span class="kt">bool</span> <span class="n">static_equal</span><span class="p">(</span><span class="k">const</span> <span class="n">P1</span><span class="o">&amp;</span> <span class="n">p1</span><span class="p">,</span> <span class="k">const</span> <span class="n">P2</span><span class="o">&amp;</span> <span class="n">p2</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">return</span> <span class="n">element_recursion</span><span class="o">&lt;</span><span class="n">K</span><span class="o">-</span><span class="mi">1</span><span class="o">&gt;::</span><span class="n">static_equal</span><span class="p">(</span><span class="n">p1</span><span class="p">,</span><span class="n">p2</span><span class="p">)</span> <span class="o">&amp;&amp;</span>
<span class="n">semantic_at_c</span><span class="o">&lt;</span><span class="n">K</span><span class="o">-</span><span class="mi">1</span><span class="o">&gt;</span><span class="p">(</span><span class="n">p1</span><span class="p">)</span><span class="o">==</span><span class="n">semantic_at_c</span><span class="o">&lt;</span><span class="n">N</span><span class="o">-</span><span class="mi">1</span><span class="o">&gt;</span><span class="p">(</span><span class="n">p2</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">};</span>
<span class="k">template</span> <span class="o">&lt;&gt;</span> <span class="k">struct</span> <span class="n">element_recursion</span><span class="o">&lt;</span><span class="mi">0</span><span class="o">&gt;</span>
<span class="p">{</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">P1</span><span class="p">,</span><span class="k">typename</span> <span class="n">P2</span><span class="o">&gt;</span>
<span class="k">static</span> <span class="kt">bool</span> <span class="n">static_equal</span><span class="p">(</span><span class="k">const</span> <span class="n">P1</span><span class="o">&amp;</span><span class="p">,</span> <span class="k">const</span> <span class="n">P2</span><span class="o">&amp;</span><span class="p">)</span> <span class="p">{</span> <span class="k">return</span> <span class="nb">true</span><span class="p">;</span> <span class="p">}</span>
<span class="p">};</span>
<span class="p">}</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">P1</span><span class="p">,</span><span class="k">typename</span> <span class="n">P2</span><span class="o">&gt;</span>
<span class="kt">bool</span> <span class="n">static_equal</span><span class="p">(</span><span class="k">const</span> <span class="n">P1</span><span class="o">&amp;</span> <span class="n">p1</span><span class="p">,</span> <span class="k">const</span> <span class="n">P2</span><span class="o">&amp;</span> <span class="n">p2</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">gil_function_requires</span><span class="o">&lt;</span><span class="n">ColorSpacesCompatibleConcept</span><span class="o">&lt;</span><span class="n">P1</span><span class="o">::</span><span class="kt">layout_t</span><span class="o">::</span><span class="kt">color_space_t</span><span class="p">,</span><span class="n">P2</span><span class="o">::</span><span class="kt">layout_t</span><span class="o">::</span><span class="kt">color_space_t</span><span class="o">&gt;</span> <span class="o">&gt;</span><span class="p">();</span>
<span class="k">return</span> <span class="n">detail</span><span class="o">::</span><span class="n">element_recursion</span><span class="o">&lt;</span><span class="n">size</span><span class="o">&lt;</span><span class="n">P1</span><span class="o">&gt;::</span><span class="n">value</span><span class="o">&gt;::</span><span class="n">static_equal</span><span class="p">(</span><span class="n">p1</span><span class="p">,</span><span class="n">p2</span><span class="p">);</span>
<span class="p">}</span>
</pre></div>
</div>
<p>This algorithm is used when invoking <tt class="docutils literal"><span class="pre">operator==</span></tt> 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>
</div>
<div class="section" id="pixel">
<h2><a class="toc-backref" href="#id7">Pixel</a></h2>
<p>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 <tt class="docutils literal"><span class="pre">ChannelConcept</span></tt>.
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>
<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="highlight-c++"><div class="highlight"><pre><span class="n">concept</span> <span class="n">PixelBasedConcept</span><span class="o">&lt;</span><span class="k">typename</span> <span class="n">T</span><span class="o">&gt;</span>
<span class="p">{</span>
<span class="k">typename</span> <span class="n">color_space_type</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span><span class="p">;</span>
<span class="n">where</span> <span class="n">Metafunction</span><span class="o">&lt;</span><span class="n">color_space_type</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span> <span class="o">&gt;</span><span class="p">;</span>
<span class="n">where</span> <span class="n">ColorSpaceConcept</span><span class="o">&lt;</span><span class="n">color_space_type</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;::</span><span class="n">type</span><span class="o">&gt;</span><span class="p">;</span>
<span class="k">typename</span> <span class="n">channel_mapping_type</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span><span class="p">;</span>
<span class="n">where</span> <span class="n">Metafunction</span><span class="o">&lt;</span><span class="n">channel_mapping_type</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span> <span class="o">&gt;</span><span class="p">;</span>
<span class="n">where</span> <span class="n">ChannelMappingConcept</span><span class="o">&lt;</span><span class="n">channel_mapping_type</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;::</span><span class="n">type</span><span class="o">&gt;</span><span class="p">;</span>
<span class="k">typename</span> <span class="n">is_planar</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span><span class="p">;</span>
<span class="n">where</span> <span class="n">Metafunction</span><span class="o">&lt;</span><span class="n">is_planar</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span> <span class="o">&gt;</span><span class="p">;</span>
<span class="n">where</span> <span class="n">SameType</span><span class="o">&lt;</span><span class="n">is_planar</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;::</span><span class="n">type</span><span class="p">,</span> <span class="kt">bool</span><span class="o">&gt;</span><span class="p">;</span>
<span class="p">};</span>
<span class="n">concept</span> <span class="n">HomogeneousPixelBasedConcept</span><span class="o">&lt;</span><span class="n">PixelBasedConcept</span> <span class="n">T</span><span class="o">&gt;</span>
<span class="p">{</span>
<span class="k">typename</span> <span class="n">channel_type</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span><span class="p">;</span>
<span class="n">where</span> <span class="n">Metafunction</span><span class="o">&lt;</span><span class="n">channel_type</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span> <span class="o">&gt;</span><span class="p">;</span>
<span class="n">where</span> <span class="n">ChannelConcept</span><span class="o">&lt;</span><span class="n">channel_type</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;::</span><span class="n">type</span><span class="o">&gt;</span><span class="p">;</span>
<span class="p">};</span>
</pre></div>
</div>
<p>Pixels model the following concepts:</p>
<div class="highlight-c++"><div class="highlight"><pre><span class="n">concept</span> <span class="n">PixelConcept</span><span class="o">&lt;</span><span class="k">typename</span> <span class="n">P</span><span class="o">&gt;</span> <span class="o">:</span> <span class="n">ColorBaseConcept</span><span class="o">&lt;</span><span class="n">P</span><span class="o">&gt;</span><span class="p">,</span> <span class="n">PixelBasedConcept</span><span class="o">&lt;</span><span class="n">P</span><span class="o">&gt;</span>
<span class="p">{</span>
<span class="n">where</span> <span class="n">is_pixel</span><span class="o">&lt;</span><span class="n">P</span><span class="o">&gt;::</span><span class="n">type</span><span class="o">::</span><span class="n">value</span><span class="o">==</span><span class="nb">true</span><span class="p">;</span>
<span class="c1">// where for each K [0..size&lt;P&gt;::value-1]:</span>
<span class="c1">// ChannelConcept&lt;kth_element_type&lt;K&gt; &gt;;</span>
<span class="k">typename</span> <span class="n">value_type</span><span class="p">;</span> <span class="n">where</span> <span class="n">PixelValueConcept</span><span class="o">&lt;</span><span class="n">value_type</span><span class="o">&gt;</span><span class="p">;</span>
<span class="k">typename</span> <span class="n">reference</span><span class="p">;</span> <span class="n">where</span> <span class="n">PixelConcept</span><span class="o">&lt;</span><span class="n">reference</span><span class="o">&gt;</span><span class="p">;</span>
<span class="k">typename</span> <span class="n">const_reference</span><span class="p">;</span> <span class="n">where</span> <span class="n">PixelConcept</span><span class="o">&lt;</span><span class="n">const_reference</span><span class="o">&gt;</span><span class="p">;</span>
<span class="k">static</span> <span class="k">const</span> <span class="kt">bool</span> <span class="n">P</span><span class="o">::</span><span class="n">is_mutable</span><span class="p">;</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="n">PixelConcept</span> <span class="n">P2</span><span class="o">&gt;</span> <span class="n">where</span> <span class="p">{</span> <span class="n">PixelConcept</span><span class="o">&lt;</span><span class="n">P</span><span class="p">,</span><span class="n">P2</span><span class="o">&gt;</span> <span class="p">}</span>
<span class="n">P</span><span class="o">::</span><span class="n">P</span><span class="p">(</span><span class="n">P2</span><span class="p">);</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="n">PixelConcept</span> <span class="n">P2</span><span class="o">&gt;</span> <span class="n">where</span> <span class="p">{</span> <span class="n">PixelConcept</span><span class="o">&lt;</span><span class="n">P</span><span class="p">,</span><span class="n">P2</span><span class="o">&gt;</span> <span class="p">}</span>
<span class="kt">bool</span> <span class="k">operator</span><span class="o">==</span><span class="p">(</span><span class="k">const</span> <span class="n">P</span><span class="o">&amp;</span><span class="p">,</span> <span class="k">const</span> <span class="n">P2</span><span class="o">&amp;</span><span class="p">);</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="n">PixelConcept</span> <span class="n">P2</span><span class="o">&gt;</span> <span class="n">where</span> <span class="p">{</span> <span class="n">PixelConcept</span><span class="o">&lt;</span><span class="n">P</span><span class="p">,</span><span class="n">P2</span><span class="o">&gt;</span> <span class="p">}</span>
<span class="kt">bool</span> <span class="k">operator</span><span class="o">!=</span><span class="p">(</span><span class="k">const</span> <span class="n">P</span><span class="o">&amp;</span><span class="p">,</span> <span class="k">const</span> <span class="n">P2</span><span class="o">&amp;</span><span class="p">);</span>
<span class="p">};</span>
<span class="n">concept</span> <span class="n">MutablePixelConcept</span><span class="o">&lt;</span><span class="k">typename</span> <span class="n">P</span><span class="o">&gt;</span> <span class="o">:</span> <span class="n">PixelConcept</span><span class="o">&lt;</span><span class="n">P</span><span class="o">&gt;</span><span class="p">,</span> <span class="n">MutableColorBaseConcept</span><span class="o">&lt;</span><span class="n">P</span><span class="o">&gt;</span>
<span class="p">{</span>
<span class="n">where</span> <span class="n">is_mutable</span><span class="o">==</span><span class="nb">true</span><span class="p">;</span>
<span class="p">};</span>
<span class="n">concept</span> <span class="n">HomogeneousPixelConcept</span><span class="o">&lt;</span><span class="n">PixelConcept</span> <span class="n">P</span><span class="o">&gt;</span> <span class="o">:</span> <span class="n">HomogeneousColorBaseConcept</span><span class="o">&lt;</span><span class="n">P</span><span class="o">&gt;</span><span class="p">,</span> <span class="n">HomogeneousPixelBasedConcept</span><span class="o">&lt;</span><span class="n">P</span><span class="o">&gt;</span>
<span class="p">{</span>
<span class="n">P</span><span class="o">::</span><span class="k">template</span> <span class="n">element_const_reference_type</span><span class="o">&lt;</span><span class="n">P</span><span class="o">&gt;::</span><span class="n">type</span> <span class="k">operator</span><span class="p">[](</span><span class="n">P</span> <span class="n">p</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="kt">size_t</span> <span class="n">i</span><span class="p">)</span> <span class="k">const</span> <span class="p">{</span> <span class="k">return</span> <span class="n">dynamic_at_c</span><span class="p">(</span><span class="n">P</span><span class="p">,</span><span class="n">i</span><span class="p">);</span> <span class="p">}</span>
<span class="p">};</span>
<span class="n">concept</span> <span class="n">MutableHomogeneousPixelConcept</span><span class="o">&lt;</span><span class="n">MutablePixelConcept</span> <span class="n">P</span><span class="o">&gt;</span> <span class="o">:</span> <span class="n">MutableHomogeneousColorBaseConcept</span><span class="o">&lt;</span><span class="n">P</span><span class="o">&gt;</span>
<span class="p">{</span>
<span class="n">P</span><span class="o">::</span><span class="k">template</span> <span class="n">element_reference_type</span><span class="o">&lt;</span><span class="n">P</span><span class="o">&gt;::</span><span class="n">type</span> <span class="k">operator</span><span class="p">[](</span><span class="n">P</span> <span class="n">p</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="kt">size_t</span> <span class="n">i</span><span class="p">)</span> <span class="p">{</span> <span class="k">return</span> <span class="n">dynamic_at_c</span><span class="p">(</span><span class="n">p</span><span class="p">,</span><span class="n">i</span><span class="p">);</span> <span class="p">}</span>
<span class="p">};</span>
<span class="n">concept</span> <span class="n">PixelValueConcept</span><span class="o">&lt;</span><span class="k">typename</span> <span class="n">P</span><span class="o">&gt;</span> <span class="o">:</span> <span class="n">PixelConcept</span><span class="o">&lt;</span><span class="n">P</span><span class="o">&gt;</span><span class="p">,</span> <span class="n">Regular</span><span class="o">&lt;</span><span class="n">P</span><span class="o">&gt;</span>
<span class="p">{</span>
<span class="n">where</span> <span class="n">SameType</span><span class="o">&lt;</span><span class="n">value_type</span><span class="p">,</span><span class="n">P</span><span class="o">&gt;</span><span class="p">;</span>
<span class="p">};</span>
<span class="n">concept</span> <span class="n">PixelsCompatibleConcept</span><span class="o">&lt;</span><span class="n">PixelConcept</span> <span class="n">P1</span><span class="p">,</span> <span class="n">PixelConcept</span> <span class="n">P2</span><span class="o">&gt;</span> <span class="o">:</span> <span class="n">ColorBasesCompatibleConcept</span><span class="o">&lt;</span><span class="n">P1</span><span class="p">,</span><span class="n">P2</span><span class="o">&gt;</span>
<span class="p">{</span>
<span class="c1">// where for each K [0..size&lt;P1&gt;::value):</span>
<span class="c1">// ChannelsCompatibleConcept&lt;kth_semantic_element_type&lt;P1,K&gt;::type, kth_semantic_element_type&lt;P2,K&gt;::type&gt;;</span>
<span class="p">};</span>
</pre></div>
</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). Convertibility requires modeling the following concept:</p>
<div class="highlight-c++"><div class="highlight"><pre><span class="k">template</span> <span class="o">&lt;</span><span class="n">PixelConcept</span> <span class="n">SrcPixel</span><span class="p">,</span> <span class="n">MutablePixelConcept</span> <span class="n">DstPixel</span><span class="o">&gt;</span>
<span class="n">concept</span> <span class="n">PixelConvertibleConcept</span>
<span class="p">{</span>
<span class="kt">void</span> <span class="n">color_convert</span><span class="p">(</span><span class="k">const</span> <span class="n">SrcPixel</span><span class="o">&amp;</span><span class="p">,</span> <span class="n">DstPixel</span><span class="o">&amp;</span><span class="p">);</span>
<span class="p">};</span>
</pre></div>
</div>
<p>The distinction between <tt class="docutils literal"><span class="pre">PixelConcept</span></tt> and <tt class="docutils literal"><span class="pre">PixelValueConcept</span></tt> is analogous to that for channels and color bases - pixel reference proxies model both,
but only pixel values model the latter.</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name" colspan="2">Related Concepts:</th></tr>
<tr class="field-odd field"><td>&nbsp;</td><td class="field-body"></td>
</tr>
</tbody>
</table>
<ul class="simple">
<li>PixelBasedConcept</li>
<li>PixelConcept</li>
<li>MutablePixelConcept</li>
<li>PixelValueConcept</li>
<li>HomogeneousPixelConcept</li>
<li>MutableHomogeneousPixelConcept</li>
<li>HomogeneousPixelValueConcept</li>
<li>PixelsCompatibleConcept</li>
<li>PixelConvertibleConcept</li>
</ul>
<p>The most commonly used pixel is a homogeneous pixel whose values are together in memory.
For this purpose GIL provides the struct <tt class="docutils literal"><span class="pre">pixel</span></tt>, templated over the channel value and layout:</p>
<div class="highlight-c++"><div class="highlight"><pre><span class="c1">// models HomogeneousPixelValueConcept</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">ChannelValue</span><span class="p">,</span> <span class="k">typename</span> <span class="n">Layout</span><span class="o">&gt;</span> <span class="k">struct</span> <span class="n">pixel</span><span class="p">;</span>
<span class="c1">// Those typedefs are already provided by GIL</span>
<span class="k">typedef</span> <span class="n">pixel</span><span class="o">&lt;</span><span class="n">bits8</span><span class="p">,</span> <span class="kt">rgb_layout_t</span><span class="o">&gt;</span> <span class="kt">rgb8_pixel_t</span><span class="p">;</span>
<span class="k">typedef</span> <span class="n">pixel</span><span class="o">&lt;</span><span class="n">bits8</span><span class="p">,</span> <span class="kt">bgr_layout_t</span><span class="o">&gt;</span> <span class="kt">bgr8_pixel_t</span><span class="p">;</span>
<span class="kt">bgr8_pixel_t</span> <span class="nf">bgr8</span><span class="p">(</span><span class="mi">255</span><span class="p">,</span><span class="mi">0</span><span class="p">,</span><span class="mi">0</span><span class="p">);</span> <span class="c1">// pixels can be initialized with the channels directly</span>
<span class="kt">rgb8_pixel_t</span> <span class="nf">rgb8</span><span class="p">(</span><span class="n">bgr8</span><span class="p">);</span> <span class="c1">// compatible pixels can also be copy-constructed</span>
<span class="n">rgb8</span> <span class="o">=</span> <span class="n">bgr8</span><span class="p">;</span> <span class="c1">// assignment and equality is defined between compatible pixels</span>
<span class="n">assert</span><span class="p">(</span><span class="n">rgb8</span> <span class="o">==</span> <span class="n">bgr8</span><span class="p">);</span> <span class="c1">// assignment and equality operate on the semantic channels</span>
<span class="c1">// The first physical channels of the two pixels are different</span>
<span class="n">assert</span><span class="p">(</span><span class="n">at_c</span><span class="o">&lt;</span><span class="mi">0</span><span class="o">&gt;</span><span class="p">(</span><span class="n">rgb8</span><span class="p">)</span> <span class="o">!=</span> <span class="n">at_c</span><span class="o">&lt;</span><span class="mi">0</span><span class="o">&gt;</span><span class="p">(</span><span class="n">bgr8</span><span class="p">));</span>
<span class="n">assert</span><span class="p">(</span><span class="n">dynamic_at_c</span><span class="p">(</span><span class="n">bgr8</span><span class="p">,</span><span class="mi">0</span><span class="p">)</span> <span class="o">!=</span> <span class="n">dynamic_at_c</span><span class="p">(</span><span class="n">rgb8</span><span class="p">,</span><span class="mi">0</span><span class="p">));</span>
<span class="n">assert</span><span class="p">(</span><span class="n">rgb8</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">!=</span> <span class="n">bgr8</span><span class="p">[</span><span class="mi">0</span><span class="p">]);</span> <span class="c1">// same as above (but operator[] is defined for pixels only)</span>
</pre></div>
</div>
<p>Planar pixels have their channels distributed in memory. While they share the same value type (<tt class="docutils literal"><span class="pre">pixel</span></tt>) with interleaved pixels, their
reference type is a proxy class containing references to each of the channels. This is implemented with the struct <tt class="docutils literal"><span class="pre">planar_pixel_reference</span></tt>:</p>
<div class="highlight-c++"><div class="highlight"><pre><span class="c1">// models HomogeneousPixel</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">ChannelReference</span><span class="p">,</span> <span class="k">typename</span> <span class="n">ColorSpace</span><span class="o">&gt;</span> <span class="k">struct</span> <span class="n">planar_pixel_reference</span><span class="p">;</span>
<span class="c1">// Define the type of a mutable and read-only reference. (These typedefs are already provided by GIL)</span>
<span class="k">typedef</span> <span class="n">planar_pixel_reference</span><span class="o">&lt;</span> <span class="n">bits8</span><span class="o">&amp;</span><span class="p">,</span><span class="kt">rgb_t</span><span class="o">&gt;</span> <span class="kt">rgb8_planar_ref_t</span><span class="p">;</span>
<span class="k">typedef</span> <span class="n">planar_pixel_reference</span><span class="o">&lt;</span><span class="k">const</span> <span class="n">bits8</span><span class="o">&amp;</span><span class="p">,</span><span class="kt">rgb_t</span><span class="o">&gt;</span> <span class="kt">rgb8c_planar_ref_t</span><span class="p">;</span>
</pre></div>
</div>
<p>Note that, unlike the <tt class="docutils literal"><span class="pre">pixel</span></tt> struct, planar pixel references are templated over the color space, not over the pixel layout. They always
use a canonical channel ordering. Ordering of their elements is unnecessary because their elements are references to the channels.</p>
<p>Sometimes the channels of a pixel may not be byte-aligned. For example an RGB pixel in &#8216;5-5-6&#8217; 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="highlight-c++"><div class="highlight"><pre><span class="c1">// define an rgb565 pixel</span>
<span class="k">typedef</span> <span class="n">packed_pixel_type</span><span class="o">&lt;</span><span class="kt">uint16_t</span><span class="p">,</span> <span class="n">mpl</span><span class="o">::</span><span class="n">vector3_c</span><span class="o">&lt;</span><span class="kt">unsigned</span><span class="p">,</span><span class="mi">5</span><span class="p">,</span><span class="mi">6</span><span class="p">,</span><span class="mi">5</span><span class="o">&gt;</span><span class="p">,</span> <span class="kt">rgb_layout_t</span><span class="o">&gt;::</span><span class="n">type</span> <span class="kt">rgb565_pixel_t</span><span class="p">;</span>
<span class="n">function_requires</span><span class="o">&lt;</span><span class="n">PixelValueConcept</span><span class="o">&lt;</span><span class="kt">rgb565_pixel_t</span><span class="o">&gt;</span> <span class="o">&gt;</span><span class="p">();</span>
<span class="n">BOOST_STATIC_ASSERT</span><span class="p">((</span><span class="k">sizeof</span><span class="p">(</span><span class="kt">rgb565_pixel_t</span><span class="p">)</span><span class="o">==</span><span class="mi">2</span><span class="p">));</span>
<span class="c1">// define a bgr556 pixel</span>
<span class="k">typedef</span> <span class="n">packed_pixel_type</span><span class="o">&lt;</span><span class="kt">uint16_t</span><span class="p">,</span> <span class="n">mpl</span><span class="o">::</span><span class="n">vector3_c</span><span class="o">&lt;</span><span class="kt">unsigned</span><span class="p">,</span><span class="mi">5</span><span class="p">,</span><span class="mi">6</span><span class="p">,</span><span class="mi">5</span><span class="o">&gt;</span><span class="p">,</span> <span class="kt">bgr_layout_t</span><span class="o">&gt;::</span><span class="n">type</span> <span class="kt">bgr556_pixel_t</span><span class="p">;</span>
<span class="n">function_requires</span><span class="o">&lt;</span><span class="n">PixelValueConcept</span><span class="o">&lt;</span><span class="kt">bgr556_pixel_t</span><span class="o">&gt;</span> <span class="o">&gt;</span><span class="p">();</span>
<span class="c1">// rgb565 is compatible with bgr556.</span>
<span class="n">function_requires</span><span class="o">&lt;</span><span class="n">PixelsCompatibleConcept</span><span class="o">&lt;</span><span class="kt">rgb565_pixel_t</span><span class="p">,</span><span class="kt">bgr556_pixel_t</span><span class="o">&gt;</span> <span class="o">&gt;</span><span class="p">();</span>
</pre></div>
</div>
<p>In some cases, the pixel itself may not be byte aligned. For example, consider an RGB pixel in &#8216;2-3-2&#8217; format. Its size is 7 bits.
GIL refers to such pixels, pixel iterators and images as &#8220;bit-aligned&#8221;. 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="highlight-c++"><div class="highlight"><pre><span class="c1">// Mutable reference to a BGR232 pixel</span>
<span class="k">typedef</span> <span class="k">const</span> <span class="n">bit_aligned_pixel_reference</span><span class="o">&lt;</span><span class="kt">unsigned</span> <span class="kt">char</span><span class="p">,</span> <span class="n">mpl</span><span class="o">::</span><span class="n">vector3_c</span><span class="o">&lt;</span><span class="kt">unsigned</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">3</span><span class="p">,</span><span class="mi">2</span><span class="o">&gt;</span><span class="p">,</span> <span class="kt">bgr_layout_t</span><span class="p">,</span> <span class="nb">true</span><span class="o">&gt;</span> <span class="kt">bgr232_ref_t</span><span class="p">;</span>
<span class="c1">// A mutable iterator over BGR232 pixels</span>
<span class="k">typedef</span> <span class="n">bit_aligned_pixel_iterator</span><span class="o">&lt;</span><span class="kt">bgr232_ref_t</span><span class="o">&gt;</span> <span class="kt">bgr232_ptr_t</span><span class="p">;</span>
<span class="c1">// BGR232 pixel value. It is a packed_pixel of size 1 byte. (The last bit is unused)</span>
<span class="k">typedef</span> <span class="n">std</span><span class="o">::</span><span class="n">iterator_traits</span><span class="o">&lt;</span><span class="kt">bgr232_ptr_t</span><span class="o">&gt;::</span><span class="n">value_type</span> <span class="kt">bgr232_pixel_t</span><span class="p">;</span>
<span class="n">BOOST_STATIC_ASSERT</span><span class="p">((</span><span class="k">sizeof</span><span class="p">(</span><span class="kt">bgr232_pixel_t</span><span class="p">)</span><span class="o">==</span><span class="mi">1</span><span class="p">));</span>
<span class="kt">bgr232_pixel_t</span> <span class="nf">red</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="mi">0</span><span class="p">,</span><span class="mi">3</span><span class="p">);</span> <span class="c1">// = 0RRGGGBB, = 01100000 = 0x60</span>
<span class="c1">// a buffer of 7 bytes fits exactly 8 BGR232 pixels.</span>
<span class="kt">unsigned</span> <span class="kt">char</span> <span class="n">pix_buffer</span><span class="p">[</span><span class="mi">7</span><span class="p">];</span>
<span class="n">std</span><span class="o">::</span><span class="n">fill</span><span class="p">(</span><span class="n">pix_buffer</span><span class="p">,</span><span class="n">pix_buffer</span><span class="o">+</span><span class="mi">7</span><span class="p">,</span><span class="mi">0</span><span class="p">);</span>
<span class="c1">// Fill the 8 pixels with red</span>
<span class="kt">bgr232_ptr_t</span> <span class="nf">pix_it</span><span class="p">(</span><span class="o">&amp;</span><span class="n">pix_buffer</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span><span class="mi">0</span><span class="p">);</span> <span class="c1">// start at bit 0 of the first pixel</span>
<span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">i</span><span class="o">&lt;</span><span class="mi">8</span><span class="p">;</span> <span class="o">++</span><span class="n">i</span><span class="p">)</span>
<span class="p">{</span>
<span class="o">*</span><span class="n">pix_it</span><span class="o">++</span> <span class="o">=</span> <span class="n">red</span><span class="p">;</span>
<span class="p">}</span>
<span class="c1">// Result: 0x60 0x30 0x11 0x0C 0x06 0x83 0xC1</span>
</pre></div>
</div>
<p>&lt;b&gt;Algorithms:&lt;/b&gt;</p>
<p>Since pixels model <tt class="docutils literal"><span class="pre">ColorBaseConcept</span></tt> and <tt class="docutils literal"><span class="pre">PixelBasedConcept</span></tt> all algorithms and metafunctions of color bases can work with them as well:</p>
<div class="highlight-c++"><div class="highlight"><pre><span class="c1">// This is how to access the first semantic channel (red)</span>
<span class="n">assert</span><span class="p">(</span><span class="n">semantic_at_c</span><span class="o">&lt;</span><span class="mi">0</span><span class="o">&gt;</span><span class="p">(</span><span class="n">rgb8</span><span class="p">)</span> <span class="o">==</span> <span class="n">semantic_at_c</span><span class="o">&lt;</span><span class="mi">0</span><span class="o">&gt;</span><span class="p">(</span><span class="n">bgr8</span><span class="p">));</span>
<span class="c1">// This is how to access the red channel by name</span>
<span class="n">assert</span><span class="p">(</span><span class="n">get_color</span><span class="o">&lt;</span><span class="kt">red_t</span><span class="o">&gt;</span><span class="p">(</span><span class="n">rgb8</span><span class="p">)</span> <span class="o">==</span> <span class="n">get_color</span><span class="o">&lt;</span><span class="kt">red_t</span><span class="o">&gt;</span><span class="p">(</span><span class="n">bgr8</span><span class="p">));</span>
<span class="c1">// This is another way of doing it (some compilers don&#39;t like the first one)</span>
<span class="n">assert</span><span class="p">(</span><span class="n">get_color</span><span class="p">(</span><span class="n">rgb8</span><span class="p">,</span><span class="kt">red_t</span><span class="p">())</span> <span class="o">==</span> <span class="n">get_color</span><span class="p">(</span><span class="n">bgr8</span><span class="p">,</span><span class="kt">red_t</span><span class="p">()));</span>
<span class="c1">// This is how to use the PixelBasedConcept metafunctions</span>
<span class="n">BOOST_MPL_ASSERT</span><span class="p">(</span><span class="n">num_channels</span><span class="o">&lt;</span><span class="kt">rgb8_pixel_t</span><span class="o">&gt;::</span><span class="n">value</span> <span class="o">==</span> <span class="mi">3</span><span class="p">);</span>
<span class="n">BOOST_MPL_ASSERT</span><span class="p">((</span><span class="n">is_same</span><span class="o">&lt;</span><span class="n">channel_type</span><span class="o">&lt;</span><span class="kt">rgb8_pixel_t</span><span class="o">&gt;::</span><span class="n">type</span><span class="p">,</span> <span class="n">bits8</span><span class="o">&gt;</span><span class="p">));</span>
<span class="n">BOOST_MPL_ASSERT</span><span class="p">((</span><span class="n">is_same</span><span class="o">&lt;</span><span class="n">color_space_type</span><span class="o">&lt;</span><span class="kt">bgr8_pixel_t</span><span class="o">&gt;::</span><span class="n">type</span><span class="p">,</span> <span class="kt">rgb_t</span><span class="o">&gt;</span> <span class="p">));</span>
<span class="n">BOOST_MPL_ASSERT</span><span class="p">((</span><span class="n">is_same</span><span class="o">&lt;</span><span class="n">channel_mapping_type</span><span class="o">&lt;</span><span class="kt">bgr8_pixel_t</span><span class="o">&gt;::</span><span class="n">type</span><span class="p">,</span> <span class="n">mpl</span><span class="o">::</span><span class="n">vector3_c</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">1</span><span class="p">,</span><span class="mi">0</span><span class="o">&gt;</span> <span class="o">&gt;</span> <span class="p">));</span>
<span class="c1">// Pixels contain just the three channels and nothing extra</span>
<span class="n">BOOST_MPL_ASSERT</span><span class="p">(</span><span class="k">sizeof</span><span class="p">(</span><span class="kt">rgb8_pixel_t</span><span class="p">)</span><span class="o">==</span><span class="mi">3</span><span class="p">);</span>
<span class="kt">rgb8_planar_ref_t</span> <span class="nf">ref</span><span class="p">(</span><span class="n">bgr8</span><span class="p">);</span> <span class="c1">// copy construction is allowed from a compatible mutable pixel type</span>
<span class="n">get_color</span><span class="o">&lt;</span><span class="kt">red_t</span><span class="o">&gt;</span><span class="p">(</span><span class="n">ref</span><span class="p">)</span> <span class="o">=</span> <span class="mi">10</span><span class="p">;</span> <span class="c1">// assignment is ok because the reference is mutable</span>
<span class="n">assert</span><span class="p">(</span><span class="n">get_color</span><span class="o">&lt;</span><span class="kt">red_t</span><span class="o">&gt;</span><span class="p">(</span><span class="n">bgr8</span><span class="p">)</span><span class="o">==</span><span class="mi">10</span><span class="p">);</span> <span class="c1">// references modify the value they are bound to</span>
<span class="c1">// Create a zero packed pixel and a full regular unpacked pixel.</span>
<span class="kt">rgb565_pixel_t</span> <span class="n">r565</span><span class="p">;</span>
<span class="kt">rgb8_pixel_t</span> <span class="nf">rgb_full</span><span class="p">(</span><span class="mi">255</span><span class="p">,</span><span class="mi">255</span><span class="p">,</span><span class="mi">255</span><span class="p">);</span>
<span class="c1">// Convert all channels of the unpacked pixel to the packed one &amp; assert the packed one is full</span>
<span class="n">get_color</span><span class="p">(</span><span class="n">r565</span><span class="p">,</span><span class="kt">red_t</span><span class="p">())</span> <span class="o">=</span> <span class="n">channel_convert</span><span class="o">&lt;</span><span class="kt">rgb565_channel0_t</span><span class="o">&gt;</span><span class="p">(</span><span class="n">get_color</span><span class="p">(</span><span class="n">rgb_full</span><span class="p">,</span><span class="kt">red_t</span><span class="p">()));</span>
<span class="n">get_color</span><span class="p">(</span><span class="n">r565</span><span class="p">,</span><span class="kt">green_t</span><span class="p">())</span> <span class="o">=</span> <span class="n">channel_convert</span><span class="o">&lt;</span><span class="kt">rgb565_channel1_t</span><span class="o">&gt;</span><span class="p">(</span><span class="n">get_color</span><span class="p">(</span><span class="n">rgb_full</span><span class="p">,</span><span class="kt">green_t</span><span class="p">()));</span>
<span class="n">get_color</span><span class="p">(</span><span class="n">r565</span><span class="p">,</span><span class="kt">blue_t</span><span class="p">())</span> <span class="o">=</span> <span class="n">channel_convert</span><span class="o">&lt;</span><span class="kt">rgb565_channel2_t</span><span class="o">&gt;</span><span class="p">(</span><span class="n">get_color</span><span class="p">(</span><span class="n">rgb_full</span><span class="p">,</span><span class="kt">blue_t</span><span class="p">()));</span>
<span class="n">assert</span><span class="p">(</span><span class="n">r565</span> <span class="o">==</span> <span class="kt">rgb565_pixel_t</span><span class="p">((</span><span class="kt">uint16_t</span><span class="p">)</span><span class="mi">65535</span><span class="p">));</span>
</pre></div>
</div>
<p>GIL also provides the <tt class="docutils literal"><span class="pre">color_convert</span></tt> algorithm to convert between pixels of different color spaces and channel types:</p>
<div class="highlight-c++"><div class="highlight"><pre><span class="kt">rgb8_pixel_t</span> <span class="nf">red_in_rgb8</span><span class="p">(</span><span class="mi">255</span><span class="p">,</span><span class="mi">0</span><span class="p">,</span><span class="mi">0</span><span class="p">);</span>
<span class="kt">cmyk16_pixel_t</span> <span class="n">red_in_cmyk16</span><span class="p">;</span>
<span class="n">color_convert</span><span class="p">(</span><span class="n">red_in_rgb8</span><span class="p">,</span><span class="n">red_in_cmyk16</span><span class="p">);</span>
</pre></div>
</div>
</div>
<div class="section" id="pixel-iterator">
<h2><a class="toc-backref" href="#id8">Pixel Iterator</a></h2>
<div class="section" id="fundamental-iterator">
<h3><a class="toc-backref" href="#id9">Fundamental Iterator</a></h3>
<p>Pixel iterators are random traversal iterators whose <tt class="docutils literal"><span class="pre">value_type</span> <span class="pre">models</span></tt> <tt class="docutils literal"><span class="pre">PixelValueConcept</span></tt>.
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="highlight-c++"><div class="highlight"><pre><span class="n">concept</span> <span class="n">PixelIteratorConcept</span><span class="o">&lt;</span><span class="n">RandomAccessTraversalIteratorConcept</span> <span class="n">Iterator</span><span class="o">&gt;</span> <span class="o">:</span> <span class="n">PixelBasedConcept</span><span class="o">&lt;</span><span class="n">Iterator</span><span class="o">&gt;</span>
<span class="p">{</span>
<span class="n">where</span> <span class="n">PixelValueConcept</span><span class="o">&lt;</span><span class="n">value_type</span><span class="o">&gt;</span><span class="p">;</span>
<span class="k">typename</span> <span class="n">const_iterator_type</span><span class="o">&lt;</span><span class="n">It</span><span class="o">&gt;::</span><span class="n">type</span><span class="p">;</span>
<span class="n">where</span> <span class="n">PixelIteratorConcept</span><span class="o">&lt;</span><span class="n">const_iterator_type</span><span class="o">&lt;</span><span class="n">It</span><span class="o">&gt;::</span><span class="n">type</span><span class="o">&gt;</span><span class="p">;</span>
<span class="k">static</span> <span class="k">const</span> <span class="kt">bool</span> <span class="n">iterator_is_mutable</span><span class="o">&lt;</span><span class="n">It</span><span class="o">&gt;::</span><span class="n">type</span><span class="o">::</span><span class="n">value</span><span class="p">;</span>
<span class="k">static</span> <span class="k">const</span> <span class="kt">bool</span> <span class="n">is_iterator_adaptor</span><span class="o">&lt;</span><span class="n">It</span><span class="o">&gt;::</span><span class="n">type</span><span class="o">::</span><span class="n">value</span><span class="p">;</span> <span class="c1">// is it an iterator adaptor</span>
<span class="p">};</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">Iterator</span><span class="o">&gt;</span>
<span class="n">concept</span> <span class="n">MutablePixelIteratorConcept</span> <span class="o">:</span> <span class="n">PixelIteratorConcept</span><span class="o">&lt;</span><span class="n">Iterator</span><span class="o">&gt;</span><span class="p">,</span> <span class="n">MutableRandomAccessIteratorConcept</span><span class="o">&lt;</span><span class="n">Iterator</span><span class="o">&gt;</span> <span class="p">{};</span>
</pre></div>
</div>
<p>&lt;b&gt;Related Concepts:&lt;/b&gt;</p>
<ul class="simple">
<li>PixelIteratorConcept&lt;Iterator&gt;</li>
<li>MutablePixelIteratorConcept&lt;Iterator&gt;</li>
</ul>
<p>&lt;b&gt;Models:&lt;/b&gt;</p>
<p>A built-in pointer to pixel, <tt class="docutils literal"><span class="pre">pixel&lt;ChannelValue,Layout&gt;*</span></tt>, is GIL&#8217;s model for pixel iterator over interleaved homogeneous pixels.
Similarly, <tt class="docutils literal"><span class="pre">packed_pixel&lt;PixelData,ChannelRefVec,Layout&gt;*</span></tt> is GIL&#8217;s model for an iterator over interleaved packed pixels.</p>
<p>For planar homogeneous pixels, GIL provides the class <tt class="docutils literal"><span class="pre">planar_pixel_iterator</span></tt>, 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="highlight-c++"><div class="highlight"><pre><span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">ChannelPtr</span><span class="p">,</span> <span class="k">typename</span> <span class="n">ColorSpace</span><span class="o">&gt;</span> <span class="k">struct</span> <span class="n">planar_pixel_iterator</span><span class="p">;</span>
<span class="c1">// GIL provided typedefs</span>
<span class="k">typedef</span> <span class="n">planar_pixel_iterator</span><span class="o">&lt;</span><span class="k">const</span> <span class="n">bits8</span><span class="o">*</span><span class="p">,</span> <span class="kt">rgb_t</span><span class="o">&gt;</span> <span class="kt">rgb8c_planar_ptr_t</span><span class="p">;</span>
<span class="k">typedef</span> <span class="n">planar_pixel_iterator</span><span class="o">&lt;</span> <span class="n">bits8</span><span class="o">*</span><span class="p">,</span> <span class="kt">rgb_t</span><span class="o">&gt;</span> <span class="kt">rgb8_planar_ptr_t</span><span class="p">;</span>
</pre></div>
</div>
<p><tt class="docutils literal"><span class="pre">planar_pixel_iterator</span></tt> also models <tt class="docutils literal"><span class="pre">HomogeneousColorBaseConcept</span></tt> (it subclasses from <tt class="docutils literal"><span class="pre">homogeneous_color_base</span></tt>) 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 p operator++ of planar iterators approximately
like this:</p>
<div class="highlight-c++"><div class="highlight"><pre><span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">T</span><span class="o">&gt;</span>
<span class="k">struct</span> <span class="n">inc</span> <span class="o">:</span> <span class="k">public</span> <span class="n">std</span><span class="o">::</span><span class="n">unary_function</span><span class="o">&lt;</span><span class="n">T</span><span class="p">,</span><span class="n">T</span><span class="o">&gt;</span>
<span class="p">{</span>
<span class="n">T</span> <span class="k">operator</span><span class="p">()(</span><span class="n">T</span> <span class="n">x</span><span class="p">)</span> <span class="k">const</span> <span class="p">{</span> <span class="k">return</span> <span class="o">++</span><span class="n">x</span><span class="p">;</span> <span class="p">}</span>
<span class="p">};</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">ChannelPtr</span><span class="p">,</span> <span class="k">typename</span> <span class="n">ColorSpace</span><span class="o">&gt;</span>
<span class="n">planar_pixel_iterator</span><span class="o">&lt;</span><span class="n">ChannelPtr</span><span class="p">,</span><span class="n">ColorSpace</span><span class="o">&gt;&amp;</span>
<span class="n">planar_pixel_iterator</span><span class="o">&lt;</span><span class="n">ChannelPtr</span><span class="p">,</span><span class="n">ColorSpace</span><span class="o">&gt;::</span><span class="k">operator</span><span class="o">++</span><span class="p">()</span>
<span class="p">{</span>
<span class="n">static_transform</span><span class="p">(</span><span class="o">*</span><span class="k">this</span><span class="p">,</span><span class="o">*</span><span class="k">this</span><span class="p">,</span><span class="n">inc</span><span class="o">&lt;</span><span class="n">ChannelPtr</span><span class="o">&gt;</span><span class="p">());</span>
<span class="k">return</span> <span class="o">*</span><span class="k">this</span><span class="p">;</span>
<span class="p">}</span>
</pre></div>
</div>
<p>Since <tt class="docutils literal"><span class="pre">static_transform</span></tt> uses compile-time recursion, incrementing an instance of <tt class="docutils literal"><span class="pre">rgb8_planar_ptr_t</span></tt> amounts to three pointer increments.
GIL also uses the class <tt class="docutils literal"><span class="pre">bit_aligned_pixel_iterator</span></tt> as a model for a pixel iterator over bit-aligned pixels. Internally it keeps track of the current byte and
the bit offset.</p>
</div>
<div class="section" id="iterator-adaptor">
<h3><a class="toc-backref" href="#id10">Iterator Adaptor</a></h3>
<p>Iterator adaptor is an iterator that wraps around another iterator. Its <tt class="docutils literal"><span class="pre">is_iterator_adaptor</span></tt> 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="highlight-c++"><div class="highlight"><pre><span class="n">concept</span> <span class="n">IteratorAdaptorConcept</span><span class="o">&lt;</span><span class="n">RandomAccessTraversalIteratorConcept</span> <span class="n">Iterator</span><span class="o">&gt;</span>
<span class="p">{</span>
<span class="n">where</span> <span class="n">SameType</span><span class="o">&lt;</span><span class="n">is_iterator_adaptor</span><span class="o">&lt;</span><span class="n">Iterator</span><span class="o">&gt;::</span><span class="n">type</span><span class="p">,</span> <span class="n">mpl</span><span class="o">::</span><span class="n">true_</span><span class="o">&gt;</span><span class="p">;</span>
<span class="k">typename</span> <span class="n">iterator_adaptor_get_base</span><span class="o">&lt;</span><span class="n">Iterator</span><span class="o">&gt;</span><span class="p">;</span>
<span class="n">where</span> <span class="n">Metafunction</span><span class="o">&lt;</span><span class="n">iterator_adaptor_get_base</span><span class="o">&lt;</span><span class="n">Iterator</span><span class="o">&gt;</span> <span class="o">&gt;</span><span class="p">;</span>
<span class="n">where</span> <span class="n">boost_concepts</span><span class="o">::</span><span class="n">ForwardTraversalConcept</span><span class="o">&lt;</span><span class="n">iterator_adaptor_get_base</span><span class="o">&lt;</span><span class="n">Iterator</span><span class="o">&gt;::</span><span class="n">type</span><span class="o">&gt;</span><span class="p">;</span>
<span class="k">typename</span> <span class="n">another_iterator</span><span class="p">;</span>
<span class="k">typename</span> <span class="n">iterator_adaptor_rebind</span><span class="o">&lt;</span><span class="n">Iterator</span><span class="p">,</span><span class="n">another_iterator</span><span class="o">&gt;::</span><span class="n">type</span><span class="p">;</span>
<span class="n">where</span> <span class="n">boost_concepts</span><span class="o">::</span><span class="n">ForwardTraversalConcept</span><span class="o">&lt;</span><span class="n">another_iterator</span><span class="o">&gt;</span><span class="p">;</span>
<span class="n">where</span> <span class="n">IteratorAdaptorConcept</span><span class="o">&lt;</span><span class="n">iterator_adaptor_rebind</span><span class="o">&lt;</span><span class="n">Iterator</span><span class="p">,</span><span class="n">another_iterator</span><span class="o">&gt;::</span><span class="n">type</span><span class="o">&gt;</span><span class="p">;</span>
<span class="k">const</span> <span class="n">iterator_adaptor_get_base</span><span class="o">&lt;</span><span class="n">Iterator</span><span class="o">&gt;::</span><span class="n">type</span><span class="o">&amp;</span> <span class="n">Iterator</span><span class="o">::</span><span class="n">base</span><span class="p">()</span> <span class="k">const</span><span class="p">;</span>
<span class="p">};</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="n">boost_concepts</span><span class="o">::</span><span class="n">Mutable_ForwardIteratorConcept</span> <span class="n">Iterator</span><span class="o">&gt;</span>
<span class="n">concept</span> <span class="n">MutableIteratorAdaptorConcept</span> <span class="o">:</span> <span class="n">IteratorAdaptorConcept</span><span class="o">&lt;</span><span class="n">Iterator</span><span class="o">&gt;</span> <span class="p">{};</span>
</pre></div>
</div>
<p>&lt;b&gt;Related Concepts:&lt;/b&gt;</p>
<ul class="simple">
<li>IteratorAdaptorConcept&lt;Iterator&gt;</li>
<li>MutableIteratorAdaptorConcept&lt;Iterator&gt;</li>
</ul>
<p>&lt;b&gt;Models:&lt;/b&gt;</p>
<p>GIL provides several models of <tt class="docutils literal"><span class="pre">IteratorAdaptorConcept</span></tt>:
- <tt class="docutils literal"><span class="pre">memory_based_step_iterator&lt;Iterator&gt;</span></tt>: An iterator adaptor that changes the fundamental step of the base iterator (see ref StepIteratorDG)
- <tt class="docutils literal"><span class="pre">dereference_iterator_adaptor&lt;Iterator,Fn&gt;</span></tt>: An iterator that applies a unary function <tt class="docutils literal"><span class="pre">Fn</span></tt> upon dereferencing. It is used, for example,
for on-the-fly color conversion. It can be used to construct a shallow image &#8220;view&#8221; that pretends to have a different color space or
channel depth. See ref ImageViewFrowImageViewDG for more. The unary function <tt class="docutils literal"><span class="pre">Fn</span></tt> must model <tt class="docutils literal"><span class="pre">PixelDereferenceAdaptorConcept</span></tt> (see below).</p>
</div>
<div class="section" id="pixel-dereference-adaptor">
<h3><a class="toc-backref" href="#id11">Pixel Dereference Adaptor</a></h3>
<p>Pixel dereference adaptor is a unary function that can be applied upon dereferencing a pixel iterator. Its argument type could be anything
(usually a <tt class="docutils literal"><span class="pre">PixelConcept</span></tt>) and the result type must be convertible to <tt class="docutils literal"><span class="pre">PixelConcept</span></tt></p>
<div class="highlight-c++"><div class="highlight"><pre><span class="k">template</span> <span class="o">&lt;</span><span class="n">boost</span><span class="o">::</span><span class="n">UnaryFunctionConcept</span> <span class="n">D</span><span class="o">&gt;</span>
<span class="n">concept</span> <span class="n">PixelDereferenceAdaptorConcept</span> <span class="o">:</span> <span class="n">DefaultConstructibleConcept</span><span class="o">&lt;</span><span class="n">D</span><span class="o">&gt;</span><span class="p">,</span> <span class="n">CopyConstructibleConcept</span><span class="o">&lt;</span><span class="n">D</span><span class="o">&gt;</span><span class="p">,</span> <span class="n">AssignableConcept</span><span class="o">&lt;</span><span class="n">D</span><span class="o">&gt;</span>
<span class="p">{</span>
<span class="k">typename</span> <span class="kt">const_t</span><span class="p">;</span> <span class="n">where</span> <span class="n">PixelDereferenceAdaptorConcept</span><span class="o">&lt;</span><span class="kt">const_t</span><span class="o">&gt;</span><span class="p">;</span>
<span class="k">typename</span> <span class="n">value_type</span><span class="p">;</span> <span class="n">where</span> <span class="n">PixelValueConcept</span><span class="o">&lt;</span><span class="n">value_type</span><span class="o">&gt;</span><span class="p">;</span>
<span class="k">typename</span> <span class="n">reference</span><span class="p">;</span> <span class="n">where</span> <span class="n">PixelConcept</span><span class="o">&lt;</span><span class="n">remove_reference</span><span class="o">&lt;</span><span class="n">reference</span><span class="o">&gt;::</span><span class="n">type</span><span class="o">&gt;</span><span class="p">;</span> <span class="c1">// may be mutable</span>
<span class="k">typename</span> <span class="n">const_reference</span><span class="p">;</span> <span class="c1">// must not be mutable</span>
<span class="k">static</span> <span class="k">const</span> <span class="kt">bool</span> <span class="n">D</span><span class="o">::</span><span class="n">is_mutable</span><span class="p">;</span>
<span class="n">where</span> <span class="n">Convertible</span><span class="o">&lt;</span><span class="n">value_type</span><span class="p">,</span> <span class="n">result_type</span><span class="o">&gt;</span><span class="p">;</span>
<span class="p">};</span>
</pre></div>
</div>
<p>&lt;b&gt;Models:&lt;/b&gt;</p>
<p>GIL provides several models of <tt class="docutils literal"><span class="pre">PixelDereferenceAdaptorConcept</span></tt>:
- <tt class="docutils literal"><span class="pre">color_convert_deref_fn</span></tt>: a function object that performs color conversion
- <tt class="docutils literal"><span class="pre">detail::nth_channel_deref_fn</span></tt>: a function object that returns a grayscale pixel corresponding to the n-th channel of a given pixel
- <tt class="docutils literal"><span class="pre">deref_compose</span></tt>: a function object that composes two models of <tt class="docutils literal"><span class="pre">PixelDereferenceAdaptorConcept</span></tt>. Similar to <tt class="docutils literal"><span class="pre">std::unary_compose</span></tt>, except it needs to pull the additional typedefs required by <tt class="docutils literal"><span class="pre">PixelDereferenceAdaptorConcept</span></tt></p>
<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. <tt class="docutils literal"><span class="pre">dereference_iterator_adaptor&lt;Iterator,Fn&gt;</span></tt> is an iterator wrapper over a pixel iterator <tt class="docutils literal"><span class="pre">Iterator</span></tt> that invokes the given dereference
iterator adaptor <tt class="docutils literal"><span class="pre">Fn</span></tt> upon dereferencing.</p>
</div>
<div class="section" id="step-iterator">
<h3><a class="toc-backref" href="#id12">Step Iterator</a></h3>
<p>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:
- a single-channel view of the red channel of an RGB interleaved image
- left-to-right flipped image (step = -fundamental_step)
- subsampled view, taking every N-th pixel (step = N*fundamental_step)
- traversal in vertical direction (step = number of bytes per row)
- any combination of the above (steps are multiplied)</p>
<p>Step iterators are forward traversal iterators that allow changing the step between adjacent values:</p>
<div class="highlight-c++"><div class="highlight"><pre><span class="n">concept</span> <span class="n">StepIteratorConcept</span><span class="o">&lt;</span><span class="n">boost_concepts</span><span class="o">::</span><span class="n">ForwardTraversalConcept</span> <span class="n">Iterator</span><span class="o">&gt;</span>
<span class="p">{</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="n">Integral</span> <span class="n">D</span><span class="o">&gt;</span> <span class="kt">void</span> <span class="n">Iterator</span><span class="o">::</span><span class="n">set_step</span><span class="p">(</span><span class="n">D</span> <span class="n">step</span><span class="p">);</span>
<span class="p">};</span>
<span class="n">concept</span> <span class="n">MutableStepIteratorConcept</span><span class="o">&lt;</span><span class="n">boost_concepts</span><span class="o">::</span><span class="n">Mutable_ForwardIteratorConcept</span> <span class="n">Iterator</span><span class="o">&gt;</span> <span class="o">:</span> <span class="n">StepIteratorConcept</span><span class="o">&lt;</span><span class="n">Iterator</span><span class="o">&gt;</span> <span class="p">{};</span>
</pre></div>
</div>
<p>GIL currently provides a step iterator whose <tt class="docutils literal"><span class="pre">value_type</span> <span class="pre">models</span></tt> <tt class="docutils literal"><span class="pre">PixelValueConcept</span></tt>. 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>
<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.
<tt class="docutils literal"><span class="pre">memunit_advanced</span></tt> and <tt class="docutils literal"><span class="pre">memunit_advanced_ref</span></tt> have a default implementation but some iterators may supply a more efficient version:</p>
<div class="highlight-c++"><div class="highlight"><pre><span class="n">concept</span> <span class="n">MemoryBasedIteratorConcept</span><span class="o">&lt;</span><span class="n">boost_concepts</span><span class="o">::</span><span class="n">RandomAccessTraversalConcept</span> <span class="n">Iterator</span><span class="o">&gt;</span>
<span class="p">{</span>
<span class="k">typename</span> <span class="n">byte_to_memunit</span><span class="o">&lt;</span><span class="n">Iterator</span><span class="o">&gt;</span><span class="p">;</span> <span class="n">where</span> <span class="n">metafunction</span><span class="o">&lt;</span><span class="n">byte_to_memunit</span><span class="o">&lt;</span><span class="n">Iterator</span><span class="o">&gt;</span> <span class="o">&gt;</span><span class="p">;</span>
<span class="n">std</span><span class="o">::</span><span class="kt">ptrdiff_t</span> <span class="n">memunit_step</span><span class="p">(</span><span class="k">const</span> <span class="n">Iterator</span><span class="o">&amp;</span><span class="p">);</span>
<span class="n">std</span><span class="o">::</span><span class="kt">ptrdiff_t</span> <span class="n">memunit_distance</span><span class="p">(</span><span class="k">const</span> <span class="n">Iterator</span><span class="o">&amp;</span> <span class="p">,</span> <span class="k">const</span> <span class="n">Iterator</span><span class="o">&amp;</span><span class="p">);</span>
<span class="kt">void</span> <span class="nf">memunit_advance</span><span class="p">(</span><span class="n">Iterator</span><span class="o">&amp;</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="kt">ptrdiff_t</span> <span class="n">diff</span><span class="p">);</span>
<span class="n">Iterator</span> <span class="nf">memunit_advanced</span><span class="p">(</span><span class="k">const</span> <span class="n">Iterator</span><span class="o">&amp;</span> <span class="n">p</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="kt">ptrdiff_t</span> <span class="n">diff</span><span class="p">)</span> <span class="p">{</span> <span class="n">Iterator</span> <span class="n">tmp</span><span class="p">;</span> <span class="n">memunit_advance</span><span class="p">(</span><span class="n">tmp</span><span class="p">,</span><span class="n">diff</span><span class="p">);</span> <span class="k">return</span> <span class="n">tmp</span><span class="p">;</span> <span class="p">}</span>
<span class="n">Iterator</span><span class="o">::</span><span class="n">reference</span> <span class="n">memunit_advanced_ref</span><span class="p">(</span><span class="k">const</span> <span class="n">Iterator</span><span class="o">&amp;</span> <span class="n">p</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="kt">ptrdiff_t</span> <span class="n">diff</span><span class="p">)</span> <span class="p">{</span> <span class="k">return</span> <span class="o">*</span><span class="n">memunit_advanced</span><span class="p">(</span><span class="n">p</span><span class="p">,</span><span class="n">diff</span><span class="p">);</span> <span class="p">}</span>
<span class="p">};</span>
</pre></div>
</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="highlight-c++"><div class="highlight"><pre><span class="n">concept</span> <span class="n">HasDynamicXStepTypeConcept</span><span class="o">&lt;</span><span class="k">typename</span> <span class="n">T</span><span class="o">&gt;</span>
<span class="p">{</span>
<span class="k">typename</span> <span class="n">dynamic_x_step_type</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span><span class="p">;</span>
<span class="n">where</span> <span class="n">Metafunction</span><span class="o">&lt;</span><span class="n">dynamic_x_step_type</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span> <span class="o">&gt;</span><span class="p">;</span>
<span class="p">};</span>
</pre></div>
</div>
<p>All models of pixel iterators, locators and image views that GIL provides support <tt class="docutils literal"><span class="pre">HasDynamicXStepTypeConcept</span></tt>.</p>
<p>&lt;b&gt;Related Concepts:&lt;/b&gt;</p>
<ul class="simple">
<li>StepIteratorConcept&lt;Iterator&gt;</li>
<li>MutableStepIteratorConcept&lt;Iterator&gt;</li>
<li>MemoryBasedIteratorConcept&lt;Iterator&gt;</li>
<li>HasDynamicXStepTypeConcept&lt;T&gt;</li>
</ul>
<p>&lt;b&gt;Models:&lt;/b&gt;</p>
<p>All standard memory-based iterators GIL currently provides model <tt class="docutils literal"><span class="pre">MemoryBasedIteratorConcept</span></tt>.
GIL provides the class <tt class="docutils literal"><span class="pre">memory_based_step_iterator</span></tt> which models <tt class="docutils literal"><span class="pre">PixelIteratorConcept</span></tt>, <tt class="docutils literal"><span class="pre">StepIteratorConcept</span></tt>, and <tt class="docutils literal"><span class="pre">MemoryBasedIteratorConcept</span></tt>.
It takes the base iterator as a template parameter (which must model <tt class="docutils literal"><span class="pre">PixelIteratorConcept</span></tt> and <tt class="docutils literal"><span class="pre">MemoryBasedIteratorConcept</span></tt>)
and allows changing the step dynamically. GIL&#8217;s implementation contains the base iterator and a <tt class="docutils literal"><span class="pre">ptrdiff_t</span></tt> 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="highlight-c++"><div class="highlight"><pre><span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">I</span><span class="o">&gt;</span> <span class="c1">// Models MemoryBasedIteratorConcept, HasDynamicXStepTypeConcept</span>
<span class="k">typename</span> <span class="n">dynamic_x_step_type</span><span class="o">&lt;</span><span class="n">I</span><span class="o">&gt;::</span><span class="n">type</span> <span class="n">make_step_iterator</span><span class="p">(</span><span class="k">const</span> <span class="n">I</span><span class="o">&amp;</span> <span class="n">it</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="kt">ptrdiff_t</span> <span class="n">step</span><span class="p">);</span>
</pre></div>
</div>
<p>GIL also provides a model of an iterator over a virtual array of pixels, <tt class="docutils literal"><span class="pre">position_iterator</span></tt>. 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 <tt class="docutils literal"><span class="pre">PixelIteratorConcept</span></tt> and <tt class="docutils literal"><span class="pre">StepIteratorConcept</span></tt> but
not <tt class="docutils literal"><span class="pre">MemoryBasedIteratorConcept</span></tt>.</p>
</div>
<div class="section" id="pixel-locator">
<h3><a class="toc-backref" href="#id13">Pixel Locator</a></h3>
<p>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&#8217;t satisfy all the requirements of iterators. For example, they don&#8217;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="highlight-c++"><div class="highlight"><pre><span class="n">concept</span> <span class="n">RandomAccessNDLocatorConcept</span><span class="o">&lt;</span><span class="n">Regular</span> <span class="n">Loc</span><span class="o">&gt;</span>
<span class="p">{</span>
<span class="k">typename</span> <span class="n">value_type</span><span class="p">;</span> <span class="c1">// value over which the locator navigates</span>
<span class="k">typename</span> <span class="n">reference</span><span class="p">;</span> <span class="c1">// result of dereferencing</span>
<span class="k">typename</span> <span class="n">difference_type</span><span class="p">;</span> <span class="n">where</span> <span class="n">PointNDConcept</span><span class="o">&lt;</span><span class="n">difference_type</span><span class="o">&gt;</span><span class="p">;</span> <span class="c1">// return value of operator-.</span>
<span class="k">typename</span> <span class="kt">const_t</span><span class="p">;</span> <span class="c1">// same as Loc, but operating over immutable values</span>
<span class="k">typename</span> <span class="kt">cached_location_t</span><span class="p">;</span> <span class="c1">// type to store relative location (for efficient repeated access)</span>
<span class="k">typename</span> <span class="kt">point_t</span> <span class="o">=</span> <span class="n">difference_type</span><span class="p">;</span>
<span class="k">static</span> <span class="k">const</span> <span class="kt">size_t</span> <span class="n">num_dimensions</span><span class="p">;</span> <span class="c1">// dimensionality of the locator</span>
<span class="n">where</span> <span class="n">num_dimensions</span> <span class="o">=</span> <span class="kt">point_t</span><span class="o">::</span><span class="n">num_dimensions</span><span class="p">;</span>
<span class="c1">// The difference_type and iterator type along each dimension. The iterators may only differ in</span>
<span class="c1">// difference_type. Their value_type must be the same as Loc::value_type</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="kt">size_t</span> <span class="n">D</span><span class="o">&gt;</span> <span class="k">struct</span> <span class="n">axis</span> <span class="p">{</span>
<span class="k">typename</span> <span class="kt">coord_t</span> <span class="o">=</span> <span class="kt">point_t</span><span class="o">::</span><span class="n">axis</span><span class="o">&lt;</span><span class="n">D</span><span class="o">&gt;::</span><span class="kt">coord_t</span><span class="p">;</span>
<span class="k">typename</span> <span class="n">iterator</span><span class="p">;</span> <span class="n">where</span> <span class="n">RandomAccessTraversalConcept</span><span class="o">&lt;</span><span class="n">iterator</span><span class="o">&gt;</span><span class="p">;</span> <span class="c1">// iterator along D-th axis.</span>
<span class="n">where</span> <span class="n">iterator</span><span class="o">::</span><span class="n">value_type</span> <span class="o">==</span> <span class="n">value_type</span><span class="p">;</span>
<span class="p">};</span>
<span class="c1">// Defines the type of a locator similar to this type, except it invokes Deref upon dereferencing</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="n">PixelDereferenceAdaptorConcept</span> <span class="n">Deref</span><span class="o">&gt;</span> <span class="k">struct</span> <span class="n">add_deref</span> <span class="p">{</span>
<span class="k">typename</span> <span class="n">type</span><span class="p">;</span> <span class="n">where</span> <span class="n">RandomAccessNDLocatorConcept</span><span class="o">&lt;</span><span class="n">type</span><span class="o">&gt;</span><span class="p">;</span>
<span class="k">static</span> <span class="n">type</span> <span class="nf">make</span><span class="p">(</span><span class="k">const</span> <span class="n">Loc</span><span class="o">&amp;</span> <span class="n">loc</span><span class="p">,</span> <span class="k">const</span> <span class="n">Deref</span><span class="o">&amp;</span> <span class="n">deref</span><span class="p">);</span>
<span class="p">};</span>
<span class="n">Loc</span><span class="o">&amp;</span> <span class="k">operator</span><span class="o">+=</span><span class="p">(</span><span class="n">Loc</span><span class="o">&amp;</span><span class="p">,</span> <span class="k">const</span> <span class="n">difference_type</span><span class="o">&amp;</span><span class="p">);</span>
<span class="n">Loc</span><span class="o">&amp;</span> <span class="k">operator</span><span class="o">-=</span><span class="p">(</span><span class="n">Loc</span><span class="o">&amp;</span><span class="p">,</span> <span class="k">const</span> <span class="n">difference_type</span><span class="o">&amp;</span><span class="p">);</span>
<span class="n">Loc</span> <span class="k">operator</span><span class="o">+</span><span class="p">(</span><span class="k">const</span> <span class="n">Loc</span><span class="o">&amp;</span><span class="p">,</span> <span class="k">const</span> <span class="n">difference_type</span><span class="o">&amp;</span><span class="p">);</span>
<span class="n">Loc</span> <span class="k">operator</span><span class="o">-</span><span class="p">(</span><span class="k">const</span> <span class="n">Loc</span><span class="o">&amp;</span><span class="p">,</span> <span class="k">const</span> <span class="n">difference_type</span><span class="o">&amp;</span><span class="p">);</span>
<span class="n">reference</span> <span class="k">operator</span><span class="o">*</span><span class="p">(</span><span class="k">const</span> <span class="n">Loc</span><span class="o">&amp;</span><span class="p">);</span>
<span class="n">reference</span> <span class="k">operator</span><span class="p">[](</span><span class="k">const</span> <span class="n">Loc</span><span class="o">&amp;</span><span class="p">,</span> <span class="k">const</span> <span class="n">difference_type</span><span class="o">&amp;</span><span class="p">);</span>
<span class="c1">// Storing relative location for faster repeated access and accessing it</span>
<span class="kt">cached_location_t</span> <span class="n">Loc</span><span class="o">::</span><span class="n">cache_location</span><span class="p">(</span><span class="k">const</span> <span class="n">difference_type</span><span class="o">&amp;</span><span class="p">)</span> <span class="k">const</span><span class="p">;</span>
<span class="n">reference</span> <span class="k">operator</span><span class="p">[](</span><span class="k">const</span> <span class="n">Loc</span><span class="o">&amp;</span><span class="p">,</span><span class="k">const</span> <span class="kt">cached_location_t</span><span class="o">&amp;</span><span class="p">);</span>
<span class="c1">// Accessing iterators along a given dimension at the current location or at a given offset</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="kt">size_t</span> <span class="n">D</span><span class="o">&gt;</span> <span class="n">axis</span><span class="o">&lt;</span><span class="n">D</span><span class="o">&gt;::</span><span class="n">iterator</span><span class="o">&amp;</span> <span class="n">Loc</span><span class="o">::</span><span class="n">axis_iterator</span><span class="p">();</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="kt">size_t</span> <span class="n">D</span><span class="o">&gt;</span> <span class="n">axis</span><span class="o">&lt;</span><span class="n">D</span><span class="o">&gt;::</span><span class="n">iterator</span> <span class="k">const</span><span class="o">&amp;</span> <span class="n">Loc</span><span class="o">::</span><span class="n">axis_iterator</span><span class="p">()</span> <span class="k">const</span><span class="p">;</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="kt">size_t</span> <span class="n">D</span><span class="o">&gt;</span> <span class="n">axis</span><span class="o">&lt;</span><span class="n">D</span><span class="o">&gt;::</span><span class="n">iterator</span> <span class="n">Loc</span><span class="o">::</span><span class="n">axis_iterator</span><span class="p">(</span><span class="k">const</span> <span class="n">difference_type</span><span class="o">&amp;</span><span class="p">)</span> <span class="k">const</span><span class="p">;</span>
<span class="p">};</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">Loc</span><span class="o">&gt;</span>
<span class="n">concept</span> <span class="n">MutableRandomAccessNDLocatorConcept</span> <span class="o">:</span> <span class="n">RandomAccessNDLocatorConcept</span><span class="o">&lt;</span><span class="n">Loc</span><span class="o">&gt;</span> <span class="p">{</span>
<span class="n">where</span> <span class="n">Mutable</span><span class="o">&lt;</span><span class="n">reference</span><span class="o">&gt;</span><span class="p">;</span>
<span class="p">};</span>
</pre></div>
</div>
<p>Two-dimensional locators have additional requirements:</p>
<div class="highlight-c++"><div class="highlight"><pre><span class="n">concept</span> <span class="n">RandomAccess2DLocatorConcept</span><span class="o">&lt;</span><span class="n">RandomAccessNDLocatorConcept</span> <span class="n">Loc</span><span class="o">&gt;</span>
<span class="p">{</span>
<span class="n">where</span> <span class="n">num_dimensions</span><span class="o">==</span><span class="mi">2</span><span class="p">;</span>
<span class="n">where</span> <span class="n">Point2DConcept</span><span class="o">&lt;</span><span class="kt">point_t</span><span class="o">&gt;</span><span class="p">;</span>
<span class="k">typename</span> <span class="n">x_iterator</span> <span class="o">=</span> <span class="n">axis</span><span class="o">&lt;</span><span class="mi">0</span><span class="o">&gt;::</span><span class="n">iterator</span><span class="p">;</span>
<span class="k">typename</span> <span class="n">y_iterator</span> <span class="o">=</span> <span class="n">axis</span><span class="o">&lt;</span><span class="mi">1</span><span class="o">&gt;::</span><span class="n">iterator</span><span class="p">;</span>
<span class="k">typename</span> <span class="kt">x_coord_t</span> <span class="o">=</span> <span class="n">axis</span><span class="o">&lt;</span><span class="mi">0</span><span class="o">&gt;::</span><span class="kt">coord_t</span><span class="p">;</span>
<span class="k">typename</span> <span class="kt">y_coord_t</span> <span class="o">=</span> <span class="n">axis</span><span class="o">&lt;</span><span class="mi">1</span><span class="o">&gt;::</span><span class="kt">coord_t</span><span class="p">;</span>
<span class="c1">// Only available to locators that have dynamic step in Y</span>
<span class="c1">//Loc::Loc(const Loc&amp; loc, y_coord_t);</span>
<span class="c1">// Only available to locators that have dynamic step in X and Y</span>
<span class="c1">//Loc::Loc(const Loc&amp; loc, x_coord_t, y_coord_t, bool transposed=false);</span>
<span class="n">x_iterator</span><span class="o">&amp;</span> <span class="n">Loc</span><span class="o">::</span><span class="n">x</span><span class="p">();</span>
<span class="n">x_iterator</span> <span class="k">const</span><span class="o">&amp;</span> <span class="n">Loc</span><span class="o">::</span><span class="n">x</span><span class="p">()</span> <span class="k">const</span><span class="p">;</span>
<span class="n">y_iterator</span><span class="o">&amp;</span> <span class="n">Loc</span><span class="o">::</span><span class="n">y</span><span class="p">();</span>
<span class="n">y_iterator</span> <span class="k">const</span><span class="o">&amp;</span> <span class="n">Loc</span><span class="o">::</span><span class="n">y</span><span class="p">()</span> <span class="k">const</span><span class="p">;</span>
<span class="n">x_iterator</span> <span class="n">Loc</span><span class="o">::</span><span class="n">x_at</span><span class="p">(</span><span class="k">const</span> <span class="n">difference_type</span><span class="o">&amp;</span><span class="p">)</span> <span class="k">const</span><span class="p">;</span>
<span class="n">y_iterator</span> <span class="n">Loc</span><span class="o">::</span><span class="n">y_at</span><span class="p">(</span><span class="k">const</span> <span class="n">difference_type</span><span class="o">&amp;</span><span class="p">)</span> <span class="k">const</span><span class="p">;</span>
<span class="n">Loc</span> <span class="n">Loc</span><span class="o">::</span><span class="n">xy_at</span><span class="p">(</span><span class="k">const</span> <span class="n">difference_type</span><span class="o">&amp;</span><span class="p">)</span> <span class="k">const</span><span class="p">;</span>
<span class="c1">// x/y versions of all methods that can take difference type</span>
<span class="n">x_iterator</span> <span class="n">Loc</span><span class="o">::</span><span class="n">x_at</span><span class="p">(</span><span class="kt">x_coord_t</span><span class="p">,</span> <span class="kt">y_coord_t</span><span class="p">)</span> <span class="k">const</span><span class="p">;</span>
<span class="n">y_iterator</span> <span class="n">Loc</span><span class="o">::</span><span class="n">y_at</span><span class="p">(</span><span class="kt">x_coord_t</span><span class="p">,</span> <span class="kt">y_coord_t</span><span class="p">)</span> <span class="k">const</span><span class="p">;</span>
<span class="n">Loc</span> <span class="n">Loc</span><span class="o">::</span><span class="n">xy_at</span><span class="p">(</span><span class="kt">x_coord_t</span><span class="p">,</span> <span class="kt">y_coord_t</span><span class="p">)</span> <span class="k">const</span><span class="p">;</span>
<span class="n">reference</span> <span class="nf">operator</span><span class="p">()(</span><span class="k">const</span> <span class="n">Loc</span><span class="o">&amp;</span><span class="p">,</span> <span class="kt">x_coord_t</span><span class="p">,</span> <span class="kt">y_coord_t</span><span class="p">);</span>
<span class="kt">cached_location_t</span> <span class="n">Loc</span><span class="o">::</span><span class="n">cache_location</span><span class="p">(</span><span class="kt">x_coord_t</span><span class="p">,</span> <span class="kt">y_coord_t</span><span class="p">)</span> <span class="k">const</span><span class="p">;</span>
<span class="kt">bool</span> <span class="n">Loc</span><span class="o">::</span><span class="n">is_1d_traversable</span><span class="p">(</span><span class="kt">x_coord_t</span> <span class="n">width</span><span class="p">)</span> <span class="k">const</span><span class="p">;</span>
<span class="kt">y_coord_t</span> <span class="n">Loc</span><span class="o">::</span><span class="n">y_distance_to</span><span class="p">(</span><span class="k">const</span> <span class="n">Loc</span><span class="o">&amp;</span> <span class="n">loc2</span><span class="p">,</span> <span class="kt">x_coord_t</span> <span class="n">x_diff</span><span class="p">)</span> <span class="k">const</span><span class="p">;</span>
<span class="p">};</span>
<span class="n">concept</span> <span class="n">MutableRandomAccess2DLocatorConcept</span><span class="o">&lt;</span><span class="n">RandomAccess2DLocatorConcept</span> <span class="n">Loc</span><span class="o">&gt;</span> <span class="o">:</span> <span class="n">MutableRandomAccessNDLocatorConcept</span><span class="o">&lt;</span><span class="n">Loc</span><span class="o">&gt;</span> <span class="p">{};</span>
</pre></div>
</div>
<p>2D locators can have a dynamic step not just horizontally, but also vertically. This gives rise to the Y equivalent of p HasDynamicXStepTypeConcept:</p>
<div class="highlight-c++"><div class="highlight"><pre><span class="n">concept</span> <span class="n">HasDynamicYStepTypeConcept</span><span class="o">&lt;</span><span class="k">typename</span> <span class="n">T</span><span class="o">&gt;</span>
<span class="p">{</span>
<span class="k">typename</span> <span class="n">dynamic_y_step_type</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span><span class="p">;</span>
<span class="n">where</span> <span class="n">Metafunction</span><span class="o">&lt;</span><span class="n">dynamic_y_step_type</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span> <span class="o">&gt;</span><span class="p">;</span>
<span class="p">};</span>
</pre></div>
</div>
<p>All locators and image views that GIL provides model <tt class="docutils literal"><span class="pre">HasDynamicYStepTypeConcept</span></tt>.</p>
<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="highlight-c++"><div class="highlight"><pre><span class="n">concept</span> <span class="n">HasTransposedTypeConcept</span><span class="o">&lt;</span><span class="k">typename</span> <span class="n">T</span><span class="o">&gt;</span>
<span class="p">{</span>
<span class="k">typename</span> <span class="n">transposed_type</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span><span class="p">;</span>
<span class="n">where</span> <span class="n">Metafunction</span><span class="o">&lt;</span><span class="n">transposed_type</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span> <span class="o">&gt;</span><span class="p">;</span>
<span class="p">};</span>
</pre></div>
</div>
<p>All GIL provided locators and views model <tt class="docutils literal"><span class="pre">HasTransposedTypeConcept</span></tt>.</p>
<p>The locators GIL uses operate over models of <tt class="docutils literal"><span class="pre">PixelConcept</span></tt> and their x and y dimension types are the same. They model the following concept:</p>
<div class="highlight-c++"><div class="highlight"><pre><span class="n">concept</span> <span class="n">PixelLocatorConcept</span><span class="o">&lt;</span><span class="n">RandomAccess2DLocatorConcept</span> <span class="n">Loc</span><span class="o">&gt;</span>
<span class="p">{</span>
<span class="n">where</span> <span class="n">PixelValueConcept</span><span class="o">&lt;</span><span class="n">value_type</span><span class="o">&gt;</span><span class="p">;</span>
<span class="n">where</span> <span class="n">PixelIteratorConcept</span><span class="o">&lt;</span><span class="n">x_iterator</span><span class="o">&gt;</span><span class="p">;</span>
<span class="n">where</span> <span class="n">PixelIteratorConcept</span><span class="o">&lt;</span><span class="n">y_iterator</span><span class="o">&gt;</span><span class="p">;</span>
<span class="n">where</span> <span class="kt">x_coord_t</span> <span class="o">==</span> <span class="kt">y_coord_t</span><span class="p">;</span>
<span class="k">typename</span> <span class="kt">coord_t</span> <span class="o">=</span> <span class="kt">x_coord_t</span><span class="p">;</span>
<span class="p">};</span>
<span class="n">concept</span> <span class="n">MutablePixelLocatorConcept</span><span class="o">&lt;</span><span class="n">PixelLocatorConcept</span> <span class="n">Loc</span><span class="o">&gt;</span> <span class="o">:</span> <span class="n">MutableRandomAccess2DLocatorConcept</span><span class="o">&lt;</span><span class="n">Loc</span><span class="o">&gt;</span> <span class="p">{};</span>
</pre></div>
</div>
<p>&lt;b&gt;Related Concepts:&lt;/b&gt;</p>
<ul class="simple">
<li>HasDynamicYStepTypeConcept&lt;T&gt;</li>
<li>HasTransposedTypeConcept&lt;T&gt;</li>
<li>RandomAccessNDLocatorConcept&lt;Locator&gt;</li>
<li>MutableRandomAccessNDLocatorConcept&lt;Locator&gt;</li>
<li>RandomAccess2DLocatorConcept&lt;Locator&gt;</li>
<li>MutableRandomAccess2DLocatorConcept&lt;Locator&gt;</li>
<li>PixelLocatorConcept&lt;Locator&gt;</li>
<li>MutablePixelLocatorConcept&lt;Locator&gt;</li>
</ul>
<p>&lt;b&gt;Models:&lt;/b&gt;</p>
<p>GIL provides two models of <tt class="docutils literal"><span class="pre">PixelLocatorConcept</span></tt> - a memory-based locator, <tt class="docutils literal"><span class="pre">memory_based_2d_locator</span></tt> and a virtual locator <tt class="docutils literal"><span class="pre">virtual_2d_locator</span></tt>.</p>
<p><tt class="docutils literal"><span class="pre">memory_based_2d_locator</span></tt> is a locator over planar or interleaved images that have their pixels in memory.
It takes a model of <tt class="docutils literal"><span class="pre">StepIteratorConcept</span></tt> over pixels as a template parameter. (When instantiated with a model of <tt class="docutils literal"><span class="pre">MutableStepIteratorConcept</span></tt>,
it models <tt class="docutils literal"><span class="pre">MutablePixelLocatorConcept</span></tt>).</p>
<div class="highlight-c++"><div class="highlight"><pre><span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">StepIterator</span><span class="o">&gt;</span> <span class="c1">// Models StepIteratorConcept, MemoryBasedIteratorConcept</span>
<span class="k">class</span> <span class="nc">memory_based_2d_locator</span><span class="p">;</span>
</pre></div>
</div>
<p>The step of <tt class="docutils literal"><span class="pre">StepIterator</span></tt> must be the number of memory units (bytes or bits) per row (thus it must be memunit advanceable). The class <tt class="docutils literal"><span class="pre">memory_based_2d_locator</span></tt> is a
wrapper around <tt class="docutils literal"><span class="pre">StepIterator</span></tt> and uses it to navigate vertically, while its base iterator is used to navigate horizontally.</p>
<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:
- <tt class="docutils literal"><span class="pre">pixel&lt;T,C&gt;*</span></tt> (for interleaved images)
- <tt class="docutils literal"><span class="pre">planar_pixel_iterator&lt;T*,C&gt;</span></tt> (for planar images)
- <tt class="docutils literal"><span class="pre">memory_based_step_iterator&lt;pixel&lt;T,C&gt;*&gt;</span></tt> (for interleaved images with non-standard step)
- <tt class="docutils literal"><span class="pre">memory_based_step_iterator&lt;planar_pixel_iterator&lt;T*,C&gt;</span> <span class="pre">&gt;</span></tt> (for planar images with non-standard step)</p>
<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>
<p>Given a horizontal iterator <tt class="docutils literal"><span class="pre">XIterator</span></tt>, we could choose the <tt class="docutils literal"><span class="pre">y-iterator</span></tt>, the iterator that moves along a column, as
<tt class="docutils literal"><span class="pre">memory_based_step_iterator&lt;XIterator&gt;</span></tt> 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>
<p>Then we can instantiate <tt class="docutils literal"><span class="pre">memory_based_2d_locator&lt;memory_based_step_iterator&lt;XIterator&gt;</span> <span class="pre">&gt;</span></tt> to obtain a 2D pixel locator, as the diagram indicates:
.. image:: step_iterator.gif</p>
<p><tt class="docutils literal"><span class="pre">virtual_2d_locator</span></tt> 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 coordinates. 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>
<p>Both the virtual and the memory-based locators subclass from <tt class="docutils literal"><span class="pre">pixel_2d_locator_base</span></tt>, a base class that provides most of the interface required
by <tt class="docutils literal"><span class="pre">PixelLocatorConcept</span></tt>. Users may find this base class useful if they need to provide other models of <tt class="docutils literal"><span class="pre">PixelLocatorConcept</span></tt>.</p>
<p>Here is some sample code using locators:</p>
<div class="highlight-c++"><div class="highlight"><pre><span class="n">loc</span><span class="o">=</span><span class="n">img</span><span class="p">.</span><span class="n">xy_at</span><span class="p">(</span><span class="mi">10</span><span class="p">,</span><span class="mi">10</span><span class="p">);</span> <span class="c1">// start at pixel (x=10,y=10)</span>
<span class="n">above</span><span class="o">=</span><span class="n">loc</span><span class="p">.</span><span class="n">cache_location</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="o">-</span><span class="mi">1</span><span class="p">);</span> <span class="c1">// remember relative locations of neighbors above and below</span>
<span class="n">below</span><span class="o">=</span><span class="n">loc</span><span class="p">.</span><span class="n">cache_location</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>
<span class="o">++</span><span class="n">loc</span><span class="p">.</span><span class="n">x</span><span class="p">();</span> <span class="c1">// move to (11,10)</span>
<span class="n">loc</span><span class="p">.</span><span class="n">y</span><span class="p">()</span><span class="o">+=</span><span class="mi">15</span><span class="p">;</span> <span class="c1">// move to (11,25)</span>
<span class="n">loc</span><span class="o">-=</span><span class="n">point2</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="kt">ptrdiff_t</span><span class="o">&gt;</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="mi">1</span><span class="p">);</span><span class="c1">// move to (10,24)</span>
<span class="o">*</span><span class="n">loc</span><span class="o">=</span><span class="p">(</span><span class="n">loc</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="o">-</span><span class="mi">1</span><span class="p">)</span><span class="o">+</span><span class="n">loc</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="mi">1</span><span class="p">))</span><span class="o">/</span><span class="mi">2</span><span class="p">;</span> <span class="c1">// set pixel (10,24) to the average of (10,23) and (10,25) (grayscale pixels only)</span>
<span class="o">*</span><span class="n">loc</span><span class="o">=</span><span class="p">(</span><span class="n">loc</span><span class="p">[</span><span class="n">above</span><span class="p">]</span><span class="o">+</span><span class="n">loc</span><span class="p">[</span><span class="n">below</span><span class="p">])</span><span class="o">/</span><span class="mi">2</span><span class="p">;</span> <span class="c1">// the same, but faster using cached relative neighbor locations</span>
</pre></div>
</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. <tt class="docutils literal"><span class="pre">++loc.x()</span></tt> 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 <tt class="docutils literal"><span class="pre">cache_location</span></tt>. In the above example <tt class="docutils literal"><span class="pre">loc[above]</span></tt> for simple interleaved images amounts to a raw array
index operator.</p>
</div>
<div class="section" id="iterator-over-2d-image">
<h3><a class="toc-backref" href="#id14">Iterator over 2D image</a></h3>
<p>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&#8217;s <tt class="docutils literal"><span class="pre">iterator_from_2d</span></tt> 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 &#8220;carriage return&#8221;. Synopsis:</p>
<div class="highlight-c++"><div class="highlight"><pre><span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">Locator</span><span class="o">&gt;</span> <span class="c1">// Models PixelLocatorConcept</span>
<span class="k">class</span> <span class="nc">iterator_from_2d</span>
<span class="p">{</span>
<span class="nl">public:</span>
<span class="n">iterator_from_2d</span><span class="p">(</span><span class="k">const</span> <span class="n">Locator</span><span class="o">&amp;</span> <span class="n">loc</span><span class="p">,</span> <span class="kt">int</span> <span class="n">x</span><span class="p">,</span> <span class="kt">int</span> <span class="n">width</span><span class="p">);</span>
<span class="n">iterator_from_2d</span><span class="o">&amp;</span> <span class="k">operator</span><span class="o">++</span><span class="p">();</span> <span class="c1">// if (++_x&lt;_width) ++_p.x(); else _p+=point_t(-_width,1);</span>
<span class="p">...</span>
<span class="nl">private:</span>
<span class="kt">int</span> <span class="n">_x</span><span class="p">,</span> <span class="n">_width</span><span class="p">;</span>
<span class="n">Locator</span> <span class="n">_p</span><span class="p">;</span>
<span class="p">};</span>
</pre></div>
</div>
<p>Iterating through the pixels in an image using <tt class="docutils literal"><span class="pre">iterator_from_2d</span></tt> 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
<tt class="docutils literal"><span class="pre">iterator_from_2d::operator++</span></tt> 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 p std::copy and
<tt class="docutils literal"><span class="pre">std::fill</span></tt>, when invoked with <tt class="docutils literal"><span class="pre">iterator_from_2d</span></tt>-s, to go through each row using their base x-iterators, and, if the image has no padding
(i.e. <tt class="docutils literal"><span class="pre">iterator_from_2d::is_1d_traversable()</span></tt> returns true) to simply iterate using the x-iterators directly.</p>
</div>
</div>
<div class="section" id="image-view">
<h2><a class="toc-backref" href="#id15">Image View</a></h2>
<p>An image view is a generalization of STL range concept to multiple dimensions. Similar to ranges (and iterators), image views are shallow, don&#8217;t
own the underlying data and don&#8217;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="highlight-c++"><div class="highlight"><pre><span class="n">concept</span> <span class="n">RandomAccessNDImageViewConcept</span><span class="o">&lt;</span><span class="n">Regular</span> <span class="n">View</span><span class="o">&gt;</span>
<span class="p">{</span>
<span class="k">typename</span> <span class="n">value_type</span><span class="p">;</span> <span class="c1">// for pixel-based views, the pixel type</span>
<span class="k">typename</span> <span class="n">reference</span><span class="p">;</span> <span class="c1">// result of dereferencing</span>
<span class="k">typename</span> <span class="n">difference_type</span><span class="p">;</span> <span class="c1">// result of operator-(iterator,iterator) (1-dimensional!)</span>
<span class="k">typename</span> <span class="kt">const_t</span><span class="p">;</span> <span class="n">where</span> <span class="n">RandomAccessNDImageViewConcept</span><span class="o">&lt;</span><span class="n">View</span><span class="o">&gt;</span><span class="p">;</span> <span class="c1">// same as View, but over immutable values</span>
<span class="k">typename</span> <span class="kt">point_t</span><span class="p">;</span> <span class="n">where</span> <span class="n">PointNDConcept</span><span class="o">&lt;</span><span class="kt">point_t</span><span class="o">&gt;</span><span class="p">;</span> <span class="c1">// N-dimensional point</span>
<span class="k">typename</span> <span class="n">locator</span><span class="p">;</span> <span class="n">where</span> <span class="n">RandomAccessNDLocatorConcept</span><span class="o">&lt;</span><span class="n">locator</span><span class="o">&gt;</span><span class="p">;</span> <span class="c1">// N-dimensional locator.</span>
<span class="k">typename</span> <span class="n">iterator</span><span class="p">;</span> <span class="n">where</span> <span class="n">RandomAccessTraversalConcept</span><span class="o">&lt;</span><span class="n">iterator</span><span class="o">&gt;</span><span class="p">;</span> <span class="c1">// 1-dimensional iterator over all values</span>
<span class="k">typename</span> <span class="n">reverse_iterator</span><span class="p">;</span> <span class="n">where</span> <span class="n">RandomAccessTraversalConcept</span><span class="o">&lt;</span><span class="n">reverse_iterator</span><span class="o">&gt;</span><span class="p">;</span>
<span class="k">typename</span> <span class="n">size_type</span><span class="p">;</span> <span class="c1">// the return value of size()</span>
<span class="c1">// Equivalent to RandomAccessNDLocatorConcept::axis</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="kt">size_t</span> <span class="n">D</span><span class="o">&gt;</span> <span class="k">struct</span> <span class="n">axis</span> <span class="p">{</span>
<span class="k">typename</span> <span class="kt">coord_t</span> <span class="o">=</span> <span class="kt">point_t</span><span class="o">::</span><span class="n">axis</span><span class="o">&lt;</span><span class="n">D</span><span class="o">&gt;::</span><span class="kt">coord_t</span><span class="p">;</span>
<span class="k">typename</span> <span class="n">iterator</span><span class="p">;</span> <span class="n">where</span> <span class="n">RandomAccessTraversalConcept</span><span class="o">&lt;</span><span class="n">iterator</span><span class="o">&gt;</span><span class="p">;</span> <span class="c1">// iterator along D-th axis.</span>
<span class="n">where</span> <span class="n">SameType</span><span class="o">&lt;</span><span class="kt">coord_t</span><span class="p">,</span> <span class="n">iterator</span><span class="o">::</span><span class="n">difference_type</span><span class="o">&gt;</span><span class="p">;</span>
<span class="n">where</span> <span class="n">SameType</span><span class="o">&lt;</span><span class="n">iterator</span><span class="o">::</span><span class="n">value_type</span><span class="p">,</span><span class="n">value_type</span><span class="o">&gt;</span><span class="p">;</span>
<span class="p">};</span>
<span class="c1">// Defines the type of a view similar to this type, except it invokes Deref upon dereferencing</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="n">PixelDereferenceAdaptorConcept</span> <span class="n">Deref</span><span class="o">&gt;</span> <span class="k">struct</span> <span class="n">add_deref</span> <span class="p">{</span>
<span class="k">typename</span> <span class="n">type</span><span class="p">;</span> <span class="n">where</span> <span class="n">RandomAccessNDImageViewConcept</span><span class="o">&lt;</span><span class="n">type</span><span class="o">&gt;</span><span class="p">;</span>
<span class="k">static</span> <span class="n">type</span> <span class="nf">make</span><span class="p">(</span><span class="k">const</span> <span class="n">View</span><span class="o">&amp;</span> <span class="n">v</span><span class="p">,</span> <span class="k">const</span> <span class="n">Deref</span><span class="o">&amp;</span> <span class="n">deref</span><span class="p">);</span>
<span class="p">};</span>
<span class="k">static</span> <span class="k">const</span> <span class="kt">size_t</span> <span class="n">num_dimensions</span> <span class="o">=</span> <span class="kt">point_t</span><span class="o">::</span><span class="n">num_dimensions</span><span class="p">;</span>
<span class="c1">// Create from a locator at the top-left corner and dimensions</span>
<span class="n">View</span><span class="o">::</span><span class="n">View</span><span class="p">(</span><span class="k">const</span> <span class="n">locator</span><span class="o">&amp;</span><span class="p">,</span> <span class="k">const</span> <span class="n">point_type</span><span class="o">&amp;</span><span class="p">);</span>
<span class="n">size_type</span> <span class="n">View</span><span class="o">::</span><span class="n">size</span><span class="p">()</span> <span class="k">const</span><span class="p">;</span> <span class="c1">// total number of elements</span>
<span class="n">reference</span> <span class="k">operator</span><span class="p">[](</span><span class="n">View</span><span class="p">,</span> <span class="k">const</span> <span class="n">difference_type</span><span class="o">&amp;</span><span class="p">)</span> <span class="k">const</span><span class="p">;</span> <span class="c1">// 1-dimensional reference</span>
<span class="n">iterator</span> <span class="n">View</span><span class="o">::</span><span class="n">begin</span><span class="p">()</span> <span class="k">const</span><span class="p">;</span>
<span class="n">iterator</span> <span class="n">View</span><span class="o">::</span><span class="n">end</span><span class="p">()</span> <span class="k">const</span><span class="p">;</span>
<span class="n">reverse_iterator</span> <span class="n">View</span><span class="o">::</span><span class="n">rbegin</span><span class="p">()</span> <span class="k">const</span><span class="p">;</span>
<span class="n">reverse_iterator</span> <span class="n">View</span><span class="o">::</span><span class="n">rend</span><span class="p">()</span> <span class="k">const</span><span class="p">;</span>
<span class="n">iterator</span> <span class="n">View</span><span class="o">::</span><span class="n">at</span><span class="p">(</span><span class="k">const</span> <span class="kt">point_t</span><span class="o">&amp;</span><span class="p">);</span>
<span class="kt">point_t</span> <span class="n">View</span><span class="o">::</span><span class="n">dimensions</span><span class="p">()</span> <span class="k">const</span><span class="p">;</span> <span class="c1">// number of elements along each dimension</span>
<span class="kt">bool</span> <span class="n">View</span><span class="o">::</span><span class="n">is_1d_traversable</span><span class="p">()</span> <span class="k">const</span><span class="p">;</span> <span class="c1">// Does an iterator over the first dimension visit each value?</span>
<span class="c1">// iterator along a given dimension starting at a given point</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="kt">size_t</span> <span class="n">D</span><span class="o">&gt;</span> <span class="n">View</span><span class="o">::</span><span class="n">axis</span><span class="o">&lt;</span><span class="n">D</span><span class="o">&gt;::</span><span class="n">iterator</span> <span class="n">View</span><span class="o">::</span><span class="n">axis_iterator</span><span class="p">(</span><span class="k">const</span> <span class="kt">point_t</span><span class="o">&amp;</span><span class="p">)</span> <span class="k">const</span><span class="p">;</span>
<span class="n">reference</span> <span class="k">operator</span><span class="p">()(</span><span class="n">View</span><span class="p">,</span><span class="k">const</span> <span class="kt">point_t</span><span class="o">&amp;</span><span class="p">)</span> <span class="k">const</span><span class="p">;</span>
<span class="p">};</span>
<span class="n">concept</span> <span class="n">MutableRandomAccessNDImageViewConcept</span><span class="o">&lt;</span><span class="n">RandomAccessNDImageViewConcept</span> <span class="n">View</span><span class="o">&gt;</span>
<span class="p">{</span>
<span class="n">where</span> <span class="n">Mutable</span><span class="o">&lt;</span><span class="n">reference</span><span class="o">&gt;</span><span class="p">;</span>
<span class="p">};</span>
</pre></div>
</div>
<p>Two-dimensional image views have the following extra requirements:</p>
<div class="highlight-c++"><div class="highlight"><pre><span class="n">concept</span> <span class="n">RandomAccess2DImageViewConcept</span><span class="o">&lt;</span><span class="n">RandomAccessNDImageViewConcept</span> <span class="n">View</span><span class="o">&gt;</span>
<span class="p">{</span>
<span class="n">where</span> <span class="n">num_dimensions</span><span class="o">==</span><span class="mi">2</span><span class="p">;</span>
<span class="k">typename</span> <span class="n">x_iterator</span> <span class="o">=</span> <span class="n">axis</span><span class="o">&lt;</span><span class="mi">0</span><span class="o">&gt;::</span><span class="n">iterator</span><span class="p">;</span>
<span class="k">typename</span> <span class="n">y_iterator</span> <span class="o">=</span> <span class="n">axis</span><span class="o">&lt;</span><span class="mi">1</span><span class="o">&gt;::</span><span class="n">iterator</span><span class="p">;</span>
<span class="k">typename</span> <span class="kt">x_coord_t</span> <span class="o">=</span> <span class="n">axis</span><span class="o">&lt;</span><span class="mi">0</span><span class="o">&gt;::</span><span class="kt">coord_t</span><span class="p">;</span>
<span class="k">typename</span> <span class="kt">y_coord_t</span> <span class="o">=</span> <span class="n">axis</span><span class="o">&lt;</span><span class="mi">1</span><span class="o">&gt;::</span><span class="kt">coord_t</span><span class="p">;</span>
<span class="k">typename</span> <span class="n">xy_locator</span> <span class="o">=</span> <span class="n">locator</span><span class="p">;</span>
<span class="kt">x_coord_t</span> <span class="n">View</span><span class="o">::</span><span class="n">width</span><span class="p">()</span> <span class="k">const</span><span class="p">;</span>
<span class="kt">y_coord_t</span> <span class="n">View</span><span class="o">::</span><span class="n">height</span><span class="p">()</span> <span class="k">const</span><span class="p">;</span>
<span class="c1">// X-navigation</span>
<span class="n">x_iterator</span> <span class="n">View</span><span class="o">::</span><span class="n">x_at</span><span class="p">(</span><span class="k">const</span> <span class="kt">point_t</span><span class="o">&amp;</span><span class="p">)</span> <span class="k">const</span><span class="p">;</span>
<span class="n">x_iterator</span> <span class="n">View</span><span class="o">::</span><span class="n">row_begin</span><span class="p">(</span><span class="kt">y_coord_t</span><span class="p">)</span> <span class="k">const</span><span class="p">;</span>
<span class="n">x_iterator</span> <span class="n">View</span><span class="o">::</span><span class="n">row_end</span> <span class="p">(</span><span class="kt">y_coord_t</span><span class="p">)</span> <span class="k">const</span><span class="p">;</span>
<span class="c1">// Y-navigation</span>
<span class="n">y_iterator</span> <span class="n">View</span><span class="o">::</span><span class="n">y_at</span><span class="p">(</span><span class="k">const</span> <span class="kt">point_t</span><span class="o">&amp;</span><span class="p">)</span> <span class="k">const</span><span class="p">;</span>
<span class="n">y_iterator</span> <span class="n">View</span><span class="o">::</span><span class="n">col_begin</span><span class="p">(</span><span class="kt">x_coord_t</span><span class="p">)</span> <span class="k">const</span><span class="p">;</span>
<span class="n">y_iterator</span> <span class="n">View</span><span class="o">::</span><span class="n">col_end</span> <span class="p">(</span><span class="kt">x_coord_t</span><span class="p">)</span> <span class="k">const</span><span class="p">;</span>
<span class="c1">// navigating in 2D</span>
<span class="n">xy_locator</span> <span class="n">View</span><span class="o">::</span><span class="n">xy_at</span><span class="p">(</span><span class="k">const</span> <span class="kt">point_t</span><span class="o">&amp;</span><span class="p">)</span> <span class="k">const</span><span class="p">;</span>
<span class="c1">// (x,y) versions of all methods taking point_t</span>
<span class="n">View</span><span class="o">::</span><span class="n">View</span><span class="p">(</span><span class="kt">x_coord_t</span><span class="p">,</span><span class="kt">y_coord_t</span><span class="p">,</span><span class="k">const</span> <span class="n">locator</span><span class="o">&amp;</span><span class="p">);</span>
<span class="n">iterator</span> <span class="n">View</span><span class="o">::</span><span class="n">at</span><span class="p">(</span><span class="kt">x_coord_t</span><span class="p">,</span><span class="kt">y_coord_t</span><span class="p">)</span> <span class="k">const</span><span class="p">;</span>
<span class="n">reference</span> <span class="k">operator</span><span class="p">()(</span><span class="n">View</span><span class="p">,</span><span class="kt">x_coord_t</span><span class="p">,</span><span class="kt">y_coord_t</span><span class="p">)</span> <span class="k">const</span><span class="p">;</span>
<span class="n">xy_locator</span> <span class="n">View</span><span class="o">::</span><span class="n">xy_at</span><span class="p">(</span><span class="kt">x_coord_t</span><span class="p">,</span><span class="kt">y_coord_t</span><span class="p">)</span> <span class="k">const</span><span class="p">;</span>
<span class="n">x_iterator</span> <span class="n">View</span><span class="o">::</span><span class="n">x_at</span><span class="p">(</span><span class="kt">x_coord_t</span><span class="p">,</span><span class="kt">y_coord_t</span><span class="p">)</span> <span class="k">const</span><span class="p">;</span>
<span class="n">y_iterator</span> <span class="n">View</span><span class="o">::</span><span class="n">y_at</span><span class="p">(</span><span class="kt">x_coord_t</span><span class="p">,</span><span class="kt">y_coord_t</span><span class="p">)</span> <span class="k">const</span><span class="p">;</span>
<span class="p">};</span>
<span class="n">concept</span> <span class="n">MutableRandomAccess2DImageViewConcept</span><span class="o">&lt;</span><span class="n">RandomAccess2DImageViewConcept</span> <span class="n">View</span><span class="o">&gt;</span>
<span class="o">:</span> <span class="n">MutableRandomAccessNDImageViewConcept</span><span class="o">&lt;</span><span class="n">View</span><span class="o">&gt;</span> <span class="p">{};</span>
</pre></div>
</div>
<p>Image views that GIL typically uses operate on value types that model <tt class="docutils literal"><span class="pre">PixelValueConcept</span></tt> and have some additional requirements:</p>
<div class="highlight-c++"><div class="highlight"><pre><span class="n">concept</span> <span class="n">ImageViewConcept</span><span class="o">&lt;</span><span class="n">RandomAccess2DImageViewConcept</span> <span class="n">View</span><span class="o">&gt;</span>
<span class="p">{</span>
<span class="n">where</span> <span class="n">PixelValueConcept</span><span class="o">&lt;</span><span class="n">value_type</span><span class="o">&gt;</span><span class="p">;</span>
<span class="n">where</span> <span class="n">PixelIteratorConcept</span><span class="o">&lt;</span><span class="n">x_iterator</span><span class="o">&gt;</span><span class="p">;</span>
<span class="n">where</span> <span class="n">PixelIteratorConcept</span><span class="o">&lt;</span><span class="n">y_iterator</span><span class="o">&gt;</span><span class="p">;</span>
<span class="n">where</span> <span class="kt">x_coord_t</span> <span class="o">==</span> <span class="kt">y_coord_t</span><span class="p">;</span>
<span class="k">typename</span> <span class="kt">coord_t</span> <span class="o">=</span> <span class="kt">x_coord_t</span><span class="p">;</span>
<span class="n">std</span><span class="o">::</span><span class="kt">size_t</span> <span class="n">View</span><span class="o">::</span><span class="n">num_channels</span><span class="p">()</span> <span class="k">const</span><span class="p">;</span>
<span class="p">};</span>
<span class="n">concept</span> <span class="n">MutableImageViewConcept</span><span class="o">&lt;</span><span class="n">ImageViewConcept</span> <span class="n">View</span><span class="o">&gt;</span> <span class="o">:</span> <span class="n">MutableRandomAccess2DImageViewConcept</span><span class="o">&lt;</span><span class="n">View</span><span class="o">&gt;</span> <span class="p">{};</span>
</pre></div>
</div>
<p>Two image views are compatible if they have compatible pixels and the same number of dimensions:</p>
<div class="highlight-c++"><div class="highlight"><pre><span class="n">concept</span> <span class="n">ViewsCompatibleConcept</span><span class="o">&lt;</span><span class="n">ImageViewConcept</span> <span class="n">V1</span><span class="p">,</span> <span class="n">ImageViewConcept</span> <span class="n">V2</span><span class="o">&gt;</span>
<span class="p">{</span>
<span class="n">where</span> <span class="n">PixelsCompatibleConcept</span><span class="o">&lt;</span><span class="n">V1</span><span class="o">::</span><span class="n">value_type</span><span class="p">,</span> <span class="n">V2</span><span class="o">::</span><span class="n">value_type</span><span class="o">&gt;</span><span class="p">;</span>
<span class="n">where</span> <span class="n">V1</span><span class="o">::</span><span class="n">num_dimensions</span> <span class="o">==</span> <span class="n">V2</span><span class="o">::</span><span class="n">num_dimensions</span><span class="p">;</span>
<span class="p">};</span>
</pre></div>
</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>
<p>&lt;b&gt;Related Concepts:&lt;/b&gt;</p>
<ul class="simple">
<li>RandomAccessNDImageViewConcept&lt;View&gt;</li>
<li>MutableRandomAccessNDImageViewConcept&lt;View&gt;</li>
<li>RandomAccess2DImageViewConcept&lt;View&gt;</li>
<li>MutableRandomAccess2DImageViewConcept&lt;View&gt;</li>
<li>ImageViewConcept&lt;View&gt;</li>
<li>MutableImageViewConcept&lt;View&gt;</li>
<li>ViewsCompatibleConcept&lt;View1,View2&gt;</li>
</ul>
<p>&lt;b&gt;Models:&lt;/b&gt;</p>
<p>GIL provides a model for <tt class="docutils literal"><span class="pre">ImageViewConcept</span></tt> called <tt class="docutils literal"><span class="pre">image_view</span></tt>. It is templated over a model of <tt class="docutils literal"><span class="pre">PixelLocatorConcept</span></tt>.
(If instantiated with a model of <tt class="docutils literal"><span class="pre">MutablePixelLocatorConcept</span></tt>, it models <tt class="docutils literal"><span class="pre">MutableImageViewConcept</span></tt>). Synopsis:</p>
<div class="highlight-c++"><div class="highlight"><pre><span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">Locator</span><span class="o">&gt;</span> <span class="c1">// Models PixelLocatorConcept (could be MutablePixelLocatorConcept)</span>
<span class="k">class</span> <span class="nc">image_view</span>
<span class="p">{</span>
<span class="nl">public:</span>
<span class="k">typedef</span> <span class="n">Locator</span> <span class="n">xy_locator</span><span class="p">;</span>
<span class="k">typedef</span> <span class="n">iterator_from_2d</span><span class="o">&lt;</span><span class="n">Locator</span><span class="o">&gt;</span> <span class="n">iterator</span><span class="p">;</span>
<span class="p">...</span>
<span class="nl">private:</span>
<span class="n">xy_locator</span> <span class="n">_pixels</span><span class="p">;</span> <span class="c1">// 2D pixel locator at the top left corner of the image view range</span>
<span class="kt">point_t</span> <span class="n">_dimensions</span><span class="p">;</span> <span class="c1">// width and height</span>
<span class="p">};</span>
</pre></div>
</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>
<div class="section" id="creating-views-from-raw-pixels">
<h3><a class="toc-backref" href="#id16">Creating Views from Raw Pixels</a></h3>
<p>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 <tt class="docutils literal"><span class="pre">interleaved_view</span></tt>, supplying the image dimensions, number of bytes per row, and a
pointer to the first pixel:</p>
<div class="highlight-c++"><div class="highlight"><pre><span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">Iterator</span><span class="o">&gt;</span> <span class="c1">// Models pixel iterator (like rgb8_ptr_t or rgb8c_ptr_t)</span>
<span class="n">image_view</span><span class="o">&lt;</span><span class="p">...</span><span class="o">&gt;</span> <span class="n">interleaved_view</span><span class="p">(</span><span class="kt">ptrdiff_t</span> <span class="n">width</span><span class="p">,</span> <span class="kt">ptrdiff_t</span> <span class="n">height</span><span class="p">,</span> <span class="n">Iterator</span> <span class="n">pixels</span><span class="p">,</span> <span class="kt">ptrdiff_t</span> <span class="n">rowsize</span><span class="p">)</span>
</pre></div>
</div>
<p>Planar views are defined for every color space and take each plane separately. Here is the RGB one:</p>
<div class="highlight-c++"><div class="highlight"><pre><span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">IC</span><span class="o">&gt;</span> <span class="c1">// Models channel iterator (like bits8* or const bits8*)</span>
<span class="n">image_view</span><span class="o">&lt;</span><span class="p">...</span><span class="o">&gt;</span> <span class="n">planar_rgb_view</span><span class="p">(</span><span class="kt">ptrdiff_t</span> <span class="n">width</span><span class="p">,</span> <span class="kt">ptrdiff_t</span> <span class="n">height</span><span class="p">,</span>
<span class="n">IC</span> <span class="n">r</span><span class="p">,</span> <span class="n">IC</span> <span class="n">g</span><span class="p">,</span> <span class="n">IC</span> <span class="n">b</span><span class="p">,</span> <span class="kt">ptrdiff_t</span> <span class="n">rowsize</span><span class="p">);</span>
</pre></div>
</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.</p>
</div>
<div class="section" id="creating-image-views-from-other-image-views">
<h3><a class="toc-backref" href="#id17">Creating Image Views from Other Image Views</a></h3>
<p>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="highlight-c++"><div class="highlight"><pre><span class="c1">// Some result view types</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">View</span><span class="o">&gt;</span>
<span class="k">struct</span> <span class="n">dynamic_xy_step_type</span> <span class="o">:</span> <span class="k">public</span> <span class="n">dynamic_y_step_type</span><span class="o">&lt;</span><span class="k">typename</span> <span class="n">dynamic_x_step_type</span><span class="o">&lt;</span><span class="n">View</span><span class="o">&gt;::</span><span class="n">type</span><span class="o">&gt;</span> <span class="p">{};</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">View</span><span class="o">&gt;</span>
<span class="k">struct</span> <span class="n">dynamic_xy_step_transposed_type</span> <span class="o">:</span> <span class="k">public</span> <span class="n">dynamic_xy_step_type</span><span class="o">&lt;</span><span class="k">typename</span> <span class="n">transposed_type</span><span class="o">&lt;</span><span class="n">View</span><span class="o">&gt;::</span><span class="n">type</span><span class="o">&gt;</span> <span class="p">{};</span>
<span class="c1">// color and bit depth converted view to match pixel type P</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">SrcView</span><span class="p">,</span> <span class="c1">// Models ImageViewConcept</span>
<span class="k">typename</span> <span class="n">DstP</span><span class="p">,</span> <span class="c1">// Models PixelConcept</span>
<span class="k">typename</span> <span class="n">ColorConverter</span><span class="o">=</span><span class="n">gil</span><span class="o">::</span><span class="n">default_color_converter</span><span class="o">&gt;</span>
<span class="k">struct</span> <span class="n">color_converted_view_type</span>
<span class="p">{</span>
<span class="k">typedef</span> <span class="p">...</span> <span class="n">type</span><span class="p">;</span> <span class="c1">// image view adaptor with value type DstP, over SrcView</span>
<span class="p">};</span>
<span class="c1">// single-channel view of the N-th channel of a given view</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">SrcView</span><span class="o">&gt;</span>
<span class="k">struct</span> <span class="n">nth_channel_view_type</span>
<span class="p">{</span>
<span class="k">typedef</span> <span class="p">...</span> <span class="n">type</span><span class="p">;</span>
<span class="p">};</span>
</pre></div>
</div>
<p>GIL Provides the following view transformations:</p>
<div class="highlight-c++"><div class="highlight"><pre><span class="c1">// flipped upside-down, left-to-right, transposed view</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">View</span><span class="o">&gt;</span> <span class="k">typename</span> <span class="n">dynamic_y_step_type</span><span class="o">&lt;</span><span class="n">View</span><span class="o">&gt;::</span><span class="n">type</span> <span class="n">flipped_up_down_view</span><span class="p">(</span><span class="k">const</span> <span class="n">View</span><span class="o">&amp;</span> <span class="n">src</span><span class="p">);</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">View</span><span class="o">&gt;</span> <span class="k">typename</span> <span class="n">dynamic_x_step_type</span><span class="o">&lt;</span><span class="n">View</span><span class="o">&gt;::</span><span class="n">type</span> <span class="n">flipped_left_right_view</span><span class="p">(</span><span class="k">const</span> <span class="n">View</span><span class="o">&amp;</span> <span class="n">src</span><span class="p">);</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">View</span><span class="o">&gt;</span> <span class="k">typename</span> <span class="n">dynamic_xy_step_transposed_type</span><span class="o">&lt;</span><span class="n">View</span><span class="o">&gt;::</span><span class="n">type</span> <span class="n">transposed_view</span><span class="p">(</span><span class="k">const</span> <span class="n">View</span><span class="o">&amp;</span> <span class="n">src</span><span class="p">);</span>
<span class="c1">// rotations</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">View</span><span class="o">&gt;</span> <span class="k">typename</span> <span class="n">dynamic_xy_step_type</span><span class="o">&lt;</span><span class="n">View</span><span class="o">&gt;::</span><span class="n">type</span> <span class="n">rotated180_view</span><span class="p">(</span><span class="k">const</span> <span class="n">View</span><span class="o">&amp;</span> <span class="n">src</span><span class="p">);</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">View</span><span class="o">&gt;</span> <span class="k">typename</span> <span class="n">dynamic_xy_step_transposed_type</span><span class="o">&lt;</span><span class="n">View</span><span class="o">&gt;::</span><span class="n">type</span> <span class="n">rotated90cw_view</span><span class="p">(</span><span class="k">const</span> <span class="n">View</span><span class="o">&amp;</span> <span class="n">src</span><span class="p">);</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">View</span><span class="o">&gt;</span> <span class="k">typename</span> <span class="n">dynamic_xy_step_transposed_type</span><span class="o">&lt;</span><span class="n">View</span><span class="o">&gt;::</span><span class="n">type</span> <span class="n">rotated90ccw_view</span><span class="p">(</span><span class="k">const</span> <span class="n">View</span><span class="o">&amp;</span> <span class="n">src</span><span class="p">);</span>
<span class="c1">// view of an axis-aligned rectangular area within an image</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">View</span><span class="o">&gt;</span> <span class="n">View</span> <span class="n">subimage_view</span><span class="p">(</span><span class="k">const</span> <span class="n">View</span><span class="o">&amp;</span> <span class="n">src</span><span class="p">,</span>
<span class="k">const</span> <span class="n">View</span><span class="o">::</span><span class="kt">point_t</span><span class="o">&amp;</span> <span class="n">top_left</span><span class="p">,</span> <span class="k">const</span> <span class="n">View</span><span class="o">::</span><span class="kt">point_t</span><span class="o">&amp;</span> <span class="n">dimensions</span><span class="p">);</span>
<span class="c1">// subsampled view (skipping pixels in X and Y)</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">View</span><span class="o">&gt;</span> <span class="k">typename</span> <span class="n">dynamic_xy_step_type</span><span class="o">&lt;</span><span class="n">View</span><span class="o">&gt;::</span><span class="n">type</span> <span class="n">subsampled_view</span><span class="p">(</span><span class="k">const</span> <span class="n">View</span><span class="o">&amp;</span> <span class="n">src</span><span class="p">,</span>
<span class="k">const</span> <span class="n">View</span><span class="o">::</span><span class="kt">point_t</span><span class="o">&amp;</span> <span class="n">step</span><span class="p">);</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">View</span><span class="p">,</span> <span class="k">typename</span> <span class="n">P</span><span class="o">&gt;</span>
<span class="n">color_converted_view_type</span><span class="o">&lt;</span><span class="n">View</span><span class="p">,</span><span class="n">P</span><span class="o">&gt;::</span><span class="n">type</span> <span class="n">color_converted_view</span><span class="p">(</span><span class="k">const</span> <span class="n">View</span><span class="o">&amp;</span> <span class="n">src</span><span class="p">);</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">View</span><span class="p">,</span> <span class="k">typename</span> <span class="n">P</span><span class="p">,</span> <span class="k">typename</span> <span class="n">CCV</span><span class="o">&gt;</span> <span class="c1">// with a custom color converter</span>
<span class="n">color_converted_view_type</span><span class="o">&lt;</span><span class="n">View</span><span class="p">,</span><span class="n">P</span><span class="p">,</span><span class="n">CCV</span><span class="o">&gt;::</span><span class="n">type</span> <span class="n">color_converted_view</span><span class="p">(</span><span class="k">const</span> <span class="n">View</span><span class="o">&amp;</span> <span class="n">src</span><span class="p">);</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">View</span><span class="o">&gt;</span>
<span class="n">nth_channel_view_type</span><span class="o">&lt;</span><span class="n">View</span><span class="o">&gt;::</span><span class="kt">view_t</span> <span class="n">nth_channel_view</span><span class="p">(</span><span class="k">const</span> <span class="n">View</span><span class="o">&amp;</span> <span class="n">view</span><span class="p">,</span> <span class="kt">int</span> <span class="n">n</span><span class="p">);</span>
</pre></div>
</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="highlight-c++"><div class="highlight"><pre><span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">View</span><span class="o">&gt;</span>
<span class="k">typename</span> <span class="n">dynamic_y_step_type</span><span class="o">&lt;</span><span class="n">View</span><span class="o">&gt;::</span><span class="n">type</span> <span class="n">flipped_up_down_view</span><span class="p">(</span><span class="k">const</span> <span class="n">View</span><span class="o">&amp;</span> <span class="n">src</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">gil_function_requires</span><span class="o">&lt;</span><span class="n">ImageViewConcept</span><span class="o">&lt;</span><span class="n">View</span><span class="o">&gt;</span> <span class="o">&gt;</span><span class="p">();</span>
<span class="k">typedef</span> <span class="k">typename</span> <span class="n">dynamic_y_step_type</span><span class="o">&lt;</span><span class="n">View</span><span class="o">&gt;::</span><span class="n">type</span> <span class="n">RView</span><span class="p">;</span>
<span class="k">return</span> <span class="nf">RView</span><span class="p">(</span><span class="n">src</span><span class="p">.</span><span class="n">dimensions</span><span class="p">(),</span><span class="k">typename</span> <span class="n">RView</span><span class="o">::</span><span class="n">xy_locator</span><span class="p">(</span><span class="n">src</span><span class="p">.</span><span class="n">xy_at</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="n">src</span><span class="p">.</span><span class="n">height</span><span class="p">()</span><span class="o">-</span><span class="mi">1</span><span class="p">),</span><span class="o">-</span><span class="mi">1</span><span class="p">));</span>
<span class="p">}</span>
</pre></div>
</div>
<p>The call to <tt class="docutils literal"><span class="pre">gil_function_requires</span></tt> ensures (at compile time) that the template parameter is a valid model of <tt class="docutils literal"><span class="pre">ImageViewConcept</span></tt>. Using it
generates easier to track compile errors, creates no extra code and has no run-time performance impact.
We are using the <tt class="docutils literal"><span class="pre">boost::concept_check</span> <span class="pre">library</span></tt>, but wrapping it in <tt class="docutils literal"><span class="pre">gil_function_requires</span></tt>, which performs the check if the <tt class="docutils literal"><span class="pre">BOOST_GIL_USE_CONCEPT_CHECK</span></tt>
is set. It is unset by default, because there is a significant increase in compile time when using concept checks. We will skip <tt class="docutils literal"><span class="pre">gil_function_requires</span></tt>
in the code examples in this guide for the sake of succinctness.</p>
<p>Image views can be freely composed (see section ref MetafunctionsDG for the typedefs <tt class="docutils literal"><span class="pre">rgb16_image_t</span></tt> and <tt class="docutils literal"><span class="pre">gray16_step_view_t)</span></tt>:</p>
<div class="highlight-c++"><div class="highlight"><pre><span class="kt">rgb16_image_t</span> <span class="nf">img</span><span class="p">(</span><span class="mi">100</span><span class="p">,</span><span class="mi">100</span><span class="p">);</span> <span class="c1">// an RGB interleaved image</span>
<span class="c1">// grayscale view over the green (index 1) channel of img</span>
<span class="kt">gray16_step_view_t</span> <span class="n">green</span><span class="o">=</span><span class="n">nth_channel_view</span><span class="p">(</span><span class="n">view</span><span class="p">(</span><span class="n">img</span><span class="p">),</span><span class="mi">1</span><span class="p">);</span>
<span class="c1">// 50x50 view of the green channel of img, upside down and taking every other pixel in X and in Y</span>
<span class="kt">gray16_step_view_t</span> <span class="n">ud_fud</span><span class="o">=</span><span class="n">flipped_up_down_view</span><span class="p">(</span><span class="n">subsampled_view</span><span class="p">(</span><span class="n">green</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">2</span><span class="p">));</span>
</pre></div>
</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 <tt class="docutils literal"><span class="pre">img</span></tt> was created.</p>
</div>
<div class="section" id="stl-style-algorithms-on-image-views">
<h3><a class="toc-backref" href="#id18">STL-Style Algorithms on Image Views</a></h3>
<p>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="highlight-c++"><div class="highlight"><pre><span class="c1">// Equivalents of std::copy and std::uninitialized_copy</span>
<span class="c1">// where ImageViewConcept&lt;V1&gt;, MutableImageViewConcept&lt;V2&gt;, ViewsCompatibleConcept&lt;V1,V2&gt;</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">V1</span><span class="p">,</span> <span class="k">typename</span> <span class="n">V2</span><span class="o">&gt;</span>
<span class="kt">void</span> <span class="n">copy_pixels</span><span class="p">(</span><span class="k">const</span> <span class="n">V1</span><span class="o">&amp;</span> <span class="n">src</span><span class="p">,</span> <span class="k">const</span> <span class="n">V2</span><span class="o">&amp;</span> <span class="n">dst</span><span class="p">);</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">V1</span><span class="p">,</span> <span class="k">typename</span> <span class="n">V2</span><span class="o">&gt;</span>
<span class="kt">void</span> <span class="n">uninitialized_copy_pixels</span><span class="p">(</span><span class="k">const</span> <span class="n">V1</span><span class="o">&amp;</span> <span class="n">src</span><span class="p">,</span> <span class="k">const</span> <span class="n">V2</span><span class="o">&amp;</span> <span class="n">dst</span><span class="p">);</span>
<span class="c1">// Equivalents of std::fill and std::uninitialized_fill</span>
<span class="c1">// where MutableImageViewConcept&lt;V&gt;, PixelConcept&lt;Value&gt;, PixelsCompatibleConcept&lt;Value,V::value_type&gt;</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">V</span><span class="p">,</span> <span class="k">typename</span> <span class="n">Value</span><span class="o">&gt;</span>
<span class="kt">void</span> <span class="n">fill_pixels</span><span class="p">(</span><span class="k">const</span> <span class="n">V</span><span class="o">&amp;</span> <span class="n">dst</span><span class="p">,</span> <span class="k">const</span> <span class="n">Value</span><span class="o">&amp;</span> <span class="n">val</span><span class="p">);</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">V</span><span class="p">,</span> <span class="k">typename</span> <span class="n">Value</span><span class="o">&gt;</span>
<span class="kt">void</span> <span class="n">uninitialized_fill_pixels</span><span class="p">(</span><span class="k">const</span> <span class="n">V</span><span class="o">&amp;</span> <span class="n">dst</span><span class="p">,</span> <span class="k">const</span> <span class="n">Value</span><span class="o">&amp;</span> <span class="n">val</span><span class="p">);</span>
<span class="c1">// Equivalent of std::for_each</span>
<span class="c1">// where ImageViewConcept&lt;V&gt;, boost::UnaryFunctionConcept&lt;F&gt;</span>
<span class="c1">// where PixelsCompatibleConcept&lt;V::reference, F::argument_type&gt;</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">V</span><span class="p">,</span> <span class="k">typename</span> <span class="n">F</span><span class="o">&gt;</span>
<span class="n">F</span> <span class="n">for_each_pixel</span><span class="p">(</span><span class="k">const</span> <span class="n">V</span><span class="o">&amp;</span> <span class="n">view</span><span class="p">,</span> <span class="n">F</span> <span class="n">fun</span><span class="p">);</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">V</span><span class="p">,</span> <span class="k">typename</span> <span class="n">F</span><span class="o">&gt;</span>
<span class="n">F</span> <span class="n">for_each_pixel_position</span><span class="p">(</span><span class="k">const</span> <span class="n">V</span><span class="o">&amp;</span> <span class="n">view</span><span class="p">,</span> <span class="n">F</span> <span class="n">fun</span><span class="p">);</span>
<span class="c1">// Equivalent of std::generate</span>
<span class="c1">// where MutableImageViewConcept&lt;V&gt;, boost::UnaryFunctionConcept&lt;F&gt;</span>
<span class="c1">// where PixelsCompatibleConcept&lt;V::reference, F::argument_type&gt;</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">V</span><span class="p">,</span> <span class="k">typename</span> <span class="n">F</span><span class="o">&gt;</span>
<span class="kt">void</span> <span class="n">generate_pixels</span><span class="p">(</span><span class="k">const</span> <span class="n">V</span><span class="o">&amp;</span> <span class="n">dst</span><span class="p">,</span> <span class="n">F</span> <span class="n">fun</span><span class="p">);</span>
<span class="c1">// Equivalent of std::transform with one source</span>
<span class="c1">// where ImageViewConcept&lt;V1&gt;, MutableImageViewConcept&lt;V2&gt;</span>
<span class="c1">// where boost::UnaryFunctionConcept&lt;F&gt;</span>
<span class="c1">// where PixelsCompatibleConcept&lt;V1::const_reference, F::argument_type&gt;</span>
<span class="c1">// where PixelsCompatibleConcept&lt;F::result_type, V2::reference&gt;</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">V1</span><span class="p">,</span> <span class="k">typename</span> <span class="n">V2</span><span class="p">,</span> <span class="k">typename</span> <span class="n">F</span><span class="o">&gt;</span>
<span class="n">F</span> <span class="n">transform_pixels</span><span class="p">(</span><span class="k">const</span> <span class="n">V1</span><span class="o">&amp;</span> <span class="n">src</span><span class="p">,</span> <span class="k">const</span> <span class="n">V2</span><span class="o">&amp;</span> <span class="n">dst</span><span class="p">,</span> <span class="n">F</span> <span class="n">fun</span><span class="p">);</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">V1</span><span class="p">,</span> <span class="k">typename</span> <span class="n">V2</span><span class="p">,</span> <span class="k">typename</span> <span class="n">F</span><span class="o">&gt;</span>
<span class="n">F</span> <span class="n">transform_pixel_positions</span><span class="p">(</span><span class="k">const</span> <span class="n">V1</span><span class="o">&amp;</span> <span class="n">src</span><span class="p">,</span> <span class="k">const</span> <span class="n">V2</span><span class="o">&amp;</span> <span class="n">dst</span><span class="p">,</span> <span class="n">F</span> <span class="n">fun</span><span class="p">);</span>
<span class="c1">// Equivalent of std::transform with two sources</span>
<span class="c1">// where ImageViewConcept&lt;V1&gt;, ImageViewConcept&lt;V2&gt;, MutableImageViewConcept&lt;V3&gt;</span>
<span class="c1">// where boost::BinaryFunctionConcept&lt;F&gt;</span>
<span class="c1">// where PixelsCompatibleConcept&lt;V1::const_reference, F::first_argument_type&gt;</span>
<span class="c1">// where PixelsCompatibleConcept&lt;V2::const_reference, F::second_argument_type&gt;</span>
<span class="c1">// where PixelsCompatibleConcept&lt;F::result_type, V3::reference&gt;</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">V1</span><span class="p">,</span> <span class="k">typename</span> <span class="n">V2</span><span class="p">,</span> <span class="k">typename</span> <span class="n">V3</span><span class="p">,</span> <span class="k">typename</span> <span class="n">F</span><span class="o">&gt;</span>
<span class="n">F</span> <span class="n">transform_pixels</span><span class="p">(</span><span class="k">const</span> <span class="n">V1</span><span class="o">&amp;</span> <span class="n">src1</span><span class="p">,</span> <span class="k">const</span> <span class="n">V2</span><span class="o">&amp;</span> <span class="n">src2</span><span class="p">,</span> <span class="k">const</span> <span class="n">V3</span><span class="o">&amp;</span> <span class="n">dst</span><span class="p">,</span> <span class="n">F</span> <span class="n">fun</span><span class="p">);</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">V1</span><span class="p">,</span> <span class="k">typename</span> <span class="n">V2</span><span class="p">,</span> <span class="k">typename</span> <span class="n">V3</span><span class="p">,</span> <span class="k">typename</span> <span class="n">F</span><span class="o">&gt;</span>
<span class="n">F</span> <span class="n">transform_pixel_positions</span><span class="p">(</span><span class="k">const</span> <span class="n">V1</span><span class="o">&amp;</span> <span class="n">src1</span><span class="p">,</span> <span class="k">const</span> <span class="n">V2</span><span class="o">&amp;</span> <span class="n">src2</span><span class="p">,</span> <span class="k">const</span> <span class="n">V3</span><span class="o">&amp;</span> <span class="n">dst</span><span class="p">,</span> <span class="n">F</span> <span class="n">fun</span><span class="p">);</span>
<span class="c1">// Copies a view into another, color converting the pixels if needed, with the default or user-defined color converter</span>
<span class="c1">// where ImageViewConcept&lt;V1&gt;, MutableImageViewConcept&lt;V2&gt;</span>
<span class="c1">// V1::value_type must be convertible to V2::value_type.</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">V1</span><span class="p">,</span> <span class="k">typename</span> <span class="n">V2</span><span class="o">&gt;</span>
<span class="kt">void</span> <span class="n">copy_and_convert_pixels</span><span class="p">(</span><span class="k">const</span> <span class="n">V1</span><span class="o">&amp;</span> <span class="n">src</span><span class="p">,</span> <span class="k">const</span> <span class="n">V2</span><span class="o">&amp;</span> <span class="n">dst</span><span class="p">);</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">V1</span><span class="p">,</span> <span class="k">typename</span> <span class="n">V2</span><span class="p">,</span> <span class="k">typename</span> <span class="n">ColorConverter</span><span class="o">&gt;</span>
<span class="kt">void</span> <span class="n">copy_and_convert_pixels</span><span class="p">(</span><span class="k">const</span> <span class="n">V1</span><span class="o">&amp;</span> <span class="n">src</span><span class="p">,</span> <span class="k">const</span> <span class="n">V2</span><span class="o">&amp;</span> <span class="n">dst</span><span class="p">,</span> <span class="n">ColorConverter</span> <span class="n">ccv</span><span class="p">);</span>
<span class="c1">// Equivalent of std::equal</span>
<span class="c1">// where ImageViewConcept&lt;V1&gt;, ImageViewConcept&lt;V2&gt;, ViewsCompatibleConcept&lt;V1,V2&gt;</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">V1</span><span class="p">,</span> <span class="k">typename</span> <span class="n">V2</span><span class="o">&gt;</span>
<span class="kt">bool</span> <span class="n">equal_pixels</span><span class="p">(</span><span class="k">const</span> <span class="n">V1</span><span class="o">&amp;</span> <span class="n">view1</span><span class="p">,</span> <span class="k">const</span> <span class="n">V2</span><span class="o">&amp;</span> <span class="n">view2</span><span class="p">);</span>
</pre></div>
</div>
<p>Algorithms that take multiple views require that they have the same dimensions.
<tt class="docutils literal"><span class="pre">for_each_pixel_position</span></tt> and <tt class="docutils literal"><span class="pre">transform_pixel_positions</span></tt> 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>
<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>
<p>The algorithms typically delegate the work to their corresponding STL algorithms. For example, <tt class="docutils literal"><span class="pre">copy_pixels</span></tt> calls <tt class="docutils literal"><span class="pre">std::copy</span></tt> either for each
row, or, when the images are 1D-traversable, once for all pixels.</p>
<p>In addition, overloads are sometimes provided for the STL algorithms. For example, <tt class="docutils literal"><span class="pre">std::copy</span></tt> for planar iterators is overloaded to perform
<tt class="docutils literal"><span class="pre">std::copy</span></tt> for each of the planes. <tt class="docutils literal"><span class="pre">std::copy</span></tt> over bitwise-copyable pixels results in <tt class="docutils literal"><span class="pre">std::copy</span></tt> over unsigned char, which STL typically
implements via p memmove.</p>
<p>As a result <tt class="docutils literal"><span class="pre">copy_pixels</span></tt> may result in a single call to <tt class="docutils literal"><span class="pre">memmove</span></tt> 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>
<p>GIL also provides some beta-versions of image processing algorithms, such as resampling and convolution in a numerics extension available on
<a class="reference external" href="http://stlab.adobe.com/gil/download.html">http://stlab.adobe.com/gil/download.html</a>. This code is in early stage of development and is not optimized for speed</p>
</div>
</div>
<div class="section" id="image">
<h2><a class="toc-backref" href="#id19">Image</a></h2>
<p>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>
<p>In the most general form images are N-dimensional and satisfy the following concept:</p>
<div class="highlight-c++"><div class="highlight"><pre><span class="n">concept</span> <span class="n">RandomAccessNDImageConcept</span><span class="o">&lt;</span><span class="k">typename</span> <span class="n">Img</span><span class="o">&gt;</span> <span class="o">:</span> <span class="n">Regular</span><span class="o">&lt;</span><span class="n">Img</span><span class="o">&gt;</span>
<span class="p">{</span>
<span class="k">typename</span> <span class="kt">view_t</span><span class="p">;</span> <span class="n">where</span> <span class="n">MutableRandomAccessNDImageViewConcept</span><span class="o">&lt;</span><span class="kt">view_t</span><span class="o">&gt;</span><span class="p">;</span>
<span class="k">typename</span> <span class="kt">const_view_t</span> <span class="o">=</span> <span class="kt">view_t</span><span class="o">::</span><span class="kt">const_t</span><span class="p">;</span>
<span class="k">typename</span> <span class="kt">point_t</span> <span class="o">=</span> <span class="kt">view_t</span><span class="o">::</span><span class="kt">point_t</span><span class="p">;</span>
<span class="k">typename</span> <span class="n">value_type</span> <span class="o">=</span> <span class="kt">view_t</span><span class="o">::</span><span class="n">value_type</span><span class="p">;</span>
<span class="k">typename</span> <span class="n">allocator_type</span><span class="p">;</span>
<span class="n">Img</span><span class="o">::</span><span class="n">Img</span><span class="p">(</span><span class="kt">point_t</span> <span class="n">dims</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="kt">size_t</span> <span class="n">alignment</span><span class="o">=</span><span class="mi">0</span><span class="p">);</span>
<span class="n">Img</span><span class="o">::</span><span class="n">Img</span><span class="p">(</span><span class="kt">point_t</span> <span class="n">dims</span><span class="p">,</span> <span class="n">value_type</span> <span class="n">fill_value</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="kt">size_t</span> <span class="n">alignment</span><span class="p">);</span>
<span class="kt">void</span> <span class="n">Img</span><span class="o">::</span><span class="n">recreate</span><span class="p">(</span><span class="kt">point_t</span> <span class="n">new_dims</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="kt">size_t</span> <span class="n">alignment</span><span class="o">=</span><span class="mi">0</span><span class="p">);</span>
<span class="kt">void</span> <span class="n">Img</span><span class="o">::</span><span class="n">recreate</span><span class="p">(</span><span class="kt">point_t</span> <span class="n">new_dims</span><span class="p">,</span> <span class="n">value_type</span> <span class="n">fill_value</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="kt">size_t</span> <span class="n">alignment</span><span class="p">);</span>
<span class="k">const</span> <span class="kt">point_t</span><span class="o">&amp;</span> <span class="n">Img</span><span class="o">::</span><span class="n">dimensions</span><span class="p">()</span> <span class="k">const</span><span class="p">;</span>
<span class="k">const</span> <span class="kt">const_view_t</span><span class="o">&amp;</span> <span class="n">const_view</span><span class="p">(</span><span class="k">const</span> <span class="n">Img</span><span class="o">&amp;</span><span class="p">);</span>
<span class="k">const</span> <span class="kt">view_t</span><span class="o">&amp;</span> <span class="n">view</span><span class="p">(</span><span class="n">Img</span><span class="o">&amp;</span><span class="p">);</span>
<span class="p">};</span>
</pre></div>
</div>
<p>Two-dimensional images have additional requirements:</p>
<div class="highlight-c++"><div class="highlight"><pre><span class="n">concept</span> <span class="n">RandomAccess2DImageConcept</span><span class="o">&lt;</span><span class="n">RandomAccessNDImageConcept</span> <span class="n">Img</span><span class="o">&gt;</span>
<span class="p">{</span>
<span class="k">typename</span> <span class="kt">x_coord_t</span> <span class="o">=</span> <span class="kt">const_view_t</span><span class="o">::</span><span class="kt">x_coord_t</span><span class="p">;</span>
<span class="k">typename</span> <span class="kt">y_coord_t</span> <span class="o">=</span> <span class="kt">const_view_t</span><span class="o">::</span><span class="kt">y_coord_t</span><span class="p">;</span>
<span class="n">Img</span><span class="o">::</span><span class="n">Img</span><span class="p">(</span><span class="kt">x_coord_t</span> <span class="n">width</span><span class="p">,</span> <span class="kt">y_coord_t</span> <span class="n">height</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="kt">size_t</span> <span class="n">alignment</span><span class="o">=</span><span class="mi">0</span><span class="p">);</span>
<span class="n">Img</span><span class="o">::</span><span class="n">Img</span><span class="p">(</span><span class="kt">x_coord_t</span> <span class="n">width</span><span class="p">,</span> <span class="kt">y_coord_t</span> <span class="n">height</span><span class="p">,</span> <span class="n">value_type</span> <span class="n">fill_value</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="kt">size_t</span> <span class="n">alignment</span><span class="p">);</span>
<span class="kt">x_coord_t</span> <span class="n">Img</span><span class="o">::</span><span class="n">width</span><span class="p">()</span> <span class="k">const</span><span class="p">;</span>
<span class="kt">y_coord_t</span> <span class="n">Img</span><span class="o">::</span><span class="n">height</span><span class="p">()</span> <span class="k">const</span><span class="p">;</span>
<span class="kt">void</span> <span class="n">Img</span><span class="o">::</span><span class="n">recreate</span><span class="p">(</span><span class="kt">x_coord_t</span> <span class="n">width</span><span class="p">,</span> <span class="kt">y_coord_t</span> <span class="n">height</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="kt">size_t</span> <span class="n">alignment</span><span class="o">=</span><span class="mi">1</span><span class="p">);</span>
<span class="kt">void</span> <span class="n">Img</span><span class="o">::</span><span class="n">recreate</span><span class="p">(</span><span class="kt">x_coord_t</span> <span class="n">width</span><span class="p">,</span> <span class="kt">y_coord_t</span> <span class="n">height</span><span class="p">,</span> <span class="n">value_type</span> <span class="n">fill_value</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="kt">size_t</span> <span class="n">alignment</span><span class="p">);</span>
<span class="p">};</span>
</pre></div>
</div>
<p>GIL&#8217;s images have views that model <tt class="docutils literal"><span class="pre">ImageViewConcept</span></tt> and operate on pixels.:</p>
<div class="highlight-c++"><div class="highlight"><pre><span class="n">concept</span> <span class="n">ImageConcept</span><span class="o">&lt;</span><span class="n">RandomAccess2DImageConcept</span> <span class="n">Img</span><span class="o">&gt;</span>
<span class="p">{</span>
<span class="n">where</span> <span class="n">MutableImageViewConcept</span><span class="o">&lt;</span><span class="kt">view_t</span><span class="o">&gt;</span><span class="p">;</span>
<span class="k">typename</span> <span class="kt">coord_t</span> <span class="o">=</span> <span class="kt">view_t</span><span class="o">::</span><span class="kt">coord_t</span><span class="p">;</span>
<span class="p">};</span>
</pre></div>
</div>
<p>Images, unlike locators and image views, don&#8217;t have &#8216;mutable&#8217; set of concepts because immutable images are not very useful.</p>
<p>&lt;b&gt;Related Concepts:&lt;/b&gt;</p>
<ul class="simple">
<li>RandomAccessNDImageConcept&lt;Image&gt;</li>
<li>RandomAccess2DImageConcept&lt;Image&gt;</li>
<li>ImageConcept&lt;Image&gt;</li>
</ul>
<p>&lt;b&gt;Models:&lt;/b&gt;</p>
<p>GIL provides a class, <tt class="docutils literal"><span class="pre">image</span></tt>, which is templated over the value type (the pixel) and models <tt class="docutils literal"><span class="pre">ImageConcept</span></tt>:</p>
<div class="highlight-c++"><div class="highlight"><pre>template &lt;typename Pixel, \\ Models PixelValueConcept
bool IsPlanar, \\ planar or interleaved image
typename A=std::allocator&lt;unsigned char&gt; &gt;
class image;
</pre></div>
</div>
<p>The image constructor takes an alignment parameter which allows for constructing images that are word-aligned or 8-byte aligned. The alignment is specified in
bytes. The default value for alignment is 0, which means there is no padding at the end of rows. Many operations are
faster using such 1D-traversable images, because <tt class="docutils literal"><span class="pre">image_view::x_iterator</span></tt> can be used to traverse the pixels, instead of the more complicated
<tt class="docutils literal"><span class="pre">image_view::iterator</span></tt>. Note that when alignment is 0, packed images are aligned to the bit - i.e. there are no padding bits at the end of rows of packed images.</p>
</div>
<div class="section" id="run-time-specified-images-and-image-views">
<h2><a class="toc-backref" href="#id20">Run-time specified images and image views</a></h2>
<p>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>
<p>GIL&#8217;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:</p>
<div class="highlight-c++"><div class="highlight"><pre><span class="cp">#include &lt;boost/gil/extension/dynamic_image/dynamic_image_all.hpp&gt;</span>
<span class="k">using</span> <span class="k">namespace</span> <span class="n">boost</span><span class="p">;</span>
<span class="cp">#define ASSERT_SAME(A,B) BOOST_STATIC_ASSERT((is_same&lt; A,B &gt;::value))</span>
<span class="c1">// Define the set of allowed images</span>
<span class="k">typedef</span> <span class="n">mpl</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">rgb8_image_t</span><span class="p">,</span> <span class="kt">cmyk16_planar_image_t</span><span class="o">&gt;</span> <span class="kt">my_images_t</span><span class="p">;</span>
<span class="c1">// Create any_image class (or any_image_view) class</span>
<span class="k">typedef</span> <span class="n">any_image</span><span class="o">&lt;</span><span class="kt">my_images_t</span><span class="o">&gt;</span> <span class="kt">my_any_image_t</span><span class="p">;</span>
<span class="c1">// Associated view types are available (equivalent to the ones in image_t)</span>
<span class="k">typedef</span> <span class="n">any_image_view</span><span class="o">&lt;</span><span class="n">mpl</span><span class="o">::</span><span class="n">vector2</span><span class="o">&lt;</span><span class="kt">rgb8_view_t</span><span class="p">,</span> <span class="kt">cmyk16_planar_view_t</span> <span class="o">&gt;</span> <span class="o">&gt;</span> <span class="n">AV</span><span class="p">;</span>
<span class="n">ASSERT_SAME</span><span class="p">(</span><span class="kt">my_any_image_t</span><span class="o">::</span><span class="kt">view_t</span><span class="p">,</span> <span class="n">AV</span><span class="p">);</span>
<span class="k">typedef</span> <span class="n">any_image_view</span><span class="o">&lt;</span><span class="n">mpl</span><span class="o">::</span><span class="n">vector2</span><span class="o">&lt;</span><span class="kt">rgb8c_view_t</span><span class="p">,</span> <span class="kt">cmyk16c_planar_view_t</span><span class="o">&gt;</span> <span class="o">&gt;</span> <span class="n">CAV</span><span class="p">;</span>
<span class="n">ASSERT_SAME</span><span class="p">(</span><span class="kt">my_any_image_t</span><span class="o">::</span><span class="kt">const_view_t</span><span class="p">,</span> <span class="n">CAV</span><span class="p">);</span>
<span class="n">ASSERT_SAME</span><span class="p">(</span><span class="kt">my_any_image_t</span><span class="o">::</span><span class="kt">const_view_t</span><span class="p">,</span> <span class="kt">my_any_image_t</span><span class="o">::</span><span class="kt">view_t</span><span class="o">::</span><span class="kt">const_t</span><span class="p">);</span>
<span class="k">typedef</span> <span class="n">any_image_view</span><span class="o">&lt;</span><span class="n">mpl</span><span class="o">::</span><span class="n">vector2</span><span class="o">&lt;</span><span class="kt">rgb8_step_view_t</span><span class="p">,</span> <span class="kt">cmyk16_planar_step_view_t</span><span class="o">&gt;</span> <span class="o">&gt;</span> <span class="n">SAV</span><span class="p">;</span>
<span class="n">ASSERT_SAME</span><span class="p">(</span><span class="k">typename</span> <span class="n">dynamic_x_step_type</span><span class="o">&lt;</span><span class="kt">my_any_image_t</span><span class="o">::</span><span class="kt">view_t</span><span class="o">&gt;::</span><span class="n">type</span><span class="p">,</span> <span class="n">SAV</span><span class="p">);</span>
<span class="c1">// Assign it a concrete image at run time:</span>
<span class="kt">my_any_image_t</span> <span class="n">myImg</span> <span class="o">=</span> <span class="kt">my_any_image_t</span><span class="p">(</span><span class="kt">rgb8_image_t</span><span class="p">(</span><span class="mi">100</span><span class="p">,</span><span class="mi">100</span><span class="p">));</span>
<span class="c1">// Change it to another at run time. The previous image gets destroyed</span>
<span class="n">myImg</span> <span class="o">=</span> <span class="kt">cmyk16_planar_image_t</span><span class="p">(</span><span class="mi">200</span><span class="p">,</span><span class="mi">100</span><span class="p">);</span>
<span class="c1">// Assigning to an image not in the allowed set throws an exception</span>
<span class="n">myImg</span> <span class="o">=</span> <span class="kt">gray8_image_t</span><span class="p">();</span> <span class="c1">// will throw std::bad_cast</span>
</pre></div>
</div>
<p><tt class="docutils literal"><span class="pre">any_image</span></tt> and <tt class="docutils literal"><span class="pre">any_image_view</span></tt> subclass from GIL&#8217;s <tt class="docutils literal"><span class="pre">variant</span></tt> 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>
<p>GIL&#8217;s variant is similar to <tt class="docutils literal"><span class="pre">boost::variant</span></tt> 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&#8217;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&#8217;s variant to be used easier in generic code. Synopsis:</p>
<div class="highlight-c++"><div class="highlight"><pre><span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">Types</span><span class="o">&gt;</span> <span class="c1">// models MPL Random Access Container</span>
<span class="k">class</span> <span class="nc">variant</span>
<span class="p">{</span>
<span class="p">...</span> <span class="n">_bits</span><span class="p">;</span>
<span class="n">std</span><span class="o">::</span><span class="kt">size_t</span> <span class="n">_index</span><span class="p">;</span>
<span class="nl">public:</span>
<span class="k">typedef</span> <span class="n">Types</span> <span class="kt">types_t</span><span class="p">;</span>
<span class="n">variant</span><span class="p">();</span>
<span class="n">variant</span><span class="p">(</span><span class="k">const</span> <span class="n">variant</span><span class="o">&amp;</span> <span class="n">v</span><span class="p">);</span>
<span class="k">virtual</span> <span class="o">~</span><span class="n">variant</span><span class="p">();</span>
<span class="n">variant</span><span class="o">&amp;</span> <span class="k">operator</span><span class="o">=</span><span class="p">(</span><span class="k">const</span> <span class="n">variant</span><span class="o">&amp;</span> <span class="n">v</span><span class="p">);</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">TS</span><span class="o">&gt;</span> <span class="k">friend</span> <span class="kt">bool</span> <span class="k">operator</span><span class="o">==</span><span class="p">(</span><span class="k">const</span> <span class="n">variant</span><span class="o">&lt;</span><span class="n">TS</span><span class="o">&gt;&amp;</span> <span class="n">x</span><span class="p">,</span> <span class="k">const</span> <span class="n">variant</span><span class="o">&lt;</span><span class="n">TS</span><span class="o">&gt;&amp;</span> <span class="n">y</span><span class="p">);</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">TS</span><span class="o">&gt;</span> <span class="k">friend</span> <span class="kt">bool</span> <span class="k">operator</span><span class="o">!=</span><span class="p">(</span><span class="k">const</span> <span class="n">variant</span><span class="o">&lt;</span><span class="n">TS</span><span class="o">&gt;&amp;</span> <span class="n">x</span><span class="p">,</span> <span class="k">const</span> <span class="n">variant</span><span class="o">&lt;</span><span class="n">TS</span><span class="o">&gt;&amp;</span> <span class="n">y</span><span class="p">);</span>
<span class="c1">// Construct/assign to type T. Throws std::bad_cast if T is not in Types</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">T</span><span class="o">&gt;</span> <span class="k">explicit</span> <span class="n">variant</span><span class="p">(</span><span class="k">const</span> <span class="n">T</span><span class="o">&amp;</span> <span class="n">obj</span><span class="p">);</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">T</span><span class="o">&gt;</span> <span class="n">variant</span><span class="o">&amp;</span> <span class="k">operator</span><span class="o">=</span><span class="p">(</span><span class="k">const</span> <span class="n">T</span><span class="o">&amp;</span> <span class="n">obj</span><span class="p">);</span>
<span class="c1">// Construct/assign by swapping T with its current instance. Only possible if they are swappable</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">T</span><span class="o">&gt;</span> <span class="k">explicit</span> <span class="n">variant</span><span class="p">(</span><span class="n">T</span><span class="o">&amp;</span> <span class="n">obj</span><span class="p">,</span> <span class="kt">bool</span> <span class="n">do_swap</span><span class="p">);</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">T</span><span class="o">&gt;</span> <span class="kt">void</span> <span class="n">move_in</span><span class="p">(</span><span class="n">T</span><span class="o">&amp;</span> <span class="n">obj</span><span class="p">);</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">T</span><span class="o">&gt;</span> <span class="k">static</span> <span class="kt">bool</span> <span class="n">has_type</span><span class="p">();</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">T</span><span class="o">&gt;</span> <span class="k">const</span> <span class="n">T</span><span class="o">&amp;</span> <span class="n">_dynamic_cast</span><span class="p">()</span> <span class="k">const</span><span class="p">;</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">T</span><span class="o">&gt;</span> <span class="n">T</span><span class="o">&amp;</span> <span class="n">_dynamic_cast</span><span class="p">();</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">T</span><span class="o">&gt;</span> <span class="kt">bool</span> <span class="n">current_type_is</span><span class="p">()</span> <span class="k">const</span><span class="p">;</span>
<span class="p">};</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">UOP</span><span class="p">,</span> <span class="k">typename</span> <span class="n">Types</span><span class="o">&gt;</span>
<span class="n">UOP</span><span class="o">::</span><span class="n">result_type</span> <span class="n">apply_operation</span><span class="p">(</span><span class="n">variant</span><span class="o">&lt;</span><span class="n">Types</span><span class="o">&gt;&amp;</span> <span class="n">v</span><span class="p">,</span> <span class="n">UOP</span> <span class="n">op</span><span class="p">);</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">UOP</span><span class="p">,</span> <span class="k">typename</span> <span class="n">Types</span><span class="o">&gt;</span>
<span class="n">UOP</span><span class="o">::</span><span class="n">result_type</span> <span class="n">apply_operation</span><span class="p">(</span><span class="k">const</span> <span class="n">variant</span><span class="o">&lt;</span><span class="n">Types</span><span class="o">&gt;&amp;</span> <span class="n">v</span><span class="p">,</span> <span class="n">UOP</span> <span class="n">op</span><span class="p">);</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">BOP</span><span class="p">,</span> <span class="k">typename</span> <span class="n">Types1</span><span class="p">,</span> <span class="k">typename</span> <span class="n">Types2</span><span class="o">&gt;</span>
<span class="n">BOP</span><span class="o">::</span><span class="n">result_type</span> <span class="n">apply_operation</span><span class="p">(</span> <span class="n">variant</span><span class="o">&lt;</span><span class="n">Types1</span><span class="o">&gt;&amp;</span> <span class="n">v1</span><span class="p">,</span> <span class="n">variant</span><span class="o">&lt;</span><span class="n">Types2</span><span class="o">&gt;&amp;</span> <span class="n">v2</span><span class="p">,</span> <span class="n">UOP</span> <span class="n">op</span><span class="p">);</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">BOP</span><span class="p">,</span> <span class="k">typename</span> <span class="n">Types1</span><span class="p">,</span> <span class="k">typename</span> <span class="n">Types2</span><span class="o">&gt;</span>
<span class="n">BOP</span><span class="o">::</span><span class="n">result_type</span> <span class="n">apply_operation</span><span class="p">(</span><span class="k">const</span> <span class="n">variant</span><span class="o">&lt;</span><span class="n">Types1</span><span class="o">&gt;&amp;</span> <span class="n">v1</span><span class="p">,</span> <span class="n">variant</span><span class="o">&lt;</span><span class="n">Types2</span><span class="o">&gt;&amp;</span> <span class="n">v2</span><span class="p">,</span> <span class="n">UOP</span> <span class="n">op</span><span class="p">);</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">BOP</span><span class="p">,</span> <span class="k">typename</span> <span class="n">Types1</span><span class="p">,</span> <span class="k">typename</span> <span class="n">Types2</span><span class="o">&gt;</span>
<span class="n">BOP</span><span class="o">::</span><span class="n">result_type</span> <span class="n">apply_operation</span><span class="p">(</span><span class="k">const</span> <span class="n">variant</span><span class="o">&lt;</span><span class="n">Types1</span><span class="o">&gt;&amp;</span> <span class="n">v1</span><span class="p">,</span> <span class="k">const</span> <span class="n">variant</span><span class="o">&lt;</span><span class="n">Types2</span><span class="o">&gt;&amp;</span> <span class="n">v2</span><span class="p">,</span> <span class="n">UOP</span> <span class="n">op</span><span class="p">);</span>
</pre></div>
</div>
<p>GIL&#8217;s <tt class="docutils literal"><span class="pre">any_image_view</span></tt> and <tt class="docutils literal"><span class="pre">any_image</span></tt> are subclasses of <tt class="docutils literal"><span class="pre">variant</span></tt>:</p>
<div class="highlight-c++"><div class="highlight"><pre><span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">ImageViewTypes</span><span class="o">&gt;</span>
<span class="k">class</span> <span class="nc">any_image_view</span> <span class="o">:</span> <span class="k">public</span> <span class="n">variant</span><span class="o">&lt;</span><span class="n">ImageViewTypes</span><span class="o">&gt;</span>
<span class="p">{</span>
<span class="nl">public:</span>
<span class="k">typedef</span> <span class="p">...</span> <span class="kt">const_t</span><span class="p">;</span> <span class="c1">// immutable equivalent of this</span>
<span class="k">typedef</span> <span class="n">std</span><span class="o">::</span><span class="kt">ptrdiff_t</span> <span class="kt">x_coord_t</span><span class="p">;</span>
<span class="k">typedef</span> <span class="n">std</span><span class="o">::</span><span class="kt">ptrdiff_t</span> <span class="kt">y_coord_t</span><span class="p">;</span>
<span class="k">typedef</span> <span class="n">point2</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="kt">ptrdiff_t</span><span class="o">&gt;</span> <span class="kt">point_t</span><span class="p">;</span>
<span class="n">any_image_view</span><span class="p">();</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">T</span><span class="o">&gt;</span> <span class="k">explicit</span> <span class="n">any_image_view</span><span class="p">(</span><span class="k">const</span> <span class="n">T</span><span class="o">&amp;</span> <span class="n">obj</span><span class="p">);</span>
<span class="n">any_image_view</span><span class="p">(</span><span class="k">const</span> <span class="n">any_image_view</span><span class="o">&amp;</span> <span class="n">v</span><span class="p">);</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">T</span><span class="o">&gt;</span> <span class="n">any_image_view</span><span class="o">&amp;</span> <span class="k">operator</span><span class="o">=</span><span class="p">(</span><span class="k">const</span> <span class="n">T</span><span class="o">&amp;</span> <span class="n">obj</span><span class="p">);</span>
<span class="n">any_image_view</span><span class="o">&amp;</span> <span class="k">operator</span><span class="o">=</span><span class="p">(</span><span class="k">const</span> <span class="n">any_image_view</span><span class="o">&amp;</span> <span class="n">v</span><span class="p">);</span>
<span class="c1">// parameters of the currently instantiated view</span>
<span class="n">std</span><span class="o">::</span><span class="kt">size_t</span> <span class="n">num_channels</span><span class="p">()</span> <span class="k">const</span><span class="p">;</span>
<span class="kt">point_t</span> <span class="n">dimensions</span><span class="p">()</span> <span class="k">const</span><span class="p">;</span>
<span class="kt">x_coord_t</span> <span class="n">width</span><span class="p">()</span> <span class="k">const</span><span class="p">;</span>
<span class="kt">y_coord_t</span> <span class="n">height</span><span class="p">()</span> <span class="k">const</span><span class="p">;</span>
<span class="p">};</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">ImageTypes</span><span class="o">&gt;</span>
<span class="k">class</span> <span class="nc">any_image</span> <span class="o">:</span> <span class="k">public</span> <span class="n">variant</span><span class="o">&lt;</span><span class="n">ImageTypes</span><span class="o">&gt;</span>
<span class="p">{</span>
<span class="k">typedef</span> <span class="n">variant</span><span class="o">&lt;</span><span class="n">ImageTypes</span><span class="o">&gt;</span> <span class="kt">parent_t</span><span class="p">;</span>
<span class="nl">public:</span>
<span class="k">typedef</span> <span class="p">...</span> <span class="kt">const_view_t</span><span class="p">;</span>
<span class="k">typedef</span> <span class="p">...</span> <span class="kt">view_t</span><span class="p">;</span>
<span class="k">typedef</span> <span class="n">std</span><span class="o">::</span><span class="kt">ptrdiff_t</span> <span class="kt">x_coord_t</span><span class="p">;</span>
<span class="k">typedef</span> <span class="n">std</span><span class="o">::</span><span class="kt">ptrdiff_t</span> <span class="kt">y_coord_t</span><span class="p">;</span>
<span class="k">typedef</span> <span class="n">point2</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="kt">ptrdiff_t</span><span class="o">&gt;</span> <span class="kt">point_t</span><span class="p">;</span>
<span class="n">any_image</span><span class="p">();</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">T</span><span class="o">&gt;</span> <span class="k">explicit</span> <span class="n">any_image</span><span class="p">(</span><span class="k">const</span> <span class="n">T</span><span class="o">&amp;</span> <span class="n">obj</span><span class="p">);</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">T</span><span class="o">&gt;</span> <span class="k">explicit</span> <span class="n">any_image</span><span class="p">(</span><span class="n">T</span><span class="o">&amp;</span> <span class="n">obj</span><span class="p">,</span> <span class="kt">bool</span> <span class="n">do_swap</span><span class="p">);</span>
<span class="n">any_image</span><span class="p">(</span><span class="k">const</span> <span class="n">any_image</span><span class="o">&amp;</span> <span class="n">v</span><span class="p">);</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">T</span><span class="o">&gt;</span> <span class="n">any_image</span><span class="o">&amp;</span> <span class="k">operator</span><span class="o">=</span><span class="p">(</span><span class="k">const</span> <span class="n">T</span><span class="o">&amp;</span> <span class="n">obj</span><span class="p">);</span>
<span class="n">any_image</span><span class="o">&amp;</span> <span class="k">operator</span><span class="o">=</span><span class="p">(</span><span class="k">const</span> <span class="n">any_image</span><span class="o">&amp;</span> <span class="n">v</span><span class="p">);</span>
<span class="kt">void</span> <span class="nf">recreate</span><span class="p">(</span><span class="k">const</span> <span class="kt">point_t</span><span class="o">&amp;</span> <span class="n">dims</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="n">alignment</span><span class="o">=</span><span class="mi">1</span><span class="p">);</span>
<span class="kt">void</span> <span class="nf">recreate</span><span class="p">(</span><span class="kt">x_coord_t</span> <span class="n">width</span><span class="p">,</span> <span class="kt">y_coord_t</span> <span class="n">height</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="n">alignment</span><span class="o">=</span><span class="mi">1</span><span class="p">);</span>
<span class="n">std</span><span class="o">::</span><span class="kt">size_t</span> <span class="n">num_channels</span><span class="p">()</span> <span class="k">const</span><span class="p">;</span>
<span class="kt">point_t</span> <span class="n">dimensions</span><span class="p">()</span> <span class="k">const</span><span class="p">;</span>
<span class="kt">x_coord_t</span> <span class="n">width</span><span class="p">()</span> <span class="k">const</span><span class="p">;</span>
<span class="kt">y_coord_t</span> <span class="n">height</span><span class="p">()</span> <span class="k">const</span><span class="p">;</span>
<span class="p">};</span>
</pre></div>
</div>
<p>Operations are invoked on variants via <tt class="docutils literal"><span class="pre">apply_operation</span></tt> 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>
<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 <tt class="docutils literal"><span class="pre">any_image_view</span></tt> has shallow default-constructor, copy-constructor, assignment and equality comparison, whereas <tt class="docutils literal"><span class="pre">any_image</span></tt>
has deep ones.</p>
<p>It is important to note that even though <tt class="docutils literal"><span class="pre">any_image_view</span></tt> and <tt class="docutils literal"><span class="pre">any_image</span></tt> resemble the static <tt class="docutils literal"><span class="pre">image_view</span></tt> and <tt class="docutils literal"><span class="pre">image</span></tt>, they do not model the full
requirements of <tt class="docutils literal"><span class="pre">ImageViewConcept</span></tt> and <tt class="docutils literal"><span class="pre">ImageConcept</span></tt>. In particular they don&#8217;t provide access to the pixels. There is no &#8220;any_pixel&#8221; or
&#8220;any_pixel_iterator&#8221; in GIL. Such constructs could be provided via the <tt class="docutils literal"><span class="pre">variant</span></tt> 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 <tt class="docutils literal"><span class="pre">apply_operation</span></tt>. 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 <tt class="docutils literal"><span class="pre">any_image_view</span></tt>, as illustrated with <tt class="docutils literal"><span class="pre">copy_pixels</span></tt>:</p>
<div class="highlight-c++"><div class="highlight"><pre><span class="kt">rgb8_view_t</span> <span class="nf">v1</span><span class="p">(...);</span> <span class="c1">// concrete image view</span>
<span class="kt">bgr8_view_t</span> <span class="nf">v2</span><span class="p">(...);</span> <span class="c1">// concrete image view compatible with v1 and of the same size</span>
<span class="n">any_image_view</span><span class="o">&lt;</span><span class="n">Types</span><span class="o">&gt;</span> <span class="n">av</span><span class="p">(...);</span> <span class="c1">// run-time specified image view</span>
<span class="c1">// Copies the pixels from v1 into v2.</span>
<span class="c1">// If the pixels are incompatible triggers compile error</span>
<span class="n">copy_pixels</span><span class="p">(</span><span class="n">v1</span><span class="p">,</span><span class="n">v2</span><span class="p">);</span>
<span class="c1">// The source or destination (or both) may be run-time instantiated.</span>
<span class="c1">// If they happen to be incompatible, throws std::bad_cast</span>
<span class="n">copy_pixels</span><span class="p">(</span><span class="n">v1</span><span class="p">,</span> <span class="n">av</span><span class="p">);</span>
<span class="n">copy_pixels</span><span class="p">(</span><span class="n">av</span><span class="p">,</span> <span class="n">v2</span><span class="p">);</span>
<span class="n">copy_pixels</span><span class="p">(</span><span class="n">av</span><span class="p">,</span> <span class="n">av</span><span class="p">);</span>
</pre></div>
</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="highlight-c++"><div class="highlight"><pre><span class="cp">#include &lt;boost\gil\extension\io\jpeg_dynamic_io.hpp&gt;</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">Image</span><span class="o">&gt;</span> <span class="c1">// Could be rgb8_image_t or any_image&lt;...&gt;</span>
<span class="kt">void</span> <span class="n">save_180rot</span><span class="p">(</span><span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="o">&amp;</span> <span class="n">file_name</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">Image</span> <span class="n">img</span><span class="p">;</span>
<span class="n">jpeg_read_image</span><span class="p">(</span><span class="n">file_name</span><span class="p">,</span> <span class="n">img</span><span class="p">);</span>
<span class="n">jpeg_write_view</span><span class="p">(</span><span class="n">file_name</span><span class="p">,</span> <span class="n">rotated180_view</span><span class="p">(</span><span class="n">view</span><span class="p">(</span><span class="n">img</span><span class="p">)));</span>
<span class="p">}</span>
</pre></div>
</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 <tt class="docutils literal"><span class="pre">rotated180_view</span></tt> is implemented:</p>
<div class="highlight-c++"><div class="highlight"><pre><span class="c1">// implementation using templated view</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">View</span><span class="o">&gt;</span>
<span class="k">typename</span> <span class="n">dynamic_xy_step_type</span><span class="o">&lt;</span><span class="n">View</span><span class="o">&gt;::</span><span class="n">type</span> <span class="n">rotated180_view</span><span class="p">(</span><span class="k">const</span> <span class="n">View</span><span class="o">&amp;</span> <span class="n">src</span><span class="p">)</span> <span class="p">{</span> <span class="p">...</span> <span class="p">}</span>
<span class="k">namespace</span> <span class="n">detail</span>
<span class="p">{</span>
<span class="c1">// the function, wrapped inside a function object</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">Result</span><span class="o">&gt;</span> <span class="k">struct</span> <span class="n">rotated180_view_fn</span>
<span class="p">{</span>
<span class="k">typedef</span> <span class="n">Result</span> <span class="n">result_type</span><span class="p">;</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">View</span><span class="o">&gt;</span> <span class="n">result_type</span> <span class="k">operator</span><span class="p">()(</span><span class="k">const</span> <span class="n">View</span><span class="o">&amp;</span> <span class="n">src</span><span class="p">)</span> <span class="k">const</span>
<span class="p">{</span>
<span class="k">return</span> <span class="n">result_type</span><span class="p">(</span><span class="n">rotated180_view</span><span class="p">(</span><span class="n">src</span><span class="p">));</span>
<span class="p">}</span>
<span class="p">};</span>
<span class="p">}</span>
<span class="c1">// overloading of the function using variant. Takes and returns run-time bound view.</span>
<span class="c1">// The returned view has a dynamic step</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">ViewTypes</span><span class="o">&gt;</span> <span class="kr">inline</span> <span class="c1">// Models MPL Random Access Container of models of ImageViewConcept</span>
<span class="k">typename</span> <span class="n">dynamic_xy_step_type</span><span class="o">&lt;</span><span class="n">any_image_view</span><span class="o">&lt;</span><span class="n">ViewTypes</span><span class="o">&gt;</span> <span class="o">&gt;::</span><span class="n">type</span> <span class="n">rotated180_view</span><span class="p">(</span><span class="k">const</span> <span class="n">any_image_view</span><span class="o">&lt;</span><span class="n">ViewTypes</span><span class="o">&gt;&amp;</span> <span class="n">src</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">return</span> <span class="n">apply_operation</span><span class="p">(</span><span class="n">src</span><span class="p">,</span><span class="n">detail</span><span class="o">::</span><span class="n">rotated180_view_fn</span><span class="o">&lt;</span><span class="k">typename</span> <span class="n">dynamic_xy_step_type</span><span class="o">&lt;</span><span class="n">any_image_view</span><span class="o">&lt;</span><span class="n">ViewTypes</span><span class="o">&gt;</span> <span class="o">&gt;::</span><span class="n">type</span><span class="o">&gt;</span><span class="p">());</span>
<span class="p">}</span>
</pre></div>
</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, <tt class="docutils literal"><span class="pre">variant</span></tt> 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>
</div>
<div class="section" id="useful-metafunctions-and-typedefs">
<h2><a class="toc-backref" href="#id21">Useful Metafunctions and Typedefs</a></h2>
<p>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>
<p><em>ColorSpace</em> + <em>BitDepth</em> + [&#8220;s|f&#8221;] + [&#8220;c&#8221;] + [&#8220;_planar&#8221;] + [&#8220;_step&#8221;] + <em>ClassType</em> + &#8220;_t&#8221;</p>
<p>where <em>ColorSpace</em> also indicates the ordering of components. Examples are <tt class="docutils literal"><span class="pre">rgb</span></tt>, <tt class="docutils literal"><span class="pre">bgr</span></tt>, <tt class="docutils literal"><span class="pre">cmyk</span></tt>, <tt class="docutils literal"><span class="pre">rgba</span></tt>. <em>BitDepth</em> can be,
for example, <tt class="docutils literal"><span class="pre">8</span></tt>,``16``,``32``. By default the bits are unsigned integral type. Append <tt class="docutils literal"><span class="pre">s</span></tt> to the bit depth to indicate signed
integral, or <tt class="docutils literal"><span class="pre">f</span></tt> to indicate floating point. <tt class="docutils literal"><span class="pre">c</span></tt> indicates object whose associated pixel reference is immutable. <tt class="docutils literal"><span class="pre">_planar</span></tt>
indicates planar organization (as opposed to interleaved). <tt class="docutils literal"><span class="pre">_step</span></tt> indicates the type has a dynamic step and <em>ClassType</em> is <tt class="docutils literal"><span class="pre">_image</span></tt>
(image, using a standard allocator), <tt class="docutils literal"><span class="pre">_view</span></tt> (image view), <tt class="docutils literal"><span class="pre">_loc</span></tt> (pixel locator), <tt class="docutils literal"><span class="pre">_ptr</span></tt> (pixel iterator), <tt class="docutils literal"><span class="pre">_ref</span></tt>
(pixel reference), <tt class="docutils literal"><span class="pre">_pixel</span></tt> (pixel value). Here are examples:</p>
<div class="highlight-c++"><div class="highlight"><pre><span class="kt">bgr8_image_t</span> <span class="n">i</span><span class="p">;</span> <span class="c1">// 8-bit unsigned (unsigned char) interleaved BGR image</span>
<span class="kt">cmyk16_pixel_t</span><span class="p">;</span> <span class="n">x</span><span class="p">;</span> <span class="c1">// 16-bit unsigned (unsigned short) CMYK pixel value;</span>
<span class="kt">cmyk16sc_planar_ref_t</span> <span class="nf">p</span><span class="p">(</span><span class="n">x</span><span class="p">);</span> <span class="c1">// const reference to a 16-bit signed integral (signed short) planar CMYK pixel x.</span>
<span class="kt">rgb32f_planar_step_ptr_t</span> <span class="n">ii</span><span class="p">;</span> <span class="c1">// step iterator to a floating point 32-bit (float) planar RGB pixel.</span>
</pre></div>
</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="highlight-c++"><div class="highlight"><pre><span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">ChannelValue</span><span class="p">,</span> <span class="k">typename</span> <span class="n">Layout</span><span class="p">,</span> <span class="kt">bool</span> <span class="n">IsPlanar</span><span class="o">=</span><span class="nb">false</span><span class="p">,</span> <span class="kt">bool</span> <span class="n">IsMutable</span><span class="o">=</span><span class="nb">true</span><span class="o">&gt;</span>
<span class="k">struct</span> <span class="n">pixel_reference_type</span> <span class="p">{</span> <span class="k">typedef</span> <span class="p">...</span> <span class="n">type</span><span class="p">;</span> <span class="p">};</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">Channel</span><span class="p">,</span> <span class="k">typename</span> <span class="n">Layout</span><span class="o">&gt;</span>
<span class="k">struct</span> <span class="n">pixel_value_type</span> <span class="p">{</span> <span class="k">typedef</span> <span class="p">...</span> <span class="n">type</span><span class="p">;</span> <span class="p">};</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">ChannelValue</span><span class="p">,</span> <span class="k">typename</span> <span class="n">Layout</span><span class="p">,</span> <span class="kt">bool</span> <span class="n">IsPlanar</span><span class="o">=</span><span class="nb">false</span><span class="p">,</span> <span class="kt">bool</span> <span class="n">IsStep</span><span class="o">=</span><span class="nb">false</span><span class="p">,</span> <span class="kt">bool</span> <span class="n">IsMutable</span><span class="o">=</span><span class="nb">true</span><span class="o">&gt;</span>
<span class="k">struct</span> <span class="n">iterator_type</span> <span class="p">{</span> <span class="k">typedef</span> <span class="p">...</span> <span class="n">type</span><span class="p">;</span> <span class="p">};</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">ChannelValue</span><span class="p">,</span> <span class="k">typename</span> <span class="n">Layout</span><span class="p">,</span> <span class="kt">bool</span> <span class="n">IsPlanar</span><span class="o">=</span><span class="nb">false</span><span class="p">,</span> <span class="kt">bool</span> <span class="n">IsXStep</span><span class="o">=</span><span class="nb">false</span><span class="p">,</span> <span class="kt">bool</span> <span class="n">IsMutable</span><span class="o">=</span><span class="nb">true</span><span class="o">&gt;</span>
<span class="k">struct</span> <span class="n">locator_type</span> <span class="p">{</span> <span class="k">typedef</span> <span class="p">...</span> <span class="n">type</span><span class="p">;</span> <span class="p">};</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">ChannelValue</span><span class="p">,</span> <span class="k">typename</span> <span class="n">Layout</span><span class="p">,</span> <span class="kt">bool</span> <span class="n">IsPlanar</span><span class="o">=</span><span class="nb">false</span><span class="p">,</span> <span class="kt">bool</span> <span class="n">IsXStep</span><span class="o">=</span><span class="nb">false</span><span class="p">,</span> <span class="kt">bool</span> <span class="n">IsMutable</span><span class="o">=</span><span class="nb">true</span><span class="o">&gt;</span>
<span class="k">struct</span> <span class="n">view_type</span> <span class="p">{</span> <span class="k">typedef</span> <span class="p">...</span> <span class="n">type</span><span class="p">;</span> <span class="p">};</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">ChannelValue</span><span class="p">,</span> <span class="k">typename</span> <span class="n">Layout</span><span class="p">,</span> <span class="kt">bool</span> <span class="n">IsPlanar</span><span class="o">=</span><span class="nb">false</span><span class="p">,</span> <span class="k">typename</span> <span class="n">Alloc</span><span class="o">=</span><span class="n">std</span><span class="o">::</span><span class="n">allocator</span><span class="o">&lt;</span><span class="kt">unsigned</span> <span class="kt">char</span><span class="o">&gt;</span> <span class="o">&gt;</span>
<span class="k">struct</span> <span class="n">image_type</span> <span class="p">{</span> <span class="k">typedef</span> <span class="p">...</span> <span class="n">type</span><span class="p">;</span> <span class="p">};</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">BitField</span><span class="p">,</span> <span class="k">typename</span> <span class="n">ChannelBitSizeVector</span><span class="p">,</span> <span class="k">typename</span> <span class="n">Layout</span><span class="p">,</span> <span class="k">typename</span> <span class="n">Alloc</span><span class="o">=</span><span class="n">std</span><span class="o">::</span><span class="n">allocator</span><span class="o">&lt;</span><span class="kt">unsigned</span> <span class="kt">char</span><span class="o">&gt;</span> <span class="o">&gt;</span>
<span class="k">struct</span> <span class="n">packed_image_type</span> <span class="p">{</span> <span class="k">typedef</span> <span class="p">...</span> <span class="n">type</span><span class="p">;</span> <span class="p">};</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">ChannelBitSizeVector</span><span class="p">,</span> <span class="k">typename</span> <span class="n">Layout</span><span class="p">,</span> <span class="k">typename</span> <span class="n">Alloc</span><span class="o">=</span><span class="n">std</span><span class="o">::</span><span class="n">allocator</span><span class="o">&lt;</span><span class="kt">unsigned</span> <span class="kt">char</span><span class="o">&gt;</span> <span class="o">&gt;</span>
<span class="k">struct</span> <span class="n">bit_aligned_image_type</span> <span class="p">{</span> <span class="k">typedef</span> <span class="p">...</span> <span class="n">type</span><span class="p">;</span> <span class="p">};</span>
</pre></div>
</div>
<p>There are also helper metafunctions to construct packed and bit-aligned images with up to five channels:</p>
<div class="highlight-c++"><div class="highlight"><pre><span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">BitField</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="n">Size1</span><span class="p">,</span>
<span class="k">typename</span> <span class="n">Layout</span><span class="p">,</span> <span class="k">typename</span> <span class="n">Alloc</span><span class="o">=</span><span class="n">std</span><span class="o">::</span><span class="n">allocator</span><span class="o">&lt;</span><span class="kt">unsigned</span> <span class="kt">char</span><span class="o">&gt;</span> <span class="o">&gt;</span>
<span class="k">struct</span> <span class="n">packed_image1_type</span> <span class="p">{</span> <span class="k">typedef</span> <span class="p">...</span> <span class="n">type</span><span class="p">;</span> <span class="p">};</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">BitField</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="n">Size1</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="n">Size2</span><span class="p">,</span>
<span class="k">typename</span> <span class="n">Layout</span><span class="p">,</span> <span class="k">typename</span> <span class="n">Alloc</span><span class="o">=</span><span class="n">std</span><span class="o">::</span><span class="n">allocator</span><span class="o">&lt;</span><span class="kt">unsigned</span> <span class="kt">char</span><span class="o">&gt;</span> <span class="o">&gt;</span>
<span class="k">struct</span> <span class="n">packed_image2_type</span> <span class="p">{</span> <span class="k">typedef</span> <span class="p">...</span> <span class="n">type</span><span class="p">;</span> <span class="p">};</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">BitField</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="n">Size1</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="n">Size2</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="n">Size3</span><span class="p">,</span>
<span class="k">typename</span> <span class="n">Layout</span><span class="p">,</span> <span class="k">typename</span> <span class="n">Alloc</span><span class="o">=</span><span class="n">std</span><span class="o">::</span><span class="n">allocator</span><span class="o">&lt;</span><span class="kt">unsigned</span> <span class="kt">char</span><span class="o">&gt;</span> <span class="o">&gt;</span>
<span class="k">struct</span> <span class="n">packed_image3_type</span> <span class="p">{</span> <span class="k">typedef</span> <span class="p">...</span> <span class="n">type</span><span class="p">;</span> <span class="p">};</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">BitField</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="n">Size1</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="n">Size2</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="n">Size3</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="n">Size4</span><span class="p">,</span>
<span class="k">typename</span> <span class="n">Layout</span><span class="p">,</span> <span class="k">typename</span> <span class="n">Alloc</span><span class="o">=</span><span class="n">std</span><span class="o">::</span><span class="n">allocator</span><span class="o">&lt;</span><span class="kt">unsigned</span> <span class="kt">char</span><span class="o">&gt;</span> <span class="o">&gt;</span>
<span class="k">struct</span> <span class="n">packed_image4_type</span> <span class="p">{</span> <span class="k">typedef</span> <span class="p">...</span> <span class="n">type</span><span class="p">;</span> <span class="p">};</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">BitField</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="n">Size1</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="n">Size2</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="n">Size3</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="n">Size4</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="n">Size5</span><span class="p">,</span>
<span class="k">typename</span> <span class="n">Layout</span><span class="p">,</span> <span class="k">typename</span> <span class="n">Alloc</span><span class="o">=</span><span class="n">std</span><span class="o">::</span><span class="n">allocator</span><span class="o">&lt;</span><span class="kt">unsigned</span> <span class="kt">char</span><span class="o">&gt;</span> <span class="o">&gt;</span>
<span class="k">struct</span> <span class="n">packed_image5_type</span> <span class="p">{</span> <span class="k">typedef</span> <span class="p">...</span> <span class="n">type</span><span class="p">;</span> <span class="p">};</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="kt">unsigned</span> <span class="n">Size1</span><span class="p">,</span>
<span class="k">typename</span> <span class="n">Layout</span><span class="p">,</span> <span class="k">typename</span> <span class="n">Alloc</span><span class="o">=</span><span class="n">std</span><span class="o">::</span><span class="n">allocator</span><span class="o">&lt;</span><span class="kt">unsigned</span> <span class="kt">char</span><span class="o">&gt;</span> <span class="o">&gt;</span>
<span class="k">struct</span> <span class="n">bit_aligned_image1_type</span> <span class="p">{</span> <span class="k">typedef</span> <span class="p">...</span> <span class="n">type</span><span class="p">;</span> <span class="p">};</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="kt">unsigned</span> <span class="n">Size1</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="n">Size2</span><span class="p">,</span>
<span class="k">typename</span> <span class="n">Layout</span><span class="p">,</span> <span class="k">typename</span> <span class="n">Alloc</span><span class="o">=</span><span class="n">std</span><span class="o">::</span><span class="n">allocator</span><span class="o">&lt;</span><span class="kt">unsigned</span> <span class="kt">char</span><span class="o">&gt;</span> <span class="o">&gt;</span>
<span class="k">struct</span> <span class="n">bit_aligned_image2_type</span> <span class="p">{</span> <span class="k">typedef</span> <span class="p">...</span> <span class="n">type</span><span class="p">;</span> <span class="p">};</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="kt">unsigned</span> <span class="n">Size1</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="n">Size2</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="n">Size3</span><span class="p">,</span>
<span class="k">typename</span> <span class="n">Layout</span><span class="p">,</span> <span class="k">typename</span> <span class="n">Alloc</span><span class="o">=</span><span class="n">std</span><span class="o">::</span><span class="n">allocator</span><span class="o">&lt;</span><span class="kt">unsigned</span> <span class="kt">char</span><span class="o">&gt;</span> <span class="o">&gt;</span>
<span class="k">struct</span> <span class="n">bit_aligned_image3_type</span> <span class="p">{</span> <span class="k">typedef</span> <span class="p">...</span> <span class="n">type</span><span class="p">;</span> <span class="p">};</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="kt">unsigned</span> <span class="n">Size1</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="n">Size2</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="n">Size3</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="n">Size4</span><span class="p">,</span>
<span class="k">typename</span> <span class="n">Layout</span><span class="p">,</span> <span class="k">typename</span> <span class="n">Alloc</span><span class="o">=</span><span class="n">std</span><span class="o">::</span><span class="n">allocator</span><span class="o">&lt;</span><span class="kt">unsigned</span> <span class="kt">char</span><span class="o">&gt;</span> <span class="o">&gt;</span>
<span class="k">struct</span> <span class="n">bit_aligned_image4_type</span> <span class="p">{</span> <span class="k">typedef</span> <span class="p">...</span> <span class="n">type</span><span class="p">;</span> <span class="p">};</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="kt">unsigned</span> <span class="n">Size1</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="n">Size2</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="n">Size3</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="n">Size4</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="n">Size5</span><span class="p">,</span>
<span class="k">typename</span> <span class="n">Layout</span><span class="p">,</span> <span class="k">typename</span> <span class="n">Alloc</span><span class="o">=</span><span class="n">std</span><span class="o">::</span><span class="n">allocator</span><span class="o">&lt;</span><span class="kt">unsigned</span> <span class="kt">char</span><span class="o">&gt;</span> <span class="o">&gt;</span>
<span class="k">struct</span> <span class="n">bit_aligned_image5_type</span> <span class="p">{</span> <span class="k">typedef</span> <span class="p">...</span> <span class="n">type</span><span class="p">;</span> <span class="p">};</span>
</pre></div>
</div>
<p>Here <tt class="docutils literal"><span class="pre">ChannelValue</span></tt> models <tt class="docutils literal"><span class="pre">ChannelValueConcept</span></tt>. We don&#8217;t need <tt class="docutils literal"><span class="pre">IsYStep</span></tt> because GIL&#8217;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="highlight-c++"><div class="highlight"><pre><span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">Pixel</span><span class="p">,</span> <span class="kt">bool</span> <span class="n">IsPlanar</span><span class="o">=</span><span class="nb">false</span><span class="p">,</span> <span class="kt">bool</span> <span class="n">IsStep</span><span class="o">=</span><span class="nb">false</span><span class="p">,</span> <span class="kt">bool</span> <span class="n">IsMutable</span><span class="o">=</span><span class="nb">true</span><span class="o">&gt;</span>
<span class="k">struct</span> <span class="n">iterator_type_from_pixel</span> <span class="p">{</span> <span class="k">typedef</span> <span class="p">...</span> <span class="n">type</span><span class="p">;</span> <span class="p">};</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">Pixel</span><span class="p">,</span> <span class="kt">bool</span> <span class="n">IsPlanar</span><span class="o">=</span><span class="nb">false</span><span class="p">,</span> <span class="kt">bool</span> <span class="n">IsStepX</span><span class="o">=</span><span class="nb">false</span><span class="p">,</span> <span class="kt">bool</span> <span class="n">IsMutable</span><span class="o">=</span><span class="nb">true</span><span class="o">&gt;</span>
<span class="k">struct</span> <span class="n">view_type_from_pixel</span> <span class="p">{</span> <span class="k">typedef</span> <span class="p">...</span> <span class="n">type</span><span class="p">;</span> <span class="p">};</span>
</pre></div>
</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="highlight-c++"><div class="highlight"><pre><span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">XIterator</span><span class="o">&gt;</span>
<span class="k">struct</span> <span class="n">type_from_x_iterator</span>
<span class="p">{</span>
<span class="k">typedef</span> <span class="p">...</span> <span class="kt">step_iterator_t</span><span class="p">;</span>
<span class="k">typedef</span> <span class="p">...</span> <span class="kt">xy_locator_t</span><span class="p">;</span>
<span class="k">typedef</span> <span class="p">...</span> <span class="kt">view_t</span><span class="p">;</span>
<span class="p">};</span>
</pre></div>
</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="highlight-c++"><div class="highlight"><pre><span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">PixelReference</span><span class="p">,</span>
<span class="k">typename</span> <span class="n">ChannelValue</span><span class="p">,</span> <span class="k">typename</span> <span class="n">Layout</span><span class="p">,</span> <span class="k">typename</span> <span class="n">IsPlanar</span><span class="p">,</span> <span class="k">typename</span> <span class="n">IsMutable</span><span class="o">&gt;</span>
<span class="k">struct</span> <span class="n">derived_pixel_reference_type</span>
<span class="p">{</span>
<span class="k">typedef</span> <span class="p">...</span> <span class="n">type</span><span class="p">;</span> <span class="c1">// Models PixelConcept</span>
<span class="p">};</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">Iterator</span><span class="p">,</span>
<span class="k">typename</span> <span class="n">ChannelValue</span><span class="p">,</span> <span class="k">typename</span> <span class="n">Layout</span><span class="p">,</span> <span class="k">typename</span> <span class="n">IsPlanar</span><span class="p">,</span> <span class="k">typename</span> <span class="n">IsStep</span><span class="p">,</span> <span class="k">typename</span> <span class="n">IsMutable</span><span class="o">&gt;</span>
<span class="k">struct</span> <span class="n">derived_iterator_type</span>
<span class="p">{</span>
<span class="k">typedef</span> <span class="p">...</span> <span class="n">type</span><span class="p">;</span> <span class="c1">// Models PixelIteratorConcept</span>
<span class="p">};</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">View</span><span class="p">,</span>
<span class="k">typename</span> <span class="n">ChannelValue</span><span class="p">,</span> <span class="k">typename</span> <span class="n">Layout</span><span class="p">,</span> <span class="k">typename</span> <span class="n">IsPlanar</span><span class="p">,</span> <span class="k">typename</span> <span class="n">IsXStep</span><span class="p">,</span> <span class="k">typename</span> <span class="n">IsMutable</span><span class="o">&gt;</span>
<span class="k">struct</span> <span class="n">derived_view_type</span>
<span class="p">{</span>
<span class="k">typedef</span> <span class="p">...</span> <span class="n">type</span><span class="p">;</span> <span class="c1">// Models ImageViewConcept</span>
<span class="p">};</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">Image</span><span class="p">,</span>
<span class="k">typename</span> <span class="n">ChannelValue</span><span class="p">,</span> <span class="k">typename</span> <span class="n">Layout</span><span class="p">,</span> <span class="k">typename</span> <span class="n">IsPlanar</span><span class="o">&gt;</span>
<span class="k">struct</span> <span class="n">derived_image_type</span>
<span class="p">{</span>
<span class="k">typedef</span> <span class="p">...</span> <span class="n">type</span><span class="p">;</span> <span class="c1">// Models ImageConcept</span>
<span class="p">};</span>
</pre></div>
</div>
<p>You can replace one or more of its properties and use <tt class="docutils literal"><span class="pre">boost::use_default</span></tt> for the rest. In this case <tt class="docutils literal"><span class="pre">IsPlanar</span></tt>, <tt class="docutils literal"><span class="pre">IsStep</span></tt> and <tt class="docutils literal"><span class="pre">IsMutable</span></tt>
are MPL boolean constants. For example, here is how to create the type of a view just like <tt class="docutils literal"><span class="pre">View</span></tt>, but being grayscale and planar:</p>
<div class="highlight-c++"><div class="highlight"><pre><span class="k">typedef</span> <span class="k">typename</span> <span class="n">derived_view_type</span><span class="o">&lt;</span><span class="n">View</span><span class="p">,</span> <span class="n">boost</span><span class="o">::</span><span class="n">use_default</span><span class="p">,</span> <span class="kt">gray_t</span><span class="p">,</span> <span class="n">mpl</span><span class="o">::</span><span class="n">true_</span><span class="o">&gt;::</span><span class="n">type</span> <span class="n">VT</span><span class="p">;</span>
</pre></div>
</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="highlight-c++"><div class="highlight"><pre><span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">T</span><span class="o">&gt;</span> <span class="k">struct</span> <span class="n">color_space_type</span> <span class="p">{</span> <span class="k">typedef</span> <span class="p">...</span> <span class="n">type</span><span class="p">;</span> <span class="p">};</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">T</span><span class="o">&gt;</span> <span class="k">struct</span> <span class="n">channel_mapping_type</span> <span class="p">{</span> <span class="k">typedef</span> <span class="p">...</span> <span class="n">type</span><span class="p">;</span> <span class="p">};</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">T</span><span class="o">&gt;</span> <span class="k">struct</span> <span class="n">is_planar</span> <span class="p">{</span> <span class="k">typedef</span> <span class="p">...</span> <span class="n">type</span><span class="p">;</span> <span class="p">};</span>
<span class="c1">// Defined by homogeneous constructs</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">T</span><span class="o">&gt;</span> <span class="k">struct</span> <span class="n">channel_type</span> <span class="p">{</span> <span class="k">typedef</span> <span class="p">...</span> <span class="n">type</span><span class="p">;</span> <span class="p">};</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">T</span><span class="o">&gt;</span> <span class="k">struct</span> <span class="n">num_channels</span> <span class="p">{</span> <span class="k">typedef</span> <span class="p">...</span> <span class="n">type</span><span class="p">;</span> <span class="p">};</span>
</pre></div>
</div>
<p>These are metafunctions, some of which return integral types which can be evaluated like this:</p>
<div class="highlight-c++"><div class="highlight"><pre><span class="n">BOOST_STATIC_ASSERT</span><span class="p">(</span><span class="n">is_planar</span><span class="o">&lt;</span><span class="kt">rgb8_planar_view_t</span><span class="o">&gt;::</span><span class="n">value</span> <span class="o">==</span> <span class="nb">true</span><span class="p">);</span>
</pre></div>
</div>
<p>GIL also supports type analysis metafunctions of the form:
[pixel_reference/iterator/locator/view/image] + p &#8220;_is_&#8221; + [basic/mutable/step]. For example:</p>
<div class="highlight-c++"><div class="highlight"><pre><span class="k">if</span> <span class="p">(</span><span class="n">view_is_mutable</span><span class="o">&lt;</span><span class="n">View</span><span class="o">&gt;::</span><span class="n">value</span><span class="p">)</span>
<span class="p">{</span>
<span class="p">...</span>
<span class="p">}</span>
</pre></div>
</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>
</div>
<div class="section" id="i-o-extension">
<h2><a class="toc-backref" href="#id22">I/O Extension</a></h2>
<p>GIL&#8217;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>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">JPEG:</th><td class="field-body">To use JPEG files, include the file &lt;tt&gt;gil/extension/io/jpeg_io.hpp&lt;/tt&gt;. If you are using run-time images,
you need to include &lt;tt&gt;gil/extension/io/jpeg_dynamic_io.hpp&lt;/tt&gt; instead. You need to compile and link against libjpeg.lib
(available at <a class="reference external" href="http://www.ijg.org">http://www.ijg.org</a>). You need to have &lt;tt&gt;jpeglib.h&lt;/tt&gt; in your include path.</td>
</tr>
<tr class="field-even field"><th class="field-name">TIFF:</th><td class="field-body">To use TIFF files, include the file &lt;tt&gt;gil/extension/io/tiff_io.hpp&lt;/tt&gt;. If you are using run-time images,
you need to include &lt;tt&gt;gil/extension/io/tiff_dynamic_io.hpp&lt;/tt&gt; instead. You need to compile and link against libtiff.lib
(available at <a class="reference external" href="http://www.libtiff.org">http://www.libtiff.org</a>). You need to have &lt;tt&gt;tiffio.h&lt;/tt&gt; in your include path.</td>
</tr>
<tr class="field-odd field"><th class="field-name">PNG:</th><td class="field-body">To use PNG files, include the file &lt;tt&gt;gil/extension/io/png_io.hpp&lt;/tt&gt;. If you are using run-time images,
you need to include &lt;tt&gt;gil/extension/io/png_dynamic_io.hpp&lt;/tt&gt; instead. You need to compile and link against libpng.lib
(available at <a class="reference external" href="http://wwwlibpng.org">http://wwwlibpng.org</a>). You need to have &lt;tt&gt;png.h&lt;/tt&gt; in your include path.</td>
</tr>
</tbody>
</table>
<p>You don&#8217;t need to install all these libraries; just the ones you will use.
Here are the I/O APIs for JPEG files (replace &#8220;jpeg&#8221; with &#8220;tiff&#8221; or &#8220;png&#8221; for the APIs of the other libraries):</p>
<div class="highlight-c++"><div class="highlight"><pre><span class="c1">// Returns the width and height of the JPEG file at the specified location.</span>
<span class="c1">// Throws std::ios_base::failure if the location does not correspond to a valid JPEG file</span>
<span class="n">point2</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="kt">ptrdiff_t</span><span class="o">&gt;</span> <span class="n">jpeg_read_dimensions</span><span class="p">(</span><span class="k">const</span> <span class="kt">char</span><span class="o">*</span><span class="p">);</span>
<span class="c1">// Allocates a new image whose dimensions are determined by the given jpeg image file, and loads the pixels into it.</span>
<span class="c1">// 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="c1">// 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="c1">// compatible with the ones specified by Image</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">Img</span><span class="o">&gt;</span> <span class="kt">void</span> <span class="n">jpeg_read_image</span><span class="p">(</span><span class="k">const</span> <span class="kt">char</span><span class="o">*</span><span class="p">,</span> <span class="n">Img</span><span class="o">&amp;</span><span class="p">);</span>
<span class="c1">// Allocates a new image whose dimensions are determined by the given jpeg image file, and loads the pixels into it,</span>
<span class="c1">// color-converting and channel-converting if necessary.</span>
<span class="c1">// 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="c1">// Throws std::ios_base::failure if the file is not a valid JPEG file or if it fails to read it.</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">Img</span><span class="o">&gt;</span> <span class="kt">void</span> <span class="n">jpeg_read_and_convert_image</span><span class="p">(</span><span class="k">const</span> <span class="kt">char</span><span class="o">*</span><span class="p">,</span> <span class="n">Img</span><span class="o">&amp;</span><span class="p">);</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">Img</span><span class="p">,</span> <span class="k">typename</span> <span class="n">CCV</span><span class="o">&gt;</span> <span class="kt">void</span> <span class="n">jpeg_read_and_convert_image</span><span class="p">(</span><span class="k">const</span> <span class="kt">char</span><span class="o">*</span><span class="p">,</span> <span class="n">Img</span><span class="o">&amp;</span><span class="p">,</span> <span class="n">CCV</span> <span class="n">color_converter</span><span class="p">);</span>
<span class="c1">// Loads the image specified by the given jpeg image file name into the given view.</span>
<span class="c1">// 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="c1">// 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="c1">// compatible with the ones specified by View, or if its dimensions don&#39;t match the ones of the view.</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">View</span><span class="o">&gt;</span> <span class="kt">void</span> <span class="n">jpeg_read_view</span><span class="p">(</span><span class="k">const</span> <span class="kt">char</span><span class="o">*</span><span class="p">,</span> <span class="k">const</span> <span class="n">View</span><span class="o">&amp;</span><span class="p">);</span>
<span class="c1">// 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="c1">// 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="c1">// Throws std::ios_base::failure if the file is not a valid JPEG file, or if its dimensions don&#39;t match the ones of the view.</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">View</span><span class="o">&gt;</span> <span class="kt">void</span> <span class="n">jpeg_read_and_convert_view</span><span class="p">(</span><span class="k">const</span> <span class="kt">char</span><span class="o">*</span><span class="p">,</span> <span class="k">const</span> <span class="n">View</span><span class="o">&amp;</span><span class="p">);</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">View</span><span class="p">,</span> <span class="k">typename</span> <span class="n">CCV</span><span class="o">&gt;</span> <span class="kt">void</span> <span class="n">jpeg_read_and_convert_view</span><span class="p">(</span><span class="k">const</span> <span class="kt">char</span><span class="o">*</span><span class="p">,</span> <span class="k">const</span> <span class="n">View</span><span class="o">&amp;</span><span class="p">,</span> <span class="n">CCV</span> <span class="n">color_converter</span><span class="p">);</span>
<span class="c1">// Saves the view to a jpeg file specified by the given jpeg image file name.</span>
<span class="c1">// 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="c1">// Throws std::ios_base::failure if it fails to create the file.</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">View</span><span class="o">&gt;</span> <span class="kt">void</span> <span class="n">jpeg_write_view</span><span class="p">(</span><span class="k">const</span> <span class="kt">char</span><span class="o">*</span><span class="p">,</span> <span class="k">const</span> <span class="n">View</span><span class="o">&amp;</span><span class="p">);</span>
<span class="c1">// Determines whether the given view type is supported for reading</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">View</span><span class="o">&gt;</span> <span class="k">struct</span> <span class="n">jpeg_read_support</span>
<span class="p">{</span>
<span class="k">static</span> <span class="k">const</span> <span class="kt">bool</span> <span class="n">value</span> <span class="o">=</span> <span class="p">...;</span>
<span class="p">};</span>
<span class="c1">// Determines whether the given view type is supported for writing</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">View</span><span class="o">&gt;</span> <span class="k">struct</span> <span class="n">jpeg_write_support</span>
<span class="p">{</span>
<span class="k">static</span> <span class="k">const</span> <span class="kt">bool</span> <span class="n">value</span> <span class="o">=</span> <span class="p">...;</span>
<span class="p">};</span>
</pre></div>
</div>
<p>If you use the dynamic image extension, make sure to include <tt class="docutils literal"><span class="pre">&quot;jpeg_dynamic_io.hpp&quot;</span></tt> instead of <tt class="docutils literal"><span class="pre">&quot;jpeg_io.hpp&quot;</span></tt>.
In addition to the above methods, you have the following overloads dealing with dynamic images:</p>
<div class="highlight-c++"><div class="highlight"><pre><span class="c1">// 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="c1">// and creates a new image of that type with the dimensions specified by the image file.</span>
<span class="c1">// Throws std::ios_base::failure if none of the types in Images are compatible with the type on disk.</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">Images</span><span class="o">&gt;</span> <span class="kt">void</span> <span class="n">jpeg_read_image</span><span class="p">(</span><span class="k">const</span> <span class="kt">char</span><span class="o">*</span><span class="p">,</span> <span class="n">any_image</span><span class="o">&lt;</span><span class="n">Images</span><span class="o">&gt;&amp;</span><span class="p">);</span>
<span class="c1">// Saves the currently instantiated view to a jpeg file specified by the given jpeg image file name.</span>
<span class="c1">// Throws std::ios_base::failure if the currently instantiated view type is not supported for writing by the I/O extension</span>
<span class="c1">// or if it fails to create the file.</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">Views</span><span class="o">&gt;</span> <span class="kt">void</span> <span class="n">jpeg_write_view</span><span class="p">(</span><span class="k">const</span> <span class="kt">char</span><span class="o">*</span><span class="p">,</span> <span class="n">any_image_view</span><span class="o">&lt;</span><span class="n">Views</span><span class="o">&gt;&amp;</span><span class="p">);</span>
</pre></div>
</div>
<p>All of the above methods have overloads taking <tt class="docutils literal"><span class="pre">std::string</span></tt> instead of <tt class="docutils literal"><span class="pre">const</span> <span class="pre">char*</span></tt></p>
</div>
<div class="section" id="sample-code">
<h2><a class="toc-backref" href="#id23">Sample Code</a></h2>
<div class="section" id="pixel-level-sample-code">
<h3><a class="toc-backref" href="#id24">Pixel-level Sample Code</a></h3>
<p>Here are some operations you can do with pixel values, pointers and references:</p>
<div class="highlight-c++"><div class="highlight"><pre><span class="kt">rgb8_pixel_t</span> <span class="nf">p1</span><span class="p">(</span><span class="mi">255</span><span class="p">,</span><span class="mi">0</span><span class="p">,</span><span class="mi">0</span><span class="p">);</span> <span class="c1">// make a red RGB pixel</span>
<span class="kt">bgr8_pixel_t</span> <span class="n">p2</span> <span class="o">=</span> <span class="n">p1</span><span class="p">;</span> <span class="c1">// RGB and BGR are compatible and the channels will be properly mapped.</span>
<span class="n">assert</span><span class="p">(</span><span class="n">p1</span><span class="o">==</span><span class="n">p2</span><span class="p">);</span> <span class="c1">// p2 will also be red.</span>
<span class="n">assert</span><span class="p">(</span><span class="n">p2</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">!=</span><span class="n">p1</span><span class="p">[</span><span class="mi">0</span><span class="p">]);</span> <span class="c1">// operator[] gives physical channel order (as laid down in memory)</span>
<span class="n">assert</span><span class="p">(</span><span class="n">semantic_at_c</span><span class="o">&lt;</span><span class="mi">0</span><span class="o">&gt;</span><span class="p">(</span><span class="n">p1</span><span class="p">)</span><span class="o">==</span><span class="n">semantic_at_c</span><span class="o">&lt;</span><span class="mi">0</span><span class="o">&gt;</span><span class="p">(</span><span class="n">p2</span><span class="p">));</span> <span class="c1">// this is how to compare the two red channels</span>
<span class="n">get_color</span><span class="p">(</span><span class="n">p1</span><span class="p">,</span><span class="kt">green_t</span><span class="p">())</span> <span class="o">=</span> <span class="n">get_color</span><span class="p">(</span><span class="n">p2</span><span class="p">,</span><span class="kt">blue_t</span><span class="p">());</span> <span class="c1">// channels can also be accessed by name</span>
<span class="k">const</span> <span class="kt">unsigned</span> <span class="kt">char</span><span class="o">*</span> <span class="n">r</span><span class="p">;</span>
<span class="k">const</span> <span class="kt">unsigned</span> <span class="kt">char</span><span class="o">*</span> <span class="n">g</span><span class="p">;</span>
<span class="k">const</span> <span class="kt">unsigned</span> <span class="kt">char</span><span class="o">*</span> <span class="n">b</span><span class="p">;</span>
<span class="kt">rgb8c_planar_ptr_t</span> <span class="nf">ptr</span><span class="p">(</span><span class="n">r</span><span class="p">,</span><span class="n">g</span><span class="p">,</span><span class="n">b</span><span class="p">);</span> <span class="c1">// constructing const planar pointer from const pointers to each plane</span>
<span class="kt">rgb8c_planar_ref_t</span> <span class="n">ref</span><span class="o">=*</span><span class="n">ptr</span><span class="p">;</span> <span class="c1">// just like built-in reference, dereferencing a planar pointer returns a planar reference</span>
<span class="n">p2</span><span class="o">=</span><span class="n">ref</span><span class="p">;</span> <span class="n">p2</span><span class="o">=</span><span class="n">p1</span><span class="p">;</span> <span class="n">p2</span><span class="o">=</span><span class="n">ptr</span><span class="p">[</span><span class="mi">7</span><span class="p">];</span> <span class="n">p2</span><span class="o">=</span><span class="kt">rgb8_pixel_t</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">3</span><span class="p">);</span> <span class="c1">// planar/interleaved references and values to RGB/BGR can be freely mixed</span>
<span class="c1">//rgb8_planar_ref_t ref2; // compile error: References have no default constructors</span>
<span class="c1">//ref2=*ptr; // compile error: Cannot construct non-const reference by dereferencing const pointer</span>
<span class="c1">//ptr[3]=p1; // compile error: Cannot set the fourth pixel through a const pointer</span>
<span class="c1">//p1 = pixel&lt;float, rgb_layout_t&gt;();// compile error: Incompatible channel depth</span>
<span class="c1">//p1 = pixel&lt;bits8, rgb_layout_t&gt;();// compile error: Incompatible color space (even though it has the same number of channels)</span>
<span class="c1">//p1 = pixel&lt;bits8,rgba_layout_t&gt;();// compile error: Incompatible color space (even though it contains red, green and blue channels)</span>
</pre></div>
</div>
<p>Here is how to use pixels in generic code:</p>
<div class="highlight-c++"><div class="highlight"><pre><span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">GrayPixel</span><span class="p">,</span> <span class="k">typename</span> <span class="n">RGBPixel</span><span class="o">&gt;</span>
<span class="kt">void</span> <span class="n">gray_to_rgb</span><span class="p">(</span><span class="k">const</span> <span class="n">GrayPixel</span><span class="o">&amp;</span> <span class="n">src</span><span class="p">,</span> <span class="n">RGBPixel</span><span class="o">&amp;</span> <span class="n">dst</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">gil_function_requires</span><span class="o">&lt;</span><span class="n">PixelConcept</span><span class="o">&lt;</span><span class="n">GrayPixel</span><span class="o">&gt;</span> <span class="o">&gt;</span><span class="p">();</span>
<span class="n">gil_function_requires</span><span class="o">&lt;</span><span class="n">MutableHomogeneousPixelConcept</span><span class="o">&lt;</span><span class="n">RGBPixel</span><span class="o">&gt;</span> <span class="o">&gt;</span><span class="p">();</span>
<span class="k">typedef</span> <span class="k">typename</span> <span class="n">color_space_type</span><span class="o">&lt;</span><span class="n">GrayPixel</span><span class="o">&gt;::</span><span class="n">type</span> <span class="kt">gray_cs_t</span><span class="p">;</span>
<span class="n">BOOST_STATIC_ASSERT</span><span class="p">((</span><span class="n">boost</span><span class="o">::</span><span class="n">is_same</span><span class="o">&lt;</span><span class="kt">gray_cs_t</span><span class="p">,</span><span class="kt">gray_t</span><span class="o">&gt;::</span><span class="n">value</span><span class="p">));</span>
<span class="k">typedef</span> <span class="k">typename</span> <span class="n">color_space_type</span><span class="o">&lt;</span><span class="n">RGBPixel</span><span class="o">&gt;::</span><span class="n">type</span> <span class="kt">rgb_cs_t</span><span class="p">;</span>
<span class="n">BOOST_STATIC_ASSERT</span><span class="p">((</span><span class="n">boost</span><span class="o">::</span><span class="n">is_same</span><span class="o">&lt;</span><span class="kt">rgb_cs_t</span><span class="p">,</span><span class="kt">rgb_t</span><span class="o">&gt;::</span><span class="n">value</span><span class="p">));</span>
<span class="k">typedef</span> <span class="k">typename</span> <span class="n">channel_type</span><span class="o">&lt;</span><span class="n">GrayPixel</span><span class="o">&gt;::</span><span class="n">type</span> <span class="kt">gray_channel_t</span><span class="p">;</span>
<span class="k">typedef</span> <span class="k">typename</span> <span class="n">channel_type</span><span class="o">&lt;</span><span class="n">RGBPixel</span><span class="o">&gt;::</span><span class="n">type</span> <span class="kt">rgb_channel_t</span><span class="p">;</span>
<span class="kt">gray_channel_t</span> <span class="n">gray</span> <span class="o">=</span> <span class="n">get_color</span><span class="p">(</span><span class="n">src</span><span class="p">,</span><span class="kt">gray_color_t</span><span class="p">());</span>
<span class="n">static_fill</span><span class="p">(</span><span class="n">dst</span><span class="p">,</span> <span class="n">channel_convert</span><span class="o">&lt;</span><span class="kt">rgb_channel_t</span><span class="o">&gt;</span><span class="p">(</span><span class="n">gray</span><span class="p">));</span>
<span class="p">}</span>
<span class="c1">// example use patterns:</span>
<span class="c1">// converting gray l-value to RGB and storing at (5,5) in a 16-bit BGR interleaved image:</span>
<span class="kt">bgr16_view_t</span> <span class="n">b16</span><span class="p">(...);</span>
<span class="n">gray_to_rgb</span><span class="p">(</span><span class="kt">gray8_pixel_t</span><span class="p">(</span><span class="mi">33</span><span class="p">),</span> <span class="n">b16</span><span class="p">(</span><span class="mi">5</span><span class="p">,</span><span class="mi">5</span><span class="p">));</span>
<span class="c1">// storing the first pixel of an 8-bit grayscale image as the 5-th pixel of 32-bit planar RGB image:</span>
<span class="kt">rgb32f_planar_view_t</span> <span class="n">rpv32</span><span class="p">;</span>
<span class="kt">gray8_view_t</span> <span class="nf">gv8</span><span class="p">(...);</span>
<span class="n">gray_to_rgb</span><span class="p">(</span><span class="o">*</span><span class="n">gv8</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span> <span class="n">rpv32</span><span class="p">[</span><span class="mi">5</span><span class="p">]);</span>
</pre></div>
</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 <tt class="docutils literal"><span class="pre">PixelConcept</span></tt>
and <tt class="docutils literal"><span class="pre">MutablePixelConcept</span></tt> respectively.</p>
</div>
<div class="section" id="creating-a-copy-of-an-image-with-a-safe-buffer">
<h3><a class="toc-backref" href="#id25">Creating a Copy of an Image with a Safe Buffer</a></h3>
<p>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="highlight-c++"><div class="highlight"><pre><span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">SrcView</span><span class="p">,</span> <span class="c1">// Models ImageViewConcept (the source view)</span>
<span class="k">typename</span> <span class="n">DstImage</span><span class="o">&gt;</span> <span class="c1">// Models ImageConcept (the returned image)</span>
<span class="kt">void</span> <span class="n">create_with_margin</span><span class="p">(</span><span class="k">const</span> <span class="n">SrcView</span><span class="o">&amp;</span> <span class="n">src</span><span class="p">,</span> <span class="kt">int</span> <span class="n">k</span><span class="p">,</span> <span class="n">DstImage</span><span class="o">&amp;</span> <span class="n">result</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">gil_function_requires</span><span class="o">&lt;</span><span class="n">ImageViewConcept</span><span class="o">&lt;</span><span class="n">SrcView</span><span class="o">&gt;</span> <span class="o">&gt;</span><span class="p">();</span>
<span class="n">gil_function_requires</span><span class="o">&lt;</span><span class="n">ImageConcept</span><span class="o">&lt;</span><span class="n">DstImage</span><span class="o">&gt;</span> <span class="o">&gt;</span><span class="p">();</span>
<span class="n">gil_function_requires</span><span class="o">&lt;</span><span class="n">ViewsCompatibleConcept</span><span class="o">&lt;</span><span class="n">SrcView</span><span class="p">,</span> <span class="k">typename</span> <span class="n">DstImage</span><span class="o">::</span><span class="kt">view_t</span><span class="o">&gt;</span> <span class="o">&gt;</span><span class="p">();</span>
<span class="n">result</span><span class="o">=</span><span class="n">DstImage</span><span class="p">(</span><span class="n">src</span><span class="p">.</span><span class="n">width</span><span class="p">()</span><span class="o">+</span><span class="mi">2</span><span class="o">*</span><span class="n">k</span><span class="p">,</span> <span class="n">src</span><span class="p">.</span><span class="n">height</span><span class="p">()</span><span class="o">+</span><span class="mi">2</span><span class="o">*</span><span class="n">k</span><span class="p">);</span>
<span class="k">typename</span> <span class="n">DstImage</span><span class="o">::</span><span class="kt">view_t</span> <span class="n">centerImg</span><span class="o">=</span><span class="n">subimage_view</span><span class="p">(</span><span class="n">view</span><span class="p">(</span><span class="n">result</span><span class="p">),</span> <span class="n">k</span><span class="p">,</span><span class="n">k</span><span class="p">,</span><span class="n">src</span><span class="p">.</span><span class="n">width</span><span class="p">(),</span><span class="n">src</span><span class="p">.</span><span class="n">height</span><span class="p">());</span>
<span class="n">std</span><span class="o">::</span><span class="n">copy</span><span class="p">(</span><span class="n">src</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span> <span class="n">src</span><span class="p">.</span><span class="n">end</span><span class="p">(),</span> <span class="n">centerImg</span><span class="p">.</span><span class="n">begin</span><span class="p">());</span>
<span class="p">}</span>
</pre></div>
</div>
<p>We allocated a larger image, then we used <tt class="docutils literal"><span class="pre">subimage_view</span></tt> to create a shallow image of
its center area of top left corner at (k,k) and of identical size as <tt class="docutils literal"><span class="pre">src</span></tt>, and finally we copied <tt class="docutils literal"><span class="pre">src</span></tt> into that center image. If the margin
needs initialization, we could have done it with <tt class="docutils literal"><span class="pre">fill_pixels</span></tt>. Here is how to simplify this code using
the <tt class="docutils literal"><span class="pre">copy_pixels</span></tt> algorithm:</p>
<div class="highlight-c++"><div class="highlight"><pre><span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">SrcView</span><span class="p">,</span> <span class="k">typename</span> <span class="n">DstImage</span><span class="o">&gt;</span>
<span class="kt">void</span> <span class="n">create_with_margin</span><span class="p">(</span><span class="k">const</span> <span class="n">SrcView</span><span class="o">&amp;</span> <span class="n">src</span><span class="p">,</span> <span class="kt">int</span> <span class="n">k</span><span class="p">,</span> <span class="n">DstImage</span><span class="o">&amp;</span> <span class="n">result</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">result</span><span class="p">.</span><span class="n">recreate</span><span class="p">(</span><span class="n">src</span><span class="p">.</span><span class="n">width</span><span class="p">()</span><span class="o">+</span><span class="mi">2</span><span class="o">*</span><span class="n">k</span><span class="p">,</span> <span class="n">src</span><span class="p">.</span><span class="n">height</span><span class="p">()</span><span class="o">+</span><span class="mi">2</span><span class="o">*</span><span class="n">k</span><span class="p">);</span>
<span class="n">copy_pixels</span><span class="p">(</span><span class="n">src</span><span class="p">,</span> <span class="n">subimage_view</span><span class="p">(</span><span class="n">view</span><span class="p">(</span><span class="n">result</span><span class="p">),</span> <span class="n">k</span><span class="p">,</span><span class="n">k</span><span class="p">,</span><span class="n">src</span><span class="p">.</span><span class="n">width</span><span class="p">(),</span><span class="n">src</span><span class="p">.</span><span class="n">height</span><span class="p">()));</span>
<span class="p">}</span>
</pre></div>
</div>
<p>(Note also that <tt class="docutils literal"><span class="pre">image::recreate</span></tt> is more efficient than <tt class="docutils literal"><span class="pre">operator=</span></tt>, 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 <tt class="docutils literal"><span class="pre">std::copy</span></tt> - when called on two identical interleaved images with no padding at the end of rows, it
simply does a <tt class="docutils literal"><span class="pre">memmove</span></tt>. For planar images it does <tt class="docutils literal"><span class="pre">memmove</span></tt> for each channel. If one of the images has padding, (as in
our case) it will try to do <tt class="docutils literal"><span class="pre">memmove</span></tt> 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.</p>
</div>
<div class="section" id="histogram">
<h3><a class="toc-backref" href="#id26">Histogram</a></h3>
<p>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:</p>
<div class="highlight-c++"><div class="highlight"><pre><span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">GrayView</span><span class="p">,</span> <span class="k">typename</span> <span class="n">R</span><span class="o">&gt;</span>
<span class="kt">void</span> <span class="n">grayimage_histogram</span><span class="p">(</span><span class="k">const</span> <span class="n">GrayView</span><span class="o">&amp;</span> <span class="n">img</span><span class="p">,</span> <span class="n">R</span><span class="o">&amp;</span> <span class="n">hist</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">for</span> <span class="p">(</span><span class="k">typename</span> <span class="n">GrayView</span><span class="o">::</span><span class="n">iterator</span> <span class="n">it</span><span class="o">=</span><span class="n">img</span><span class="p">.</span><span class="n">begin</span><span class="p">();</span> <span class="n">it</span><span class="o">!=</span><span class="n">img</span><span class="p">.</span><span class="n">end</span><span class="p">();</span> <span class="o">++</span><span class="n">it</span><span class="p">)</span>
<span class="o">++</span><span class="n">hist</span><span class="p">[</span><span class="o">*</span><span class="n">it</span><span class="p">];</span>
<span class="p">}</span>
</pre></div>
</div>
<p>Using <tt class="docutils literal"><span class="pre">boost::lambda</span></tt> and GIL&#8217;s <tt class="docutils literal"><span class="pre">for_each_pixel</span></tt> algorithm, we can write this more compactly:</p>
<div class="highlight-c++"><div class="highlight"><pre><span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">GrayView</span><span class="p">,</span> <span class="k">typename</span> <span class="n">R</span><span class="o">&gt;</span>
<span class="kt">void</span> <span class="n">grayimage_histogram</span><span class="p">(</span><span class="k">const</span> <span class="n">GrayView</span><span class="o">&amp;</span> <span class="n">v</span><span class="p">,</span> <span class="n">R</span><span class="o">&amp;</span> <span class="n">hist</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">for_each_pixel</span><span class="p">(</span><span class="n">v</span><span class="p">,</span> <span class="o">++</span><span class="n">var</span><span class="p">(</span><span class="n">hist</span><span class="p">)[</span><span class="n">_1</span><span class="p">]);</span>
<span class="p">}</span>
</pre></div>
</div>
<p>Where <tt class="docutils literal"><span class="pre">for_each_pixel</span></tt> invokes <tt class="docutils literal"><span class="pre">std::for_each</span></tt> and <tt class="docutils literal"><span class="pre">var</span></tt> and <tt class="docutils literal"><span class="pre">_1</span></tt> are <tt class="docutils literal"><span class="pre">boost::lambda</span></tt> constructs.
To compute the luminosity histogram, we call the above method using the grayscale view of an image:</p>
<div class="highlight-c++"><div class="highlight"><pre><span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">View</span><span class="p">,</span> <span class="k">typename</span> <span class="n">R</span><span class="o">&gt;</span>
<span class="kt">void</span> <span class="n">luminosity_histogram</span><span class="p">(</span><span class="k">const</span> <span class="n">View</span><span class="o">&amp;</span> <span class="n">v</span><span class="p">,</span> <span class="n">R</span><span class="o">&amp;</span> <span class="n">hist</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">grayimage_histogram</span><span class="p">(</span><span class="n">color_converted_view</span><span class="o">&lt;</span><span class="kt">gray8_pixel_t</span><span class="o">&gt;</span><span class="p">(</span><span class="n">v</span><span class="p">),</span><span class="n">hist</span><span class="p">);</span>
<span class="p">}</span>
</pre></div>
</div>
<p>This is how to invoke it:</p>
<div class="highlight-c++"><div class="highlight"><pre><span class="kt">unsigned</span> <span class="kt">char</span> <span class="n">hist</span><span class="p">[</span><span class="mi">256</span><span class="p">];</span>
<span class="n">std</span><span class="o">::</span><span class="n">fill</span><span class="p">(</span><span class="n">hist</span><span class="p">,</span><span class="n">hist</span><span class="o">+</span><span class="mi">256</span><span class="p">,</span><span class="mi">0</span><span class="p">);</span>
<span class="n">luminosity_histogram</span><span class="p">(</span><span class="n">my_view</span><span class="p">,</span><span class="n">hist</span><span class="p">);</span>
</pre></div>
</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="highlight-c++"><div class="highlight"><pre><span class="n">grayimage_histogram</span><span class="p">(</span><span class="n">nth_channel_view</span><span class="p">(</span><span class="n">subimage_view</span><span class="p">(</span><span class="n">img</span><span class="p">,</span><span class="mi">0</span><span class="p">,</span><span class="mi">0</span><span class="p">,</span><span class="mi">100</span><span class="p">,</span><span class="mi">100</span><span class="p">),</span><span class="mi">1</span><span class="p">),</span><span class="n">hist</span><span class="p">);</span>
</pre></div>
</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.</p>
</div>
<div class="section" id="using-image-views">
<h3><a class="toc-backref" href="#id27">Using Image Views</a></h3>
<p>The following code illustrates the power of using image views:</p>
<div class="highlight-c++"><div class="highlight"><pre><span class="n">jpeg_read_image</span><span class="p">(</span><span class="s">&quot;monkey.jpg&quot;</span><span class="p">,</span> <span class="n">img</span><span class="p">);</span>
<span class="n">step1</span><span class="o">=</span><span class="n">view</span><span class="p">(</span><span class="n">img</span><span class="p">);</span>
<span class="n">step2</span><span class="o">=</span><span class="n">subimage_view</span><span class="p">(</span><span class="n">step1</span><span class="p">,</span> <span class="mi">200</span><span class="p">,</span><span class="mi">300</span><span class="p">,</span> <span class="mi">150</span><span class="p">,</span><span class="mi">150</span><span class="p">);</span>
<span class="n">step3</span><span class="o">=</span><span class="n">color_converted_view</span><span class="o">&lt;</span><span class="kt">rgb8_view_t</span><span class="p">,</span><span class="kt">gray8_pixel_t</span><span class="o">&gt;</span><span class="p">(</span><span class="n">step2</span><span class="p">);</span>
<span class="n">step4</span><span class="o">=</span><span class="n">rotated180_view</span><span class="p">(</span><span class="n">step3</span><span class="p">);</span>
<span class="n">step5</span><span class="o">=</span><span class="n">subsampled_view</span><span class="p">(</span><span class="n">step4</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span><span class="mi">1</span><span class="p">);</span>
<span class="n">jpeg_write_view</span><span class="p">(</span><span class="s">&quot;monkey_transform.jpg&quot;</span><span class="p">,</span> <span class="n">step5</span><span class="p">);</span>
</pre></div>
</div>
<p>The intermediate images are shown here:</p>
<img alt="_images/monkey_steps.jpg" src="_images/monkey_steps.jpg" />
<p>Notice that no pixels are ever copied. All the work is done inside <tt class="docutils literal"><span class="pre">jpeg_write_view</span></tt>.
If we call our <tt class="docutils literal"><span class="pre">luminosity_histogram</span></tt> with <tt class="docutils literal"><span class="pre">step5</span></tt> it will do the right thing.</p>
</div>
</div>
<div class="section" id="extending-the-generic-image-library">
<h2><a class="toc-backref" href="#id28">Extending the Generic Image Library</a></h2>
<p>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.</p>
<div class="section" id="defining-new-color-spaces">
<h3><a class="toc-backref" href="#id29">Defining New Color Spaces</a></h3>
<p>Each color space is in a separate file. To add a new color space, just copy one of the existing ones (like rgb.hpp) 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).</p>
</div>
<div class="section" id="defining-new-channel-types">
<h3><a class="toc-backref" href="#id30">Defining New Channel Types</a></h3>
<p>Most of the time you don&#8217;t need to do anything special to use a new channel type. You can just use it:</p>
<div class="highlight-c++"><div class="highlight"><pre><span class="k">typedef</span> <span class="n">pixel</span><span class="o">&lt;</span><span class="kt">double</span><span class="p">,</span><span class="kt">rgb_layout_t</span><span class="o">&gt;</span> <span class="kt">rgb64_pixel_t</span><span class="p">;</span> <span class="c1">// 64 bit RGB pixel</span>
<span class="k">typedef</span> <span class="n">rgb64_pixel</span><span class="o">*</span> <span class="kt">rgb64_pixel_ptr_t</span><span class="p">;</span><span class="c1">// pointer to 64-bit interleaved data</span>
<span class="k">typedef</span> <span class="n">image_type</span><span class="o">&lt;</span><span class="kt">double</span><span class="p">,</span><span class="kt">rgb_layout_t</span><span class="o">&gt;::</span><span class="n">type</span> <span class="kt">rgb64_image_t</span><span class="p">;</span> <span class="c1">// 64-bit interleaved image</span>
</pre></div>
</div>
<p>If you want to use your own channel class, you will need to provide a specialization of <tt class="docutils literal"><span class="pre">channel_traits</span></tt> for it (see channel.hpp).
If you want to do conversion between your and existing channel types, you will need to provide an overload of <tt class="docutils literal"><span class="pre">channel_convert</span></tt>.</p>
</div>
<div class="section" id="overloading-color-conversion">
<h3><a class="toc-backref" href="#id31">Overloading Color Conversion</a></h3>
<p>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&#8217;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="highlight-c++"><div class="highlight"><pre><span class="c1">// make the default use GIL&#39;s default</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">SrcColorSpace</span><span class="p">,</span> <span class="k">typename</span> <span class="n">DstColorSpace</span><span class="o">&gt;</span>
<span class="k">struct</span> <span class="n">my_color_converter_impl</span>
<span class="o">:</span> <span class="k">public</span> <span class="n">default_color_converter_impl</span><span class="o">&lt;</span><span class="n">SrcColorSpace</span><span class="p">,</span><span class="n">DstColorSpace</span><span class="o">&gt;</span> <span class="p">{};</span>
<span class="c1">// provide specializations only for cases you care about</span>
<span class="c1">// (in this case, if the destination is grayscale, invert it)</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">SrcColorSpace</span><span class="o">&gt;</span>
<span class="k">struct</span> <span class="n">my_color_converter_impl</span><span class="o">&lt;</span><span class="n">SrcColorSpace</span><span class="p">,</span><span class="kt">gray_t</span><span class="o">&gt;</span>
<span class="p">{</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">SrcP</span><span class="p">,</span> <span class="k">typename</span> <span class="n">DstP</span><span class="o">&gt;</span> <span class="c1">// Model PixelConcept</span>
<span class="kt">void</span> <span class="k">operator</span><span class="p">()(</span><span class="k">const</span> <span class="n">SrcP</span><span class="o">&amp;</span> <span class="n">src</span><span class="p">,</span> <span class="n">DstP</span><span class="o">&amp;</span> <span class="n">dst</span><span class="p">)</span> <span class="k">const</span>
<span class="p">{</span>
<span class="n">default_color_converter_impl</span><span class="o">&lt;</span><span class="n">SrcColorSpace</span><span class="p">,</span><span class="kt">gray_t</span><span class="o">&gt;</span><span class="p">()(</span><span class="n">src</span><span class="p">,</span><span class="n">dst</span><span class="p">);</span>
<span class="n">get_color</span><span class="p">(</span><span class="n">dst</span><span class="p">,</span><span class="kt">gray_color_t</span><span class="p">())</span><span class="o">=</span><span class="n">channel_invert</span><span class="p">(</span><span class="n">get_color</span><span class="p">(</span><span class="n">dst</span><span class="p">,</span><span class="kt">gray_color_t</span><span class="p">()));</span>
<span class="p">}</span>
<span class="p">};</span>
<span class="c1">// create a color converter object that dispatches to your own implementation</span>
<span class="k">struct</span> <span class="n">my_color_converter</span>
<span class="p">{</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">SrcP</span><span class="p">,</span> <span class="k">typename</span> <span class="n">DstP</span><span class="o">&gt;</span> <span class="c1">// Model PixelConcept</span>
<span class="kt">void</span> <span class="k">operator</span><span class="p">()(</span><span class="k">const</span> <span class="n">SrcP</span><span class="o">&amp;</span> <span class="n">src</span><span class="p">,</span><span class="n">DstP</span><span class="o">&amp;</span> <span class="n">dst</span><span class="p">)</span> <span class="k">const</span>
<span class="p">{</span>
<span class="k">typedef</span> <span class="k">typename</span> <span class="n">color_space_type</span><span class="o">&lt;</span><span class="n">SrcP</span><span class="o">&gt;::</span><span class="n">type</span> <span class="n">SrcColorSpace</span><span class="p">;</span>
<span class="k">typedef</span> <span class="k">typename</span> <span class="n">color_space_type</span><span class="o">&lt;</span><span class="n">DstP</span><span class="o">&gt;::</span><span class="n">type</span> <span class="n">DstColorSpace</span><span class="p">;</span>
<span class="n">my_color_converter_impl</span><span class="o">&lt;</span><span class="n">SrcColorSpace</span><span class="p">,</span><span class="n">DstColorSpace</span><span class="o">&gt;</span><span class="p">()(</span><span class="n">src</span><span class="p">,</span><span class="n">dst</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">};</span>
</pre></div>
</div>
<p>GIL&#8217;s color conversion functions take the color converter as an optional parameter. You can pass your own color converter:</p>
<div class="highlight-c++"><div class="highlight"><pre><span class="n">color_converted_view</span><span class="o">&lt;</span><span class="kt">gray8_pixel_t</span><span class="o">&gt;</span><span class="p">(</span><span class="n">img_view</span><span class="p">,</span><span class="n">my_color_converter</span><span class="p">());</span>
</pre></div>
</div>
</div>
<div class="section" id="defining-new-image-views">
<h3><a class="toc-backref" href="#id32">Defining New Image Views</a></h3>
<p>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&#8217;s look at the implementation of <tt class="docutils literal"><span class="pre">color_converted_view</span></tt> (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 <tt class="docutils literal"><span class="pre">PixelDereferenceAdaptorConcept</span></tt>; a function object that will be called when we dereference a pixel iterator.
It will call <tt class="docutils literal"><span class="pre">color_convert</span></tt> to convert to the destination pixel type:</p>
<div class="highlight-c++"><div class="highlight"><pre><span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">SrcConstRefP</span><span class="p">,</span> <span class="c1">// const reference to the source pixel</span>
<span class="k">typename</span> <span class="n">DstP</span><span class="o">&gt;</span> <span class="c1">// Destination pixel value (models PixelValueConcept)</span>
<span class="k">class</span> <span class="nc">color_convert_deref_fn</span>
<span class="p">{</span>
<span class="nl">public:</span>
<span class="k">typedef</span> <span class="n">color_convert_deref_fn</span> <span class="kt">const_t</span><span class="p">;</span>
<span class="k">typedef</span> <span class="n">DstP</span> <span class="n">value_type</span><span class="p">;</span>
<span class="k">typedef</span> <span class="n">value_type</span> <span class="n">reference</span><span class="p">;</span> <span class="c1">// read-only dereferencing</span>
<span class="k">typedef</span> <span class="k">const</span> <span class="n">value_type</span><span class="o">&amp;</span> <span class="n">const_reference</span><span class="p">;</span>
<span class="k">typedef</span> <span class="n">SrcConstRefP</span> <span class="n">argument_type</span><span class="p">;</span>
<span class="k">typedef</span> <span class="n">reference</span> <span class="n">result_type</span><span class="p">;</span>
<span class="n">BOOST_STATIC_CONSTANT</span><span class="p">(</span><span class="kt">bool</span><span class="p">,</span> <span class="n">is_mutable</span><span class="o">=</span><span class="nb">false</span><span class="p">);</span>
<span class="n">result_type</span> <span class="k">operator</span><span class="p">()(</span><span class="n">argument_type</span> <span class="n">srcP</span><span class="p">)</span> <span class="k">const</span> <span class="p">{</span>
<span class="n">result_type</span> <span class="n">dstP</span><span class="p">;</span>
<span class="n">color_convert</span><span class="p">(</span><span class="n">srcP</span><span class="p">,</span><span class="n">dstP</span><span class="p">);</span>
<span class="k">return</span> <span class="n">dstP</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">};</span>
</pre></div>
</div>
<p>We then use the <tt class="docutils literal"><span class="pre">add_deref</span></tt> member struct of image views to construct the type of a view that invokes a given function object (<tt class="docutils literal"><span class="pre">deref_t</span></tt>) upon
dereferencing. In our case, it performs color conversion:</p>
<div class="highlight-c++"><div class="highlight"><pre><span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">SrcView</span><span class="p">,</span> <span class="k">typename</span> <span class="n">DstP</span><span class="o">&gt;</span>
<span class="k">struct</span> <span class="n">color_converted_view_type</span>
<span class="p">{</span>
<span class="nl">private:</span>
<span class="k">typedef</span> <span class="k">typename</span> <span class="n">SrcView</span><span class="o">::</span><span class="kt">const_t</span><span class="o">::</span><span class="n">reference</span> <span class="n">src_pix_ref</span><span class="p">;</span> <span class="c1">// const reference to pixel in SrcView</span>
<span class="k">typedef</span> <span class="n">color_convert_deref_fn</span><span class="o">&lt;</span><span class="n">src_pix_ref</span><span class="p">,</span> <span class="n">DstP</span><span class="o">&gt;</span> <span class="kt">deref_t</span><span class="p">;</span> <span class="c1">// the dereference adaptor that performs color conversion</span>
<span class="k">typedef</span> <span class="k">typename</span> <span class="n">SrcView</span><span class="o">::</span><span class="k">template</span> <span class="n">add_deref</span><span class="o">&lt;</span><span class="kt">deref_t</span><span class="o">&gt;</span> <span class="kt">add_ref_t</span><span class="p">;</span>
<span class="nl">public:</span>
<span class="k">typedef</span> <span class="k">typename</span> <span class="kt">add_ref_t</span><span class="o">::</span><span class="n">type</span> <span class="n">type</span><span class="p">;</span> <span class="c1">// the color converted view type</span>
<span class="k">static</span> <span class="n">type</span> <span class="nf">make</span><span class="p">(</span><span class="k">const</span> <span class="n">SrcView</span><span class="o">&amp;</span> <span class="n">sv</span><span class="p">)</span> <span class="p">{</span> <span class="k">return</span> <span class="kt">add_ref_t</span><span class="o">::</span><span class="n">make</span><span class="p">(</span><span class="n">sv</span><span class="p">,</span> <span class="kt">deref_t</span><span class="p">());</span> <span class="p">}</span>
<span class="p">};</span>
</pre></div>
</div>
<p>Finally our <tt class="docutils literal"><span class="pre">color_converted_view</span></tt> code simply creates color-converted view from the source view:</p>
<div class="highlight-c++"><div class="highlight"><pre><span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">DstP</span><span class="p">,</span> <span class="k">typename</span> <span class="n">View</span><span class="o">&gt;</span> <span class="kr">inline</span>
<span class="k">typename</span> <span class="n">color_converted_view_type</span><span class="o">&lt;</span><span class="n">View</span><span class="p">,</span><span class="n">DstP</span><span class="o">&gt;::</span><span class="n">type</span> <span class="n">color_convert_view</span><span class="p">(</span><span class="k">const</span> <span class="n">View</span><span class="o">&amp;</span> <span class="n">src</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">return</span> <span class="n">color_converted_view_type</span><span class="o">&lt;</span><span class="n">View</span><span class="p">,</span><span class="n">DstP</span><span class="o">&gt;::</span><span class="n">make</span><span class="p">(</span><span class="n">src</span><span class="p">);</span>
<span class="p">}</span>
</pre></div>
</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>
</div>
</div>
<div class="section" id="technicalities">
<h2><a class="toc-backref" href="#id33">Technicalities</a></h2>
<div class="section" id="creating-a-reference-proxy">
<h3><a class="toc-backref" href="#id34">Creating a reference proxy</a></h3>
<p>Sometimes it is necessary to create a proxy class that represents a reference to a given object. Examples of these are GIL&#8217;s reference
to a planar pixel (<tt class="docutils literal"><span class="pre">planar_pixel_reference</span></tt>) and GIL&#8217;s sub-byte 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="highlight-c++"><div class="highlight"><pre><span class="k">struct</span> <span class="n">rgb_planar_pixel_iterator</span>
<span class="p">{</span>
<span class="k">typedef</span> <span class="n">my_reference_proxy</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span> <span class="n">reference</span><span class="p">;</span>
<span class="n">reference</span> <span class="k">operator</span><span class="o">*</span><span class="p">()</span> <span class="k">const</span> <span class="p">{</span> <span class="k">return</span> <span class="n">reference</span><span class="p">(</span><span class="n">red</span><span class="p">,</span><span class="n">green</span><span class="p">,</span><span class="n">blue</span><span class="p">);</span> <span class="p">}</span>
<span class="p">};</span>
</pre></div>
</div>
<p>The problem arises when an iterator is dereferenced directly into a function that takes a mutable pixel:</p>
<div class="highlight-c++"><div class="highlight"><pre><span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">Pixel</span><span class="o">&gt;</span> <span class="c1">// Models MutablePixelConcept</span>
<span class="kt">void</span> <span class="n">invert_pixel</span><span class="p">(</span><span class="n">Pixel</span><span class="o">&amp;</span> <span class="n">p</span><span class="p">);</span>
<span class="n">rgb_planar_pixel_iterator</span> <span class="n">myIt</span><span class="p">;</span>
<span class="n">invert_pixel</span><span class="p">(</span><span class="o">*</span><span class="n">myIt</span><span class="p">);</span> <span class="c1">// compile error!</span>
</pre></div>
</div>
<p>C++ does not allow for matching a temporary object against a non-constant reference. The solution is to:
- Use const qualifier on all members of the reference proxy object:</p>
<div class="highlight-c++"><div class="highlight"><pre><span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">T</span><span class="o">&gt;</span>
<span class="k">struct</span> <span class="n">my_reference_proxy</span>
<span class="p">{</span>
<span class="k">const</span> <span class="n">my_reference_proxy</span><span class="o">&amp;</span> <span class="k">operator</span><span class="o">=</span><span class="p">(</span><span class="k">const</span> <span class="n">my_reference_proxy</span><span class="o">&amp;</span> <span class="n">p</span><span class="p">)</span> <span class="k">const</span><span class="p">;</span>
<span class="k">const</span> <span class="n">my_reference_proxy</span><span class="o">*</span> <span class="k">operator</span><span class="o">-&gt;</span><span class="p">()</span> <span class="k">const</span> <span class="p">{</span> <span class="k">return</span> <span class="k">this</span><span class="p">;</span> <span class="p">}</span>
<span class="p">...</span>
<span class="p">};</span>
</pre></div>
</div>
<ul>
<li><p class="first">Use different classes to denote mutable and constant reference (maybe based on the constness of the template parameter)</p>
</li>
<li><p class="first">Define the reference type of your iterator with const qualifier:</p>
<div class="highlight-c++"><div class="highlight"><pre><span class="k">struct</span> <span class="n">iterator_traits</span><span class="o">&lt;</span><span class="n">rgb_planar_pixel_iterator</span><span class="o">&gt;</span>
<span class="p">{</span>
<span class="k">typedef</span> <span class="k">const</span> <span class="n">my_reference_proxy</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span> <span class="n">reference</span><span class="p">;</span>
<span class="p">};</span>
</pre></div>
</div>
</li>
</ul>
<p>A second important issue is providing an overload for <tt class="docutils literal"><span class="pre">swap</span></tt> for your reference class. The default <tt class="docutils literal"><span class="pre">std::swap</span></tt> 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 <tt class="docutils literal"><span class="pre">swap</span></tt> function is incorrectly called qualified, as <tt class="docutils literal"><span class="pre">std::swap</span></tt>.
The only way for these STL algorithms to use your overload is if you define it in the <tt class="docutils literal"><span class="pre">std</span></tt> namespace:</p>
<div class="highlight-c++"><div class="highlight"><pre><span class="k">namespace</span> <span class="n">std</span>
<span class="p">{</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">T</span><span class="o">&gt;</span>
<span class="kt">void</span> <span class="n">swap</span><span class="p">(</span><span class="n">my_reference_proxy</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;&amp;</span> <span class="n">x</span><span class="p">,</span> <span class="n">my_reference_proxy</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;&amp;</span> <span class="n">y</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">my_value</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span> <span class="n">tmp</span><span class="o">=</span><span class="n">x</span><span class="p">;</span>
<span class="n">x</span><span class="o">=</span><span class="n">y</span><span class="p">;</span>
<span class="n">y</span><span class="o">=</span><span class="n">tmp</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
</pre></div>
</div>
<p>Lastly, remember that constructors and copy-constructors of proxy references are always shallow and assignment operators are deep.</p>
<p>We are grateful to Dave Abrahams, Sean Parent and Alex Stepanov for suggesting the above solution.</p>
</div>
</div>
<div class="section" id="conclusion">
<h2><a class="toc-backref" href="#id35">Conclusion</a></h2>
<p>The Generic Image Library is designed with the following five goals in mind:</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Generality:</th><td class="field-body">Abstracts image representations from algorithms on images. It allows for writing code once and have it work for any image type.</td>
</tr>
<tr class="field-even field"><th class="field-name">Performance:</th><td class="field-body">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.</td>
</tr>
<tr class="field-odd field"><th class="field-name">Flexibility:</th><td class="field-body">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.</td>
</tr>
<tr class="field-even field"><th class="field-name">Extensibility:</th><td class="field-body">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.</td>
</tr>
<tr class="field-odd field"><th class="field-name">Compatibility:</th><td class="field-body">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.</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="navbar" style="text-align:right;">
<a class="prev" title="Numeric extension" href="numeric.html"><img src="_static/prev.png" alt="prev"/></a>
</div>
</div>
</body>
</html>