read.hpp 9.5 KB

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