add boost on mac

This commit is contained in:
Bassem Girgis
2019-08-10 16:38:17 -05:00
parent 861b918727
commit be945cb63b
14105 changed files with 2714968 additions and 0 deletions

View File

@@ -0,0 +1,479 @@
//
// Copyright 2007-2008 Andreas Pokorny, Christian Henning
//
// 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_DEVICE_HPP
#define BOOST_GIL_EXTENSION_IO_TIFF_DETAIL_DEVICE_HPP
#include <boost/gil/extension/io/tiff/tags.hpp>
#include <boost/gil/extension/io/tiff/detail/log.hpp>
#include <boost/gil/io/base.hpp>
#include <boost/gil/io/device.hpp>
#include <boost/mpl/size.hpp>
#include <algorithm>
#include <memory>
#include <sstream>
// 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
#include <tiffio.hxx>
namespace boost { namespace gil { namespace detail {
template <int n_args>
struct get_property_f {
template <typename Property>
bool call_me(typename Property:: type& value, std::shared_ptr<TIFF>& file);
};
template <int n_args>
struct set_property_f {
template <typename Property>
bool call_me(const typename Property:: type& value, std::shared_ptr<TIFF>& file) const;
};
template <> struct get_property_f <1>
{
// For single-valued properties
template <typename Property>
bool call_me(typename Property::type & value, std::shared_ptr<TIFF>& file) const
{
// @todo: defaulted, really?
return (1 == TIFFGetFieldDefaulted( file.get()
, Property:: tag
, & value));
}
};
template <> struct get_property_f <2>
{
// Specialisation for multi-valued properties. @todo: add one of
// these for the three-parameter fields too.
template <typename Property>
bool call_me(typename Property:: type & vs, std::shared_ptr<TIFF>& file) const
{
typename mpl:: at <typename Property:: arg_types, mpl::int_<0> >:: type length;
typename mpl:: at <typename Property:: arg_types, mpl::int_<1> >:: type pointer;
if (1 == TIFFGetFieldDefaulted( file.get()
, Property:: tag
, & length
, & pointer)) {
std:: copy_n (static_cast <typename Property:: type:: const_pointer> (pointer), length, std:: back_inserter (vs));
return true;
} else
return false;
}
};
template <> struct set_property_f <1>
{
// For single-valued properties
template <typename Property>
inline
bool call_me(typename Property:: type const & value, std::shared_ptr<TIFF>& file) const
{
return (1 == TIFFSetField( file.get()
, Property:: tag
, value));
}
};
template <> struct set_property_f <2>
{
// Specialisation for multi-valued properties. @todo: add one
// of these for the three-parameter fields too. Actually we
// will need further templation / specialisation for the
// two-element fields which aren't a length and a data buffer
// (e.g. http://www.awaresystems.be/imaging/tiff/tifftags/dotrange.html
// )
template <typename Property>
inline
bool call_me(typename Property:: type const & values, std::shared_ptr<TIFF>& file) const
{
typename mpl:: at <typename Property:: arg_types, mpl::int_<0> >:: type const length = values. size ();
typename mpl:: at <typename Property:: arg_types, mpl::int_<1> >:: type const pointer = & (values. front ());
return (1 == TIFFSetField( file.get()
, Property:: tag
, length
, pointer));
}
};
template< typename Log >
class tiff_device_base
{
public:
using tiff_file_t = std::shared_ptr<TIFF>;
tiff_device_base()
{}
tiff_device_base( TIFF* tiff_file )
: _tiff_file( tiff_file
, TIFFClose )
{}
template <typename Property>
bool get_property( typename Property::type& value )
{
return get_property_f <mpl:: size <typename Property:: arg_types>::value > ().template call_me<Property>(value, _tiff_file);
}
template <typename Property>
inline
bool set_property( const typename Property::type& value )
{
// http://www.remotesensing.org/libtiff/man/TIFFSetField.3tiff.html
return set_property_f <mpl:: size <typename Property:: arg_types>::value > ().template call_me<Property> (value, _tiff_file);
}
// TIFFIsByteSwapped returns a non-zero value if the image data was in a different
// byte-order than the host machine. Zero is returned if the TIFF file and local
// host byte-orders are the same. Note that TIFFReadTile(), TIFFReadStrip() and TIFFReadScanline()
// functions already normally perform byte swapping to local host order if needed.
bool are_bytes_swapped()
{
return ( TIFFIsByteSwapped( _tiff_file.get() )) ? true : false;
}
bool is_tiled() const
{
return ( TIFFIsTiled( _tiff_file.get() )) ? true : false;
}
unsigned int get_default_strip_size()
{
return TIFFDefaultStripSize( _tiff_file.get()
, 0 );
}
std::size_t get_scanline_size()
{
return TIFFScanlineSize( _tiff_file.get() );
}
std::size_t get_tile_size()
{
return TIFFTileSize( _tiff_file.get() );
}
int get_field_defaulted( uint16_t*& red
, uint16_t*& green
, uint16_t*& blue
)
{
return TIFFGetFieldDefaulted( _tiff_file.get()
, TIFFTAG_COLORMAP
, &red
, &green
, &blue
);
}
template< typename Buffer >
void read_scanline( Buffer& buffer
, std::ptrdiff_t row
, tsample_t plane
)
{
io_error_if( TIFFReadScanline( _tiff_file.get()
, reinterpret_cast< tdata_t >( &buffer.front() )
, (uint32) row
, plane ) == -1
, "Read error."
);
}
void read_scanline( byte_t* buffer
, std::ptrdiff_t row
, tsample_t plane
)
{
io_error_if( TIFFReadScanline( _tiff_file.get()
, reinterpret_cast< tdata_t >( buffer )
, (uint32) row
, plane ) == -1
, "Read error."
);
}
template< typename Buffer >
void read_tile( Buffer& buffer
, std::ptrdiff_t x
, std::ptrdiff_t y
, std::ptrdiff_t z
, tsample_t plane
)
{
if( TIFFReadTile( _tiff_file.get()
, reinterpret_cast< tdata_t >( &buffer.front() )
, (uint32) x
, (uint32) y
, (uint32) z
, plane
) == -1 )
{
std::ostringstream oss;
oss << "Read tile error (" << x << "," << y << "," << z << "," << plane << ").";
io_error(oss.str().c_str());
}
}
template< typename Buffer >
void write_scaline( Buffer& buffer
, uint32 row
, tsample_t plane
)
{
io_error_if( TIFFWriteScanline( _tiff_file.get()
, &buffer.front()
, row
, plane
) == -1
, "Write error"
);
}
void write_scaline( byte_t* buffer
, uint32 row
, tsample_t plane
)
{
io_error_if( TIFFWriteScanline( _tiff_file.get()
, buffer
, row
, plane
) == -1
, "Write error"
);
}
template< typename Buffer >
void write_tile( Buffer& buffer
, uint32 x
, uint32 y
, uint32 z
, tsample_t plane
)
{
if( TIFFWriteTile( _tiff_file.get()
, &buffer.front()
, x
, y
, z
, plane
) == -1 )
{
std::ostringstream oss;
oss << "Write tile error (" << x << "," << y << "," << z << "," << plane << ").";
io_error(oss.str().c_str());
}
}
void set_directory( tdir_t directory )
{
io_error_if( TIFFSetDirectory( _tiff_file.get()
, directory
) != 1
, "Failing to set directory"
);
}
// return false if the given tile width or height is not TIFF compliant (multiple of 16) or larger than image size, true otherwise
bool check_tile_size( tiff_tile_width::type& width
, tiff_tile_length::type& height
)
{
bool result = true;
uint32 tw = static_cast< uint32 >( width );
uint32 th = static_cast< uint32 >( height );
TIFFDefaultTileSize( _tiff_file.get()
, &tw
, &th
);
if(width==0 || width%16!=0)
{
width = tw;
result = false;
}
if(height==0 || height%16!=0)
{
height = th;
result = false;
}
return result;
}
protected:
tiff_file_t _tiff_file;
Log _log;
};
/*!
*
* file_stream_device specialization for tiff images, which are based on TIFF*.
*/
template<>
class file_stream_device< tiff_tag > : public tiff_device_base< tiff_no_log >
{
public:
struct read_tag {};
struct write_tag {};
file_stream_device( std::string const& file_name, read_tag )
{
TIFF* tiff;
io_error_if( ( tiff = TIFFOpen( file_name.c_str(), "r" )) == nullptr
, "file_stream_device: failed to open file" );
_tiff_file = tiff_file_t( tiff, TIFFClose );
}
file_stream_device( std::string const& file_name, write_tag )
{
TIFF* tiff;
io_error_if( ( tiff = TIFFOpen( file_name.c_str(), "w" )) == nullptr
, "file_stream_device: failed to open file" );
_tiff_file = tiff_file_t( tiff, TIFFClose );
}
file_stream_device( TIFF* tiff_file )
: tiff_device_base( tiff_file )
{}
};
/*!
*
* ostream_device specialization for tiff images.
*/
template<>
class ostream_device< tiff_tag > : public tiff_device_base< tiff_no_log >
{
public:
ostream_device( std::ostream & out )
: _out( out )
{
TIFF* tiff;
io_error_if( ( tiff = TIFFStreamOpen( ""
, &_out
)
) == nullptr
, "ostream_device: failed to stream"
);
_tiff_file = tiff_file_t( tiff, TIFFClose );
}
private:
ostream_device& operator=( const ostream_device& ) { return *this; }
private:
std::ostream& _out;
};
/*!
*
* ostream_device specialization for tiff images.
*/
template<>
class istream_device< tiff_tag > : public tiff_device_base< tiff_no_log >
{
public:
istream_device( std::istream & in )
: _in( in )
{
TIFF* tiff;
io_error_if( ( tiff = TIFFStreamOpen( ""
, &_in
)
) == nullptr
, "istream_device: failed to stream"
);
_tiff_file = tiff_file_t( tiff, TIFFClose );
}
private:
istream_device& operator=( const istream_device& ) { return *this; }
private:
std::istream& _in;
};
/*
template< typename T, typename D >
struct is_adaptable_input_device< tiff_tag, T, D > : mpl::false_{};
*/
template< typename FormatTag >
struct is_adaptable_input_device< FormatTag
, TIFF*
, void
>
: mpl::true_
{
using device_type = file_stream_device<FormatTag>;
};
template< typename FormatTag >
struct is_adaptable_output_device< FormatTag
, TIFF*
, void
>
: mpl::true_
{
using device_type = file_stream_device<FormatTag>;
};
template < typename Channel > struct sample_format : public mpl::int_<SAMPLEFORMAT_UINT> {};
template<> struct sample_format<uint8_t> : public mpl::int_<SAMPLEFORMAT_UINT> {};
template<> struct sample_format<uint16_t> : public mpl::int_<SAMPLEFORMAT_UINT> {};
template<> struct sample_format<uint32_t> : public mpl::int_<SAMPLEFORMAT_UINT> {};
template<> struct sample_format<float32_t> : public mpl::int_<SAMPLEFORMAT_IEEEFP> {};
template<> struct sample_format<double> : public mpl::int_<SAMPLEFORMAT_IEEEFP> {};
template<> struct sample_format<int8_t> : public mpl::int_<SAMPLEFORMAT_INT> {};
template<> struct sample_format<int16_t> : public mpl::int_<SAMPLEFORMAT_INT> {};
template<> struct sample_format<int32_t> : public mpl::int_<SAMPLEFORMAT_INT> {};
template <typename Channel> struct photometric_interpretation {};
template<> struct photometric_interpretation< gray_t > : public mpl::int_< PHOTOMETRIC_MINISBLACK > {};
template<> struct photometric_interpretation< rgb_t > : public mpl::int_< PHOTOMETRIC_RGB > {};
template<> struct photometric_interpretation< rgba_t > : public mpl::int_< PHOTOMETRIC_RGB > {};
template<> struct photometric_interpretation< cmyk_t > : public mpl::int_< PHOTOMETRIC_SEPARATED > {};
} // namespace detail
} // namespace gil
} // namespace boost
#endif

