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