784 lines
27 KiB
C++
784 lines
27 KiB
C++
//
|
|
// 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_READER_HPP
|
|
#define BOOST_GIL_EXTENSION_IO_TIFF_DETAIL_READER_HPP
|
|
|
|
#include <boost/gil/extension/io/tiff/detail/device.hpp>
|
|
#include <boost/gil/extension/io/tiff/detail/is_allowed.hpp>
|
|
#include <boost/gil/extension/io/tiff/detail/reader_backend.hpp>
|
|
|
|
#include <boost/gil/io/detail/dynamic.hpp>
|
|
#include <boost/gil/io/base.hpp>
|
|
#include <boost/gil/io/bit_operations.hpp>
|
|
#include <boost/gil/io/conversion_policies.hpp>
|
|
#include <boost/gil/io/device.hpp>
|
|
#include <boost/gil/io/reader_base.hpp>
|
|
#include <boost/gil/io/row_buffer_helper.hpp>
|
|
|
|
#include <boost/assert.hpp>
|
|
|
|
#include <algorithm>
|
|
#include <string>
|
|
#include <type_traits>
|
|
#include <vector>
|
|
|
|
// 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 <tiff.h>
|
|
#include <tiffio.h>
|
|
|
|
#ifndef BOOST_GIL_EXTENSION_IO_TIFF_C_LIB_COMPILED_AS_CPLUSPLUS
|
|
}
|
|
#endif
|
|
|
|
namespace boost { namespace gil {
|
|
|
|
#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
|
|
#pragma warning(push)
|
|
#pragma warning(disable:4512) //assignment operator could not be generated
|
|
#endif
|
|
|
|
template < int K >
|
|
struct plane_recursion
|
|
{
|
|
template< typename View
|
|
, typename Device
|
|
, typename ConversionPolicy
|
|
>
|
|
static
|
|
void read_plane( const View& dst_view
|
|
, reader< Device
|
|
, tiff_tag
|
|
, ConversionPolicy >* p
|
|
)
|
|
{
|
|
using plane_t = typename kth_channel_view_type<K, View>::type;
|
|
plane_t plane = kth_channel_view<K>( dst_view );
|
|
|
|
p->template read_data< detail::row_buffer_helper_view< plane_t > >( plane, K );
|
|
|
|
plane_recursion< K - 1 >::read_plane( dst_view, p );
|
|
}
|
|
};
|
|
|
|
template <>
|
|
struct plane_recursion< -1 >
|
|
{
|
|
template< typename View
|
|
, typename Device
|
|
, typename ConversionPolicy
|
|
>
|
|
static
|
|
void read_plane( const View& /* dst_view */
|
|
, reader< Device
|
|
, tiff_tag
|
|
, ConversionPolicy
|
|
>* /* p */
|
|
)
|
|
{}
|
|
};
|
|
|
|
///
|
|
/// Tiff Reader
|
|
///
|
|
template< typename Device
|
|
, typename ConversionPolicy
|
|
>
|
|
class reader< Device
|
|
, tiff_tag
|
|
, ConversionPolicy
|
|
>
|
|
: public reader_base< tiff_tag
|
|
, ConversionPolicy >
|
|
|
|
, public reader_backend< Device
|
|
, tiff_tag
|
|
>
|
|
{
|
|
private:
|
|
|
|
using this_t = reader<Device, tiff_tag, ConversionPolicy>;
|
|
using cc_t = typename ConversionPolicy::color_converter_type;
|
|
|
|
public:
|
|
|
|
using backend_t = reader_backend<Device, tiff_tag>;
|
|
|
|
reader( const Device& io_dev
|
|
, const image_read_settings< tiff_tag >& settings
|
|
)
|
|
: reader_base< tiff_tag
|
|
, ConversionPolicy
|
|
>()
|
|
, backend_t( io_dev
|
|
, settings
|
|
)
|
|
{}
|
|
|
|
reader( const Device& io_dev
|
|
, const typename ConversionPolicy::color_converter_type& cc
|
|
, const image_read_settings< tiff_tag >& settings
|
|
)
|
|
: reader_base< tiff_tag
|
|
, ConversionPolicy
|
|
>( cc )
|
|
, backend_t( io_dev
|
|
, settings
|
|
)
|
|
{}
|
|
|
|
// only works for homogeneous image types
|
|
template< typename View >
|
|
void apply( View& dst_view )
|
|
{
|
|
if( this->_info._photometric_interpretation == PHOTOMETRIC_PALETTE )
|
|
{
|
|
this->_scanline_length = this->_info._width
|
|
* num_channels< rgb16_view_t >::value
|
|
* sizeof( channel_type<rgb16_view_t>::type );
|
|
|
|
// Steps:
|
|
// 1. Read indices. It's an array of grayX_pixel_t.
|
|
// 2. Read palette. It's an array of rgb16_pixel_t.
|
|
// 3. ??? Create virtual image or transform the two arrays
|
|
// into a rgb16_image_t object. The latter might
|
|
// be a good first solution.
|
|
|
|
switch( this->_info._bits_per_sample )
|
|
{
|
|
case 1: { read_palette_image< gray1_image_t >( dst_view ); break; }
|
|
case 2: { read_palette_image< gray2_image_t >( dst_view ); break; }
|
|
case 4: { read_palette_image< gray4_image_t >( dst_view ); break; }
|
|
case 8: { read_palette_image< gray8_image_t >( dst_view ); break; }
|
|
case 16: { read_palette_image< gray16_image_t >( dst_view ); break; }
|
|
|
|
default: { io_error( "Not supported palette " ); }
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
else
|
|
{
|
|
this->_scanline_length = this->_io_dev.get_scanline_size();
|
|
|
|
// In case we only read the image the user's type and
|
|
// the tiff type need to compatible. Which means:
|
|
// color_spaces_are_compatible && channels_are_pairwise_compatible
|
|
|
|
using is_read_only = typename std::is_same
|
|
<
|
|
ConversionPolicy,
|
|
detail::read_and_no_convert
|
|
>::type;
|
|
|
|
io_error_if( !detail::is_allowed< View >( this->_info
|
|
, is_read_only()
|
|
)
|
|
, "Image types aren't compatible."
|
|
);
|
|
|
|
if( this->_info._planar_configuration == PLANARCONFIG_SEPARATE )
|
|
{
|
|
plane_recursion< num_channels< View >::value - 1 >::read_plane( dst_view
|
|
, this
|
|
);
|
|
}
|
|
else if( this->_info._planar_configuration == PLANARCONFIG_CONTIG )
|
|
{
|
|
read( dst_view
|
|
, typename is_read_only::type()
|
|
);
|
|
}
|
|
else
|
|
{
|
|
io_error( "Wrong planar configuration setting." );
|
|
}
|
|
}
|
|
}
|
|
|
|
private:
|
|
|
|
template< typename View >
|
|
void read( View v
|
|
, std::true_type // is_read_only
|
|
)
|
|
{
|
|
read_data< detail::row_buffer_helper_view< View > >( v, 0 );
|
|
}
|
|
|
|
template< typename View >
|
|
void read( View v
|
|
, std::false_type // is_read_only
|
|
)
|
|
{
|
|
// 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: { read_data< detail::row_buffer_helper_view< gray1_image_t::view_t > >( v, 0 ); break; }
|
|
case 2: { read_data< detail::row_buffer_helper_view< gray2_image_t::view_t > >( v, 0 ); break; }
|
|
case 4: { read_data< detail::row_buffer_helper_view< gray4_image_t::view_t > >( v, 0 ); break; }
|
|
case 8: { read_data< detail::row_buffer_helper_view< gray8_view_t > >( v, 0 ); break; }
|
|
case 16: { read_data< detail::row_buffer_helper_view< gray16_view_t > >( v, 0 ); break; }
|
|
case 32: { read_data< detail::row_buffer_helper_view< gray32_view_t > >( v, 0 ); 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 8: { read_data< detail::row_buffer_helper_view< rgb8_view_t > >( v, 0 ); break; }
|
|
case 16: { read_data< detail::row_buffer_helper_view< rgb16_view_t > >( v, 0 ); break; }
|
|
case 32: { read_data< detail::row_buffer_helper_view< rgb32_view_t > >( v, 0 ); break; }
|
|
default: { io_error( "Image type is not supported." ); }
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case 4:
|
|
{
|
|
switch( this->_info._bits_per_sample )
|
|
{
|
|
case 8: { read_data< detail::row_buffer_helper_view< rgba8_view_t > >( v, 0 ); break; }
|
|
case 16: { read_data< detail::row_buffer_helper_view< rgba16_view_t > >( v, 0 ); break; }
|
|
case 32: { read_data< detail::row_buffer_helper_view< rgba32_view_t > >( v, 0 ); 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 8: { read_data< detail::row_buffer_helper_view< cmyk8_view_t > >( v, 0 ); break; }
|
|
case 16: { read_data< detail::row_buffer_helper_view< cmyk16_view_t > >( v, 0 ); break; }
|
|
case 32: { read_data< detail::row_buffer_helper_view< cmyk32_view_t > >( v, 0 ); break; }
|
|
default: { io_error( "Image type is not supported." ); }
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
default: { io_error( "Image type is not supported." ); }
|
|
}
|
|
}
|
|
|
|
template< typename PaletteImage
|
|
, typename View
|
|
>
|
|
void read_palette_image( const View& dst_view )
|
|
{
|
|
PaletteImage indices( this->_info._width - this->_settings._top_left.x
|
|
, this->_info._height - this->_settings._top_left.y );
|
|
|
|
// read the palette first
|
|
read_data< detail::row_buffer_helper_view
|
|
<
|
|
typename PaletteImage::view_t>
|
|
>(view(indices), 0);
|
|
|
|
read_palette_image(dst_view, view(indices),
|
|
typename std::is_same<View, rgb16_view_t>::type());
|
|
}
|
|
|
|
template< typename View
|
|
, typename Indices_View
|
|
>
|
|
void read_palette_image( const View& dst_view
|
|
, const Indices_View& indices_view
|
|
, std::true_type // is View rgb16_view_t
|
|
)
|
|
{
|
|
tiff_color_map::red_t red = nullptr;
|
|
tiff_color_map::green_t green = nullptr;
|
|
tiff_color_map::blue_t blue = nullptr;
|
|
|
|
this->_io_dev.get_field_defaulted( red, green, blue );
|
|
|
|
using channel_t = typename channel_traits<typename element_type<typename Indices_View::value_type>::type>::value_type;
|
|
|
|
int num_colors = channel_traits< channel_t >::max_value();
|
|
|
|
rgb16_planar_view_t palette = planar_rgb_view( num_colors
|
|
, 1
|
|
, red
|
|
, green
|
|
, blue
|
|
, sizeof(uint16_t) * num_colors );
|
|
|
|
for( typename rgb16_view_t::y_coord_t y = 0; y < dst_view.height(); ++y )
|
|
{
|
|
typename rgb16_view_t::x_iterator it = dst_view.row_begin( y );
|
|
typename rgb16_view_t::x_iterator end = dst_view.row_end( y );
|
|
|
|
typename Indices_View::x_iterator indices_it = indices_view.row_begin( y );
|
|
|
|
for( ; it != end; ++it, ++indices_it )
|
|
{
|
|
uint16_t i = gil::at_c<0>( *indices_it );
|
|
|
|
*it = palette[i];
|
|
}
|
|
}
|
|
}
|
|
|
|
template< typename View
|
|
, typename Indices_View
|
|
>
|
|
inline
|
|
void read_palette_image( const View& /* dst_view */
|
|
, const Indices_View& /* indices_view */
|
|
, std::false_type // is View rgb16_view_t
|
|
)
|
|
{
|
|
io_error( "User supplied image type must be rgb16_image_t." );
|
|
}
|
|
|
|
template< typename Buffer >
|
|
void skip_over_rows( Buffer& buffer
|
|
, int plane
|
|
)
|
|
{
|
|
if( this->_info._compression != COMPRESSION_NONE )
|
|
{
|
|
// Skipping over rows is not possible for compressed images( no random access ). See man
|
|
// page ( diagnostics section ) for more information.
|
|
for( std::ptrdiff_t row = 0; row < this->_settings._top_left.y; ++row )
|
|
{
|
|
this->_io_dev.read_scanline( buffer
|
|
, row
|
|
, static_cast< tsample_t >( plane ));
|
|
}
|
|
}
|
|
}
|
|
|
|
template< typename Buffer
|
|
, typename View
|
|
>
|
|
void read_data( const View& dst_view
|
|
, int /* plane */ )
|
|
{
|
|
if( this->_io_dev.is_tiled() )
|
|
{
|
|
read_tiled_data< Buffer >( dst_view, 0 );
|
|
}
|
|
else
|
|
{
|
|
read_stripped_data< Buffer >( dst_view, 0 );
|
|
}
|
|
}
|
|
|
|
|
|
template< typename Buffer
|
|
, typename View
|
|
>
|
|
void read_tiled_data( const View& dst_view
|
|
, int plane
|
|
)
|
|
{
|
|
if( dst_view.width() != this->_info._width
|
|
|| dst_view.height() != this->_info._height
|
|
)
|
|
{
|
|
// read a subimage
|
|
read_tiled_data_subimage< Buffer >( dst_view, plane );
|
|
}
|
|
else
|
|
{
|
|
// read full image
|
|
read_tiled_data_full< Buffer >( dst_view, plane );
|
|
}
|
|
}
|
|
|
|
template< typename Buffer
|
|
, typename View
|
|
>
|
|
void read_tiled_data_subimage( const View& dst_view
|
|
, int plane
|
|
)
|
|
{
|
|
///@todo: why is
|
|
/// using row_buffer_helper_t = Buffer;
|
|
/// not working? I get compiler error with MSVC10.
|
|
/// read_stripped_data IS working.
|
|
using row_buffer_helper_t = detail::row_buffer_helper_view<View>;
|
|
|
|
using it_t = typename row_buffer_helper_t::iterator_t;
|
|
|
|
tiff_image_width::type image_width = this->_info._width;
|
|
tiff_image_height::type image_height = this->_info._height;
|
|
|
|
tiff_tile_width::type tile_width = this->_info._tile_width;
|
|
tiff_tile_length::type tile_height = this->_info._tile_length;
|
|
|
|
std::ptrdiff_t subimage_x = this->_settings._top_left.x;
|
|
std::ptrdiff_t subimage_y = this->_settings._top_left.y;
|
|
|
|
std::ptrdiff_t subimage_width = this->_settings._dim.x;
|
|
std::ptrdiff_t subimage_height = this->_settings._dim.y;
|
|
|
|
row_buffer_helper_t row_buffer_helper(this->_io_dev.get_tile_size(), true );
|
|
|
|
for( unsigned int y = 0; y < image_height; y += tile_height )
|
|
{
|
|
for( unsigned int x = 0; x < image_width; x += tile_width )
|
|
{
|
|
uint32_t current_tile_width = ( x + tile_width < image_width ) ? tile_width : image_width - x;
|
|
uint32_t current_tile_length = ( y + tile_height < image_height ) ? tile_height : image_height - y;
|
|
|
|
this->_io_dev.read_tile( row_buffer_helper.buffer()
|
|
, x
|
|
, y
|
|
, 0
|
|
, static_cast< tsample_t >( plane )
|
|
);
|
|
|
|
// these are all whole image coordinates
|
|
point_t tile_top_left ( x, y );
|
|
point_t tile_lower_right( x + current_tile_width - 1, y + current_tile_length - 1 );
|
|
|
|
point_t view_top_left ( subimage_x, subimage_y );
|
|
point_t view_lower_right( subimage_x + subimage_width - 1
|
|
, subimage_y + subimage_height - 1 );
|
|
|
|
if( tile_top_left.x > view_lower_right.x
|
|
|| tile_top_left.y > view_lower_right.y
|
|
|| tile_lower_right.x < view_top_left.x
|
|
|| tile_lower_right.y < view_top_left.y
|
|
)
|
|
{
|
|
// current tile and dst_view do not overlap
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
// dst_view is overlapping the current tile
|
|
|
|
// next is to define the portion in the tile that needs to be copied
|
|
|
|
// get the whole image coordinates
|
|
std::ptrdiff_t img_x0 = ( tile_top_left.x >= view_top_left.x ) ? tile_top_left.x : view_top_left.x;
|
|
std::ptrdiff_t img_y0 = ( tile_top_left.y >= view_top_left.y ) ? tile_top_left.y : view_top_left.y;
|
|
|
|
std::ptrdiff_t img_x1 = ( tile_lower_right.x <= view_lower_right.x ) ? tile_lower_right.x : view_lower_right.x;
|
|
std::ptrdiff_t img_y1 = ( tile_lower_right.y <= view_lower_right.y ) ? tile_lower_right.y : view_lower_right.y;
|
|
|
|
// convert to tile coordinates
|
|
std::ptrdiff_t tile_x0 = img_x0 - x;
|
|
std::ptrdiff_t tile_y0 = img_y0 - y;
|
|
std::ptrdiff_t tile_x1 = img_x1 - x;
|
|
std::ptrdiff_t tile_y1 = img_y1 - y;
|
|
|
|
BOOST_ASSERT(tile_x0 >= 0 && tile_y0 >= 0 && tile_x1 >= 0 && tile_y1 >= 0);
|
|
BOOST_ASSERT(tile_x0 <= img_x1 && tile_y0 <= img_y1);
|
|
BOOST_ASSERT(tile_x0 < tile_width && tile_y0 < tile_height && tile_x1 < tile_width && tile_y1 < tile_height);
|
|
|
|
std::ptrdiff_t tile_subimage_view_width = tile_x1 - tile_x0 + 1;
|
|
std::ptrdiff_t tile_subimage_view_height = tile_y1 - tile_y0 + 1;
|
|
|
|
// convert to dst_view coordinates
|
|
std::ptrdiff_t dst_x0 = img_x0 - subimage_x;
|
|
std::ptrdiff_t dst_y0 = img_y0 - subimage_y;
|
|
BOOST_ASSERT(dst_x0 >= 0 && dst_y0 >= 0);
|
|
|
|
View dst_subimage_view = subimage_view( dst_view
|
|
, (int) dst_x0
|
|
, (int) dst_y0
|
|
, (int) tile_subimage_view_width
|
|
, (int) tile_subimage_view_height
|
|
);
|
|
|
|
// the row_buffer is a 1D array which represents a 2D image. We cannot
|
|
// use interleaved_view here, since row_buffer could be bit_aligned.
|
|
// Interleaved_view's fourth parameter "rowsize_in_bytes" doesn't work
|
|
// for bit_aligned pixels.
|
|
|
|
for( std::ptrdiff_t dst_row = 0; dst_row < dst_subimage_view.height(); ++dst_row )
|
|
{
|
|
std::ptrdiff_t tile_row = dst_row + tile_y0;
|
|
|
|
// jump to the beginning of the current tile row
|
|
it_t begin = row_buffer_helper.begin() + tile_row * tile_width;
|
|
|
|
begin += tile_x0;
|
|
it_t end = begin + dst_subimage_view.width();
|
|
|
|
this->_cc_policy.read( begin
|
|
, end
|
|
, dst_subimage_view.row_begin( dst_row )
|
|
);
|
|
} //for
|
|
}
|
|
} // for
|
|
} // for
|
|
}
|
|
|
|
template< typename Buffer
|
|
, typename View
|
|
>
|
|
void read_tiled_data_full( const View& dst_view
|
|
, int plane
|
|
)
|
|
{
|
|
///@todo: why is
|
|
/// using row_buffer_helper_t = Buffer;
|
|
/// not working? I get compiler error with MSVC10.
|
|
/// read_stripped_data IS working.
|
|
using row_buffer_helper_t = detail::row_buffer_helper_view<View>;
|
|
|
|
using it_t = typename row_buffer_helper_t::iterator_t;
|
|
|
|
tiff_image_width::type image_width = this->_info._width;
|
|
tiff_image_height::type image_height = this->_info._height;
|
|
|
|
tiff_tile_width::type tile_width = this->_info._tile_width;
|
|
tiff_tile_length::type tile_height = this->_info._tile_length;
|
|
|
|
row_buffer_helper_t row_buffer_helper(this->_io_dev.get_tile_size(), true );
|
|
|
|
for( unsigned int y = 0; y < image_height; y += tile_height )
|
|
{
|
|
for( unsigned int x = 0; x < image_width; x += tile_width )
|
|
{
|
|
uint32_t current_tile_width = ( x + tile_width < image_width ) ? tile_width : image_width - x;
|
|
uint32_t current_tile_length = ( y + tile_height < image_height ) ? tile_height : image_height - y;
|
|
|
|
this->_io_dev.read_tile( row_buffer_helper.buffer()
|
|
, x
|
|
, y
|
|
, 0
|
|
, static_cast< tsample_t >( plane )
|
|
);
|
|
|
|
View dst_subimage_view = subimage_view( dst_view
|
|
, x
|
|
, y
|
|
, current_tile_width
|
|
, current_tile_length
|
|
);
|
|
|
|
// the row_buffer is a 1D array which represents a 2D image. We cannot
|
|
// use interleaved_view here, since row_buffer could be bit_aligned.
|
|
// Interleaved_view's fourth parameter "rowsize_in_bytes" doesn't work
|
|
// for bit_aligned pixels.
|
|
|
|
for( int row = 0; row < dst_subimage_view.height(); ++row )
|
|
{
|
|
it_t begin = row_buffer_helper.begin() + row * tile_width;
|
|
it_t end = begin + dst_subimage_view.width();
|
|
|
|
this->_cc_policy.read( begin
|
|
, end
|
|
, dst_subimage_view.row_begin( row )
|
|
);
|
|
} //for
|
|
} // for
|
|
} // for
|
|
}
|
|
|
|
template< typename Buffer
|
|
, typename View
|
|
>
|
|
void read_stripped_data( const View& dst_view
|
|
, int plane )
|
|
{
|
|
using is_view_bit_aligned_t = typename is_bit_aligned<typename View::value_type>::type;
|
|
|
|
//using row_buffer_helper_t =detail::row_buffer_helper_view<View>;
|
|
using row_buffer_helper_t = Buffer;
|
|
using it_t = typename row_buffer_helper_t::iterator_t;
|
|
|
|
std::size_t size_to_allocate = buffer_size< typename View::value_type >( dst_view.width()
|
|
, is_view_bit_aligned_t() );
|
|
row_buffer_helper_t row_buffer_helper( size_to_allocate, true );
|
|
|
|
it_t begin = row_buffer_helper.begin();
|
|
|
|
it_t first = begin + this->_settings._top_left.x;
|
|
it_t last = first + this->_settings._dim.x; // one after last element
|
|
|
|
// I don't think tiff allows for random access of row, that's why we need
|
|
// to read and discard rows when reading subimages.
|
|
skip_over_rows( row_buffer_helper.buffer()
|
|
, plane
|
|
);
|
|
|
|
std::ptrdiff_t row = this->_settings._top_left.y;
|
|
std::ptrdiff_t row_end = row + this->_settings._dim.y;
|
|
std::ptrdiff_t dst_row = 0;
|
|
|
|
for(
|
|
; row < row_end
|
|
; ++row, ++dst_row
|
|
)
|
|
{
|
|
this->_io_dev.read_scanline( row_buffer_helper.buffer()
|
|
, row
|
|
, static_cast< tsample_t >( plane )
|
|
);
|
|
|
|
this->_cc_policy.read( first
|
|
, last
|
|
, dst_view.row_begin( dst_row ));
|
|
}
|
|
}
|
|
|
|
template< typename Pixel >
|
|
std::size_t buffer_size( std::size_t width
|
|
, std::false_type // is_bit_aligned
|
|
)
|
|
{
|
|
std::size_t scanline_size_in_bytes = this->_io_dev.get_scanline_size();
|
|
|
|
std::size_t element_size = sizeof( Pixel );
|
|
|
|
std::size_t ret = std::max( width
|
|
, (( scanline_size_in_bytes + element_size - 1 ) / element_size )
|
|
);
|
|
|
|
return ret;
|
|
}
|
|
|
|
template< typename Pixel >
|
|
std::size_t buffer_size( std::size_t /* width */
|
|
, std::true_type // is_bit_aligned
|
|
)
|
|
{
|
|
return this->_io_dev.get_scanline_size();
|
|
}
|
|
|
|
private:
|
|
|
|
template < int K > friend struct plane_recursion;
|
|
};
|
|
|
|
namespace detail {
|
|
|
|
struct tiff_type_format_checker
|
|
{
|
|
tiff_type_format_checker( const image_read_info< tiff_tag >& info )
|
|
: _info( info )
|
|
{}
|
|
|
|
template< typename Image >
|
|
bool apply()
|
|
{
|
|
using view_t = typename Image::view_t;
|
|
|
|
return is_allowed< view_t >( _info
|
|
, std::true_type()
|
|
);
|
|
}
|
|
|
|
private:
|
|
tiff_type_format_checker& operator=( const tiff_type_format_checker& ) { return *this; }
|
|
|
|
private:
|
|
|
|
const image_read_info< tiff_tag > _info;
|
|
};
|
|
|
|
struct tiff_read_is_supported
|
|
{
|
|
template< typename View >
|
|
struct apply : public is_read_supported< typename get_pixel_type< View >::type
|
|
, tiff_tag
|
|
>
|
|
{};
|
|
};
|
|
|
|
} // namespace detail
|
|
|
|
|
|
///
|
|
/// Tiff Dynamic Image Reader
|
|
///
|
|
template< typename Device >
|
|
class dynamic_image_reader< Device
|
|
, tiff_tag
|
|
>
|
|
: public reader< Device
|
|
, tiff_tag
|
|
, detail::read_and_no_convert
|
|
>
|
|
{
|
|
using parent_t = reader<Device, tiff_tag, detail::read_and_no_convert>;
|
|
|
|
public:
|
|
|
|
dynamic_image_reader( const Device& io_dev
|
|
, const image_read_settings< tiff_tag >& settings
|
|
)
|
|
: parent_t( io_dev
|
|
, settings
|
|
)
|
|
{}
|
|
|
|
template< typename ...Images >
|
|
void apply( any_image< Images... >& images )
|
|
{
|
|
detail::tiff_type_format_checker format_checker( this->_info );
|
|
|
|
if( !construct_matched( images
|
|
, format_checker
|
|
))
|
|
{
|
|
io_error( "No matching image type between those of the given any_image and that of the file" );
|
|
}
|
|
else
|
|
{
|
|
this->init_image( images
|
|
, this->_settings
|
|
);
|
|
|
|
detail::dynamic_io_fnobj< detail::tiff_read_is_supported
|
|
, parent_t
|
|
> op( this );
|
|
|
|
variant2::visit( op
|
|
, view( images )
|
|
);
|
|
}
|
|
}
|
|
};
|
|
|
|
#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
|
|
#pragma warning(pop)
|
|
#endif
|
|
|
|
} // namespace gil
|
|
} // namespace boost
|
|
|
|
#endif
|