summaryrefslogtreecommitdiff
path: root/boost/gil/extension/io/tiff/detail/write.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'boost/gil/extension/io/tiff/detail/write.hpp')
-rw-r--r--boost/gil/extension/io/tiff/detail/write.hpp463
1 files changed, 463 insertions, 0 deletions
diff --git a/boost/gil/extension/io/tiff/detail/write.hpp b/boost/gil/extension/io/tiff/detail/write.hpp
new file mode 100644
index 0000000000..06b72858d8
--- /dev/null
+++ b/boost/gil/extension/io/tiff/detail/write.hpp
@@ -0,0 +1,463 @@
+/*
+ Copyright 2007-2012 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_DETAIL_WRITE_HPP
+#define BOOST_GIL_EXTENSION_IO_TIFF_DETAIL_WRITE_HPP
+
+////////////////////////////////////////////////////////////////////////////////////////
+/// \file
+/// \brief
+/// \author Christian Henning, Lubomir Bourdev \n
+///
+/// \date 2007-2012 \n
+///
+////////////////////////////////////////////////////////////////////////////////////////
+
+extern "C" {
+#include "tiff.h"
+#include "tiffio.h"
+}
+
+#include <algorithm>
+#include <string>
+#include <vector>
+#include <boost/static_assert.hpp>
+
+#include <boost/gil/premultiply.hpp>
+
+#include <boost/gil/extension/io/tiff/tags.hpp>
+
+#include <boost/gil/io/base.hpp>
+#include <boost/gil/io/device.hpp>
+
+#include <boost/gil/extension/io/tiff/detail/writer_backend.hpp>
+#include <boost/gil/extension/io/tiff/detail/device.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
+
+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
+ > {};
+
+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:
+ typedef writer_backend< Device, tiff_tag > backend_t;
+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 )
+ {
+ 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;
+ 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 );
+
+ typedef typename View::x_iterator x_it_t;
+ 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 );
+
+ 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 < 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
+ )
+ {
+ typedef typename color_space_type<typename View::value_type>::type colour_space_t;
+ typedef mpl::bool_<mpl::contains<colour_space_t, alpha_t>::value> has_alpha_t;
+
+ 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() );
+
+ typedef typename View::x_iterator x_it_t;
+ 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() );
+
+ typedef typename detail::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(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 )
+ );
+
+ typedef typename color_space_type<typename View::value_type>::type colour_space_t;
+ typedef mpl::bool_<mpl::contains<colour_space_t, alpha_t>::value> has_alpha_t;
+
+ 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
+ >
+{
+ typedef writer< Device
+ , tiff_tag
+ > parent_t;
+
+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