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 // reader(const Device & io_dev,const image_read_settings<raw_tag> & settings)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 // reader(const Device & io_dev,const cc_t & cc,const image_read_settings<raw_tag> & settings)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 > apply(const View & dst_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 { raw_type_format_checkerboost::gil::detail::raw_type_format_checker161 raw_type_format_checker( const image_read_info< raw_tag >& info ) 162 : _info( info ) 163 {} 164 165 template< typename Image > applyboost::gil::detail::raw_type_format_checker166 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 dynamic_image_reader(const Device & io_dev,const image_read_settings<raw_tag> & settings)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 > apply(any_image<Images> & 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 242