Files
lms/boost/gil/extension/io_new/formats/tiff/write.hpp
T

423 lines
15 KiB
C++

/*
Copyright 2007-2008 Christian Henning, Lubomir Bourdev
Use, modification and distribution are subject to 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_IO_WRITE_HPP
#define BOOST_GIL_EXTENSION_IO_TIFF_IO_WRITE_HPP
////////////////////////////////////////////////////////////////////////////////////////
/// \file
/// \brief
/// \author Christian Henning, Lubomir Bourdev \n
///
/// \date 2007-2008 \n
///
////////////////////////////////////////////////////////////////////////////////////////
extern "C" {
#include "tiff.h"
#include "tiffio.h"
}
#include <algorithm>
#include <string>
#include <vector>
#include <boost/static_assert.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/gil/extension/io_new/tiff_tags.hpp>
#include <boost/gil/extension/io_new/detail/base.hpp>
#include <boost/gil/extension/io_new/detail/io_device.hpp>
#include "device.hpp"
namespace boost { namespace gil { namespace detail {
template <typename PixelReference>
struct my_interleaved_pixel_iterator_type_from_pixel_reference
{
private:
typedef typename remove_reference< PixelReference >::type::value_type pixel_t;
public:
typedef typename iterator_type_from_pixel< pixel_t
, false
, false
, true
>::type 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
> {};
template < typename Channel > struct sample_format : public mpl::int_<SAMPLEFORMAT_UINT> {};
template<> struct sample_format<bits8> : public mpl::int_<SAMPLEFORMAT_UINT> {};
template<> struct sample_format<bits16> : public mpl::int_<SAMPLEFORMAT_UINT> {};
template<> struct sample_format<bits32> : public mpl::int_<SAMPLEFORMAT_UINT> {};
template<> struct sample_format<bits32f> : public mpl::int_<SAMPLEFORMAT_IEEEFP> {};
template<> struct sample_format<double> : public mpl::int_<SAMPLEFORMAT_IEEEFP> {};
template<> struct sample_format<bits8s> : public mpl::int_<SAMPLEFORMAT_INT> {};
template<> struct sample_format<bits16s> : public mpl::int_<SAMPLEFORMAT_INT> {};
template<> struct sample_format<bits32s> : 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 > {};
template < typename Device, typename Log >
class writer< Device
, tiff_tag
, Log
>
{
public:
typedef image_write_info<tiff_tag, Log> info_t;
writer( Device& dev )
: _io_dev( dev ) {}
template<typename View>
void apply( const View& view )
{
typedef typename color_space_type<View>::type color_space_t;
info_t info;
// 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. This writer
// will assume PHOTOMETRIC_MINISBLACK for gray_t images and PHOTOMETRIC_RGB
// for rgb_t images.
info._photometric_interpretation = photometric_interpretation< color_space_t >::value;
write_view( view
, info );
}
template<typename View>
void apply( const View& view
, const info_t& info )
{
write_view( view
, info );
}
private:
template< typename View >
void write_view( const View& src_view
, const info_t& info
)
{
typedef typename View::value_type pixel_t;
// get the type of the first channel (heterogeneous pixels might be broken for now!)
typedef typename channel_traits< typename element_type< pixel_t >::type >::value_type channel_t;
// write dimensions
tiff_image_width::type width = (tiff_image_width::type) src_view.width();
tiff_image_height::type height = (tiff_image_height::type) src_view.height();
_io_dev.template set_property< tiff_image_width >( width );
_io_dev.template set_property< tiff_image_height >( height );
// write planar configuration
if( is_bit_aligned< View >::value == false )
{
_io_dev.template set_property<tiff_planar_configuration>( info._planar_configuration );
}
// write samples per pixel
tiff_samples_per_pixel::type samples_per_pixel = num_channels< pixel_t >::value;
_io_dev.template set_property<tiff_samples_per_pixel>( samples_per_pixel );
// 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 = unsigned_integral_num_bits<channel_t>::value;
_io_dev.template set_property<tiff_bits_per_sample>( bits_per_sample );
// write sample format
tiff_sample_format::type sampl_format = sample_format< channel_t >::type::value;
_io_dev.template set_property<tiff_sample_format>( sampl_format );
// write photometric format
_io_dev.template set_property<tiff_photometric_interpretation>( info._photometric_interpretation );
// write compression
_io_dev.template set_property<tiff_compression>( info._compression );
// write orientation
_io_dev.template set_property<tiff_orientation>( info._orientation );
// write rows per strip
_io_dev.template set_property<tiff_rows_per_strip>( _io_dev.get_default_strip_size() );
if(!info._is_tiled)
{
write_data( src_view
, info
, (src_view.width() * samples_per_pixel * bits_per_sample + 7) / 8
, typename is_bit_aligned< pixel_t >::type()
);
}
else
{
tiff_tile_width::type tw = info._tile_width;
tiff_tile_length::type th = info._tile_length;
if(!_io_dev.check_tile_size( tw, th ))
{
io_error( "Tile sizes need to be multiples of 16." );
}
// tile related tags
_io_dev.template set_property<tiff_tile_width> ( tw );
_io_dev.template set_property<tiff_tile_length>( th );
write_tiled_data( src_view
, tw
, th
, typename is_bit_aligned< pixel_t >::type()
);
}
}
template< typename View >
void write_data( const View& src_view
, const info_t& /* info */
, std::size_t row_size_in_bytes
, const mpl::true_& // bit_aligned
)
{
byte_vector_t row( row_size_in_bytes );
typedef typename View::x_iterator x_it_t;
x_it_t row_it = x_it_t( &(*row.begin()));
for( typename View::y_coord_t y = 0; y < src_view.height(); ++y )
{
std::copy( src_view.row_begin( y )
, src_view.row_end( y )
, row_it
);
_io_dev.write_scaline( row
, (uint32) y
, 0
);
// @todo: do optional bit swapping here if you need to...
}
}
template< typename View >
void write_tiled_data( const View& src_view
, tiff_tile_width::type tw
, tiff_tile_length::type th
, const mpl::true_& // bit_aligned
)
{
byte_vector_t row( _io_dev.get_tile_size() );
typedef typename View::x_iterator x_it_t;
x_it_t row_it = x_it_t( &(*row.begin()));
internal_write_tiled_data(src_view, tw, th, row, row_it);
}
template< typename View >
void write_data( const View& src_view
, const info_t& info
, std::size_t row_size_in_bytes
, const mpl::false_& // bit_aligned
)
{
byte_vector_t row( row_size_in_bytes );
typedef typename my_interleaved_pixel_iterator_type_from_pixel_reference< typename View::reference
>::type x_iterator;
x_iterator row_it = x_iterator( &(*row.begin()));
for( typename View::y_coord_t y = 0; y < src_view.height(); ++y )
{
std::copy( src_view.row_begin( y )
, src_view.row_end( y )
, row_it
);
_io_dev.write_scaline( row
, (uint32) y
, 0
);
// @todo: do optional bit swapping here if you need to...
}
}
template< typename View >
void write_tiled_data( const View& src_view
, tiff_tile_width::type tw
, tiff_tile_length::type th
, const mpl::false_& // bit_aligned
)
{
byte_vector_t row( _io_dev.get_tile_size() );
typedef typename my_interleaved_pixel_iterator_type_from_pixel_reference< typename View::reference
>::type x_iterator;
x_iterator row_it = x_iterator( &(*row.begin()));
internal_write_tiled_data(src_view, tw, th, row, row_it);
}
template< typename View,
typename IteratorType >
void internal_write_tiled_data( const View& src_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 < src_view.height() )
{
while( j < src_view.width() )
{
if( j + tw < src_view.width() && i + th < src_view.height() )
{
// a tile is fully included in the image: just copy values
tile_subimage_view = subimage_view( src_view
, static_cast< int >( j )
, static_cast< int >( i )
, static_cast< int >( tw )
, static_cast< int >( th )
);
std::copy( tile_subimage_view.begin()
, tile_subimage_view.end()
, it
);
}
else
{
std::ptrdiff_t width = src_view.width();
std::ptrdiff_t height = src_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( src_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()));
}
_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...
}
Device& _io_dev;
};
struct tiff_write_is_supported
{
template< typename View >
struct apply
: public is_write_supported< typename get_pixel_type< View >::type
, tiff_tag
>
{};
};
template< typename Device >
class dynamic_image_writer< Device
, tiff_tag
>
: public writer< Device
, tiff_tag
>
{
typedef writer< Device
, tiff_tag
> parent_t;
public:
dynamic_image_writer( Device& file )
: parent_t( file )
{}
template< typename Views >
void apply( const any_image_view< Views >& views )
{
dynamic_io_fnobj< tiff_write_is_supported
, parent_t
> op( this );
apply_operation( views, op );
}
};
} // namespace detail
} // namespace gil
} // namespace boost
#endif // BOOST_GIL_EXTENSION_IO_TIFF_IO_WRITE_HPP