// // Copyright 2005-2007 Adobe Systems Incorporated // // Distributed under 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 // #include #include #include #include #include #include #include using namespace boost::gil; using std::swap; using namespace boost; void error_if(bool condition); struct increment { template void operator()(Incrementable& x) const { ++x; } }; struct prev { template auto operator()(const Subtractable& x) const -> typename channel_traits::value_type { using return_type = typename channel_traits::value_type; return static_cast(x - 1); } }; struct set_to_one{ int operator()() const { return 1; } }; // Construct with two pixel types. They must be compatible and the second must be mutable template struct do_basic_test : public C1, public C2 { using pixel1_t = typename C1::type; using pixel2_t = typename C2::type; using pixel1_value_t = typename C1::pixel_t::value_type; using pixel2_value_t = typename C2::pixel_t::value_type; using pixel_value_t = pixel1_value_t; do_basic_test(const pixel_value_t& v) : C1(v), C2(v) {} void test_all() { test_heterogeneous(); // test homogeneous algorithms - fill, max, min static const int num_chan = num_channels::value; static_fill(C2::_pixel, gil::at_c<0>(C1::_pixel)+1); error_if(gil::at_c<0>(C2::_pixel) != gil::at_c(C2::_pixel)); C2::_pixel = C1::_pixel; error_if(static_max(C2::_pixel) != static_max(C1::_pixel)); error_if(static_min(C2::_pixel) != static_min(C1::_pixel)); error_if(static_max(C2::_pixel) < static_min(C2::_pixel)); // test operator[] C2::_pixel[0] = C1::_pixel[0]+1; error_if(C2::_pixel[0] != C1::_pixel[0]+1); } void test_heterogeneous() { // Both must be pixel types (not necessarily pixel values). The second must be mutable. They must be compatible boost::function_requires >(); boost::function_requires >(); boost::function_requires >(); C2::_pixel = C1::_pixel; // test operator= error_if(C1::_pixel != C2::_pixel); // test operator== // construct a pixel value from it pixel1_value_t v1(C1::_pixel); pixel2_value_t v2(C2::_pixel); error_if(v1 != v2); // construct from a pixel value pixel1_t c1(v1); pixel2_t c2(v2); error_if(c1 != c2); // Invert the first semantic channel. C2::_pixel = C1::_pixel; semantic_at_c<0>(C2::_pixel) = channel_invert(semantic_at_c<0>(C2::_pixel)); error_if(C1::_pixel == C2::_pixel); // now they must not be equal // test pixel algorithms C2::_pixel = C1::_pixel; static_for_each(C2::_pixel, increment()); static_transform(C2::_pixel, C2::_pixel, prev()); error_if(C1::_pixel!=C2::_pixel); static_generate(C2::_pixel, set_to_one()); error_if(gil::at_c<0>(C2::_pixel) != 1); // Test swap if both are mutable and if their value type is the same // (We know the second one is mutable) using p1_ref = typename boost::add_reference::type; using is_swappable = std::integral_constant < bool, pixel_reference_is_mutable::value && std::is_same::value >; test_swap(is_swappable{}); } void test_swap(std::false_type) {} void test_swap(std::true_type) { // test swap static_fill(C1::_pixel, 0); static_fill(C2::_pixel, 1); pixel_value_t pv1(C1::_pixel); pixel_value_t pv2(C2::_pixel); error_if(C2::_pixel == C1::_pixel); swap(C1::_pixel, C2::_pixel); error_if(C1::_pixel != pv2 || C2::_pixel != pv1); } }; template class value_core { public: using type = PixelValue; using pixel_t = type; type _pixel; value_core() : _pixel(0) {} value_core(const type& val) : _pixel(val) { // test copy constructor boost::function_requires >(); type p2; // test default constructor boost::ignore_unused(p2); } }; template class reference_core : public value_core::type::value_type, Tag> { public: using type = PixelRef; using pixel_t = typename boost::remove_reference::type; using parent_t = value_core; type _pixel; reference_core() : parent_t(), _pixel(parent_t::_pixel) {} reference_core(const typename pixel_t::value_type& val) : parent_t(val), _pixel(parent_t::_pixel) { boost::function_requires >(); } }; // Use a subset of pixel models that covers all color spaces, channel depths, reference/value, planar/interleaved, const/mutable // color conversion will be invoked on pairs of them. Having an exhaustive binary check would be too big/expensive. using representative_pixels_t = mp11::mp_list < value_core, reference_core, value_core, reference_core, value_core, reference_core, reference_core, // immutable reference reference_core >; template struct ccv2 { template void color_convert_compatible(const P1& p1, P2& p2, std::true_type) { using value_t = typename P1::value_type; p2 = p1; value_t converted; color_convert(p1, converted); error_if(converted != p2); } template void color_convert_compatible(const P1& p1, P2& p2, std::false_type) { color_convert(p1,p2); } template void color_convert_impl(const P1& p1, P2& p2) { using is_compatible = typename pixels_are_compatible::type; color_convert_compatible(p1, p2, is_compatible()); } template void operator()(Pixel2) { // convert from Pixel1 to Pixel2 (or, if Pixel2 is immutable, to its value type) using p2_is_mutable = pixel_reference_is_mutable; using pixel_model_t = typename std::remove_reference::type; using p2_value_t = typename pixel_model_t::value_type; using pixel2_mutable = mp11::mp_if>; Pixel1 p1; pixel2_mutable p2; color_convert_impl(p1._pixel, p2._pixel); } }; struct ccv1 { template void operator()(Pixel) { mp11::mp_for_each(ccv2()); } }; void test_color_convert() { mp11::mp_for_each(ccv1()); } void test_packed_pixel() { using rgb565_pixel_t = packed_pixel_type, rgb_layout_t>::type; boost::function_requires >(); static_assert(sizeof(rgb565_pixel_t) == 2, ""); // define a bgr556 pixel using bgr556_pixel_t = packed_pixel_type, bgr_layout_t>::type; boost::function_requires >(); // Create a zero packed pixel and a full regular unpacked pixel. rgb565_pixel_t r565;//((uint16_t)0); rgb8_pixel_t rgb_full(255,255,255); // Convert all channels of the unpacked pixel to the packed one & ensure the packed one is full get_color(r565,red_t()) = channel_convert::type>(get_color(rgb_full,red_t())); get_color(r565,green_t()) = channel_convert::type>(get_color(rgb_full,green_t())); get_color(r565,blue_t()) = channel_convert::type>(get_color(rgb_full,blue_t())); error_if(r565 != rgb565_pixel_t((uint16_t)65535)); // rgb565 is compatible with bgr556. Test interoperability boost::function_requires >(); do_basic_test, value_core >(r565).test_heterogeneous(); color_convert(r565,rgb_full); color_convert(rgb_full,r565); // Test bit-aligned pixel reference using bgr121_ref_t = const bit_aligned_pixel_reference, bgr_layout_t, true>; using rgb121_ref_t = const bit_aligned_pixel_reference, rgb_layout_t, true>; using rgb121_pixel_t = rgb121_ref_t::value_type; rgb121_pixel_t p121; do_basic_test, reference_core >(p121).test_heterogeneous(); do_basic_test, reference_core >(p121).test_heterogeneous(); static_assert(pixel_reference_is_proxy::value, ""); static_assert(pixel_reference_is_proxy::value, ""); static_assert(!pixel_reference_is_proxy::value, ""); static_assert(!pixel_reference_is_proxy::value, ""); static_assert(!pixel_reference_is_proxy::value, ""); static_assert(pixel_reference_is_mutable::value, ""); static_assert(!pixel_reference_is_mutable::value, ""); static_assert(pixel_reference_is_mutable::value, ""); static_assert(pixel_reference_is_mutable::value, ""); static_assert(!pixel_reference_is_mutable::value, ""); static_assert(!pixel_reference_is_mutable::value, ""); static_assert(pixel_reference_is_mutable::value, ""); static_assert(!pixel_reference_is_mutable::value, ""); } void test_pixel() { test_packed_pixel(); rgb8_pixel_t rgb8(1,2,3); do_basic_test, reference_core >(rgb8).test_all(); do_basic_test, reference_core >(rgb8).test_all(); do_basic_test, reference_core >(rgb8).test_all(); do_basic_test, reference_core >(rgb8).test_all(); test_color_convert(); // Semantic vs physical channel accessors. Named channel accessors bgr8_pixel_t bgr8(rgb8); error_if(bgr8[0] == rgb8[0]); error_if(dynamic_at_c(bgr8,0) == dynamic_at_c(rgb8,0)); error_if(gil::at_c<0>(bgr8) == gil::at_c<0>(rgb8)); error_if(semantic_at_c<0>(bgr8) != semantic_at_c<0>(rgb8)); error_if(get_color(bgr8,blue_t()) != get_color(rgb8,blue_t())); // Assigning a grayscale channel to a pixel gray16_pixel_t g16(34); g16 = 8; uint16_t g = get_color(g16,gray_color_t()); error_if(g != 8); error_if(g16 != 8); } int main() { try { test_pixel(); return EXIT_SUCCESS; } catch (std::exception const& e) { std::cerr << e.what() << std::endl; return EXIT_FAILURE; } catch (...) { return EXIT_FAILURE; } }