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_PNG_DETAIL_WRITE_HPP 9 #define BOOST_GIL_EXTENSION_IO_PNG_DETAIL_WRITE_HPP 10 11 #include <boost/gil/extension/io/png/detail/writer_backend.hpp> 12 13 #include <boost/gil/io/device.hpp> 14 #include <boost/gil/io/dynamic_io_new.hpp> 15 #include <boost/gil/io/row_buffer_helper.hpp> 16 #include <boost/gil/detail/mp11.hpp> 17 18 #include <type_traits> 19 20 namespace boost { namespace gil { 21 22 #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) 23 #pragma warning(push) 24 #pragma warning(disable:4512) //assignment operator could not be generated 25 #endif 26 27 namespace detail { 28 29 struct png_write_is_supported 30 { 31 template< typename View > 32 struct apply 33 : public is_write_supported< typename get_pixel_type< View >::type 34 , png_tag 35 > 36 {}; 37 }; 38 39 } // namespace detail 40 41 /// 42 /// PNG Writer 43 /// 44 template< typename Device > 45 class writer< Device 46 , png_tag 47 > 48 : public writer_backend< Device 49 , png_tag 50 > 51 { 52 53 public: 54 55 using backend_t = writer_backend<Device, png_tag>; 56 writer(const Device & io_dev,const image_write_info<png_tag> & info)57 writer( const Device& io_dev 58 , const image_write_info< png_tag >& info 59 ) 60 : backend_t( io_dev 61 , info 62 ) 63 {} 64 65 66 template< typename View > apply(const View & view)67 void apply( const View& view ) 68 { 69 io_error_if( view.width() == 0 && view.height() == 0 70 , "png format cannot handle empty views." 71 ); 72 73 this->write_header( view ); 74 75 write_view( view 76 , typename is_bit_aligned< typename View::value_type >::type() 77 ); 78 } 79 80 private: 81 82 template<typename View> write_view(const View & view,std::false_type)83 void write_view( const View& view 84 , std::false_type // is bit aligned 85 ) 86 { 87 using pixel_t = typename get_pixel_type<View>::type; 88 89 using png_rw_info = detail::png_write_support 90 < 91 typename channel_type<pixel_t>::type, 92 typename color_space_type<pixel_t>::type 93 >; 94 95 if( little_endian() ) 96 { 97 set_swap< png_rw_info >(); 98 } 99 100 std::vector< pixel< typename channel_type< View >::type 101 , layout<typename color_space_type< View >::type > 102 > 103 > row_buffer( view.width() ); 104 105 for( int y = 0; y != view.height(); ++ y) 106 { 107 std::copy( view.row_begin( y ) 108 , view.row_end ( y ) 109 , row_buffer.begin() 110 ); 111 112 png_write_row( this->get_struct() 113 , reinterpret_cast< png_bytep >( row_buffer.data() ) 114 ); 115 } 116 117 png_write_end( this->get_struct() 118 , this->get_info() 119 ); 120 } 121 122 template<typename View> write_view(const View & view,std::true_type)123 void write_view( const View& view 124 , std::true_type // is bit aligned 125 ) 126 { 127 using png_rw_info = detail::png_write_support 128 < 129 typename kth_semantic_element_type<typename View::value_type, 0>::type, 130 typename color_space_type<View>::type 131 >; 132 133 if (little_endian() ) 134 { 135 set_swap< png_rw_info >(); 136 } 137 138 detail::row_buffer_helper_view< View > row_buffer( view.width() 139 , false 140 ); 141 142 for( int y = 0; y != view.height(); ++y ) 143 { 144 std::copy( view.row_begin( y ) 145 , view.row_end ( y ) 146 , row_buffer.begin() 147 ); 148 149 png_write_row( this->get_struct() 150 , reinterpret_cast< png_bytep >( row_buffer.data() ) 151 ); 152 } 153 154 png_free_data( this->get_struct() 155 , this->get_info() 156 , PNG_FREE_UNKN 157 , -1 158 ); 159 160 png_write_end( this->get_struct() 161 , this->get_info() 162 ); 163 } 164 165 template<typename Info> 166 struct is_less_than_eight : mp11::mp_less 167 < 168 std::integral_constant<int, Info::_bit_depth>, 169 std::integral_constant<int, 8> 170 > 171 {}; 172 173 template<typename Info> 174 struct is_equal_to_sixteen : mp11::mp_less 175 < 176 std::integral_constant<int, Info::_bit_depth>, 177 std::integral_constant<int, 16> 178 > 179 {}; 180 181 template <typename Info> set_swap(typename std::enable_if<is_less_than_eight<Info>::value>::type * =0)182 void set_swap(typename std::enable_if<is_less_than_eight<Info>::value>::type* /*ptr*/ = 0) 183 { 184 png_set_packswap(this->get_struct()); 185 } 186 187 template <typename Info> set_swap(typename std::enable_if<is_equal_to_sixteen<Info>::value>::type * =0)188 void set_swap(typename std::enable_if<is_equal_to_sixteen<Info>::value>::type* /*ptr*/ = 0) 189 { 190 png_set_swap(this->get_struct()); 191 } 192 193 template <typename Info> set_swap(typename std::enable_if<mp11::mp_and<mp11::mp_not<is_less_than_eight<Info>>,mp11::mp_not<is_equal_to_sixteen<Info>>>::value>::type * =nullptr)194 void set_swap( 195 typename std::enable_if 196 < 197 mp11::mp_and 198 < 199 mp11::mp_not<is_less_than_eight<Info>>, 200 mp11::mp_not<is_equal_to_sixteen<Info>> 201 >::value 202 >::type* /*ptr*/ = nullptr) 203 { 204 } 205 }; 206 207 /// 208 /// PNG Dynamic Image Writer 209 /// 210 template< typename Device > 211 class dynamic_image_writer< Device 212 , png_tag 213 > 214 : public writer< Device 215 , png_tag 216 > 217 { 218 using parent_t = writer<Device, png_tag>; 219 220 public: 221 dynamic_image_writer(const Device & io_dev,const image_write_info<png_tag> & info)222 dynamic_image_writer( const Device& io_dev 223 , const image_write_info< png_tag >& info 224 ) 225 : parent_t( io_dev 226 , info 227 ) 228 {} 229 230 template< typename ...Views > apply(const any_image_view<Views...> & views)231 void apply( const any_image_view< Views... >& views ) 232 { 233 detail::dynamic_io_fnobj< detail::png_write_is_supported 234 , parent_t 235 > op( this ); 236 237 apply_operation( views, op ); 238 } 239 }; 240 241 #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) 242 #pragma warning(pop) 243 #endif 244 245 } // namespace gil 246 } // namespace boost 247 248 #endif 249