View File

@@ -0,0 +1,256 @@
//
// Copyright 2008 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_IS_ALLOWED_HPP
#define BOOST_GIL_EXTENSION_IO_TIFF_DETAIL_IS_ALLOWED_HPP
#include <boost/gil/extension/io/tiff/tags.hpp>
#include <boost/gil/io/base.hpp>
#include <boost/mpl/for_each.hpp>
#include <type_traits>
namespace boost { namespace gil { namespace detail {
using channel_sizes_t = std::vector<tiff_bits_per_sample::type>;
template <typename View, typename Channel, typename Enable = void>
struct Format_Type {};
// is_bit_aligned< View >
template <typename View, typename Channel>
struct Format_Type
<
View,
Channel,
typename std::enable_if
<
is_bit_aligned
<
typename get_pixel_type<View>::type
>::value
>::type
>
{
static const int value = SAMPLEFORMAT_UINT;
};
// is_not_bit_aligned< View > && is_unsigned< Channel >
template <typename View, typename Channel>
struct Format_Type
<
View,
Channel,
typename std::enable_if
<
mpl::and_
<
mpl::not_
<
typename is_bit_aligned<typename get_pixel_type<View>::type>::type
>,
is_unsigned<Channel>
>::value
>::type
>
{
static const int value = SAMPLEFORMAT_UINT;
};
// is_not_bit_aligned< View > && is_signed< Channel >
template <typename View, typename Channel>
struct Format_Type
<
View,
Channel,
typename std::enable_if
<
mpl::and_
<
mpl::not_
<
typename is_bit_aligned<typename get_pixel_type<View>::type>::type
>,
is_signed<Channel>
>::value
>::type
>
{
static const int value = SAMPLEFORMAT_INT;
};
// is_not_bit_aligned< View > && is_floating_point< Channel >
template <typename View, typename Channel>
struct Format_Type
<
View,
Channel,
typename std::enable_if
<
mpl::and_
<
mpl::not_
<
typename is_bit_aligned<typename get_pixel_type<View>::type>::type
>,
is_floating_point<Channel>
>::value
>::type
>
{
static const int value = SAMPLEFORMAT_IEEEFP;
};
//template< typename Channel >
//int format_value( mpl::true_ ) // is_bit_aligned
//{
// return SAMPLEFORMAT_UINT;
//}
//
//template< typename Channel >
//int format_value( mpl::false_ ) // is_bit_aligned
//{
// if( is_unsigned< Channel >::value )
// {
// return SAMPLEFORMAT_UINT;
// }
//
// if( is_signed< Channel >::value )
// {
// return SAMPLEFORMAT_INT;
// }
//
// else if( is_floating_point< Channel >::value )
// {
// return SAMPLEFORMAT_IEEEFP;
// }
//
// io_error( "Unkown channel format." );
//}
// The following two functions look the same but are different since one is using
// a pixel_t as template parameter whereas the other is using reference_t.
template< typename View >
bool compare_channel_sizes( const channel_sizes_t& channel_sizes // in bits
, mpl::false_ // is_bit_aligned
, mpl::true_ // is_homogeneous
)
{
using pixel_t = typename View::value_type;
using channel_t = typename channel_traits<typename element_type<pixel_t>::type>::value_type;
unsigned int s = detail::unsigned_integral_num_bits< channel_t >::value;
return ( s == channel_sizes[0] );
}
template< typename View >
bool compare_channel_sizes( const channel_sizes_t& channel_sizes // in bits
, mpl::true_ // is_bit_aligned
, mpl::true_ // is_homogeneous
)
{
using ref_t = typename View::reference;
using channel_t = typename channel_traits<typename element_type<ref_t>::type>::value_type;
channel_t c;
unsigned int s = detail::unsigned_integral_num_bits< channel_t >::value;
return ( s == channel_sizes[0] );
}
struct compare_channel_sizes_fn
{
compare_channel_sizes_fn( uint16_t* a )
: _a( a )
, _b( true )
{}
template< typename ChannelSize >
void operator()( ChannelSize x)
{
if( x != *_a++ )
{
_b = false;
}
}
uint16_t* _a;
bool _b;
};
template< typename T >
struct channel_sizes_type {};
template< typename B, typename C, typename L, bool M >
struct channel_sizes_type< bit_aligned_pixel_reference< B, C, L, M > > { using type = C; };
template< typename B, typename C, typename L, bool M >
struct channel_sizes_type< const bit_aligned_pixel_reference< B, C, L, M > > { using type = C; };
template< typename View >
bool compare_channel_sizes( channel_sizes_t& channel_sizes // in bits
, mpl::true_ // is_bit_aligned
, mpl::false_ // is_homogeneous
)
{
// loop through all channels and compare
using ref_t = typename View::reference;
using cs_t = typename channel_sizes_type<ref_t>::type;
compare_channel_sizes_fn fn( &channel_sizes.front() );
mpl::for_each< cs_t >( fn );
return fn._b;
}
template< typename View >
bool is_allowed( const image_read_info< tiff_tag >& info
, mpl::true_ // is read_and_no_convert
)
{
channel_sizes_t channel_sizes( info._samples_per_pixel
, info._bits_per_sample
);
using pixel_t = typename get_pixel_type<View>::type;
using channel_t = typename channel_traits<typename element_type<pixel_t>::type>::value_type;
using num_channel_t = typename num_channels<pixel_t>::value_type;
const num_channel_t dst_samples_per_pixel = num_channels< pixel_t >::value;
//const num_channel_t dst_sample_format = format_value< channel_t >( typename is_bit_aligned< pixel_t >::type() );
const num_channel_t dst_sample_format = Format_Type<View, channel_t>::value;
return ( dst_samples_per_pixel == info._samples_per_pixel
&& compare_channel_sizes< View >( channel_sizes
, typename is_bit_aligned< pixel_t >::type()
, typename is_homogeneous< pixel_t >::type()
)
&& dst_sample_format == info._sample_format
);
}
template< typename View >
bool is_allowed( const image_read_info< tiff_tag >& /* info */
, mpl::false_ // is read_and_no_convert
)
{
return true;
}
} // namespace detail
} // namespace gil
} // namespace boost
#endif

