write.hpp 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. //
  2. // Copyright 2012 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_BMP_DETAIL_WRITE_HPP
  9. #define BOOST_GIL_EXTENSION_IO_BMP_DETAIL_WRITE_HPP
  10. #include <boost/gil/extension/io/bmp/tags.hpp>
  11. #include <boost/gil/extension/io/bmp/detail/writer_backend.hpp>
  12. #include <boost/gil/io/base.hpp>
  13. #include <boost/gil/io/device.hpp>
  14. #include <boost/gil/io/dynamic_io_new.hpp>
  15. #include <vector>
  16. namespace boost { namespace gil {
  17. #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
  18. #pragma warning(push)
  19. #pragma warning(disable:4512) //assignment operator could not be generated
  20. #endif
  21. namespace detail {
  22. struct bmp_write_is_supported
  23. {
  24. template< typename View >
  25. struct apply
  26. : public is_write_supported< typename get_pixel_type< View >::type
  27. , bmp_tag
  28. >
  29. {};
  30. };
  31. template < int N > struct get_bgr_cs {};
  32. template <> struct get_bgr_cs< 1 > { using type = gray8_view_t; };
  33. template <> struct get_bgr_cs< 3 > { using type = bgr8_view_t; };
  34. template <> struct get_bgr_cs< 4 > { using type = bgra8_view_t; };
  35. } // namespace detail
  36. ///
  37. /// BMP Writer
  38. ///
  39. template< typename Device >
  40. class writer< Device
  41. , bmp_tag
  42. >
  43. : public writer_backend< Device
  44. , bmp_tag
  45. >
  46. {
  47. public:
  48. writer( const Device& io_dev
  49. , const image_write_info< bmp_tag >& info
  50. )
  51. : backend_t( io_dev
  52. , info
  53. )
  54. {}
  55. template<typename View>
  56. void apply( const View& view )
  57. {
  58. write( view );
  59. }
  60. private:
  61. using backend_t = writer_backend<Device, bmp_tag>;
  62. template< typename View >
  63. void write( const View& view )
  64. {
  65. // using channel_t = typename channel_type<
  66. // typename get_pixel_type<View>::type>::type;
  67. // using color_space_t = typename color_space_type<View>::type;
  68. // check if supported
  69. /*
  70. /// todo
  71. if( bmp_read_write_support_private<channel_t, color_space_t>::channel != 8)
  72. {
  73. io_error("Input view type is incompatible with the image type");
  74. }
  75. */
  76. // compute the file size
  77. int bpp = num_channels< View >::value * 8;
  78. int entries = 0;
  79. /*
  80. /// @todo: Not supported for now. bit_aligned_images refer to indexed images
  81. /// in this context.
  82. if( bpp <= 8 )
  83. {
  84. entries = 1u << bpp;
  85. }
  86. */
  87. std::size_t spn = ( view.width() * num_channels< View >::value + 3 ) & ~3;
  88. std::size_t ofs = bmp_header_size::_size
  89. + bmp_header_size::_win32_info_size
  90. + entries * 4;
  91. std::size_t siz = ofs + spn * view.height();
  92. // write the BMP file header
  93. this->_io_dev.write_uint16( bmp_signature );
  94. this->_io_dev.write_uint32( (uint32_t) siz );
  95. this->_io_dev.write_uint16( 0 );
  96. this->_io_dev.write_uint16( 0 );
  97. this->_io_dev.write_uint32( (uint32_t) ofs );
  98. // writes Windows information header
  99. this->_io_dev.write_uint32( bmp_header_size::_win32_info_size );
  100. this->_io_dev.write_uint32( static_cast< uint32_t >( view.width() ));
  101. this->_io_dev.write_uint32( static_cast< uint32_t >( view.height() ));
  102. this->_io_dev.write_uint16( 1 );
  103. this->_io_dev.write_uint16( static_cast< uint16_t >( bpp ));
  104. this->_io_dev.write_uint32( bmp_compression::_rgb );
  105. this->_io_dev.write_uint32( 0 );
  106. this->_io_dev.write_uint32( 0 );
  107. this->_io_dev.write_uint32( 0 );
  108. this->_io_dev.write_uint32( entries );
  109. this->_io_dev.write_uint32( 0 );
  110. write_image< View
  111. , typename detail::get_bgr_cs< num_channels< View >::value >::type
  112. >( view, spn );
  113. }
  114. template< typename View
  115. , typename BMP_View
  116. >
  117. void write_image( const View& view
  118. , const std::size_t spn
  119. )
  120. {
  121. byte_vector_t buffer( spn );
  122. std::fill( buffer.begin(), buffer.end(), 0 );
  123. BMP_View row = interleaved_view( view.width()
  124. , 1
  125. , (typename BMP_View::value_type*) &buffer.front()
  126. , spn
  127. );
  128. for( typename View::y_coord_t y = view.height() - 1; y > -1; --y )
  129. {
  130. copy_pixels( subimage_view( view
  131. , 0
  132. , (int) y
  133. , (int) view.width()
  134. , 1
  135. )
  136. , row
  137. );
  138. this->_io_dev.write( &buffer.front(), spn );
  139. }
  140. }
  141. };
  142. ///
  143. /// BMP Dynamic Image Writer
  144. ///
  145. template< typename Device >
  146. class dynamic_image_writer< Device
  147. , bmp_tag
  148. >
  149. : public writer< Device
  150. , bmp_tag
  151. >
  152. {
  153. using parent_t = writer<Device, bmp_tag>;
  154. public:
  155. dynamic_image_writer( const Device& io_dev
  156. , const image_write_info< bmp_tag >& info
  157. )
  158. : parent_t( io_dev
  159. , info
  160. )
  161. {}
  162. template< typename Views >
  163. void apply( const any_image_view< Views >& views )
  164. {
  165. detail::dynamic_io_fnobj< detail::bmp_write_is_supported
  166. , parent_t
  167. > op( this );
  168. apply_operation( views
  169. , op
  170. );
  171. }
  172. };
  173. #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
  174. #pragma warning(pop)
  175. #endif
  176. } // gil
  177. } // boost
  178. #endif