Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:36:57

0001 //
0002 // Copyright 2007-2012 Christian Henning, Andreas Pokorny, Lubomir Bourdev
0003 //
0004 // Distributed under the Boost Software License, Version 1.0
0005 // See accompanying file LICENSE_1_0.txt or copy at
0006 // http://www.boost.org/LICENSE_1_0.txt
0007 //
0008 #ifndef BOOST_GIL_EXTENSION_IO_PNG_DETAIL_READ_HPP
0009 #define BOOST_GIL_EXTENSION_IO_PNG_DETAIL_READ_HPP
0010 
0011 #include <boost/gil/extension/io/png/tags.hpp>
0012 #include <boost/gil/extension/io/png/detail/reader_backend.hpp>
0013 #include <boost/gil/extension/io/png/detail/is_allowed.hpp>
0014 
0015 #include <boost/gil.hpp> // FIXME: Include what you use!
0016 #include <boost/gil/io/detail/dynamic.hpp>
0017 #include <boost/gil/io/base.hpp>
0018 #include <boost/gil/io/conversion_policies.hpp>
0019 #include <boost/gil/io/device.hpp>
0020 #include <boost/gil/io/error.hpp>
0021 #include <boost/gil/io/reader_base.hpp>
0022 #include <boost/gil/io/row_buffer_helper.hpp>
0023 #include <boost/gil/io/typedefs.hpp>
0024 
0025 #include <type_traits>
0026 
0027 namespace boost { namespace gil {
0028 
0029 #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
0030 #pragma warning(push)
0031 #pragma warning(disable:4512) //assignment operator could not be generated
0032 #endif
0033 
0034 ///
0035 /// PNG Reader
0036 ///
0037 template< typename Device
0038         , typename ConversionPolicy
0039         >
0040 class reader< Device
0041             , png_tag
0042             , ConversionPolicy
0043             >
0044     : public reader_base< png_tag
0045                         , ConversionPolicy >
0046     , public reader_backend< Device
0047                            , png_tag
0048                            >
0049 {
0050 private:
0051 
0052     using this_t = reader<Device, png_tag, ConversionPolicy>;
0053     using cc_t = typename ConversionPolicy::color_converter_type;
0054 
0055 public:
0056 
0057     using backend_t = reader_backend<Device, png_tag>;
0058 
0059 public:
0060 
0061     reader( const Device&                         io_dev
0062           , const image_read_settings< png_tag >& settings
0063           )
0064     : reader_base< png_tag
0065                  , ConversionPolicy
0066                  >()
0067     , backend_t( io_dev
0068                , settings
0069                )
0070     {}
0071 
0072     reader( const Device&                                          io_dev
0073           , const typename ConversionPolicy::color_converter_type& cc
0074           , const image_read_settings< png_tag >&                  settings
0075           )
0076     : reader_base< png_tag
0077                  , ConversionPolicy
0078                  >( cc )
0079     , backend_t( io_dev
0080                , settings
0081                )
0082     {}
0083 
0084     template< typename View >
0085     void apply( const View& view )
0086     {
0087         // guard from errors in the following functions
0088         if (setjmp( png_jmpbuf( this->get_struct() )))
0089         {
0090             io_error("png is invalid");
0091         }
0092 
0093         // The info structures are filled at this point.
0094 
0095         // Now it's time for some transformations.
0096 
0097         if( little_endian() )
0098         {
0099             if( this->_info._bit_depth == 16 )
0100             {
0101                 // Swap bytes of 16 bit files to least significant byte first.
0102                 png_set_swap( this->get_struct() );
0103             }
0104 
0105             if( this->_info._bit_depth < 8 )
0106             {
0107                 // swap bits of 1, 2, 4 bit packed pixel formats
0108                 png_set_packswap( this->get_struct() );
0109             }
0110         }
0111 
0112         if( this->_info._color_type == PNG_COLOR_TYPE_PALETTE )
0113         {
0114             png_set_palette_to_rgb( this->get_struct() );
0115         }
0116 
0117         if( png_get_valid( this->get_struct(), this->get_info(), PNG_INFO_tRNS ) )
0118         {
0119             png_set_tRNS_to_alpha( this->get_struct() );
0120         }
0121 
0122         // Tell libpng to handle the gamma conversion for you.  The final call
0123         // is a good guess for PC generated images, but it should be configurable
0124         // by the user at run time by the user.  It is strongly suggested that
0125         // your application support gamma correction.
0126         if( this->_settings._apply_screen_gamma )
0127         {
0128             // png_set_gamma will change the image data!
0129 
0130 #ifdef BOOST_GIL_IO_PNG_FLOATING_POINT_SUPPORTED
0131         png_set_gamma( this->get_struct()
0132                      , this->_settings._screen_gamma
0133                      , this->_info._file_gamma
0134                      );
0135 #else
0136         png_set_gamma( this->get_struct()
0137                      , this->_settings._screen_gamma
0138                      , this->_info._file_gamma
0139                      );
0140 #endif // BOOST_GIL_IO_PNG_FLOATING_POINT_SUPPORTED
0141         }
0142 
0143         // Turn on interlace handling.  REQUIRED if you are not using
0144         // png_read_image().  To see how to handle interlacing passes,
0145         // see the png_read_row() method below:
0146         this->_number_passes = png_set_interlace_handling( this->get_struct() );
0147 
0148 
0149         // The above transformation might have changed the bit_depth and color type.
0150         png_read_update_info( this->get_struct()
0151                             , this->get_info()
0152                             );
0153 
0154         this->_info._bit_depth = png_get_bit_depth( this->get_struct()
0155                                                   , this->get_info()
0156                                                   );
0157 
0158         this->_info._num_channels = png_get_channels( this->get_struct()
0159                                                     , this->get_info()
0160                                                     );
0161 
0162         this->_info._color_type = png_get_color_type( this->get_struct()
0163                                                     , this->get_info()
0164                                                     );
0165 
0166         this->_scanline_length = png_get_rowbytes( this->get_struct()
0167                                                  , this->get_info()
0168                                                  );
0169 
0170         switch( this->_info._color_type )
0171         {
0172             case PNG_COLOR_TYPE_GRAY:
0173             {
0174                 switch( this->_info._bit_depth )
0175                 {
0176                     case  1: read_rows< gray1_image_t::view_t::reference >( view ); break;
0177                     case  2: read_rows< gray2_image_t::view_t::reference >( view ); break;
0178                     case  4: read_rows< gray4_image_t::view_t::reference >( view ); break;
0179                     case  8: read_rows< gray8_pixel_t  >( view ); break;
0180                     case 16: read_rows< gray16_pixel_t >( view ); break;
0181                     default: io_error( "png_reader::read_data(): unknown combination of color type and bit depth" );
0182                 }
0183 
0184                 break;
0185             }
0186             case PNG_COLOR_TYPE_GA:
0187             {
0188                 #ifdef BOOST_GIL_IO_ENABLE_GRAY_ALPHA
0189                 switch( this->_info._bit_depth )
0190                 {
0191                     case  8: read_rows< gray_alpha8_pixel_t > ( view ); break;
0192                     case 16: read_rows< gray_alpha16_pixel_t >( view ); break;
0193                     default: io_error( "png_reader::read_data(): unknown combination of color type and bit depth" );
0194                 }
0195                 #else
0196                     io_error( "gray_alpha isn't enabled. Define BOOST_GIL_IO_ENABLE_GRAY_ALPHA when building application." );
0197                 #endif // BOOST_GIL_IO_ENABLE_GRAY_ALPHA
0198 
0199 
0200                 break;
0201             }
0202             case PNG_COLOR_TYPE_RGB:
0203             {
0204                 switch( this->_info._bit_depth )
0205                 {
0206                     case 8:  read_rows< rgb8_pixel_t > ( view ); break;
0207                     case 16: read_rows< rgb16_pixel_t >( view ); break;
0208                     default: io_error( "png_reader::read_data(): unknown combination of color type and bit depth" );
0209                 }
0210 
0211                 break;
0212             }
0213             case PNG_COLOR_TYPE_RGBA:
0214             {
0215                 switch( this->_info._bit_depth )
0216                 {
0217                     case  8: read_rows< rgba8_pixel_t > ( view ); break;
0218                     case 16: read_rows< rgba16_pixel_t >( view ); break;
0219                     default: io_error( "png_reader_color_convert::read_data(): unknown combination of color type and bit depth" );
0220                 }
0221 
0222                 break;
0223             }
0224             default: io_error( "png_reader_color_convert::read_data(): unknown color type" );
0225         }
0226 
0227         // read rest of file, and get additional chunks in info_ptr
0228         png_read_end( this->get_struct()
0229                     , nullptr
0230                     );
0231     }
0232 
0233 private:
0234 
0235     template< typename ImagePixel
0236             , typename View
0237             >
0238     void read_rows( const View& view )
0239     {
0240         // guard from errors in the following functions
0241         if (setjmp( png_jmpbuf( this->get_struct() )))
0242         {
0243             io_error("png is invalid");
0244         }
0245 
0246         using row_buffer_helper_t = detail::row_buffer_helper_view<ImagePixel>;
0247 
0248         using it_t = typename row_buffer_helper_t::iterator_t;
0249 
0250         using is_read_and_convert_t = typename std::is_same
0251             <
0252                 ConversionPolicy,
0253                 detail::read_and_no_convert
0254             >::type;
0255 
0256         io_error_if( !detail::is_allowed< View >( this->_info
0257                                                 , is_read_and_convert_t()
0258                                                 )
0259                    , "Image types aren't compatible."
0260                    );
0261 
0262         std::size_t rowbytes = png_get_rowbytes( this->get_struct()
0263                                                , this->get_info()
0264                                                );
0265 
0266         row_buffer_helper_t buffer( rowbytes
0267                                   , true
0268                                   );
0269 
0270         png_bytep row_ptr = (png_bytep)( &( buffer.data()[0]));
0271 
0272         for( std::size_t pass = 0; pass < this->_number_passes; pass++ )
0273         {
0274             if( pass == this->_number_passes - 1 )
0275             {
0276                 // skip lines if necessary
0277                 for( std::ptrdiff_t y = 0; y < this->_settings._top_left.y; ++y )
0278                 {
0279                     // Read the image using the "sparkle" effect.
0280                     png_read_rows( this->get_struct()
0281                                  , &row_ptr
0282                                  , nullptr
0283                                  , 1
0284                                  );
0285                 }
0286 
0287                 for( std::ptrdiff_t y = 0
0288                    ; y < this->_settings._dim.y
0289                    ; ++y
0290                    )
0291                 {
0292                     // Read the image using the "sparkle" effect.
0293                     png_read_rows( this->get_struct()
0294                                  , &row_ptr
0295                                  , nullptr
0296                                  , 1
0297                                  );
0298 
0299                     it_t first = buffer.begin() + this->_settings._top_left.x;
0300                     it_t last  = first + this->_settings._dim.x; // one after last element
0301 
0302                     this->_cc_policy.read( first
0303                                          , last
0304                                          , view.row_begin( y ));
0305                 }
0306 
0307                 // Read the rest of the image. libpng needs that.
0308                 std::ptrdiff_t remaining_rows = static_cast< std::ptrdiff_t >( this->_info._height )
0309                                               - this->_settings._top_left.y
0310                                               - this->_settings._dim.y;
0311                 for( std::ptrdiff_t y = 0
0312                    ; y < remaining_rows
0313                    ; ++y
0314                    )
0315                 {
0316                     // Read the image using the "sparkle" effect.
0317                     png_read_rows( this->get_struct()
0318                                  , &row_ptr
0319                                  , nullptr
0320                                  , 1
0321                                  );
0322                 }
0323             }
0324             else
0325             {
0326                 for( int y = 0; y < view.height(); ++y )
0327                 {
0328                     // Read the image using the "sparkle" effect.
0329                     png_read_rows( this->get_struct()
0330                                  , &row_ptr
0331                                  , nullptr
0332                                  , 1
0333                                  );
0334                 }
0335             }
0336         }
0337     }
0338 };
0339 
0340 namespace detail {
0341 
0342 struct png_type_format_checker
0343 {
0344     png_type_format_checker( png_bitdepth::type   bit_depth
0345                            , png_color_type::type color_type
0346                            )
0347     : _bit_depth ( bit_depth  )
0348     , _color_type( color_type )
0349     {}
0350 
0351     template< typename Image >
0352     bool apply()
0353     {
0354         using is_supported_t = is_read_supported
0355             <
0356                 typename get_pixel_type<typename Image::view_t>::type,
0357                 png_tag
0358             >;
0359 
0360         return is_supported_t::_bit_depth  == _bit_depth
0361             && is_supported_t::_color_type == _color_type;
0362     }
0363 
0364 private:
0365 
0366     png_bitdepth::type   _bit_depth;
0367     png_color_type::type _color_type;
0368 };
0369 
0370 struct png_read_is_supported
0371 {
0372     template< typename View >
0373     struct apply : public is_read_supported< typename get_pixel_type< View >::type
0374                                            , png_tag
0375                                            >
0376     {};
0377 };
0378 
0379 } // namespace detail
0380 
0381 
0382 ///
0383 /// PNG Dynamic Image Reader
0384 ///
0385 template< typename Device
0386         >
0387 class dynamic_image_reader< Device
0388                           , png_tag
0389                           >
0390     : public reader< Device
0391                    , png_tag
0392                    , detail::read_and_no_convert
0393                    >
0394 {
0395     using parent_t = reader
0396         <
0397             Device,
0398             png_tag,
0399             detail::read_and_no_convert
0400         >;
0401 
0402 public:
0403 
0404     dynamic_image_reader( const Device&                         io_dev
0405                         , const image_read_settings< png_tag >& settings
0406                         )
0407     : parent_t( io_dev
0408               , settings
0409               )
0410     {}
0411 
0412     template< typename ...Images >
0413     void apply( any_image< Images... >& images )
0414     {
0415         detail::png_type_format_checker format_checker( this->_info._bit_depth
0416                                                       , this->_info._color_type
0417                                                       );
0418 
0419         if( !detail::construct_matched( images
0420                               , format_checker
0421                               ))
0422         {
0423             io_error( "No matching image type between those of the given any_image and that of the file" );
0424         }
0425         else
0426         {
0427             this->init_image( images
0428                             , this->_settings
0429                             );
0430 
0431             detail::dynamic_io_fnobj< detail::png_read_is_supported
0432                                     , parent_t
0433                                     > op( this );
0434 
0435             variant2::visit( op
0436                            , view( images )
0437                            );
0438         }
0439     }
0440 };
0441 
0442 #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
0443 #pragma warning(pop)
0444 #endif
0445 
0446 } // namespace gil
0447 } // namespace boost
0448 
0449 #endif