mirror of
https://github.com/boostorg/gil.git
synced 2026-01-26 18:42:12 +00:00
378 lines
14 KiB
C++
378 lines
14 KiB
C++
/*
|
|
Copyright 2005-2007 Adobe Systems Incorporated
|
|
|
|
Use, modification and distribution are subject to the Boost Software License,
|
|
Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
|
http://www.boost.org/LICENSE_1_0.txt).
|
|
|
|
See http://opensource.adobe.com/gil for most recent version including documentation.
|
|
*/
|
|
// channel.cpp : Tests channel
|
|
//
|
|
|
|
#include <exception>
|
|
#include <boost/gil/gil_config.hpp>
|
|
#include <boost/gil/channel_algorithm.hpp>
|
|
#include <boost/gil/gil_concept.hpp>
|
|
|
|
#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
|
|
#pragma warning(push)
|
|
#pragma warning(disable:4512) //assignment operator could not be generated
|
|
#endif
|
|
|
|
|
|
using namespace boost::gil;
|
|
using namespace std;
|
|
|
|
void error_if(bool);
|
|
|
|
bits8 c8_min = channel_traits<bits8 >::min_value();
|
|
bits8 c8_max = channel_traits<bits8 >::max_value();
|
|
bits8s c8s_min = channel_traits<bits8s >::min_value();
|
|
bits8s c8s_max = channel_traits<bits8s >::max_value();
|
|
bits16 c16_min = channel_traits<bits16 >::min_value();
|
|
bits16 c16_max = channel_traits<bits16 >::max_value();
|
|
bits16s c16s_min = channel_traits<bits16s>::min_value();
|
|
bits16s c16s_max = channel_traits<bits16s>::max_value();
|
|
bits32 c32_min = channel_traits<bits32 >::min_value();
|
|
bits32 c32_max = channel_traits<bits32 >::max_value();
|
|
bits32s c32s_min = channel_traits<bits32s>::min_value();
|
|
bits32s c32s_max = channel_traits<bits32s>::max_value();
|
|
bits32f c32f_min = channel_traits<bits32f>::min_value();
|
|
bits32f c32f_max = channel_traits<bits32f>::max_value();
|
|
|
|
|
|
template <typename ChannelTestCore>
|
|
struct do_test : public ChannelTestCore {
|
|
typedef typename ChannelTestCore::channel_t channel_t;
|
|
typedef typename channel_traits<channel_t>::value_type channel_value_t;
|
|
|
|
do_test() : ChannelTestCore() {
|
|
error_if(this->_min_v != channel_traits<channel_t>::min_value());
|
|
error_if(this->_max_v != channel_traits<channel_t>::max_value());
|
|
}
|
|
|
|
void test_all() {
|
|
test_channel_invert();
|
|
test_channel_convert();
|
|
test_channel_multiply();
|
|
test_channel_math();
|
|
}
|
|
|
|
void test_mutable(boost::mpl::false_) {}
|
|
void test_mutable(boost::mpl::true_) {
|
|
channel_value_t mv=this->_min_v;
|
|
++this->_min_v; this->_min_v++;
|
|
--this->_min_v; this->_min_v--;
|
|
error_if(mv!=this->_min_v);
|
|
|
|
this->_min_v+=1;
|
|
this->_min_v-=1;
|
|
error_if(mv!=this->_min_v);
|
|
|
|
this->_min_v*=1;
|
|
this->_min_v/=1;
|
|
error_if(mv!=this->_min_v);
|
|
|
|
this->_min_v = 1; // assignable to scalar
|
|
this->_min_v = mv; // and to value type
|
|
|
|
// test swap
|
|
channel_value_t v1=this->_min_v;
|
|
channel_value_t v2=this->_max_v;
|
|
swap(this->_min_v, this->_max_v);
|
|
|
|
channel_value_t v3=this->_min_v;
|
|
channel_value_t v4=this->_max_v;
|
|
error_if(v1!=v4 || v2!=v3);
|
|
}
|
|
|
|
void test_channel_math() {
|
|
error_if(this->_min_v >= this->_max_v);
|
|
error_if(this->_max_v <= this->_min_v);
|
|
error_if(this->_min_v > this->_max_v);
|
|
error_if(this->_max_v < this->_min_v);
|
|
error_if(this->_max_v == this->_min_v);
|
|
error_if(!(this->_max_v != this->_min_v));
|
|
|
|
error_if(this->_min_v * 1 != this->_min_v);
|
|
error_if(this->_min_v / 1 != this->_min_v);
|
|
|
|
error_if((this->_min_v + 1) + 1 != (this->_min_v + 2));
|
|
error_if((this->_max_v - 1) - 1 != (this->_max_v - 2));
|
|
|
|
error_if(this->_min_v != 1 && this->_min_v==1); // comparable to integral
|
|
|
|
|
|
test_mutable(boost::mpl::bool_<channel_traits<channel_t>::is_mutable>());
|
|
}
|
|
|
|
|
|
void test_channel_invert() {
|
|
error_if(channel_invert(this->_min_v) != this->_max_v);
|
|
error_if(channel_invert(this->_max_v) != this->_min_v);
|
|
}
|
|
|
|
void test_channel_multiply() {
|
|
error_if(channel_multiply(this->_min_v, this->_min_v) != this->_min_v);
|
|
error_if(channel_multiply(this->_max_v, this->_max_v) != this->_max_v);
|
|
error_if(channel_multiply(this->_max_v, this->_min_v) != this->_min_v);
|
|
}
|
|
|
|
void test_channel_convert() {
|
|
channel_value_t v_min, v_max;
|
|
|
|
v_min=channel_convert<channel_t>(c8_min);
|
|
v_max=channel_convert<channel_t>(c8_max);
|
|
error_if(v_min!=this->_min_v || v_max!=this->_max_v);
|
|
|
|
v_min=channel_convert<channel_t>(c8s_min);
|
|
v_max=channel_convert<channel_t>(c8s_max);
|
|
error_if(v_min!=this->_min_v || v_max!=this->_max_v);
|
|
|
|
v_min=channel_convert<channel_t>(c16_min);
|
|
v_max=channel_convert<channel_t>(c16_max);
|
|
error_if(v_min!=this->_min_v || v_max!=this->_max_v);
|
|
|
|
v_min=channel_convert<channel_t>(c16s_min);
|
|
v_max=channel_convert<channel_t>(c16s_max);
|
|
error_if(v_min!=this->_min_v || v_max!=this->_max_v);
|
|
|
|
v_min=channel_convert<channel_t>(c32_min);
|
|
v_max=channel_convert<channel_t>(c32_max);
|
|
error_if(v_min!=this->_min_v || v_max!=this->_max_v);
|
|
|
|
v_min=channel_convert<channel_t>(c32s_min);
|
|
v_max=channel_convert<channel_t>(c32s_max);
|
|
error_if(v_min!=this->_min_v || v_max!=this->_max_v);
|
|
|
|
v_min=channel_convert<channel_t>(c32f_min);
|
|
v_max=channel_convert<channel_t>(c32f_max);
|
|
error_if(v_min!=this->_min_v || v_max!=this->_max_v);
|
|
}
|
|
};
|
|
|
|
// Different core classes depending on the different types of channels - channel values, references and subbyte references
|
|
// The cores ensure there are two members, _min_v and _max_v initialized with the minimum and maximum channel value.
|
|
// The different channel types have different ways to initialize them, thus require different cores
|
|
|
|
// For channel values simply initialize the value directly
|
|
template <typename ChannelValue>
|
|
class value_core {
|
|
protected:
|
|
typedef ChannelValue channel_t;
|
|
channel_t _min_v, _max_v;
|
|
|
|
value_core() : _min_v(channel_traits<ChannelValue>::min_value()), _max_v(channel_traits<ChannelValue>::max_value()) {
|
|
boost::function_requires<ChannelValueConcept<ChannelValue> >();
|
|
}
|
|
};
|
|
|
|
// For channel references we need to have separate channel values
|
|
template <typename ChannelRef>
|
|
class reference_core : public value_core<typename channel_traits<ChannelRef>::value_type> {
|
|
typedef value_core<typename channel_traits<ChannelRef>::value_type> parent_t;
|
|
protected:
|
|
typedef ChannelRef channel_t;
|
|
channel_t _min_v, _max_v;
|
|
|
|
reference_core() : parent_t(), _min_v(parent_t::_min_v), _max_v(parent_t::_max_v) {
|
|
boost::function_requires<ChannelConcept<ChannelRef> >();
|
|
}
|
|
};
|
|
|
|
// For subbyte channel references we need to store the bit buffers somewhere
|
|
template <typename ChannelSubbyteRef, typename ChannelMutableRef = ChannelSubbyteRef>
|
|
class packed_reference_core {
|
|
protected:
|
|
typedef ChannelSubbyteRef channel_t;
|
|
typedef typename channel_t::integer_t integer_t;
|
|
channel_t _min_v, _max_v;
|
|
|
|
integer_t _min_buf, _max_buf;
|
|
|
|
packed_reference_core() : _min_v(&_min_buf), _max_v(&_max_buf) {
|
|
ChannelMutableRef b1(&_min_buf), b2(&_max_buf);
|
|
b1 = channel_traits<channel_t>::min_value();
|
|
b2 = channel_traits<channel_t>::max_value();
|
|
|
|
boost::function_requires<ChannelConcept<ChannelSubbyteRef> >();
|
|
}
|
|
};
|
|
|
|
template <typename ChannelSubbyteRef, typename ChannelMutableRef = ChannelSubbyteRef>
|
|
class packed_dynamic_reference_core {
|
|
protected:
|
|
typedef ChannelSubbyteRef channel_t;
|
|
channel_t _min_v, _max_v;
|
|
|
|
typename channel_t::integer_t _min_buf, _max_buf;
|
|
|
|
packed_dynamic_reference_core(int first_bit1=1, int first_bit2=2) : _min_v(&_min_buf,first_bit1), _max_v(&_max_buf,first_bit2) {
|
|
ChannelMutableRef b1(&_min_buf,1), b2(&_max_buf,2);
|
|
b1 = channel_traits<channel_t>::min_value();
|
|
b2 = channel_traits<channel_t>::max_value();
|
|
|
|
boost::function_requires<ChannelConcept<ChannelSubbyteRef> >();
|
|
}
|
|
};
|
|
|
|
|
|
template <typename ChannelValue>
|
|
void test_channel_value() {
|
|
do_test<value_core<ChannelValue> >().test_all();
|
|
}
|
|
|
|
template <typename ChannelRef>
|
|
void test_channel_reference() {
|
|
do_test<reference_core<ChannelRef> >().test_all();
|
|
}
|
|
|
|
template <typename ChannelSubbyteRef>
|
|
void test_packed_channel_reference() {
|
|
do_test<packed_reference_core<ChannelSubbyteRef,ChannelSubbyteRef> >().test_all();
|
|
}
|
|
|
|
template <typename ChannelSubbyteRef, typename MutableRef>
|
|
void test_const_packed_channel_reference() {
|
|
do_test<packed_reference_core<ChannelSubbyteRef,MutableRef> >().test_all();
|
|
}
|
|
|
|
template <typename ChannelSubbyteRef>
|
|
void test_packed_dynamic_channel_reference() {
|
|
do_test<packed_dynamic_reference_core<ChannelSubbyteRef,ChannelSubbyteRef> >().test_all();
|
|
}
|
|
|
|
template <typename ChannelSubbyteRef, typename MutableRef>
|
|
void test_const_packed_dynamic_channel_reference() {
|
|
do_test<packed_dynamic_reference_core<ChannelSubbyteRef,MutableRef> >().test_all();
|
|
}
|
|
|
|
template <typename ChannelValue>
|
|
void test_channel_value_impl() {
|
|
test_channel_value<ChannelValue>();
|
|
test_channel_reference<ChannelValue&>();
|
|
test_channel_reference<const ChannelValue&>();
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////
|
|
///
|
|
/// A channel archetype - to test the minimum requirements of the concept
|
|
///
|
|
/////////////////////////////////////////////////////////
|
|
|
|
struct channel_value_archetype;
|
|
struct channel_archetype {
|
|
// equality comparable
|
|
friend bool operator==(const channel_archetype&,const channel_archetype&) { return true; }
|
|
friend bool operator!=(const channel_archetype&,const channel_archetype&) { return false; }
|
|
// less-than comparable
|
|
friend bool operator<(const channel_archetype&,const channel_archetype&) { return false; }
|
|
// convertible to a scalar
|
|
operator bits8() const { return 0; }
|
|
|
|
|
|
channel_archetype& operator++() { return *this; }
|
|
channel_archetype& operator--() { return *this; }
|
|
channel_archetype operator++(int) { return *this; }
|
|
channel_archetype operator--(int) { return *this; }
|
|
|
|
template <typename Scalar> channel_archetype operator+=(Scalar) { return *this; }
|
|
template <typename Scalar> channel_archetype operator-=(Scalar) { return *this; }
|
|
template <typename Scalar> channel_archetype operator*=(Scalar) { return *this; }
|
|
template <typename Scalar> channel_archetype operator/=(Scalar) { return *this; }
|
|
|
|
typedef channel_value_archetype value_type;
|
|
typedef channel_archetype reference;
|
|
typedef const channel_archetype const_reference;
|
|
typedef channel_value_archetype* pointer;
|
|
typedef const channel_value_archetype* const_pointer;
|
|
BOOST_STATIC_CONSTANT(bool, is_mutable=true);
|
|
|
|
static value_type min_value();
|
|
static value_type max_value();
|
|
};
|
|
|
|
|
|
struct channel_value_archetype : public channel_archetype {
|
|
channel_value_archetype() {} // default constructible
|
|
channel_value_archetype(const channel_value_archetype&) {} // copy constructible
|
|
channel_value_archetype& operator=(const channel_value_archetype&){return *this;} // assignable
|
|
channel_value_archetype(bits8) {}
|
|
};
|
|
|
|
channel_value_archetype channel_archetype::min_value() { return channel_value_archetype(); }
|
|
channel_value_archetype channel_archetype::max_value() { return channel_value_archetype(); }
|
|
|
|
|
|
void test_packed_channel_reference() {
|
|
typedef packed_channel_reference<boost::uint16_t, 0,5,true> channel16_0_5_reference_t;
|
|
typedef packed_channel_reference<boost::uint16_t, 5,6,true> channel16_5_6_reference_t;
|
|
typedef packed_channel_reference<boost::uint16_t, 11,5,true> channel16_11_5_reference_t;
|
|
|
|
boost::uint16_t data=0;
|
|
channel16_0_5_reference_t channel1(&data);
|
|
channel16_5_6_reference_t channel2(&data);
|
|
channel16_11_5_reference_t channel3(&data);
|
|
|
|
channel1=channel_traits<channel16_0_5_reference_t>::max_value();
|
|
channel2=channel_traits<channel16_5_6_reference_t>::max_value();
|
|
channel3=channel_traits<channel16_11_5_reference_t>::max_value();
|
|
error_if(data!=65535);
|
|
|
|
test_packed_channel_reference<channel16_0_5_reference_t>();
|
|
test_packed_channel_reference<channel16_5_6_reference_t>();
|
|
test_packed_channel_reference<channel16_11_5_reference_t>();
|
|
}
|
|
|
|
void test_packed_dynamic_channel_reference() {
|
|
typedef packed_dynamic_channel_reference<boost::uint16_t,5,true> channel16_5_reference_t;
|
|
typedef packed_dynamic_channel_reference<boost::uint16_t,6,true> channel16_6_reference_t;
|
|
|
|
boost::uint16_t data=0;
|
|
channel16_5_reference_t channel1(&data,0);
|
|
channel16_6_reference_t channel2(&data,5);
|
|
channel16_5_reference_t channel3(&data,11);
|
|
|
|
channel1=channel_traits<channel16_5_reference_t>::max_value();
|
|
channel2=channel_traits<channel16_6_reference_t>::max_value();
|
|
channel3=channel_traits<channel16_5_reference_t>::max_value();
|
|
error_if(data!=65535);
|
|
|
|
test_packed_dynamic_channel_reference<channel16_5_reference_t>();
|
|
}
|
|
|
|
void test_channel() {
|
|
test_channel_value_impl<bits8>();
|
|
test_channel_value_impl<bits8s>();
|
|
test_channel_value_impl<bits16>();
|
|
test_channel_value_impl<bits16s>();
|
|
test_channel_value_impl<bits32>();
|
|
test_channel_value_impl<bits32s>();
|
|
|
|
test_channel_value_impl<bits32f>();
|
|
|
|
test_packed_channel_reference();
|
|
test_packed_dynamic_channel_reference();
|
|
|
|
// Do only compile-time tests for the archetype (because asserts like val1<val2 fail)
|
|
boost::function_requires<MutableChannelConcept<channel_archetype> >();
|
|
|
|
do_test<value_core<channel_value_archetype> >();
|
|
do_test<reference_core<channel_archetype> >();
|
|
do_test<reference_core<const channel_archetype&> >();
|
|
}
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
test_channel();
|
|
}
|
|
|
|
// TODO:
|
|
// - provide algorithm performance overloads for scoped channel and packed channels
|
|
// - Update concepts and documentation
|
|
// - What to do about pointer types?!
|
|
// - Performance!!
|
|
// - is channel_convert the same as native?
|
|
// - is operator++ on bits32f the same as native? How about if operator++ is defined in scoped_channel to do _value++?
|