// // Copyright 2007-2012 Christian Henning, Lubomir Bourdev // // Distributed under the Boost Software License, Version 1.0 // See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt // #ifndef BOOST_GIL_EXTENSION_IO_TIFF_DETAIL_SCANLINE_READ_HPP #define BOOST_GIL_EXTENSION_IO_TIFF_DETAIL_SCANLINE_READ_HPP #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // taken from jpegxx - https://bitbucket.org/edd/jpegxx/src/ea2492a1a4a6/src/ijg_headers.hpp #ifndef BOOST_GIL_EXTENSION_IO_TIFF_C_LIB_COMPILED_AS_CPLUSPLUS extern "C" { #endif #include #include #ifndef BOOST_GIL_EXTENSION_IO_TIFF_C_LIB_COMPILED_AS_CPLUSPLUS } #endif namespace boost { namespace gil { /// /// TIFF scanline reader /// template< typename Device > class scanline_reader< Device , tiff_tag > : public reader_backend< Device , tiff_tag > { public: using tag_t = tiff_tag; using backend_t = reader_backend; using this_t = scanline_reader; using iterator_t = scanline_read_iterator; scanline_reader( Device& device , const image_read_settings< tiff_tag >& settings ) : backend_t( device , settings ) { initialize(); } /// Read part of image defined by View and return the data. void read( byte_t* dst, int pos ) { _read_function( this, dst, pos ); } /// Skip over a scanline. void skip( byte_t* dst, int pos ) { this->_read_function( this, dst, pos ); } iterator_t begin() { return iterator_t( *this ); } iterator_t end() { return iterator_t( *this, this->_info._height ); } private: void initialize() { io_error_if( this->_info._is_tiled , "scanline_reader doesn't support tiled tiff images." ); if( this->_info._photometric_interpretation == PHOTOMETRIC_PALETTE ) { this->_scanline_length = this->_info._width * num_channels< rgb16_view_t >::value * sizeof( channel_type::type ); this->_io_dev.get_field_defaulted( this->_red , this->_green , this->_blue ); _buffer = std::vector< byte_t >( this->_io_dev.get_scanline_size() ); switch( this->_info._bits_per_sample ) { case 1: { using channel_t = channel_type::type>::type; int num_colors = channel_traits< channel_t >::max_value() + 1; this->_palette = planar_rgb_view( num_colors , 1 , this->_red , this->_green , this->_blue , sizeof(uint16_t) * num_colors ); _read_function = std::mem_fn(&this_t::read_1_bit_index_image); break; } case 2: { using channel_t = channel_type::type>::type; int num_colors = channel_traits< channel_t >::max_value() + 1; this->_palette = planar_rgb_view( num_colors , 1 , this->_red , this->_green , this->_blue , sizeof(uint16_t) * num_colors ); _read_function = std::mem_fn(&this_t::read_2_bits_index_image); break; } case 4: { using channel_t = channel_type::type>::type; int num_colors = channel_traits< channel_t >::max_value() + 1; this->_palette = planar_rgb_view( num_colors , 1 , this->_red , this->_green , this->_blue , sizeof(uint16_t) * num_colors ); _read_function = std::mem_fn(&this_t::read_4_bits_index_image); break; } case 8: { using channel_t = channel_type::type>::type; int num_colors = channel_traits< channel_t >::max_value() + 1; this->_palette = planar_rgb_view( num_colors , 1 , this->_red , this->_green , this->_blue , sizeof(uint16_t) * num_colors ); _read_function = std::mem_fn(&this_t::read_8_bits_index_image); break; } case 16: { using channel_t = channel_type::type>::type; int num_colors = channel_traits< channel_t >::max_value() + 1; this->_palette = planar_rgb_view( num_colors , 1 , this->_red , this->_green , this->_blue , sizeof(uint16_t) * num_colors ); _read_function = std::mem_fn(&this_t::read_16_bits_index_image); break; } case 24: { using channel_t = channel_type::type>::type; int num_colors = channel_traits< channel_t >::max_value() + 1; this->_palette = planar_rgb_view( num_colors , 1 , this->_red , this->_green , this->_blue , sizeof(uint16_t) * num_colors ); _read_function = std::mem_fn(&this_t::read_24_bits_index_image); break; } case 32: { using channel_t = channel_type::type>::type; int num_colors = channel_traits< channel_t >::max_value() + 1; this->_palette = planar_rgb_view( num_colors , 1 , this->_red , this->_green , this->_blue , sizeof(uint16_t) * num_colors ); _read_function = std::mem_fn(&this_t::read_32_bits_index_image); break; } default: { io_error( "Not supported palette " ); } } } else { this->_scanline_length = this->_io_dev.get_scanline_size(); if( this->_info._planar_configuration == PLANARCONFIG_SEPARATE ) { io_error( "scanline_reader doesn't support planar tiff images." ); } else if( this->_info._planar_configuration == PLANARCONFIG_CONTIG ) { // the read_data function needs to know what gil type the source image is // to have the default color converter function correctly switch( this->_info._photometric_interpretation ) { case PHOTOMETRIC_MINISWHITE: case PHOTOMETRIC_MINISBLACK: { switch( this->_info._bits_per_sample ) { case 1: case 2: case 4: case 6: case 8: case 10: case 12: case 14: case 16: case 24: case 32: { _read_function = std::mem_fn(&this_t::read_row); break; } default: { io_error( "Image type is not supported." ); } } break; } case PHOTOMETRIC_RGB: { switch( this->_info._samples_per_pixel ) { case 3: { switch( this->_info._bits_per_sample ) { case 2: case 4: case 8: case 10: case 12: case 14: case 16: case 24: case 32: { _read_function = std::mem_fn(&this_t::read_row); break; } default: { io_error( "Image type is not supported." ); } } break; } case 4: { switch( this->_info._bits_per_sample ) { case 2: case 4: case 8: case 10: case 12: case 14: case 16: case 24: case 32: { _read_function = std::mem_fn(&this_t::read_row); break; } default: { io_error( "Image type is not supported." ); } } break; } default: { io_error( "Image type is not supported." ); } } break; } case PHOTOMETRIC_SEPARATED: // CYMK { switch( this->_info._bits_per_sample ) { case 2: case 4: case 8: case 10: case 12: case 14: case 16: case 24: case 32: { _read_function = std::mem_fn(&this_t::read_row); break; } default: { io_error( "Image type is not supported." ); } } break; } default: { io_error( "Image type is not supported." ); } } } else { io_error( "Wrong planar configuration setting." ); } } } template< typename Src_View > void read_n_bits_row( byte_t* dst, int pos ) { using dst_view_t = rgb16_view_t; this->_io_dev.read_scanline( _buffer , pos , 0 ); Src_View src_view = interleaved_view( this->_info._width , 1 , (typename Src_View::x_iterator) &_buffer.front() , this->_scanline_length ); dst_view_t dst_view = interleaved_view( this->_info._width , 1 , (typename dst_view_t::value_type*) dst , num_channels< dst_view_t >::value * 2 * this->_info._width ); typename Src_View::x_iterator src_it = src_view.row_begin( 0 ); typename dst_view_t::x_iterator dst_it = dst_view.row_begin( 0 ); for( dst_view_t::x_coord_t i = 0 ; i < this->_info._width ; ++i, src_it++, dst_it++ ) { auto const c = static_cast(get_color(*src_it, gray_color_t())); *dst_it = this->_palette[c]; } } void read_1_bit_index_image( byte_t* dst, int pos ) { read_n_bits_row< gray1_image_t::view_t >( dst, pos ); } void read_2_bits_index_image( byte_t* dst, int pos ) { read_n_bits_row< gray2_image_t::view_t >( dst, pos ); } void read_4_bits_index_image( byte_t* dst, int pos ) { read_n_bits_row< gray4_image_t::view_t >( dst, pos ); } void read_8_bits_index_image( byte_t* dst, int pos ) { read_n_bits_row< gray8_image_t::view_t >( dst, pos ); } void read_16_bits_index_image( byte_t* dst, int pos ) { read_n_bits_row< gray16_image_t::view_t >( dst, pos ); } void read_24_bits_index_image( byte_t* dst, int pos ) { read_n_bits_row< gray24_image_t::view_t >( dst, pos ); } void read_32_bits_index_image( byte_t* dst, int pos ) { read_n_bits_row< gray32_image_t::view_t >( dst, pos ); } void read_row(byte_t* dst, int pos ) { this->_io_dev.read_scanline( dst , pos , 0 ); } private: std::vector< byte_t> _buffer; detail::mirror_bits, std::true_type> _mirror_bites; std::function _read_function; }; } // namespace gil } // namespace boost #endif