1 //
2 // Copyright 2008 Christian Henning, Lubomir Bourdev
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 #ifndef BOOST_GIL_EXTENSION_IO_TIFF_DETAIL_IS_ALLOWED_HPP
9 #define BOOST_GIL_EXTENSION_IO_TIFF_DETAIL_IS_ALLOWED_HPP
10 
11 #include <boost/gil/extension/io/tiff/tags.hpp>
12 #include <boost/gil/extension/toolbox/metafunctions/is_bit_aligned.hpp>
13 #include <boost/gil/detail/mp11.hpp>
14 #include <boost/gil/io/base.hpp>
15 
16 #include <type_traits>
17 
18 namespace boost { namespace gil { namespace detail {
19 
20 using channel_sizes_t = std::vector<tiff_bits_per_sample::type>;
21 
22 template <typename View, typename Channel, typename Enable = void>
23 struct Format_Type {};
24 
25 // is_bit_aligned< View >
26 template <typename View, typename Channel>
27 struct Format_Type
28 <
29     View,
30     Channel,
31     typename std::enable_if
32     <
33         is_bit_aligned
34         <
35             typename get_pixel_type<View>::type
36         >::value
37     >::type
38 >
39 {
40     static const int value = SAMPLEFORMAT_UINT;
41 };
42 
43 // is_not_bit_aligned< View > && is_unsigned< Channel >
44 template <typename View, typename Channel>
45 struct Format_Type
46 <
47     View,
48     Channel,
49     typename std::enable_if
50     <
51         mp11::mp_and
52         <
53             mp11::mp_not
54             <
55                 typename is_bit_aligned<typename get_pixel_type<View>::type>::type
56             >,
57             std::is_unsigned<Channel>
58         >::value
59     >::type
60 >
61 {
62     static const int value = SAMPLEFORMAT_UINT;
63 };
64 
65 // is_not_bit_aligned< View > && is_signed< Channel >
66 template <typename View, typename Channel>
67 struct Format_Type
68 <
69     View,
70     Channel,
71     typename std::enable_if
72     <
73         mp11::mp_and
74         <
75             mp11::mp_not
76             <
77                 typename is_bit_aligned<typename get_pixel_type<View>::type>::type
78             >,
79             std::is_signed<Channel>
80         >::value
81     >::type
82 >
83 {
84     static const int value = SAMPLEFORMAT_INT;
85 };
86 
87 // is_not_bit_aligned< View > && is_floating_point< Channel >
88 template <typename View, typename Channel>
89 struct Format_Type
90 <
91     View,
92     Channel,
93     typename std::enable_if
94     <
95         mp11::mp_and
96         <
97             mp11::mp_not
98             <
99                 typename is_bit_aligned<typename get_pixel_type<View>::type>::type
100             >,
101             is_floating_point<Channel>
102         >::value
103     >::type
104 >
105 {
106     static const int value = SAMPLEFORMAT_IEEEFP;
107 };
108 
109 //template< typename Channel >
110 //int format_value( std::true_type ) // is_bit_aligned
111 //{
112 //    return SAMPLEFORMAT_UINT;
113 //}
114 //
115 //template< typename Channel >
116 //int format_value( std::false_type ) // is_bit_aligned
117 //{
118 //    if( is_unsigned< Channel >::value )
119 //    {
120 //        return SAMPLEFORMAT_UINT;
121 //    }
122 //
123 //    if( is_signed< Channel >::value )
124 //    {
125 //        return SAMPLEFORMAT_INT;
126 //    }
127 //
128 //    else if( is_floating_point< Channel >::value )
129 //    {
130 //        return SAMPLEFORMAT_IEEEFP;
131 //    }
132 //
133 //    io_error( "Unkown channel format." );
134 //}
135 
136 // The following two functions look the same but are different since one is using
137 // a pixel_t as template parameter whereas the other is using reference_t.
138 template< typename View >
compare_channel_sizes(const channel_sizes_t & channel_sizes,std::false_type,std::true_type)139 bool compare_channel_sizes( const channel_sizes_t& channel_sizes // in bits
140                           , std::false_type                      // is_bit_aligned
141                           , std::true_type                       // is_homogeneous
142                           )
143 {
144     using pixel_t = typename View::value_type;
145     using channel_t = typename channel_traits<typename element_type<pixel_t>::type>::value_type;
146 
147     unsigned int s = detail::unsigned_integral_num_bits< channel_t >::value;
148 
149     return ( s == channel_sizes[0] );
150 }
151 
152 
153 template< typename View >
compare_channel_sizes(const channel_sizes_t & channel_sizes,std::true_type,std::true_type)154 bool compare_channel_sizes( const channel_sizes_t& channel_sizes // in bits
155                           , std::true_type                       // is_bit_aligned
156                           , std::true_type                       // is_homogeneous
157                           )
158 {
159     using ref_t = typename View::reference;
160     using channel_t = typename channel_traits<typename element_type<ref_t>::type>::value_type;
161 
162     unsigned int s = detail::unsigned_integral_num_bits< channel_t >::value;
163     return ( s == channel_sizes[0] );
164 }
165 
166 struct compare_channel_sizes_fn
167 {
compare_channel_sizes_fnboost::gil::detail::compare_channel_sizes_fn168     compare_channel_sizes_fn( uint16_t* a )
169     : _a( a )
170     , _b( true )
171     {}
172 
173     template< typename ChannelSize >
operator ()boost::gil::detail::compare_channel_sizes_fn174     void operator()( ChannelSize x)
175     {
176         if( x != *_a++ )
177         {
178             _b = false;
179         }
180     }
181 
182     uint16_t* _a;
183     bool _b;
184 };
185 
186 template< typename T >
187 struct channel_sizes_type {};
188 
189 template< typename B, typename C, typename L, bool M >
190 struct channel_sizes_type< bit_aligned_pixel_reference< B, C, L, M > > { using type = C; };
191 
192 template< typename B, typename C, typename L, bool M >
193 struct channel_sizes_type< const bit_aligned_pixel_reference< B, C, L, M > > { using type = C; };
194 
195 template< typename View >
compare_channel_sizes(channel_sizes_t & channel_sizes,std::true_type,std::false_type)196 bool compare_channel_sizes( channel_sizes_t& channel_sizes // in bits
197                           , std::true_type                 // is_bit_aligned
198                           , std::false_type                // is_homogeneous
199                           )
200 {
201     // loop through all channels and compare
202 
203     using ref_t = typename View::reference;
204     using cs_t = typename channel_sizes_type<ref_t>::type;
205 
206     compare_channel_sizes_fn fn( &channel_sizes.front() );
207     mp11::mp_for_each<cs_t>(fn);
208 
209     return fn._b;
210 }
211 
212 template< typename View >
is_allowed(const image_read_info<tiff_tag> & info,std::true_type)213 bool is_allowed( const image_read_info< tiff_tag >& info
214                , std::true_type // is read_and_no_convert
215                )
216 {
217     channel_sizes_t channel_sizes( info._samples_per_pixel
218                                  , info._bits_per_sample
219                                  );
220 
221     using pixel_t = typename get_pixel_type<View>::type;
222     using channel_t = typename channel_traits<typename element_type<pixel_t>::type>::value_type;
223 
224     using num_channel_t = typename num_channels<pixel_t>::value_type;
225 
226     const num_channel_t dst_samples_per_pixel = num_channels< pixel_t >::value;
227 
228     //const num_channel_t dst_sample_format     = format_value< channel_t >( typename is_bit_aligned< pixel_t >::type() );
229     const num_channel_t dst_sample_format     = Format_Type<View, channel_t>::value;
230 
231 
232     return (  dst_samples_per_pixel == info._samples_per_pixel
233            && compare_channel_sizes< View >( channel_sizes
234                                            , typename is_bit_aligned< pixel_t >::type()
235                                            , typename is_homogeneous< pixel_t >::type()
236                                            )
237            && dst_sample_format == info._sample_format
238            );
239 }
240 
241 template< typename View >
is_allowed(const image_read_info<tiff_tag> &,std::false_type)242 bool is_allowed( const image_read_info< tiff_tag >& /* info */
243                , std::false_type // is read_and_no_convert
244                )
245 {
246     return true;
247 }
248 
249 } // namespace detail
250 } // namespace gil
251 } // namespace boost
252 
253 #endif
254