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