Imported Upstream version 1.72.0
[platform/upstream/boost.git] / boost / gil / extension / io / raw / detail / read.hpp
1 //
2 // Copyright 2012 Olivier Tournaire, Christian Henning
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_RAW_DETAIL_READ_HPP
9 #define BOOST_GIL_EXTENSION_IO_RAW_DETAIL_READ_HPP
10
11 #include <boost/gil/extension/io/raw/tags.hpp>
12 #include <boost/gil/extension/io/raw/detail/device.hpp>
13 #include <boost/gil/extension/io/raw/detail/is_allowed.hpp>
14 #include <boost/gil/extension/io/raw/detail/reader_backend.hpp>
15
16 #include <boost/gil/io/base.hpp>
17 #include <boost/gil/io/bit_operations.hpp>
18 #include <boost/gil/io/conversion_policies.hpp>
19 #include <boost/gil/io/device.hpp>
20 #include <boost/gil/io/dynamic_io_new.hpp>
21 #include <boost/gil/io/reader_base.hpp>
22 #include <boost/gil/io/row_buffer_helper.hpp>
23 #include <boost/gil/io/typedefs.hpp>
24
25 #include <cstdio>
26 #include <sstream>
27 #include <type_traits>
28 #include <vector>
29
30 namespace boost { namespace gil {
31
32 #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
33 #pragma warning(push)
34 #pragma warning(disable:4512) //assignment operator could not be generated
35 #endif
36
37 #define BUILD_INTERLEAVED_VIEW(color_layout, bits_per_pixel) \
38 { \
39     color_layout##bits_per_pixel##_view_t build = boost::gil::interleaved_view(processed_image->width, \
40                                                                              processed_image->height, \
41                                                                              (color_layout##bits_per_pixel##_pixel_t*)processed_image->data, \
42                                                                              processed_image->colors*processed_image->width*processed_image->bits/8); \
43     this->_cc_policy.read( build.begin(), build.end(), dst_view.begin() ); \
44 } \
45
46
47 template< typename Device
48         , typename ConversionPolicy
49         >
50 class reader< Device
51             , raw_tag
52             , ConversionPolicy
53             >
54     : public reader_base< raw_tag
55                         , ConversionPolicy
56                         >
57     , public reader_backend< Device
58                            , raw_tag
59                            >
60 {
61 private:
62
63     using this_t = reader<Device, raw_tag, ConversionPolicy>;
64     using cc_t = typename ConversionPolicy::color_converter_type;
65
66 public:
67
68     using backend_t = reader_backend<Device, raw_tag>;
69
70     //
71     // Constructor
72     //
73     reader( const Device&                         io_dev
74           , const image_read_settings< raw_tag >& settings
75           )
76     : backend_t( io_dev
77                , settings
78                )
79     {}
80
81     //
82     // Constructor
83     //
84     reader( const Device&                         io_dev
85           , const cc_t&                           cc
86           , const image_read_settings< raw_tag >& settings
87           )
88     : reader_base< raw_tag
89                  , ConversionPolicy
90                  >( cc )
91     , backend_t( io_dev
92                , settings
93                )
94     {}
95
96     template< typename View >
97     void apply( const View& dst_view )
98     {
99         if( this->_info._valid == false )
100         {
101             io_error( "Image header was not read." );
102         }
103
104         using is_read_and_convert_t = typename std::is_same
105             <
106                 ConversionPolicy,
107                 detail::read_and_no_convert
108             >::type;
109
110         io_error_if( !detail::is_allowed< View >( this->_info
111                                                 , is_read_and_convert_t()
112                                                 )
113                    , "Image types aren't compatible."
114                    );
115
116         // TODO: better error handling based on return code
117         int return_code = this->_io_dev.unpack();
118         io_error_if( return_code != LIBRAW_SUCCESS, "Unable to unpack image" );
119         this->_info._unpack_function_name = this->_io_dev.get_unpack_function_name();
120
121         return_code = this->_io_dev.dcraw_process();
122         io_error_if( return_code != LIBRAW_SUCCESS, "Unable to emulate dcraw behavior to process image" );
123
124         libraw_processed_image_t* processed_image = this->_io_dev.dcraw_make_mem_image(&return_code);
125         io_error_if( return_code != LIBRAW_SUCCESS, "Unable to dcraw_make_mem_image" );
126
127         if(processed_image->colors!=1 && processed_image->colors!=3)
128             io_error( "Image is neither gray nor RGB" );
129
130         if(processed_image->bits!=8 && processed_image->bits!=16)
131             io_error( "Image is neither 8bit nor 16bit" );
132
133         // TODO Olivier Tournaire
134         // Here, we should use a metafunction to reduce code size and avoid a (compile time) macro
135         if(processed_image->bits==8)
136         {
137             if(processed_image->colors==1){ BUILD_INTERLEAVED_VIEW(gray, 8); }
138             else                          { BUILD_INTERLEAVED_VIEW(rgb,  8); }
139         }
140         else if(processed_image->bits==16)
141         {
142             if(processed_image->colors==1){ BUILD_INTERLEAVED_VIEW(gray, 16); }
143             else                          { BUILD_INTERLEAVED_VIEW(rgb,  16); }
144         }
145     }
146 };
147
148 namespace detail {
149
150 struct raw_read_is_supported
151 {
152     template< typename View >
153     struct apply : public is_read_supported< typename get_pixel_type< View >::type
154                                            , raw_tag
155                                            >
156     {};
157 };
158
159 struct raw_type_format_checker
160 {
161     raw_type_format_checker( const image_read_info< raw_tag >& info )
162     : _info( info )
163     {}
164
165     template< typename Image >
166     bool apply()
167     {
168         using view_t = typename Image::view_t;
169         return is_allowed<view_t>(_info, std::true_type{});
170     }
171
172 private:
173     ///todo: do we need this here. Should be part of reader_backend
174     const image_read_info< raw_tag >& _info;
175 };
176
177 } // namespace detail
178
179 ///
180 /// RAW Dynamic Reader
181 ///
182 template< typename Device >
183 class dynamic_image_reader< Device
184                           , raw_tag
185                           >
186     : public reader< Device
187                    , raw_tag
188                    , detail::read_and_no_convert
189                    >
190 {
191     using parent_t = reader<Device, raw_tag, detail::read_and_no_convert>;
192
193 public:
194
195     dynamic_image_reader( const Device&                         io_dev
196                         , const image_read_settings< raw_tag >& settings
197                         )
198     : parent_t( io_dev
199               , settings
200               )
201     {}
202
203     template< typename Images >
204     void apply( any_image< Images >& images )
205     {
206         detail::raw_type_format_checker format_checker( this->_info );
207
208         if( !construct_matched( images
209                                , format_checker
210                                ))
211         {
212             std::ostringstream error_message;
213             error_message << "No matching image type between those of the given any_image and that of the file.\n";
214             error_message << "Image type must be {gray||rgb}{8||16} unsigned for RAW image files.";
215             io_error( error_message.str().c_str() );
216         }
217         else
218         {
219             if( !this->_info._valid )
220               this->read_header();
221             this->init_image(images, this->_settings);
222
223             detail::dynamic_io_fnobj< detail::raw_read_is_supported
224                                     , parent_t
225                                     > op( this );
226
227             apply_operation( view( images )
228                             , op
229                             );
230         }
231     }
232 };
233
234 #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
235 #pragma warning(pop)
236 #endif
237
238 } // gil
239 } // boost
240
241 #endif