View File

@@ -0,0 +1,66 @@
//
// Copyright 2009 Christian Henning
//
// 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_LOG_HPP
#define BOOST_GIL_EXTENSION_IO_TIFF_DETAIL_LOG_HPP
#include <iostream>
extern "C" {
#include "tiffio.h"
}
namespace boost { namespace gil {
class tiff_no_log
{
public:
tiff_no_log()
{
TIFFSetErrorHandler ( nullptr );
TIFFSetWarningHandler( nullptr );
}
};
class console_log
{
public:
console_log()
{
TIFFSetErrorHandler ( console_log::error );
TIFFSetWarningHandler( console_log::warning );
}
private:
static void error( const char* /* module */
, const char* fmt
, va_list ap
)
{
char buf[1000];
sprintf(buf, fmt, ap);
std::cout << "error: " << buf << std::endl;
}
static void warning( char const* /* module */
, char const* fmt
, va_list ap
)
{
char buf[1000];
sprintf(buf, fmt, ap);
std::cout << "warning: " << fmt << std::endl;
}
};
} // namespace gil
} // namespace boost
#endif

View File

@@ -0,0 +1,780 @@
//
// 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/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/dynamic_io_new.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 <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 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
, mpl::true_ // is_read_only
)
{
read_data< detail::row_buffer_helper_view< View > >( v, 0 );
}
template< typename View >
void read( View v
, mpl::false_ // 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 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
, mpl::true_ // 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 */
, mpl::false_ // 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
, mpl::false_ // 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 */
, mpl::true_ // 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
, mpl::true_()
);
}
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 );
apply_operation( view( images )
, op
);
}
}
};
#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
#pragma warning(pop)
#endif
} // namespace gil
} // namespace boost
#endif

View File

