File indexing completed on 2025-12-16 09:51:47
0001
0002
0003
0004
0005
0006
0007
0008 #ifndef BOOST_GIL_EXTENSION_IO_PNG_DETAIL_WRITE_HPP
0009 #define BOOST_GIL_EXTENSION_IO_PNG_DETAIL_WRITE_HPP
0010
0011 #include <boost/gil/extension/io/png/detail/writer_backend.hpp>
0012
0013 #include <boost/gil/io/device.hpp>
0014 #include <boost/gil/io/detail/dynamic.hpp>
0015 #include <boost/gil/io/row_buffer_helper.hpp>
0016 #include <boost/gil/detail/mp11.hpp>
0017
0018 #include <type_traits>
0019
0020 namespace boost { namespace gil {
0021
0022 #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
0023 #pragma warning(push)
0024 #pragma warning(disable:4512)
0025 #endif
0026
0027 namespace detail {
0028
0029 struct png_write_is_supported
0030 {
0031 template< typename View >
0032 struct apply
0033 : public is_write_supported< typename get_pixel_type< View >::type
0034 , png_tag
0035 >
0036 {};
0037 };
0038
0039 }
0040
0041
0042
0043
0044 template< typename Device >
0045 class writer< Device
0046 , png_tag
0047 >
0048 : public writer_backend< Device
0049 , png_tag
0050 >
0051 {
0052
0053 public:
0054
0055 using backend_t = writer_backend<Device, png_tag>;
0056
0057 writer( const Device& io_dev
0058 , const image_write_info< png_tag >& info
0059 )
0060 : backend_t( io_dev
0061 , info
0062 )
0063 {}
0064
0065
0066 template< typename View >
0067 void apply( const View& view )
0068 {
0069 io_error_if( view.width() == 0 && view.height() == 0
0070 , "png format cannot handle empty views."
0071 );
0072
0073 this->write_header( view );
0074
0075 write_view( view
0076 , typename is_bit_aligned< typename View::value_type >::type()
0077 );
0078 }
0079
0080 private:
0081
0082 template<typename View>
0083 void write_view( const View& view
0084 , std::false_type
0085 )
0086 {
0087 using pixel_t = typename get_pixel_type<View>::type;
0088
0089 using png_rw_info = detail::png_write_support
0090 <
0091 typename channel_type<pixel_t>::type,
0092 typename color_space_type<pixel_t>::type
0093 >;
0094
0095 if( little_endian() )
0096 {
0097 set_swap< png_rw_info >();
0098 }
0099
0100 std::vector< pixel< typename channel_type< View >::type
0101 , layout<typename color_space_type< View >::type >
0102 >
0103 > row_buffer( view.width() );
0104
0105 for( int y = 0; y != view.height(); ++ y)
0106 {
0107 std::copy( view.row_begin( y )
0108 , view.row_end ( y )
0109 , row_buffer.begin()
0110 );
0111
0112 png_write_row( this->get_struct()
0113 , reinterpret_cast< png_bytep >( row_buffer.data() )
0114 );
0115 }
0116
0117 png_write_end( this->get_struct()
0118 , this->get_info()
0119 );
0120 }
0121
0122 template<typename View>
0123 void write_view( const View& view
0124 , std::true_type
0125 )
0126 {
0127 using png_rw_info = detail::png_write_support
0128 <
0129 typename kth_semantic_element_type<typename View::value_type, 0>::type,
0130 typename color_space_type<View>::type
0131 >;
0132
0133 if (little_endian() )
0134 {
0135 set_swap< png_rw_info >();
0136 }
0137
0138 detail::row_buffer_helper_view< View > row_buffer( view.width()
0139 , false
0140 );
0141
0142 for( int y = 0; y != view.height(); ++y )
0143 {
0144 std::copy( view.row_begin( y )
0145 , view.row_end ( y )
0146 , row_buffer.begin()
0147 );
0148
0149 png_write_row( this->get_struct()
0150 , reinterpret_cast< png_bytep >( row_buffer.data() )
0151 );
0152 }
0153
0154 png_free_data( this->get_struct()
0155 , this->get_info()
0156 , PNG_FREE_UNKN
0157 , -1
0158 );
0159
0160 png_write_end( this->get_struct()
0161 , this->get_info()
0162 );
0163 }
0164
0165 template<typename Info>
0166 struct is_less_than_eight : mp11::mp_less
0167 <
0168 std::integral_constant<int, Info::_bit_depth>,
0169 std::integral_constant<int, 8>
0170 >
0171 {};
0172
0173 template<typename Info>
0174 struct is_equal_to_sixteen : mp11::mp_and
0175 <
0176 mp11::mp_not
0177 <
0178 mp11::mp_less
0179 <
0180 std::integral_constant<int, Info::_bit_depth>,
0181 std::integral_constant<int, 16>
0182 >
0183 >,
0184 mp11::mp_not
0185 <
0186 mp11::mp_less
0187 <
0188 std::integral_constant<int, 16>,
0189 std::integral_constant<int, Info::_bit_depth>
0190 >
0191 >
0192 >
0193 {};
0194
0195 template <typename Info>
0196 void set_swap(typename std::enable_if<is_less_than_eight<Info>::value>::type* = 0)
0197 {
0198 png_set_packswap(this->get_struct());
0199 }
0200
0201 template <typename Info>
0202 void set_swap(typename std::enable_if<is_equal_to_sixteen<Info>::value>::type* = 0)
0203 {
0204 png_set_swap(this->get_struct());
0205 }
0206
0207 template <typename Info>
0208 void set_swap(
0209 typename std::enable_if
0210 <
0211 mp11::mp_and
0212 <
0213 mp11::mp_not<is_less_than_eight<Info>>,
0214 mp11::mp_not<is_equal_to_sixteen<Info>>
0215 >::value
0216 >::type* = nullptr)
0217 {
0218 }
0219 };
0220
0221
0222
0223
0224 template< typename Device >
0225 class dynamic_image_writer< Device
0226 , png_tag
0227 >
0228 : public writer< Device
0229 , png_tag
0230 >
0231 {
0232 using parent_t = writer<Device, png_tag>;
0233
0234 public:
0235
0236 dynamic_image_writer( const Device& io_dev
0237 , const image_write_info< png_tag >& info
0238 )
0239 : parent_t( io_dev
0240 , info
0241 )
0242 {}
0243
0244 template< typename ...Views >
0245 void apply( const any_image_view< Views... >& views )
0246 {
0247 detail::dynamic_io_fnobj< detail::png_write_is_supported
0248 , parent_t
0249 > op( this );
0250
0251 variant2::visit( op, views );
0252 }
0253 };
0254
0255 #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
0256 #pragma warning(pop)
0257 #endif
0258
0259 }
0260 }
0261
0262 #endif