read.hpp 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317
  1. //
  2. // Copyright 2007-2012 Christian Henning, Andreas Pokorny, 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_JPEG_DETAIL_READ_HPP
  9. #define BOOST_GIL_EXTENSION_IO_JPEG_DETAIL_READ_HPP
  10. #include <boost/gil/extension/io/jpeg/tags.hpp>
  11. #include <boost/gil/extension/io/jpeg/detail/base.hpp>
  12. #include <boost/gil/extension/io/jpeg/detail/is_allowed.hpp>
  13. #include <boost/gil/io/base.hpp>
  14. #include <boost/gil/io/conversion_policies.hpp>
  15. #include <boost/gil/io/device.hpp>
  16. #include <boost/gil/io/dynamic_io_new.hpp>
  17. #include <boost/gil/io/reader_base.hpp>
  18. #include <boost/gil/io/typedefs.hpp>
  19. #include <csetjmp>
  20. #include <type_traits>
  21. #include <vector>
  22. namespace boost { namespace gil {
  23. #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
  24. #pragma warning(push)
  25. #pragma warning(disable:4512) //assignment operator could not be generated
  26. #pragma warning(disable:4611) //interaction between '_setjmp' and C++ object destruction is non-portable
  27. #endif
  28. ///
  29. /// JPEG Reader
  30. ///
  31. template< typename Device
  32. , typename ConversionPolicy
  33. >
  34. class reader< Device
  35. , jpeg_tag
  36. , ConversionPolicy
  37. >
  38. : public reader_base< jpeg_tag
  39. , ConversionPolicy
  40. >
  41. , public reader_backend< Device
  42. , jpeg_tag
  43. >
  44. {
  45. private:
  46. using this_t = reader<Device, jpeg_tag, ConversionPolicy>;
  47. using cc_t = typename ConversionPolicy::color_converter_type;
  48. public:
  49. using backend_t = reader_backend<Device, jpeg_tag>;
  50. public:
  51. //
  52. // Constructor
  53. //
  54. reader( const Device& io_dev
  55. , const image_read_settings< jpeg_tag >& settings
  56. )
  57. : reader_base< jpeg_tag
  58. , ConversionPolicy
  59. >()
  60. , backend_t( io_dev
  61. , settings
  62. )
  63. {}
  64. //
  65. // Constructor
  66. //
  67. reader( const Device& io_dev
  68. , const typename ConversionPolicy::color_converter_type& cc
  69. , const image_read_settings< jpeg_tag >& settings
  70. )
  71. : reader_base< jpeg_tag
  72. , ConversionPolicy
  73. >( cc )
  74. , backend_t( io_dev
  75. , settings
  76. )
  77. {}
  78. template<typename View>
  79. void apply( const View& view )
  80. {
  81. // Fire exception in case of error.
  82. if( setjmp( this->_mark ))
  83. {
  84. this->raise_error();
  85. }
  86. this->get()->dct_method = this->_settings._dct_method;
  87. using is_read_and_convert_t = typename std::is_same
  88. <
  89. ConversionPolicy,
  90. detail::read_and_no_convert
  91. >::type;
  92. io_error_if( !detail::is_allowed< View >( this->_info
  93. , is_read_and_convert_t()
  94. )
  95. , "Image types aren't compatible."
  96. );
  97. if( jpeg_start_decompress( this->get() ) == false )
  98. {
  99. io_error( "Cannot start decompression." );
  100. }
  101. switch( this->_info._color_space )
  102. {
  103. case JCS_GRAYSCALE:
  104. {
  105. this->_scanline_length = this->_info._width;
  106. read_rows< gray8_pixel_t >( view );
  107. break;
  108. }
  109. case JCS_RGB:
  110. //!\todo add Y'CbCr? We loose image quality when reading JCS_YCbCr as JCS_RGB
  111. case JCS_YCbCr:
  112. {
  113. this->_scanline_length = this->_info._width * num_channels< rgb8_view_t >::value;
  114. read_rows< rgb8_pixel_t >( view );
  115. break;
  116. }
  117. case JCS_CMYK:
  118. //!\todo add Y'CbCrK? We loose image quality when reading JCS_YCCK as JCS_CMYK
  119. case JCS_YCCK:
  120. {
  121. this->get()->out_color_space = JCS_CMYK;
  122. this->_scanline_length = this->_info._width * num_channels< cmyk8_view_t >::value;
  123. read_rows< cmyk8_pixel_t >( view );
  124. break;
  125. }
  126. default: { io_error( "Unsupported jpeg color space." ); }
  127. }
  128. jpeg_finish_decompress ( this->get() );
  129. }
  130. private:
  131. template< typename ImagePixel
  132. , typename View
  133. >
  134. void read_rows( const View& view )
  135. {
  136. using buffer_t = std::vector<ImagePixel>;
  137. buffer_t buffer( this->_info._width );
  138. // In case of an error we'll jump back to here and fire an exception.
  139. // @todo Is the buffer above cleaned up when the exception is thrown?
  140. // The strategy right now is to allocate necessary memory before
  141. // the setjmp.
  142. if( setjmp( this->_mark ))
  143. {
  144. this->raise_error();
  145. }
  146. JSAMPLE *row_adr = reinterpret_cast< JSAMPLE* >( &buffer[0] );
  147. //Skip scanlines if necessary.
  148. for( int y = 0; y < this->_settings._top_left.y; ++y )
  149. {
  150. io_error_if( jpeg_read_scanlines( this->get()
  151. , &row_adr
  152. , 1
  153. ) !=1
  154. , "jpeg_read_scanlines: fail to read JPEG file"
  155. );
  156. }
  157. // Read data.
  158. for( int y = 0; y < view.height(); ++y )
  159. {
  160. io_error_if( jpeg_read_scanlines( this->get()
  161. , &row_adr
  162. , 1
  163. ) != 1
  164. , "jpeg_read_scanlines: fail to read JPEG file"
  165. );
  166. typename buffer_t::iterator beg = buffer.begin() + this->_settings._top_left.x;
  167. typename buffer_t::iterator end = beg + this->_settings._dim.x;
  168. this->_cc_policy.read( beg
  169. , end
  170. , view.row_begin( y )
  171. );
  172. }
  173. //@todo: There might be a better way to do that.
  174. while( this->get()->output_scanline < this->get()->image_height )
  175. {
  176. io_error_if( jpeg_read_scanlines( this->get()
  177. , &row_adr
  178. , 1
  179. ) !=1
  180. , "jpeg_read_scanlines: fail to read JPEG file"
  181. );
  182. }
  183. }
  184. };
  185. namespace detail {
  186. struct jpeg_type_format_checker
  187. {
  188. jpeg_type_format_checker( jpeg_color_space::type color_space )
  189. : _color_space( color_space )
  190. {}
  191. template< typename Image >
  192. bool apply()
  193. {
  194. return is_read_supported< typename get_pixel_type< typename Image::view_t >::type
  195. , jpeg_tag
  196. >::_color_space == _color_space;
  197. }
  198. private:
  199. jpeg_color_space::type _color_space;
  200. };
  201. struct jpeg_read_is_supported
  202. {
  203. template< typename View >
  204. struct apply : public is_read_supported< typename get_pixel_type< View >::type
  205. , jpeg_tag
  206. >
  207. {};
  208. };
  209. } // namespace detail
  210. ///
  211. /// JPEG Dynamic Reader
  212. ///
  213. template< typename Device >
  214. class dynamic_image_reader< Device
  215. , jpeg_tag
  216. >
  217. : public reader< Device
  218. , jpeg_tag
  219. , detail::read_and_no_convert
  220. >
  221. {
  222. using parent_t = reader<Device, jpeg_tag, detail::read_and_no_convert>;
  223. public:
  224. dynamic_image_reader( const Device& io_dev
  225. , const image_read_settings< jpeg_tag >& settings
  226. )
  227. : parent_t( io_dev
  228. , settings
  229. )
  230. {}
  231. template< typename Images >
  232. void apply( any_image< Images >& images )
  233. {
  234. detail::jpeg_type_format_checker format_checker( this->_info._color_space != JCS_YCbCr
  235. ? this->_info._color_space
  236. : JCS_RGB
  237. );
  238. if( !construct_matched( images
  239. , format_checker
  240. ))
  241. {
  242. io_error( "No matching image type between those of the given any_image and that of the file" );
  243. }
  244. else
  245. {
  246. this->init_image( images
  247. , this->_settings
  248. );
  249. detail::dynamic_io_fnobj< detail::jpeg_read_is_supported
  250. , parent_t
  251. > op( this );
  252. apply_operation( view( images )
  253. , op
  254. );
  255. }
  256. }
  257. };
  258. #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
  259. #pragma warning(pop)
  260. #endif
  261. } // gil
  262. } // boost
  263. #endif