@@ -0,0 +1,162 @@
//
// Copyright 2012 Christian Henning
//
// 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_BACKEND_HPP
#define BOOST_GIL_EXTENSION_IO_TIFF_DETAIL_READER_BACKEND_HPP
#include <boost/gil/extension/io/tiff/tags.hpp>
namespace boost { namespace gil {
#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
#pragma warning(push)
#pragma warning(disable:4512) //assignment operator could not be generated
#endif
///
/// TIFF Backend
///
template< typename Device >
struct reader_backend< Device
, tiff_tag
>
{
public:
using format_tag_t = tiff_tag;
public:
reader_backend( const Device& io_dev
, const image_read_settings< tiff_tag >& settings
)
: _io_dev ( io_dev )
, _settings( settings )
, _info()
, _scanline_length( 0 )
, _red ( nullptr )
, _green( nullptr )
, _blue ( nullptr )
{
init_multipage_read( settings );
read_header();
if( _settings._dim.x == 0 )
{
_settings._dim.x = _info._width;
}
if( _settings._dim.y == 0 )
{
_settings._dim.y = _info._height;
}
}
void read_header()
{
io_error_if( _io_dev.template get_property<tiff_image_width> ( _info._width ) == false
, "cannot read tiff tag." );
io_error_if( _io_dev.template get_property<tiff_image_height> ( _info._height ) == false
, "cannot read tiff tag." );
io_error_if( _io_dev.template get_property<tiff_compression> ( _info._compression ) == false
, "cannot read tiff tag." );
io_error_if( _io_dev.template get_property<tiff_samples_per_pixel> ( _info._samples_per_pixel ) == false
, "cannot read tiff tag." );
io_error_if( _io_dev.template get_property<tiff_bits_per_sample> ( _info._bits_per_sample ) == false
, "cannot read tiff tag." );
io_error_if( _io_dev.template get_property<tiff_sample_format> ( _info._sample_format ) == false
, "cannot read tiff tag." );
io_error_if( _io_dev.template get_property<tiff_planar_configuration> ( _info._planar_configuration ) == false
, "cannot read tiff tag." );
io_error_if( _io_dev.template get_property<tiff_photometric_interpretation>( _info._photometric_interpretation ) == false
, "cannot read tiff tag." );
_info._is_tiled = false;
// Tile tags
if( _io_dev.is_tiled() )
{
_info._is_tiled = true;
io_error_if( !_io_dev.template get_property< tiff_tile_width >( _info._tile_width )
, "cannot read tiff_tile_width tag." );
io_error_if( !_io_dev.template get_property< tiff_tile_length >( _info._tile_length )
, "cannot read tiff_tile_length tag." );
}
io_error_if( _io_dev.template get_property<tiff_resolution_unit>( _info._resolution_unit) == false
, "cannot read tiff tag");
io_error_if( _io_dev. template get_property<tiff_x_resolution>( _info._x_resolution ) == false
, "cannot read tiff tag" );
io_error_if( _io_dev. template get_property<tiff_y_resolution>( _info._y_resolution ) == false
, "cannot read tiff tag" );
/// optional and non-baseline properties below here
_io_dev. template get_property <tiff_icc_profile> ( _info._icc_profile );
}
/// Check if image is large enough.
void check_image_size( const point_t& img_dim )
{
if( _settings._dim.x > 0 )
{
if( img_dim.x < _settings._dim.x ) { io_error( "Supplied image is too small" ); }
}
else
{
if( (tiff_image_width::type) img_dim.x < _info._width ) { io_error( "Supplied image is too small" ); }
}
if( _settings._dim.y > 0 )
{
if( img_dim.y < _settings._dim.y ) { io_error( "Supplied image is too small" ); }
}
else
{
if( (tiff_image_height::type) img_dim.y < _info._height ) { io_error( "Supplied image is too small" ); }
}
}
private:
void init_multipage_read( const image_read_settings< tiff_tag >& settings )
{
if( settings._directory > 0 )
{
_io_dev.set_directory( settings._directory );
}
}
public:
Device _io_dev;
image_read_settings< tiff_tag > _settings;
image_read_info< tiff_tag > _info;
std::size_t _scanline_length;
// palette
tiff_color_map::red_t _red;
tiff_color_map::green_t _green;
tiff_color_map::blue_t _blue;
rgb16_planar_view_t _palette;
};
#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
#pragma warning(pop)
#endif
} // namespace gil
} // namespace boost
#endif

View File

@@ -0,0 +1,447 @@
//
// 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 <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/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/gil/io/scanline_read_iterator.hpp>
#include <algorithm>
#include <functional>
#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 {
///
/// 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<Device, tag_t>;
using this_t = scanline_reader<Device, tag_t>;
using iterator_t = scanline_read_iterator<this_t>;
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<rgb16_view_t>::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<get_pixel_type<gray1_image_t::view_t>::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<get_pixel_type<gray2_image_t::view_t>::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<get_pixel_type<gray4_image_t::view_t>::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<get_pixel_type<gray8_image_t::view_t>::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<get_pixel_type<gray16_image_t::view_t>::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<get_pixel_type<gray24_image_t::view_t>::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<get_pixel_type<gray32_image_t::view_t>::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<std::uint16_t>(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::vector<byte_t>, std::true_type> _mirror_bites;
std::function<void(this_t*, byte_t*, int)> _read_function;
};
} // namespace gil
} // namespace boost
#endif

View File

@@ -0,0 +1,54 @@
//
// Copyright 2007-2008 Christian Henning, Andreas Pokorny, 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_SUPPORTED_TYPES_HPP
#define BOOST_GIL_EXTENSION_IO_TIFF_DETAIL_SUPPORTED_TYPES_HPP
#include <boost/gil/extension/io/tiff/tags.hpp>
#include <boost/gil/channel.hpp>
#include <boost/gil/color_base.hpp>
#include <boost/gil/io/base.hpp>
#include <boost/mpl/not.hpp>
#include <boost/type_traits/is_same.hpp>
namespace boost{ namespace gil {
namespace detail {
// Read support
// TIFF virtually supports everything
struct tiff_read_support : read_support_true
{};
// Write support
struct tiff_write_support : write_support_true
{};
} // namespace detail
template< typename Pixel >
struct is_read_supported< Pixel
, tiff_tag
>
: mpl::bool_< detail::tiff_read_support::is_supported > {};
template< typename Pixel >
struct is_write_supported< Pixel
, tiff_tag
>
: mpl::bool_< detail::tiff_write_support::is_supported >
{};
} // namespace gil
} // namespace boost
#endif

View File

