2 // Copyright 2005-2007 Adobe Systems Incorporated
4 // Distributed under the Boost Software License, Version 1.0
5 // See accompanying file LICENSE_1_0.txt or copy at
6 // http://www.boost.org/LICENSE_1_0.txt
8 #include <boost/gil/channel.hpp>
9 #include <boost/gil/channel_algorithm.hpp>
10 #include <boost/gil/typedefs.hpp>
15 #include <type_traits>
17 #if defined(BOOST_CLANG)
18 #pragma clang diagnostic push
19 #pragma clang diagnostic ignored "-Wfloat-equal"
20 #elif BOOST_GCC >= 40700
21 #pragma GCC diagnostic push
22 #pragma GCC diagnostic ignored "-Wfloat-equal"
23 #elif BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
25 #pragma warning(disable:4512) //assignment operator could not be generated
28 using namespace boost::gil
;
33 auto c8_min
= channel_traits
<uint8_t>::min_value();
34 auto c8_max
= channel_traits
<uint8_t>::max_value();
35 auto c8s_min
= channel_traits
<int8_t>::min_value();
36 auto c8s_max
= channel_traits
<int8_t>::max_value();
37 auto c16_min
= channel_traits
<uint16_t>::min_value();
38 auto c16_max
= channel_traits
<uint16_t>::max_value();
39 auto c16s_min
= channel_traits
<int16_t>::min_value();
40 auto c16s_max
= channel_traits
<int16_t>::max_value();
41 auto c32_min
= channel_traits
<uint32_t>::min_value();
42 auto c32_max
= channel_traits
<uint32_t>::max_value();
43 auto c32s_min
= channel_traits
<int32_t>::min_value();
44 auto c32s_max
= channel_traits
<int32_t>::max_value();
45 auto c32f_min
= channel_traits
<float32_t
>::min_value();
46 auto c32f_max
= channel_traits
<float32_t
>::max_value();
49 template <typename ChannelTestCore
>
50 struct do_test
: public ChannelTestCore
{
51 using channel_t
= typename
ChannelTestCore::channel_t
;
52 using channel_value_t
= typename channel_traits
<channel_t
>::value_type
;
54 do_test() : ChannelTestCore() {
55 error_if(this->_min_v
!= channel_traits
<channel_t
>::min_value());
56 error_if(this->_max_v
!= channel_traits
<channel_t
>::max_value());
60 test_channel_invert();
61 test_channel_convert();
62 test_channel_multiply();
66 void test_mutable(std::false_type
) {}
67 void test_mutable(std::true_type
) {
68 channel_value_t mv
=this->_min_v
;
69 ++this->_min_v
; this->_min_v
++;
70 --this->_min_v
; this->_min_v
--;
71 error_if(mv
!=this->_min_v
);
75 error_if(mv
!=this->_min_v
);
79 error_if(mv
!=this->_min_v
);
81 this->_min_v
= 1; // assignable to scalar
82 this->_min_v
= mv
; // and to value type
85 channel_value_t v1
=this->_min_v
;
86 channel_value_t v2
=this->_max_v
;
87 swap(this->_min_v
, this->_max_v
);
89 channel_value_t v3
=this->_min_v
;
90 channel_value_t v4
=this->_max_v
;
91 error_if(v1
!=v4
|| v2
!=v3
);
94 void test_channel_math() {
95 error_if(this->_min_v
>= this->_max_v
);
96 error_if(this->_max_v
<= this->_min_v
);
97 error_if(this->_min_v
> this->_max_v
);
98 error_if(this->_max_v
< this->_min_v
);
99 error_if(this->_max_v
== this->_min_v
);
100 error_if(!(this->_max_v
!= this->_min_v
));
102 error_if(this->_min_v
* 1 != this->_min_v
);
103 error_if(this->_min_v
/ 1 != this->_min_v
);
105 error_if((this->_min_v
+ 1) + 1 != (this->_min_v
+ 2));
106 error_if((this->_max_v
- 1) - 1 != (this->_max_v
- 2));
108 error_if(this->_min_v
!= 1 && this->_min_v
==1); // comparable to integral
111 test_mutable(std::integral_constant
<bool, channel_traits
<channel_t
>::is_mutable
>());
115 void test_channel_invert() {
116 error_if(channel_invert(this->_min_v
) != this->_max_v
);
117 error_if(channel_invert(this->_max_v
) != this->_min_v
);
120 void test_channel_multiply() {
121 error_if(channel_multiply(this->_min_v
, this->_min_v
) != this->_min_v
);
122 error_if(channel_multiply(this->_max_v
, this->_max_v
) != this->_max_v
);
123 error_if(channel_multiply(this->_max_v
, this->_min_v
) != this->_min_v
);
126 void test_channel_convert() {
127 channel_value_t v_min
, v_max
;
129 v_min
=channel_convert
<channel_t
>(c8_min
);
130 v_max
=channel_convert
<channel_t
>(c8_max
);
131 error_if(v_min
!=this->_min_v
|| v_max
!=this->_max_v
);
133 v_min
=channel_convert
<channel_t
>(c8s_min
);
134 v_max
=channel_convert
<channel_t
>(c8s_max
);
135 error_if(v_min
!=this->_min_v
|| v_max
!=this->_max_v
);
137 v_min
=channel_convert
<channel_t
>(c16_min
);
138 v_max
=channel_convert
<channel_t
>(c16_max
);
139 error_if(v_min
!=this->_min_v
|| v_max
!=this->_max_v
);
141 v_min
=channel_convert
<channel_t
>(c16s_min
);
142 v_max
=channel_convert
<channel_t
>(c16s_max
);
143 error_if(v_min
!=this->_min_v
|| v_max
!=this->_max_v
);
145 v_min
=channel_convert
<channel_t
>(c32_min
);
146 v_max
=channel_convert
<channel_t
>(c32_max
);
147 error_if(v_min
!=this->_min_v
|| v_max
!=this->_max_v
);
149 v_min
=channel_convert
<channel_t
>(c32s_min
);
150 v_max
=channel_convert
<channel_t
>(c32s_max
);
151 error_if(v_min
!=this->_min_v
|| v_max
!=this->_max_v
);
153 v_min
=channel_convert
<channel_t
>(c32f_min
);
154 v_max
=channel_convert
<channel_t
>(c32f_max
);
155 error_if(v_min
!=this->_min_v
|| v_max
!=this->_max_v
);
159 // Different core classes depending on the different types of channels - channel values, references and subbyte references
160 // The cores ensure there are two members, _min_v and _max_v initialized with the minimum and maximum channel value.
161 // The different channel types have different ways to initialize them, thus require different cores
163 // For channel values simply initialize the value directly
164 template <typename ChannelValue
>
167 using channel_t
= ChannelValue
;
172 : _min_v(channel_traits
<ChannelValue
>::min_value())
173 , _max_v(channel_traits
<ChannelValue
>::max_value())
175 boost::function_requires
<ChannelValueConcept
<ChannelValue
> >();
179 // For channel references we need to have separate channel values
180 template <typename ChannelRef
>
181 class reference_core
: public value_core
<typename channel_traits
<ChannelRef
>::value_type
>
183 using parent_t
= value_core
<typename channel_traits
<ChannelRef
>::value_type
>;
186 using channel_t
= ChannelRef
;
192 , _min_v(parent_t::_min_v
)
193 , _max_v(parent_t::_max_v
)
195 boost::function_requires
<ChannelConcept
<ChannelRef
> >();
199 // For subbyte channel references we need to store the bit buffers somewhere
200 template <typename ChannelSubbyteRef
, typename ChannelMutableRef
= ChannelSubbyteRef
>
201 class packed_reference_core
{
203 using channel_t
= ChannelSubbyteRef
;
204 using integer_t
= typename
channel_t::integer_t
;
205 channel_t _min_v
, _max_v
;
207 integer_t _min_buf
, _max_buf
;
209 packed_reference_core() : _min_v(&_min_buf
), _max_v(&_max_buf
) {
210 ChannelMutableRef
b1(&_min_buf
), b2(&_max_buf
);
211 b1
= channel_traits
<channel_t
>::min_value();
212 b2
= channel_traits
<channel_t
>::max_value();
214 boost::function_requires
<ChannelConcept
<ChannelSubbyteRef
> >();
218 template <typename ChannelSubbyteRef
, typename ChannelMutableRef
= ChannelSubbyteRef
>
219 class packed_dynamic_reference_core
{
221 using channel_t
= ChannelSubbyteRef
;
222 channel_t _min_v
, _max_v
;
224 typename
channel_t::integer_t _min_buf
, _max_buf
;
226 packed_dynamic_reference_core(int first_bit1
=1, int first_bit2
=2) : _min_v(&_min_buf
,first_bit1
), _max_v(&_max_buf
,first_bit2
) {
227 ChannelMutableRef
b1(&_min_buf
,1), b2(&_max_buf
,2);
228 b1
= channel_traits
<channel_t
>::min_value();
229 b2
= channel_traits
<channel_t
>::max_value();
231 boost::function_requires
<ChannelConcept
<ChannelSubbyteRef
> >();
236 template <typename ChannelValue
>
237 void test_channel_value() {
238 do_test
<value_core
<ChannelValue
> >().test_all();
241 template <typename ChannelRef
>
242 void test_channel_reference() {
243 do_test
<reference_core
<ChannelRef
> >().test_all();
246 template <typename ChannelSubbyteRef
>
247 void test_packed_channel_reference() {
248 do_test
<packed_reference_core
<ChannelSubbyteRef
,ChannelSubbyteRef
> >().test_all();
251 template <typename ChannelSubbyteRef
, typename MutableRef
>
252 void test_const_packed_channel_reference() {
253 do_test
<packed_reference_core
<ChannelSubbyteRef
,MutableRef
> >().test_all();
256 template <typename ChannelSubbyteRef
>
257 void test_packed_dynamic_channel_reference() {
258 do_test
<packed_dynamic_reference_core
<ChannelSubbyteRef
,ChannelSubbyteRef
> >().test_all();
261 template <typename ChannelSubbyteRef
, typename MutableRef
>
262 void test_const_packed_dynamic_channel_reference() {
263 do_test
<packed_dynamic_reference_core
<ChannelSubbyteRef
,MutableRef
> >().test_all();
266 template <typename ChannelValue
>
267 void test_channel_value_impl() {
268 test_channel_value
<ChannelValue
>();
269 test_channel_reference
<ChannelValue
&>();
270 test_channel_reference
<const ChannelValue
&>();
273 /////////////////////////////////////////////////////////
275 /// A channel archetype - to test the minimum requirements of the concept
277 /////////////////////////////////////////////////////////
279 struct channel_value_archetype
;
280 struct channel_archetype
{
281 // equality comparable
282 friend bool operator==(const channel_archetype
&,const channel_archetype
&) { return true; }
283 friend bool operator!=(const channel_archetype
&,const channel_archetype
&) { return false; }
284 // less-than comparable
285 friend bool operator<(const channel_archetype
&,const channel_archetype
&) { return false; }
286 // convertible to a scalar
287 operator std::uint8_t() const { return 0; }
290 channel_archetype
& operator++() { return *this; }
291 channel_archetype
& operator--() { return *this; }
292 channel_archetype
operator++(int) { return *this; }
293 channel_archetype
operator--(int) { return *this; }
295 template <typename Scalar
> channel_archetype
operator+=(Scalar
) { return *this; }
296 template <typename Scalar
> channel_archetype
operator-=(Scalar
) { return *this; }
297 template <typename Scalar
> channel_archetype
operator*=(Scalar
) { return *this; }
298 template <typename Scalar
> channel_archetype
operator/=(Scalar
) { return *this; }
300 using value_type
= channel_value_archetype
;
301 using reference
= channel_archetype
;
302 using const_reference
= channel_archetype
const;
303 using pointer
= channel_value_archetype
*;
304 using const_pointer
= channel_value_archetype
const*;
305 static constexpr bool is_mutable
=true;
307 static value_type
min_value();
308 static value_type
max_value();
312 struct channel_value_archetype
: public channel_archetype
{
313 channel_value_archetype() {} // default constructible
314 channel_value_archetype(const channel_value_archetype
&) {} // copy constructible
315 channel_value_archetype
& operator=(const channel_value_archetype
&){return *this;} // assignable
316 channel_value_archetype(std::uint8_t) {}
319 channel_value_archetype
channel_archetype::min_value() { return channel_value_archetype(); }
320 channel_value_archetype
channel_archetype::max_value() { return channel_value_archetype(); }
323 void test_packed_channel_reference()
325 using channel16_0_5_reference_t
= packed_channel_reference
<std::uint16_t, 0, 5, true>;
326 using channel16_5_6_reference_t
= packed_channel_reference
<std::uint16_t, 5, 6, true>;
327 using channel16_11_5_reference_t
= packed_channel_reference
<std::uint16_t, 11, 5, true>;
329 std::uint16_t data
=0;
330 channel16_0_5_reference_t
channel1(&data
);
331 channel16_5_6_reference_t
channel2(&data
);
332 channel16_11_5_reference_t
channel3(&data
);
334 channel1
=channel_traits
<channel16_0_5_reference_t
>::max_value();
335 channel2
=channel_traits
<channel16_5_6_reference_t
>::max_value();
336 channel3
=channel_traits
<channel16_11_5_reference_t
>::max_value();
337 error_if(data
!=65535);
339 test_packed_channel_reference
<channel16_0_5_reference_t
>();
340 test_packed_channel_reference
<channel16_5_6_reference_t
>();
341 test_packed_channel_reference
<channel16_11_5_reference_t
>();
344 void test_packed_dynamic_channel_reference()
346 using channel16_5_reference_t
= packed_dynamic_channel_reference
<std::uint16_t, 5, true>;
347 using channel16_6_reference_t
= packed_dynamic_channel_reference
<std::uint16_t, 6, true>;
349 std::uint16_t data
=0;
350 channel16_5_reference_t
channel1(&data
,0);
351 channel16_6_reference_t
channel2(&data
,5);
352 channel16_5_reference_t
channel3(&data
,11);
354 channel1
=channel_traits
<channel16_5_reference_t
>::max_value();
355 channel2
=channel_traits
<channel16_6_reference_t
>::max_value();
356 channel3
=channel_traits
<channel16_5_reference_t
>::max_value();
357 error_if(data
!=65535);
359 test_packed_dynamic_channel_reference
<channel16_5_reference_t
>();
362 void test_channel() {
363 test_channel_value_impl
<uint8_t>();
364 test_channel_value_impl
<int8_t>();
365 test_channel_value_impl
<uint16_t>();
366 test_channel_value_impl
<int16_t>();
367 test_channel_value_impl
<uint32_t>();
368 test_channel_value_impl
<int16_t>();
370 test_channel_value_impl
<float32_t
>();
372 test_packed_channel_reference();
373 test_packed_dynamic_channel_reference();
375 // Do only compile-time tests for the archetype (because asserts like val1<val2 fail)
376 boost::function_requires
<MutableChannelConcept
<channel_archetype
> >();
378 do_test
<value_core
<channel_value_archetype
> >();
379 do_test
<reference_core
<channel_archetype
> >();
380 do_test
<reference_core
<const channel_archetype
&> >();
391 catch (std::exception
const& e
)
393 std::cerr
<< e
.what() << std::endl
;
403 // - provide algorithm performance overloads for scoped channel and packed channels
404 // - Update concepts and documentation
405 // - What to do about pointer types?!
407 // - is channel_convert the same as native?
408 // - is operator++ on float32_t the same as native? How about if operator++ is defined in scoped_channel to do _value++?