1Channel
2=======
3
4.. contents::
5   :local:
6   :depth: 2
7
8Overview
9--------
10
11A channel indicates the intensity of a color component (for example, the red
12channel in an RGB pixel). Typical channel operations are getting, comparing
13and setting the channel values. Channels have associated minimum and maximum
14value. GIL channels model the following concept:
15
16.. code-block:: cpp
17
18  concept ChannelConcept<typename T> : EqualityComparable<T>
19  {
20      typename value_type      = T;        // use channel_traits<T>::value_type to access it
21      where ChannelValueConcept<value_type>;
22      typename reference       = T&;       // use channel_traits<T>::reference to access it
23      typename pointer         = T*;       // use channel_traits<T>::pointer to access it
24      typename const_reference = const T&; // use channel_traits<T>::const_reference to access it
25      typename const_pointer   = const T*; // use channel_traits<T>::const_pointer to access it
26      static const bool is_mutable;        // use channel_traits<T>::is_mutable to access it
27
28      static T min_value();                // use channel_traits<T>::min_value to access it
29      static T max_value();                // use channel_traits<T>::min_value to access it
30  };
31
32  concept MutableChannelConcept<ChannelConcept T> : Swappable<T>, Assignable<T> {};
33
34  concept ChannelValueConcept<ChannelConcept T> : Regular<T> {};
35
36GIL allows built-in integral and floating point types to be channels.
37Therefore the associated types and range information are defined in
38``channel_traits`` with the following default implementation:
39
40.. code-block:: cpp
41
42  template <typename T>
43  struct channel_traits
44  {
45      typedef T         value_type;
46      typedef T&        reference;
47      typedef T*        pointer;
48      typedef T& const  const_reference;
49      typedef T* const  const_pointer;
50
51      static value_type min_value() { return std::numeric_limits<T>::min(); }
52      static value_type max_value() { return std::numeric_limits<T>::max(); }
53  };
54
55Two channel types are *compatible* if they have the same value type:
56
57.. code-block:: cpp
58
59  concept ChannelsCompatibleConcept<ChannelConcept T1, ChannelConcept T2>
60  {
61      where SameType<T1::value_type, T2::value_type>;
62  };
63
64A channel may be *convertible* to another channel:
65
66.. code-block:: cpp
67
68  template <ChannelConcept Src, ChannelValueConcept Dst>
69  concept ChannelConvertibleConcept
70  {
71      Dst channel_convert(Src);
72  };
73
74Note that ``ChannelConcept`` and ``MutableChannelConcept`` do not require a
75default constructor. Channels that also support default construction (and thus
76are regular types) model ``ChannelValueConcept``.
77To understand the motivation for this distinction, consider a 16-bit RGB pixel
78in a "565" bit pattern. Its channels correspond to bit ranges. To support such
79channels, we need to create a custom proxy class corresponding to a reference
80to a sub-byte channel.
81Such a proxy reference class models only ``ChannelConcept``, because, similar
82to native C++ references, it may not have a default constructor.
83
84Note also that algorithms may impose additional requirements on channels,
85such as support for arithmetic operations.
86
87.. seealso::
88
89  - `ChannelConcept<T> <reference/structboost_1_1gil_1_1_channel_concept.html>`_
90  - `ChannelValueConcept<T> <reference/structboost_1_1gil_1_1_channel_value_concept.html>`_
91  - `MutableChannelConcept<T> <reference/structboost_1_1gil_1_1_mutable_channel_concept.html>`_
92  - `ChannelsCompatibleConcept<T1,T2> <reference/structboost_1_1gil_1_1_channels_compatible_concept.html>`_
93  - `ChannelConvertibleConcept<SrcChannel,DstChannel> <reference/structboost_1_1gil_1_1_channel_convertible_concept.html>`_
94
95Models
96------
97
98All C++11 fundamental integer and float point types are valid channels.
99
100The minimum and maximum values of a channel modeled by a built-in type
101correspond to the minimum and maximum physical range of the built-in type, as
102specified by its ``std::numeric_limits``. Sometimes the physical range is not
103appropriate. GIL provides ``scoped_channel_value``, a model for a channel
104adapter that allows for specifying a custom range.
105We use it to define a ``[0..1]`` floating point channel type as follows:
106
107.. code-block:: cpp
108
109  struct float_zero { static float apply() { return 0.0f; } };
110  struct float_one  { static float apply() { return 1.0f; } };
111  typedef scoped_channel_value<float,float_zero,float_one> bits32f;
112
113GIL also provides models for channels corresponding to ranges of bits:
114
115.. code-block:: cpp
116
117  // Value of a channel defined over NumBits bits. Models ChannelValueConcept
118  template <int NumBits> class packed_channel_value;
119
120  // Reference to a channel defined over NumBits bits. Models ChannelConcept
121  template <int FirstBit,
122          int NumBits,       // Defines the sequence of bits in the data value that contain the channel
123          bool Mutable>      // true if the reference is mutable
124  class packed_channel_reference;
125
126  // Reference to a channel defined over NumBits bits. Its FirstBit is a run-time parameter. Models ChannelConcept
127  template <int NumBits,       // Defines the sequence of bits in the data value that contain the channel
128          bool Mutable>      // true if the reference is mutable
129  class packed_dynamic_channel_reference;
130
131Note that there are two models of a reference proxy which differ based on
132whether the offset of the channel range is specified as a template or a
133run-time parameter. The first model is faster and more compact while the
134second model is more flexible. For example, the second model allows us to
135construct an iterator over bit range channels.
136
137Algorithms
138----------
139
140Here is how to construct the three channels of a 16-bit "565" pixel and set
141them to their maximum value:
142
143.. code-block:: cpp
144
145  using channel16_0_5_reference_t  = packed_channel_reference<0, 5, true>;
146  using channel16_5_6_reference_t  = packed_channel_reference<5, 6, true>;
147  using channel16_11_5_reference_t = packed_channel_reference<11, 5, true>;
148
149  std::uint16_t data=0;
150  channel16_0_5_reference_t  channel1(&data);
151  channel16_5_6_reference_t  channel2(&data);
152  channel16_11_5_reference_t channel3(&data);
153
154  channel1 = channel_traits<channel16_0_5_reference_t>::max_value();
155  channel2 = channel_traits<channel16_5_6_reference_t>::max_value();
156  channel3 = channel_traits<channel16_11_5_reference_t>::max_value();
157  assert(data == 65535);
158
159Assignment, equality comparison and copy construction are defined only between
160compatible channels:
161
162.. code-block:: cpp
163
164  packed_channel_value<5> channel_6bit = channel1;
165  channel_6bit = channel3;
166
167  // compile error: Assignment between incompatible channels
168  //channel_6bit = channel2;
169
170All channel models provided by GIL are pairwise convertible:
171
172.. code-block:: cpp
173
174  channel1 = channel_traits<channel16_0_5_reference_t>::max_value();
175  assert(channel1 == 31);
176
177  bits16 chan16 = channel_convert<bits16>(channel1);
178  assert(chan16 == 65535);
179
180Channel conversion is a lossy operation. GIL's channel conversion is a linear
181transformation between the ranges of the source and destination channel.
182It maps precisely the minimum to the minimum and the maximum to the maximum.
183(For example, to convert from uint8_t to uint16_t GIL does not do a bit shift
184because it will not properly match the maximum values. Instead GIL multiplies
185the source by 257).
186
187All channel models that GIL provides are convertible from/to an integral or
188floating point type. Thus they support arithmetic operations. Here are the
189channel-level algorithms that GIL provides:
190
191.. code-block:: cpp
192
193  // Converts a source channel value into a destination channel.
194  // Linearly maps the value of the source into the range of the destination.
195  template <typename DstChannel, typename SrcChannel>
196  typename channel_traits<DstChannel>::value_type channel_convert(SrcChannel src);
197
198  // returns max_value - x + min_value
199  template <typename Channel>
200  typename channel_traits<Channel>::value_type channel_invert(Channel x);
201
202  // returns a * b / max_value
203  template <typename Channel>
204  typename channel_traits<Channel>::value_type channel_multiply(Channel a, Channel b);
205