@@ -0,0 +1,449 @@
//
// 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_WRITE_HPP
#define BOOST_GIL_EXTENSION_IO_TIFF_DETAIL_WRITE_HPP
#include <boost/gil/extension/io/tiff/tags.hpp>
#include <boost/gil/extension/io/tiff/detail/writer_backend.hpp>
#include <boost/gil/extension/io/tiff/detail/device.hpp>
#include <boost/gil/premultiply.hpp>
#include <boost/gil/io/base.hpp>
#include <boost/gil/io/device.hpp>
#include <boost/gil/io/dynamic_io_new.hpp>
#include <algorithm>
#include <string>
#include <vector>
extern "C" {
#include "tiff.h"
#include "tiffio.h"
}
namespace boost { namespace gil {
#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
#pragma warning(push)
#pragma warning(disable:4512) //assignment operator could not be generated
#endif
namespace detail {
template <typename PixelReference>
struct my_interleaved_pixel_iterator_type_from_pixel_reference
{
private:
using pixel_t = typename remove_reference<PixelReference>::type::value_type;
public:
using type = typename iterator_type_from_pixel
<
pixel_t,
false,
false,
true
>::type;
};
template< typename Channel
, typename Layout
, bool Mutable
>
struct my_interleaved_pixel_iterator_type_from_pixel_reference< const bit_aligned_pixel_reference< byte_t
, Channel
, Layout
, Mutable
>
>
: public iterator_type_from_pixel< const bit_aligned_pixel_reference< uint8_t
, Channel
, Layout
, Mutable
>
,false
,false
,true
> {};
struct tiff_write_is_supported
{
template< typename View >
struct apply
: public is_write_supported< typename get_pixel_type< View >::type
, tiff_tag
>
{};
};
} // namespace detail
///
/// TIFF Writer
///
template < typename Device, typename Log >
class writer< Device
, tiff_tag
, Log
>
: public writer_backend< Device
, tiff_tag
>
{
private:
using backend_t = writer_backend<Device, tiff_tag>;
public:
writer( const Device& io_dev
, const image_write_info< tiff_tag >& info
)
: backend_t( io_dev
, info
)
{}
template<typename View>
void apply( const View& view )
{
write_view( view );
}
private:
template< typename View >
void write_view( const View& view )
{
using pixel_t = typename View::value_type;
// get the type of the first channel (heterogeneous pixels might be broken for now!)
using channel_t = typename channel_traits<typename element_type<pixel_t>::type>::value_type;
tiff_bits_per_sample::type bits_per_sample = detail::unsigned_integral_num_bits< channel_t >::value;
tiff_samples_per_pixel::type samples_per_pixel = num_channels< pixel_t >::value;
this->write_header( view );
if( this->_info._is_tiled == false )
{
write_data( view
, (view.width() * samples_per_pixel * bits_per_sample + 7) / 8
, typename is_bit_aligned< pixel_t >::type()
);
}
else
{
tiff_tile_width::type tw = this->_info._tile_width;
tiff_tile_length::type th = this->_info._tile_length;
if(!this->_io_dev.check_tile_size( tw, th ))
{
io_error( "Tile sizes need to be multiples of 16." );
}
// tile related tags
this->_io_dev.template set_property<tiff_tile_width> ( tw );
this->_io_dev.template set_property<tiff_tile_length>( th );
write_tiled_data( view
, tw
, th
, typename is_bit_aligned< pixel_t >::type()
);
}
}
//////////////////////////////
template<typename View>
void write_bit_aligned_view_to_dev( const View& view
, const std::size_t row_size_in_bytes
, const mpl::true_& // has_alpha
)
{
byte_vector_t row( row_size_in_bytes );
using x_it_t = typename View::x_iterator;
x_it_t row_it = x_it_t( &(*row.begin()));
auto pm_view = premultiply_view <typename View:: value_type> (view);
for( typename View::y_coord_t y = 0; y < pm_view.height(); ++y )
{
std::copy( pm_view.row_begin( y )
, pm_view.row_end( y )
, row_it
);
this->_io_dev.write_scaline( row
, (uint32) y
, 0
);
// @todo: do optional bit swapping here if you need to...
}
}
template<typename View>
void write_bit_aligned_view_to_dev( const View& view
, const std::size_t row_size_in_bytes
, const mpl::false_& // has_alpha
)
{
byte_vector_t row( row_size_in_bytes );
using x_it_t = typename View::x_iterator;
x_it_t row_it = x_it_t( &(*row.begin()));
for( typename View::y_coord_t y = 0; y < view.height(); ++y )
{
std::copy( view.row_begin( y )
, view.row_end( y )
, row_it
);
this->_io_dev.write_scaline( row
, (uint32) y
, 0
);
// @todo: do optional bit swapping here if you need to...
}
}
/////////////////////////////
template< typename View >
void write_data( const View& view
, std::size_t row_size_in_bytes
, const mpl::true_& // bit_aligned
)
{
using colour_space_t = typename color_space_type<typename View::value_type>::type;
using has_alpha_t = mpl::bool_<mpl::contains<colour_space_t, alpha_t>::value>;
write_bit_aligned_view_to_dev(view, row_size_in_bytes, has_alpha_t());
}
template< typename View>
void write_tiled_data( const View& view
, tiff_tile_width::type tw
, tiff_tile_length::type th
, const mpl::true_& // bit_aligned
)
{
byte_vector_t row( this->_io_dev.get_tile_size() );
using x_it_t = typename View::x_iterator;
x_it_t row_it = x_it_t( &(*row.begin()));
internal_write_tiled_data(view, tw, th, row, row_it);
}
template< typename View >
void write_data( const View& view
, std::size_t
, const mpl::false_& // bit_aligned
)
{
std::vector< pixel< typename channel_type< View >::type
, layout<typename color_space_type< View >::type >
>
> row( view.size() );
byte_t* row_addr = reinterpret_cast< byte_t* >( &row.front() );
// @todo: is there an overhead to doing this when there's no
// alpha to premultiply by? I'd hope it's optimised out.
auto pm_view = premultiply_view <typename View:: value_type> (view);
for( typename View::y_coord_t y = 0; y < pm_view.height(); ++y )
{
std::copy( pm_view.row_begin( y )
, pm_view.row_end( y )
, row.begin()
);
this->_io_dev.write_scaline( row_addr
, (uint32) y
, 0
);
// @todo: do optional bit swapping here if you need to...
}
}
template< typename View >
void write_tiled_data( const View& view
, tiff_tile_width::type tw
, tiff_tile_length::type th
, const mpl::false_& // bit_aligned
)
{
byte_vector_t row( this->_io_dev.get_tile_size() );
using x_iterator = typename detail::my_interleaved_pixel_iterator_type_from_pixel_reference<typename View::reference>::type;
x_iterator row_it = x_iterator( &(*row.begin()));
internal_write_tiled_data(view, tw, th, row, row_it);
}
//////////////////////////////
template< typename View
, typename IteratorType
>
void write_tiled_view_to_dev( const View& view
, IteratorType it
, const mpl::true_& // has_alpha
)
{
auto pm_view = premultiply_view <typename View:: value_type>( view );
std::copy( pm_view.begin()
, pm_view.end()
, it
);
}
template< typename View
, typename IteratorType
>
void write_tiled_view_to_dev( const View& view
, IteratorType it
, const mpl::false_& // has_alpha
)
{
std::copy( view.begin()
, view.end()
, it
);
}
/////////////////////////////
template< typename View,
typename IteratorType
>
void internal_write_tiled_data( const View& view
, tiff_tile_width::type tw
, tiff_tile_length::type th
, byte_vector_t& row
, IteratorType it
)
{
std::ptrdiff_t i = 0, j = 0;
View tile_subimage_view;
while( i < view.height() )
{
while( j < view.width() )
{
if( j + tw < view.width() && i + th < view.height() )
{
// a tile is fully included in the image: just copy values
tile_subimage_view = subimage_view( view
, static_cast< int >( j )
, static_cast< int >( i )
, static_cast< int >( tw )
, static_cast< int >( th )
);
using colour_space_t = typename color_space_type<typename View::value_type>::type;
using has_alpha_t = mpl::bool_<mpl::contains<colour_space_t, alpha_t>::value>;
write_tiled_view_to_dev(tile_subimage_view, it, has_alpha_t());
}
else
{
std::ptrdiff_t width = view.width();
std::ptrdiff_t height = view.height();
std::ptrdiff_t current_tile_width = ( j + tw < width ) ? tw : width - j;
std::ptrdiff_t current_tile_length = ( i + th < height) ? th : height - i;
tile_subimage_view = subimage_view( view
, static_cast< int >( j )
, static_cast< int >( i )
, static_cast< int >( current_tile_width )
, static_cast< int >( current_tile_length )
);
for( typename View::y_coord_t y = 0; y < tile_subimage_view.height(); ++y )
{
std::copy( tile_subimage_view.row_begin( y )
, tile_subimage_view.row_end( y )
, it
);
std::advance(it, tw);
}
it = IteratorType( &(*row.begin()));
}
this->_io_dev.write_tile( row
, static_cast< uint32 >( j )
, static_cast< uint32 >( i )
, 0
, 0
);
j += tw;
}
j = 0;
i += th;
}
// @todo: do optional bit swapping here if you need to...
}
};
///
/// TIFF Dynamic Image Writer
///
template< typename Device >
class dynamic_image_writer< Device
, tiff_tag
>
: public writer< Device
, tiff_tag
>
{
using parent_t = writer<Device, tiff_tag>;
public:
dynamic_image_writer( const Device& io_dev
, const image_write_info< tiff_tag >& info
)
: parent_t( io_dev
, info
)
{}
template< typename Views >
void apply( const any_image_view< Views >& views )
{
detail::dynamic_io_fnobj< detail::tiff_write_is_supported
, parent_t
> op( this );
apply_operation( views, op );
}
};
#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
#pragma warning(pop)
#endif
} // namespace gil
} // namespace boost
#endif

View File

