pixel.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. //
  2. // Copyright 2005-2007 Adobe Systems Incorporated
  3. //
  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
  7. //
  8. #include <boost/gil.hpp>
  9. #include <boost/core/ignore_unused.hpp>
  10. #include <boost/mp11.hpp>
  11. #include <exception>
  12. #include <iostream>
  13. #include <iterator>
  14. #include <type_traits>
  15. using namespace boost::gil;
  16. using std::swap;
  17. using namespace boost;
  18. void error_if(bool condition);
  19. struct increment {
  20. template <typename Incrementable> void operator()(Incrementable& x) const { ++x; }
  21. };
  22. struct prev
  23. {
  24. template <typename Subtractable>
  25. auto operator()(const Subtractable& x) const -> typename channel_traits<Subtractable>::value_type
  26. {
  27. using return_type = typename channel_traits<Subtractable>::value_type;
  28. return static_cast<return_type>(x - 1);
  29. }
  30. };
  31. struct set_to_one{ int operator()() const { return 1; } };
  32. // Construct with two pixel types. They must be compatible and the second must be mutable
  33. template <typename C1, typename C2>
  34. struct do_basic_test : public C1, public C2
  35. {
  36. using pixel1_t = typename C1::type;
  37. using pixel2_t = typename C2::type;
  38. using pixel1_value_t = typename C1::pixel_t::value_type;
  39. using pixel2_value_t = typename C2::pixel_t::value_type;
  40. using pixel_value_t = pixel1_value_t;
  41. do_basic_test(const pixel_value_t& v) : C1(v), C2(v) {}
  42. void test_all() {
  43. test_heterogeneous();
  44. // test homogeneous algorithms - fill, max, min
  45. static const int num_chan = num_channels<typename C2::pixel_t>::value;
  46. static_fill(C2::_pixel, gil::at_c<0>(C1::_pixel)+1);
  47. error_if(gil::at_c<0>(C2::_pixel) != gil::at_c<num_chan-1>(C2::_pixel));
  48. C2::_pixel = C1::_pixel;
  49. error_if(static_max(C2::_pixel) != static_max(C1::_pixel));
  50. error_if(static_min(C2::_pixel) != static_min(C1::_pixel));
  51. error_if(static_max(C2::_pixel) < static_min(C2::_pixel));
  52. // test operator[]
  53. C2::_pixel[0] = C1::_pixel[0]+1;
  54. error_if(C2::_pixel[0] != C1::_pixel[0]+1);
  55. }
  56. void test_heterogeneous() {
  57. // Both must be pixel types (not necessarily pixel values). The second must be mutable. They must be compatible
  58. boost::function_requires<PixelConcept<typename C1::pixel_t> >();
  59. boost::function_requires<MutablePixelConcept<typename C2::pixel_t> >();
  60. boost::function_requires<PixelsCompatibleConcept<typename C1::pixel_t,typename C2::pixel_t> >();
  61. C2::_pixel = C1::_pixel; // test operator=
  62. error_if(C1::_pixel != C2::_pixel); // test operator==
  63. // construct a pixel value from it
  64. pixel1_value_t v1(C1::_pixel);
  65. pixel2_value_t v2(C2::_pixel);
  66. error_if(v1 != v2);
  67. // construct from a pixel value
  68. pixel1_t c1(v1);
  69. pixel2_t c2(v2);
  70. error_if(c1 != c2);
  71. // Invert the first semantic channel.
  72. C2::_pixel = C1::_pixel;
  73. semantic_at_c<0>(C2::_pixel) = channel_invert(semantic_at_c<0>(C2::_pixel));
  74. error_if(C1::_pixel == C2::_pixel); // now they must not be equal
  75. // test pixel algorithms
  76. C2::_pixel = C1::_pixel;
  77. static_for_each(C2::_pixel, increment());
  78. static_transform(C2::_pixel, C2::_pixel, prev());
  79. error_if(C1::_pixel!=C2::_pixel);
  80. static_generate(C2::_pixel, set_to_one());
  81. error_if(gil::at_c<0>(C2::_pixel) != 1);
  82. // Test swap if both are mutable and if their value type is the same
  83. // (We know the second one is mutable)
  84. using p1_ref = typename boost::add_reference<typename C1::type>::type;
  85. using is_swappable = std::integral_constant
  86. <
  87. bool,
  88. pixel_reference_is_mutable<p1_ref>::value &&
  89. std::is_same<pixel1_value_t, pixel2_value_t>::value
  90. >;
  91. test_swap(is_swappable{});
  92. }
  93. void test_swap(std::false_type) {}
  94. void test_swap(std::true_type) {
  95. // test swap
  96. static_fill(C1::_pixel, 0);
  97. static_fill(C2::_pixel, 1);
  98. pixel_value_t pv1(C1::_pixel);
  99. pixel_value_t pv2(C2::_pixel);
  100. error_if(C2::_pixel == C1::_pixel);
  101. swap(C1::_pixel, C2::_pixel);
  102. error_if(C1::_pixel != pv2 || C2::_pixel != pv1);
  103. }
  104. };
  105. template <typename PixelValue, int Tag=0>
  106. class value_core
  107. {
  108. public:
  109. using type = PixelValue;
  110. using pixel_t = type;
  111. type _pixel;
  112. value_core() : _pixel(0) {}
  113. value_core(const type& val) : _pixel(val) { // test copy constructor
  114. boost::function_requires<PixelValueConcept<pixel_t> >();
  115. type p2; // test default constructor
  116. boost::ignore_unused(p2);
  117. }
  118. };
  119. template <typename PixelRef, int Tag=0>
  120. class reference_core : public value_core<typename std::remove_reference<PixelRef>::type::value_type, Tag>
  121. {
  122. public:
  123. using type = PixelRef;
  124. using pixel_t = typename boost::remove_reference<PixelRef>::type;
  125. using parent_t = value_core<typename pixel_t::value_type, Tag>;
  126. type _pixel;
  127. reference_core() : parent_t(), _pixel(parent_t::_pixel) {}
  128. reference_core(const typename pixel_t::value_type& val) : parent_t(val), _pixel(parent_t::_pixel) {
  129. boost::function_requires<PixelConcept<pixel_t> >();
  130. }
  131. };
  132. // Use a subset of pixel models that covers all color spaces, channel depths, reference/value, planar/interleaved, const/mutable
  133. // color conversion will be invoked on pairs of them. Having an exhaustive binary check would be too big/expensive.
  134. using representative_pixels_t = mp11::mp_list
  135. <
  136. value_core<gray8_pixel_t>,
  137. reference_core<gray16_pixel_t&>,
  138. value_core<bgr8_pixel_t>,
  139. reference_core<rgb8_planar_ref_t>,
  140. value_core<argb32_pixel_t>,
  141. reference_core<cmyk32f_pixel_t&>,
  142. reference_core<abgr16c_ref_t>, // immutable reference
  143. reference_core<rgb32fc_planar_ref_t>
  144. >;
  145. template <typename Pixel1>
  146. struct ccv2 {
  147. template <typename P1, typename P2>
  148. void color_convert_compatible(const P1& p1, P2& p2, std::true_type) {
  149. using value_t = typename P1::value_type;
  150. p2 = p1;
  151. value_t converted;
  152. color_convert(p1, converted);
  153. error_if(converted != p2);
  154. }
  155. template <typename P1, typename P2>
  156. void color_convert_compatible(const P1& p1, P2& p2, std::false_type) {
  157. color_convert(p1,p2);
  158. }
  159. template <typename P1, typename P2>
  160. void color_convert_impl(const P1& p1, P2& p2) {
  161. using is_compatible = typename pixels_are_compatible<P1,P2>::type;
  162. color_convert_compatible(p1, p2, is_compatible());
  163. }
  164. template <typename Pixel2>
  165. void operator()(Pixel2) {
  166. // convert from Pixel1 to Pixel2 (or, if Pixel2 is immutable, to its value type)
  167. using p2_is_mutable = pixel_reference_is_mutable<typename Pixel2::type>;
  168. using pixel_model_t = typename std::remove_reference<typename Pixel2::type>::type;
  169. using p2_value_t = typename pixel_model_t::value_type;
  170. using pixel2_mutable = mp11::mp_if<p2_is_mutable, Pixel2, value_core<p2_value_t>>;
  171. Pixel1 p1;
  172. pixel2_mutable p2;
  173. color_convert_impl(p1._pixel, p2._pixel);
  174. }
  175. };
  176. struct ccv1 {
  177. template <typename Pixel>
  178. void operator()(Pixel) {
  179. mp11::mp_for_each<representative_pixels_t>(ccv2<Pixel>());
  180. }
  181. };
  182. void test_color_convert() {
  183. mp11::mp_for_each<representative_pixels_t>(ccv1());
  184. }
  185. void test_packed_pixel()
  186. {
  187. using rgb565_pixel_t = packed_pixel_type<uint16_t, mp11::mp_list_c<unsigned,5,6,5>, rgb_layout_t>::type;
  188. boost::function_requires<PixelValueConcept<rgb565_pixel_t> >();
  189. static_assert(sizeof(rgb565_pixel_t) == 2, "");
  190. // define a bgr556 pixel
  191. using bgr556_pixel_t = packed_pixel_type<uint16_t, mp11::mp_list_c<unsigned,5,6,5>, bgr_layout_t>::type;
  192. boost::function_requires<PixelValueConcept<bgr556_pixel_t> >();
  193. // Create a zero packed pixel and a full regular unpacked pixel.
  194. rgb565_pixel_t r565;//((uint16_t)0);
  195. rgb8_pixel_t rgb_full(255,255,255);
  196. // Convert all channels of the unpacked pixel to the packed one & ensure the packed one is full
  197. get_color(r565,red_t()) = channel_convert<kth_element_type<rgb565_pixel_t, 0>::type>(get_color(rgb_full,red_t()));
  198. get_color(r565,green_t()) = channel_convert<kth_element_type<rgb565_pixel_t, 1>::type>(get_color(rgb_full,green_t()));
  199. get_color(r565,blue_t()) = channel_convert<kth_element_type<rgb565_pixel_t, 2>::type>(get_color(rgb_full,blue_t()));
  200. error_if(r565 != rgb565_pixel_t((uint16_t)65535));
  201. // rgb565 is compatible with bgr556. Test interoperability
  202. boost::function_requires<PixelsCompatibleConcept<rgb565_pixel_t,bgr556_pixel_t> >();
  203. do_basic_test<value_core<rgb565_pixel_t,0>, value_core<bgr556_pixel_t,1> >(r565).test_heterogeneous();
  204. color_convert(r565,rgb_full);
  205. color_convert(rgb_full,r565);
  206. // Test bit-aligned pixel reference
  207. using bgr121_ref_t = const bit_aligned_pixel_reference<std::uint8_t, mp11::mp_list_c<int,1,2,1>, bgr_layout_t, true>;
  208. using rgb121_ref_t = const bit_aligned_pixel_reference<std::uint8_t, mp11::mp_list_c<int,1,2,1>, rgb_layout_t, true>;
  209. using rgb121_pixel_t = rgb121_ref_t::value_type;
  210. rgb121_pixel_t p121;
  211. do_basic_test<reference_core<bgr121_ref_t,0>, reference_core<rgb121_ref_t,1> >(p121).test_heterogeneous();
  212. do_basic_test<value_core<rgb121_pixel_t,0>, reference_core<rgb121_ref_t,1> >(p121).test_heterogeneous();
  213. static_assert(pixel_reference_is_proxy<rgb8_planar_ref_t>::value, "");
  214. static_assert(pixel_reference_is_proxy<bgr121_ref_t>::value, "");
  215. static_assert(!pixel_reference_is_proxy<rgb8_pixel_t>::value, "");
  216. static_assert(!pixel_reference_is_proxy<rgb8_pixel_t&>::value, "");
  217. static_assert(!pixel_reference_is_proxy<rgb8_pixel_t const&>::value, "");
  218. static_assert(pixel_reference_is_mutable<rgb8_pixel_t&>::value, "");
  219. static_assert(!pixel_reference_is_mutable<rgb8_pixel_t const&>::value, "");
  220. static_assert(pixel_reference_is_mutable<rgb8_planar_ref_t>::value, "");
  221. static_assert(pixel_reference_is_mutable<rgb8_planar_ref_t const&>::value, "");
  222. static_assert(!pixel_reference_is_mutable<rgb8c_planar_ref_t>::value, "");
  223. static_assert(!pixel_reference_is_mutable<rgb8c_planar_ref_t const&>::value, "");
  224. static_assert(pixel_reference_is_mutable<bgr121_ref_t>::value, "");
  225. static_assert(!pixel_reference_is_mutable<bgr121_ref_t::const_reference>::value, "");
  226. }
  227. void test_pixel() {
  228. test_packed_pixel();
  229. rgb8_pixel_t rgb8(1,2,3);
  230. do_basic_test<value_core<rgb8_pixel_t,0>, reference_core<rgb8_pixel_t&,1> >(rgb8).test_all();
  231. do_basic_test<value_core<bgr8_pixel_t,0>, reference_core<rgb8_planar_ref_t,1> >(rgb8).test_all();
  232. do_basic_test<reference_core<rgb8_planar_ref_t,0>, reference_core<bgr8_pixel_t&,1> >(rgb8).test_all();
  233. do_basic_test<reference_core<const rgb8_pixel_t&,0>, reference_core<rgb8_pixel_t&,1> >(rgb8).test_all();
  234. test_color_convert();
  235. // Semantic vs physical channel accessors. Named channel accessors
  236. bgr8_pixel_t bgr8(rgb8);
  237. error_if(bgr8[0] == rgb8[0]);
  238. error_if(dynamic_at_c(bgr8,0) == dynamic_at_c(rgb8,0));
  239. error_if(gil::at_c<0>(bgr8) == gil::at_c<0>(rgb8));
  240. error_if(semantic_at_c<0>(bgr8) != semantic_at_c<0>(rgb8));
  241. error_if(get_color(bgr8,blue_t()) != get_color(rgb8,blue_t()));
  242. // Assigning a grayscale channel to a pixel
  243. gray16_pixel_t g16(34);
  244. g16 = 8;
  245. uint16_t g = get_color(g16,gray_color_t());
  246. error_if(g != 8);
  247. error_if(g16 != 8);
  248. }
  249. int main()
  250. {
  251. try
  252. {
  253. test_pixel();
  254. return EXIT_SUCCESS;
  255. }
  256. catch (std::exception const& e)
  257. {
  258. std::cerr << e.what() << std::endl;
  259. return EXIT_FAILURE;
  260. }
  261. catch (...)
  262. {
  263. return EXIT_FAILURE;
  264. }
  265. }