2 // Copyright 2007-2012 Christian Henning, Andreas Pokorny, Lubomir Bourdev
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
8 #ifndef BOOST_GIL_EXTENSION_IO_PNG_DETAIL_READ_HPP
9 #define BOOST_GIL_EXTENSION_IO_PNG_DETAIL_READ_HPP
11 #include <boost/gil/extension/io/png/tags.hpp>
12 #include <boost/gil/extension/io/png/detail/reader_backend.hpp>
13 #include <boost/gil/extension/io/png/detail/is_allowed.hpp>
15 #include <boost/gil.hpp> // FIXME: Include what you use!
16 #include <boost/gil/io/base.hpp>
17 #include <boost/gil/io/conversion_policies.hpp>
18 #include <boost/gil/io/device.hpp>
19 #include <boost/gil/io/dynamic_io_new.hpp>
20 #include <boost/gil/io/reader_base.hpp>
21 #include <boost/gil/io/row_buffer_helper.hpp>
22 #include <boost/gil/io/typedefs.hpp>
24 #include <type_traits>
26 namespace boost { namespace gil {
28 #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
30 #pragma warning(disable:4512) //assignment operator could not be generated
36 template< typename Device
37 , typename ConversionPolicy
43 : public reader_base< png_tag
45 , public reader_backend< Device
51 using this_t = reader<Device, png_tag, ConversionPolicy>;
52 using cc_t = typename ConversionPolicy::color_converter_type;
56 using backend_t = reader_backend<Device, png_tag>;
60 reader( const Device& io_dev
61 , const image_read_settings< png_tag >& settings
63 : reader_base< png_tag
71 reader( const Device& io_dev
72 , const typename ConversionPolicy::color_converter_type& cc
73 , const image_read_settings< png_tag >& settings
75 : reader_base< png_tag
83 template< typename View >
84 void apply( const View& view )
86 // The info structures are filled at this point.
88 // Now it's time for some transformations.
92 if( this->_info._bit_depth == 16 )
94 // Swap bytes of 16 bit files to least significant byte first.
95 png_set_swap( this->get_struct() );
98 if( this->_info._bit_depth < 8 )
100 // swap bits of 1, 2, 4 bit packed pixel formats
101 png_set_packswap( this->get_struct() );
105 if( this->_info._color_type == PNG_COLOR_TYPE_PALETTE )
107 png_set_palette_to_rgb( this->get_struct() );
110 if( png_get_valid( this->get_struct(), this->get_info(), PNG_INFO_tRNS ) )
112 png_set_tRNS_to_alpha( this->get_struct() );
115 // Tell libpng to handle the gamma conversion for you. The final call
116 // is a good guess for PC generated images, but it should be configurable
117 // by the user at run time by the user. It is strongly suggested that
118 // your application support gamma correction.
119 if( this->_settings._apply_screen_gamma )
121 // png_set_gamma will change the image data!
123 #ifdef BOOST_GIL_IO_PNG_FLOATING_POINT_SUPPORTED
124 png_set_gamma( this->get_struct()
125 , this->_settings._screen_gamma
126 , this->_info._file_gamma
129 png_set_gamma( this->get_struct()
130 , this->_settings._screen_gamma
131 , this->_info._file_gamma
133 #endif // BOOST_GIL_IO_PNG_FLOATING_POINT_SUPPORTED
136 // Turn on interlace handling. REQUIRED if you are not using
137 // png_read_image(). To see how to handle interlacing passes,
138 // see the png_read_row() method below:
139 this->_number_passes = png_set_interlace_handling( this->get_struct() );
142 // The above transformation might have changed the bit_depth and color type.
143 png_read_update_info( this->get_struct()
147 this->_info._bit_depth = png_get_bit_depth( this->get_struct()
151 this->_info._num_channels = png_get_channels( this->get_struct()
155 this->_info._color_type = png_get_color_type( this->get_struct()
159 this->_scanline_length = png_get_rowbytes( this->get_struct()
163 switch( this->_info._color_type )
165 case PNG_COLOR_TYPE_GRAY:
167 switch( this->_info._bit_depth )
169 case 1: read_rows< gray1_image_t::view_t::reference >( view ); break;
170 case 2: read_rows< gray2_image_t::view_t::reference >( view ); break;
171 case 4: read_rows< gray4_image_t::view_t::reference >( view ); break;
172 case 8: read_rows< gray8_pixel_t >( view ); break;
173 case 16: read_rows< gray16_pixel_t >( view ); break;
174 default: io_error( "png_reader::read_data(): unknown combination of color type and bit depth" );
179 case PNG_COLOR_TYPE_GA:
181 #ifdef BOOST_GIL_IO_ENABLE_GRAY_ALPHA
182 switch( this->_info._bit_depth )
184 case 8: read_rows< gray_alpha8_pixel_t > ( view ); break;
185 case 16: read_rows< gray_alpha16_pixel_t >( view ); break;
186 default: io_error( "png_reader::read_data(): unknown combination of color type and bit depth" );
189 io_error( "gray_alpha isn't enabled. Define BOOST_GIL_IO_ENABLE_GRAY_ALPHA when building application." );
190 #endif // BOOST_GIL_IO_ENABLE_GRAY_ALPHA
195 case PNG_COLOR_TYPE_RGB:
197 switch( this->_info._bit_depth )
199 case 8: read_rows< rgb8_pixel_t > ( view ); break;
200 case 16: read_rows< rgb16_pixel_t >( view ); break;
201 default: io_error( "png_reader::read_data(): unknown combination of color type and bit depth" );
206 case PNG_COLOR_TYPE_RGBA:
208 switch( this->_info._bit_depth )
210 case 8: read_rows< rgba8_pixel_t > ( view ); break;
211 case 16: read_rows< rgba16_pixel_t >( view ); break;
212 default: io_error( "png_reader_color_convert::read_data(): unknown combination of color type and bit depth" );
217 default: io_error( "png_reader_color_convert::read_data(): unknown color type" );
220 // read rest of file, and get additional chunks in info_ptr
221 png_read_end( this->get_struct()
228 template< typename ImagePixel
231 void read_rows( const View& view )
233 using row_buffer_helper_t = detail::row_buffer_helper_view<ImagePixel>;
235 using it_t = typename row_buffer_helper_t::iterator_t;
237 using is_read_and_convert_t = typename std::is_same
240 detail::read_and_no_convert
243 io_error_if( !detail::is_allowed< View >( this->_info
244 , is_read_and_convert_t()
246 , "Image types aren't compatible."
249 std::size_t rowbytes = png_get_rowbytes( this->get_struct()
253 row_buffer_helper_t buffer( rowbytes
257 png_bytep row_ptr = (png_bytep)( &( buffer.data()[0]));
259 for( std::size_t pass = 0; pass < this->_number_passes; pass++ )
261 if( pass == this->_number_passes - 1 )
263 // skip lines if necessary
264 for( std::ptrdiff_t y = 0; y < this->_settings._top_left.y; ++y )
266 // Read the image using the "sparkle" effect.
267 png_read_rows( this->get_struct()
274 for( std::ptrdiff_t y = 0
275 ; y < this->_settings._dim.y
279 // Read the image using the "sparkle" effect.
280 png_read_rows( this->get_struct()
286 it_t first = buffer.begin() + this->_settings._top_left.x;
287 it_t last = first + this->_settings._dim.x; // one after last element
289 this->_cc_policy.read( first
291 , view.row_begin( y ));
294 // Read the rest of the image. libpng needs that.
295 std::ptrdiff_t remaining_rows = static_cast< std::ptrdiff_t >( this->_info._height )
296 - this->_settings._top_left.y
297 - this->_settings._dim.y;
298 for( std::ptrdiff_t y = 0
303 // Read the image using the "sparkle" effect.
304 png_read_rows( this->get_struct()
313 for( int y = 0; y < view.height(); ++y )
315 // Read the image using the "sparkle" effect.
316 png_read_rows( this->get_struct()
329 struct png_type_format_checker
331 png_type_format_checker( png_bitdepth::type bit_depth
332 , png_color_type::type color_type
334 : _bit_depth ( bit_depth )
335 , _color_type( color_type )
338 template< typename Image >
341 using is_supported_t = is_read_supported
343 typename get_pixel_type<typename Image::view_t>::type,
347 return is_supported_t::_bit_depth == _bit_depth
348 && is_supported_t::_color_type == _color_type;
353 png_bitdepth::type _bit_depth;
354 png_color_type::type _color_type;
357 struct png_read_is_supported
359 template< typename View >
360 struct apply : public is_read_supported< typename get_pixel_type< View >::type
366 } // namespace detail
370 /// PNG Dynamic Image Reader
372 template< typename Device
374 class dynamic_image_reader< Device
377 : public reader< Device
379 , detail::read_and_no_convert
382 using parent_t = reader
386 detail::read_and_no_convert
391 dynamic_image_reader( const Device& io_dev
392 , const image_read_settings< png_tag >& settings
399 template< typename Images >
400 void apply( any_image< Images >& images )
402 detail::png_type_format_checker format_checker( this->_info._bit_depth
403 , this->_info._color_type
406 if( !construct_matched( images
410 io_error( "No matching image type between those of the given any_image and that of the file" );
414 this->init_image( images
418 detail::dynamic_io_fnobj< detail::png_read_is_supported
422 apply_operation( view( images )
429 #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)