@@ -0,0 +1,135 @@
//
// Copyright 2012 Christian Henning
//
// 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_WRITER_BACKEND_HPP
#define BOOST_GIL_EXTENSION_IO_TIFF_DETAIL_WRITER_BACKEND_HPP
#include <boost/gil/extension/io/tiff/tags.hpp>
#include <boost/gil/extension/io/tiff/detail/device.hpp>
#include <boost/mpl/contains.hpp>
namespace boost { namespace gil {
#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
#pragma warning(push)
#pragma warning(disable:4512) //assignment operator could not be generated
#endif
///
/// TIFF Writer Backend
///
template< typename Device >
struct writer_backend< Device
, tiff_tag
>
{
public:
using format_tag_t = tiff_tag;
public:
writer_backend( const Device& io_dev
, const image_write_info< tiff_tag >& info
)
: _io_dev( io_dev )
, _info( info )
{}
protected:
template< typename View >
void write_header( const View& view )
{
using pixel_t = typename View::value_type;
// get the type of the first channel (heterogeneous pixels might be broken for now!)
using channel_t = typename channel_traits<typename element_type<pixel_t>::type>::value_type;
using color_space_t = typename color_space_type<View>::type;
if(! this->_info._photometric_interpretation_user_defined )
{
// write photometric interpretion - Warning: This value is rather
// subjective. The user should better set this value itself. There
// is no way to decide if a image is PHOTOMETRIC_MINISWHITE or
// PHOTOMETRIC_MINISBLACK. If the user has not manually set it, then
// this writer will assume PHOTOMETRIC_MINISBLACK for gray_t images,
// PHOTOMETRIC_RGB for rgb_t images, and PHOTOMETRIC_SEPARATED (as
// is conventional) for cmyk_t images.
this->_info._photometric_interpretation = detail::photometric_interpretation< color_space_t >::value;
}
// write dimensions
tiff_image_width::type width = (tiff_image_width::type) view.width();
tiff_image_height::type height = (tiff_image_height::type) view.height();
this->_io_dev.template set_property< tiff_image_width >( width );
this->_io_dev.template set_property< tiff_image_height >( height );
// write planar configuration
this->_io_dev.template set_property<tiff_planar_configuration>( this->_info._planar_configuration );
// write samples per pixel
tiff_samples_per_pixel::type samples_per_pixel = num_channels< pixel_t >::value;
this->_io_dev.template set_property<tiff_samples_per_pixel>( samples_per_pixel );
if (mpl:: contains <color_space_t, alpha_t>:: value) {
std:: vector <uint16_t> extra_samples {EXTRASAMPLE_ASSOCALPHA};
this->_io_dev.template set_property<tiff_extra_samples>( extra_samples );
}
// write bits per sample
// @todo: Settings this value usually requires to write for each sample the bit
// value seperately in case they are different, like rgb556.
tiff_bits_per_sample::type bits_per_sample = detail::unsigned_integral_num_bits< channel_t >::value;
this->_io_dev.template set_property<tiff_bits_per_sample>( bits_per_sample );
// write sample format
tiff_sample_format::type sampl_format = detail::sample_format< channel_t >::value;
this->_io_dev.template set_property<tiff_sample_format>( sampl_format );
// write photometric format
this->_io_dev.template set_property<tiff_photometric_interpretation>( this->_info._photometric_interpretation );
// write compression
this->_io_dev.template set_property<tiff_compression>( this->_info._compression );
// write orientation
this->_io_dev.template set_property<tiff_orientation>( this->_info._orientation );
// write rows per strip
this->_io_dev.template set_property<tiff_rows_per_strip>( this->_io_dev.get_default_strip_size() );
// write x, y resolution and units
this->_io_dev.template set_property<tiff_resolution_unit>( this->_info._resolution_unit );
this->_io_dev.template set_property<tiff_x_resolution>( this->_info._x_resolution );
this->_io_dev.template set_property<tiff_y_resolution>( this->_info._y_resolution );
/// Optional and / or non-baseline tags below here
// write ICC colour profile, if it's there
// http://www.color.org/icc_specs2.xalter
if ( 0 != this->_info._icc_profile.size())
this->_io_dev.template set_property<tiff_icc_profile>( this->_info._icc_profile );
}
public:
Device _io_dev;
image_write_info< tiff_tag > _info;
};
#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
#pragma warning(pop)
#endif
} // namespace gil
} // namespace boost
#endif

View File

@@ -0,0 +1,160 @@
//
// Copyright 2007-2008 Christian Henning
//
// 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_OLD_HPP
#define BOOST_GIL_EXTENSION_IO_TIFF_OLD_HPP
#include <boost/gil/extension/io/tiff.hpp>
namespace boost { namespace gil {
/// \ingroup TIFF_IO
/// \brief Returns the width and height of the TIFF file at the specified location.
/// Throws std::ios_base::failure if the location does not correspond to a valid TIFF file
template<typename String>
inline point_t tiff_read_dimensions(String const& filename)
{
using backend_t = typename get_reader_backend<String, tiff_tag>::type;
backend_t backend = read_image_info(filename, tiff_tag());
return { backend._info._width, backend._info._height };
}
/// \ingroup TIFF_IO
/// \brief Loads the image specified by the given tiff image file name into the given view.
/// Triggers a compile assert if the view color space and channel depth are not supported by the TIFF library or by the I/O extension.
/// Throws std::ios_base::failure if the file is not a valid TIFF file, or if its color space or channel depth are not
/// compatible with the ones specified by View, or if its dimensions don't match the ones of the view.
template< typename String
, typename View
>
inline
void tiff_read_view( const String& filename
, const View& view
)
{
read_view( filename
, view
, tiff_tag()
);
}
/// \ingroup TIFF_IO
/// \brief Allocates a new image whose dimensions are determined by the given tiff image file, and loads the pixels into it.
/// Triggers a compile assert if the image color space or channel depth are not supported by the TIFF library or by the I/O extension.
/// Throws std::ios_base::failure if the file is not a valid TIFF file, or if its color space or channel depth are not
/// compatible with the ones specified by Image
template< typename String
, typename Image
>
inline
void tiff_read_image( const String& filename
, Image& img
)
{
read_image( filename
, img
, tiff_tag()
);
}
/// \ingroup TIFF_IO
/// \brief Loads and color-converts the image specified by the given tiff image file name into the given view.
/// Throws std::ios_base::failure if the file is not a valid TIFF file, or if its dimensions don't match the ones of the view.
template< typename String
, typename View
, typename CC
>
inline
void tiff_read_and_convert_view( const String& filename
, const View& view
, CC cc
)
{
read_and_convert_view( filename
, view
, cc
, tiff_tag()
);
}
/// \ingroup TIFF_IO
/// \brief Loads and color-converts the image specified by the given tiff image file name into the given view.
/// Throws std::ios_base::failure if the file is not a valid TIFF file, or if its dimensions don't match the ones of the view.
template< typename String
, typename View
>
inline
void tiff_read_and_convert_view( const String& filename
, const View& view
)
{
read_and_convert_view( filename
, view
, tiff_tag()
);
}
/// \ingroup TIFF_IO
/// \brief Allocates a new image whose dimensions are determined by the given tiff image file, loads and color-converts the pixels into it.
/// Throws std::ios_base::failure if the file is not a valid TIFF file
template< typename String
, typename Image
, typename CC
>
inline
void tiff_read_and_convert_image( const String& filename
, Image& img
, CC cc
)
{
read_and_convert_image( filename
, img
, cc
, tiff_tag()
);
}
/// \ingroup TIFF_IO
/// \brief Allocates a new image whose dimensions are determined by the given tiff image file, loads and color-converts the pixels into it.
/// Throws std::ios_base::failure if the file is not a valid TIFF file
template< typename String
, typename Image
>
inline
void tiff_read_and_convert_image( const String filename
, Image& img
)
{
read_and_convert_image( filename
, img
, tiff_tag()
);
}
/// \ingroup TIFF_IO
/// \brief Saves the view to a tiff file specified by the given tiff image file name.
/// Triggers a compile assert if the view color space and channel depth are not supported by the TIFF library or by the I/O extension.
/// Throws std::ios_base::failure if it fails to create the file.
template< typename String
, typename View
>
inline
void tiff_write_view( const String& filename
, const View& view
)
{
write_view( filename
, view
, tiff_tag()
);
}
} // namespace gil
} // namespace boost
#endif

View File

@@ -0,0 +1,30 @@
//
// Copyright 2007-2008 Christian Henning
//
// 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_READ_HPP
#define BOOST_GIL_EXTENSION_IO_TIFF_READ_HPP
#define BOOST_GIL_EXTENSION_IO_TIFF_READ_ENABLED // TODO: Document, explain, review
#include <boost/gil/extension/io/tiff/tags.hpp>
#include <boost/gil/extension/io/tiff/detail/read.hpp>
#include <boost/gil/extension/io/tiff/detail/scanline_read.hpp>
#include <boost/gil/extension/io/tiff/detail/supported_types.hpp>
#include <boost/gil/io/get_reader.hpp>
#include <boost/gil/io/make_backend.hpp>
#include <boost/gil/io/make_dynamic_image_reader.hpp>
#include <boost/gil/io/make_reader.hpp>
#include <boost/gil/io/make_scanline_reader.hpp>
#include <boost/gil/io/read_and_convert_image.hpp>
#include <boost/gil/io/read_and_convert_view.hpp>
#include <boost/gil/io/read_image.hpp>
#include <boost/gil/io/read_image_info.hpp>
#include <boost/gil/io/read_view.hpp>
#include <boost/gil/io/scanline_read_iterator.hpp>
#endif

View File

@@ -0,0 +1,351 @@
//
// Copyright 2007-2008 Christian Henning, Andreas Pokorny, 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_TAGS_HPP
#define BOOST_GIL_EXTENSION_IO_TIFF_TAGS_HPP
#include <boost/gil/extension/io/tiff/detail/log.hpp>
#include <boost/gil/io/base.hpp>
#include <boost/mpl/vector.hpp>
// 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>
#ifndef BOOST_GIL_EXTENSION_IO_TIFF_C_LIB_COMPILED_AS_CPLUSPLUS
}
#endif
namespace boost { namespace gil {
/// Defines tiff tag.
struct tiff_tag : format_tag {};
/// http://www.awaresystems.be/imaging/tiff/tifftags/baseline.html
/// http://www.remotesensing.org/libtiff/
/// TIFF property base class
template< typename T, int Value >
struct tiff_property_base : property_base< T >
{
/// Tag, needed when reading or writing image properties.
static const ttag_t tag = Value;
/// The list of argument types used in the interface of LibTIFF
/// for
/// this property:
/// http://www.remotesensing.org/libtiff/man/TIFFGetField.3tiff.html
/// http://www.remotesensing.org/libtiff/man/TIFFSetField.3tiff.html
using arg_types = mpl::vector<typename property_base<unsigned short>::type>;
};
/// baseline tags
/// Defines type for new subfile property.
struct tiff_new_subfile_type : tiff_property_base< uint32_t, TIFFTAG_SUBFILETYPE > {};
/// Defines type for subfile property.
struct tiff_subfile_type : tiff_property_base< uint16_t, TIFFTAG_OSUBFILETYPE > {};
/// Defines type for image width property.
struct tiff_image_width : tiff_property_base< uint32_t, TIFFTAG_IMAGEWIDTH > {};
/// Defines type for image height property.
struct tiff_image_height : tiff_property_base< uint32_t, TIFFTAG_IMAGELENGTH > {};
/// Defines type for bits per sample property.
struct tiff_bits_per_sample : tiff_property_base< uint16_t, TIFFTAG_BITSPERSAMPLE > {};
/// Defines type for compression property.
struct tiff_compression : tiff_property_base< uint16_t, TIFFTAG_COMPRESSION > {};
/// Defines type for photometric interpretation property.
struct tiff_photometric_interpretation : tiff_property_base< uint16_t, TIFFTAG_PHOTOMETRIC > {};
/// Defines type for threshold property.
struct tiff_thresholding : tiff_property_base< uint16_t, TIFFTAG_THRESHHOLDING > {};
/// Defines type for cell width property.
struct tiff_cell_width : tiff_property_base< uint16_t, TIFFTAG_CELLWIDTH > {};
/// Defines type for cell length property.
struct tiff_cell_length : tiff_property_base< uint16_t, TIFFTAG_CELLLENGTH > {};
/// Defines type for fill order property.
struct tiff_fill_order : tiff_property_base< std::string, TIFFTAG_FILLORDER > {};
/// Defines type for image description.
struct tiff_image_description : tiff_property_base< std::string, TIFFTAG_IMAGEDESCRIPTION > {};
/// Defines type for make property.
struct tiff_make : tiff_property_base< std::string, TIFFTAG_MAKE > {};
/// Defines type for model property.
struct tiff_model : tiff_property_base< std::string, TIFFTAG_MODEL > {};
/// Defines type for image orientation.
struct tiff_orientation : tiff_property_base< uint16_t, TIFFTAG_ORIENTATION > {};
/// Defines type for samples per pixel property.
struct tiff_samples_per_pixel : tiff_property_base< uint16_t, TIFFTAG_SAMPLESPERPIXEL > {};
/// Defines type for rows per strip property.
struct tiff_rows_per_strip : tiff_property_base< uint32_t, TIFFTAG_ROWSPERSTRIP > {};
/// Defines type for min sample property.
struct tiff_min_sample_value : tiff_property_base< uint16_t, TIFFTAG_MINSAMPLEVALUE > {};
/// Defines type for max sample property.
struct tiff_max_sample_value : tiff_property_base< uint16_t, TIFFTAG_MAXSAMPLEVALUE > {};
/// Defines type for x resolution property.
struct tiff_x_resolution : tiff_property_base< float, TIFFTAG_XRESOLUTION > {};
/// Defines type for y resolution property.
struct tiff_y_resolution : tiff_property_base< float, TIFFTAG_YRESOLUTION > {};
/// Defines type for resolution unit property.
enum class tiff_resolution_unit_value: std:: uint16_t {
NONE = RESUNIT_NONE,
INCH = RESUNIT_INCH,
CENTIMETER = RESUNIT_CENTIMETER
};
struct tiff_resolution_unit : tiff_property_base< tiff_resolution_unit_value, TIFFTAG_RESOLUTIONUNIT > {};
/// Defines type for planar configuration property.
struct tiff_planar_configuration : tiff_property_base< uint16_t, TIFFTAG_PLANARCONFIG > {};
/// Defines type for gray response unit property.
struct tiff_gray_response_unit : tiff_property_base< uint16_t, TIFFTAG_GRAYRESPONSEUNIT > {};
/// Defines type for gray response curve property.
struct tiff_gray_response_curve : tiff_property_base< uint16_t*, TIFFTAG_GRAYRESPONSECURVE > {};
/// Defines type for software vendor property.
struct tiff_software : tiff_property_base< std::string, TIFFTAG_SOFTWARE > {};
/// Defines type for date time property.
struct tiff_date_time : tiff_property_base< std::string, TIFFTAG_DATETIME > {};
/// Defines type for artist information property.
struct tiff_artist : tiff_property_base< std::string, TIFFTAG_ARTIST > {};
/// Defines type for host computer property.
struct tiff_host_computer : tiff_property_base< std::string, TIFFTAG_HOSTCOMPUTER > {};
/// Helper structure for reading a color mapper.
struct tiff_color_map
{
using red_t = uint16_t *;
using green_t = uint16_t *;
using blue_t = uint16_t *;
static const unsigned int tag = TIFFTAG_COLORMAP;
};
/// Defines type for extra samples property.
struct tiff_extra_samples : tiff_property_base<std:: vector <uint16_t>, TIFFTAG_EXTRASAMPLES>
{
using arg_types = mpl::vector<uint16_t, uint16_t const *>;
};
/// Defines type for copyright property.
struct tiff_copyright : tiff_property_base< std::string, TIFFTAG_COPYRIGHT > {};
/// non-baseline tags
/// Defines type for sample format property.
struct tiff_sample_format : tiff_property_base< uint16_t, TIFFTAG_SAMPLEFORMAT > {};
/// Defines type for indexed property.
/// Not supported yet
//struct tiff_indexed : tiff_property_base< bool, TIFFTAG_INDEXED > {};
/// Tile related tags
/// Defines type for a (not) tiled tiff image
struct tiff_is_tiled : tiff_property_base< bool, false > {};
/// Defines type for tile width
struct tiff_tile_width : tiff_property_base< long, TIFFTAG_TILEWIDTH > {};
/// Defines type for tile length
struct tiff_tile_length : tiff_property_base< long, TIFFTAG_TILELENGTH > {};
/// Defines the page to read in a multipage tiff file.
#include <boost/mpl/integral_c.hpp>
struct tiff_directory : property_base< tdir_t >
{
using default_value = boost::mpl::integral_c<type, 0>;
};
/// Non-baseline tags
/// Defines type for icc profile property.
struct tiff_icc_profile : tiff_property_base<std::vector<uint8_t>, TIFFTAG_ICCPROFILE>
{
using arg_types = mpl::vector<uint32_t, void const *>;
};
/// Read information for tiff images.
///
/// The structure is returned when using read_image_info.
template<>
struct image_read_info< tiff_tag >
{
image_read_info()
: _width( 0 )
, _height( 0 )
, _compression( COMPRESSION_NONE )
, _bits_per_sample( 0 )
, _samples_per_pixel( 0 )
, _sample_format( SAMPLEFORMAT_UINT )
, _planar_configuration( PLANARCONFIG_CONTIG )
, _photometric_interpretation( PHOTOMETRIC_MINISWHITE )
, _is_tiled( false )
, _tile_width ( 0 )
, _tile_length( 0 )
, _x_resolution( 1 )
, _y_resolution( 1 )
, _resolution_unit( tiff_resolution_unit_value:: NONE )
, _icc_profile( )
{}
/// The number of rows of pixels in the image.
tiff_image_width::type _width;
/// The number of columns in the image, i.e., the number of pixels per row.
tiff_image_height::type _height;
/// Compression scheme used on the image data.
tiff_compression::type _compression;
/// Number of bits per component.
tiff_bits_per_sample::type _bits_per_sample;
/// The number of components per pixel.
tiff_samples_per_pixel::type _samples_per_pixel;
/// Specifies how to interpret each data sample in a pixel.
tiff_sample_format::type _sample_format;
/// How the components of each pixel are stored.
tiff_planar_configuration::type _planar_configuration;
/// The color space of the image data.
tiff_photometric_interpretation::type _photometric_interpretation;
/// Is tiled?
tiff_is_tiled::type _is_tiled;
/// Tile width
tiff_tile_width::type _tile_width;
/// Tile length
tiff_tile_length::type _tile_length;
tiff_x_resolution::type _x_resolution;
tiff_y_resolution::type _y_resolution;
tiff_resolution_unit::type _resolution_unit;
tiff_icc_profile:: type _icc_profile;
};
/// Read settings for tiff images.
///
/// The structure can be used for all read_xxx functions, except read_image_info.
template<>
struct image_read_settings< tiff_tag > : public image_read_settings_base
{
/// Default constructor
image_read_settings< tiff_tag >()
: image_read_settings_base()
, _directory( tiff_directory::default_value::value )
{}
/// Constructor
/// \param top_left Top left coordinate for reading partial image.
/// \param dim Dimensions for reading partial image.
/// \param directory Defines the page to read in a multipage tiff file.
image_read_settings( const point_t& top_left
, const point_t& dim
, const tiff_directory::type& directory = tiff_directory::default_value::value
)
: image_read_settings_base( top_left
, dim
)
, _directory( directory )
{}
/// Defines the page to read in a multipage tiff file.
tiff_directory::type _directory;
};
/// Write settings for tiff images.
///
/// The structure can be used for all write_xxx functions, except write_image_info.
template< typename Log >
struct image_write_info< tiff_tag, Log >
{
/// Default constructor
image_write_info()
: _photometric_interpretation ( PHOTOMETRIC_MINISBLACK )
, _photometric_interpretation_user_defined( false )
, _compression ( COMPRESSION_NONE )
, _orientation ( ORIENTATION_TOPLEFT )
, _planar_configuration ( PLANARCONFIG_CONTIG )
, _is_tiled ( false )
, _tile_width ( 0 )
, _tile_length ( 0 )
, _x_resolution ( 1 )
, _y_resolution ( 1 )
, _resolution_unit ( tiff_resolution_unit_value::NONE )
, _icc_profile ( )
{}
/// The color space of the image data.
tiff_photometric_interpretation::type _photometric_interpretation;
bool _photometric_interpretation_user_defined;
/// Compression scheme used on the image data.
tiff_compression::type _compression;
/// The orientation of the image with respect to the rows and columns.
tiff_orientation::type _orientation;
/// How the components of each pixel are stored.
tiff_planar_configuration::type _planar_configuration;
/// Is the image tiled?
tiff_is_tiled::type _is_tiled;
/// Tiles width
tiff_tile_width::type _tile_width;
/// Tiles length
tiff_tile_length::type _tile_length;
/// x, y resolution
tiff_x_resolution::type _x_resolution;
tiff_y_resolution::type _y_resolution;
tiff_resolution_unit::type _resolution_unit;
tiff_icc_profile:: type _icc_profile;
/// A log to transcript error and warning messages issued by libtiff.
Log _log;
};
} // namespace gil
} // namespace boost
#endif

View File

@@ -0,0 +1,19 @@
//
// Copyright 2007-2008 Christian Henning
//
// 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_WRITE_HPP
#define BOOST_GIL_EXTENSION_IO_TIFF_WRITE_HPP
#include <boost/gil/extension/io/tiff/tags.hpp>
#include <boost/gil/extension/io/tiff/detail/supported_types.hpp>
#include <boost/gil/extension/io/tiff/detail/write.hpp>
#include <boost/gil/io/make_dynamic_image_writer.hpp>
#include <boost/gil/io/make_writer.hpp>
#include <boost/gil/io/write_view.hpp>
#endif