diff options
Diffstat (limited to 'boost/gil/extension')
135 files changed, 20584 insertions, 2017 deletions
diff --git a/boost/gil/extension/dynamic_image/algorithm.hpp b/boost/gil/extension/dynamic_image/algorithm.hpp index dffd399918..abd5776b0e 100644 --- a/boost/gil/extension/dynamic_image/algorithm.hpp +++ b/boost/gil/extension/dynamic_image/algorithm.hpp @@ -30,7 +30,7 @@ namespace boost { namespace gil { namespace detail { struct equal_pixels_fn : public binary_operation_obj<equal_pixels_fn,bool> { template <typename V1, typename V2> - GIL_FORCEINLINE bool apply_compatible(const V1& v1, const V2& v2) const { + BOOST_FORCEINLINE bool apply_compatible(const V1& v1, const V2& v2) const { return equal_pixels(v1,v2); } }; @@ -60,7 +60,7 @@ bool equal_pixels(const any_image_view<Types1>& src, const any_image_view<Types2 namespace detail { struct copy_pixels_fn : public binary_operation_obj<copy_pixels_fn> { template <typename View1, typename View2> - GIL_FORCEINLINE void apply_compatible(const View1& src, const View2& dst) const { + BOOST_FORCEINLINE void apply_compatible(const View1& src, const View2& dst) const { copy_pixels(src,dst); } }; @@ -144,7 +144,7 @@ template <bool COMPATIBLE> struct fill_pixels_fn1 { // copy_pixels invoked on incompatible images template <> struct fill_pixels_fn1<false> { - template <typename V, typename Value> static void apply(const V& src, const Value& val) { throw std::bad_cast();} + template <typename V, typename Value> static void apply(const V&, const Value&) { throw std::bad_cast();} }; template <typename Value> diff --git a/boost/gil/extension/dynamic_image/any_image.hpp b/boost/gil/extension/dynamic_image/any_image.hpp index dde831994a..3c4445ff10 100644 --- a/boost/gil/extension/dynamic_image/any_image.hpp +++ b/boost/gil/extension/dynamic_image/any_image.hpp @@ -29,6 +29,11 @@ //#pragma warning(disable : 4244) // conversion from 'std::ptrdiff_t' to 'int', possible loss of data. even if we static-assert the two types are the same (on visual studio 8) //#endif +#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) +#pragma warning(push) +#pragma warning(disable:4512) //assignment operator could not be generated +#endif + namespace boost { namespace gil { namespace detail { @@ -84,9 +89,11 @@ public: template <typename T> explicit any_image(const T& obj) : parent_t(obj) {} template <typename T> explicit any_image(T& obj, bool do_swap) : parent_t(obj,do_swap) {} any_image(const any_image& v) : parent_t((const parent_t&)v) {} + template <typename Types> any_image(const any_image<Types>& v) : parent_t((const variant<Types>&)v) {} - template <typename T> any_image& operator=(const T& obj) { parent_t::operator=(obj); return *this; } - any_image& operator=(const any_image& v) { parent_t::operator=((const parent_t&)v); return *this;} + template <typename T> any_image& operator=(const T& obj) { parent_t::operator=(obj); return *this; } + any_image& operator=(const any_image& v) { parent_t::operator=((const parent_t&)v); return *this;} + template <typename Types> any_image& operator=(const any_image<Types>& v) { parent_t::operator=((const variant<Types>&)v); return *this;} void recreate(const point_t& dims, unsigned alignment=1) { apply_operation(*this,detail::recreate_image_fnobj(dims,alignment)); } void recreate(x_coord_t width, y_coord_t height, unsigned alignment=1) { recreate(point2<std::ptrdiff_t>(width,height),alignment); } @@ -104,13 +111,13 @@ public: /// \ingroup ImageModel /// \brief Returns the non-constant-pixel view of any image. The returned view is any view. -template <typename Types> GIL_FORCEINLINE // Models ImageVectorConcept +template <typename Types> BOOST_FORCEINLINE // Models ImageVectorConcept typename any_image<Types>::view_t view(any_image<Types>& anyImage) { return apply_operation(anyImage, detail::any_image_get_view<typename any_image<Types>::view_t>()); } /// \brief Returns the constant-pixel view of any image. The returned view is any view. -template <typename Types> GIL_FORCEINLINE // Models ImageVectorConcept +template <typename Types> BOOST_FORCEINLINE // Models ImageVectorConcept typename any_image<Types>::const_view_t const_view(const any_image<Types>& anyImage) { return apply_operation(anyImage, detail::any_image_get_const_view<typename any_image<Types>::const_view_t>()); } @@ -118,6 +125,10 @@ typename any_image<Types>::const_view_t const_view(const any_image<Types>& anyIm } } // namespace boost::gil +#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) +#pragma warning(pop) +#endif + //#ifdef _MSC_VER //#pragma warning(pop) //#endif diff --git a/boost/gil/extension/dynamic_image/any_image_view.hpp b/boost/gil/extension/dynamic_image/any_image_view.hpp index 1b1d5503fc..a99e8baaea 100644 --- a/boost/gil/extension/dynamic_image/any_image_view.hpp +++ b/boost/gil/extension/dynamic_image/any_image_view.hpp @@ -38,7 +38,7 @@ template <typename View> struct dynamic_xy_step_transposed_type; namespace detail { struct any_type_get_num_channels { // works for both image_view and image typedef int result_type; - template <typename T> result_type operator()(const T& v) const { return num_channels<T>::value; } + template <typename T> result_type operator()(const T&) const { return num_channels<T>::value; } }; struct any_type_get_dimensions { // works for both image_view and image typedef point2<std::ptrdiff_t> result_type; @@ -72,9 +72,11 @@ public: any_image_view() : parent_t() {} template <typename T> explicit any_image_view(const T& obj) : parent_t(obj) {} any_image_view(const any_image_view& v) : parent_t((const parent_t&)v) {} + template <typename Types> any_image_view(const any_image_view<Types>& v) : parent_t((const variant<Types>&)v) {} - template <typename T> any_image_view& operator=(const T& obj) { parent_t::operator=(obj); return *this; } - any_image_view& operator=(const any_image_view& v) { parent_t::operator=((const parent_t&)v); return *this;} + template <typename T> any_image_view& operator=(const T& obj) { parent_t::operator=(obj); return *this; } + any_image_view& operator=(const any_image_view& v) { parent_t::operator=((const parent_t&)v); return *this;} + template <typename Types> any_image_view& operator=(const any_image_view<Types>& v) { parent_t::operator=((const variant<Types>&)v); return *this;} std::size_t num_channels() const { return apply_operation(*this, detail::any_type_get_num_channels()); } point_t dimensions() const { return apply_operation(*this, detail::any_type_get_dimensions()); } diff --git a/boost/gil/extension/dynamic_image/apply_operation.hpp b/boost/gil/extension/dynamic_image/apply_operation.hpp index ed2571391e..beb79bad77 100644 --- a/boost/gil/extension/dynamic_image/apply_operation.hpp +++ b/boost/gil/extension/dynamic_image/apply_operation.hpp @@ -31,21 +31,21 @@ namespace boost { namespace gil { /// \ingroup Variant /// \brief Invokes a generic mutable operation (represented as a unary function object) on a variant -template <typename Types, typename UnaryOp> GIL_FORCEINLINE +template <typename Types, typename UnaryOp> BOOST_FORCEINLINE typename UnaryOp::result_type apply_operation(variant<Types>& arg, UnaryOp op) { return apply_operation_base<Types>(arg._bits, arg._index ,op); } /// \ingroup Variant /// \brief Invokes a generic constant operation (represented as a unary function object) on a variant -template <typename Types, typename UnaryOp> GIL_FORCEINLINE +template <typename Types, typename UnaryOp> BOOST_FORCEINLINE typename UnaryOp::result_type apply_operation(const variant<Types>& arg, UnaryOp op) { return apply_operation_basec<Types>(arg._bits, arg._index ,op); } /// \ingroup Variant /// \brief Invokes a generic constant operation (represented as a binary function object) on two variants -template <typename Types1, typename Types2, typename BinaryOp> GIL_FORCEINLINE +template <typename Types1, typename Types2, typename BinaryOp> BOOST_FORCEINLINE typename BinaryOp::result_type apply_operation(const variant<Types1>& arg1, const variant<Types2>& arg2, BinaryOp op) { return apply_operation_base<Types1,Types2>(arg1._bits, arg1._index, arg2._bits, arg2._index, op); } diff --git a/boost/gil/extension/dynamic_image/apply_operation_base.hpp b/boost/gil/extension/dynamic_image/apply_operation_base.hpp index 3b55de6e03..2204a93b01 100644 --- a/boost/gil/extension/dynamic_image/apply_operation_base.hpp +++ b/boost/gil/extension/dynamic_image/apply_operation_base.hpp @@ -127,13 +127,13 @@ GIL_GENERATE_APPLY_FWD_OPS(99) // unary application template <typename Types, typename Bits, typename Op> -typename Op::result_type GIL_FORCEINLINE apply_operation_basec(const Bits& bits, std::size_t index, Op op) { +typename Op::result_type BOOST_FORCEINLINE apply_operation_basec(const Bits& bits, std::size_t index, Op op) { return detail::apply_operation_fwd_fn<mpl::size<Types>::value>().template applyc<Types>(bits,index,op); } // unary application template <typename Types, typename Bits, typename Op> -typename Op::result_type GIL_FORCEINLINE apply_operation_base( Bits& bits, std::size_t index, Op op) { +typename Op::result_type BOOST_FORCEINLINE apply_operation_base( Bits& bits, std::size_t index, Op op) { return detail::apply_operation_fwd_fn<mpl::size<Types>::value>().template apply<Types>(bits,index,op); } @@ -141,26 +141,26 @@ namespace detail { template <typename T2, typename Op> struct reduce_bind1 { const T2& _t2; - Op& _op; + Op& _op; typedef typename Op::result_type result_type; reduce_bind1(const T2& t2, Op& op) : _t2(t2), _op(op) {} - template <typename T1> GIL_FORCEINLINE result_type operator()(const T1& t1) { return _op(t1, _t2); } + template <typename T1> BOOST_FORCEINLINE result_type operator()(const T1& t1) { return _op(t1, _t2); } }; template <typename Types1, typename Bits1, typename Op> struct reduce_bind2 { const Bits1& _bits1; std::size_t _index1; - Op& _op; + Op& _op; typedef typename Op::result_type result_type; reduce_bind2(const Bits1& bits1, std::size_t index1, Op& op) : _bits1(bits1), _index1(index1), _op(op) {} - template <typename T2> GIL_FORCEINLINE result_type operator()(const T2& t2) { + template <typename T2> BOOST_FORCEINLINE result_type operator()(const T2& t2) { return apply_operation_basec<Types1>(_bits1, _index1, reduce_bind1<T2,Op>(t2, _op)); } }; @@ -168,7 +168,7 @@ namespace detail { // Binary application by applying on each dimension separately template <typename Types1, typename Types2, typename Bits1, typename Bits2, typename Op> -static typename Op::result_type GIL_FORCEINLINE apply_operation_base(const Bits1& bits1, std::size_t index1, const Bits2& bits2, std::size_t index2, Op op) { +static typename Op::result_type BOOST_FORCEINLINE apply_operation_base(const Bits1& bits1, std::size_t index1, const Bits2& bits2, std::size_t index2, Op op) { return apply_operation_basec<Types2>(bits2,index2,detail::reduce_bind2<Types1,Bits1,Op>(bits1,index1,op)); } diff --git a/boost/gil/extension/dynamic_image/image_view_factory.hpp b/boost/gil/extension/dynamic_image/image_view_factory.hpp index fe82ef1c6b..69ac4f681d 100644 --- a/boost/gil/extension/dynamic_image/image_view_factory.hpp +++ b/boost/gil/extension/dynamic_image/image_view_factory.hpp @@ -175,7 +175,7 @@ struct color_converted_view_type<any_image_view<ViewTypes>,DstP,CC> { /// \ingroup ImageViewTransformationsColorConvert /// \brief overload of generic color_converted_view with user defined color-converter template <typename DstP, typename ViewTypes, typename CC> inline // Models MPL Random Access Container of models of ImageViewConcept -typename color_converted_view_type<any_image_view<ViewTypes>, DstP, CC>::type color_converted_view(const any_image_view<ViewTypes>& src,CC cc) { +typename color_converted_view_type<any_image_view<ViewTypes>, DstP, CC>::type color_converted_view(const any_image_view<ViewTypes>& src, CC) { return apply_operation(src,detail::color_converted_view_fn<DstP,typename color_converted_view_type<any_image_view<ViewTypes>, DstP, CC>::type >()); } @@ -198,7 +198,7 @@ typename color_converted_view_type<any_image_view<ViewTypes>, DstP>::type color_ /// \brief overload of generic color_converted_view with user defined color-converter /// These are workarounds for GCC 3.4, which thinks color_converted_view is ambiguous with the same method for templated views (in gil/image_view_factory.hpp) template <typename DstP, typename ViewTypes, typename CC> inline // Models MPL Random Access Container of models of ImageViewConcept -typename color_converted_view_type<any_image_view<ViewTypes>, DstP, CC>::type any_color_converted_view(const any_image_view<ViewTypes>& src,CC cc) { +typename color_converted_view_type<any_image_view<ViewTypes>, DstP, CC>::type any_color_converted_view(const any_image_view<ViewTypes>& src, CC) { return apply_operation(src,detail::color_converted_view_fn<DstP,typename color_converted_view_type<any_image_view<ViewTypes>, DstP, CC>::type >()); } diff --git a/boost/gil/extension/dynamic_image/reduce.hpp b/boost/gil/extension/dynamic_image/reduce.hpp index ea8623deed..6e86faa991 100644 --- a/boost/gil/extension/dynamic_image/reduce.hpp +++ b/boost/gil/extension/dynamic_image/reduce.hpp @@ -59,7 +59,7 @@ struct mapping_vector {}; template <typename SrcTypes, typename DstTypes, long K> struct at_c<mapping_vector<SrcTypes,DstTypes>, K> { - static const std::size_t value=size<DstTypes>::value - order<DstTypes, typename at_c<SrcTypes,K>::type>::type::value +1; + static const std::size_t value=size<DstTypes>::value - order<DstTypes, typename gil::at_c<SrcTypes,K>::type>::type::value +1; typedef size_t<value> type; }; @@ -147,11 +147,11 @@ struct unary_reduce : public unary_reduce_impl<Types,Op> { typedef typename mpl::mapping_vector<reduced_t, unique_t> indices_t; return gil::at_c<indices_t, unsigned short>(index); } - template <typename Bits> GIL_FORCEINLINE static typename Op::result_type applyc(const Bits& bits, std::size_t index, Op op) { + template <typename Bits> BOOST_FORCEINLINE static typename Op::result_type applyc(const Bits& bits, std::size_t index, Op op) { return apply_operation_basec<unique_t>(bits,map_index(index),op); } - template <typename Bits> GIL_FORCEINLINE static typename Op::result_type apply(Bits& bits, std::size_t index, Op op) { + template <typename Bits> BOOST_FORCEINLINE static typename Op::result_type apply(Bits& bits, std::size_t index, Op op) { return apply_operation_base<unique_t>(bits,map_index(index),op); } }; @@ -161,11 +161,11 @@ struct unary_reduce<Types,Op,true> : public unary_reduce_impl<Types,Op> { typedef typename unary_reduce_impl<Types,Op>::unique_t unique_t; static unsigned short inline map_index(std::size_t index) { return 0; } - template <typename Bits> GIL_FORCEINLINE static typename Op::result_type applyc(const Bits& bits, std::size_t index, Op op) { + template <typename Bits> BOOST_FORCEINLINE static typename Op::result_type applyc(const Bits& bits, std::size_t index, Op op) { return op(*gil_reinterpret_cast_c<const typename mpl::front<unique_t>::type*>(&bits)); } - template <typename Bits> GIL_FORCEINLINE static typename Op::result_type apply(Bits& bits, std::size_t index, Op op) { + template <typename Bits> BOOST_FORCEINLINE static typename Op::result_type apply(Bits& bits, std::size_t index, Op op) { return op(*gil_reinterpret_cast<typename mpl::front<unique_t>::type*>(&bits)); } }; @@ -245,17 +245,17 @@ public: }; template <typename Types, typename UnaryOp> -GIL_FORCEINLINE typename UnaryOp::result_type apply_operation(variant<Types>& arg, UnaryOp op) { +BOOST_FORCEINLINE typename UnaryOp::result_type apply_operation(variant<Types>& arg, UnaryOp op) { return unary_reduce<Types,UnaryOp>::template apply(arg._bits, arg._index ,op); } template <typename Types, typename UnaryOp> -GIL_FORCEINLINE typename UnaryOp::result_type apply_operation(const variant<Types>& arg, UnaryOp op) { +BOOST_FORCEINLINE typename UnaryOp::result_type apply_operation(const variant<Types>& arg, UnaryOp op) { return unary_reduce<Types,UnaryOp>::template applyc(arg._bits, arg._index ,op); } template <typename Types1, typename Types2, typename BinaryOp> -GIL_FORCEINLINE typename BinaryOp::result_type apply_operation(const variant<Types1>& arg1, const variant<Types2>& arg2, BinaryOp op) { +BOOST_FORCEINLINE typename BinaryOp::result_type apply_operation(const variant<Types1>& arg1, const variant<Types2>& arg2, BinaryOp op) { return binary_reduce<Types1,Types2,BinaryOp>::template apply(arg1._bits, arg1._index, arg2._bits, arg2._index, op); } @@ -699,11 +699,11 @@ namespace detail { struct any_type_get_num_channels; template <typename View> struct reduce_view_basic<any_type_get_num_channels,View,true> { typedef typename View::color_space_t::base Cs; - typedef typename view_type<bits8,typename reduce_color_space<Cs>::type>::type type; + typedef typename view_type<uint8_t,typename reduce_color_space<Cs>::type>::type type; }; template <typename Img> struct reduce_image_basic<any_type_get_num_channels,Img,true> { typedef typename Img::color_space_t::base Cs; - typedef typename image_type<bits8,typename reduce_color_space<Cs>::type>::type type; + typedef typename image_type<uint8_t,typename reduce_color_space<Cs>::type>::type type; }; //////////////////////////////////////////////////////// diff --git a/boost/gil/extension/dynamic_image/variant.hpp b/boost/gil/extension/dynamic_image/variant.hpp index 24460ca6bf..1ab53b549d 100644 --- a/boost/gil/extension/dynamic_image/variant.hpp +++ b/boost/gil/extension/dynamic_image/variant.hpp @@ -29,7 +29,8 @@ #include <algorithm> #include <typeinfo> #include <boost/bind.hpp> - +#include <boost/utility/enable_if.hpp> +#include <boost/mpl/bool.hpp> #include <boost/mpl/transform.hpp> #include <boost/mpl/size.hpp> #include <boost/mpl/sizeof.hpp> @@ -48,6 +49,7 @@ namespace detail { }; template <typename T, typename Bits> void copy_construct_in_place(const T& t, Bits& bits); template <typename Bits> struct copy_construct_in_place_fn; + template <typename Types> struct type_to_index_fn; } /** \brief Represents a concrete instance of a run-time specified type from a set of types @@ -100,6 +102,11 @@ public: // Throws std::bad_cast if T is not in Types template <typename T> explicit variant(const T& obj){ _index=type_id<T>(); if (_index==NUM_TYPES) throw std::bad_cast(); detail::copy_construct_in_place(obj, _bits); } + template <typename Types2> explicit variant(const variant<Types2>& obj) : _index(apply_operation(obj,detail::type_to_index_fn<Types>())) { + if (_index==NUM_TYPES) throw std::bad_cast(); + apply_operation(obj, detail::copy_construct_in_place_fn<base_t>(_bits)); + } + // When doSwap is true, swaps obj with the contents of the variant. obj will contain default-constructed instance after the call template <typename T> explicit variant(T& obj, bool do_swap); @@ -161,6 +168,13 @@ namespace detail { return x==*gil_reinterpret_cast_c<const T*>(&_dst); } }; + + template <typename Types> + struct type_to_index_fn { + typedef std::size_t result_type; + + template <typename T> result_type operator()(const T&) const { return detail::type_to_index<Types,T>::value; } + }; } // When doSwap is true, swaps obj with the contents of the variant. obj will contain default-constructed instance after the call diff --git a/boost/gil/extension/io/bmp.hpp b/boost/gil/extension/io/bmp.hpp new file mode 100644 index 0000000000..d9242dde0c --- /dev/null +++ b/boost/gil/extension/io/bmp.hpp @@ -0,0 +1,25 @@ +/* + Copyright 2008 Christian Henning + 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_BMP_HPP +#define BOOST_GIL_EXTENSION_IO_BMP_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file +/// \brief +/// \author Christian Henning \n +/// +/// \date 2008 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +#include <boost/gil/extension/io/bmp/read.hpp> +#include <boost/gil/extension/io/bmp/write.hpp> + +#endif diff --git a/boost/gil/extension/io/bmp/detail/is_allowed.hpp b/boost/gil/extension/io/bmp/detail/is_allowed.hpp new file mode 100644 index 0000000000..fab24d58d7 --- /dev/null +++ b/boost/gil/extension/io/bmp/detail/is_allowed.hpp @@ -0,0 +1,92 @@ +/* + Copyright 2009 Christian Henning + 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_BMP_DETAIL_IS_ALLOWED_HPP +#define BOOST_GIL_EXTENSION_IO_BMP_DETAIL_IS_ALLOWED_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file +/// \brief +/// \author Christian Henning \n +/// +/// \date 2008 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +namespace boost { namespace gil { namespace detail { + +template< typename View > +bool is_allowed( const image_read_info< bmp_tag >& info + , mpl::true_ // is read_and_no_convert + ) +{ + bmp_bits_per_pixel::type src_bits_per_pixel = 0; + + switch( info._bits_per_pixel ) + { + case 1: + case 4: + case 8: + { + if( info._header_size == bmp_header_size::_win32_info_size + && info._compression != bmp_compression::_rle8 + && info._compression != bmp_compression::_rle4 + ) + { + src_bits_per_pixel = 32; + } + else + { + src_bits_per_pixel = 24; + } + + break; + } + + case 15: + case 16: + { + src_bits_per_pixel = 24; + + break; + } + + case 24: + case 32: + { + src_bits_per_pixel = info._bits_per_pixel; + + break; + } + default: + { + io_error( "Pixel size not supported." ); + } + } + + typedef typename channel_traits< typename element_type< typename View::value_type >::type >::value_type channel_t; + bmp_bits_per_pixel::type dst_bits_per_pixel = detail::unsigned_integral_num_bits< channel_t >::value + * num_channels< View >::value; + + return ( dst_bits_per_pixel == src_bits_per_pixel ); +} + +template< typename View > +bool is_allowed( const image_read_info< bmp_tag >& /* info */ + , mpl::false_ // is read_and_convert + ) +{ + return true; +} + +} // namespace detail +} // namespace gil +} // namespace boost + +#endif diff --git a/boost/gil/extension/io/bmp/detail/read.hpp b/boost/gil/extension/io/bmp/detail/read.hpp new file mode 100644 index 0000000000..09e5652885 --- /dev/null +++ b/boost/gil/extension/io/bmp/detail/read.hpp @@ -0,0 +1,758 @@ +/* + Copyright 2012 Christian Henning + 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_BMP_DETAIL_READ_HPP +#define BOOST_GIL_EXTENSION_IO_BMP_DETAIL_READ_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file +/// \brief +/// \author Christian Henning \n +/// +/// \date 2012 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +#include <vector> + +#include <boost/mpl/and.hpp> +#include <boost/type_traits/is_same.hpp> +#include <boost/utility/enable_if.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/row_buffer_helper.hpp> +#include <boost/gil/io/reader_base.hpp> +#include <boost/gil/io/device.hpp> +#include <boost/gil/io/typedefs.hpp> + +#include <boost/gil/extension/io/bmp/detail/reader_backend.hpp> +#include <boost/gil/extension/io/bmp/detail/is_allowed.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 + +/// +/// BMP Reader +/// +template< typename Device + , typename ConversionPolicy + > +class reader< Device + , bmp_tag + , ConversionPolicy + > + : public reader_base< bmp_tag + , ConversionPolicy + > + , public reader_backend< Device + , bmp_tag + > +{ +private: + + typedef reader< Device + , bmp_tag + , ConversionPolicy + > this_t; + + typedef typename ConversionPolicy::color_converter_type cc_t; + +public: + + typedef reader_backend< Device, bmp_tag > backend_t; + +public: + + // + // Constructor + // + reader( const Device& io_dev + , const image_read_settings< bmp_tag >& settings + ) + : backend_t( io_dev + , settings + ) + , _pitch( 0 ) + {} + + // + // Constructor + // + reader( const Device& io_dev + , const ConversionPolicy& cc + , const image_read_settings< bmp_tag >& settings + ) + : reader_base< bmp_tag + , ConversionPolicy + >( cc ) + , backend_t( io_dev + , settings + ) + , _pitch( 0 ) + {} + + + /// Read image. + template< typename View > + void apply( const View& dst_view ) + { + if( this->_info._valid == false ) + { + io_error( "Image header was not read." ); + } + + typedef typename is_same< ConversionPolicy + , detail::read_and_no_convert + >::type is_read_and_convert_t; + + io_error_if( !detail::is_allowed< View >( this->_info + , is_read_and_convert_t() + ) + , "Image types aren't compatible." + ); + + // the row pitch must be multiple 4 bytes + if( this->_info._bits_per_pixel < 8 ) + { + _pitch = static_cast<long>((( this->_info._width * this->_info._bits_per_pixel ) + 7 ) >> 3 ); + } + else + { + _pitch = static_cast<long>( this->_info._width * (( this->_info._bits_per_pixel + 7 ) >> 3 )); + } + + _pitch = (_pitch + 3) & ~3; + + switch( this->_info._bits_per_pixel ) + { + case 1: + { + this->_scanline_length = ( this->_info._width * num_channels< rgba8_view_t >::value + 3 ) & ~3; + + read_palette_image< gray1_image_t::view_t + , detail::mirror_bits< byte_vector_t + , mpl::true_ + > + > ( dst_view ); + break; + } + + case 4: + { + switch ( this->_info._compression ) + { + case bmp_compression::_rle4: + { + ///@todo How can we determine that? + this->_scanline_length = 0; + + read_palette_image_rle( dst_view ); + + break; + } + + case bmp_compression::_rgb: + { + this->_scanline_length = ( this->_info._width * num_channels< rgba8_view_t >::value + 3 ) & ~3; + + read_palette_image< gray4_image_t::view_t + , detail::swap_half_bytes< byte_vector_t + , mpl::true_ + > + > ( dst_view ); + break; + } + + default: + { + io_error( "Unsupported compression mode in BMP file." ); + break; + } + } + break; + } + + case 8: + { + switch ( this->_info._compression ) + { + case bmp_compression::_rle8: + { + ///@todo How can we determine that? + this->_scanline_length = 0; + + read_palette_image_rle( dst_view ); + break; + } + + case bmp_compression::_rgb: + { + this->_scanline_length = ( this->_info._width * num_channels< rgba8_view_t >::value + 3 ) & ~3; + + read_palette_image< gray8_image_t::view_t + , detail::do_nothing< std::vector< gray8_pixel_t > > + > ( dst_view ); + break; + } + + default: + { + io_error( "Unsupported compression mode in BMP file." ); + break; + } + } + + break; + } + + case 15: case 16: + { + this->_scanline_length = ( this->_info._width * num_channels< rgb8_view_t >::value + 3 ) & ~3; + + read_data_15( dst_view ); + + break; + } + + case 24: + { + this->_scanline_length = ( this->_info._width * num_channels< rgb8_view_t >::value + 3 ) & ~3; + + read_data< bgr8_view_t >( dst_view ); + + break; + } + + case 32: + { + this->_scanline_length = ( this->_info._width * num_channels< rgba8_view_t >::value + 3 ) & ~3; + + read_data< bgra8_view_t >( dst_view ); + + break; + } + } + } + +private: + + long get_offset( std::ptrdiff_t pos ) + { + if( this->_info._height > 0 ) + { + // the image is upside down + return static_cast<long>( ( this->_info._offset + + ( this->_info._height - 1 - pos ) * _pitch + )); + } + else + { + return static_cast<long>( ( this->_info._offset + + pos * _pitch + )); + } + } + + template< typename View_Src + , typename Byte_Manipulator + , typename View_Dst + > + void read_palette_image( const View_Dst& view ) + { + this->read_palette(); + + typedef detail::row_buffer_helper_view< View_Src > rh_t; + typedef typename rh_t::iterator_t it_t; + + rh_t rh( _pitch, true ); + + // we have to swap bits + Byte_Manipulator byte_manipulator; + + for( std::ptrdiff_t y = 0 + ; y < this->_settings._dim.y + ; ++y + ) + { + this->_io_dev.seek( get_offset( y + this->_settings._top_left.y )); + + this->_io_dev.read( reinterpret_cast< byte_t* >( rh.data() ) + , _pitch + ); + + byte_manipulator( rh.buffer() ); + + typename View_Dst::x_iterator dst_it = view.row_begin( y ); + + it_t it = rh.begin() + this->_settings._top_left.x; + it_t end = it + this->_settings._dim.x; + + for( ; it != end; ++it, ++dst_it ) + { + unsigned char c = get_color( *it, gray_color_t() ); + *dst_it = this->_palette[ c ]; + } + } + } + + template< typename View > + void read_data_15( const View& view ) + { + byte_vector_t row( _pitch ); + + // read the color masks + if( this->_info._compression == bmp_compression::_bitfield ) + { + this->_mask.red.mask = this->_io_dev.read_uint32(); + this->_mask.green.mask = this->_io_dev.read_uint32(); + this->_mask.blue.mask = this->_io_dev.read_uint32(); + + this->_mask.red.width = detail::count_ones( this->_mask.red.mask ); + this->_mask.green.width = detail::count_ones( this->_mask.green.mask ); + this->_mask.blue.width = detail::count_ones( this->_mask.blue.mask ); + + this->_mask.red.shift = detail::trailing_zeros( this->_mask.red.mask ); + this->_mask.green.shift = detail::trailing_zeros( this->_mask.green.mask ); + this->_mask.blue.shift = detail::trailing_zeros( this->_mask.blue.mask ); + } + else if( this->_info._compression == bmp_compression::_rgb ) + { + switch( this->_info._bits_per_pixel ) + { + case 15: + case 16: + { + this->_mask.red.mask = 0x007C00; this->_mask.red.width = 5; this->_mask.red.shift = 10; + this->_mask.green.mask = 0x0003E0; this->_mask.green.width = 5; this->_mask.green.shift = 5; + this->_mask.blue.mask = 0x00001F; this->_mask.blue.width = 5; this->_mask.blue.shift = 0; + + break; + } + + case 24: + case 32: + { + this->_mask.red.mask = 0xFF0000; this->_mask.red.width = 8; this->_mask.red.shift = 16; + this->_mask.green.mask = 0x00FF00; this->_mask.green.width = 8; this->_mask.green.shift = 8; + this->_mask.blue.mask = 0x0000FF; this->_mask.blue.width = 8; this->_mask.blue.shift = 0; + + break; + } + } + } + else + { + io_error( "bmp_reader::apply(): unsupported BMP compression" ); + } + + typedef rgb8_image_t image_t; + typedef typename image_t::view_t::x_iterator it_t; + + for( std::ptrdiff_t y = 0 + ; y < this->_settings._dim.y + ; ++y + ) + { + this->_io_dev.seek( get_offset( y + this->_settings._top_left.y )); + + this->_io_dev.read( &row.front() + , row.size() + ); + + image_t img_row( this->_info._width, 1 ); + image_t::view_t v = gil::view( img_row ); + it_t it = v.row_begin( 0 ); + + it_t beg = v.row_begin( 0 ) + this->_settings._top_left.x; + it_t end = beg + this->_settings._dim.x; + + byte_t* src = &row.front(); + for( int32_t i = 0 ; i < this->_info._width; ++i, src += 2 ) + { + int p = ( src[1] << 8 ) | src[0]; + + int r = ((p & this->_mask.red.mask) >> this->_mask.red.shift) << (8 - this->_mask.red.width); + int g = ((p & this->_mask.green.mask) >> this->_mask.green.shift) << (8 - this->_mask.green.width); + int b = ((p & this->_mask.blue.mask) >> this->_mask.blue.shift) << (8 - this->_mask.blue.width); + + get_color( it[i], red_t() ) = static_cast< byte_t >( r ); + get_color( it[i], green_t() ) = static_cast< byte_t >( g ); + get_color( it[i], blue_t() ) = static_cast< byte_t >( b ); + } + + this->_cc_policy.read( beg + , end + , view.row_begin( y ) + ); + } + } + + + // 8-8-8 BGR + // 8-8-8-8 BGRA + template< typename View_Src + , typename View_Dst + > + void read_data( const View_Dst& view ) + { + byte_vector_t row( _pitch ); + + View_Src v = interleaved_view( this->_info._width + , 1 + , (typename View_Src::value_type*) &row.front() + , this->_info._width * num_channels< View_Src >::value + ); + + typename View_Src::x_iterator beg = v.row_begin( 0 ) + this->_settings._top_left.x; + typename View_Src::x_iterator end = beg + this->_settings._dim.x; + + for( std::ptrdiff_t y = 0 + ; y < this->_settings._dim.y + ; ++y + ) + { + this->_io_dev.seek( get_offset( y + this->_settings._top_left.y )); + + this->_io_dev.read( &row.front() + , row.size() + ); + + this->_cc_policy.read( beg + , end + , view.row_begin( y ) + ); + } + } + + template< typename Buffer + , typename View + > + void copy_row_if_needed( const Buffer& buf + , const View& view + , std::ptrdiff_t y + ) + { + if( y >= this->_settings._top_left.y + && y < this->_settings._dim.y + ) + { + typename Buffer::const_iterator beg = buf.begin() + this->_settings._top_left.x; + typename Buffer::const_iterator end = beg + this->_settings._dim.x; + + std::copy( beg + , end + , view.row_begin( y ) + ); + } + } + + template< typename View_Dst > + void read_palette_image_rle( const View_Dst& view ) + { + assert( this->_info._compression == bmp_compression::_rle4 + || this->_info._compression == bmp_compression::_rle8 + ); + + this->read_palette(); + + // jump to start of rle4 data + this->_io_dev.seek( this->_info._offset ); + + // we need to know the stream position for padding purposes + std::size_t stream_pos = this->_info._offset; + + typedef std::vector< rgba8_pixel_t > Buf_type; + Buf_type buf( this->_settings._dim.x ); + Buf_type::iterator dst_it = buf.begin(); + Buf_type::iterator dst_end = buf.end(); + + // If height is positive, the bitmap is a bottom-up DIB. + // If height is negative, the bitmap is a top-down DIB. + // The origin of a bottom-up DIB is the bottom left corner of the bitmap image, + // which is the first pixel of the first row of bitmap data. + // The origin of a top-down DIB is also the bottom left corner of the bitmap image, + // but in this case the bottom left corner is the first pixel of the last row of bitmap data. + // - "Programming Windows", 5th Ed. by Charles Petzold explains Windows docs ambiguities. + std::ptrdiff_t ybeg = 0; + std::ptrdiff_t yend = this->_settings._dim.y; + std::ptrdiff_t yinc = 1; + if( this->_info._height > 0 ) + { + ybeg = this->_settings._dim.y - 1; + yend = -1; + yinc = -1; + } + + std::ptrdiff_t y = ybeg; + bool finished = false; + + while ( !finished ) + { + std::ptrdiff_t count = this->_io_dev.read_uint8(); + std::ptrdiff_t second = this->_io_dev.read_uint8(); + stream_pos += 2; + + if ( count ) + { + // encoded mode + + // clamp to boundary + if( count > dst_end - dst_it ) + { + count = dst_end - dst_it; + } + + if( this->_info._compression == bmp_compression::_rle4 ) + { + std::ptrdiff_t cs[2] = { second >> 4, second & 0x0f }; + + for( int i = 0; i < count; ++i ) + { + *dst_it++ = this->_palette[ cs[i & 1] ]; + } + } + else + { + for( int i = 0; i < count; ++i ) + { + *dst_it++ = this->_palette[ second ]; + } + } + } + else + { + switch( second ) + { + case 0: // end of row + { + copy_row_if_needed( buf, view, y ); + + y += yinc; + if( y == yend ) + { + finished = true; + } + else + { + dst_it = buf.begin(); + dst_end = buf.end(); + } + + break; + } + + case 1: // end of bitmap + { + copy_row_if_needed( buf, view, y ); + finished = true; + + break; + } + + case 2: // offset coordinates + { + std::ptrdiff_t dx = this->_io_dev.read_uint8(); + std::ptrdiff_t dy = this->_io_dev.read_uint8() * yinc; + stream_pos += 2; + + if( dy ) + { + copy_row_if_needed( buf, view, y ); + } + + std::ptrdiff_t x = dst_it - buf.begin(); + x += dx; + + if( x > this->_info._width ) + { + io_error( "Mangled BMP file." ); + } + + y += dy; + if( yinc > 0 ? y > yend : y < yend ) + { + io_error( "Mangled BMP file." ); + } + + dst_it = buf.begin() + x; + dst_end = buf.end(); + + break; + } + + default: // absolute mode + { + count = second; + + // clamp to boundary + if( count > dst_end - dst_it ) + { + count = dst_end - dst_it; + } + + if ( this->_info._compression == bmp_compression::_rle4 ) + { + for( int i = 0; i < count; ++i ) + { + uint8_t packed_indices = this->_io_dev.read_uint8(); + ++stream_pos; + + *dst_it++ = this->_palette[ packed_indices >> 4 ]; + if( ++i == second ) + break; + + *dst_it++ = this->_palette[ packed_indices & 0x0f ]; + } + } + else + { + for( int i = 0; i < count; ++i ) + { + uint8_t c = this->_io_dev.read_uint8(); + ++stream_pos; + *dst_it++ = this->_palette[ c ]; + } + } + + // pad to word boundary + if( ( stream_pos - get_offset( 0 )) & 1 ) + { + this->_io_dev.seek( 1, SEEK_CUR ); + ++stream_pos; + } + + break; + } + } + } + } + } + +private: + + std::size_t _pitch; +}; + +namespace detail { + +class bmp_type_format_checker +{ +public: + + bmp_type_format_checker( const bmp_bits_per_pixel::type& bpp ) + : _bpp( bpp ) + {} + + template< typename Image > + bool apply() + { + if( _bpp < 32 ) + { + return pixels_are_compatible< typename Image::value_type, rgb8_pixel_t >::value + ? true + : false; + } + else + { + return pixels_are_compatible< typename Image::value_type, rgba8_pixel_t >::value + ? true + : false; + } + } + +private: + + // to avoid C4512 + bmp_type_format_checker& operator=( const bmp_type_format_checker& ) { return *this; } + +private: + + const bmp_bits_per_pixel::type _bpp; +}; + +struct bmp_read_is_supported +{ + template< typename View > + struct apply : public is_read_supported< typename get_pixel_type< View >::type + , bmp_tag + > + {}; +}; + +} // namespace detail + +/// +/// BMP Dynamic Reader +/// +template< typename Device > +class dynamic_image_reader< Device + , bmp_tag + > + : public reader< Device + , bmp_tag + , detail::read_and_no_convert + > +{ + typedef reader< Device + , bmp_tag + , detail::read_and_no_convert + > parent_t; + +public: + + dynamic_image_reader( const Device& io_dev + , const image_read_settings< bmp_tag >& settings + ) + : parent_t( io_dev + , settings + ) + {} + + template< typename Images > + void apply( any_image< Images >& images ) + { + detail::bmp_type_format_checker format_checker( this->_info._bits_per_pixel ); + + 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::bmp_read_is_supported + , parent_t + > op( this ); + + apply_operation( view( images ) + , op + ); + } + } +}; + +#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) +#pragma warning(pop) +#endif + +} // gil +} // boost + +#endif diff --git a/boost/gil/extension/io/bmp/detail/reader_backend.hpp b/boost/gil/extension/io/bmp/detail/reader_backend.hpp new file mode 100644 index 0000000000..589a5e3c4f --- /dev/null +++ b/boost/gil/extension/io/bmp/detail/reader_backend.hpp @@ -0,0 +1,258 @@ +/* + Copyright 2012 Christian Henning + 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_BMP_DETAIL_READER_BACKEND_HPP +#define BOOST_GIL_EXTENSION_IO_BMP_DETAIL_READER_BACKEND_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file +/// \brief +/// \author Christian Henning \n +/// +/// \date 2012 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +#include <boost/gil/extension/io/bmp/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 + +/// Color channel mask +struct bit_field +{ + unsigned int mask; // Bit mask at corresponding position + unsigned int width; // Bit width of the mask + unsigned int shift; // Bit position from right to left +}; + +/// BMP color masks +struct color_mask +{ + bit_field red; // Red bits + bit_field green; // Green bits + bit_field blue; // Blue bits +}; + + +/// +/// BMP Backend +/// +template< typename Device > +struct reader_backend< Device + , bmp_tag + > +{ +public: + + typedef bmp_tag format_tag_t; + +public: + + reader_backend( const Device& io_dev + , const image_read_settings< bmp_tag >& settings + ) + : _io_dev ( io_dev ) + , _settings( settings ) + , _info() + , _scanline_length( 0 ) + , _palette() + { + 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() + { + // the magic number used to identify the BMP file: + // 0x42 0x4D (ASCII code points for B and M) + if( _io_dev.read_uint16() == 0x424D ) + { + io_error( "Wrong magic number for bmp file." ); + } + + // the size of the BMP file in bytes + _io_dev.read_uint32(); + + // reserved; actual value depends on the application that creates the image + _io_dev.read_uint16(); + // reserved; actual value depends on the application that creates the image + _io_dev.read_uint16(); + + _info._offset = _io_dev.read_uint32(); + + + // bitmap information + + // the size of this header ( 40 bytes ) + _info._header_size = _io_dev.read_uint32(); + + if( _info._header_size == bmp_header_size::_win32_info_size ) + { + _info._width = _io_dev.read_uint32(); + _info._height = _io_dev.read_uint32(); + + if (_info._height < 0) + { + _info._height = -_info._height; + _info._top_down = true; + } + + // the number of color planes being used. Must be set to 1. + _io_dev.read_uint16(); + + _info._bits_per_pixel = _io_dev.read_uint16(); + + _info._compression = _io_dev.read_uint32(); + + _info._image_size = _io_dev.read_uint32(); + + _info._horizontal_resolution = _io_dev.read_uint32(); + _info._vertical_resolution = _io_dev.read_uint32(); + + _info._num_colors = _io_dev.read_uint32(); + _info._num_important_colors = _io_dev.read_uint32(); + + } + else if( _info._header_size == bmp_header_size::_os2_info_size ) + { + _info._width = static_cast< bmp_image_width::type >( _io_dev.read_uint16() ); + _info._height = static_cast< bmp_image_height::type >( _io_dev.read_uint16() ); + + // the number of color planes being used. Must be set to 1. + _io_dev.read_uint16(); + + _info._bits_per_pixel = _io_dev.read_uint16(); + + _info._compression = bmp_compression::_rgb; + + // not used + _info._image_size = 0; + _info._horizontal_resolution = 0; + _info._vertical_resolution = 0; + _info._num_colors = 0; + _info._num_important_colors = 0; + } + else if (_info._header_size > bmp_header_size::_win32_info_size) + { + // could be v4 or v5 + // see MSDN: Bitmap Header Types ( BITMAPV4HEADER or BITMAPV5HEADER ) + + _info._width = _io_dev.read_uint32(); + _info._height = _io_dev.read_uint32(); + + // the number of color planes being used. Must be set to 1. + _io_dev.read_uint16(); + + _info._bits_per_pixel = _io_dev.read_uint16(); + + _info._compression = _io_dev.read_uint32(); + + _info._image_size = _io_dev.read_uint32(); + + _info._horizontal_resolution = _io_dev.read_uint32(); + _info._vertical_resolution = _io_dev.read_uint32(); + + _info._num_colors = _io_dev.read_uint32(); + _info._num_important_colors = _io_dev.read_uint32(); + } + else + { + io_error( "Invalid BMP info header." ); + } + + _info._valid = true; + } + + void read_palette() + { + int entries = this->_info._num_colors; + + if( entries == 0 ) + { + entries = 1u << this->_info._bits_per_pixel; + } + + _palette.resize( entries, rgba8_pixel_t(0, 0, 0, 0)); + + for( int i = 0; i < entries; ++i ) + { + get_color( _palette[i], blue_t() ) = _io_dev.read_uint8(); + get_color( _palette[i], green_t() ) = _io_dev.read_uint8(); + get_color( _palette[i], red_t() ) = _io_dev.read_uint8(); + + // there are 4 entries when windows header + // but 3 for os2 header + if( _info._header_size == bmp_header_size::_win32_info_size ) + { + _io_dev.read_uint8(); + } + + } // for + } + + /// 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( 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( img_dim.y < _info._height ) { io_error( "Supplied image is too small" ); } + } + } + +public: + + Device _io_dev; + + image_read_settings< bmp_tag > _settings; + image_read_info< bmp_tag > _info; + + std::size_t _scanline_length; + + ///@todo make it an image. + std::vector< rgba8_pixel_t > _palette; + + color_mask _mask; +}; + +#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) +#pragma warning(pop) +#endif + +} // namespace gil +} // namespace boost + +#endif diff --git a/boost/gil/extension/io/bmp/detail/scanline_read.hpp b/boost/gil/extension/io/bmp/detail/scanline_read.hpp new file mode 100644 index 0000000000..fdc1e54f68 --- /dev/null +++ b/boost/gil/extension/io/bmp/detail/scanline_read.hpp @@ -0,0 +1,425 @@ +/* + Copyright 2008 Christian Henning + 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_BMP_DETAIL_SCANLINE_READ_HPP +#define BOOST_GIL_EXTENSION_IO_BMP_DETAIL_SCANLINE_READ_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file +/// \brief +/// \author Christian Henning \n +/// +/// \date 2008 - 2012 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +#include <vector> + +#include <boost/function.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/row_buffer_helper.hpp> +#include <boost/gil/io/reader_base.hpp> +#include <boost/gil/io/device.hpp> +#include <boost/gil/io/scanline_read_iterator.hpp> +#include <boost/gil/io/typedefs.hpp> + +#include <boost/gil/extension/io/bmp/detail/reader_backend.hpp> +#include <boost/gil/extension/io/bmp/detail/is_allowed.hpp> + +namespace boost { namespace gil { + +/// +/// BMP Scanline Reader +/// +template< typename Device > +class scanline_reader< Device + , bmp_tag + > + : public reader_backend< Device + , bmp_tag + > +{ +public: + + typedef bmp_tag tag_t; + typedef reader_backend < Device, tag_t > backend_t; + typedef scanline_reader< Device, tag_t > this_t; + typedef scanline_read_iterator< this_t > iterator_t; + +public: + + // + // Constructor + // + scanline_reader( Device& device + , const image_read_settings< bmp_tag >& settings + ) + : backend_t( device + , settings + ) + + , _pitch( 0 ) + { + initialize(); + } + + /// Read part of image defined by View and return the data. + void read( byte_t* dst, int pos ) + { + // jump to scanline + long offset = 0; + + if( this->_info._height > 0 ) + { + // the image is upside down + offset = this->_info._offset + + ( this->_info._height - 1 - pos ) * this->_pitch; + } + else + { + offset = this->_info._offset + + pos * _pitch; + } + + this->_io_dev.seek( offset ); + + + // read data + _read_function(this, dst); + } + + /// Skip over a scanline. + void skip( byte_t*, int ) + { + // nothing to do. + } + + iterator_t begin() { return iterator_t( *this ); } + iterator_t end() { return iterator_t( *this, this->_info._height ); } + +private: + + void initialize() + { + if( this->_info._bits_per_pixel < 8 ) + { + _pitch = (( this->_info._width * this->_info._bits_per_pixel ) + 7 ) >> 3; + } + else + { + _pitch = this->_info._width * (( this->_info._bits_per_pixel + 7 ) >> 3); + } + + _pitch = (_pitch + 3) & ~3; + + // + + switch( this->_info._bits_per_pixel ) + { + case 1: + { + this->_scanline_length = ( this->_info._width * num_channels< rgba8_view_t >::value + 3 ) & ~3; + + read_palette(); + _buffer.resize( _pitch ); + + _read_function = boost::mem_fn( &this_t::read_1_bit_row ); + + break; + } + + case 4: + { + switch( this->_info._compression ) + { + case bmp_compression::_rle4: + { + io_error( "Cannot read run-length encoded images in iterator mode. Try to read as whole image." ); + + break; + } + + case bmp_compression::_rgb : + { + this->_scanline_length = ( this->_info._width * num_channels< rgba8_view_t >::value + 3 ) & ~3; + + read_palette(); + _buffer.resize( _pitch ); + + _read_function = boost::mem_fn( &this_t::read_4_bits_row ); + + break; + } + + default: + { + io_error( "Unsupported compression mode in BMP file." ); + } + } + + break; + } + + case 8: + { + switch( this->_info._compression ) + { + case bmp_compression::_rle8: + { + io_error( "Cannot read run-length encoded images in iterator mode. Try to read as whole image." ); + + break; + } + case bmp_compression::_rgb: + { + this->_scanline_length = ( this->_info._width * num_channels< rgba8_view_t >::value + 3 ) & ~3; + + read_palette(); + _buffer.resize( _pitch ); + + _read_function = boost::mem_fn( &this_t::read_8_bits_row ); + + break; + } + + default: { io_error( "Unsupported compression mode in BMP file." ); break; } + } + + break; + } + + case 15: + case 16: + { + this->_scanline_length = ( this->_info._width * num_channels< rgb8_view_t >::value + 3 ) & ~3; + + _buffer.resize( _pitch ); + + if( this->_info._compression == bmp_compression::_bitfield ) + { + this->_mask.red.mask = this->_io_dev.read_uint32(); + this->_mask.green.mask = this->_io_dev.read_uint32(); + this->_mask.blue.mask = this->_io_dev.read_uint32(); + + this->_mask.red.width = detail::count_ones( this->_mask.red.mask ); + this->_mask.green.width = detail::count_ones( this->_mask.green.mask ); + this->_mask.blue.width = detail::count_ones( this->_mask.blue.mask ); + + this->_mask.red.shift = detail::trailing_zeros( this->_mask.red.mask ); + this->_mask.green.shift = detail::trailing_zeros( this->_mask.green.mask ); + this->_mask.blue.shift = detail::trailing_zeros( this->_mask.blue.mask ); + } + else if( this->_info._compression == bmp_compression::_rgb ) + { + switch( this->_info._bits_per_pixel ) + { + case 15: + case 16: + { + this->_mask.red.mask = 0x007C00; this->_mask.red.width = 5; this->_mask.red.shift = 10; + this->_mask.green.mask = 0x0003E0; this->_mask.green.width = 5; this->_mask.green.shift = 5; + this->_mask.blue.mask = 0x00001F; this->_mask.blue.width = 5; this->_mask.blue.shift = 0; + + break; + } + + case 24: + case 32: + { + this->_mask.red.mask = 0xFF0000; this->_mask.red.width = 8; this->_mask.red.shift = 16; + this->_mask.green.mask = 0x00FF00; this->_mask.green.width = 8; this->_mask.green.shift = 8; + this->_mask.blue.mask = 0x0000FF; this->_mask.blue.width = 8; this->_mask.blue.shift = 0; + + break; + } + } + } + else + { + io_error( "Unsupported BMP compression." ); + } + + + _read_function = boost::mem_fn( &this_t::read_15_bits_row ); + + break; + } + + case 24: + { + this->_scanline_length = ( this->_info._width * num_channels< rgb8_view_t >::value + 3 ) & ~3; + _read_function = boost::mem_fn( &this_t::read_row ); + + break; + } + + case 32: + { + this->_scanline_length = ( this->_info._width * num_channels< rgba8_view_t >::value + 3 ) & ~3; + _read_function = boost::mem_fn( &this_t::read_row ); + + break; + } + + default: + { + io_error( "Unsupported bits per pixel." ); + } + } + } + + void read_palette() + { + if( this->_palette.size() > 0 ) + { + // palette has been read already. + return; + } + + int entries = this->_info._num_colors; + + if( entries == 0 ) + { + entries = 1u << this->_info._bits_per_pixel; + } + + this->_palette.resize( entries, rgba8_pixel_t(0,0,0,0) ); + + for( int i = 0; i < entries; ++i ) + { + get_color( this->_palette[i], blue_t() ) = this->_io_dev.read_uint8(); + get_color( this->_palette[i], green_t() ) = this->_io_dev.read_uint8(); + get_color( this->_palette[i], red_t() ) = this->_io_dev.read_uint8(); + + // there are 4 entries when windows header + // but 3 for os2 header + if( this->_info._header_size == bmp_header_size::_win32_info_size ) + { + this->_io_dev.read_uint8(); + } + + } // for + } + + template< typename View > + void read_bit_row( byte_t* dst ) + { + typedef View src_view_t; + typedef rgba8_image_t::view_t dst_view_t; + + src_view_t src_view = interleaved_view( this->_info._width + , 1 + , (typename src_view_t::x_iterator) &_buffer.front() + , this->_pitch + ); + + dst_view_t dst_view = interleaved_view( this->_info._width + , 1 + , (typename dst_view_t::value_type*) dst + , num_channels< dst_view_t >::value * this->_info._width + ); + + + typename src_view_t::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++ + ) + { + unsigned char c = get_color( *src_it, gray_color_t() ); + *dst_it = this->_palette[c]; + } + } + + // Read 1 bit image. The colors are encoded by an index. + void read_1_bit_row( byte_t* dst ) + { + this->_io_dev.read( &_buffer.front(), _pitch ); + _mirror_bits( _buffer ); + + read_bit_row< gray1_image_t::view_t >( dst ); + } + + // Read 4 bits image. The colors are encoded by an index. + void read_4_bits_row( byte_t* dst ) + { + this->_io_dev.read( &_buffer.front(), _pitch ); + _swap_half_bytes( _buffer ); + + read_bit_row< gray4_image_t::view_t >( dst ); + } + + /// Read 8 bits image. The colors are encoded by an index. + void read_8_bits_row( byte_t* dst ) + { + this->_io_dev.read( &_buffer.front(), _pitch ); + + read_bit_row< gray8_image_t::view_t >( dst ); + } + + /// Read 15 or 16 bits image. + void read_15_bits_row( byte_t* dst ) + { + typedef rgb8_view_t dst_view_t; + + dst_view_t dst_view = interleaved_view( this->_info._width + , 1 + , (typename dst_view_t::value_type*) dst + , this->_pitch + ); + + typename dst_view_t::x_iterator dst_it = dst_view.row_begin( 0 ); + + // + byte_t* src = &_buffer.front(); + this->_io_dev.read( src, _pitch ); + + for( dst_view_t::x_coord_t i = 0 + ; i < this->_info._width + ; ++i, src += 2 + ) + { + int p = ( src[1] << 8 ) | src[0]; + + int r = ((p & this->_mask.red.mask) >> this->_mask.red.shift) << (8 - this->_mask.red.width); + int g = ((p & this->_mask.green.mask) >> this->_mask.green.shift) << (8 - this->_mask.green.width); + int b = ((p & this->_mask.blue.mask) >> this->_mask.blue.shift) << (8 - this->_mask.blue.width); + + get_color( dst_it[i], red_t() ) = static_cast< byte_t >( r ); + get_color( dst_it[i], green_t() ) = static_cast< byte_t >( g ); + get_color( dst_it[i], blue_t() ) = static_cast< byte_t >( b ); + } + } + + void read_row( byte_t* dst ) + { + this->_io_dev.read( dst, _pitch ); + } + +private: + + // the row pitch must be multiple of 4 bytes + int _pitch; + + std::vector< byte_t > _buffer; + detail::mirror_bits < std::vector< byte_t >, mpl::true_ > _mirror_bits; + detail::swap_half_bytes< std::vector< byte_t >, mpl::true_ > _swap_half_bytes; + + boost::function< void ( this_t*, byte_t* ) > _read_function; +}; + +} // namespace gil +} // namespace boost + +#endif diff --git a/boost/gil/extension/io/bmp/detail/supported_types.hpp b/boost/gil/extension/io/bmp/detail/supported_types.hpp new file mode 100644 index 0000000000..89765594aa --- /dev/null +++ b/boost/gil/extension/io/bmp/detail/supported_types.hpp @@ -0,0 +1,150 @@ +/* + Copyright 2008 Christian Henning + 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_BMP_DETAIL_SUPPORTED_TYPES_HPP +#define BOOST_GIL_EXTENSION_IO_BMP_DETAIL_SUPPORTED_TYPES_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file +/// \brief +/// \author Christian Henning \n +/// +/// \date 2008 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +#include <boost/mpl/not.hpp> +#include <boost/type_traits/is_same.hpp> + +#include <boost/gil/channel.hpp> +#include <boost/gil/color_base.hpp> +#include <boost/gil/bit_aligned_pixel_reference.hpp> +#include <boost/gil/packed_pixel.hpp> + +#include <boost/gil/io/base.hpp> + + +namespace boost { namespace gil { namespace detail { + +// Read support + +template< typename Channel + , typename ColorSpace + > +struct bmp_read_support : read_support_false +{ + static const bmp_bits_per_pixel::type bpp = 0; +}; + +template< typename BitField + , bool Mutable + > +struct bmp_read_support< packed_dynamic_channel_reference< BitField + , 1 + , Mutable + > + , gray_t + > : read_support_true +{ + static const bmp_bits_per_pixel::type bpp = 1; +}; + +template< typename BitField + , bool Mutable + > +struct bmp_read_support< packed_dynamic_channel_reference< BitField + , 4 + , Mutable + > + , gray_t + > : read_support_true +{ + static const bmp_bits_per_pixel::type bpp = 4; +}; + + +template<> +struct bmp_read_support<uint8_t + , gray_t + > : read_support_true +{ + static const bmp_bits_per_pixel::type bpp = 8; +}; + + + +template<> +struct bmp_read_support<uint8_t + , rgb_t + > : read_support_true +{ + static const bmp_bits_per_pixel::type bpp = 24; +}; + + +template<> +struct bmp_read_support<uint8_t + , rgba_t + > : read_support_true +{ + static const bmp_bits_per_pixel::type bpp = 32; +}; + + +// Write support + +template< typename Channel + , typename ColorSpace + > +struct bmp_write_support : write_support_false +{}; + +template<> +struct bmp_write_support<uint8_t + , rgb_t + > : write_support_true {}; + +template<> +struct bmp_write_support<uint8_t + , rgba_t + > : write_support_true {}; + +} // namespace detail + + +template< typename Pixel > +struct is_read_supported< Pixel + , bmp_tag + > + : mpl::bool_< detail::bmp_read_support< typename channel_type< Pixel >::type + , typename color_space_type< Pixel >::type + >::is_supported + > +{ + typedef detail::bmp_read_support< typename channel_type< Pixel >::type + , typename color_space_type< Pixel >::type + > parent_t; + + static const typename bmp_bits_per_pixel::type bpp = parent_t::bpp; +}; + +template< typename Pixel > +struct is_write_supported< Pixel + , bmp_tag + > + : mpl::bool_< detail::bmp_write_support< typename channel_type< Pixel >::type + , typename color_space_type< Pixel >::type + >::is_supported + > {}; + +} // namespace gil +} // namespace boost + + +#endif diff --git a/boost/gil/extension/io/bmp/detail/write.hpp b/boost/gil/extension/io/bmp/detail/write.hpp new file mode 100644 index 0000000000..08ea24bae0 --- /dev/null +++ b/boost/gil/extension/io/bmp/detail/write.hpp @@ -0,0 +1,230 @@ +/* + Copyright 2012 Christian Henning + 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_BMP_DETAIL_WRITE_HPP +#define BOOST_GIL_EXTENSION_IO_BMP_DETAIL_WRITE_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file +/// \brief +/// \author Christian Henning \n +/// +/// \date 2012 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +#include <vector> + +#include <boost/gil/io/base.hpp> +#include <boost/gil/io/device.hpp> + +#include <boost/gil/extension/io/bmp/tags.hpp> + +#include <boost/gil/extension/io/bmp/detail/writer_backend.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 { + +struct bmp_write_is_supported +{ + template< typename View > + struct apply + : public is_write_supported< typename get_pixel_type< View >::type + , bmp_tag + > + {}; +}; + +template < int N > struct get_bgr_cs {}; +template <> struct get_bgr_cs< 1 > { typedef gray8_view_t type; }; +template <> struct get_bgr_cs< 3 > { typedef bgr8_view_t type; }; +template <> struct get_bgr_cs< 4 > { typedef bgra8_view_t type; }; + +} // namespace detail + +/// +/// BMP Writer +/// +template< typename Device > +class writer< Device + , bmp_tag + > + : public writer_backend< Device + , bmp_tag + > +{ +public: + + writer( const Device& io_dev + , const image_write_info< bmp_tag >& info + ) + : backend_t( io_dev + , info + ) + {} + + template<typename View> + void apply( const View& view ) + { + write( view ); + } + +private: + + typedef writer_backend< Device, bmp_tag > backend_t; + + template< typename View > + void write( const View& view ) + { + // typedef typename channel_type< + // typename get_pixel_type< View >::type >::type channel_t; + + // typedef typename color_space_type< View >::type color_space_t; + + // check if supported +/* + /// todo + if( bmp_read_write_support_private<channel_t, color_space_t>::channel != 8) + { + io_error("Input view type is incompatible with the image type"); + } +*/ + + // compute the file size + int bpp = num_channels< View >::value * 8; + int entries = 0; + +/* + /// @todo: Not supported for now. bit_aligned_images refer to indexed images + /// in this context. + if( bpp <= 8 ) + { + entries = 1u << bpp; + } +*/ + + std::size_t spn = ( view.width() * num_channels< View >::value + 3 ) & ~3; + std::size_t ofs = bmp_header_size::_size + + bmp_header_size::_win32_info_size + + entries * 4; + + std::size_t siz = ofs + spn * view.height(); + + // write the BMP file header + this->_io_dev.write_uint16( bmp_signature ); + this->_io_dev.write_uint32( (uint32_t) siz ); + this->_io_dev.write_uint16( 0 ); + this->_io_dev.write_uint16( 0 ); + this->_io_dev.write_uint32( (uint32_t) ofs ); + + // writes Windows information header + this->_io_dev.write_uint32( bmp_header_size::_win32_info_size ); + this->_io_dev.write_uint32( static_cast< uint32_t >( view.width() )); + this->_io_dev.write_uint32( static_cast< uint32_t >( view.height() )); + this->_io_dev.write_uint16( 1 ); + this->_io_dev.write_uint16( static_cast< uint16_t >( bpp )); + this->_io_dev.write_uint32( bmp_compression::_rgb ); + this->_io_dev.write_uint32( 0 ); + this->_io_dev.write_uint32( 0 ); + this->_io_dev.write_uint32( 0 ); + this->_io_dev.write_uint32( entries ); + this->_io_dev.write_uint32( 0 ); + + write_image< View + , typename detail::get_bgr_cs< num_channels< View >::value >::type + >( view, spn ); + } + + + template< typename View + , typename BMP_View + > + void write_image( const View& view + , const std::size_t spn + ) + { + byte_vector_t buffer( spn ); + std::fill( buffer.begin(), buffer.end(), 0 ); + + + BMP_View row = interleaved_view( view.width() + , 1 + , (typename BMP_View::value_type*) &buffer.front() + , spn + ); + + for( typename View::y_coord_t y = view.height() - 1; y > -1; --y ) + { + copy_pixels( subimage_view( view + , 0 + , (int) y + , (int) view.width() + , 1 + ) + , row + ); + + this->_io_dev.write( &buffer.front(), spn ); + } + + } +}; + +/// +/// BMP Dynamic Image Writer +/// +template< typename Device > +class dynamic_image_writer< Device + , bmp_tag + > + : public writer< Device + , bmp_tag + > +{ + typedef writer< Device + , bmp_tag + > parent_t; + +public: + + dynamic_image_writer( const Device& io_dev + , const image_write_info< bmp_tag >& info + ) + : parent_t( io_dev + , info + ) + {} + + template< typename Views > + void apply( const any_image_view< Views >& views ) + { + detail::dynamic_io_fnobj< detail::bmp_write_is_supported + , parent_t + > op( this ); + + apply_operation( views + , op + ); + } +}; + +#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) +#pragma warning(pop) +#endif + +} // gil +} // boost + +#endif diff --git a/boost/gil/extension/io/bmp/detail/writer_backend.hpp b/boost/gil/extension/io/bmp/detail/writer_backend.hpp new file mode 100644 index 0000000000..a5147859f8 --- /dev/null +++ b/boost/gil/extension/io/bmp/detail/writer_backend.hpp @@ -0,0 +1,66 @@ +/* + Copyright 2012 Christian Henning + 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_BMP_DETAIL_WRITER_BACKEND_HPP +#define BOOST_GIL_EXTENSION_IO_BMP_DETAIL_WRITER_BACKEND_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file +/// \brief +/// \author Christian Henning \n +/// +/// \date 2012 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +#include <boost/gil/extension/io/bmp/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 + +/// +/// BMP Writer Backend +/// +template< typename Device > +struct writer_backend< Device + , bmp_tag + > +{ +public: + + typedef bmp_tag format_tag_t; + +public: + + writer_backend( const Device& io_dev + , const image_write_info< bmp_tag >& info + ) + : _io_dev( io_dev ) + , _info ( info ) + {} + +public: + + Device _io_dev; + + image_write_info< bmp_tag > _info; +}; + +#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) +#pragma warning(pop) +#endif + +} // namespace gil +} // namespace boost + +#endif diff --git a/boost/gil/extension/io/bmp/old.hpp b/boost/gil/extension/io/bmp/old.hpp new file mode 100644 index 0000000000..b265ca1960 --- /dev/null +++ b/boost/gil/extension/io/bmp/old.hpp @@ -0,0 +1,181 @@ +/* + Copyright 2008 Christian Henning + 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_BMP_OLD_HPP +#define BOOST_GIL_EXTENSION_IO_BMP_OLD_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file +/// \brief +/// \author Christian Henning \n +/// +/// \date 2008 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +#include <boost/gil/extension/io/bmp.hpp> + +namespace boost { namespace gil { + +/// \ingroup BMP_IO +/// \brief Returns the width and height of the BMP file at the specified location. +/// Throws std::ios_base::failure if the location does not correspond to a valid BMP file +template< typename String > +inline +point2< std::ptrdiff_t > bmp_read_dimensions( const String& filename ) +{ + typedef typename get_reader_backend< String + , bmp_tag + >::type backend_t; + + backend_t backend = read_image_info( filename + , bmp_tag() + ); + + return point2< std::ptrdiff_t >( backend._info._width + , backend._info._height + ); +} + + +/// \ingroup BMP_IO +/// \brief Loads the image specified by the given bmp image file name into the given view. +/// Triggers a compile assert if the view color space and channel depth are not supported by the BMP library or by the I/O extension. +/// Throws std::ios_base::failure if the file is not a valid BMP 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 bmp_read_view( const String& filename + , const View& view + ) +{ + read_view( filename + , view + , bmp_tag() + ); +} + +/// \ingroup BMP_IO +/// \brief Allocates a new image whose dimensions are determined by the given bmp 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 BMP library or by the I/O extension. +/// Throws std::ios_base::failure if the file is not a valid BMP 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 bmp_read_image( const String& filename + , Image& img + ) +{ + read_image( filename + , img + , bmp_tag() + ); +} + +/// \ingroup BMP_IO +/// \brief Loads and color-converts the image specified by the given bmp image file name into the given view. +/// Throws std::ios_base::failure if the file is not a valid BMP file, or if its dimensions don't match the ones of the view. +template< typename String + , typename View + , typename CC + > +inline +void bmp_read_and_convert_view( const String& filename + , const View& view + , CC cc + ) +{ + read_and_convert_view( filename + , view + , cc + , bmp_tag() + ); +} + +/// \ingroup BMP_IO +/// \brief Loads and color-converts the image specified by the given bmp image file name into the given view. +/// Throws std::ios_base::failure if the file is not a valid BMP file, or if its dimensions don't match the ones of the view. +template< typename String + , typename View + > +inline +void bmp_read_and_convert_view( const String& filename + , const View& view + ) +{ + read_and_convert_view( filename + , view + , bmp_tag() + ); +} + +/// \ingroup BMP_IO +/// \brief Allocates a new image whose dimensions are determined by the given bmp image file, loads and color-converts the pixels into it. +/// Throws std::ios_base::failure if the file is not a valid BMP file +template< typename String + , typename Image + , typename CC + > +inline +void bmp_read_and_convert_image( const String& filename + , Image& img + , CC cc + ) +{ + read_and_convert_image( filename + , img + , cc + , bmp_tag() + ); +} + +/// \ingroup BMP_IO +/// \brief Allocates a new image whose dimensions are determined by the given bmp image file, loads and color-converts the pixels into it. +/// Throws std::ios_base::failure if the file is not a valid BMP file +template< typename String + , typename Image + > +inline +void bmp_read_and_convert_image( const String filename + , Image& img + ) +{ + read_and_convert_image( filename + , img + , bmp_tag() + ); +} + + +/// \ingroup BMP_IO +/// \brief Saves the view to a bmp file specified by the given bmp image file name. +/// Triggers a compile assert if the view color space and channel depth are not supported by the BMP 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 bmp_write_view( const String& filename + , const View& view + ) +{ + write_view( filename + , view + , bmp_tag() + ); +} + +} // namespace gil +} // namespace boost + +#endif diff --git a/boost/gil/extension/io/bmp/read.hpp b/boost/gil/extension/io/bmp/read.hpp new file mode 100644 index 0000000000..e28c169bdf --- /dev/null +++ b/boost/gil/extension/io/bmp/read.hpp @@ -0,0 +1,43 @@ +/* + Copyright 2008 Christian Henning + 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_BMP_READ_HPP +#define BOOST_GIL_EXTENSION_IO_BMP_READ_HPP + +#define BOOST_GIL_EXTENSION_IO_BMP_READ_ENABLED + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file +/// \brief +/// \author Christian Henning \n +/// +/// \date 2008 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +#include <boost/gil/extension/io/bmp/tags.hpp> +#include <boost/gil/extension/io/bmp/detail/supported_types.hpp> +#include <boost/gil/extension/io/bmp/detail/read.hpp> +#include <boost/gil/extension/io/bmp/detail/scanline_read.hpp> + +#include <boost/gil/io/get_reader.hpp> +#include <boost/gil/io/make_backend.hpp> +#include <boost/gil/io/make_reader.hpp> +#include <boost/gil/io/make_dynamic_image_reader.hpp> +#include <boost/gil/io/make_scanline_reader.hpp> + +#include <boost/gil/io/read_image.hpp> +#include <boost/gil/io/read_view.hpp> +#include <boost/gil/io/read_image_info.hpp> +#include <boost/gil/io/read_and_convert_image.hpp> +#include <boost/gil/io/read_and_convert_view.hpp> + +#include <boost/gil/io/scanline_read_iterator.hpp> + +#endif diff --git a/boost/gil/extension/io/bmp/tags.hpp b/boost/gil/extension/io/bmp/tags.hpp new file mode 100644 index 0000000000..ec8c4a15f8 --- /dev/null +++ b/boost/gil/extension/io/bmp/tags.hpp @@ -0,0 +1,170 @@ +/* + Copyright 2008 Christian Henning + 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_BMP_TAGS_HPP +#define BOOST_GIL_EXTENSION_IO_BMP_TAGS_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file +/// \brief +/// \author Christian Henning \n +/// +/// \date 2008 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +#include <boost/gil/io/base.hpp> + +namespace boost { namespace gil { + +/// Defines bmp tag. +struct bmp_tag : format_tag {}; + + /// See http://en.wikipedia.org/wiki/BMP_file_format#BMP_File_Header for reference. + +/// Defines type for offset value. +struct bmp_offset : property_base< uint32_t > {}; + +/// Defines type for header sizes. +struct bmp_header_size : property_base< uint32_t > +{ + static const type _size = 14; /// Constant size for bmp file header size. + static const type _win32_info_size = 40; /// Constant size for win32 bmp info header size. + static const type _os2_info_size = 12; /// Constant size for os2 bmp info header size. +}; + +/// Defines type for image width property. +struct bmp_image_width : property_base< int32_t > {}; + +/// Defines type for image height property. +struct bmp_image_height : property_base< int32_t > {}; + +/// Defines type for bits per pixels property. +struct bmp_bits_per_pixel : property_base< uint16_t > {}; + +/// Defines type for compression property. +struct bmp_compression : property_base< uint32_t > +{ + static const type _rgb = 0; /// RGB without compression + static const type _rle8 = 1; /// 8 bit index with RLE compression + static const type _rle4 = 2; /// 4 bit index with RLE compression + static const type _bitfield = 3; /// 16 or 32 bit fields without compression +}; + +/// Defines type for image size property. +struct bmp_image_size : property_base< uint32_t > {}; + +/// Defines type for horizontal resolution property. +struct bmp_horizontal_resolution : property_base< int32_t > {}; + +/// Defines type for vertical resolution property. +struct bmp_vertical_resolution : property_base< int32_t > {}; + +/// Defines type for number of colors property. +struct bmp_num_colors : property_base< uint32_t > {}; + +/// Defines type for important number of colors property. +struct bmp_num_important_colors : property_base< uint32_t > {}; + +/// if height is negative then image is stored top-down instead of bottom-up. +struct bmp_top_down : property_base< bool > {}; + +static const uint32_t bmp_signature = 0x4D42; /// Constant signature for bmp file format. + +/// Read information for bmp images. +/// +/// The structure is returned when using read_image_info. +template<> +struct image_read_info< bmp_tag > +{ + /// Default contructor. + image_read_info< bmp_tag >() + : _top_down(false) + , _valid( false ) + {} + + /// The offset, i.e. starting address, of the byte where the bitmap data can be found. + bmp_offset::type _offset; + + /// The size of this header: + /// - 40 bytes for Windows V3 header + /// - 12 bytes for OS/2 V1 header + bmp_header_size::type _header_size; + + /// The bitmap width in pixels ( signed integer ). + bmp_image_width::type _width; + + /// The bitmap height in pixels ( signed integer ). + bmp_image_height::type _height; + + /// The number of bits per pixel, which is the color depth of the image. + /// Typical values are 1, 4, 8, 16, 24 and 32. + bmp_bits_per_pixel::type _bits_per_pixel; + + /// The compression method being used. See above for a list of possible values. + bmp_compression::type _compression; + + /// The image size. This is the size of the raw bitmap data (see below), + /// and should not be confused with the file size. + bmp_image_size::type _image_size; + + /// The horizontal resolution of the image. (pixel per meter, signed integer) + bmp_horizontal_resolution::type _horizontal_resolution; + + /// The vertical resolution of the image. (pixel per meter, signed integer) + bmp_vertical_resolution::type _vertical_resolution; + + /// The number of colors in the color palette, or 0 to default to 2^n - 1. + bmp_num_colors::type _num_colors; + + /// The number of important colors used, or 0 when every color is important; + /// generally ignored. + bmp_num_important_colors::type _num_important_colors; + + bmp_top_down::type _top_down; + + /// Used internaly to identify is the header has been read. + bool _valid; +}; + +/// Read settings for bmp images. +/// +/// The structure can be used for all read_xxx functions, except read_image_info. +template<> +struct image_read_settings< bmp_tag > : public image_read_settings_base +{ + /// Default constructor + image_read_settings() + : image_read_settings_base() + {} + + /// Constructor + /// \param top_left Top left coordinate for reading partial image. + /// \param dim Dimensions for reading partial image. + image_read_settings( const point_t& top_left + , const point_t& dim + ) + : image_read_settings_base( top_left + , dim + ) + {} +}; + +/// Write information for bmp images. +/// +/// The structure can be used for write_view() function. +template<> +struct image_write_info< bmp_tag > +{ +}; + +} // namespace gil +} // namespace boost + +#endif diff --git a/boost/gil/extension/io/bmp/write.hpp b/boost/gil/extension/io/bmp/write.hpp new file mode 100644 index 0000000000..634bf3bd89 --- /dev/null +++ b/boost/gil/extension/io/bmp/write.hpp @@ -0,0 +1,31 @@ +/* + Copyright 2008 Christian Henning + 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_BMP_WRITE_HPP +#define BOOST_GIL_EXTENSION_IO_BMP_WRITE_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file +/// \brief +/// \author Christian Henning \n +/// +/// \date 2008 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +#include <boost/gil/extension/io/bmp/tags.hpp> +#include <boost/gil/extension/io/bmp/detail/supported_types.hpp> +#include <boost/gil/extension/io/bmp/detail/write.hpp> + +#include <boost/gil/io/make_writer.hpp> +#include <boost/gil/io/make_dynamic_image_writer.hpp> + +#include <boost/gil/io/write_view.hpp> + +#endif diff --git a/boost/gil/extension/io/io_error.hpp b/boost/gil/extension/io/io_error.hpp deleted file mode 100644 index 5ea79c58f6..0000000000 --- a/boost/gil/extension/io/io_error.hpp +++ /dev/null @@ -1,51 +0,0 @@ -/* - Copyright 2005-2007 Adobe Systems Incorporated - - 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). - - See http://opensource.adobe.com/gil for most recent version including documentation. -*/ -/*************************************************************************************************/ - -#ifndef GIL_IO_ERROR_H -#define GIL_IO_ERROR_H - -/// \file -/// \brief Handle input-output errors -/// \author Lubomir Bourdev and Hailin Jin \n -/// Adobe Systems Incorporated -/// \date 2005-2007 \n Last updated on May 30, 2006 - -#include <ios> -#include "../../gil_config.hpp" -#include <boost/shared_ptr.hpp> - -namespace boost { namespace gil { - -inline void io_error(const char* descr) { throw std::ios_base::failure(descr); } -inline void io_error_if(bool expr, const char* descr="") { if (expr) io_error(descr); } - -namespace detail { - class file_mgr { - protected: - shared_ptr<FILE> _fp; - - struct null_deleter { void operator()(void const*) const {} }; - file_mgr(FILE* file) : _fp(file, null_deleter()) {} - - file_mgr(const char* filename, const char* flags) { - FILE* fp; - io_error_if((fp=fopen(filename,flags))==NULL, "file_mgr: failed to open file"); - _fp=shared_ptr<FILE>(fp,fclose); - } - - public: - FILE* get() { return _fp.get(); } - }; -} - -} } // namespace boost::gil - -#endif diff --git a/boost/gil/extension/io/jpeg.hpp b/boost/gil/extension/io/jpeg.hpp new file mode 100644 index 0000000000..8f4b5db410 --- /dev/null +++ b/boost/gil/extension/io/jpeg.hpp @@ -0,0 +1,25 @@ +/* + Copyright 2007-2008 Christian Henning + 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_JPEG_HPP +#define BOOST_GIL_EXTENSION_IO_JPEG_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file +/// \brief +/// \author Christian Henning, Andreas Pokorny \n +/// +/// \date 2007-2008 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +#include <boost/gil/extension/io/jpeg/read.hpp> +#include <boost/gil/extension/io/jpeg/write.hpp> + +#endif diff --git a/boost/gil/extension/io/jpeg/detail/base.hpp b/boost/gil/extension/io/jpeg/detail/base.hpp new file mode 100644 index 0000000000..551c4759d1 --- /dev/null +++ b/boost/gil/extension/io/jpeg/detail/base.hpp @@ -0,0 +1,46 @@ +/* + Copyright 2010 Christian Henning + 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_JPEG_DETAIL_BASE_HPP +#define BOOST_GIL_EXTENSION_IO_JPEG_DETAIL_BASE_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file +/// \brief +/// \author Christian Henning \n +/// +/// \date 2010 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// +#include <boost/gil/extension/io/jpeg/tags.hpp> + +namespace boost { namespace gil { + +#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) +#pragma warning(push) +#pragma warning(disable:4324) //structure was padded due to __declspec(align()) +#endif + +class jpeg_io_base +{ + +protected: + + jpeg_error_mgr _jerr; + jmp_buf _mark; +}; + +#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) +#pragma warning(pop) +#endif + +} // namespace gil +} // namespace boost + +#endif diff --git a/boost/gil/extension/io/jpeg/detail/is_allowed.hpp b/boost/gil/extension/io/jpeg/detail/is_allowed.hpp new file mode 100644 index 0000000000..cf8015492e --- /dev/null +++ b/boost/gil/extension/io/jpeg/detail/is_allowed.hpp @@ -0,0 +1,54 @@ +/* + Copyright 2009 Christian Henning + 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_JPEG_DETAIL_IS_ALLOWED_HPP +#define BOOST_GIL_EXTENSION_IO_JPEG_DETAIL_IS_ALLOWED_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file +/// \brief +/// \author Christian Henning \n +/// +/// \date 2008 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +namespace boost { namespace gil { namespace detail { + +template< typename View > +bool is_allowed( const image_read_info< jpeg_tag >& info + , mpl::true_ // is read_and_no_convert + ) +{ + if( info._color_space == JCS_YCbCr ) + { + // We read JCS_YCbCr files as rgb. + return ( is_read_supported< typename View::value_type + , jpeg_tag + >::_color_space == JCS_RGB ); + } + + return ( is_read_supported< typename View::value_type + , jpeg_tag + >::_color_space == info._color_space ); +} + +template< typename View > +bool is_allowed( const image_read_info< jpeg_tag >& /* info */ + , mpl::false_ // is read_and_convert + ) +{ + return true; +} + +} // namespace detail +} // namespace gil +} // namespace boost + +#endif diff --git a/boost/gil/extension/io/jpeg/detail/read.hpp b/boost/gil/extension/io/jpeg/detail/read.hpp new file mode 100644 index 0000000000..f3f5a8afef --- /dev/null +++ b/boost/gil/extension/io/jpeg/detail/read.hpp @@ -0,0 +1,331 @@ +/* + Copyright 2007-2012 Christian Henning, Andreas Pokorny, 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_JPEG_DETAIL_READ_HPP +#define BOOST_GIL_EXTENSION_IO_JPEG_DETAIL_READ_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file +/// \brief +/// \author Christian Henning, Andreas Pokorny, Lubomir Bourdev \n +/// +/// \date 2007-2012 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +#include <csetjmp> +#include <vector> +#include <boost/gil/extension/io/jpeg/tags.hpp> + +#include <boost/gil/io/base.hpp> +#include <boost/gil/io/conversion_policies.hpp> +#include <boost/gil/io/reader_base.hpp> +#include <boost/gil/io/device.hpp> +#include <boost/gil/io/typedefs.hpp> + +#include <boost/gil/extension/io/jpeg/detail/base.hpp> +#include <boost/gil/extension/io/jpeg/detail/is_allowed.hpp> + +namespace boost { namespace gil { + +#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) +#pragma warning(push) +#pragma warning(disable:4512) //assignment operator could not be generated +#pragma warning(disable:4611) //interaction between '_setjmp' and C++ object destruction is non-portable +#endif + +/// +/// JPEG Reader +/// +template< typename Device + , typename ConversionPolicy + > +class reader< Device + , jpeg_tag + , ConversionPolicy + > + : public reader_base< jpeg_tag + , ConversionPolicy + > + , public reader_backend< Device + , jpeg_tag + > +{ +private: + + typedef reader< Device + , jpeg_tag + , ConversionPolicy + > this_t; + + typedef typename ConversionPolicy::color_converter_type cc_t; + +public: + + typedef reader_backend< Device, jpeg_tag > backend_t; + +public: + + // + // Constructor + // + reader( const Device& io_dev + , const image_read_settings< jpeg_tag >& settings + ) + : reader_base< jpeg_tag + , ConversionPolicy + >() + + , backend_t( io_dev + , settings + ) + {} + + // + // Constructor + // + reader( const Device& io_dev + , const typename ConversionPolicy::color_converter_type& cc + , const image_read_settings< jpeg_tag >& settings + ) + : reader_base< jpeg_tag + , ConversionPolicy + >( cc ) + , backend_t( io_dev + , settings + ) + {} + + template<typename View> + void apply( const View& view ) + { + // Fire exception in case of error. + if( setjmp( this->_mark )) + { + this->raise_error(); + } + + this->get()->dct_method = this->_settings._dct_method; + + typedef typename is_same< ConversionPolicy + , detail::read_and_no_convert + >::type is_read_and_convert_t; + + io_error_if( !detail::is_allowed< View >( this->_info + , is_read_and_convert_t() + ) + , "Image types aren't compatible." + ); + + if( jpeg_start_decompress( this->get() ) == false ) + { + io_error( "Cannot start decompression." ); + } + + switch( this->_info._color_space ) + { + case JCS_GRAYSCALE: + { + this->_scanline_length = this->_info._width; + read_rows< gray8_pixel_t >( view ); + + break; + } + + case JCS_RGB: + //!\todo add Y'CbCr? We loose image quality when reading JCS_YCbCr as JCS_RGB + case JCS_YCbCr: + { + this->_scanline_length = this->_info._width * num_channels< rgb8_view_t >::value; + + read_rows< rgb8_pixel_t >( view ); + break; + } + + case JCS_CMYK: + //!\todo add Y'CbCrK? We loose image quality when reading JCS_YCCK as JCS_CMYK + case JCS_YCCK: + { + this->get()->out_color_space = JCS_CMYK; + this->_scanline_length = this->_info._width * num_channels< cmyk8_view_t >::value; + + read_rows< cmyk8_pixel_t >( view ); + + break; + } + default: { io_error( "Unsupported jpeg color space." ); } + } + + jpeg_finish_decompress ( this->get() ); + } + +private: + + template< typename ImagePixel + , typename View + > + void read_rows( const View& view ) + { + typedef std::vector<ImagePixel> buffer_t; + buffer_t buffer( this->_info._width ); + + // In case of an error we'll jump back to here and fire an exception. + // @todo Is the buffer above cleaned up when the exception is thrown? + // The strategy right now is to allocate necessary memory before + // the setjmp. + if( setjmp( this->_mark )) + { + this->raise_error(); + } + + + JSAMPLE *row_adr = reinterpret_cast< JSAMPLE* >( &buffer[0] ); + + //Skip scanlines if necessary. + for( int y = 0; y < this->_settings._top_left.y; ++y ) + { + io_error_if( jpeg_read_scanlines( this->get() + , &row_adr + , 1 + ) !=1 + , "jpeg_read_scanlines: fail to read JPEG file" + ); + } + + // Read data. + for( int y = 0; y < view.height(); ++y ) + { + io_error_if( jpeg_read_scanlines( this->get() + , &row_adr + , 1 + ) != 1 + , "jpeg_read_scanlines: fail to read JPEG file" + ); + + typename buffer_t::iterator beg = buffer.begin() + this->_settings._top_left.x; + typename buffer_t::iterator end = beg + this->_settings._dim.x; + + this->_cc_policy.read( beg + , end + , view.row_begin( y ) + ); + } + + //@todo: There might be a better way to do that. + while( this->get()->output_scanline < this->get()->image_height ) + { + io_error_if( jpeg_read_scanlines( this->get() + , &row_adr + , 1 + ) !=1 + , "jpeg_read_scanlines: fail to read JPEG file" + ); + } + + } +}; + +namespace detail { + +struct jpeg_type_format_checker +{ + jpeg_type_format_checker( jpeg_color_space::type color_space ) + : _color_space( color_space ) + {} + + template< typename Image > + bool apply() + { + return is_read_supported< typename get_pixel_type< typename Image::view_t >::type + , jpeg_tag + >::_color_space == _color_space; + } + +private: + + jpeg_color_space::type _color_space; +}; + +struct jpeg_read_is_supported +{ + template< typename View > + struct apply : public is_read_supported< typename get_pixel_type< View >::type + , jpeg_tag + > + {}; +}; + +} // namespace detail + +/// +/// JPEG Dynamic Reader +/// +template< typename Device > +class dynamic_image_reader< Device + , jpeg_tag + > + : public reader< Device + , jpeg_tag + , detail::read_and_no_convert + > +{ + typedef reader< Device + , jpeg_tag + , detail::read_and_no_convert + > parent_t; + +public: + + dynamic_image_reader( const Device& io_dev + , const image_read_settings< jpeg_tag >& settings + ) + : parent_t( io_dev + , settings + ) + {} + + template< typename Images > + void apply( any_image< Images >& images ) + { + detail::jpeg_type_format_checker format_checker( this->_info._color_space != JCS_YCbCr + ? this->_info._color_space + : JCS_RGB + ); + + 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::jpeg_read_is_supported + , parent_t + > op( this ); + + apply_operation( view( images ) + , op + ); + } + } +}; + +#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) +#pragma warning(pop) +#endif + +} // gil +} // boost + +#endif diff --git a/boost/gil/extension/io/jpeg/detail/reader_backend.hpp b/boost/gil/extension/io/jpeg/detail/reader_backend.hpp new file mode 100644 index 0000000000..71c446af4f --- /dev/null +++ b/boost/gil/extension/io/jpeg/detail/reader_backend.hpp @@ -0,0 +1,329 @@ +/* + Copyright 2012 Christian Henning + 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_JPEG_DETAIL_READER_BACKEND_HPP +#define BOOST_GIL_EXTENSION_IO_JPEG_DETAIL_READER_BACKEND_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file +/// \brief +/// \author Christian Henning \n +/// +/// \date 2012 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +#include <boost/gil/extension/io/jpeg/tags.hpp> + +#include <memory> + +namespace boost { namespace gil { + +#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) +#pragma warning(push) +#pragma warning(disable:4512) //assignment operator could not be generated +#pragma warning(disable:4611) //interaction between '_setjmp' and C++ object destruction is non-portable +#endif + +namespace detail { + +/// +/// Wrapper for libjpeg's decompress object. Implements value semantics. +/// +struct jpeg_decompress_wrapper +{ +protected: + + using jpeg_decompress_ptr_t = std::shared_ptr<jpeg_decompress_struct> ; + +protected: + + /// + /// Default Constructor + /// + jpeg_decompress_wrapper() + : _jpeg_decompress_ptr( new jpeg_decompress_struct() + , jpeg_decompress_deleter + ) + {} + + jpeg_decompress_struct* get() { return _jpeg_decompress_ptr.get(); } + const jpeg_decompress_struct* get() const { return _jpeg_decompress_ptr.get(); } + +private: + + static void jpeg_decompress_deleter( jpeg_decompress_struct* jpeg_decompress_ptr ) + { + if( jpeg_decompress_ptr ) + { + jpeg_destroy_decompress( jpeg_decompress_ptr ); + + delete jpeg_decompress_ptr; + jpeg_decompress_ptr = NULL; + } + } + +private: + + jpeg_decompress_ptr_t _jpeg_decompress_ptr; + +}; + +} // namespace detail + +/// +/// JPEG Backend +/// +template< typename Device > +struct reader_backend< Device + , jpeg_tag + > + : public jpeg_io_base + , public detail::jpeg_decompress_wrapper +{ +public: + + typedef jpeg_tag format_tag_t; + +public: + // + // Constructor + // + reader_backend( const Device& io_dev + , const image_read_settings< jpeg_tag >& settings + ) + : _io_dev( io_dev ) + , _settings( settings ) + , _info() + + , _scanline_length( 0 ) + { + get()->err = jpeg_std_error( &_jerr ); + get()->client_data = this; + + // Error exit handler: does not return to caller. + _jerr.error_exit = &reader_backend::error_exit; + + if( setjmp( _mark )) + { + raise_error(); + } + + _src._jsrc.bytes_in_buffer = 0; + _src._jsrc.next_input_byte = buffer; + _src._jsrc.init_source = reinterpret_cast< void(*) ( j_decompress_ptr )>( &reader_backend< Device, jpeg_tag >::init_device ); + _src._jsrc.fill_input_buffer = reinterpret_cast< boolean(*)( j_decompress_ptr )>( &reader_backend< Device, jpeg_tag >::fill_buffer ); + _src._jsrc.skip_input_data = reinterpret_cast< void(*) ( j_decompress_ptr + , long num_bytes + ) >( &reader_backend< Device, jpeg_tag >::skip_input_data ); + _src._jsrc.term_source = reinterpret_cast< void(*) ( j_decompress_ptr ) >( &reader_backend< Device, jpeg_tag >::close_device ); + _src._jsrc.resync_to_restart = jpeg_resync_to_restart; + _src._this = this; + + jpeg_create_decompress( get() ); + + get()->src = &_src._jsrc; + + jpeg_read_header( get() + , TRUE + ); + + io_error_if( get()->data_precision != 8 + , "Image file is not supported." + ); + + // + read_header(); + + // + if( _settings._dim.x == 0 ) + { + _settings._dim.x = _info._width; + } + + if( _settings._dim.y == 0 ) + { + _settings._dim.y = _info._height; + } + } + + /// Read image header. + void read_header() + { + _info._width = get()->image_width; + _info._height = get()->image_height; + _info._num_components = get()->num_components; + _info._color_space = get()->jpeg_color_space; + _info._data_precision = get()->data_precision; + + _info._density_unit = get()->density_unit; + _info._x_density = get()->X_density; + _info._y_density = get()->Y_density; + + // obtain real world dimensions + // taken from https://bitbucket.org/edd/jpegxx/src/ea2492a1a4a6/src/read.cpp#cl-62 + + jpeg_calc_output_dimensions( get() ); + + double units_conversion = 0; + if (get()->density_unit == 1) // dots per inch + { + units_conversion = 25.4; // millimeters in an inch + } + else if (get()->density_unit == 2) // dots per cm + { + units_conversion = 10; // millimeters in a centimeter + } + + _info._pixel_width_mm = get()->X_density ? (get()->output_width / double(get()->X_density)) * units_conversion : 0; + _info._pixel_height_mm = get()->Y_density ? (get()->output_height / double(get()->Y_density)) * units_conversion : 0; + } + + /// Return image read settings. + const image_read_settings< jpeg_tag >& get_settings() + { + return _settings; + } + + /// Return image header info. + const image_read_info< jpeg_tag >& get_info() + { + return _info; + } + + /// 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( (jpeg_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( (jpeg_image_height::type) img_dim.y < _info._height ) { io_error( "Supplied image is too small" ); } + } + } + +protected: + + // Taken from jerror.c + /* + * Error exit handler: must not return to caller. + * + * Applications may override this if they want to get control back after + * an error. Typically one would longjmp somewhere instead of exiting. + * The setjmp buffer can be made a private field within an expanded error + * handler object. Note that the info needed to generate an error message + * is stored in the error object, so you can generate the message now or + * later, at your convenience. + * You should make sure that the JPEG object is cleaned up (with jpeg_abort + * or jpeg_destroy) at some point. + */ + static void error_exit( j_common_ptr cinfo ) + { + reader_backend< Device, jpeg_tag >* mgr = reinterpret_cast< reader_backend< Device, jpeg_tag >* >( cinfo->client_data ); + + longjmp( mgr->_mark, 1 ); + } + + void raise_error() + { + // we clean up in the destructor + + io_error( "jpeg is invalid." ); + } + +private: + + // See jdatasrc.c for default implementation for the following static member functions. + + static void init_device( jpeg_decompress_struct* cinfo ) + { + gil_jpeg_source_mgr* src = reinterpret_cast< gil_jpeg_source_mgr* >( cinfo->src ); + src->_jsrc.bytes_in_buffer = 0; + src->_jsrc.next_input_byte = src->_this->buffer; + } + + static boolean fill_buffer( jpeg_decompress_struct* cinfo ) + { + gil_jpeg_source_mgr* src = reinterpret_cast< gil_jpeg_source_mgr* >( cinfo->src ); + size_t count = src->_this->_io_dev.read(src->_this->buffer, sizeof(src->_this->buffer) ); + + if( count <= 0 ) + { + // libjpeg does that: adding an EOF marker + src->_this->buffer[0] = (JOCTET) 0xFF; + src->_this->buffer[1] = (JOCTET) JPEG_EOI; + count = 2; + } + + src->_jsrc.next_input_byte = src->_this->buffer; + src->_jsrc.bytes_in_buffer = count; + + return TRUE; + } + + static void skip_input_data( jpeg_decompress_struct * cinfo, long num_bytes ) + { + gil_jpeg_source_mgr* src = reinterpret_cast< gil_jpeg_source_mgr* >( cinfo->src ); + + if( num_bytes > 0 ) + { + while( num_bytes > long( src->_jsrc.bytes_in_buffer )) + { + num_bytes -= (long) src->_jsrc.bytes_in_buffer; + fill_buffer( cinfo ); + } + + src->_jsrc.next_input_byte += num_bytes; + src->_jsrc.bytes_in_buffer -= num_bytes; + } + } + + static void close_device( jpeg_decompress_struct* ) {} + +public: + + Device _io_dev; + + image_read_settings< jpeg_tag > _settings; + image_read_info< jpeg_tag > _info; + + std::size_t _scanline_length; + + struct gil_jpeg_source_mgr + { + jpeg_source_mgr _jsrc; + reader_backend* _this; + }; + + gil_jpeg_source_mgr _src; + + // libjpeg default is 4096 - see jdatasrc.c + JOCTET buffer[4096]; +}; + +#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) +#pragma warning(pop) +#endif + +} // namespace gil +} // namespace boost + +#endif diff --git a/boost/gil/extension/io/jpeg/detail/scanline_read.hpp b/boost/gil/extension/io/jpeg/detail/scanline_read.hpp new file mode 100644 index 0000000000..ee33154c61 --- /dev/null +++ b/boost/gil/extension/io/jpeg/detail/scanline_read.hpp @@ -0,0 +1,163 @@ +/* + Copyright 2007-2012 Christian Henning, Andreas Pokorny, 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_JPEG_DETAIL_SCANLINE_READ_HPP +#define BOOST_GIL_EXTENSION_IO_JPEG_DETAIL_SCANLINE_READ_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file +/// \brief +/// \author Christian Henning, Andreas Pokorny, Lubomir Bourdev \n +/// +/// \date 2007-2012 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +#include <csetjmp> +#include <vector> + +#include <boost/gil/io/base.hpp> +#include <boost/gil/io/conversion_policies.hpp> +#include <boost/gil/io/reader_base.hpp> +#include <boost/gil/io/device.hpp> +#include <boost/gil/io/scanline_read_iterator.hpp> +#include <boost/gil/io/typedefs.hpp> + + +#include <boost/gil/extension/io/jpeg/detail/reader_backend.hpp> +#include <boost/gil/extension/io/jpeg/detail/base.hpp> +#include <boost/gil/extension/io/jpeg/detail/is_allowed.hpp> + +namespace boost { namespace gil { + +#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) +#pragma warning(push) +#pragma warning(disable:4611) //interaction between '_setjmp' and C++ object destruction is non-portable +#endif + +/// +/// JPEG Scanline Reader +/// +template< typename Device > +class scanline_reader< Device + , jpeg_tag + > + : public reader_backend< Device + , jpeg_tag + > +{ +public: + + typedef jpeg_tag tag_t; + typedef reader_backend < Device, tag_t > backend_t; + typedef scanline_reader< Device, tag_t > this_t; + typedef scanline_read_iterator< this_t > iterator_t; + +public: + scanline_reader( Device& device + , const image_read_settings< jpeg_tag >& settings + ) + : reader_backend< Device + , jpeg_tag + >( device + , settings + ) + { + initialize(); + } + + void read( byte_t* dst + , int + ) + { + // Fire exception in case of error. + if( setjmp( this->_mark )) { this->raise_error(); } + + // read data + read_scanline( dst ); + } + + /// Skip over a scanline. + void skip( byte_t* dst, int ) + { + // Fire exception in case of error. + if( setjmp( this->_mark )) { this->raise_error(); } + + // read data + read_scanline( dst ); + } + + iterator_t begin() { return iterator_t( *this ); } + iterator_t end() { return iterator_t( *this, this->_info._height ); } + +private: + + void initialize() + { + this->get()->dct_method = this->_settings._dct_method; + + io_error_if( jpeg_start_decompress( this->get() ) == false + , "Cannot start decompression." ); + + switch( this->_info._color_space ) + { + case JCS_GRAYSCALE: + { + this->_scanline_length = this->_info._width; + + break; + } + + case JCS_RGB: + //!\todo add Y'CbCr? We loose image quality when reading JCS_YCbCr as JCS_RGB + case JCS_YCbCr: + { + this->_scanline_length = this->_info._width * num_channels< rgb8_view_t >::value; + + break; + } + + + case JCS_CMYK: + //!\todo add Y'CbCrK? We loose image quality when reading JCS_YCCK as JCS_CMYK + case JCS_YCCK: + { + this->get()->out_color_space = JCS_CMYK; + this->_scanline_length = this->_info._width * num_channels< cmyk8_view_t >::value; + + break; + } + + default: { io_error( "Unsupported jpeg color space." ); } + } + } + + void read_scanline( byte_t* dst ) + { + JSAMPLE *row_adr = reinterpret_cast< JSAMPLE* >( dst ); + + // Read data. + io_error_if( jpeg_read_scanlines( this->get() + , &row_adr + , 1 + ) != 1 + , "jpeg_read_scanlines: fail to read JPEG file" + ); + + } +}; + +#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) +#pragma warning(pop) +#endif + +} // namespace gil +} // namespace boost + +#endif diff --git a/boost/gil/extension/io/jpeg/detail/supported_types.hpp b/boost/gil/extension/io/jpeg/detail/supported_types.hpp new file mode 100644 index 0000000000..209a99f857 --- /dev/null +++ b/boost/gil/extension/io/jpeg/detail/supported_types.hpp @@ -0,0 +1,121 @@ +/* + Copyright 2007-2008 Christian Henning, Andreas Pokorny, 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_JPEG_DETAIL_SUPPORTED_TYPES_HPP +#define BOOST_GIL_EXTENSION_IO_JPEG_DETAIL_SUPPORTED_TYPES_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file +/// \brief +/// \author Christian Henning, Andreas Pokorny, Lubomir Bourdev \n +/// +/// \date 2007-2008 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +#include <boost/mpl/not.hpp> +#include <boost/type_traits/is_same.hpp> + +#include <boost/gil/channel.hpp> +#include <boost/gil/color_base.hpp> + +namespace boost { namespace gil { namespace detail { + +// Read support + +template< jpeg_color_space::type ColorSpace > +struct jpeg_rw_support_base +{ + static const jpeg_color_space::type _color_space = ColorSpace; +}; + +template< typename Channel + , typename ColorSpace + > +struct jpeg_read_support : read_support_false + , jpeg_rw_support_base< JCS_UNKNOWN > {}; + +template<> +struct jpeg_read_support<uint8_t + , rgb_t + > : read_support_true + , jpeg_rw_support_base< JCS_RGB > {}; + +template<> +struct jpeg_read_support<uint8_t + , cmyk_t + > : read_support_true + , jpeg_rw_support_base< JCS_CMYK > {}; + +template<> +struct jpeg_read_support<uint8_t + , gray_t + > : read_support_true + , jpeg_rw_support_base< JCS_GRAYSCALE > {}; + +// Write support + +template< typename Channel + , typename ColorSpace + > +struct jpeg_write_support : write_support_false + , jpeg_rw_support_base< JCS_UNKNOWN > {}; + +template<> +struct jpeg_write_support<uint8_t + , gray_t + > : write_support_true + , jpeg_rw_support_base< JCS_GRAYSCALE > {}; + +template<> +struct jpeg_write_support<uint8_t + , rgb_t + > : write_support_true + , jpeg_rw_support_base< JCS_RGB > {}; + +template<> +struct jpeg_write_support<uint8_t + , cmyk_t + > : write_support_true + , jpeg_rw_support_base< JCS_CMYK > {}; + +} // namespace detail + +template< typename Pixel > +struct is_read_supported< Pixel + , jpeg_tag + > + : mpl::bool_< detail::jpeg_read_support< typename channel_type< Pixel >::type + , typename color_space_type< Pixel >::type + >::is_supported + > +{ + typedef detail::jpeg_read_support< typename channel_type< Pixel >::type + , typename color_space_type< Pixel >::type + > parent_t; + + static const typename jpeg_color_space::type _color_space = parent_t::_color_space; +}; + +template< typename Pixel > +struct is_write_supported< Pixel + , jpeg_tag + > + : mpl::bool_< detail::jpeg_write_support< typename channel_type< Pixel >::type + , typename color_space_type< Pixel >::type + >::is_supported + > +{}; + + +} // namespace gil +} // namespace boost + + +#endif diff --git a/boost/gil/extension/io/jpeg/detail/write.hpp b/boost/gil/extension/io/jpeg/detail/write.hpp new file mode 100644 index 0000000000..f9d2abfb57 --- /dev/null +++ b/boost/gil/extension/io/jpeg/detail/write.hpp @@ -0,0 +1,194 @@ +/* + Copyright 2007-2008 Christian Henning, Andreas Pokorny, 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_JPEG_DETAIL_WRITE_HPP +#define BOOST_GIL_EXTENSION_IO_JPEG_DETAIL_WRITE_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file +/// \brief +/// \author Christian Henning, Andreas Pokorny, Lubomir Bourdev \n +/// +/// \date 2007-2008 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +#include <vector> + +#include <boost/gil/io/base.hpp> +#include <boost/gil/io/device.hpp> + +#include <boost/gil/extension/io/jpeg/tags.hpp> + +#include <boost/gil/extension/io/jpeg/detail/supported_types.hpp> +#include <boost/gil/extension/io/jpeg/detail/writer_backend.hpp> + +namespace boost { namespace gil { + +#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) +#pragma warning(push) +#pragma warning(disable:4512) //assignment operator could not be generated +#pragma warning(disable:4611) //interaction between '_setjmp' and C++ object destruction is non-portable +#endif + +namespace detail { + +struct jpeg_write_is_supported +{ + template< typename View > + struct apply + : public is_write_supported< typename get_pixel_type< View >::type + , jpeg_tag + > + {}; +}; + +} // detail + +/// +/// JPEG Writer +/// +template< typename Device > +class writer< Device + , jpeg_tag + > + : public writer_backend< Device + , jpeg_tag + > +{ +public: + + typedef writer_backend< Device + , jpeg_tag + > backend_t; + +public: + + writer( const Device& io_dev + , const image_write_info< jpeg_tag >& info + ) + : backend_t( io_dev + , info + ) + {} + + template<typename View> + void apply( const View& view ) + { + write_rows( view ); + } + +private: + + template<typename View> + void write_rows( const View& view ) + { + std::vector< pixel< typename channel_type< View >::type + , layout<typename color_space_type< View >::type > + > + > row_buffer( view.width() ); + + // In case of an error we'll jump back to here and fire an exception. + // @todo Is the buffer above cleaned up when the exception is thrown? + // The strategy right now is to allocate necessary memory before + // the setjmp. + if( setjmp( this->_mark )) { this->raise_error(); } + + typedef typename channel_type< typename View::value_type >::type channel_t; + + this->get()->image_width = JDIMENSION( view.width() ); + this->get()->image_height = JDIMENSION( view.height() ); + this->get()->input_components = num_channels<View>::value; + this->get()->in_color_space = detail::jpeg_write_support< channel_t + , typename color_space_type< View >::type + >::_color_space; + + jpeg_set_defaults( this->get() ); + + jpeg_set_quality( this->get() + , this->_info._quality + , TRUE + ); + + // Needs to be done after jpeg_set_defaults() since it's overridding this value back to slow. + this->get()->dct_method = this->_info._dct_method; + + + // set the pixel dimensions + this->get()->density_unit = this->_info._density_unit; + this->get()->X_density = this->_info._x_density; + this->get()->Y_density = this->_info._y_density; + + // done reading header information + + jpeg_start_compress( this->get() + , TRUE + ); + + JSAMPLE* row_addr = reinterpret_cast< JSAMPLE* >( &row_buffer[0] ); + + for( int y =0; y != view.height(); ++ y ) + { + std::copy( view.row_begin( y ) + , view.row_end ( y ) + , row_buffer.begin() + ); + + jpeg_write_scanlines( this->get() + , &row_addr + , 1 + ); + } + } +}; + +/// +/// JPEG Dyamic Image Writer +/// +template< typename Device > +class dynamic_image_writer< Device + , jpeg_tag + > + : public writer< Device + , jpeg_tag + > +{ + typedef writer< Device + , jpeg_tag + > parent_t; + +public: + + dynamic_image_writer( const Device& io_dev + , const image_write_info< jpeg_tag >& info + ) + : parent_t( io_dev + , info + ) + {} + + template< typename Views > + void apply( const any_image_view< Views >& views ) + { + detail::dynamic_io_fnobj< detail::jpeg_write_is_supported + , parent_t + > op( this ); + + apply_operation( views, op ); + } +}; + +#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) +#pragma warning(pop) +#endif + +} // gil +} // boost + +#endif diff --git a/boost/gil/extension/io/jpeg/detail/writer_backend.hpp b/boost/gil/extension/io/jpeg/detail/writer_backend.hpp new file mode 100644 index 0000000000..962c46df69 --- /dev/null +++ b/boost/gil/extension/io/jpeg/detail/writer_backend.hpp @@ -0,0 +1,203 @@ +/* + Copyright 2012 Christian Henning + 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_JPEG_DETAIL_WRITER_BACKEND_HPP +#define BOOST_GIL_EXTENSION_IO_JPEG_DETAIL_WRITER_BACKEND_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file +/// \brief +/// \author Christian Henning \n +/// +/// \date 2012 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +#include <boost/gil/extension/io/jpeg/tags.hpp> +#include <boost/gil/extension/io/jpeg/detail/base.hpp> + +#include <memory> + +namespace boost { namespace gil { + +#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) +#pragma warning(push) +#pragma warning(disable:4512) //assignment operator could not be generated +#pragma warning(disable:4611) //interaction between '_setjmp' and C++ object destruction is non-portable +#endif + +namespace detail { + +/// +/// Wrapper for libjpeg's compress object. Implements value semantics. +/// +struct jpeg_compress_wrapper +{ +protected: + + using jpeg_compress_ptr_t = std::shared_ptr<jpeg_compress_struct>; + +protected: + + /// + /// Default Constructor + /// + jpeg_compress_wrapper() + : _jpeg_compress_ptr( new jpeg_compress_struct() + , jpeg_compress_deleter + ) + {} + + jpeg_compress_struct* get() { return _jpeg_compress_ptr.get(); } + const jpeg_compress_struct* get() const { return _jpeg_compress_ptr.get(); } + +private: + + static void jpeg_compress_deleter( jpeg_compress_struct* jpeg_compress_ptr ) + { + if( jpeg_compress_ptr ) + { + jpeg_destroy_compress( jpeg_compress_ptr ); + + delete jpeg_compress_ptr; + jpeg_compress_ptr = NULL; + } + } + +private: + + jpeg_compress_ptr_t _jpeg_compress_ptr; + +}; + +} // namespace detail + +/// +/// JPEG Writer Backend +/// +template< typename Device > +struct writer_backend< Device + , jpeg_tag + > + : public jpeg_io_base + , public detail::jpeg_compress_wrapper +{ +public: + + typedef jpeg_tag format_tag_t; + +public: + /// + /// Constructor + /// + writer_backend( const Device& io_dev + , const image_write_info< jpeg_tag >& info + ) + : _io_dev( io_dev ) + , _info( info ) + { + get()->err = jpeg_std_error( &_jerr ); + get()->client_data = this; + + // Error exit handler: does not return to caller. + _jerr.error_exit = &writer< Device, jpeg_tag >::error_exit; + + // Fire exception in case of error. + if( setjmp( _mark )) { raise_error(); } + + _dest._jdest.free_in_buffer = sizeof( buffer ); + _dest._jdest.next_output_byte = buffer; + _dest._jdest.init_destination = reinterpret_cast< void(*) ( j_compress_ptr ) >( &writer< Device, jpeg_tag >::init_device ); + _dest._jdest.empty_output_buffer = reinterpret_cast< boolean(*)( j_compress_ptr ) >( &writer< Device, jpeg_tag >::empty_buffer ); + _dest._jdest.term_destination = reinterpret_cast< void(*) ( j_compress_ptr ) >( &writer< Device, jpeg_tag >::close_device ); + _dest._this = this; + + jpeg_create_compress( get() ); + get()->dest = &_dest._jdest; + } + + ~writer_backend() + { + jpeg_finish_compress ( get() ); + jpeg_destroy_compress( get() ); + } + +protected: + + struct gil_jpeg_destination_mgr + { + jpeg_destination_mgr _jdest; + writer_backend< Device + , jpeg_tag + >* _this; + }; + + static void init_device( jpeg_compress_struct* cinfo ) + { + gil_jpeg_destination_mgr* dest = reinterpret_cast< gil_jpeg_destination_mgr* >( cinfo->dest ); + + dest->_jdest.free_in_buffer = sizeof( dest->_this->buffer ); + dest->_jdest.next_output_byte = dest->_this->buffer; + } + + static boolean empty_buffer( jpeg_compress_struct* cinfo ) + { + gil_jpeg_destination_mgr* dest = reinterpret_cast< gil_jpeg_destination_mgr* >( cinfo->dest ); + + dest->_this->_io_dev.write( dest->_this->buffer + , buffer_size + ); + + writer<Device,jpeg_tag>::init_device( cinfo ); + return static_cast<boolean>(TRUE); + } + + static void close_device( jpeg_compress_struct* cinfo ) + { + writer_backend< Device + , jpeg_tag + >::empty_buffer( cinfo ); + + gil_jpeg_destination_mgr* dest = reinterpret_cast< gil_jpeg_destination_mgr* >( cinfo->dest ); + + dest->_this->_io_dev.flush(); + } + + void raise_error() + { + io_error( "Cannot write jpeg file." ); + } + + static void error_exit( j_common_ptr cinfo ) + { + writer< Device, jpeg_tag >* mgr = reinterpret_cast< writer< Device, jpeg_tag >* >( cinfo->client_data ); + + longjmp( mgr->_mark, 1 ); + } + +public: + + Device _io_dev; + + image_write_info< jpeg_tag > _info; + + gil_jpeg_destination_mgr _dest; + + static const unsigned int buffer_size = 1024; + JOCTET buffer[buffer_size]; +}; + +#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) +#pragma warning(pop) +#endif + +} // namespace gil +} // namespace boost + +#endif diff --git a/boost/gil/extension/io/jpeg/old.hpp b/boost/gil/extension/io/jpeg/old.hpp new file mode 100644 index 0000000000..3b3dd2a89b --- /dev/null +++ b/boost/gil/extension/io/jpeg/old.hpp @@ -0,0 +1,182 @@ +/* + Copyright 2007-2008 Christian Henning + 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_JPEG_OLD_HPP +#define BOOST_GIL_EXTENSION_IO_JPEG_OLD_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file +/// \brief +/// \author Christian Henning \n +/// +/// \date 2007-2008 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +#include <boost/gil/extension/io/jpeg.hpp> + +namespace boost { namespace gil { + +/// \ingroup JPEG_IO +/// \brief Returns the width and height of the JPEG file at the specified location. +/// Throws std::ios_base::failure if the location does not correspond to a valid JPEG file +template< typename String > +inline +point2< std::ptrdiff_t > jpeg_read_dimensions( const String& filename ) +{ + typedef typename get_reader_backend< String + , jpeg_tag + >::type backend_t; + + backend_t backend = read_image_info( filename + , jpeg_tag() + ); + + return point2< std::ptrdiff_t >( backend._info._width + , backend._info._height + ); +} + + +/// \ingroup JPEG_IO +/// \brief Loads the image specified by the given jpeg image file name into the given view. +/// Triggers a compile assert if the view color space and channel depth are not supported by the JPEG library or by the I/O extension. +/// Throws std::ios_base::failure if the file is not a valid JPEG 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 jpeg_read_view( const String& filename + , const View& view + ) +{ + read_view( filename + , view + , jpeg_tag() + ); +} + +/// \ingroup JPEG_IO +/// \brief Allocates a new image whose dimensions are determined by the given jpeg 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 JPEG library or by the I/O extension. +/// Throws std::ios_base::failure if the file is not a valid JPEG 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 jpeg_read_image( const String& filename + , Image& img + ) +{ + read_image( filename + , img + , jpeg_tag() + ); +} + +/// \ingroup JPEG_IO +/// \brief Loads and color-converts the image specified by the given jpeg image file name into the given view. +/// Throws std::ios_base::failure if the file is not a valid JPEG file, or if its dimensions don't match the ones of the view. +template< typename String + , typename View + , typename CC + > +inline +void jpeg_read_and_convert_view( const String& filename + , const View& view + , CC cc + ) +{ + read_and_convert_view( filename + , view + , cc + , jpeg_tag() + ); +} + +/// \ingroup JPEG_IO +/// \brief Loads and color-converts the image specified by the given jpeg image file name into the given view. +/// Throws std::ios_base::failure if the file is not a valid JPEG file, or if its dimensions don't match the ones of the view. +template< typename String + , typename View + > +inline +void jpeg_read_and_convert_view( const String& filename + , const View& view + ) +{ + read_and_convert_view( filename + , view + , jpeg_tag() + ); +} + +/// \ingroup JPEG_IO +/// \brief Allocates a new image whose dimensions are determined by the given jpeg image file, loads and color-converts the pixels into it. +/// Throws std::ios_base::failure if the file is not a valid JPEG file +template< typename String + , typename Image + , typename CC + > +inline +void jpeg_read_and_convert_image( const String& filename + , Image& img + , CC cc + ) +{ + read_and_convert_image( filename + , img + , cc + , jpeg_tag() + ); +} + +/// \ingroup JPEG_IO +/// \brief Allocates a new image whose dimensions are determined by the given jpeg image file, loads and color-converts the pixels into it. +/// Throws std::ios_base::failure if the file is not a valid JPEG file +template< typename String + , typename Image + > +inline +void jpeg_read_and_convert_image( const String filename + , Image& img + ) +{ + read_and_convert_image( filename + , img + , jpeg_tag() + ); +} + + +/// \ingroup JPEG_IO +/// \brief Saves the view to a jpeg file specified by the given jpeg image file name. +/// Triggers a compile assert if the view color space and channel depth are not supported by the JPEG 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 jpeg_write_view( const String& filename + , const View& view + , int quality = jpeg_quality::default_value + ) +{ + write_view( filename + , view + , image_write_info< jpeg_tag >( quality ) + ); +} + +} // namespace gil +} // namespace boost + +#endif diff --git a/boost/gil/extension/io/jpeg/read.hpp b/boost/gil/extension/io/jpeg/read.hpp new file mode 100644 index 0000000000..ada31ff5bf --- /dev/null +++ b/boost/gil/extension/io/jpeg/read.hpp @@ -0,0 +1,43 @@ +/* + Copyright 2007-2008 Christian Henning + 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_JPEG_READ_HPP +#define BOOST_GIL_EXTENSION_IO_JPEG_READ_HPP + +#define BOOST_GIL_EXTENSION_IO_JPEG_READ_ENABLED + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file +/// \brief +/// \author Christian Henning, Andreas Pokorny \n +/// +/// \date 2007-2008 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +#include <boost/gil/extension/io/jpeg/tags.hpp> +#include <boost/gil/extension/io/jpeg/detail/supported_types.hpp> +#include <boost/gil/extension/io/jpeg/detail/read.hpp> +#include <boost/gil/extension/io/jpeg/detail/scanline_read.hpp> + +#include <boost/gil/io/get_reader.hpp> +#include <boost/gil/io/make_backend.hpp> +#include <boost/gil/io/make_reader.hpp> +#include <boost/gil/io/make_dynamic_image_reader.hpp> +#include <boost/gil/io/make_scanline_reader.hpp> + +#include <boost/gil/io/read_image.hpp> +#include <boost/gil/io/read_view.hpp> +#include <boost/gil/io/read_image_info.hpp> +#include <boost/gil/io/read_and_convert_image.hpp> +#include <boost/gil/io/read_and_convert_view.hpp> + +#include <boost/gil/io/scanline_read_iterator.hpp> + +#endif diff --git a/boost/gil/extension/io/jpeg/tags.hpp b/boost/gil/extension/io/jpeg/tags.hpp new file mode 100644 index 0000000000..047b5cbfd5 --- /dev/null +++ b/boost/gil/extension/io/jpeg/tags.hpp @@ -0,0 +1,244 @@ +/* + Copyright 2007-2012 Christian Henning, Andreas Pokorny, 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_JPEG_TAGS_HPP +#define BOOST_GIL_EXTENSION_IO_JPEG_TAGS_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file +/// \brief All supported jpeg tags by the gil io extension. +/// \author Christian Henning, Andreas Pokorny, Lubomir Bourdev \n +/// +/// \date 2007-2012 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +// taken from jpegxx - https://bitbucket.org/edd/jpegxx/src/ea2492a1a4a6/src/ijg_headers.hpp +#ifndef BOOST_GIL_EXTENSION_IO_JPEG_C_LIB_COMPILED_AS_CPLUSPLUS + extern "C" { +#else + // DONT_USE_EXTERN_C introduced in v7 of the IJG library. + // By default the v7 IJG headers check for __cplusplus being defined and + // wrap the content in an 'extern "C"' block if it's present. + // When DONT_USE_EXTERN_C is defined, this wrapping is not performed. + #ifndef DONT_USE_EXTERN_C + #define DONT_USE_EXTERN_C 1 + #endif +#endif + +//jpeglib doesn't know about FILE +#include <stdio.h> + +#include <jpeglib.h> +#include <jerror.h> + +#ifndef BOOST_GIL_EXTENSION_IO_JPEG_C_LIB_COMPILED_AS_CPLUSPLUS + } +#endif + +#include <boost/gil/io/base.hpp> + +namespace boost { namespace gil { + +/// Defines jpeg tag. +struct jpeg_tag : format_tag {}; + +/// see http://en.wikipedia.org/wiki/JPEG for reference + +/// Defines type for image width property. +struct jpeg_image_width : property_base< JDIMENSION > {}; + +/// Defines type for image height property. +struct jpeg_image_height : property_base< JDIMENSION > {}; + +/// Defines type for number of components property. +struct jpeg_num_components : property_base< int > {}; + +/// Defines type for color space property. +struct jpeg_color_space : property_base< J_COLOR_SPACE > {}; + +/// Defines type for jpeg quality property. +struct jpeg_quality : property_base< int > +{ + static const type default_value = 100; +}; + +/// Defines type for data precision property. +struct jpeg_data_precision : property_base< int > {}; + +/// JFIF code for pixel size units +struct jpeg_density_unit : property_base< UINT8 > +{ + static const type default_value = 0; +}; + +/// pixel density +struct jpeg_pixel_density : property_base< UINT16 > +{ + static const type default_value = 0; +}; + +/// Defines type for dct ( discrete cosine transformation ) method property. +struct jpeg_dct_method : property_base< J_DCT_METHOD > +{ + static const type slow = JDCT_ISLOW; + static const type fast = JDCT_IFAST; + static const type floating_pt = JDCT_FLOAT; + static const type fastest = JDCT_FASTEST; + + static const type default_value = slow; +}; + +/// Read information for jpeg images. +/// +/// The structure is returned when using read_image_info. +template<> +struct image_read_info< jpeg_tag > +{ + image_read_info() + : _width ( 0 ) + , _height( 0 ) + + , _num_components( 0 ) + + , _color_space( J_COLOR_SPACE( 0 )) + + , _data_precision( 0 ) + + , _density_unit ( 0 ) + , _x_density ( 0 ) + , _y_density ( 0 ) + + , _pixel_width_mm ( 0.0 ) + , _pixel_height_mm( 0.0 ) + {} + + /// The image width. + jpeg_image_width::type _width; + + /// The image height. + jpeg_image_height::type _height; + + /// The number of channels. + jpeg_num_components::type _num_components; + + /// The color space. + jpeg_color_space::type _color_space; + + /// The width of channel. + /// I believe this number is always 8 in the case libjpeg is built with 8. + /// see: http://www.asmail.be/msg0055405033.html + jpeg_data_precision::type _data_precision; + + /// Density conversion unit. + jpeg_density_unit::type _density_unit; + jpeg_pixel_density::type _x_density; + jpeg_pixel_density::type _y_density; + + /// Real-world dimensions + double _pixel_width_mm; + double _pixel_height_mm; +}; + +/// Read settings for jpeg images. +/// +/// The structure can be used for all read_xxx functions, except read_image_info. +template<> +struct image_read_settings< jpeg_tag > : public image_read_settings_base +{ + /// Default constructor + image_read_settings<jpeg_tag>() + : image_read_settings_base() + , _dct_method( jpeg_dct_method::default_value ) + {} + + /// Constructor + /// \param top_left Top left coordinate for reading partial image. + /// \param dim Dimensions for reading partial image. + /// \param dct_method Specifies dct method. + image_read_settings( const point_t& top_left + , const point_t& dim + , jpeg_dct_method::type dct_method = jpeg_dct_method::default_value + ) + : image_read_settings_base( top_left + , dim + ) + , _dct_method( dct_method ) + {} + + /// The dct ( discrete cosine transformation ) method. + jpeg_dct_method::type _dct_method; +}; + +/// Write information for jpeg images. +/// +/// The structure can be used for write_view() function. +template<> +struct image_write_info< jpeg_tag > +{ + /// Constructor + /// \param quality Defines the jpeg quality. + /// \param dct_method Defines the DCT method. + /// \param density_unit Defines the density unit. + /// \param x_density Defines the x density. + /// \param y_density Defines the y density. + image_write_info( const jpeg_quality::type quality = jpeg_quality::default_value + , const jpeg_dct_method::type dct_method = jpeg_dct_method::default_value + , const jpeg_density_unit::type density_unit = jpeg_density_unit::default_value + , const jpeg_pixel_density::type x_density = jpeg_pixel_density::default_value + , const jpeg_pixel_density::type y_density = jpeg_pixel_density::default_value + ) + : _quality ( quality ) + , _dct_method( dct_method ) + + , _density_unit( density_unit ) + , _x_density ( x_density ) + , _y_density ( y_density ) + {} + + /// The jpeg quality. + jpeg_quality::type _quality; + + /// The dct ( discrete cosine transformation ) method. + jpeg_dct_method::type _dct_method; + + /// Density conversion unit. + jpeg_density_unit::type _density_unit; + + /// Pixel density dimensions. + jpeg_pixel_density::type _x_density; + jpeg_pixel_density::type _y_density; + + /// Sets the pixel dimensions. + void set_pixel_dimensions( int image_width // in pixels + , int image_height // in pixels + , double pixel_width // in mm + , double pixel_height // in mm + ) + { + _density_unit = 2; // dots per cm + + _x_density = round( image_width / ( pixel_width / 10 )); + _y_density = round( image_height / ( pixel_height / 10 )); + } + +private: + + UINT16 round( double d ) + { + return static_cast< UINT16 >( d + 0.5 ); + } + +}; + + +} // namespace gil +} // namespace boost + +#endif diff --git a/boost/gil/extension/io/jpeg/write.hpp b/boost/gil/extension/io/jpeg/write.hpp new file mode 100644 index 0000000000..e04967b0ec --- /dev/null +++ b/boost/gil/extension/io/jpeg/write.hpp @@ -0,0 +1,31 @@ +/* + Copyright 2007-2008 Christian Henning + 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_JPEG_WRITE_HPP +#define BOOST_GIL_EXTENSION_IO_JPEG_WRITE_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file +/// \brief +/// \author Christian Henning \n +/// +/// \date 2007-2008 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +#include <boost/gil/extension/io/jpeg/tags.hpp> +#include <boost/gil/extension/io/jpeg/detail/supported_types.hpp> +#include <boost/gil/extension/io/jpeg/detail/write.hpp> + +#include <boost/gil/io/make_writer.hpp> +#include <boost/gil/io/make_dynamic_image_writer.hpp> + +#include <boost/gil/io/write_view.hpp> + +#endif diff --git a/boost/gil/extension/io/jpeg_dynamic_io.hpp b/boost/gil/extension/io/jpeg_dynamic_io.hpp deleted file mode 100644 index b1108fe8fa..0000000000 --- a/boost/gil/extension/io/jpeg_dynamic_io.hpp +++ /dev/null @@ -1,130 +0,0 @@ -/* - Copyright 2005-2007 Adobe Systems Incorporated - - 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). - - See http://opensource.adobe.com/gil for most recent version including documentation. -*/ - -/*************************************************************************************************/ - -#ifndef GIL_JPEG_DYNAMIC_IO_H -#define GIL_JPEG_DYNAMIC_IO_H - -/// \file -/// \brief Support for reading and writing JPEG files -/// Requires libjpeg -/// -/// \author Hailin Jin and Lubomir Bourdev \n -/// Adobe Systems Incorporated -/// \date 2005-2007 \n Last updated June 10, 2006 - -#include <stdio.h> -#include <string> -#include <boost/mpl/bool.hpp> -#include <boost/shared_ptr.hpp> -#include "../dynamic_image/dynamic_image_all.hpp" -#include "io_error.hpp" - -#include "jpeg_io.hpp" -#include "jpeg_io_private.hpp" -#include "dynamic_io.hpp" - -namespace boost { namespace gil { - -namespace detail { - -struct jpeg_write_is_supported { - template<typename View> struct apply - : public mpl::bool_<jpeg_write_support<View>::is_supported> {}; -}; - -class jpeg_writer_dynamic : public jpeg_writer { - int _quality; -public: - jpeg_writer_dynamic(FILE* file, int quality=100) : jpeg_writer(file) , _quality(quality) {} - jpeg_writer_dynamic(const char* filename, int quality=100) : jpeg_writer(filename), _quality(quality) {} - - template <typename Views> - void write_view(const any_image_view<Views>& runtime_view) { - dynamic_io_fnobj<jpeg_write_is_supported, jpeg_writer> op(this); - apply_operation(runtime_view,op); - } -}; - -class jpeg_type_format_checker { - J_COLOR_SPACE _color_type; -public: - jpeg_type_format_checker(J_COLOR_SPACE color_type_in) : - _color_type(color_type_in) {} - template <typename Image> - bool apply() { - return jpeg_read_support<typename Image::view_t>::color_type==_color_type; - } -}; - -struct jpeg_read_is_supported { - template<typename View> struct apply - : public mpl::bool_<jpeg_read_support<View>::is_supported> {}; -}; - -class jpeg_reader_dynamic : public jpeg_reader { -public: - jpeg_reader_dynamic(FILE* file) : jpeg_reader(file) {} - jpeg_reader_dynamic(const char* filename) : jpeg_reader(filename){} - - template <typename Images> - void read_image(any_image<Images>& im) { - if (!construct_matched(im,detail::jpeg_type_format_checker(_cinfo.out_color_space))) { - io_error("jpeg_reader_dynamic::read_image(): no matching image type between those of the given any_image and that of the file"); - } else { - im.recreate(get_dimensions()); - dynamic_io_fnobj<jpeg_read_is_supported, jpeg_reader> op(this); - apply_operation(view(im),op); - } - } -}; - -} // namespace detail - - -/// \ingroup JPEG_IO -/// \brief reads a JPEG image into a run-time instantiated image -/// Opens the given JPEG file name, selects the first type in Images whose color space and channel are compatible to those of the image file -/// and creates a new image of that type with the dimensions specified by the image file. -/// Throws std::ios_base::failure if none of the types in Images are compatible with the type on disk. -template <typename Images> -inline void jpeg_read_image(const char* filename,any_image<Images>& im) { - detail::jpeg_reader_dynamic m(filename); - m.read_image(im); -} - -/// \ingroup JPEG_IO -/// \brief reads a JPEG image into a run-time instantiated image -template <typename Images> -inline void jpeg_read_image(const std::string& filename,any_image<Images>& im) { - jpeg_read_image(filename.c_str(),im); -} - -/// \ingroup JPEG_IO -/// \brief Saves the currently instantiated view to a jpeg file specified by the given jpeg image file name. -/// Throws std::ios_base::failure if the currently instantiated view type is not supported for writing by the I/O extension -/// or if it fails to create the file. -template <typename Views> -inline void jpeg_write_view(const char* filename,const any_image_view<Views>& runtime_view) { - detail::jpeg_writer_dynamic m(filename); - m.write_view(runtime_view); -} - -/// \ingroup JPEG_IO -/// \brief Saves the currently instantiated view to a jpeg file specified by the given jpeg image file name. -template <typename Views> -inline void jpeg_write_view(const std::string& filename,const any_image_view<Views>& runtime_view) { - jpeg_write_view(filename.c_str(),runtime_view); -} - -} } // namespace boost::gil - -#endif diff --git a/boost/gil/extension/io/jpeg_io.hpp b/boost/gil/extension/io/jpeg_io.hpp deleted file mode 100644 index b9adc02339..0000000000 --- a/boost/gil/extension/io/jpeg_io.hpp +++ /dev/null @@ -1,202 +0,0 @@ -/* - Copyright 2005-2007 Adobe Systems Incorporated - - 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). - - See http://opensource.adobe.com/gil for most recent version including documentation. -*/ - -/*************************************************************************************************/ - -#ifndef GIL_JPEG_IO_H -#define GIL_JPEG_IO_H - -/// \file -/// \brief Support for reading and writing JPEG files -/// Requires libjpeg -/// \author Hailin Jin and Lubomir Bourdev \n -/// Adobe Systems Incorporated -/// \date 2005-2007 \n Last updated September 24, 2006 - -#include <cstdio> -#include <algorithm> -#include <string> -#include <boost/static_assert.hpp> -#include <boost/shared_ptr.hpp> -extern "C" { -#include <jpeglib.h> -} -#include "io_error.hpp" -#include "jpeg_io_private.hpp" - -namespace boost { namespace gil { - -/// \ingroup JPEG_IO -/// \brief Determines whether the given view type is supported for reading -template <typename View> -struct jpeg_read_support { - BOOST_STATIC_CONSTANT(bool,is_supported= - (detail::jpeg_read_support_private<typename channel_type<View>::type, - typename color_space_type<View>::type>::is_supported)); - BOOST_STATIC_CONSTANT(J_COLOR_SPACE,color_type= - (detail::jpeg_read_support_private<typename channel_type<View>::type, - typename color_space_type<View>::type>::color_type)); - BOOST_STATIC_CONSTANT(bool, value=is_supported); -}; - -/// \ingroup JPEG_IO -/// \brief Returns the width and height of the JPEG file at the specified location. -/// Throws std::ios_base::failure if the location does not correspond to a valid JPEG file -inline point2<std::ptrdiff_t> jpeg_read_dimensions(const char* filename) { - detail::jpeg_reader m(filename); - return m.get_dimensions(); -} - -/// \ingroup JPEG_IO -/// \brief Returns the width and height of the JPEG file at the specified location. -/// Throws std::ios_base::failure if the location does not correspond to a valid JPEG file -inline point2<std::ptrdiff_t> jpeg_read_dimensions(const std::string& filename) { - return jpeg_read_dimensions(filename.c_str()); -} - -/// \ingroup JPEG_IO -/// \brief Loads the image specified by the given jpeg image file name into the given view. -/// Triggers a compile assert if the view color space and channel depth are not supported by the JPEG library or by the I/O extension. -/// Throws std::ios_base::failure if the file is not a valid JPEG 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 View> -inline void jpeg_read_view(const char* filename,const View& view) { - BOOST_STATIC_ASSERT(jpeg_read_support<View>::is_supported); - - detail::jpeg_reader m(filename); - m.apply(view); -} - -/// \ingroup JPEG_IO -/// \brief Loads the image specified by the given jpeg image file name into the given view. -template <typename View> -inline void jpeg_read_view(const std::string& filename,const View& view) { - jpeg_read_view(filename.c_str(),view); -} - -/// \ingroup JPEG_IO -/// \brief Allocates a new image whose dimensions are determined by the given jpeg 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 JPEG library or by the I/O extension. -/// Throws std::ios_base::failure if the file is not a valid JPEG file, or if its color space or channel depth are not -/// compatible with the ones specified by Image -template <typename Image> -inline void jpeg_read_image(const char* filename,Image& im) { - BOOST_STATIC_ASSERT(jpeg_read_support<typename Image::view_t>::is_supported); - - detail::jpeg_reader m(filename); - m.read_image(im); -} - -/// \ingroup JPEG_IO -/// \brief Allocates a new image whose dimensions are determined by the given jpeg image file, and loads the pixels into it. -template <typename Image> -inline void jpeg_read_image(const std::string& filename,Image& im) { - jpeg_read_image(filename.c_str(),im); -} - -/// \ingroup JPEG_IO -/// \brief Loads and color-converts the image specified by the given jpeg image file name into the given view. -/// Throws std::ios_base::failure if the file is not a valid JPEG file, or if its dimensions don't match the ones of the view. -template <typename View,typename CC> -inline void jpeg_read_and_convert_view(const char* filename,const View& view,CC cc) { - detail::jpeg_reader_color_convert<CC> m(filename,cc); - m.apply(view); -} - -/// \ingroup JPEG_IO -/// \brief Loads and color-converts the image specified by the given jpeg image file name into the given view. -/// Throws std::ios_base::failure if the file is not a valid JPEG file, or if its dimensions don't match the ones of the view. -template <typename View> -inline void jpeg_read_and_convert_view(const char* filename,const View& view) { - detail::jpeg_reader_color_convert<default_color_converter> m(filename,default_color_converter()); - m.apply(view); -} - -/// \ingroup JPEG_IO -/// \brief Loads and color-converts the image specified by the given jpeg image file name into the given view. -template <typename View,typename CC> -inline void jpeg_read_and_convert_view(const std::string& filename,const View& view,CC cc) { - jpeg_read_and_convert_view(filename.c_str(),view); -} - -/// \ingroup JPEG_IO -/// \brief Loads and color-converts the image specified by the given jpeg image file name into the given view. -template <typename View> -inline void jpeg_read_and_convert_view(const std::string& filename,const View& view) { - jpeg_read_and_convert_view(filename.c_str(),view); -} - -/// \ingroup JPEG_IO -/// \brief Allocates a new image whose dimensions are determined by the given jpeg image file, loads and color-converts the pixels into it. -/// Throws std::ios_base::failure if the file is not a valid JPEG file -template <typename Image,typename CC> -inline void jpeg_read_and_convert_image(const char* filename,Image& im,CC cc) { - detail::jpeg_reader_color_convert<CC> m(filename,cc); - m.read_image(im); -} - -/// \ingroup JPEG_IO -/// \brief Allocates a new image whose dimensions are determined by the given jpeg image file, loads and color-converts the pixels into it. -/// Throws std::ios_base::failure if the file is not a valid JPEG file -template <typename Image> -inline void jpeg_read_and_convert_image(const char* filename,Image& im) { - detail::jpeg_reader_color_convert<default_color_converter> m(filename,default_color_converter()); - m.read_image(im); -} - -/// \ingroup JPEG_IO -/// \brief Allocates a new image whose dimensions are determined by the given jpeg image file, loads and color-converts the pixels into it. -template <typename Image,typename CC> -inline void jpeg_read_and_convert_image(const std::string& filename,Image& im,CC cc) { - jpeg_read_and_convert_image(filename.c_str(),im); -} - -/// \ingroup JPEG_IO -/// \brief Allocates a new image whose dimensions are determined by the given jpeg image file, loads and color-converts the pixels into it. -template <typename Image> -inline void jpeg_read_and_convert_image(const std::string& filename,Image& im) { - jpeg_read_and_convert_image(filename.c_str(),im); -} - -/// \ingroup JPEG_IO -/// \brief Determines whether the given view type is supported for writing -template <typename View> -struct jpeg_write_support { - BOOST_STATIC_CONSTANT(bool,is_supported= - (detail::jpeg_write_support_private<typename channel_type<View>::type, - typename color_space_type<View>::type>::is_supported)); - BOOST_STATIC_CONSTANT(J_COLOR_SPACE,color_type= - (detail::jpeg_write_support_private<typename channel_type<View>::type, - typename color_space_type<View>::type>::color_type)); - BOOST_STATIC_CONSTANT(bool, value=is_supported); -}; - -/// \ingroup JPEG_IO -/// \brief Saves the view to a jpeg file specified by the given jpeg image file name. -/// Triggers a compile assert if the view color space and channel depth are not supported by the JPEG library or by the I/O extension. -/// Throws std::ios_base::failure if it fails to create the file. -template <typename View> -inline void jpeg_write_view(const char* filename,const View& view,int quality=100) { - BOOST_STATIC_ASSERT(jpeg_write_support<View>::is_supported); - - detail::jpeg_writer m(filename); - m.apply(view,quality); -} - -/// \ingroup JPEG_IO -/// \brief Saves the view to a jpeg file specified by the given jpeg image file name. -template <typename View> -inline void jpeg_write_view(const std::string& filename,const View& view,int quality=100) { - jpeg_write_view(filename.c_str(),view,quality); -} - -} } // namespace boost::gil - -#endif diff --git a/boost/gil/extension/io/jpeg_io_private.hpp b/boost/gil/extension/io/jpeg_io_private.hpp deleted file mode 100644 index 4b3e7bdd5b..0000000000 --- a/boost/gil/extension/io/jpeg_io_private.hpp +++ /dev/null @@ -1,226 +0,0 @@ -/* - Copyright 2005-2007 Adobe Systems Incorporated - - 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). - - See http://opensource.adobe.com/gil for most recent version including documentation. -*/ - -/*************************************************************************************************/ - -#ifndef GIL_JPEG_IO_PRIVATE_H -#define GIL_JPEG_IO_PRIVATE_H - -/// \file -/// \brief Internal support for reading and writing JPEG files -/// \author Hailin Jin and Lubomir Bourdev \n -/// Adobe Systems Incorporated -/// \date 2005-2007 \n Last updated September 24, 2006 - -#include <stdio.h> -#include <boost/static_assert.hpp> -#include <vector> -#include "../../gil_all.hpp" -#include "io_error.hpp" -#include <jpeglib.h> - -namespace boost { namespace gil { - -namespace detail { - -// lbourdev: What is the advantage of having channel and colorspace together? Are there cases where they are interrelated? - -template <typename Channel,typename ColorSpace> -struct jpeg_read_support_private { - BOOST_STATIC_CONSTANT(bool,is_supported=false); - BOOST_STATIC_CONSTANT(J_COLOR_SPACE,color_type=JCS_UNKNOWN); -}; -template <> -struct jpeg_read_support_private<bits8,gray_t> { - BOOST_STATIC_ASSERT(BITS_IN_JSAMPLE==8); - BOOST_STATIC_CONSTANT(bool,is_supported=true); - BOOST_STATIC_CONSTANT(J_COLOR_SPACE,color_type=JCS_GRAYSCALE); -}; -template <> -struct jpeg_read_support_private<bits8,rgb_t> { - BOOST_STATIC_ASSERT(BITS_IN_JSAMPLE==8); - BOOST_STATIC_CONSTANT(bool,is_supported=true); - BOOST_STATIC_CONSTANT(J_COLOR_SPACE,color_type=JCS_RGB); -}; -template <> -struct jpeg_read_support_private<bits8,cmyk_t> { - BOOST_STATIC_ASSERT(BITS_IN_JSAMPLE==8); - BOOST_STATIC_CONSTANT(bool,is_supported=true); - BOOST_STATIC_CONSTANT(J_COLOR_SPACE,color_type=JCS_CMYK); -}; -template <typename Channel,typename ColorSpace> -struct jpeg_write_support_private { - BOOST_STATIC_CONSTANT(bool,is_supported=false); - BOOST_STATIC_CONSTANT(J_COLOR_SPACE,color_type=JCS_UNKNOWN); -}; -template <> -struct jpeg_write_support_private<bits8,gray_t> { - BOOST_STATIC_ASSERT(BITS_IN_JSAMPLE==8); - BOOST_STATIC_CONSTANT(bool,is_supported=true); - BOOST_STATIC_CONSTANT(J_COLOR_SPACE,color_type=JCS_GRAYSCALE); -}; -template <> -struct jpeg_write_support_private<bits8,rgb_t> { - BOOST_STATIC_ASSERT(BITS_IN_JSAMPLE==8); - BOOST_STATIC_CONSTANT(bool,is_supported=true); - BOOST_STATIC_CONSTANT(J_COLOR_SPACE,color_type=JCS_RGB); -}; -template <> -struct jpeg_write_support_private<bits8,cmyk_t> { - BOOST_STATIC_ASSERT(BITS_IN_JSAMPLE==8); - BOOST_STATIC_CONSTANT(bool,is_supported=true); - BOOST_STATIC_CONSTANT(J_COLOR_SPACE,color_type=JCS_CMYK); -}; - - -class jpeg_reader : public file_mgr { -protected: - jpeg_decompress_struct _cinfo; - jpeg_error_mgr _jerr; - - void init() { - _cinfo.err=jpeg_std_error(&_jerr); - jpeg_create_decompress(&_cinfo); - jpeg_stdio_src(&_cinfo,_fp.get()); - jpeg_read_header(&_cinfo,TRUE); - } -public: - jpeg_reader(FILE* file) : file_mgr(file) { init(); } - jpeg_reader(const char* filename) : file_mgr(filename, "rb") { init(); } - - ~jpeg_reader() { jpeg_destroy_decompress(&_cinfo); } - - template <typename View> - void apply(const View& view) { - jpeg_start_decompress(&_cinfo); // lbourdev: Can this return an error? You need to check and throw. Check all other library methods that can return an error state... - io_error_if(_cinfo.data_precision!=8,"jpeg_reader::apply(): this image file is not supported"); - io_error_if(_cinfo.out_color_space!=jpeg_read_support_private<typename channel_type<View>::type, - typename color_space_type<View>::type>::color_type, - "jpeg_reader::apply(): input view type does not match the image file"); - io_error_if(view.dimensions() != get_dimensions(), "jpeg_reader::apply(): input view dimensions do not match the image file"); - std::vector<pixel<bits8,layout<typename color_space_type<View>::type> > > row(view.width()); - JSAMPLE* row_address=(JSAMPLE*)&row.front(); - for(int y=0;y<view.height();++y) { - io_error_if(jpeg_read_scanlines(&_cinfo,(JSAMPARRAY)&row_address,1)!=1, - "jpeg_reader::apply(): fail to read JPEG file"); - std::copy(row.begin(),row.end(),view.row_begin(y)); - } - jpeg_finish_decompress(&_cinfo); - } - - template <typename Image> - void read_image(Image& im) { - im.recreate(get_dimensions()); - apply(view(im)); - } - - point2<std::ptrdiff_t> get_dimensions() const { - return point2<std::ptrdiff_t>(_cinfo.image_width,_cinfo.image_height); - } -}; - -// This code will be simplified... -template <typename CC> -class jpeg_reader_color_convert : public jpeg_reader { -private: - CC _cc; -public: - jpeg_reader_color_convert(FILE* file,CC cc_in) : jpeg_reader(file),_cc(cc_in) {} - jpeg_reader_color_convert(FILE* file) : jpeg_reader(file) {} - jpeg_reader_color_convert(const char* filename,CC cc_in) : jpeg_reader(filename),_cc(cc_in) {} - jpeg_reader_color_convert(const char* filename) : jpeg_reader(filename) {} - template <typename View> - void apply(const View& view) { - jpeg_start_decompress(&_cinfo); // lbourdev: Can this return an error? You need to check and throw. Check all other library methods that can return an error state... - io_error_if(_cinfo.data_precision!=8,"jpeg_reader_color_covert::apply(): this image file is not supported"); - io_error_if(view.dimensions() != get_dimensions(), "jpeg_reader_color_covert::apply(): input view dimensions don't match the image file"); - switch (_cinfo.out_color_space) { - case JCS_GRAYSCALE: { - std::vector<gray8_pixel_t> row(view.width()); - JSAMPLE* row_address=(JSAMPLE*)&row.front(); - for(int y=0;y<view.height();++y) { - io_error_if(jpeg_read_scanlines(&_cinfo,(JSAMPARRAY)&row_address,1)!=1, - "jpeg_reader_color_covert::apply(): fail to read JPEG file"); - std::transform(row.begin(),row.end(),view.row_begin(y),color_convert_deref_fn<gray8_ref_t, typename View::value_type,CC>(_cc)); - } - break; - } - case JCS_RGB: { - std::vector<rgb8_pixel_t> row(view.width()); - JSAMPLE* row_address=(JSAMPLE*)&row.front(); - for(int y=0;y<view.height();++y) { - io_error_if(jpeg_read_scanlines(&_cinfo,(JSAMPARRAY)&row_address,1)!=1, - "jpeg_reader_color_covert::apply(): fail to read JPEG file"); - std::transform(row.begin(),row.end(),view.row_begin(y),color_convert_deref_fn<rgb8_ref_t, typename View::value_type,CC>(_cc)); - } - break; - } - case JCS_CMYK: { - std::vector<cmyk8_pixel_t> row(view.width()); - JSAMPLE* row_address=(JSAMPLE*)&row.front(); - for(int y=0;y<view.height();++y) { - io_error_if(jpeg_read_scanlines(&_cinfo,(JSAMPARRAY)&row_address,1)!=1, - "jpeg_reader_color_covert::apply(): fail to read JPEG file"); - std::transform(row.begin(),row.end(),view.row_begin(y),color_convert_deref_fn<cmyk8_ref_t, typename View::value_type,CC>(_cc)); - } - break; - } - default: - io_error("jpeg_reader_color_covert::apply(): unknown color type"); - } - jpeg_finish_decompress(&_cinfo); - } - template <typename Image> - void read_image(Image& im) { - im.recreate(get_dimensions()); - apply(view(im)); - } -}; - -class jpeg_writer : public file_mgr { - jpeg_compress_struct _cinfo; - jpeg_error_mgr _jerr; - - void init() { - _cinfo.err=jpeg_std_error(&_jerr); - jpeg_create_compress(&_cinfo); - jpeg_stdio_dest(&_cinfo,_fp.get()); - } -public: - jpeg_writer(FILE* file) : file_mgr(file) { init(); } - jpeg_writer(const char* filename) : file_mgr(filename, "wb") { init(); } - ~jpeg_writer() { jpeg_destroy_compress(&_cinfo); } - - template <typename View> - void apply(const View& view,int quality=100) { - _cinfo.image_width = (JDIMENSION)view.width(); - _cinfo.image_height = (JDIMENSION)view.height(); - _cinfo.input_components=num_channels<View>::value; - _cinfo.in_color_space = jpeg_write_support_private<typename channel_type<View>::type, - typename color_space_type<View>::type>::color_type; - jpeg_set_defaults(&_cinfo); - jpeg_set_quality(&_cinfo, quality, TRUE); - jpeg_start_compress(&_cinfo, TRUE); - std::vector<pixel<bits8,layout<typename color_space_type<View>::type> > > row(view.width()); - JSAMPLE* row_address=(JSAMPLE*)&row.front(); - for (int y=0;y<view.height(); ++y) { - std::copy(view.row_begin(y),view.row_end(y),row.begin()); - io_error_if(jpeg_write_scanlines(&_cinfo,(JSAMPARRAY)&row_address,1) != 1, - "jpeg_writer::apply(): fail to write file"); - } - jpeg_finish_compress(&_cinfo); - } -}; - -} // namespace detail - -} } // namespace boost::gil - -#endif diff --git a/boost/gil/extension/io/png.hpp b/boost/gil/extension/io/png.hpp new file mode 100644 index 0000000000..648170b1c0 --- /dev/null +++ b/boost/gil/extension/io/png.hpp @@ -0,0 +1,25 @@ +/* + Copyright 2007-2008 Christian Henning + 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_PNG_HPP +#define BOOST_GIL_EXTENSION_IO_PNG_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file +/// \brief +/// \author Christian Henning \n +/// +/// \date 2007-2008 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +#include <boost/gil/extension/io/png/read.hpp> +#include <boost/gil/extension/io/png/write.hpp> + +#endif diff --git a/boost/gil/extension/io/png/detail/base.hpp b/boost/gil/extension/io/png/detail/base.hpp new file mode 100644 index 0000000000..a58d033d10 --- /dev/null +++ b/boost/gil/extension/io/png/detail/base.hpp @@ -0,0 +1,109 @@ +/* + Copyright 2012 Christian Henning + 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_PNG_DETAIL_BASE_HPP +#define BOOST_GIL_EXTENSION_IO_PNG_DETAIL_BASE_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file +/// \brief +/// \author Christian Henning \n +/// +/// \date 2012 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +#include <boost/gil/extension/io/png/tags.hpp> + +#include <memory> + +namespace boost { namespace gil { namespace detail { + +struct png_ptr_wrapper +{ + png_ptr_wrapper() + : _struct( NULL ) + , _info ( NULL ) + {} + + png_structp _struct; + png_infop _info; +}; + +/// +/// Wrapper for libpng's png_struct and png_info object. Implements value semantics. +/// +struct png_struct_info_wrapper +{ +protected: + + using png_ptr_t = std::shared_ptr<png_ptr_wrapper>; + +protected: + + /// + /// Default Constructor + /// + png_struct_info_wrapper( bool read = true ) + : _png_ptr( new png_ptr_wrapper() + , ( ( read ) ? png_ptr_read_deleter : png_ptr_write_deleter ) + ) + {} + + png_ptr_wrapper* get() { return _png_ptr.get(); } + const png_ptr_wrapper* get() const { return _png_ptr.get(); } + + png_structp get_struct() { return get()->_struct; } + const png_structp get_struct() const { return get()->_struct; } + + png_infop get_info() { return get()->_info; } + const png_infop get_info() const { return get()->_info; } + +private: + + static void png_ptr_read_deleter( png_ptr_wrapper* png_ptr ) + { + if( png_ptr ) + { + assert( png_ptr->_struct && png_ptr->_info ); + + png_destroy_read_struct( &png_ptr->_struct + , &png_ptr->_info + , NULL + ); + + delete png_ptr; + png_ptr = NULL; + } + } + + static void png_ptr_write_deleter( png_ptr_wrapper* png_ptr ) + { + if( png_ptr ) + { + assert( png_ptr->_struct && png_ptr->_info ); + + png_destroy_write_struct( &png_ptr->_struct + , &png_ptr->_info + ); + + delete png_ptr; + png_ptr = NULL; + } + } + + +private: + + png_ptr_t _png_ptr; +}; + +} // namespace detail +} // namespace gil +} // namespace boost + +#endif diff --git a/boost/gil/extension/io/png/detail/is_allowed.hpp b/boost/gil/extension/io/png/detail/is_allowed.hpp new file mode 100644 index 0000000000..cf83dd5f02 --- /dev/null +++ b/boost/gil/extension/io/png/detail/is_allowed.hpp @@ -0,0 +1,55 @@ +/* + Copyright 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_PNG_DETAIL_IS_ALLOWED_HPP +#define BOOST_GIL_EXTENSION_IO_PNG_DETAIL_IS_ALLOWED_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file +/// \brief +/// \author Christian Henning \n +/// +/// \date 2008 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +#include <boost/mpl/for_each.hpp> + +namespace boost { namespace gil { namespace detail { + +template< typename View > +bool is_allowed( const image_read_info< png_tag >& info + , mpl::true_ // is read_and_no_convert + ) +{ + typedef typename get_pixel_type< View >::type pixel_t; + + typedef typename channel_traits< + typename element_type< pixel_t >::type >::value_type channel_t; + + const png_num_channels::type dst_num_channels = num_channels< pixel_t >::value; + const png_bitdepth::type dst_bit_depth = detail::unsigned_integral_num_bits< channel_t >::value; + + return dst_num_channels == info._num_channels + && dst_bit_depth == info._bit_depth; +} + +template< typename View > +bool is_allowed( const image_read_info< png_tag >& /* info */ + , mpl::false_ // is read_and_convert + ) +{ + return true; +} + +} // namespace detail +} // namespace gil +} // namespace boost + +#endif diff --git a/boost/gil/extension/io/png/detail/read.hpp b/boost/gil/extension/io/png/detail/read.hpp new file mode 100644 index 0000000000..9c4588c380 --- /dev/null +++ b/boost/gil/extension/io/png/detail/read.hpp @@ -0,0 +1,444 @@ +/* + Copyright 2007-2012 Christian Henning, Andreas Pokorny, 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_PNG_DETAIL_READ_HPP +#define BOOST_GIL_EXTENSION_IO_PNG_DETAIL_READ_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file +/// \brief +/// \author Christian Henning, Andreas Pokorny, Lubomir Bourdev \n +/// +/// \date 2007-2012 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +#include <boost/gil/extension/io/png/tags.hpp> + +#include <boost/gil.hpp> + +#include <boost/gil/io/base.hpp> +#include <boost/gil/io/reader_base.hpp> +#include <boost/gil/io/conversion_policies.hpp> +#include <boost/gil/io/device.hpp> +#include <boost/gil/io/typedefs.hpp> +#include <boost/gil/io/row_buffer_helper.hpp> + +#include <boost/gil/extension/io/png/detail/reader_backend.hpp> +#include <boost/gil/extension/io/png/detail/is_allowed.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 + +/// +/// PNG Reader +/// +template< typename Device + , typename ConversionPolicy + > +class reader< Device + , png_tag + , ConversionPolicy + > + : public reader_base< png_tag + , ConversionPolicy > + , public reader_backend< Device + , png_tag + > +{ +private: + + typedef reader< Device + , png_tag + , ConversionPolicy + > this_t; + + typedef typename ConversionPolicy::color_converter_type cc_t; + +public: + + typedef reader_backend< Device, png_tag > backend_t; + +public: + + reader( const Device& io_dev + , const image_read_settings< png_tag >& settings + ) + : reader_base< png_tag + , ConversionPolicy + >() + , backend_t( io_dev + , settings + ) + {} + + reader( const Device& io_dev + , const typename ConversionPolicy::color_converter_type& cc + , const image_read_settings< png_tag >& settings + ) + : reader_base< png_tag + , ConversionPolicy + >( cc ) + , backend_t( io_dev + , settings + ) + {} + + template< typename View > + void apply( const View& view ) + { + // The info structures are filled at this point. + + // Now it's time for some transformations. + + if( little_endian() ) + { + if( this->_info._bit_depth == 16 ) + { + // Swap bytes of 16 bit files to least significant byte first. + png_set_swap( this->get_struct() ); + } + + if( this->_info._bit_depth < 8 ) + { + // swap bits of 1, 2, 4 bit packed pixel formats + png_set_packswap( this->get_struct() ); + } + } + + if( this->_info._color_type == PNG_COLOR_TYPE_PALETTE ) + { + png_set_palette_to_rgb( this->get_struct() ); + } + + if( png_get_valid( this->get_struct(), this->get_info(), PNG_INFO_tRNS ) ) + { + png_set_tRNS_to_alpha( this->get_struct() ); + } + + // Tell libpng to handle the gamma conversion for you. The final call + // is a good guess for PC generated images, but it should be configurable + // by the user at run time by the user. It is strongly suggested that + // your application support gamma correction. + if( this->_settings._apply_screen_gamma ) + { + // png_set_gamma will change the image data! + +#ifdef BOOST_GIL_IO_PNG_FLOATING_POINT_SUPPORTED + png_set_gamma( this->get_struct() + , this->_settings._screen_gamma + , this->_info._file_gamma + ); +#else + png_set_gamma( this->get_struct() + , this->_settings._screen_gamma + , this->_info._file_gamma + ); +#endif // BOOST_GIL_IO_PNG_FLOATING_POINT_SUPPORTED + } + + // Turn on interlace handling. REQUIRED if you are not using + // png_read_image(). To see how to handle interlacing passes, + // see the png_read_row() method below: + this->_number_passes = png_set_interlace_handling( this->get_struct() ); + + + // The above transformation might have changed the bit_depth and color type. + png_read_update_info( this->get_struct() + , this->get_info() + ); + + this->_info._bit_depth = png_get_bit_depth( this->get_struct() + , this->get_info() + ); + + this->_info._num_channels = png_get_channels( this->get_struct() + , this->get_info() + ); + + this->_info._color_type = png_get_color_type( this->get_struct() + , this->get_info() + ); + + this->_scanline_length = png_get_rowbytes( this->get_struct() + , this->get_info() + ); + + switch( this->_info._color_type ) + { + case PNG_COLOR_TYPE_GRAY: + { + switch( this->_info._bit_depth ) + { + case 1: read_rows< gray1_image_t::view_t::reference >( view ); break; + case 2: read_rows< gray2_image_t::view_t::reference >( view ); break; + case 4: read_rows< gray4_image_t::view_t::reference >( view ); break; + case 8: read_rows< gray8_pixel_t >( view ); break; + case 16: read_rows< gray16_pixel_t >( view ); break; + default: io_error( "png_reader::read_data(): unknown combination of color type and bit depth" ); + } + + break; + } + case PNG_COLOR_TYPE_GA: + { + #ifdef BOOST_GIL_IO_ENABLE_GRAY_ALPHA + switch( this->_info._bit_depth ) + { + case 8: read_rows< gray_alpha8_pixel_t > ( view ); break; + case 16: read_rows< gray_alpha16_pixel_t >( view ); break; + default: io_error( "png_reader::read_data(): unknown combination of color type and bit depth" ); + } + #else + io_error( "gray_alpha isn't enabled. Use ENABLE_GRAY_ALPHA when building application." ); + #endif // BOOST_GIL_IO_ENABLE_GRAY_ALPHA + + + break; + } + case PNG_COLOR_TYPE_RGB: + { + switch( this->_info._bit_depth ) + { + case 8: read_rows< rgb8_pixel_t > ( view ); break; + case 16: read_rows< rgb16_pixel_t >( view ); break; + default: io_error( "png_reader::read_data(): unknown combination of color type and bit depth" ); + } + + break; + } + case PNG_COLOR_TYPE_RGBA: + { + switch( this->_info._bit_depth ) + { + case 8: read_rows< rgba8_pixel_t > ( view ); break; + case 16: read_rows< rgba16_pixel_t >( view ); break; + default: io_error( "png_reader_color_convert::read_data(): unknown combination of color type and bit depth" ); + } + + break; + } + default: io_error( "png_reader_color_convert::read_data(): unknown color type" ); + } + + // read rest of file, and get additional chunks in info_ptr + png_read_end( this->get_struct() + , NULL + ); + } + +private: + + template< typename ImagePixel + , typename View + > + void read_rows( const View& view ) + { + typedef detail::row_buffer_helper_view< ImagePixel > row_buffer_helper_t; + + typedef typename row_buffer_helper_t::iterator_t it_t; + + typedef typename is_same< ConversionPolicy + , detail::read_and_no_convert + >::type is_read_and_convert_t; + + io_error_if( !detail::is_allowed< View >( this->_info + , is_read_and_convert_t() + ) + , "Image types aren't compatible." + ); + + std::size_t rowbytes = png_get_rowbytes( this->get_struct() + , this->get_info() + ); + + row_buffer_helper_t buffer( rowbytes + , true + ); + + png_bytep row_ptr = (png_bytep)( &( buffer.data()[0])); + + for( std::size_t pass = 0; pass < this->_number_passes; pass++ ) + { + if( pass == this->_number_passes - 1 ) + { + // skip lines if necessary + for( std::ptrdiff_t y = 0; y < this->_settings._top_left.y; ++y ) + { + // Read the image using the "sparkle" effect. + png_read_rows( this->get_struct() + , &row_ptr + , NULL + , 1 + ); + } + + for( std::ptrdiff_t y = 0 + ; y < this->_settings._dim.y + ; ++y + ) + { + // Read the image using the "sparkle" effect. + png_read_rows( this->get_struct() + , &row_ptr + , NULL + , 1 + ); + + it_t first = buffer.begin() + this->_settings._top_left.x; + it_t last = first + this->_settings._dim.x; // one after last element + + this->_cc_policy.read( first + , last + , view.row_begin( y )); + } + + // Read the rest of the image. libpng needs that. + std::ptrdiff_t remaining_rows = static_cast< std::ptrdiff_t >( this->_info._height ) + - this->_settings._top_left.y + - this->_settings._dim.y; + for( std::ptrdiff_t y = 0 + ; y < remaining_rows + ; ++y + ) + { + // Read the image using the "sparkle" effect. + png_read_rows( this->get_struct() + , &row_ptr + , NULL + , 1 + ); + } + } + else + { + for( int y = 0; y < view.height(); ++y ) + { + // Read the image using the "sparkle" effect. + png_read_rows( this->get_struct() + , &row_ptr + , NULL + , 1 + ); + } + } + } + } +}; + +namespace detail { + +struct png_type_format_checker +{ + png_type_format_checker( png_bitdepth::type bit_depth + , png_color_type::type color_type + ) + : _bit_depth ( bit_depth ) + , _color_type( color_type ) + {} + + template< typename Image > + bool apply() + { + typedef is_read_supported< typename get_pixel_type< typename Image::view_t >::type + , png_tag + > is_supported_t; + + return is_supported_t::_bit_depth == _bit_depth + && is_supported_t::_color_type == _color_type; + } + +private: + + png_bitdepth::type _bit_depth; + png_color_type::type _color_type; +}; + +struct png_read_is_supported +{ + template< typename View > + struct apply : public is_read_supported< typename get_pixel_type< View >::type + , png_tag + > + {}; +}; + +} // namespace detail + + +/// +/// PNG Dynamic Image Reader +/// +template< typename Device + > +class dynamic_image_reader< Device + , png_tag + > + : public reader< Device + , png_tag + , detail::read_and_no_convert + > +{ + typedef reader< Device + , png_tag + , detail::read_and_no_convert + > parent_t; + +public: + + dynamic_image_reader( const Device& io_dev + , const image_read_settings< png_tag >& settings + ) + : parent_t( io_dev + , settings + ) + {} + + template< typename Images > + void apply( any_image< Images >& images ) + { + detail::png_type_format_checker format_checker( this->_info._bit_depth + , this->_info._color_type + ); + + 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::png_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 diff --git a/boost/gil/extension/io/png/detail/reader_backend.hpp b/boost/gil/extension/io/png/detail/reader_backend.hpp new file mode 100644 index 0000000000..914d4c7505 --- /dev/null +++ b/boost/gil/extension/io/png/detail/reader_backend.hpp @@ -0,0 +1,698 @@ +/* + Copyright 2012 Christian Henning + 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_DETAIL_READER_BACKEND_HPP +#define BOOST_GIL_EXTENSION_IO_DETAIL_READER_BACKEND_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file +/// \brief +/// \author Christian Henning \n +/// +/// \date 2012 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +#include <boost/gil/extension/io/png/tags.hpp> + +#include <boost/gil/extension/io/png/detail/base.hpp> + +namespace boost { namespace gil { + +#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) +#pragma warning(push) +#pragma warning(disable:4512) //assignment operator could not be generated +#pragma warning(disable:4611) //interaction between '_setjmp' and C++ object destruction is non-portable +#endif + +/// +/// PNG Backend +/// +template<typename Device > +struct reader_backend< Device + , png_tag + > + : public detail::png_struct_info_wrapper +{ +public: + + typedef png_tag format_tag_t; + +public: + + typedef reader_backend< Device + , png_tag + > this_t; + + +public: + + reader_backend( const Device& io_dev + , const image_read_settings< png_tag >& settings + ) + : _io_dev( io_dev ) + + , _settings( settings ) + , _info() + , _scanline_length( 0 ) + + , _number_passes( 0 ) + { + 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() + { + using boost::gil::detail::PNG_BYTES_TO_CHECK; + + // check the file's first few bytes + byte_t buf[PNG_BYTES_TO_CHECK]; + + io_error_if( _io_dev.read( buf + , PNG_BYTES_TO_CHECK + ) != PNG_BYTES_TO_CHECK + , "png_check_validity: failed to read image" + ); + + io_error_if( png_sig_cmp( png_bytep(buf) + , png_size_t(0) + , PNG_BYTES_TO_CHECK + ) != 0 + , "png_check_validity: invalid png image" + ); + + // Create and initialize the png_struct with the desired error handler + // functions. If you want to use the default stderr and longjump method, + // you can supply NULL for the last three parameters. We also supply the + // the compiler header file version, so that we know if the application + // was compiled with a compatible version of the library. REQUIRED + get()->_struct = png_create_read_struct( PNG_LIBPNG_VER_STRING + , NULL // user_error_ptr + , NULL // user_error_fn + , NULL // user_warning_fn + ); + + io_error_if( get()->_struct == NULL + , "png_reader: fail to call png_create_write_struct()" + ); + + png_uint_32 user_chunk_data[4]; + user_chunk_data[0] = 0; + user_chunk_data[1] = 0; + user_chunk_data[2] = 0; + user_chunk_data[3] = 0; + png_set_read_user_chunk_fn( get_struct() + , user_chunk_data + , this_t::read_user_chunk_callback + ); + + // Allocate/initialize the memory for image information. REQUIRED. + get()->_info = png_create_info_struct( get_struct() ); + + if( get_info() == NULL ) + { + png_destroy_read_struct( &get()->_struct + , NULL + , NULL + ); + + io_error( "png_reader: fail to call png_create_info_struct()" ); + } + + // Set error handling if you are using the setjmp/longjmp method (this is + // the normal method of doing things with libpng). REQUIRED unless you + // set up your own error handlers in the png_create_read_struct() earlier. + if( setjmp( png_jmpbuf( get_struct() ))) + { + //free all of the memory associated with the png_ptr and info_ptr + png_destroy_read_struct( &get()->_struct + , &get()->_info + , NULL + ); + + io_error( "png is invalid" ); + } + + png_set_read_fn( get_struct() + , static_cast< png_voidp >( &this->_io_dev ) + , this_t::read_data + ); + + // Set up a callback function that will be + // called after each row has been read, which you can use to control + // a progress meter or the like. + png_set_read_status_fn( get_struct() + , this_t::read_row_callback + ); + + // Set up a callback which implements user defined transformation. + // @todo + png_set_read_user_transform_fn( get_struct() + , png_user_transform_ptr( NULL ) + ); + + png_set_keep_unknown_chunks( get_struct() + , PNG_HANDLE_CHUNK_ALWAYS + , NULL + , 0 + ); + + + // Make sure we read the signature. + // @todo make it an option + png_set_sig_bytes( get_struct() + , PNG_BYTES_TO_CHECK + ); + + // The call to png_read_info() gives us all of the information from the + // PNG file before the first IDAT (image data chunk). REQUIRED + png_read_info( get_struct() + , get_info() + ); + + /// + /// Start reading the image information + /// + + // get PNG_IHDR chunk information from png_info structure + png_get_IHDR( get_struct() + , get_info() + , &this->_info._width + , &this->_info._height + , &this->_info._bit_depth + , &this->_info._color_type + , &this->_info._interlace_method + , &this->_info._compression_method + , &this->_info._filter_method + ); + + // get number of color channels in image + this->_info._num_channels = png_get_channels( get_struct() + , get_info() + ); + +#ifdef BOOST_GIL_IO_PNG_FLOATING_POINT_SUPPORTED + + // Get CIE chromacities and referenced white point + if( this->_settings._read_cie_chromacities ) + { + this->_info._valid_cie_colors = png_get_cHRM( get_struct() + , get_info() + , &this->_info._white_x, &this->_info._white_y + , &this->_info._red_x, &this->_info._red_y + , &this->_info._green_x, &this->_info._green_y + , &this->_info._blue_x, &this->_info._blue_y + ); + } + + // get the gamma value + if( this->_settings._read_file_gamma ) + { + this->_info._valid_file_gamma = png_get_gAMA( get_struct() + , get_info() + , &this->_info._file_gamma + ); + + if( this->_info._valid_file_gamma == false ) + { + this->_info._file_gamma = 1.0; + } + } +#else + + // Get CIE chromacities and referenced white point + if( this->_settings._read_cie_chromacities ) + { + this->_info._valid_cie_colors = png_get_cHRM_fixed( get_struct() + , get_info() + , &this->_info._white_x, &this->_info._white_y + , &this->_info._red_x, &this->_info._red_y + , &this->_info._green_x, &this->_info._green_y + , &this->_info._blue_x, &this->_info._blue_y + ); + } + + // get the gamma value + if( this->_settings._read_file_gamma ) + { + this->_info._valid_file_gamma = png_get_gAMA_fixed( get_struct() + , get_info() + , &this->_info._file_gamma + ); + + if( this->_info._valid_file_gamma == false ) + { + this->_info._file_gamma = 1; + } + } +#endif // BOOST_GIL_IO_PNG_FLOATING_POINT_SUPPORTED + + // get the embedded ICC profile data + if( this->_settings._read_icc_profile ) + { +#if PNG_LIBPNG_VER_MINOR >= 5 + png_charp icc_name = png_charp( NULL ); + png_bytep profile = png_bytep( NULL ); + + this->_info._valid_icc_profile = png_get_iCCP( get_struct() + , get_info() + , &icc_name + , &this->_info._iccp_compression_type + , &profile + , &this->_info._profile_length + ); +#else + png_charp icc_name = png_charp( NULL ); + png_charp profile = png_charp( NULL ); + + this->_info._valid_icc_profile = png_get_iCCP( get_struct() + , get_info() + , &icc_name + , &this->_info._iccp_compression_type + , &profile + , &this->_info._profile_length + ); +#endif + if( icc_name ) + { + this->_info._icc_name.append( icc_name + , std::strlen( icc_name ) + ); + } + + if( this->_info._profile_length != 0 ) + { + std:: copy_n (profile, this->_info._profile_length, std:: back_inserter (this->_info._profile)); + } + } + + // get the rendering intent + if( this->_settings._read_intent ) + { + this->_info._valid_intent = png_get_sRGB( get_struct() + , get_info() + , &this->_info._intent + ); + } + + // get image palette information from png_info structure + if( this->_settings._read_palette ) + { + png_colorp palette = png_colorp( NULL ); + + this->_info._valid_palette = png_get_PLTE( get_struct() + , get_info() + , &palette + , &this->_info._num_palette + ); + + if( this->_info._num_palette > 0 ) + { + this->_info._palette.resize( this->_info._num_palette ); + std::copy( palette + , palette + this->_info._num_palette + , &this->_info._palette.front() + ); + } + } + + // get background color + if( this->_settings._read_background ) + { + png_color_16p background = png_color_16p( NULL ); + + this->_info._valid_background = png_get_bKGD( get_struct() + , get_info() + , &background + ); + if( background ) + { + this->_info._background = *background; + } + } + + // get the histogram + if( this->_settings._read_histogram ) + { + png_uint_16p histogram = png_uint_16p( NULL ); + + this->_info._valid_histogram = png_get_hIST( get_struct() + , get_info() + , &histogram + ); + + if( histogram ) + { + // the number of values is set by the number of colors inside + // the palette. + if( this->_settings._read_palette == false ) + { + png_colorp palette = png_colorp( NULL ); + png_get_PLTE( get_struct() + , get_info() + , &palette + , &this->_info._num_palette + ); + } + + std::copy( histogram + , histogram + this->_info._num_palette + , &this->_info._histogram.front() + ); + } + } + + // get screen offsets for the given image + if( this->_settings._read_screen_offsets ) + { + this->_info._valid_offset = png_get_oFFs( get_struct() + , get_info() + , &this->_info._offset_x + , &this->_info._offset_y + , &this->_info._off_unit_type + ); + } + + + // get pixel calibration settings + if( this->_settings._read_pixel_calibration ) + { + png_charp purpose = png_charp ( NULL ); + png_charp units = png_charp ( NULL ); + png_charpp params = png_charpp( NULL ); + + this->_info._valid_pixel_calibration = png_get_pCAL( get_struct() + , get_info() + , &purpose + , &this->_info._X0 + , &this->_info._X1 + , &this->_info._cal_type + , &this->_info._num_params + , &units + , ¶ms + ); + if( purpose ) + { + this->_info._purpose.append( purpose + , std::strlen( purpose ) + ); + } + + if( units ) + { + this->_info._units.append( units + , std::strlen( units ) + ); + } + + if( this->_info._num_params > 0 ) + { + this->_info._params.resize( this->_info._num_params ); + + for( png_CAL_nparam::type i = 0 + ; i < this->_info._num_params + ; ++i + ) + { + this->_info._params[i].append( params[i] + , std::strlen( params[i] ) + ); + } + } + } + + // get the physical resolution + if( this->_settings._read_physical_resolution ) + { + this->_info._valid_resolution = png_get_pHYs( get_struct() + , get_info() + , &this->_info._res_x + , &this->_info._res_y + , &this->_info._phy_unit_type + ); + } + + // get the image resolution in pixels per meter. + if( this->_settings._read_pixels_per_meter ) + { + this->_info._pixels_per_meter = png_get_pixels_per_meter( get_struct() + , get_info() + ); + } + + + // get number of significant bits for each color channel + if( this->_settings._read_number_of_significant_bits ) + { + png_color_8p sig_bits = png_color_8p( NULL ); + + this->_info._valid_significant_bits = png_get_sBIT( get_struct() + , get_info() + , &sig_bits + ); + + // @todo Is there one or more colors? + if( sig_bits ) + { + this->_info._sig_bits = *sig_bits; + } + } + +#ifndef BOOST_GIL_IO_PNG_1_4_OR_LOWER + +#ifdef BOOST_GIL_IO_PNG_FLOATING_POINT_SUPPORTED + + // get physical scale settings + if( this->_settings._read_scale_factors ) + { + this->_info._valid_scale_factors = png_get_sCAL( get_struct() + , get_info() + , &this->_info._scale_unit + , &this->_info._scale_width + , &this->_info._scale_height + ); + } +#else +#ifdef BOOST_GIL_IO_PNG_FIXED_POINT_SUPPORTED + if( this->_settings._read_scale_factors ) + { + this->_info._valid_scale_factors = png_get_sCAL_fixed( get_struct() + , get_info() + , &this->_info._scale_unit + , &this->_info._scale_width + , &this->_info._scale_height + ); + } +#else + if( this->_settings._read_scale_factors ) + { + png_charp scale_width = NULL; + png_charp scale_height = NULL; + + if( this->_info._valid_scale_factors = png_get_sCAL_s( get_struct() + , get_info() + , &this->_info._scale_unit + , &scale_width + , &scale_height + ) > 0 + ) + { + if( scale_width ) + { + this->_info._scale_width.append( scale_width + , std::strlen( scale_width ) + ); + } + + if( scale_height ) + { + this->_info._scale_height.append( scale_height + , std::strlen( scale_height ) + ); + } + } + } +#endif // BOOST_GIL_IO_PNG_FIXED_POINT_SUPPORTED +#endif // BOOST_GIL_IO_PNG_FLOATING_POINT_SUPPORTED +#endif // BOOST_GIL_IO_PNG_1_4_OR_LOWER + + // get comments information from png_info structure + if( this->_settings._read_comments ) + { + png_textp text = png_textp( NULL ); + + this->_info._valid_text = png_get_text( get_struct() + , get_info() + , &text + , &this->_info._num_text + ); + + if( this->_info._num_text > 0 ) + { + this->_info._text.resize( this->_info._num_text ); + + for( png_num_text::type i = 0 + ; i < this->_info._num_text + ; ++i + ) + { + this->_info._text[i]._compression = text[i].compression; + this->_info._text[i]._key.append( text[i].key + , std::strlen( text[i].key ) + ); + + this->_info._text[i]._text.append( text[i].text + , std::strlen( text[i].text ) + ); + } + } + } + + // get last modification time + if( this->_settings._read_last_modification_time ) + { + png_timep mod_time = png_timep( NULL ); + this->_info._valid_modification_time = png_get_tIME( get_struct() + , get_info() + , &mod_time + ); + if( mod_time ) + { + this->_info._mod_time = *mod_time; + } + } + + // get transparency data + if( this->_settings._read_transparency_data ) + { + png_bytep trans = png_bytep ( NULL ); + png_color_16p trans_values = png_color_16p( NULL ); + + this->_info._valid_transparency_factors = png_get_tRNS( get_struct() + , get_info() + , &trans + , &this->_info._num_trans + , &trans_values + ); + + if( trans ) + { + //@todo What to do, here? How do I know the length of the "trans" array? + } + + if( this->_info._num_trans ) + { + this->_info._trans_values.resize( this->_info._num_trans ); + std::copy( trans_values + , trans_values + this->_info._num_trans + , &this->_info._trans_values.front() + ); + } + } + + // @todo One day! +/* + if( false ) + { + png_unknown_chunkp unknowns = png_unknown_chunkp( NULL ); + int num_unknowns = static_cast< int >( png_get_unknown_chunks( get_struct() + , get_info() + , &unknowns + ) + ); + } +*/ + } + + /// 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( 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( img_dim.y < _info._height ) { io_error( "Supplied image is too small" ); } + } + } + +protected: + + static void read_data( png_structp png_ptr + , png_bytep data + , png_size_t length + ) + { + static_cast<Device*>(png_get_io_ptr(png_ptr) )->read( data + , length ); + } + + static void flush( png_structp png_ptr ) + { + static_cast<Device*>(png_get_io_ptr(png_ptr) )->flush(); + } + + + static int read_user_chunk_callback( png_struct* /* png_ptr */ + , png_unknown_chunkp /* chunk */ + ) + { + // @todo + return 0; + } + + static void read_row_callback( png_structp /* png_ptr */ + , png_uint_32 /* row_number */ + , int /* pass */ + ) + { + // @todo + } + +public: + + Device _io_dev; + + image_read_settings< png_tag > _settings; + image_read_info < png_tag > _info; + + std::size_t _scanline_length; + + std::size_t _number_passes; +}; + +#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) +#pragma warning(pop) +#endif + +} // namespace gil +} // namespace boost + +#endif diff --git a/boost/gil/extension/io/png/detail/scanline_read.hpp b/boost/gil/extension/io/png/detail/scanline_read.hpp new file mode 100644 index 0000000000..33b1dcba31 --- /dev/null +++ b/boost/gil/extension/io/png/detail/scanline_read.hpp @@ -0,0 +1,181 @@ +/* + Copyright 2007-2012 Christian Henning, Andreas Pokorny, 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_PNG_DETAIL_SCANLINE_READ_HPP +#define BOOST_GIL_EXTENSION_IO_PNG_DETAIL_SCANLINE_READ_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file +/// \brief +/// \author Christian Henning, Andreas Pokorny, Lubomir Bourdev \n +/// +/// \date 2007-2012 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +#include <boost/gil.hpp> + +#include <boost/gil/io/base.hpp> +#include <boost/gil/io/reader_base.hpp> +#include <boost/gil/io/conversion_policies.hpp> +#include <boost/gil/io/device.hpp> +#include <boost/gil/io/typedefs.hpp> +#include <boost/gil/io/row_buffer_helper.hpp> +#include <boost/gil/io/scanline_read_iterator.hpp> + +#include <boost/gil/extension/io/png/detail/reader_backend.hpp> +#include <boost/gil/extension/io/png/detail/is_allowed.hpp> + +namespace boost { namespace gil { + +/// +/// PNG Reader +/// +template< typename Device > +class scanline_reader< Device + , png_tag + > + : public reader_backend< Device + , png_tag + > +{ +public: + + typedef png_tag tag_t; + typedef reader_backend < Device, tag_t > backend_t; + typedef scanline_reader< Device, tag_t > this_t; + typedef scanline_read_iterator< this_t > iterator_t; + +public: + + // + // Constructor + // + scanline_reader( const Device& io_dev + , const image_read_settings< png_tag >& settings + ) + : reader_backend< Device + , png_tag + >( io_dev + , settings + ) + { + initialize(); + } + + void read( byte_t* dst + , int + ) + { + read_scanline( dst ); + } + + /// Skip over a scanline. + void skip( byte_t* dst, int ) + { + read_scanline( dst ); + } + + iterator_t begin() { return iterator_t( *this ); } + iterator_t end() { return iterator_t( *this, this->_info._height ); } + +private: + + void initialize() + { + // Now it's time for some transformations. + + if( little_endian() ) + { + if( this->_info._bit_depth == 16 ) + { + // Swap bytes of 16 bit files to least significant byte first. + png_set_swap( this->get()->_struct ); + } + + if( this->_info._bit_depth < 8 ) + { + // swap bits of 1, 2, 4 bit packed pixel formats + png_set_packswap( this->get()->_struct ); + } + } + + if( this->_info._color_type == PNG_COLOR_TYPE_PALETTE ) + { + png_set_palette_to_rgb( this->get()->_struct ); + } + + if( this->_info._num_trans > 0 ) + { + png_set_tRNS_to_alpha( this->get()->_struct ); + } + + // Tell libpng to handle the gamma conversion for you. The final call + // is a good guess for PC generated images, but it should be configurable + // by the user at run time by the user. It is strongly suggested that + // your application support gamma correction. + if( this->_settings._apply_screen_gamma ) + { + // png_set_gamma will change the image data! + +#ifdef BOOST_GIL_IO_PNG_FLOATING_POINT_SUPPORTED + png_set_gamma( this->get()->_struct + , this->_settings._screen_gamma + , this->_info._file_gamma + ); +#else + png_set_gamma( this->get()->_struct + , this->_settings._screen_gamma + , this->_info._file_gamma + ); +#endif // BOOST_GIL_IO_PNG_FLOATING_POINT_SUPPORTED + } + + // Interlaced images are not supported. + this->_number_passes = png_set_interlace_handling( this->get()->_struct ); + io_error_if( this->_number_passes != 1 + , "scanline_read_iterator cannot read interlaced png images." + ); + + + // The above transformation might have changed the bit_depth and color type. + png_read_update_info( this->get()->_struct + , this->get()->_info + ); + + this->_info._bit_depth = png_get_bit_depth( this->get()->_struct + , this->get()->_info + ); + + this->_info._num_channels = png_get_channels( this->get()->_struct + , this->get()->_info + ); + + this->_info._color_type = png_get_color_type( this->get()->_struct + , this->get()->_info + ); + + this->_scanline_length = png_get_rowbytes( this->get()->_struct + , this->get()->_info + ); + } + + void read_scanline( byte_t* dst ) + { + png_read_row( this->get()->_struct + , dst + , NULL + ); + } +}; + +} // namespace gil +} // namespace boost + +#endif diff --git a/boost/gil/extension/io/png/detail/supported_types.hpp b/boost/gil/extension/io/png/detail/supported_types.hpp new file mode 100644 index 0000000000..165e8f4877 --- /dev/null +++ b/boost/gil/extension/io/png/detail/supported_types.hpp @@ -0,0 +1,366 @@ +/* + Copyright 2007-2008 Christian Henning, Andreas Pokorny, 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_PNG_DETAIL_SUPPORTED_TYPES_HPP +#define BOOST_GIL_EXTENSION_IO_PNG_DETAIL_SUPPORTED_TYPES_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file +/// \brief +/// \author Christian Henning, Andreas Pokorny, Lubomir Bourdev \n +/// +/// \date 2007-2008 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +#ifdef BOOST_GIL_IO_ENABLE_GRAY_ALPHA +#include <boost/gil/extension/toolbox/color_spaces/gray_alpha.hpp> +#endif // BOOST_GIL_IO_ENABLE_GRAY_ALPHA + +namespace boost { namespace gil { namespace detail { + +static const size_t PNG_BYTES_TO_CHECK = 4; + +// Read support +template< png_bitdepth::type BitDepth + , png_color_type::type ColorType + > +struct png_rw_support_base +{ + static const png_bitdepth::type _bit_depth = BitDepth; + static const png_color_type::type _color_type = ColorType; +}; + +template< typename Channel + , typename ColorSpace + > +struct png_read_support : read_support_false + , png_rw_support_base< 1 + , PNG_COLOR_TYPE_GRAY + > {}; + +template< typename BitField + , bool Mutable + > +struct png_read_support< packed_dynamic_channel_reference< BitField + , 1 + , Mutable + > + , gray_t + > : read_support_true + , png_rw_support_base< 1 + , PNG_COLOR_TYPE_GRAY + > {}; + +template< typename BitField + , bool Mutable + > +struct png_read_support< packed_dynamic_channel_reference< BitField + , 2 + , Mutable + > + , gray_t + > : read_support_true + , png_rw_support_base< 2 + , PNG_COLOR_TYPE_GRAY + > {}; + +template< typename BitField + , bool Mutable + > +struct png_read_support< packed_dynamic_channel_reference< BitField + , 4 + , Mutable + > + , gray_t + > : read_support_true + , png_rw_support_base< 4 + , PNG_COLOR_TYPE_GRAY + > {}; + +template<> +struct png_read_support<uint8_t + , gray_t + > : read_support_true + , png_rw_support_base< 8 + , PNG_COLOR_TYPE_GRAY + > {}; + +#ifdef BOOST_GIL_IO_ENABLE_GRAY_ALPHA +template<> +struct png_read_support<uint8_t + , gray_alpha_t + > : read_support_true + , png_rw_support_base< 8 + , PNG_COLOR_TYPE_GA + > {}; +#endif // BOOST_GIL_IO_ENABLE_GRAY_ALPHA + +template<> +struct png_read_support<uint8_t + , rgb_t + > : read_support_true + , png_rw_support_base< 8 + , PNG_COLOR_TYPE_RGB + > {}; + +template<> +struct png_read_support<uint8_t + , rgba_t + > : read_support_true + , png_rw_support_base< 8 + , PNG_COLOR_TYPE_RGBA + > {}; + +template<> +struct png_read_support<uint16_t + , gray_t + > : read_support_true + , png_rw_support_base< 16 + , PNG_COLOR_TYPE_GRAY + > {}; + +template<> +struct png_read_support<uint16_t + , rgb_t + > : read_support_true + , png_rw_support_base< 16 + , PNG_COLOR_TYPE_RGB + > {}; + +template<> +struct png_read_support<uint16_t + , rgba_t + > : read_support_true + , png_rw_support_base< 16 + , PNG_COLOR_TYPE_RGBA + > {}; + +#ifdef BOOST_GIL_IO_ENABLE_GRAY_ALPHA +template<> +struct png_read_support<uint16_t + , gray_alpha_t + > : read_support_true + , png_rw_support_base< 16 + , PNG_COLOR_TYPE_GA + > {}; +#endif // BOOST_GIL_IO_ENABLE_GRAY_ALPHA + +// Write support + +template< typename Channel + , typename ColorSpace + > +struct png_write_support : write_support_false + , png_rw_support_base< 1 + , PNG_COLOR_TYPE_GRAY + > {}; + +template< typename BitField + , bool Mutable + > +struct png_write_support< packed_dynamic_channel_reference< BitField + , 1 + , Mutable + > + , gray_t + > : write_support_true + , png_rw_support_base< 1 + , PNG_COLOR_TYPE_GRAY + > +{}; + +template< typename BitField + , bool Mutable + > +struct png_write_support< packed_dynamic_channel_reference< BitField + , 1 + , Mutable + > const + , gray_t + > : write_support_true + , png_rw_support_base< 1 + , PNG_COLOR_TYPE_GRAY + > +{}; + +template< typename BitField + , bool Mutable + > +struct png_write_support< packed_dynamic_channel_reference< BitField + , 2 + , Mutable + > + , gray_t + > : write_support_true + , png_rw_support_base< 2 + , PNG_COLOR_TYPE_GRAY + > +{}; + +template< typename BitField + , bool Mutable + > +struct png_write_support< packed_dynamic_channel_reference< BitField + , 2 + , Mutable + > const + , gray_t + > : write_support_true + , png_rw_support_base< 2 + , PNG_COLOR_TYPE_GRAY + > +{}; + +template< typename BitField + , bool Mutable + > +struct png_write_support< packed_dynamic_channel_reference< BitField + , 4 + , Mutable + > + , gray_t + > : write_support_true + , png_rw_support_base< 4 + , PNG_COLOR_TYPE_GRAY + > +{}; + +template< typename BitField + , bool Mutable + > +struct png_write_support< packed_dynamic_channel_reference< BitField + , 4 + , Mutable + > const + , gray_t + > : write_support_true + , png_rw_support_base< 4 + , PNG_COLOR_TYPE_GRAY + > +{}; + +template<> +struct png_write_support<uint8_t + , gray_t + > : write_support_true + , png_rw_support_base< 8 + , PNG_COLOR_TYPE_GRAY + > +{}; + +#ifdef BOOST_GIL_IO_ENABLE_GRAY_ALPHA +template<> +struct png_write_support<uint8_t + , gray_alpha_t + > : write_support_true + , png_rw_support_base< 8 + , PNG_COLOR_TYPE_GA + > +{}; +#endif // BOOST_GIL_IO_ENABLE_GRAY_ALPHA + +template<> +struct png_write_support<uint8_t + , rgb_t + > : write_support_true + , png_rw_support_base< 8 + , PNG_COLOR_TYPE_RGB + > +{}; + +template<> +struct png_write_support<uint8_t + , rgba_t + > : write_support_true + , png_rw_support_base< 8 + , PNG_COLOR_TYPE_RGBA + > +{}; + +template<> +struct png_write_support<uint16_t + , gray_t + > : write_support_true + , png_rw_support_base< 16 + , PNG_COLOR_TYPE_GRAY + > +{}; + +template<> +struct png_write_support<uint16_t + , rgb_t + > : write_support_true + , png_rw_support_base< 16 + , PNG_COLOR_TYPE_RGB + > +{}; + +template<> +struct png_write_support<uint16_t + , rgba_t + > : write_support_true + , png_rw_support_base< 16 + , PNG_COLOR_TYPE_RGBA + > +{}; + +#ifdef BOOST_GIL_IO_ENABLE_GRAY_ALPHA +template<> +struct png_write_support<uint16_t + , gray_alpha_t + > : write_support_true + , png_rw_support_base< 16 + , PNG_COLOR_TYPE_GA + > +{}; +#endif // BOOST_GIL_IO_ENABLE_GRAY_ALPHA + + +} // namespace detail + +template< typename Pixel > +struct is_read_supported< Pixel + , png_tag + > + : mpl::bool_< detail::png_read_support< typename channel_type< Pixel >::type + , typename color_space_type< Pixel >::type + >::is_supported + > +{ + typedef detail::png_read_support< typename channel_type< Pixel >::type + , typename color_space_type< Pixel >::type + > parent_t; + + static const png_bitdepth::type _bit_depth = parent_t::_bit_depth; + static const png_color_type::type _color_type = parent_t::_color_type; +}; + +template< typename Pixel > +struct is_write_supported< Pixel + , png_tag + > + : mpl::bool_< detail::png_write_support< typename channel_type< Pixel >::type + , typename color_space_type< Pixel >::type + >::is_supported + > +{ + typedef detail::png_write_support< typename channel_type< Pixel >::type + , typename color_space_type< Pixel >::type + > parent_t; + + static const png_bitdepth::type _bit_depth = parent_t::_bit_depth; + static const png_color_type::type _color_type = parent_t::_color_type; +}; + +} // namespace gil +} // namespace boost + + +#endif diff --git a/boost/gil/extension/io/png/detail/write.hpp b/boost/gil/extension/io/png/detail/write.hpp new file mode 100644 index 0000000000..e571c09459 --- /dev/null +++ b/boost/gil/extension/io/png/detail/write.hpp @@ -0,0 +1,242 @@ +/* + Copyright 2007-2012 Christian Henning, Andreas Pokorny, 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_PNG_DETAIL_WRITE_HPP +#define BOOST_GIL_EXTENSION_IO_PNG_DETAIL_WRITE_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file +/// \brief +/// \author Christian Henning, Andreas Pokorny, Lubomir Bourdev \n +/// +/// \date 2007-2012 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +#include <boost/mpl/and.hpp> +#include <boost/mpl/equal_to.hpp> +#include <boost/mpl/less.hpp> +#include <boost/mpl/not.hpp> + +#include <boost/gil/io/device.hpp> +#include <boost/gil/io/row_buffer_helper.hpp> + +#include <boost/gil/extension/io/png/detail/writer_backend.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 { + +struct png_write_is_supported +{ + template< typename View > + struct apply + : public is_write_supported< typename get_pixel_type< View >::type + , png_tag + > + {}; +}; + +} // namespace detail + +/// +/// PNG Writer +/// +template< typename Device > +class writer< Device + , png_tag + > + : public writer_backend< Device + , png_tag + > +{ + +public: + + typedef writer_backend< Device , png_tag > backend_t; + + writer( const Device& io_dev + , const image_write_info< png_tag >& info + ) + : backend_t( io_dev + , info + ) + {} + + + template< typename View > + void apply( const View& view ) + { + io_error_if( view.width() == 0 && view.height() == 0 + , "png format cannot handle empty views." + ); + + this->write_header( view ); + + write_view( view + , typename is_bit_aligned< typename View::value_type >::type() + ); + } + +private: + + template<typename View> + void write_view( const View& view + , mpl::false_ // is bit aligned + ) + { + typedef typename get_pixel_type< View >::type pixel_t; + + typedef detail::png_write_support< typename channel_type < pixel_t >::type + , typename color_space_type< pixel_t >::type + > png_rw_info; + + if( little_endian() ) + { + set_swap< png_rw_info >(); + } + + std::vector< pixel< typename channel_type< View >::type + , layout<typename color_space_type< View >::type > + > + > row_buffer( view.width() ); + + for( int y = 0; y != view.height(); ++ y) + { + std::copy( view.row_begin( y ) + , view.row_end ( y ) + , row_buffer.begin() + ); + + png_write_row( this->get_struct() + , reinterpret_cast< png_bytep >( row_buffer.data() ) + ); + } + + png_write_end( this->get_struct() + , this->get_info() + ); + } + + template<typename View> + void write_view( const View& view + , mpl::true_ // is bit aligned + ) + { + typedef detail::png_write_support< typename kth_semantic_element_type< typename View::value_type + , 0 + >::type + , typename color_space_type<View>::type + > png_rw_info; + + if (little_endian() ) + { + set_swap< png_rw_info >(); + } + + detail::row_buffer_helper_view< View > row_buffer( view.width() + , false + ); + + for( int y = 0; y != view.height(); ++y ) + { + std::copy( view.row_begin( y ) + , view.row_end ( y ) + , row_buffer.begin() + ); + + png_write_row( this->get_struct() + , reinterpret_cast< png_bytep >( row_buffer.data() ) + ); + } + + png_free_data( this->get_struct() + , this->get_info() + , PNG_FREE_UNKN + , -1 + ); + + png_write_end( this->get_struct() + , this->get_info() + ); + } + + template< typename Info > struct is_less_than_eight : mpl::less< mpl::int_< Info::_bit_depth >, mpl::int_< 8 > > {}; + template< typename Info > struct is_equal_to_sixteen : mpl::equal_to< mpl::int_< Info::_bit_depth >, mpl::int_< 16 > > {}; + + template< typename Info > + void set_swap( typename enable_if< is_less_than_eight< Info > >::type* /* ptr */ = 0 ) + { + png_set_packswap( this->get_struct() ); + } + + template< typename Info > + void set_swap( typename enable_if< is_equal_to_sixteen< Info > >::type* /* ptr */ = 0 ) + { + png_set_swap( this->get_struct() ); + } + + template< typename Info > + void set_swap( typename enable_if< mpl::and_< mpl::not_< is_less_than_eight< Info > > + , mpl::not_< is_equal_to_sixteen< Info > > + > + >::type* /* ptr */ = 0 + ) + {} +}; + +/// +/// PNG Dynamic Image Writer +/// +template< typename Device > +class dynamic_image_writer< Device + , png_tag + > + : public writer< Device + , png_tag + > +{ + typedef writer< Device + , png_tag + > parent_t; + +public: + + dynamic_image_writer( const Device& io_dev + , const image_write_info< png_tag >& info +) + : parent_t( io_dev + , info + ) + {} + + template< typename Views > + void apply( const any_image_view< Views >& views ) + { + detail::dynamic_io_fnobj< detail::png_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 diff --git a/boost/gil/extension/io/png/detail/writer_backend.hpp b/boost/gil/extension/io/png/detail/writer_backend.hpp new file mode 100644 index 0000000000..e018df79ea --- /dev/null +++ b/boost/gil/extension/io/png/detail/writer_backend.hpp @@ -0,0 +1,516 @@ +/* + Copyright 2012 Christian Henning + 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_PNG_DETAIL_WRITER_BACKEND_HPP +#define BOOST_GIL_EXTENSION_IO_PNG_DETAIL_WRITER_BACKEND_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file +/// \brief +/// \author Christian Henning \n +/// +/// \date 2012 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +#include <boost/gil/io/typedefs.hpp> +#include <boost/gil/io/base.hpp> + +#include <boost/gil/extension/io/png/tags.hpp> + +#include <boost/gil/extension/io/png/detail/base.hpp> +#include <boost/gil/extension/io/png/detail/supported_types.hpp> + +namespace boost { namespace gil { + +#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) +#pragma warning(push) +#pragma warning(disable:4512) //assignment operator could not be generated +#pragma warning(disable:4611) //interaction between '_setjmp' and C++ object destruction is non-portable +#endif + +/// +/// PNG Writer Backend +/// +template< typename Device > +struct writer_backend< Device + , png_tag + > + : public detail::png_struct_info_wrapper +{ + +private: + + typedef writer_backend< Device + , png_tag + > this_t; + +public: + + typedef png_tag format_tag_t; + +public: + + /// + /// Constructor + /// + writer_backend( const Device& io_dev + , const image_write_info< png_tag >& info + ) + : png_struct_info_wrapper( false ) + , _io_dev( io_dev ) + , _info( info ) + { + // Create and initialize the png_struct with the desired error handler + // functions. If you want to use the default stderr and longjump method, + // you can supply NULL for the last three parameters. We also check that + // the library version is compatible with the one used at compile time, + // in case we are using dynamically linked libraries. REQUIRED. + get()->_struct = png_create_write_struct( PNG_LIBPNG_VER_STRING + , NULL // user_error_ptr + , NULL // user_error_fn + , NULL // user_warning_fn + ); + + io_error_if( get_struct() == NULL + , "png_writer: fail to call png_create_write_struct()" + ); + + // Allocate/initialize the image information data. REQUIRED + get()->_info = png_create_info_struct( get_struct() ); + + if( get_info() == NULL ) + { + png_destroy_write_struct( &get()->_struct + , NULL + ); + + io_error( "png_writer: fail to call png_create_info_struct()" ); + } + + // Set error handling. REQUIRED if you aren't supplying your own + // error handling functions in the png_create_write_struct() call. + if( setjmp( png_jmpbuf( get_struct() ))) + { + //free all of the memory associated with the png_ptr and info_ptr + png_destroy_write_struct( &get()->_struct + , &get()->_info + ); + + io_error( "png_writer: fail to call setjmp()" ); + } + + init_io( get_struct() ); + } + +protected: + + template< typename View > + void write_header( const View& view ) + { + typedef detail::png_write_support< typename channel_type< typename get_pixel_type< View >::type >::type + , typename color_space_type< View >::type + > png_rw_info_t; + + // Set the image information here. Width and height are up to 2^31, + // bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on + // the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY, + // PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB, + // or PNG_COLOR_TYPE_RGB_ALPHA. interlace is either PNG_INTERLACE_NONE or + // PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST + // currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. REQUIRED + png_set_IHDR( get_struct() + , get_info() + , static_cast< png_image_width::type >( view.width() ) + , static_cast< png_image_height::type >( view.height() ) + , static_cast< png_bitdepth::type >( png_rw_info_t::_bit_depth ) + , static_cast< png_color_type::type >( png_rw_info_t::_color_type ) + , _info._interlace_method + , _info._compression_type + , _info._filter_method + ); + +#ifdef BOOST_GIL_IO_PNG_FLOATING_POINT_SUPPORTED + if( _info._valid_cie_colors ) + { + png_set_cHRM( get_struct() + , get_info() + , _info._white_x + , _info._white_y + , _info._red_x + , _info._red_y + , _info._green_x + , _info._green_y + , _info._blue_x + , _info._blue_y + ); + } + + if( _info._valid_file_gamma ) + { + png_set_gAMA( get_struct() + , get_info() + , _info._file_gamma + ); + } +#else + if( _info._valid_cie_colors ) + { + png_set_cHRM_fixed( get_struct() + , get_info() + , _info._white_x + , _info._white_y + , _info._red_x + , _info._red_y + , _info._green_x + , _info._green_y + , _info._blue_x + , _info._blue_y + ); + } + + if( _info._valid_file_gamma ) + { + png_set_gAMA_fixed( get_struct() + , get_info() + , _info._file_gamma + ); + } +#endif // BOOST_GIL_IO_PNG_FLOATING_POINT_SUPPORTED + + if( _info._valid_icc_profile ) + { +#if PNG_LIBPNG_VER_MINOR >= 5 + png_set_iCCP( get_struct() + , get_info() + , const_cast< png_charp >( _info._icc_name.c_str() ) + , _info._iccp_compression_type + , reinterpret_cast< png_const_bytep >( & (_info._profile.front ()) ) + , _info._profile_length + ); +#else + png_set_iCCP( get_struct() + , get_info() + , const_cast< png_charp >( _info._icc_name.c_str() ) + , _info._iccp_compression_type + , const_cast< png_charp >( & (_info._profile.front()) ) + , _info._profile_length + ); +#endif + } + + if( _info._valid_intent ) + { + png_set_sRGB( get_struct() + , get_info() + , _info._intent + ); + } + + if( _info._valid_palette ) + { + png_set_PLTE( get_struct() + , get_info() + , const_cast< png_colorp >( &_info._palette.front() ) + , _info._num_palette + ); + } + + if( _info._valid_background ) + { + png_set_bKGD( get_struct() + , get_info() + , const_cast< png_color_16p >( &_info._background ) + ); + } + + if( _info._valid_histogram ) + { + png_set_hIST( get_struct() + , get_info() + , const_cast< png_uint_16p >( &_info._histogram.front() ) + ); + } + + if( _info._valid_offset ) + { + png_set_oFFs( get_struct() + , get_info() + , _info._offset_x + , _info._offset_y + , _info._off_unit_type + ); + } + + if( _info._valid_pixel_calibration ) + { + std::vector< const char* > params( _info._num_params ); + for( std::size_t i = 0; i < params.size(); ++i ) + { + params[i] = _info._params[ i ].c_str(); + } + + png_set_pCAL( get_struct() + , get_info() + , const_cast< png_charp >( _info._purpose.c_str() ) + , _info._X0 + , _info._X1 + , _info._cal_type + , _info._num_params + , const_cast< png_charp >( _info._units.c_str() ) + , const_cast< png_charpp >( ¶ms.front() ) + ); + } + + if( _info._valid_resolution ) + { + png_set_pHYs( get_struct() + , get_info() + , _info._res_x + , _info._res_y + , _info._phy_unit_type + ); + } + + if( _info._valid_significant_bits ) + { + png_set_sBIT( get_struct() + , get_info() + , const_cast< png_color_8p >( &_info._sig_bits ) + ); + } + +#ifndef BOOST_GIL_IO_PNG_1_4_OR_LOWER + +#ifdef BOOST_GIL_IO_PNG_FLOATING_POINT_SUPPORTED + if( _info._valid_scale_factors ) + { + png_set_sCAL( get_struct() + , get_info() + , this->_info._scale_unit + , this->_info._scale_width + , this->_info._scale_height + ); + } +#else +#ifdef BOOST_GIL_IO_PNG_FIXED_POINT_SUPPORTED + if( _info._valid_scale_factors ) + { + png_set_sCAL_fixed( get_struct() + , get_info() + , this->_info._scale_unit + , this->_info._scale_width + , this->_info._scale_height + ); + } +#else + if( _info._valid_scale_factors ) + { + png_set_sCAL_s( get_struct() + , get_info() + , this->_info._scale_unit + , const_cast< png_charp >( this->_info._scale_width.c_str() ) + , const_cast< png_charp >( this->_info._scale_height.c_str() ) + ); + } + +#endif // BOOST_GIL_IO_PNG_FIXED_POINT_SUPPORTED +#endif // BOOST_GIL_IO_PNG_FLOATING_POINT_SUPPORTED +#endif // BOOST_GIL_IO_PNG_1_4_OR_LOWER + + if( _info._valid_text ) + { + std::vector< png_text > texts( _info._num_text ); + for( std::size_t i = 0; i < texts.size(); ++i ) + { + png_text pt; + pt.compression = _info._text[i]._compression; + pt.key = const_cast< png_charp >( this->_info._text[i]._key.c_str() ); + pt.text = const_cast< png_charp >( this->_info._text[i]._text.c_str() ); + pt.text_length = _info._text[i]._text.length(); + + texts[i] = pt; + } + + png_set_text( get_struct() + , get_info() + , &texts.front() + , _info._num_text + ); + } + + if( _info._valid_modification_time ) + { + png_set_tIME( get_struct() + , get_info() + , const_cast< png_timep >( &_info._mod_time ) + ); + } + + if( _info._valid_transparency_factors ) + { + int sample_max = ( 1u << _info._bit_depth ); + + /* libpng doesn't reject a tRNS chunk with out-of-range samples */ + if( !( ( _info._color_type == PNG_COLOR_TYPE_GRAY + && (int) _info._trans_values[0].gray > sample_max + ) + || ( _info._color_type == PNG_COLOR_TYPE_RGB + &&( (int) _info._trans_values[0].red > sample_max + || (int) _info._trans_values[0].green > sample_max + || (int) _info._trans_values[0].blue > sample_max + ) + ) + ) + ) + { + //@todo Fix that once reading transparency values works +/* + png_set_tRNS( get_struct() + , get_info() + , trans + , num_trans + , trans_values + ); +*/ + } + } + + // Compression Levels - valid values are [0,9] + png_set_compression_level( get_struct() + , _info._compression_level + ); + + png_set_compression_mem_level( get_struct() + , _info._compression_mem_level + ); + + png_set_compression_strategy( get_struct() + , _info._compression_strategy + ); + + png_set_compression_window_bits( get_struct() + , _info._compression_window_bits + ); + + png_set_compression_method( get_struct() + , _info._compression_method + ); + + png_set_compression_buffer_size( get_struct() + , _info._compression_buffer_size + ); + +#ifdef BOOST_GIL_IO_PNG_DITHERING_SUPPORTED + // Dithering + if( _info._set_dithering ) + { + png_set_dither( get_struct() + , &_info._dithering_palette.front() + , _info._dithering_num_palette + , _info._dithering_maximum_colors + , &_info._dithering_histogram.front() + , _info._full_dither + ); + } +#endif // BOOST_GIL_IO_PNG_DITHERING_SUPPORTED + + // Filter + if( _info._set_filter ) + { + png_set_filter( get_struct() + , 0 + , _info._filter + ); + } + + // Invert Mono + if( _info._invert_mono ) + { + png_set_invert_mono( get_struct() ); + } + + // True Bits + if( _info._set_true_bits ) + { + png_set_sBIT( get_struct() + , get_info() + , &_info._true_bits.front() + ); + } + + // sRGB Intent + if( _info._set_srgb_intent ) + { + png_set_sRGB( get_struct() + , get_info() + , _info._srgb_intent + ); + } + + // Strip Alpha + if( _info._strip_alpha ) + { + png_set_strip_alpha( get_struct() ); + } + + // Swap Alpha + if( _info._swap_alpha ) + { + png_set_swap_alpha( get_struct() ); + } + + + png_write_info( get_struct() + , get_info() + ); + } + +protected: + + static void write_data( png_structp png_ptr + , png_bytep data + , png_size_t length + ) + { + static_cast< Device* >( png_get_io_ptr( png_ptr ))->write( data + , length ); + } + + static void flush( png_structp png_ptr ) + { + static_cast< Device* >(png_get_io_ptr(png_ptr) )->flush(); + } + +private: + + void init_io( png_structp png_ptr ) + { + png_set_write_fn( png_ptr + , static_cast< void* > ( &this->_io_dev ) + , static_cast< png_rw_ptr > ( &this_t::write_data ) + , static_cast< png_flush_ptr >( &this_t::flush ) + ); + } + +public: + + Device _io_dev; + + image_write_info< png_tag > _info; +}; + +#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) +#pragma warning(pop) +#endif + +} // namespace gil +} // namespace boost + +#endif diff --git a/boost/gil/extension/io/png/old.hpp b/boost/gil/extension/io/png/old.hpp new file mode 100644 index 0000000000..217633661e --- /dev/null +++ b/boost/gil/extension/io/png/old.hpp @@ -0,0 +1,179 @@ +/* + Copyright 2007-2008 Christian Henning + 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_PNG_OLD_HPP +#define BOOST_GIL_EXTENSION_IO_PNG_OLD_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file +/// \brief +/// \author Christian Henning \n +/// +/// \date 2007-2008 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +#include <boost/gil/extension/io/png.hpp> + +namespace boost { namespace gil { + +/// \ingroup PNG_IO +/// \brief Returns the width and height of the PNG file at the specified location. +/// Throws std::ios_base::failure if the location does not correspond to a valid PNG file +template< typename String > +inline +point2< std::ptrdiff_t > png_read_dimensions( const String& filename ) +{ + typedef typename get_reader_backend< String + , png_tag + >::type backend_t; + + backend_t backend = read_image_info( filename + , png_tag() + ); + + return point2< std::ptrdiff_t >( backend._info._width + , backend._info._height + ); +} + +/// \ingroup PNG_IO +/// \brief Loads the image specified by the given png image file name into the given view. +/// Triggers a compile assert if the view color space and channel depth are not supported by the PNG library or by the I/O extension. +/// Throws std::ios_base::failure if the file is not a valid PNG 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 png_read_view( const String& filename + , const View& view + ) +{ + read_view( filename + , view + , png_tag() + ); +} + +/// \ingroup PNG_IO +/// \brief Allocates a new image whose dimensions are determined by the given png 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 PNG library or by the I/O extension. +/// Throws std::ios_base::failure if the file is not a valid PNG 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 png_read_image( const String& filename + , Image& img + ) +{ + read_image( filename + , img + , png_tag() + ); +} + +/// \ingroup PNG_IO +/// \brief Loads the image specified by the given png image file name and color-converts it into the given view. +/// Throws std::ios_base::failure if the file is not a valid PNG file, or if its dimensions don't match the ones of the view. +template< typename String + , typename View + , typename CC + > +inline +void png_read_and_convert_view( const String& filename + , const View& view + , CC cc + ) +{ + read_and_convert_view( filename + , view + , cc + , png_tag() + ); +} + +/// \ingroup PNG_IO +/// \brief Loads the image specified by the given png image file name and color-converts it into the given view. +/// Throws std::ios_base::failure if the file is not a valid PNG file, or if its dimensions don't match the ones of the view. +template< typename String + , typename View + > +inline +void png_read_and_convert_view( const String& filename + , const View& view + ) +{ + read_and_convert_view( filename + , view + , png_tag() + ); +} + +/// \ingroup PNG_IO +/// \brief Allocates a new image whose dimensions are determined by the given png image file, loads and color-converts the pixels into it. +/// Throws std::ios_base::failure if the file is not a valid PNG file +template< typename String + , typename Image + , typename CC + > +inline +void png_read_and_convert_image( const String& filename + , Image& img + , CC cc + ) +{ + read_and_convert_image( filename + , img + , cc + , png_tag() + ); +} + +/// \ingroup PNG_IO +/// \brief Allocates a new image whose dimensions are determined by the given png image file, loads and color-converts the pixels into it. +/// Throws std::ios_base::failure if the file is not a valid PNG file +template< typename String + , typename Image + > +inline +void png_read_and_convert_image( const String filename + , Image& img + ) +{ + read_and_convert_image( filename + , img + , png_tag() + ); +} + +/// \ingroup PNG_IO +/// \brief Saves the view to a png file specified by the given png image file name. +/// Triggers a compile assert if the view color space and channel depth are not supported by the PNG 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 png_write_view( const String& filename + , const View& view + ) +{ + write_view( filename + , view + , png_tag() + ); +} + +} // namespace gil +} // namespace boost + +#endif diff --git a/boost/gil/extension/io/png/read.hpp b/boost/gil/extension/io/png/read.hpp new file mode 100644 index 0000000000..32bbd7e01b --- /dev/null +++ b/boost/gil/extension/io/png/read.hpp @@ -0,0 +1,43 @@ +/* + Copyright 2007-2008 Christian Henning + 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_PNG_READ_HPP +#define BOOST_GIL_EXTENSION_IO_PNG_READ_HPP + +#define BOOST_GIL_EXTENSION_IO_PNG_READ_ENABLED + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file +/// \brief +/// \author Christian Henning \n +/// +/// \date 2007-2008 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +#include <boost/gil/extension/io/png/tags.hpp> +#include <boost/gil/extension/io/png/detail/supported_types.hpp> +#include <boost/gil/extension/io/png/detail/read.hpp> +#include <boost/gil/extension/io/png/detail/scanline_read.hpp> + +#include <boost/gil/io/get_reader.hpp> +#include <boost/gil/io/make_backend.hpp> +#include <boost/gil/io/make_reader.hpp> +#include <boost/gil/io/make_dynamic_image_reader.hpp> +#include <boost/gil/io/make_scanline_reader.hpp> + +#include <boost/gil/io/read_image.hpp> +#include <boost/gil/io/read_view.hpp> +#include <boost/gil/io/read_image_info.hpp> +#include <boost/gil/io/read_and_convert_image.hpp> +#include <boost/gil/io/read_and_convert_view.hpp> + +#include <boost/gil/io/scanline_read_iterator.hpp> + +#endif diff --git a/boost/gil/extension/io/png/tags.hpp b/boost/gil/extension/io/png/tags.hpp new file mode 100644 index 0000000000..79e3b489a0 --- /dev/null +++ b/boost/gil/extension/io/png/tags.hpp @@ -0,0 +1,844 @@ +/* + Copyright 2007-2008 Christian Henning, Andreas Pokorny, 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_PNG_TAGS_HPP +#define BOOST_GIL_EXTENSION_IO_PNG_TAGS_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file +/// \brief +/// \author Christian Henning, Andreas Pokorny, Lubomir Bourdev \n +/// +/// \date 2007-2008 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +#ifdef BOOST_GIL_IO_PNG_FLOATING_POINT_SUPPORTED +#ifdef BOOST_GIL_IO_PNG_FIXED_POINT_SUPPORTED +# error "Cannot set both symbols" +#endif // BOOST_GIL_IO_PNG_FIXED_POINT_SUPPORTED +#endif // BOOST_GIL_IO_PNG_FLOATING_POINT_SUPPORTED + +#ifndef BOOST_GIL_EXTENSION_IO_PNG_C_LIB_COMPILED_AS_CPLUSPLUS + extern "C" { +#endif + #include <png.h> +#ifndef BOOST_GIL_EXTENSION_IO_PNG_C_LIB_COMPILED_AS_CPLUSPLUS + } +#endif + +#ifndef BOOST_GIL_EXTENSION_IO_ZLIB_C_LIB_COMPILED_AS_CPLUSPLUS + extern "C" { +#endif + #include <zlib.h> +#ifndef BOOST_GIL_EXTENSION_IO_ZLIB_C_LIB_COMPILED_AS_CPLUSPLUS + } +#endif + +#if PNG_LIBPNG_VER_MAJOR == 1 +#if PNG_LIBPNG_VER_MINOR <= 4 +#define BOOST_GIL_IO_PNG_1_4_OR_LOWER +#endif // PNG_LIBPNG_VER_MAJOR == 1 +#endif // PNG_LIBPNG_VER_MINOR <= 4 + +#include <string> +#include <vector> + +#include <boost/gil/io/base.hpp> + +namespace boost { namespace gil { + +/// Defines png tag. +struct png_tag : format_tag {}; + +/// see http://en.wikipedia.org/wiki/Portable_Network_Graphics for reference + +/// Defines type for image width property. +struct png_image_width : property_base< png_uint_32 > {}; + +/// Defines type for image height property. +struct png_image_height : property_base< png_uint_32 > {}; + +/// Defines type for interlace method property. +struct png_interlace_method : property_base< int > {}; + +/// Defines type for filter method property. +struct png_filter_method : property_base< int > {}; + +/// Defines type for bit depth method property. +struct png_bitdepth : property_base< int > {}; + +/// Defines type for bit depth method property. +struct png_color_type : property_base< int > {}; + +/// Defines type for number of channels property. +struct png_num_channels : property_base< png_byte > {}; + +#ifdef BOOST_GIL_IO_PNG_FLOATING_POINT_SUPPORTED + + /// Defines type for CIE chromacities property. + struct png_chromacities_type : property_base< double > {}; + + /// Defines type for gamma correction property. + struct png_gamma : property_base< double > {}; + + /// Defines type for physical scale unit property. + struct png_unit : property_base< int > {}; + + /// Defines type for physical scale property. + struct png_scale : property_base< double > {}; + +#else + /// Defines type for CIE chromacities property. + struct png_chromacities_type : property_base< png_fixed_point > {}; + + /// Defines type for gamma correction property. + struct png_gamma : property_base< png_fixed_point > {}; + + /// Defines type for physical scale unit property. + struct png_unit : property_base< int > {}; + +#ifdef BOOST_GIL_IO_PNG_FIXED_POINT_SUPPORTED + /// Defines type for physical scale property. + struct png_scale : property_base< png_fixed_point > {}; +#else + /// Defines type for physical scale property. + struct png_scale : property_base< std::string > {}; +#endif // BOOST_GIL_IO_PNG_FIXED_POINT_SUPPORTED + +#endif // BOOST_GIL_IO_PNG_FLOATING_POINT_SUPPORTED + +/// Returns image resolution in pixels per meter, from pHYs chunk data. +struct png_pixels_per_meter : property_base< png_uint_32 > {}; + +/// Defines type for ICC profile name property. +struct png_ICC_name : property_base< std::string > {}; +/// Defines type for ICC profile property. +#if PNG_LIBPNG_VER_MINOR >= 5 +struct png_ICC_profile : property_base< std:: vector <uint8_t> > {}; +#else +struct png_ICC_profile : property_base< std:: vector <char> > {}; +#endif +/// Defines type for ICC profile length property. +struct png_ICC_profile_length : property_base< png_uint_32 > {}; +/// Defines type for ICC compression property. +struct png_ICC_compression_type : property_base< int > {}; + +/// Defines type for rendering intent property. +struct png_intent : property_base< int > {}; + +/// Defines type for color palette property. +struct png_color_palette : property_base< std::vector< png_color > > {}; +/// Defines type for number of colors property. +struct png_num_palette : property_base< int > {}; + +/// Defines type for background property. +struct png_background : property_base< png_color_16 > {}; + +/// Defines type for histogram property. +struct png_histrogram : property_base< std::vector< png_uint_16 > > {}; + +/// Defines type for screen offset property. +struct png_offset : property_base< png_int_32 > {}; +/// Defines type for screen offset type property. +struct png_offset_type : property_base< int > {}; + +/// Defines type pixel calibration for property. +struct png_CAL : property_base< std::string > {}; +/// Defines type for pixel calibration parameters property. +struct png_CAL_params : property_base< std::vector< std::string > > {}; +/// Defines type for pixel calibration x property. +struct png_CAL_X : property_base< png_int_32 > {}; +/// Defines type for pixel calibration type property. +struct png_CAL_type : property_base< int > {}; +/// Defines type for number of pixel calibration properties. +struct png_CAL_nparam : property_base< int > {}; + +/// Defines type for physical resolution property. +struct png_resolution : property_base< png_uint_32 > {}; +/// Defines type for physical resolution unit property. +struct png_unit_type : property_base< int > {}; + +/// Defines type for significant bits property. +struct png_significant_bits : property_base< png_color_8 > {}; + +/// Helper structure for reading text property. +struct gil_io_png_text +{ + /// Compression type + int _compression; + // Key + std::string _key; + /// Text + std::string _text; +}; + +/// Defines type for text property. +struct png_text_ : property_base< std::vector< gil_io_png_text > > {}; +/// Defines type for number of text property. +struct png_num_text : property_base< int > {}; + +/// Defines type for modification time property. +struct png_mod_time : property_base< png_time > {}; + +/// Defines type for transparency data property. +struct png_trans : property_base< std::vector< png_byte > > {}; +/// Defines type for number of transparency data property. +struct png_num_trans : property_base< int > {}; +/// Defines type for transparency data values property. +struct png_trans_values : property_base< std::vector< png_color_16 > > {}; + +/// Defines type for png function return type. +struct png_return_value : property_base< png_uint_32 > {}; + +//////////////////////// +// Write properties +//////////////////////// + +// relates to info_ptr->compression_type +struct png_compression_type : property_base< png_byte > +{ + static const type default_value = PNG_COMPRESSION_TYPE_BASE; +}; + +// compression level - default values taken from libpng manual. +// Look for png_set_compression_level +struct png_compression_level : property_base< int > +{ + static const type default_value = 3; +}; + +struct png_compression_mem_level : property_base< int > +{ + static const type default_value = MAX_MEM_LEVEL; +}; + +struct png_compression_strategy : property_base< int > +{ + static const type default_value = Z_DEFAULT_STRATEGY; +}; + +struct png_compression_window_bits : property_base< int > +{ + static const type default_value = 9; +}; + +struct png_compression_method : property_base< int > +{ + static const type default_value = 8; +}; + +struct png_compression_buffer_size : property_base< int > +{ + static const type default_value = 8192; +}; + +// dithering +struct png_dithering_palette : property_base< std::vector< png_color > > +{}; + +struct png_dithering_num_palette : property_base< int > +{ + static const type default_value = 0; +}; + +struct png_dithering_maximum_colors : property_base< int > +{ + static const type default_value = 0; +}; + +struct png_dithering_histogram : property_base< std::vector< png_uint_16 > > +{}; + +struct png_full_dither : property_base< int > +{ + static const type default_value = 0; +}; + +// filter +struct png_filter : property_base< int > +{ + static const type default_value = 0; +}; + +// invert mono +struct png_invert_mono : property_base< bool > +{ + static const type default_value = false; +}; + +// true bits +struct png_true_bits : property_base< std::vector< png_color_8 > > +{}; + +// sRGB Intent +struct png_srgb_intent : property_base< int > +{ + static const type default_value = 0; +}; + +// strip alpha +struct png_strip_alpha : property_base< bool > +{ + static const type default_value = false; +}; + +struct png_swap_alpha : property_base< bool > +{ + static const type default_value = false; +}; + + +/// PNG info base class. Containing all header information both for reading and writing. +/// +/// This base structure was created to avoid code doubling. +struct png_info_base +{ + /// Default constructor + png_info_base() + : _width ( 0 ) + , _height( 0 ) + + , _bit_depth ( 0 ) + , _color_type ( 0 ) + , _interlace_method ( PNG_INTERLACE_NONE ) + , _compression_method( PNG_COMPRESSION_TYPE_DEFAULT ) + , _filter_method ( PNG_FILTER_TYPE_DEFAULT ) + + , _num_channels( 0 ) + +#ifdef BOOST_GIL_IO_PNG_FLOATING_POINT_SUPPORTED + , _valid_cie_colors( 0 ) + , _white_x ( 0.0 ) + , _white_y ( 0.0 ) + , _red_x ( 0.0 ) + , _red_y ( 0.0 ) + , _green_x ( 0.0 ) + , _green_y ( 0.0 ) + , _blue_x ( 0.0 ) + , _blue_y ( 0.0 ) + + , _valid_file_gamma( 0 ) + , _file_gamma ( 1.0 ) +#else + , _valid_cie_colors( 0 ) + , _white_x ( 0 ) + , _white_y ( 0 ) + , _red_x ( 0 ) + , _red_y ( 0 ) + , _green_x ( 0 ) + , _green_y ( 0 ) + , _blue_x ( 0 ) + , _blue_y ( 0 ) + + , _valid_file_gamma( 0 ) + , _file_gamma ( 1 ) +#endif // BOOST_GIL_IO_PNG_FLOATING_POINT_SUPPORTED + + , _valid_icc_profile ( 0 ) + , _icc_name ( ) + , _iccp_compression_type( PNG_COMPRESSION_TYPE_BASE ) + , _profile ( ) + , _profile_length ( 0 ) + + , _valid_intent( 0 ) + , _intent ( 0 ) + + , _valid_palette( 0 ) + , _palette ( ) + , _num_palette ( 0 ) + + , _valid_background( 0 ) + , _background ( ) + + , _valid_histogram( 0 ) + , _histogram ( ) + + , _valid_offset ( 0 ) + , _offset_x ( 0 ) + , _offset_y ( 0 ) + , _off_unit_type( PNG_OFFSET_PIXEL ) + + , _valid_pixel_calibration( 0 ) + , _purpose ( ) + , _X0 ( 0 ) + , _X1 ( 0 ) + , _cal_type ( 0 ) + , _num_params ( 0 ) + , _units ( ) + , _params ( ) + + , _valid_resolution( 0 ) + , _res_x ( 0 ) + , _res_y ( 0 ) + , _phy_unit_type ( PNG_RESOLUTION_UNKNOWN ) + + , _pixels_per_meter( 0 ) + + , _valid_significant_bits( 0 ) + , _sig_bits ( ) + + , _valid_scale_factors( 0 ) + , _scale_unit ( PNG_SCALE_UNKNOWN ) +#ifdef BOOST_GIL_IO_PNG_FLOATING_POINT_SUPPORTED + , _scale_width ( 0.0 ) + , _scale_height( 0.0 ) +#else +#ifdef BOOST_GIL_IO_PNG_FIXED_POINT_SUPPORTED + , _scale_width ( 0 ) + , _scale_height( 0 ) +#else + , _scale_width () + , _scale_height() +#endif // BOOST_GIL_IO_PNG_FIXED_POINT_SUPPORTED +#endif // BOOST_GIL_IO_PNG_FLOATING_POINT_SUPPORTED + + , _valid_text( 0 ) + , _text ( ) + , _num_text ( 0 ) + + , _valid_modification_time( 0 ) + , _mod_time ( ) + + , _valid_transparency_factors( 0 ) + , _trans ( ) + , _num_trans ( 0 ) + , _trans_values ( ) + {} + + /// The image width. + png_image_width::type _width; + /// The image height. + png_image_height::type _height; + + /// The bit depth per channel. + png_bitdepth::type _bit_depth; + /// The color space type. + png_color_type::type _color_type; + /// The interlace methos. + png_interlace_method::type _interlace_method; + /// The compression method. + png_compression_method::type _compression_method; + /// The filer method. + png_filter_method::type _filter_method; + + /// The number of channels. + png_num_channels::type _num_channels; + + // CIE chromacities + /// The return value when reading CIE chromacities. + png_return_value::type _valid_cie_colors; + /// The white x value. + png_chromacities_type::type _white_x; + /// The white y value. + png_chromacities_type::type _white_y; + /// The red x value. + png_chromacities_type::type _red_x; + /// The red y value. + png_chromacities_type::type _red_y; + /// The green x value. + png_chromacities_type::type _green_x; + /// The green y value. + png_chromacities_type::type _green_y; + /// The blue x value. + png_chromacities_type::type _blue_x; + /// The blue y value. + png_chromacities_type::type _blue_y; + + // Gamma Value + /// The return value when reading gamma value. + png_return_value::type _valid_file_gamma; + /// The file gamma value. + png_gamma::type _file_gamma; + + // Embedded ICC profile + /// The return value when reading ICC profile. + png_return_value::type _valid_icc_profile; + /// The ICC name. + png_ICC_name::type _icc_name; + /// The icc compression type. + png_ICC_compression_type::type _iccp_compression_type; + /// The ICC profile. + png_ICC_profile::type _profile; + /// The ICC profile length. + png_ICC_profile_length::type _profile_length; + + // Rendering intent + /// The return value when reading rendering intent. + png_return_value::type _valid_intent; + /// The rendering intent value. + png_intent::type _intent; + + // Image palette + /// The return value when reading image palette. + png_return_value::type _valid_palette; + /// The color palette. + png_color_palette::type _palette; + /// The number of colors in the palettes. + png_num_palette::type _num_palette; + + // Background + /// The return value when reading background. + png_return_value::type _valid_background; + /// The background color. + png_background::type _background; + + // Histogram + /// The return value when reading histogram. + png_return_value::type _valid_histogram; + /// The histogram. + png_histrogram::type _histogram; + + // Screen offsets + /// The return value when reading screen offsets. + png_return_value::type _valid_offset; + /// The x offset. + png_offset::type _offset_x; + /// The y offset. + png_offset::type _offset_y; + /// The offset unit. + png_offset_type::type _off_unit_type; + + // Pixel Calibration + /// The return value when reading pixel calibration. + png_return_value::type _valid_pixel_calibration; + /// The purpose. + png_CAL::type _purpose; + /// The x_0 value. + png_CAL_X::type _X0; + /// The x_1 value. + png_CAL_X::type _X1; + /// The calibration type. + png_CAL_type::type _cal_type; + /// The number of calibration parameters. + png_CAL_nparam::type _num_params; + /// The calibration unit type. + png_CAL::type _units; + /// The calibration parameters. + png_CAL_params::type _params; + + // Physical resolution + /// The return value when reading physical resolution properties. + png_return_value::type _valid_resolution; + /// The x physical resolution. + png_resolution::type _res_x; + /// The y physical resolution. + png_resolution::type _res_y; + /// The physical resolution unit. + png_unit_type::type _phy_unit_type; + + /// The Image resolution in pixels per meter. + png_pixels_per_meter::type _pixels_per_meter; + + // Number of significant bits + /// The return value when reading significant bits. + png_return_value::type _valid_significant_bits; + /// The significant bits. + png_significant_bits::type _sig_bits; + + // Scale Factors + /// The return value when reading scale factors. + png_return_value::type _valid_scale_factors; + /// The scaling unit. + png_unit::type _scale_unit; + /// The scaling width. + png_scale::type _scale_width; + /// The scaling height. + png_scale::type _scale_height; + + // Comments information + /// The return value when reading image comments. + png_return_value::type _valid_text; + /// The comments. + png_text_::type _text; + /// The number of comments. + png_num_text::type _num_text; + + // Last modification time + /// The return value when reading modification time. + png_return_value::type _valid_modification_time; + /// The modification time. + png_mod_time::type _mod_time; + + // Transparency data + /// The return value when reading transparency data. + png_return_value::type _valid_transparency_factors; + /// The transparency data. + png_trans::type _trans; + /// The number of transparency data. + png_num_trans::type _num_trans; + /// The transparency data values. + png_trans_values::type _trans_values; +}; + +/// Read information for png images. +/// +/// The structure is returned when using read_image_info. +template<> +struct image_read_info< png_tag > : public png_info_base +{ + /// Default constructor. + image_read_info< png_tag >() + : png_info_base() + {} +}; + +/// PNG settings base class. +/// +/// This base structure was created to avoid code doubling. +struct png_read_settings_base +{ + /// Default Constructor. + png_read_settings_base() + { + _read_cie_chromacities = false; + _read_file_gamma = false; + _read_icc_profile = false; + _read_intent = false; + _read_palette = false; + _read_background = false; + _read_histogram = false; + _read_screen_offsets = false; + _read_pixel_calibration = false; + _read_physical_resolution = false; + _read_pixels_per_meter = false; + _read_number_of_significant_bits = false; + _read_scale_factors = false; + _read_comments = false; + _read_last_modification_time = false; + _read_transparency_data = false; + } + + /// Helper function to enabling reading all png properties. + void set_read_members_true() + { + _read_cie_chromacities = true; + _read_file_gamma = true; + _read_icc_profile = true; + _read_intent = true; + _read_palette = true; + _read_background = true; + _read_histogram = true; + _read_screen_offsets = true; + _read_pixel_calibration = true; + _read_physical_resolution = true; + _read_pixels_per_meter = true; + _read_number_of_significant_bits = true; + _read_scale_factors = true; + _read_comments = true; + _read_last_modification_time = true; + _read_transparency_data = true; + } + + /// Enable reading CIE chromacities. + bool _read_cie_chromacities; + /// Enable reading file gamma. + bool _read_file_gamma; + /// Enable reading ICC profile. + bool _read_icc_profile; + /// Enable reading rendering intent. + bool _read_intent; + /// Enable reading color palette. + bool _read_palette; + /// Enable reading background color. + bool _read_background; + /// Enable reading histogram. + bool _read_histogram; + /// Enable reading screen offsets. + bool _read_screen_offsets; + /// Enable reading pixel calibration. + bool _read_pixel_calibration; + /// Enable reading physical resolution. + bool _read_physical_resolution; + /// Enable reading pixels per meter information. + bool _read_pixels_per_meter; + /// Enable reading significant bits. + bool _read_number_of_significant_bits; + /// Enable reading scaling factors. + bool _read_scale_factors; + /// Enable reading comments. + bool _read_comments; + /// Enable reading modification time. + bool _read_last_modification_time; + /// Enable reading transparency data. + bool _read_transparency_data; +}; + +#ifdef BOOST_GIL_IO_PNG_FLOATING_POINT_SUPPORTED + +/// Read settings for png images. +/// +/// The structure can be used for all read_xxx functions, except read_image_info. +template<> +struct image_read_settings< png_tag > : public image_read_settings_base + , public png_read_settings_base +{ + /// Default Constructor + image_read_settings< png_tag >() + : image_read_settings_base() + , png_read_settings_base() + , _screen_gamma( 1.0 ) + {} + + /// Constructor + /// \param top_left Top left coordinate for reading partial image. + /// \param dim Dimensions for reading partial image. + /// \param gamma Screen gamma value. + image_read_settings( const point_t& top_left + , const point_t& dim + , const bool apply_screen_gamma = false + , const png_gamma::type& screen_gamma = 1.0 + ) + : image_read_settings_base( top_left + , dim + ) + , png_read_settings_base() + , _apply_screen_gamma( apply_screen_gamma ) + , _screen_gamma( screen_gamma ) + {} + + /// Apply screen gamma value. + bool _apply_screen_gamma; + /// The screen gamma value. + png_gamma::type _screen_gamma; +}; + +#else + +/// Read settings for png images. +/// +/// The structure can be used for all read_xxx functions, except read_image_info. +template<> +struct image_read_settings< png_tag > : public image_read_settings_base + , public png_read_settings_base +{ + /// Default Constructor. + image_read_settings< png_tag >() + : image_read_settings_base() + , png_read_settings_base() + , _apply_screen_gamma( false ) + , _screen_gamma ( 2 ) + {} + + image_read_settings( const point_t& top_left + , const point_t& dim + ) + : image_read_settings_base( top_left + , dim + ) + , png_read_settings_base() + , _apply_screen_gamma( false ) + , _screen_gamma ( 2 ) + {} + + /// Apply screen gamma value. + bool _apply_screen_gamma; + /// The screen gamma value. + png_gamma::type _screen_gamma; +}; +#endif + +/// Write information for png images. +/// +/// The structure can be used for write_view() function. +template<> +struct image_write_info< png_tag > : public png_info_base +{ + image_write_info( const png_compression_type::type compression_type = png_compression_type::default_value + , const png_compression_level::type compression_level = png_compression_level::default_value + , const png_compression_mem_level::type compression_mem_level = png_compression_mem_level::default_value + , const png_compression_strategy::type compression_strategy = png_compression_strategy::default_value + , const png_compression_window_bits::type compression_window_bits = png_compression_window_bits::default_value + , const png_compression_method::type compression_method = png_compression_method::default_value + , const png_compression_buffer_size::type compression_buffer_size = png_compression_buffer_size::default_value + , const png_dithering_num_palette::type num_palette = png_dithering_num_palette::default_value + , const png_dithering_maximum_colors::type maximum_colors = png_dithering_maximum_colors::default_value + , const png_full_dither::type full_dither = png_full_dither::default_value + , const png_filter::type filter = png_filter::default_value + , const png_invert_mono::type invert_mono = png_invert_mono::default_value + , const png_srgb_intent::type srgb_intent = png_srgb_intent::default_value + , const png_strip_alpha::type strip_alpha = png_strip_alpha::default_value + , const png_swap_alpha::type swap_alpha = png_swap_alpha::default_value + ) + : png_info_base() + , _compression_type( compression_type ) + , _compression_level( compression_level ) + , _compression_mem_level( compression_mem_level ) + , _compression_strategy( compression_strategy ) + , _compression_window_bits( compression_window_bits ) + , _compression_method( compression_method ) + , _compression_buffer_size( compression_buffer_size ) + + , _set_dithering( false ) + , _dithering_palette() + , _dithering_num_palette( num_palette ) + , _dithering_maximum_colors( maximum_colors ) + , _dithering_histogram() + , _full_dither( full_dither ) + + , _set_filter( false ) + , _filter( filter ) + + , _invert_mono( invert_mono ) + + , _set_true_bits( false ) + , _true_bits() + + , _set_srgb_intent( false ) + , _srgb_intent( srgb_intent ) + + , _strip_alpha( strip_alpha ) + + , _swap_alpha( swap_alpha ) + {} + + // compression stuff + png_compression_type::type _compression_type; + png_compression_level::type _compression_level; + png_compression_mem_level::type _compression_mem_level; + png_compression_strategy::type _compression_strategy; + png_compression_window_bits::type _compression_window_bits; + png_compression_method::type _compression_method; + png_compression_buffer_size::type _compression_buffer_size; + + // png_set_dither + bool _set_dithering; + png_dithering_palette::type _dithering_palette; + png_dithering_num_palette::type _dithering_num_palette; + png_dithering_maximum_colors::type _dithering_maximum_colors; + png_dithering_histogram::type _dithering_histogram; + png_full_dither::type _full_dither; + + //png_set_filter + bool _set_filter; + png_filter::type _filter; + + // png_set_invert_mono + png_invert_mono::type _invert_mono; + + // png_set_sBIT + bool _set_true_bits; + png_true_bits::type _true_bits; + + // png_set_sRGB + bool _set_srgb_intent; + png_srgb_intent::type _srgb_intent; + + // png_set_strip_alpha + png_strip_alpha::type _strip_alpha; + + // png_set_swap_alpha + png_swap_alpha::type _swap_alpha; + +}; + +} // namespace gil +} // namespace boost + +#endif diff --git a/boost/gil/extension/io/png/write.hpp b/boost/gil/extension/io/png/write.hpp new file mode 100644 index 0000000000..47d2a8ae78 --- /dev/null +++ b/boost/gil/extension/io/png/write.hpp @@ -0,0 +1,31 @@ +/* + Copyright 2007-2008 Christian Henning + 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_PNG_WRITE_HPP +#define BOOST_GIL_EXTENSION_IO_PNG_WRITE_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file +/// \brief +/// \author Christian Henning \n +/// +/// \date 2007-2008 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +#include <boost/gil/extension/io/png/tags.hpp> +#include <boost/gil/extension/io/png/detail/supported_types.hpp> +#include <boost/gil/extension/io/png/detail/write.hpp> + +#include <boost/gil/io/make_writer.hpp> +#include <boost/gil/io/make_dynamic_image_writer.hpp> + +#include <boost/gil/io/write_view.hpp> + +#endif diff --git a/boost/gil/extension/io/png_dynamic_io.hpp b/boost/gil/extension/io/png_dynamic_io.hpp deleted file mode 100644 index a3a25a97f4..0000000000 --- a/boost/gil/extension/io/png_dynamic_io.hpp +++ /dev/null @@ -1,141 +0,0 @@ -/* - Copyright 2005-2007 Adobe Systems Incorporated - - 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). - - See http://opensource.adobe.com/gil for most recent version including documentation. -*/ - -/*************************************************************************************************/ - -#ifndef GIL_PNG_DYNAMIC_IO_H -#define GIL_PNG_DYNAMIC_IO_H - -/// \file -/// \brief Support for reading and writing PNG files -/// Requires libpng and zlib! -/// -/// \author Hailin Jin and Lubomir Bourdev \n -/// Adobe Systems Incorporated -/// \date 2005-2007 \n Last updated June 10, 2006 -// -// We are currently providing the following functions: -// template <typename Images> void png_read_image(const char*,any_image<Images>&) -// template <typename Images> void png_read_image(FILE*,any_image<Images>&,std::size_t) -// template <typename Views> void png_write_view(const char*,const any_image_view<View>&) -// template <typename Views> void png_write_view(FILE*,const any_image_view<View>&) - - -#include <string> -#include <stdio.h> -#include <boost/mpl/bool.hpp> -#include <boost/shared_ptr.hpp> -#include "../dynamic_image/dynamic_image_all.hpp" -#include "io_error.hpp" -#include "png_io.hpp" -#include "png_io_private.hpp" -#include "dynamic_io.hpp" - -namespace boost { namespace gil { - -namespace detail { - -struct png_write_is_supported { - template<typename View> struct apply - : public mpl::bool_<png_write_support<View>::is_supported> {}; -}; - -class png_writer_dynamic : public png_writer { -public: - png_writer_dynamic(FILE* file ) : png_writer(file) {} - png_writer_dynamic(const char* filename) : png_writer(filename){} - - template <typename Views> - void write_view(const any_image_view<Views>& runtime_view) { - dynamic_io_fnobj<png_write_is_supported, png_writer> op(this); - apply_operation(runtime_view,op); - } -}; - -class png_type_format_checker { - int _bit_depth; - int _color_type; -public: - png_type_format_checker(int bit_depth_in,int color_type_in) : - _bit_depth(bit_depth_in),_color_type(color_type_in) {} - template <typename Image> - bool apply() { - return png_read_support<typename Image::view_t>::bit_depth==_bit_depth && - png_read_support<typename Image::view_t>::color_type==_color_type; - } -}; - -struct png_read_is_supported { - template<typename View> struct apply - : public mpl::bool_<png_read_support<View>::is_supported> {}; -}; - -class png_reader_dynamic : public png_reader { -public: - png_reader_dynamic(FILE* file) : png_reader(file) {} - png_reader_dynamic(const char* filename) : png_reader(filename){} - - template <typename Images> - void read_image(any_image<Images>& im) { - png_uint_32 width, height; - int bit_depth, color_type, interlace_type; - png_get_IHDR(_png_ptr, _info_ptr, - &width, &height,&bit_depth,&color_type,&interlace_type, - NULL, NULL); - if (!construct_matched(im,png_type_format_checker(bit_depth,color_type))) { - io_error("png_reader_dynamic::read_image(): no matching image type between those of the given any_image and that of the file"); - } else { - im.recreate(width,height); - dynamic_io_fnobj<png_read_is_supported, png_reader> op(this); - apply_operation(view(im),op); - } - } -}; - -} // namespace detail - -/// \ingroup PNG_IO -/// \brief reads a PNG image into a run-time instantiated image -/// Opens the given png file name, selects the first type in Images whose color space and channel are compatible to those of the image file -/// and creates a new image of that type with the dimensions specified by the image file. -/// Throws std::ios_base::failure if none of the types in Images are compatible with the type on disk. -template <typename Images> -inline void png_read_image(const char* filename,any_image<Images>& im) { - detail::png_reader_dynamic m(filename); - m.read_image(im); -} - -/// \ingroup PNG_IO -/// \brief reads a PNG image into a run-time instantiated image -template <typename Images> -inline void png_read_image(const std::string& filename,any_image<Images>& im) { - png_read_image(filename.c_str(),im); -} - -/// \ingroup PNG_IO -/// \brief Saves the currently instantiated view to a png file specified by the given png image file name. -/// Throws std::ios_base::failure if the currently instantiated view type is not supported for writing by the I/O extension -/// or if it fails to create the file. -template <typename Views> -inline void png_write_view(const char* filename,const any_image_view<Views>& runtime_view) { - detail::png_writer_dynamic m(filename); - m.write_view(runtime_view); -} - -/// \ingroup PNG_IO -/// \brief Saves the currently instantiated view to a png file specified by the given png image file name. -template <typename Views> -inline void png_write_view(const std::string& filename,const any_image_view<Views>& runtime_view) { - png_write_view(filename.c_str(),runtime_view); -} - -} } // namespace boost::gil - -#endif diff --git a/boost/gil/extension/io/png_io.hpp b/boost/gil/extension/io/png_io.hpp deleted file mode 100644 index 9b57cebb86..0000000000 --- a/boost/gil/extension/io/png_io.hpp +++ /dev/null @@ -1,214 +0,0 @@ -/* - Copyright 2005-2007 Adobe Systems Incorporated - - 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). - - See http://opensource.adobe.com/gil for most recent version including documentation. -*/ - -/*************************************************************************************************/ - -#ifndef GIL_PNG_IO_H -#define GIL_PNG_IO_H - -/// \file -/// \brief Support for reading and writing PNG files -/// Requires libpng and zlib! -// -// We are currently providing the following functions: -// point2<std::ptrdiff_t> png_read_dimensions(const char*) -// template <typename View> void png_read_view(const char*,const View&) -// template <typename View> void png_read_image(const char*,image<View>&) -// template <typename View> void png_write_view(const char*,const View&) -// template <typename View> struct png_read_support; -// template <typename View> struct png_write_support; -// -/// \author Hailin Jin and Lubomir Bourdev \n -/// Adobe Systems Incorporated -/// \date 2005-2007 \n Last updated September 24, 2006 - -#include <stdio.h> -#include <string> -extern "C" { -#include "png.h" -} -#include <boost/static_assert.hpp> -#include "../../gil_config.hpp" -#include "../../utilities.hpp" -#include "io_error.hpp" -#include "png_io_private.hpp" - -namespace boost { namespace gil { - -/// \ingroup PNG_IO -/// \brief Returns the width and height of the PNG file at the specified location. -/// Throws std::ios_base::failure if the location does not correspond to a valid PNG file -inline point2<std::ptrdiff_t> png_read_dimensions(const char *filename) { - detail::png_reader m(filename); - return m.get_dimensions(); -} - -/// \ingroup PNG_IO -/// \brief Returns the width and height of the PNG file at the specified location. -/// Throws std::ios_base::failure if the location does not correspond to a valid PNG file -inline point2<std::ptrdiff_t> png_read_dimensions(const std::string& filename) { - return png_read_dimensions(filename.c_str()); -} - -/// \ingroup PNG_IO -/// \brief Determines whether the given view type is supported for reading -template <typename View> -struct png_read_support { - BOOST_STATIC_CONSTANT(bool,is_supported= - (detail::png_read_support_private<typename channel_type<View>::type, - typename color_space_type<View>::type>::is_supported)); - BOOST_STATIC_CONSTANT(int,bit_depth= - (detail::png_read_support_private<typename channel_type<View>::type, - typename color_space_type<View>::type>::bit_depth)); - BOOST_STATIC_CONSTANT(int,color_type= - (detail::png_read_support_private<typename channel_type<View>::type, - typename color_space_type<View>::type>::color_type)); - BOOST_STATIC_CONSTANT(bool, value=is_supported); -}; - -/// \ingroup PNG_IO -/// \brief Loads the image specified by the given png image file name into the given view. -/// Triggers a compile assert if the view color space and channel depth are not supported by the PNG library or by the I/O extension. -/// Throws std::ios_base::failure if the file is not a valid PNG 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 View> -inline void png_read_view(const char* filename,const View& view) { - BOOST_STATIC_ASSERT(png_read_support<View>::is_supported); - detail::png_reader m(filename); - m.apply(view); -} - -/// \ingroup PNG_IO -/// \brief Loads the image specified by the given png image file name into the given view. -template <typename View> -inline void png_read_view(const std::string& filename,const View& view) { - png_read_view(filename.c_str(),view); -} - -/// \ingroup PNG_IO -/// \brief Allocates a new image whose dimensions are determined by the given png 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 PNG library or by the I/O extension. -/// Throws std::ios_base::failure if the file is not a valid PNG file, or if its color space or channel depth are not -/// compatible with the ones specified by Image -template <typename Image> -inline void png_read_image(const char* filename,Image& im) { - BOOST_STATIC_ASSERT(png_read_support<typename Image::view_t>::is_supported); - detail::png_reader m(filename); - m.read_image(im); -} - -/// \ingroup PNG_IO -/// \brief Allocates a new image whose dimensions are determined by the given png image file, and loads the pixels into it. -template <typename Image> -inline void png_read_image(const std::string& filename,Image& im) { - png_read_image(filename.c_str(),im); -} - -/// \ingroup PNG_IO -/// \brief Loads the image specified by the given png image file name and color-converts it into the given view. -/// Throws std::ios_base::failure if the file is not a valid PNG file, or if its dimensions don't match the ones of the view. -template <typename View,typename CC> -inline void png_read_and_convert_view(const char* filename,const View& view,CC cc) { - detail::png_reader_color_convert<CC> m(filename,cc); - m.apply(view); -} - -/// \ingroup PNG_IO -/// \brief Loads the image specified by the given png image file name and color-converts it into the given view. -/// Throws std::ios_base::failure if the file is not a valid PNG file, or if its dimensions don't match the ones of the view. -template <typename View> -inline void png_read_and_convert_view(const char* filename,const View& view) { - detail::png_reader_color_convert<default_color_converter> m(filename,default_color_converter()); - m.apply(view); -} - -/// \ingroup PNG_IO -/// \brief Loads the image specified by the given png image file name and color-converts it into the given view. -template <typename View,typename CC> -inline void png_read_and_convert_view(const std::string& filename,const View& view,CC cc) { - png_read_and_convert_view(filename.c_str(),view,cc); -} - -/// \ingroup PNG_IO -/// \brief Loads the image specified by the given png image file name and color-converts it into the given view. -template <typename View> -inline void png_read_and_convert_view(const std::string& filename,const View& view) { - png_read_and_convert_view(filename.c_str(),view); -} - -/// \ingroup PNG_IO -/// \brief Allocates a new image whose dimensions are determined by the given png image file, loads and color-converts the pixels into it. -/// Throws std::ios_base::failure if the file is not a valid PNG file -template <typename Image,typename CC> -inline void png_read_and_convert_image(const char* filename,Image& im,CC cc) { - detail::png_reader_color_convert<CC> m(filename,cc); - m.read_image(im); -} - -/// \ingroup PNG_IO -/// \brief Allocates a new image whose dimensions are determined by the given png image file, loads and color-converts the pixels into it. -/// Throws std::ios_base::failure if the file is not a valid PNG file -template <typename Image> -inline void png_read_and_convert_image(const char* filename,Image& im) { - detail::png_reader_color_convert<default_color_converter> m(filename,default_color_converter()); - m.read_image(im); -} - -/// \ingroup PNG_IO -/// \brief Allocates a new image whose dimensions are determined by the given png image file, loads and color-converts the pixels into it. -template <typename Image,typename CC> -inline void png_read_and_convert_image(const std::string& filename,Image& im,CC cc) { - png_read_and_convert_image(filename.c_str(),im,cc); -} - -/// \ingroup PNG_IO -/// \brief Allocates a new image whose dimensions are determined by the given png image file, loads and color-converts the pixels into it. -template <typename Image> -inline void png_read_and_convert_image(const std::string& filename,Image& im) { - png_read_and_convert_image(filename.c_str(),im); -} - -/// \ingroup PNG_IO -/// \brief Determines whether the given view type is supported for writing -template <typename View> -struct png_write_support { - BOOST_STATIC_CONSTANT(bool,is_supported= - (detail::png_write_support_private<typename channel_type<View>::type, - typename color_space_type<View>::type>::is_supported)); - BOOST_STATIC_CONSTANT(int,bit_depth= - (detail::png_write_support_private<typename channel_type<View>::type, - typename color_space_type<View>::type>::bit_depth)); - BOOST_STATIC_CONSTANT(int,color_type= - (detail::png_write_support_private<typename channel_type<View>::type, - typename color_space_type<View>::type>::color_type)); - BOOST_STATIC_CONSTANT(bool, value=is_supported); -}; - -/// \ingroup PNG_IO -/// \brief Saves the view to a png file specified by the given png image file name. -/// Triggers a compile assert if the view color space and channel depth are not supported by the PNG library or by the I/O extension. -/// Throws std::ios_base::failure if it fails to create the file. -template <typename View> -inline void png_write_view(const char* filename,const View& view) { - BOOST_STATIC_ASSERT(png_write_support<View>::is_supported); - detail::png_writer m(filename); - m.apply(view); -} - -/// \ingroup PNG_IO -/// \brief Saves the view to a png file specified by the given png image file name. -template <typename View> -inline void png_write_view(const std::string& filename,const View& view) { - png_write_view(filename.c_str(),view); -} - -} } // namespace boost::gil - -#endif diff --git a/boost/gil/extension/io/png_io_private.hpp b/boost/gil/extension/io/png_io_private.hpp deleted file mode 100644 index a0ee57be55..0000000000 --- a/boost/gil/extension/io/png_io_private.hpp +++ /dev/null @@ -1,360 +0,0 @@ -/* - Copyright 2005-2007 Adobe Systems Incorporated - - 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). - - See http://stlab.adobe.com/gil for most recent version including documentation. -*/ -/*************************************************************************************************/ - -#ifndef GIL_PNG_IO_PRIVATE_H -#define GIL_PNG_IO_PRIVATE_H - -/// \file -/// \brief Internal support for reading and writing PNG files -/// \author Hailin Jin and Lubomir Bourdev \n -/// Adobe Systems Incorporated -/// \date 2005-2007 \n Last updated August 14, 2007 - -#include <algorithm> -#include <vector> -#include <boost/static_assert.hpp> -#include "../../gil_all.hpp" -#include "io_error.hpp" -#include <png.h> - -namespace boost { namespace gil { - -namespace detail { - -static const std::size_t PNG_BYTES_TO_CHECK = 4; - -// lbourdev: These can be greatly simplified, for example: -template <typename Cs> struct png_color_type {BOOST_STATIC_CONSTANT(int,color_type=0);}; -template<> struct png_color_type<gray_t> { BOOST_STATIC_CONSTANT(int,color_type=PNG_COLOR_TYPE_GRAY); }; -template<> struct png_color_type<rgb_t> { BOOST_STATIC_CONSTANT(int,color_type=PNG_COLOR_TYPE_RGB); }; -template<> struct png_color_type<rgba_t> { BOOST_STATIC_CONSTANT(int,color_type=PNG_COLOR_TYPE_RGBA); }; - -template <typename Channel,typename ColorSpace> struct png_is_supported {BOOST_STATIC_CONSTANT(bool,value=false);}; -template <> struct png_is_supported<bits8,gray_t> {BOOST_STATIC_CONSTANT(bool,value=true);}; -template <> struct png_is_supported<bits8,rgb_t> {BOOST_STATIC_CONSTANT(bool,value=true);}; -template <> struct png_is_supported<bits8,rgba_t> {BOOST_STATIC_CONSTANT(bool,value=true);}; -template <> struct png_is_supported<bits16,gray_t> {BOOST_STATIC_CONSTANT(bool,value=true);}; -template <> struct png_is_supported<bits16,rgb_t> {BOOST_STATIC_CONSTANT(bool,value=true);}; -template <> struct png_is_supported<bits16,rgba_t> {BOOST_STATIC_CONSTANT(bool,value=true);}; - -template <typename Channel> struct png_bit_depth {BOOST_STATIC_CONSTANT(int,bit_depth=sizeof(Channel)*8);}; - -template <typename Channel,typename ColorSpace> -struct png_read_support_private { - BOOST_STATIC_CONSTANT(bool,is_supported=false); - BOOST_STATIC_CONSTANT(int,bit_depth=0); - BOOST_STATIC_CONSTANT(int,color_type=0); -}; -template <> -struct png_read_support_private<bits8,gray_t> { - BOOST_STATIC_CONSTANT(bool,is_supported=true); - BOOST_STATIC_CONSTANT(int,bit_depth=8); - BOOST_STATIC_CONSTANT(int,color_type=PNG_COLOR_TYPE_GRAY); -}; -template <> -struct png_read_support_private<bits8,rgb_t> { - BOOST_STATIC_CONSTANT(bool,is_supported=true); - BOOST_STATIC_CONSTANT(int,bit_depth=8); - BOOST_STATIC_CONSTANT(int,color_type=PNG_COLOR_TYPE_RGB); -}; -template <> -struct png_read_support_private<bits8,rgba_t> { - BOOST_STATIC_CONSTANT(bool,is_supported=true); - BOOST_STATIC_CONSTANT(int,bit_depth=8); - BOOST_STATIC_CONSTANT(int,color_type=PNG_COLOR_TYPE_RGBA); -}; -template <> -struct png_read_support_private<bits16,gray_t> { - BOOST_STATIC_CONSTANT(bool,is_supported=true); - BOOST_STATIC_CONSTANT(int,bit_depth=16); - BOOST_STATIC_CONSTANT(int,color_type=PNG_COLOR_TYPE_GRAY); -}; -template <> -struct png_read_support_private<bits16,rgb_t> { - BOOST_STATIC_CONSTANT(bool,is_supported=true); - BOOST_STATIC_CONSTANT(int,bit_depth=16); - BOOST_STATIC_CONSTANT(int,color_type=PNG_COLOR_TYPE_RGB); -}; -template <> -struct png_read_support_private<bits16,rgba_t> { - BOOST_STATIC_CONSTANT(bool,is_supported=true); - BOOST_STATIC_CONSTANT(int,bit_depth=16); - BOOST_STATIC_CONSTANT(int,color_type=PNG_COLOR_TYPE_RGBA); -}; - -template <typename Channel,typename ColorSpace> -struct png_write_support_private { - BOOST_STATIC_CONSTANT(bool,is_supported=false); - BOOST_STATIC_CONSTANT(int,bit_depth=0); - BOOST_STATIC_CONSTANT(int,color_type=0); -}; -template <> -struct png_write_support_private<bits8,gray_t> { - BOOST_STATIC_CONSTANT(bool,is_supported=true); - BOOST_STATIC_CONSTANT(int,bit_depth=8); - BOOST_STATIC_CONSTANT(int,color_type=PNG_COLOR_TYPE_GRAY); -}; -template <> -struct png_write_support_private<bits8,rgb_t> { - BOOST_STATIC_CONSTANT(bool,is_supported=true); - BOOST_STATIC_CONSTANT(int,bit_depth=8); - BOOST_STATIC_CONSTANT(int,color_type=PNG_COLOR_TYPE_RGB); -}; -template <> -struct png_write_support_private<bits8,rgba_t> { - BOOST_STATIC_CONSTANT(bool,is_supported=true); - BOOST_STATIC_CONSTANT(int,bit_depth=8); - BOOST_STATIC_CONSTANT(int,color_type=PNG_COLOR_TYPE_RGBA); -}; -template <> -struct png_write_support_private<bits16,gray_t> { - BOOST_STATIC_CONSTANT(bool,is_supported=true); - BOOST_STATIC_CONSTANT(int,bit_depth=16); - BOOST_STATIC_CONSTANT(int,color_type=PNG_COLOR_TYPE_GRAY); -}; -template <> -struct png_write_support_private<bits16,rgb_t> { - BOOST_STATIC_CONSTANT(bool,is_supported=true); - BOOST_STATIC_CONSTANT(int,bit_depth=16); - BOOST_STATIC_CONSTANT(int,color_type=PNG_COLOR_TYPE_RGB); -}; -template <> -struct png_write_support_private<bits16,rgba_t> { - BOOST_STATIC_CONSTANT(bool,is_supported=true); - BOOST_STATIC_CONSTANT(int,bit_depth=16); - BOOST_STATIC_CONSTANT(int,color_type=PNG_COLOR_TYPE_RGBA); -}; - -class png_reader : public file_mgr { -protected: - png_structp _png_ptr; - png_infop _info_ptr; - - void init() { - char buf[PNG_BYTES_TO_CHECK]; - // read in some of the signature bytes - io_error_if(fread(buf, 1, PNG_BYTES_TO_CHECK, get()) != detail::PNG_BYTES_TO_CHECK, - "png_check_validity: fail to read file"); - // compare the first PNG_BYTES_TO_CHECK bytes of the signature. - io_error_if(png_sig_cmp((png_bytep)buf, (png_size_t)0, detail::PNG_BYTES_TO_CHECK)!=0, - "png_check_validity: invalid png file"); - - _png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,NULL,NULL,NULL); - io_error_if(_png_ptr==NULL,"png_get_file_size: fail to call png_create_write_struct()"); - // allocate/initialize the image information data - _info_ptr = png_create_info_struct(_png_ptr); - if (_info_ptr == NULL) { - png_destroy_read_struct(&_png_ptr,NULL,NULL); - io_error("png_get_file_size: fail to call png_create_info_struct()"); - } - if (setjmp(png_jmpbuf(_png_ptr))) { - //free all of the memory associated with the png_ptr and info_ptr - png_destroy_read_struct(&_png_ptr, &_info_ptr, NULL); - io_error("png_get_file_size: fail to call setjmp()"); - } - png_init_io(_png_ptr, get()); - png_set_sig_bytes(_png_ptr,PNG_BYTES_TO_CHECK); - png_read_info(_png_ptr, _info_ptr); - if (little_endian() && png_get_bit_depth(_png_ptr,_info_ptr)>8) - png_set_swap(_png_ptr); - } -public: - png_reader(FILE* file ) : file_mgr(file) { init(); } - png_reader(const char* filename) : file_mgr(filename, "rb") { init(); } - - ~png_reader() { - png_destroy_read_struct(&_png_ptr,&_info_ptr,NULL); - } - point2<std::ptrdiff_t> get_dimensions() { - return point2<std::ptrdiff_t>(png_get_image_width(_png_ptr,_info_ptr), - png_get_image_height(_png_ptr,_info_ptr)); - } - template <typename View> - void apply(const View& view) { - png_uint_32 width, height; - int bit_depth, color_type, interlace_type; - png_get_IHDR(_png_ptr, _info_ptr, - &width, &height,&bit_depth,&color_type,&interlace_type, - NULL, NULL); - io_error_if(((png_uint_32)view.width()!=width || (png_uint_32)view.height()!= height), - "png_read_view: input view size does not match PNG file size"); - - if(png_read_support_private<typename channel_type<View>::type, - typename color_space_type<View>::type>::bit_depth!=bit_depth || - png_read_support_private<typename channel_type<View>::type, - typename color_space_type<View>::type>::color_type!=color_type) - io_error("png_read_view: input view type is incompatible with the image type"); - - std::vector<pixel<typename channel_type<View>::type, - layout<typename color_space_type<View>::type> > > row(width); - for(png_uint_32 y=0;y<height;++y) { - png_read_row(_png_ptr,(png_bytep)&row.front(),NULL); - std::copy(row.begin(),row.end(),view.row_begin(y)); - } - png_read_end(_png_ptr,NULL); - } - - template <typename Image> - void read_image(Image& im) { - im.recreate(get_dimensions()); - apply(view(im)); - } -}; - -// This code will be simplified... -template <typename CC> -class png_reader_color_convert : public png_reader { -private: - CC _cc; -public: - png_reader_color_convert(FILE* file ,CC cc_in) : png_reader(file),_cc(cc_in) {} - png_reader_color_convert(FILE* file ) : png_reader(file) {} - png_reader_color_convert(const char* filename,CC cc_in) : png_reader(filename),_cc(cc_in) {} - png_reader_color_convert(const char* filename) : png_reader(filename) {} - template <typename View> - void apply(const View& view) { - png_uint_32 width, height; - int bit_depth, color_type, interlace_type; - png_get_IHDR(_png_ptr, _info_ptr, - &width, &height,&bit_depth,&color_type,&interlace_type, - int_p_NULL, int_p_NULL); - io_error_if(((png_uint_32)view.width()!=width || (png_uint_32)view.height()!= height), - "png_reader_color_convert::apply(): input view size does not match PNG file size"); - switch (color_type) { - case PNG_COLOR_TYPE_GRAY: - switch (bit_depth) { - case 8: { - std::vector<gray8_pixel_t> row(width); - for(png_uint_32 y=0;y<height;++y) { - png_read_row(_png_ptr,(png_bytep)&row.front(),NULL); - std::transform(row.begin(),row.end(),view.row_begin(y),color_convert_deref_fn<gray8_ref_t,typename View::value_type,CC>(_cc)); - } - break; - } - case 16: { - std::vector<gray16_pixel_t> row(width); - for(png_uint_32 y=0;y<height;++y) { - png_read_row(_png_ptr,(png_bytep)&row.front(),NULL); - std::transform(row.begin(),row.end(),view.row_begin(y),color_convert_deref_fn<gray16_ref_t,typename View::value_type,CC>(_cc)); - } - break; - } - default: io_error("png_reader_color_convert::apply(): unknown combination of color type and bit depth"); - } - break; - case PNG_COLOR_TYPE_RGB: - switch (bit_depth) { - case 8: { - std::vector<rgb8_pixel_t> row(width); - for(png_uint_32 y=0;y<height;++y) { - png_read_row(_png_ptr,(png_bytep)&row.front(),NULL); - std::transform(row.begin(),row.end(),view.row_begin(y),color_convert_deref_fn<rgb8_ref_t,typename View::value_type,CC>(_cc)); - } - break; - } - case 16: { - std::vector<rgb16_pixel_t> row(width); - for(png_uint_32 y=0;y<height;++y) { - png_read_row(_png_ptr,(png_bytep)&row.front(),NULL); - std::transform(row.begin(),row.end(),view.row_begin(y),color_convert_deref_fn<rgb16_ref_t,typename View::value_type,CC>(_cc)); - } - break; - } - default: io_error("png_reader_color_convert::apply(): unknown combination of color type and bit depth"); - } - break; - case PNG_COLOR_TYPE_RGBA: - switch (bit_depth) { - case 8: { - std::vector<rgba8_pixel_t> row(width); - for(png_uint_32 y=0;y<height;++y) { - png_read_row(_png_ptr,(png_bytep)&row.front(),NULL); - std::transform(row.begin(),row.end(),view.row_begin(y),color_convert_deref_fn<rgba8_ref_t,typename View::value_type,CC>(_cc)); - } - break; - } - case 16: { - std::vector<rgba16_pixel_t> row(width); - for(png_uint_32 y=0;y<height;++y) { - png_read_row(_png_ptr,(png_bytep)&row.front(),NULL); - std::transform(row.begin(),row.end(),view.row_begin(y),color_convert_deref_fn<rgba16_ref_t,typename View::value_type,CC>(_cc)); - } - break; - } - default: io_error("png_reader_color_convert::apply(): unknown combination of color type and bit depth"); - } - break; - default: io_error("png_reader_color_convert::apply(): unknown color type"); - } - png_read_end(_png_ptr,NULL); - } - template <typename Image> - void read_image(Image& im) { - im.recreate(get_dimensions()); - apply(view(im)); - } -}; - - -class png_writer : public file_mgr { -protected: - png_structp _png_ptr; - png_infop _info_ptr; - - void init() { - _png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,NULL,NULL,NULL); - io_error_if(!_png_ptr,"png_write_initialize: fail to call png_create_write_struct()"); - _info_ptr = png_create_info_struct(_png_ptr); - if (!_info_ptr) { - png_destroy_write_struct(&_png_ptr,NULL); - io_error("png_write_initialize: fail to call png_create_info_struct()"); - } - if (setjmp(png_jmpbuf(_png_ptr))) { - png_destroy_write_struct(&_png_ptr, &_info_ptr); - io_error("png_write_initialize: fail to call setjmp(png_jmpbuf())"); - } - png_init_io(_png_ptr,get()); - } -public: - png_writer(FILE* file ) : file_mgr(file) { init(); } - png_writer(const char* filename) : file_mgr(filename, "wb") { init(); } - - ~png_writer() { - png_destroy_write_struct(&_png_ptr,&_info_ptr); - } - template <typename View> - void apply(const View& view) { - png_set_IHDR(_png_ptr, _info_ptr, view.width(), view.height(), - png_write_support_private<typename channel_type<View>::type, - typename color_space_type<View>::type>::bit_depth, - png_write_support_private<typename channel_type<View>::type, - typename color_space_type<View>::type>::color_type, - PNG_INTERLACE_NONE, - PNG_COMPRESSION_TYPE_DEFAULT,PNG_FILTER_TYPE_DEFAULT); - png_write_info(_png_ptr,_info_ptr); - if (little_endian() && - png_write_support_private<typename channel_type<View>::type, - typename color_space_type<View>::type>::bit_depth>8) - png_set_swap(_png_ptr); - std::vector<pixel<typename channel_type<View>::type, - layout<typename color_space_type<View>::type> > > row(view.width()); - for(int y=0;y<view.height();++y) { - std::copy(view.row_begin(y),view.row_end(y),row.begin()); - png_write_row(_png_ptr,(png_bytep)&row.front()); - } - png_write_end(_png_ptr,_info_ptr); - } -}; - -} // namespace detail -} } // namespace boost::gil - -#endif diff --git a/boost/gil/extension/io/pnm.hpp b/boost/gil/extension/io/pnm.hpp new file mode 100644 index 0000000000..8e69277fce --- /dev/null +++ b/boost/gil/extension/io/pnm.hpp @@ -0,0 +1,25 @@ +/* + Copyright 2008 Christian Henning + 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_PNM_HPP +#define BOOST_GIL_EXTENSION_IO_PNM_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file +/// \brief +/// \author Christian Henning \n +/// +/// \date 2008 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +#include <boost/gil/extension/io/pnm/read.hpp> +#include <boost/gil/extension/io/pnm/write.hpp> + +#endif diff --git a/boost/gil/extension/io/pnm/detail/is_allowed.hpp b/boost/gil/extension/io/pnm/detail/is_allowed.hpp new file mode 100644 index 0000000000..91be3091fa --- /dev/null +++ b/boost/gil/extension/io/pnm/detail/is_allowed.hpp @@ -0,0 +1,60 @@ +/* + Copyright 2009 Christian Henning + 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_PNM_DETAIL_IS_ALLOWED_HPP +#define BOOST_GIL_EXTENSION_IO_PNM_DETAIL_IS_ALLOWED_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file +/// \brief +/// \author Christian Henning \n +/// +/// \date 2008 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +namespace boost { namespace gil { namespace detail { + +template< typename View > +bool is_allowed( const image_read_info< pnm_tag >& info + , mpl::true_ // is read_and_no_convert + ) +{ + pnm_image_type::type asc_type = is_read_supported< typename get_pixel_type< View >::type + , pnm_tag + >::_asc_type; + + pnm_image_type::type bin_type = is_read_supported< typename get_pixel_type< View >::type + , pnm_tag + >::_bin_type; + if( info._type == pnm_image_type::mono_asc_t::value ) + { + // ascii mono images are read gray8_image_t + return ( asc_type == pnm_image_type::gray_asc_t::value ); + } + + + return ( asc_type == info._type + || bin_type == info._type + ); +} + +template< typename View > +bool is_allowed( const image_read_info< pnm_tag >& /* info */ + , mpl::false_ // is read_and_convert + ) +{ + return true; +} + +} // namespace detail +} // namespace gil +} // namespace boost + +#endif diff --git a/boost/gil/extension/io/pnm/detail/read.hpp b/boost/gil/extension/io/pnm/detail/read.hpp new file mode 100644 index 0000000000..5f267ada5e --- /dev/null +++ b/boost/gil/extension/io/pnm/detail/read.hpp @@ -0,0 +1,465 @@ +/* + Copyright 2012 Christian Henning + 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_PNM_DETAIL_READ_HPP +#define BOOST_GIL_EXTENSION_IO_PNM_DETAIL_READ_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file +/// \brief +/// \author Christian Henning \n +/// +/// \date 2012 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +#include <vector> +#include <boost/bind.hpp> +#include <boost/gil.hpp> +#include <boost/gil/extension/io/pnm/tags.hpp> + +#include <boost/gil/io/base.hpp> +#include <boost/gil/io/conversion_policies.hpp> +#include <boost/gil/io/row_buffer_helper.hpp> +#include <boost/gil/io/bit_operations.hpp> +#include <boost/gil/io/reader_base.hpp> +#include <boost/gil/io/device.hpp> +#include <boost/gil/io/typedefs.hpp> + +#include <boost/gil/extension/io/pnm/detail/reader_backend.hpp> +#include <boost/gil/extension/io/pnm/detail/is_allowed.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 + +/// +/// PNM Reader +/// +template< typename Device + , typename ConversionPolicy + > +class reader< Device + , pnm_tag + , ConversionPolicy + > + : public reader_base< pnm_tag + , ConversionPolicy + > + , public reader_backend< Device + , pnm_tag + > +{ + +private: + + typedef reader< Device + , pnm_tag + , ConversionPolicy + > this_t; + + typedef typename ConversionPolicy::color_converter_type cc_t; + +public: + + typedef reader_backend< Device, pnm_tag > backend_t; + +public: + + reader( const Device& io_dev + , const image_read_settings< pnm_tag >& settings + ) + : reader_base< pnm_tag + , ConversionPolicy + >() + , backend_t( io_dev + , settings + ) + {} + + reader( const Device& io_dev + , const cc_t& cc + , const image_read_settings< pnm_tag >& settings + ) + : reader_base< pnm_tag + , ConversionPolicy + >( cc ) + , backend_t( io_dev + , settings + ) + {} + + template<typename View> + void apply( const View& view ) + { + typedef typename is_same< ConversionPolicy + , detail::read_and_no_convert + >::type is_read_and_convert_t; + + io_error_if( !detail::is_allowed< View >( this->_info + , is_read_and_convert_t() + ) + , "Image types aren't compatible." + ); + + switch( this->_info._type ) + { + // reading mono text is reading grayscale but with only two values + case pnm_image_type::mono_asc_t::value: + case pnm_image_type::gray_asc_t::value: + { + this->_scanline_length = this->_info._width; + + read_text_data< gray8_view_t >( view ); + + break; + } + + case pnm_image_type::color_asc_t::value: + { + this->_scanline_length = this->_info._width * num_channels< rgb8_view_t >::value; + + read_text_data< rgb8_view_t >( view ); + + break; + } + + case pnm_image_type::mono_bin_t::value: + { + //gray1_image_t + this->_scanline_length = ( this->_info._width + 7 ) >> 3; + + read_bin_data< gray1_image_t::view_t >( view ); + + break; + } + + case pnm_image_type::gray_bin_t::value: + { + // gray8_image_t + this->_scanline_length = this->_info._width; + + read_bin_data< gray8_view_t >( view ); + + break; + } + + case pnm_image_type::color_bin_t::value: + { + // rgb8_image_t + this->_scanline_length = this->_info._width * num_channels< rgb8_view_t >::value; + + read_bin_data< rgb8_view_t >( view ); + break; + } + } + } + +private: + + template< typename View_Src + , typename View_Dst + > + void read_text_data( const View_Dst& dst ) + { + typedef typename View_Dst::y_coord_t y_t; + + byte_vector_t row( this->_scanline_length ); + + //Skip scanlines if necessary. + for( int y = 0; y < this->_settings._top_left.y; ++y ) + { + read_text_row< View_Src >( dst, row, y, false ); + } + + for( y_t y = 0; y < dst.height(); ++y ) + { + read_text_row< View_Src >( dst, row, y, true ); + } + } + + template< typename View_Src + , typename View_Dst + > + void read_text_row( const View_Dst& dst + , byte_vector_t& row + , typename View_Dst::y_coord_t y + , bool process + ) + { + View_Src src = interleaved_view( this->_info._width + , 1 + , (typename View_Src::value_type*) &row.front() + , this->_scanline_length + ); + + for( uint32_t x = 0; x < this->_scanline_length; ++x ) + { + for( uint32_t k = 0; ; ) + { + int ch = this->_io_dev.getc_unchecked(); + + if( isdigit( ch )) + { + buf[ k++ ] = static_cast< char >( ch ); + } + else if( k ) + { + buf[ k ] = 0; + break; + } + else if( ch == EOF || !isspace( ch )) + { + return; + } + } + + if( process ) + { + int value = atoi( buf ); + + if( this->_info._max_value == 1 ) + { + typedef typename channel_type< typename get_pixel_type< View_Dst >::type >::type channel_t; + + // for pnm format 0 is white + row[x] = ( value != 0 ) + ? typename channel_traits< channel_t >::value_type( 0 ) + : channel_traits< channel_t >::max_value(); + } + else + { + row[x] = static_cast< byte_t >( value ); + } + } + } + + if( process ) + { + // We are reading a gray1_image like a gray8_image but the two pixel_t + // aren't compatible. Though, read_and_no_convert::read(...) wont work. + copy_data< View_Dst + , View_Src >( dst + , src + , y + , typename is_same< View_Dst + , gray1_image_t::view_t + >::type() + ); + } + } + + template< typename View_Dst + , typename View_Src + > + void copy_data( const View_Dst& dst + , const View_Src& src + , typename View_Dst::y_coord_t y + , mpl::true_ // is gray1_view + ) + { + if( this->_info._max_value == 1 ) + { + typename View_Dst::x_iterator it = dst.row_begin( y ); + + for( typename View_Dst::x_coord_t x = 0 + ; x < dst.width() + ; ++x + ) + { + it[x] = src[x]; + } + } + else + { + copy_data( dst + , src + , y + , mpl::false_() + ); + } + } + + template< typename View_Dst + , typename View_Src + > + void copy_data( const View_Dst& view + , const View_Src& src + , typename View_Dst::y_coord_t y + , mpl::false_ // is gray1_view + ) + { + typename View_Src::x_iterator beg = src.row_begin( 0 ) + this->_settings._top_left.x; + typename View_Src::x_iterator end = beg + this->_settings._dim.x; + + this->_cc_policy.read( beg + , end + , view.row_begin( y ) + ); + } + + + template< typename View_Src + , typename View_Dst + > + void read_bin_data( const View_Dst& view ) + { + typedef typename View_Dst::y_coord_t y_t; + typedef typename is_bit_aligned< + typename View_Src::value_type >::type is_bit_aligned_t; + + typedef detail::row_buffer_helper_view< View_Src > rh_t; + rh_t rh( this->_scanline_length, true ); + + typename rh_t::iterator_t beg = rh.begin() + this->_settings._top_left.x; + typename rh_t::iterator_t end = beg + this->_settings._dim.x; + + // For bit_aligned images we need to negate all bytes in the row_buffer + // to make sure that 0 is black and 255 is white. + detail::negate_bits< typename rh_t::buffer_t + , is_bit_aligned_t + > neg; + + detail::swap_half_bytes< typename rh_t::buffer_t + , is_bit_aligned_t + > swhb; + + //Skip scanlines if necessary. + for( y_t y = 0; y < this->_settings._top_left.y; ++y ) + { + this->_io_dev.read( reinterpret_cast< byte_t* >( rh.data() ) + , this->_scanline_length + ); + } + + for( y_t y = 0; y < view.height(); ++y ) + { + this->_io_dev.read( reinterpret_cast< byte_t* >( rh.data() ) + , this->_scanline_length + ); + + neg( rh.buffer() ); + swhb( rh.buffer() ); + + this->_cc_policy.read( beg + , end + , view.row_begin( y ) + ); + } + } + +private: + + char buf[16]; + +}; + + +namespace detail { + +struct pnm_type_format_checker +{ + pnm_type_format_checker( pnm_image_type::type type ) + : _type( type ) + {} + + template< typename Image > + bool apply() + { + typedef is_read_supported< typename get_pixel_type< typename Image::view_t >::type + , pnm_tag + > is_supported_t; + + return is_supported_t::_asc_type == _type + || is_supported_t::_bin_type == _type; + } + +private: + + pnm_image_type::type _type; +}; + +struct pnm_read_is_supported +{ + template< typename View > + struct apply : public is_read_supported< typename get_pixel_type< View >::type + , pnm_tag + > + {}; +}; + +} // namespace detail + +/// +/// PNM Dynamic Image Reader +/// +template< typename Device + > +class dynamic_image_reader< Device + , pnm_tag + > + : public reader< Device + , pnm_tag + , detail::read_and_no_convert + > +{ + typedef reader< Device + , pnm_tag + , detail::read_and_no_convert + > parent_t; + +public: + + dynamic_image_reader( const Device& io_dev + , const image_read_settings< pnm_tag >& settings + ) + : parent_t( io_dev + , settings + ) + {} + + template< typename Images > + void apply( any_image< Images >& images ) + { + detail::pnm_type_format_checker format_checker( this->_info._type ); + + 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::pnm_read_is_supported + , parent_t + > op( this ); + + apply_operation( view( images ) + , op + ); + } + } +}; + +#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) +#pragma warning(pop) +#endif + +} // gil +} // boost + +#endif diff --git a/boost/gil/extension/io/pnm/detail/reader_backend.hpp b/boost/gil/extension/io/pnm/detail/reader_backend.hpp new file mode 100644 index 0000000000..01ab7a0aaa --- /dev/null +++ b/boost/gil/extension/io/pnm/detail/reader_backend.hpp @@ -0,0 +1,192 @@ +/* + Copyright 2012 Christian Henning + 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_PNM_DETAIL_READER_BACKEND_HPP +#define BOOST_GIL_EXTENSION_IO_PNM_DETAIL_READER_BACKEND_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file +/// \brief +/// \author Christian Henning \n +/// +/// \date 2012 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +#include <boost/gil/extension/io/pnm/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 + +/// +/// PNM Backend +/// +template< typename Device > +struct reader_backend< Device + , pnm_tag + > +{ +public: + + typedef pnm_tag format_tag_t; + +public: + + reader_backend( const Device& io_dev + , const image_read_settings< pnm_tag >& settings + ) + : _io_dev ( io_dev ) + , _settings( settings ) + , _info() + + , _scanline_length( 0 ) + { + 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() + { + // read signature + io_error_if( read_char() != 'P', "Invalid PNM signature" ); + + _info._type = read_char() - '0'; + + io_error_if( _info._type < pnm_image_type::mono_asc_t::value || _info._type > pnm_image_type::color_bin_t::value + , "Invalid PNM file (supports P1 to P6)" + ); + + _info._width = read_int(); + _info._height = read_int(); + + if( _info._type == pnm_image_type::mono_asc_t::value || _info._type == pnm_image_type::mono_bin_t::value ) + { + _info._max_value = 1; + } + else + { + _info._max_value = read_int(); + + io_error_if( _info._max_value > 255 + , "Unsupported PNM format (supports maximum value 255)" + ); + } + } + + /// 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( 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( img_dim.y < _info._height ) { io_error( "Supplied image is too small" ); } + } + } + +private: + + // Read a character and skip a comment if necessary. + char read_char() + { + char ch; + + if(( ch = _io_dev.getc() ) == '#' ) + { + // skip comment to EOL + do + { + ch = _io_dev.getc(); + } + while (ch != '\n' && ch != '\r'); + } + + return ch; + } + + unsigned int read_int() + { + char ch; + + // skip whitespaces, tabs, and new lines + do + { + ch = read_char(); + } + while (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r'); + + if( ch < '0' || ch > '9' ) + { + io_error( "Unexpected characters reading decimal digits" ); + } + + unsigned val = 0; + + do + { + unsigned dig = ch - '0'; + + if( val > INT_MAX / 10 - dig ) + { + io_error( "Integer too large" ); + } + + val = val * 10 + dig; + + ch = read_char(); + } + while( '0' <= ch && ch <= '9' ); + + return val; + } + + +public: + + Device _io_dev; + + image_read_settings< pnm_tag > _settings; + image_read_info< pnm_tag > _info; + + std::size_t _scanline_length; +}; + +#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) +#pragma warning(pop) +#endif + +} // namespace gil +} // namespace boost + +#endif diff --git a/boost/gil/extension/io/pnm/detail/scanline_read.hpp b/boost/gil/extension/io/pnm/detail/scanline_read.hpp new file mode 100644 index 0000000000..b109528145 --- /dev/null +++ b/boost/gil/extension/io/pnm/detail/scanline_read.hpp @@ -0,0 +1,259 @@ +/* + Copyright 2012 Christian Henning + 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_PNM_DETAIL_SCANLINE_READ_HPP +#define BOOST_GIL_EXTENSION_IO_PNM_DETAIL_SCANLINE_READ_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file +/// \brief +/// \author Christian Henning \n +/// +/// \date 2012 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +#include <vector> +#include <boost/bind.hpp> +#include <boost/function.hpp> + +#include <boost/gil.hpp> + +#include <boost/gil/io/base.hpp> +#include <boost/gil/io/conversion_policies.hpp> +#include <boost/gil/io/row_buffer_helper.hpp> +#include <boost/gil/io/bit_operations.hpp> +#include <boost/gil/io/reader_base.hpp> +#include <boost/gil/io/device.hpp> +#include <boost/gil/io/scanline_read_iterator.hpp> +#include <boost/gil/io/typedefs.hpp> + +#include <boost/gil/extension/io/pnm/detail/reader_backend.hpp> +#include <boost/gil/extension/io/pnm/detail/is_allowed.hpp> + +namespace boost { namespace gil { + +/// +/// PNM Reader +/// +template< typename Device > +class scanline_reader< Device + , pnm_tag + > + : public reader_backend< Device + , pnm_tag + > +{ +public: + + typedef pnm_tag tag_t; + typedef reader_backend < Device, tag_t > backend_t; + typedef scanline_reader< Device, tag_t > this_t; + typedef scanline_read_iterator< this_t > iterator_t; + + +public: + scanline_reader( Device& device + , const image_read_settings< pnm_tag >& settings + ) + : backend_t( device + , settings + ) + { + initialize(); + } + + /// Read part of image defined by View and return the data. + void read( byte_t* dst + , int + ) + { + _read_function( this, dst ); + } + + /// Skip over a scanline. + void skip( byte_t*, int ) + { + _skip_function( this ); + } + + iterator_t begin() { return iterator_t( *this ); } + iterator_t end() { return iterator_t( *this, this->_info._height ); } + +private: + + void initialize() + { + switch( this->_info._type ) + { + // reading mono text is reading grayscale but with only two values + case pnm_image_type::mono_asc_t::value: + case pnm_image_type::gray_asc_t::value: + { + this->_scanline_length = this->_info._width; + + _read_function = boost::mem_fn( &this_t::read_text_row ); + _skip_function = boost::mem_fn( &this_t::skip_text_row ); + + break; + } + + case pnm_image_type::color_asc_t::value: + { + this->_scanline_length = this->_info._width * num_channels< rgb8_view_t >::value; + + _read_function = boost::mem_fn( &this_t::read_text_row ); + _skip_function = boost::mem_fn( &this_t::skip_text_row ); + + break; + } + + + case pnm_image_type::mono_bin_t::value: + { + //gray1_image_t + this->_scanline_length = ( this->_info._width + 7 ) >> 3; + + _read_function = boost::mem_fn( &this_t::read_binary_bit_row ); + _skip_function = boost::mem_fn( &this_t::skip_binary_row ); + + break; + } + + case pnm_image_type::gray_bin_t::value: + { + // gray8_image_t + this->_scanline_length = this->_info._width; + + _read_function = boost::mem_fn( &this_t::read_binary_byte_row ); + _skip_function = boost::mem_fn( &this_t::skip_binary_row ); + + break; + } + + case pnm_image_type::color_bin_t::value: + { + // rgb8_image_t + this->_scanline_length = this->_info._width * num_channels< rgb8_view_t >::value; + + _read_function = boost::mem_fn( &this_t::read_binary_byte_row ); + _skip_function = boost::mem_fn( &this_t::skip_binary_row ); + + break; + } + + default: { io_error( "Unsupported pnm file." ); break; } + } + } + + void read_text_row( byte_t* dst ) + { + for( std::size_t x = 0; x < this->_scanline_length; ++x ) + { + for( uint32_t k = 0; ; ) + { + int ch = this->_io_dev.getc_unchecked(); + + if( isdigit( ch )) + { + _text_buffer[ k++ ] = static_cast< char >( ch ); + } + else if( k ) + { + _text_buffer[ k ] = 0; + break; + } + else if( ch == EOF || !isspace( ch )) + { + return; + } + } + + int value = atoi( _text_buffer ); + + if( this->_info._max_value == 1 ) + { + // for pnm format 0 is white + dst[x] = ( value != 0 ) + ? 0 + : 255; + } + else + { + dst[x] = static_cast< byte_t >( value ); + } + } + } + + void skip_text_row() + { + for( std::size_t x = 0; x < this->_scanline_length; ++x ) + { + for( uint32_t k = 0; ; ) + { + int ch = this->_io_dev.getc_unchecked(); + + if( isdigit( ch )) + { + k++; + } + else if( k ) + { + break; + } + else if( ch == EOF || !isspace( ch )) + { + return; + } + } + } + } + + + void read_binary_bit_row( byte_t* dst ) + { + this->_io_dev.read( dst + , this->_scanline_length + ); + + _negate_bits ( dst, this->_scanline_length ); + _swap_half_bytes( dst, this->_scanline_length ); + + } + + void read_binary_byte_row( byte_t* dst ) + { + this->_io_dev.read( dst + , this->_scanline_length + ); + } + + void skip_binary_row() + { + this->_io_dev.seek( static_cast<long>( this->_scanline_length ), SEEK_CUR ); + } + +private: + + char _text_buffer[16]; + + // For bit_aligned images we need to negate all bytes in the row_buffer + // to make sure that 0 is black and 255 is white. + detail::negate_bits < std::vector< byte_t >, mpl::true_ > _negate_bits; + detail::swap_half_bytes< std::vector< byte_t >, mpl::true_ > _swap_half_bytes; + + boost::function< void ( this_t*, byte_t* ) > _read_function; + boost::function< void ( this_t* ) > _skip_function; +}; + + +} // namespace gil +} // namespace boost + +#endif diff --git a/boost/gil/extension/io/pnm/detail/supported_types.hpp b/boost/gil/extension/io/pnm/detail/supported_types.hpp new file mode 100644 index 0000000000..7bede91402 --- /dev/null +++ b/boost/gil/extension/io/pnm/detail/supported_types.hpp @@ -0,0 +1,146 @@ +/* + Copyright 2008 Christian Henning + 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_PNM_DETAIL_SUPPORTED_TYPES_HPP +#define BOOST_GIL_EXTENSION_IO_PNM_DETAIL_SUPPORTED_TYPES_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file +/// \brief +/// \author Christian Henning \n +/// +/// \date 2008 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +#include <boost/mpl/not.hpp> +#include <boost/type_traits/is_same.hpp> + +#include <boost/gil/channel.hpp> +#include <boost/gil/color_base.hpp> + +namespace boost { namespace gil { namespace detail { + +// Read Support + +template< pnm_image_type::type ASCII_Type + , pnm_image_type::type Binary_Type + > +struct pnm_rw_support_base +{ + static const pnm_image_type::type _asc_type = ASCII_Type; + static const pnm_image_type::type _bin_type = Binary_Type; +}; + +template< typename Channel + , typename ColorSpace + > +struct pnm_read_support : read_support_false + , pnm_rw_support_base< 0 + , 0 + > {}; + +template< typename BitField, bool Mutable > +struct pnm_read_support< packed_dynamic_channel_reference< BitField + , 1 + , Mutable + > + , gray_t + > : read_support_true + , pnm_rw_support_base< pnm_image_type::mono_asc_t::value + , pnm_image_type::mono_bin_t::value + > {}; + +template<> +struct pnm_read_support<uint8_t + , gray_t + > : read_support_true + , pnm_rw_support_base< pnm_image_type::gray_asc_t::value + , pnm_image_type::gray_bin_t::value + > {}; + + +template<> +struct pnm_read_support<uint8_t + , rgb_t + > : read_support_true + , pnm_rw_support_base< pnm_image_type::color_asc_t::value + , pnm_image_type::color_bin_t::value + > {}; + +// Write support + +template< typename Channel + , typename ColorSpace + > +struct pnm_write_support : write_support_false +{}; + +template< typename BitField, bool Mutable > +struct pnm_write_support< packed_dynamic_channel_reference< BitField + , 1 + , Mutable + > + , gray_t + > : write_support_true + , pnm_rw_support_base< pnm_image_type::mono_asc_t::value + , pnm_image_type::mono_bin_t::value + > {}; + + +template<> +struct pnm_write_support<uint8_t + , gray_t + > : write_support_true + , pnm_rw_support_base< pnm_image_type::gray_asc_t::value + , pnm_image_type::gray_bin_t::value + > {}; + + +template<> +struct pnm_write_support<uint8_t + , rgb_t + > : write_support_true + , pnm_rw_support_base< pnm_image_type::color_asc_t::value + , pnm_image_type::color_bin_t::value + > {}; + +} // namespace detail + +template< typename Pixel > +struct is_read_supported< Pixel + , pnm_tag + > + : mpl::bool_< detail::pnm_read_support< typename channel_type < Pixel >::type + , typename color_space_type< Pixel >::type + >::is_supported + > +{ + typedef detail::pnm_read_support< typename channel_type < Pixel >::type + , typename color_space_type< Pixel >::type + > parent_t; + + static const pnm_image_type::type _asc_type = parent_t::_asc_type; + static const pnm_image_type::type _bin_type = parent_t::_bin_type; +}; + +template< typename Pixel > +struct is_write_supported< Pixel + , pnm_tag + > + : mpl::bool_< detail::pnm_write_support< typename channel_type < Pixel >::type + , typename color_space_type< Pixel >::type + >::is_supported + > {}; + +} // namespace gil +} // namespace boost + + +#endif diff --git a/boost/gil/extension/io/pnm/detail/write.hpp b/boost/gil/extension/io/pnm/detail/write.hpp new file mode 100644 index 0000000000..f92307c9c8 --- /dev/null +++ b/boost/gil/extension/io/pnm/detail/write.hpp @@ -0,0 +1,268 @@ +/* + Copyright 2012 Christian Henning + 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_PNM_DETAIL_WRITE_HPP +#define BOOST_GIL_EXTENSION_IO_PNM_DETAIL_WRITE_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file +/// \brief +/// \author Christian Henning \n +/// +/// \date 2012 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +#include <cstdlib> +#include <string> + +#include <boost/gil/extension/io/pnm/tags.hpp> + +#include <boost/gil/io/base.hpp> +#include <boost/gil/io/device.hpp> + +#include <boost/gil/extension/io/pnm/detail/writer_backend.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 { + +struct pnm_write_is_supported +{ + template< typename View > + struct apply + : public is_write_supported< typename get_pixel_type< View >::type + , pnm_tag + > + {}; +}; + +} // namespace detail + +/// +/// PNM Writer +/// +template< typename Device > +class writer< Device + , pnm_tag + > + : public writer_backend< Device + , pnm_tag + > +{ +private: + typedef writer_backend< Device, pnm_tag > backend_t; + +public: + + writer( const Device& io_dev + , const image_write_info< pnm_tag >& info + ) + : backend_t( io_dev + , info + ) + {} + + template< typename View > + void apply( const View& view ) + { + typedef typename get_pixel_type< View >::type pixel_t; + + std::size_t width = view.width(); + std::size_t height = view.height(); + + std::size_t chn = num_channels< View >::value; + std::size_t pitch = chn * width; + + unsigned int type = get_type< num_channels< View >::value >( is_bit_aligned< pixel_t >() ); + + // write header + + // Add a white space at each string so read_int() can decide when a numbers ends. + + std::string str( "P" ); + str += std::to_string( type ) + std::string( " " ); + this->_io_dev.print_line( str ); + + str.clear(); + str += std::to_string( width ) + std::string( " " ); + this->_io_dev.print_line( str ); + + str.clear(); + str += std::to_string( height ) + std::string( " " ); + this->_io_dev.print_line( str ); + + if( type != pnm_image_type::mono_bin_t::value ) + { + this->_io_dev.print_line( "255 "); + } + + // write data + write_data( view + , pitch + , typename is_bit_aligned< pixel_t >::type() + ); + } + +private: + + template< int Channels > + unsigned int get_type( mpl::true_ /* is_bit_aligned */ ) + { + return boost::mpl::if_c< Channels == 1 + , pnm_image_type::mono_bin_t + , pnm_image_type::color_bin_t + >::type::value; + } + + template< int Channels > + unsigned int get_type( mpl::false_ /* is_bit_aligned */ ) + { + return boost::mpl::if_c< Channels == 1 + , pnm_image_type::gray_bin_t + , pnm_image_type::color_bin_t + >::type::value; + } + + template< typename View > + void write_data( const View& src + , std::size_t pitch + , const mpl::true_& // bit_aligned + ) + { + BOOST_STATIC_ASSERT(( is_same< View + , typename gray1_image_t::view_t + >::value + )); + + byte_vector_t row( pitch / 8 ); + + typedef typename View::x_iterator x_it_t; + x_it_t row_it = x_it_t( &( *row.begin() )); + + detail::negate_bits< byte_vector_t + , mpl::true_ + > neg; + + detail::mirror_bits< byte_vector_t + , mpl::true_ + > mirror; + + + for( typename View::y_coord_t y = 0; y < src.height(); ++y ) + { + std::copy( src.row_begin( y ) + , src.row_end( y ) + , row_it + ); + + mirror( row ); + neg ( row ); + + this->_io_dev.write( &row.front() + , pitch / 8 + ); + } + } + + template< typename View > + void write_data( const View& src + , std::size_t pitch + , const mpl::false_& // bit_aligned + ) + { + std::vector< pixel< typename channel_type< View >::type + , layout<typename color_space_type< View >::type > + > + > buf( src.width() ); + + // typedef typename View::value_type pixel_t; + // typedef typename view_type_from_pixel< pixel_t >::type view_t; + + //view_t row = interleaved_view( src.width() + // , 1 + // , reinterpret_cast< pixel_t* >( &buf.front() ) + // , pitch + // ); + + byte_t* row_addr = reinterpret_cast< byte_t* >( &buf.front() ); + + for( typename View::y_coord_t y = 0 + ; y < src.height() + ; ++y + ) + { + //copy_pixels( subimage_view( src + // , 0 + // , (int) y + // , (int) src.width() + // , 1 + // ) + // , row + // ); + + std::copy( src.row_begin( y ) + , src.row_end ( y ) + , buf.begin() + ); + + this->_io_dev.write( row_addr, pitch ); + } + } +}; + +/// +/// PNM Writer +/// +template< typename Device > +class dynamic_image_writer< Device + , pnm_tag + > + : public writer< Device + , pnm_tag + > +{ + typedef writer< Device + , pnm_tag + > parent_t; + +public: + + dynamic_image_writer( const Device& io_dev + , const image_write_info< pnm_tag >& info + ) + : parent_t( io_dev + , info + ) + {} + + template< typename Views > + void apply( const any_image_view< Views >& views ) + { + detail::dynamic_io_fnobj< detail::pnm_write_is_supported + , parent_t + > op( this ); + + apply_operation( views, op ); + } +}; + +#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) +#pragma warning(pop) +#endif + +} // gil +} // boost + +#endif diff --git a/boost/gil/extension/io/pnm/detail/writer_backend.hpp b/boost/gil/extension/io/pnm/detail/writer_backend.hpp new file mode 100644 index 0000000000..38672e6f71 --- /dev/null +++ b/boost/gil/extension/io/pnm/detail/writer_backend.hpp @@ -0,0 +1,66 @@ +/* + Copyright 2012 Christian Henning + 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_PNM_DETAIL_WRITER_BACKEND_HPP +#define BOOST_GIL_EXTENSION_IO_PNM_DETAIL_WRITER_BACKEND_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file +/// \brief +/// \author Christian Henning \n +/// +/// \date 2012 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +#include <boost/gil/extension/io/pnm/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 + +/// +/// PNM Writer Backend +/// +template< typename Device > +struct writer_backend< Device + , pnm_tag + > +{ +public: + + typedef pnm_tag format_tag_t; + +public: + + writer_backend( const Device& io_dev + , const image_write_info< pnm_tag >& info + ) + : _io_dev( io_dev ) + , _info( info ) + {} + +public: + + Device _io_dev; + + image_write_info< pnm_tag > _info; +}; + +#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) +#pragma warning(pop) +#endif + +} // namespace gil +} // namespace boost + +#endif diff --git a/boost/gil/extension/io/pnm/old.hpp b/boost/gil/extension/io/pnm/old.hpp new file mode 100644 index 0000000000..a9a1529ca0 --- /dev/null +++ b/boost/gil/extension/io/pnm/old.hpp @@ -0,0 +1,181 @@ +/* + Copyright 2008 Christian Henning + 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_PNM_OLD_HPP +#define BOOST_GIL_EXTENSION_IO_PNM_OLD_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file +/// \brief +/// \author Christian Henning \n +/// +/// \date 2008 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +#include <boost/gil/extension/io/pnm.hpp> + +namespace boost { namespace gil { + +/// \ingroup PNM_IO +/// \brief Returns the width and height of the PNM file at the specified location. +/// Throws std::ios_base::failure if the location does not correspond to a valid PNM file +template< typename String > +inline +point2< std::ptrdiff_t > pnm_read_dimensions( const String& filename ) +{ + typedef typename get_reader_backend< String + , pnm_tag + >::type backend_t; + + backend_t backend = read_image_info( filename + , pnm_tag() + ); + + return point2< std::ptrdiff_t >( backend._info._width + , backend._info._height + ); +} + + +/// \ingroup PNM_IO +/// \brief Loads the image specified by the given pnm image file name into the given view. +/// Triggers a compile assert if the view color space and channel depth are not supported by the PNM library or by the I/O extension. +/// Throws std::ios_base::failure if the file is not a valid PNM 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 pnm_read_view( const String& filename + , const View& view + ) +{ + read_view( filename + , view + , pnm_tag() + ); +} + +/// \ingroup PNM_IO +/// \brief Allocates a new image whose dimensions are determined by the given pnm 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 PNM library or by the I/O extension. +/// Throws std::ios_base::failure if the file is not a valid PNM 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 pnm_read_image( const String& filename + , Image& img + ) +{ + read_image( filename + , img + , pnm_tag() + ); +} + +/// \ingroup PNM_IO +/// \brief Loads and color-converts the image specified by the given pnm image file name into the given view. +/// Throws std::ios_base::failure if the file is not a valid PNM file, or if its dimensions don't match the ones of the view. +template< typename String + , typename View + , typename CC + > +inline +void pnm_read_and_convert_view( const String& filename + , const View& view + , CC cc + ) +{ + read_and_convert_view( filename + , view + , cc + , pnm_tag() + ); +} + +/// \ingroup PNM_IO +/// \brief Loads and color-converts the image specified by the given pnm image file name into the given view. +/// Throws std::ios_base::failure if the file is not a valid PNM file, or if its dimensions don't match the ones of the view. +template< typename String + , typename View + > +inline +void pnm_read_and_convert_view( const String& filename + , const View& view + ) +{ + read_and_convert_view( filename + , view + , pnm_tag() + ); +} + +/// \ingroup PNM_IO +/// \brief Allocates a new image whose dimensions are determined by the given pnm image file, loads and color-converts the pixels into it. +/// Throws std::ios_base::failure if the file is not a valid PNM file +template< typename String + , typename Image + , typename CC + > +inline +void pnm_read_and_convert_image( const String& filename + , Image& img + , CC cc + ) +{ + read_and_convert_image( filename + , img + , cc + , pnm_tag() + ); +} + +/// \ingroup PNM_IO +/// \brief Allocates a new image whose dimensions are determined by the given pnm image file, loads and color-converts the pixels into it. +/// Throws std::ios_base::failure if the file is not a valid PNM file +template< typename String + , typename Image + > +inline +void pnm_read_and_convert_image( const String filename + , Image& img + ) +{ + read_and_convert_image( filename + , img + , pnm_tag() + ); +} + + +/// \ingroup PNM_IO +/// \brief Saves the view to a pnm file specified by the given pnm image file name. +/// Triggers a compile assert if the view color space and channel depth are not supported by the PNM 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 pnm_write_view( const String& filename + , const View& view + ) +{ + write_view( filename + , view + , pnm_tag() + ); +} + +} // namespace gil +} // namespace boost + +#endif diff --git a/boost/gil/extension/io/pnm/read.hpp b/boost/gil/extension/io/pnm/read.hpp new file mode 100644 index 0000000000..67ec2635d8 --- /dev/null +++ b/boost/gil/extension/io/pnm/read.hpp @@ -0,0 +1,41 @@ +/* + Copyright 2008 Christian Henning + 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_PNM_READ_HPP +#define BOOST_GIL_EXTENSION_IO_PNM_READ_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file +/// \brief +/// \author Christian Henning \n +/// +/// \date 2008 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +#include <boost/gil/extension/io/pnm/tags.hpp> +#include <boost/gil/extension/io/pnm/detail/supported_types.hpp> +#include <boost/gil/extension/io/pnm/detail/read.hpp> +#include <boost/gil/extension/io/pnm/detail/scanline_read.hpp> + +#include <boost/gil/io/get_reader.hpp> +#include <boost/gil/io/make_backend.hpp> +#include <boost/gil/io/make_reader.hpp> +#include <boost/gil/io/make_dynamic_image_reader.hpp> +#include <boost/gil/io/make_scanline_reader.hpp> + +#include <boost/gil/io/read_image.hpp> +#include <boost/gil/io/read_view.hpp> +#include <boost/gil/io/read_image_info.hpp> +#include <boost/gil/io/read_and_convert_image.hpp> +#include <boost/gil/io/read_and_convert_view.hpp> + +#include <boost/gil/io/scanline_read_iterator.hpp> + +#endif diff --git a/boost/gil/extension/io/pnm/tags.hpp b/boost/gil/extension/io/pnm/tags.hpp new file mode 100644 index 0000000000..2151c373ed --- /dev/null +++ b/boost/gil/extension/io/pnm/tags.hpp @@ -0,0 +1,106 @@ +/* + Copyright 2008 Christian Henning + 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_PNM_TAGS_HPP +#define BOOST_GIL_EXTENSION_IO_PNM_TAGS_HPP + +#define BOOST_GIL_EXTENSION_IO_PNM_READ_ENABLED + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file +/// \brief +/// \author Christian Henning \n +/// +/// \date 2008 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +#include <boost/mpl/integral_c.hpp> + +#include <boost/gil/io/base.hpp> + +namespace boost { namespace gil { + +/// Defines pnm tag. +struct pnm_tag : format_tag {}; + +/// see http://en.wikipedia.org/wiki/Portable_Bitmap_File_Format for reference + +/// Defines type for image type property. +struct pnm_image_type : property_base< uint32_t > +{ + typedef boost::mpl::integral_c< type, 1 > mono_asc_t; + typedef boost::mpl::integral_c< type, 2 > gray_asc_t; + typedef boost::mpl::integral_c< type, 3 > color_asc_t; + + typedef boost::mpl::integral_c< type, 4 > mono_bin_t; + typedef boost::mpl::integral_c< type, 5 > gray_bin_t; + typedef boost::mpl::integral_c< type, 6 > color_bin_t; +}; + +/// Defines type for image width property. +struct pnm_image_width : property_base< uint32_t > {}; + +/// Defines type for image height property. +struct pnm_image_height : property_base< uint32_t > {}; + +/// Defines type for image max value property. +struct pnm_image_max_value : property_base< uint32_t > {}; + +/// Read information for pnm images. +/// +/// The structure is returned when using read_image_info. +template<> +struct image_read_info< pnm_tag > +{ + /// The image type. + pnm_image_type::type _type; + /// The image width. + pnm_image_width::type _width; + /// The image height. + pnm_image_height::type _height; + /// The image max value. + pnm_image_max_value::type _max_value; +}; + +/// Read settings for pnm images. +/// +/// The structure can be used for all read_xxx functions, except read_image_info. +template<> +struct image_read_settings< pnm_tag > : public image_read_settings_base +{ + /// Default constructor + image_read_settings< pnm_tag >() + : image_read_settings_base() + {} + + /// Constructor + /// \param top_left Top left coordinate for reading partial image. + /// \param dim Dimensions for reading partial image. + image_read_settings( const point_t& top_left + , const point_t& dim + ) + : image_read_settings_base( top_left + , dim + ) + {} +}; + +/// Write information for pnm images. +/// +/// The structure can be used for write_view() function. +template<> +struct image_write_info< pnm_tag > +{ +}; + +} // namespace gil +} // namespace boost + +#endif diff --git a/boost/gil/extension/io/pnm/write.hpp b/boost/gil/extension/io/pnm/write.hpp new file mode 100644 index 0000000000..1a90483cd8 --- /dev/null +++ b/boost/gil/extension/io/pnm/write.hpp @@ -0,0 +1,31 @@ +/* + Copyright 2008 Christian Henning + 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_PNM_WRITE_HPP +#define BOOST_GIL_EXTENSION_IO_PNM_WRITE_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file +/// \brief +/// \author Christian Henning \n +/// +/// \date 2008 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +#include <boost/gil/extension/io/pnm/tags.hpp> +#include <boost/gil/extension/io/pnm/detail/supported_types.hpp> +#include <boost/gil/extension/io/pnm/detail/write.hpp> + +#include <boost/gil/io/make_writer.hpp> +#include <boost/gil/io/make_dynamic_image_writer.hpp> + +#include <boost/gil/io/write_view.hpp> + +#endif diff --git a/boost/gil/extension/io/raw.hpp b/boost/gil/extension/io/raw.hpp new file mode 100644 index 0000000000..c3a3626c75 --- /dev/null +++ b/boost/gil/extension/io/raw.hpp @@ -0,0 +1,24 @@ +/* + Copyright 2013 Christian Henning + 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_RAW_HPP +#define BOOST_GIL_EXTENSION_IO_RAW_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file +/// \brief +/// \author Olivier tournaire \n +/// +/// \date 2012 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +#include <boost/gil/extension/io/raw/read.hpp> + +#endif diff --git a/boost/gil/extension/io/raw/detail/device.hpp b/boost/gil/extension/io/raw/detail/device.hpp new file mode 100644 index 0000000000..7f93336d51 --- /dev/null +++ b/boost/gil/extension/io/raw/detail/device.hpp @@ -0,0 +1,143 @@ +/* + Copyright 2007-2012 Olivier Tournaire, Christian Henning + 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_RAW_DETAIL_DEVICE_HPP +#define BOOST_GIL_EXTENSION_IO_RAW_DETAIL_DEVICE_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file +/// \brief +/// \author Olivier Tournaire \n +/// +/// \date 2012 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +#include <boost/utility/enable_if.hpp> + +#include <boost/gil/io/base.hpp> +#include <boost/gil/io/device.hpp> + +#include <memory> + +namespace boost { namespace gil { namespace detail { + +class raw_device_base +{ +public: + + /// + /// Constructor + /// + raw_device_base() + : _processor_ptr( new LibRaw ) + {} + + // iparams getters + std::string get_camera_manufacturer() { return std::string(_processor_ptr.get()->imgdata.idata.make); } + std::string get_camera_model() { return std::string(_processor_ptr.get()->imgdata.idata.model); } + unsigned get_raw_count() { return _processor_ptr.get()->imgdata.idata.raw_count; } + unsigned get_dng_version() { return _processor_ptr.get()->imgdata.idata.dng_version; } + int get_colors() { return _processor_ptr.get()->imgdata.idata.colors; } + unsigned get_filters() { return _processor_ptr.get()->imgdata.idata.filters; } + std::string get_cdesc() { return std::string(_processor_ptr.get()->imgdata.idata.cdesc); } + + // image_sizes getters + unsigned short get_raw_width() { return _processor_ptr.get()->imgdata.sizes.raw_width; } + unsigned short get_raw_height() { return _processor_ptr.get()->imgdata.sizes.raw_height; } + unsigned short get_image_width() { return _processor_ptr.get()->imgdata.sizes.width; } + unsigned short get_image_height() { return _processor_ptr.get()->imgdata.sizes.height; } + unsigned short get_top_margin() { return _processor_ptr.get()->imgdata.sizes.top_margin; } + unsigned short get_left_margin() { return _processor_ptr.get()->imgdata.sizes.left_margin; } + unsigned short get_iwidth() { return _processor_ptr.get()->imgdata.sizes.iwidth; } + unsigned short get_iheight() { return _processor_ptr.get()->imgdata.sizes.iheight; } + double get_pixel_aspect() { return _processor_ptr.get()->imgdata.sizes.pixel_aspect; } + int get_flip() { return _processor_ptr.get()->imgdata.sizes.flip; } + + // colordata getters + // TODO + + // imgother getters + float get_iso_speed() { return _processor_ptr.get()->imgdata.other.iso_speed; } + float get_shutter() { return _processor_ptr.get()->imgdata.other.shutter; } + float get_aperture() { return _processor_ptr.get()->imgdata.other.aperture; } + float get_focal_len() { return _processor_ptr.get()->imgdata.other.focal_len; } + time_t get_timestamp() { return _processor_ptr.get()->imgdata.other.timestamp; } + unsigned int get_shot_order() { return _processor_ptr.get()->imgdata.other.shot_order; } + unsigned* get_gpsdata() { return _processor_ptr.get()->imgdata.other.gpsdata; } + std::string get_desc() { return std::string(_processor_ptr.get()->imgdata.other.desc); } + std::string get_artist() { return std::string(_processor_ptr.get()->imgdata.other.artist); } + + std::string get_version() { return std::string(_processor_ptr.get()->version()); } + std::string get_unpack_function_name() { return std::string(_processor_ptr.get()->unpack_function_name()); } + + void get_mem_image_format(int *widthp, int *heightp, int *colorsp, int *bpp) { _processor_ptr.get()->get_mem_image_format(widthp, heightp, colorsp, bpp); } + + int unpack() { return _processor_ptr.get()->unpack(); } + int dcraw_process() { return _processor_ptr.get()->dcraw_process(); } + libraw_processed_image_t* dcraw_make_mem_image(int* error_code=NULL) { return _processor_ptr.get()->dcraw_make_mem_image(error_code); } + +protected: + + using libraw_ptr_t = std::shared_ptr<LibRaw>; + libraw_ptr_t _processor_ptr; +}; + +/*! + * + * file_stream_device specialization for raw images + */ +template<> +class file_stream_device< raw_tag > : public raw_device_base +{ +public: + + struct read_tag {}; + + /// + /// Constructor + /// + file_stream_device( std::string const& file_name + , read_tag = read_tag() + ) + { + io_error_if( _processor_ptr.get()->open_file( file_name.c_str() ) != LIBRAW_SUCCESS + , "file_stream_device: failed to open file" + ); + } + + /// + /// Constructor + /// + file_stream_device( const char* file_name + , read_tag = read_tag() + ) + { + io_error_if( _processor_ptr.get()->open_file( file_name ) != LIBRAW_SUCCESS + , "file_stream_device: failed to open file" + ); + } +}; + +template< typename FormatTag > +struct is_adaptable_input_device< FormatTag + , LibRaw + , void + > + : mpl::true_ +{ + typedef file_stream_device< FormatTag > device_type; +}; + + +} // namespace detail +} // namespace gil +} // namespace boost + +#endif diff --git a/boost/gil/extension/io/raw/detail/is_allowed.hpp b/boost/gil/extension/io/raw/detail/is_allowed.hpp new file mode 100644 index 0000000000..852378abae --- /dev/null +++ b/boost/gil/extension/io/raw/detail/is_allowed.hpp @@ -0,0 +1,57 @@ +/* + Copyright 2009 Christian Henning + 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_RAW_DETAIL_IS_ALLOWED_HPP +#define BOOST_GIL_EXTENSION_IO_RAW_DETAIL_IS_ALLOWED_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file +/// \brief +/// \author Olivier Tournaire \n +/// +/// \date 2011 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +#include <boost/gil/io/base.hpp> +#include <iostream> + +namespace boost { namespace gil { namespace detail { + +template< typename View > +bool is_allowed( const image_read_info< raw_tag >& info + , mpl::true_ // is read_and_no_convert + ) +{ + typedef typename get_pixel_type< View >::type pixel_t; + typedef typename num_channels< pixel_t >::value_type num_channel_t; + typedef typename channel_traits< typename element_type< typename View::value_type >::type >::value_type channel_t; + + const num_channel_t dst_samples_per_pixel = num_channels< pixel_t >::value; + const unsigned int dst_bits_per_pixel = detail::unsigned_integral_num_bits< channel_t >::value; + const bool is_type_signed = boost::is_signed< channel_t >::value; + + return( dst_samples_per_pixel == info._samples_per_pixel && + dst_bits_per_pixel == static_cast<unsigned int>(info._bits_per_pixel) && + !is_type_signed ); +} + +template< typename View > +bool is_allowed( const image_read_info< raw_tag >& /* info */ + , mpl::false_ // is read_and_convert + ) +{ + return true; +} + +} // namespace detail +} // namespace gil +} // namespace boost + +#endif diff --git a/boost/gil/extension/io/raw/detail/read.hpp b/boost/gil/extension/io/raw/detail/read.hpp new file mode 100644 index 0000000000..6406d6575e --- /dev/null +++ b/boost/gil/extension/io/raw/detail/read.hpp @@ -0,0 +1,259 @@ +/* + Copyright 2012 Olivier Tournaire, Christian Henning + 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_RAW_DETAIL_READ_HPP +#define BOOST_GIL_EXTENSION_IO_RAW_DETAIL_READ_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file +/// \brief +/// \author Olivier Tournaire, Christian Henning \n +/// +/// \date 2012 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +#include <cstdio> +#include <vector> +#include <boost/gil/extension/io/raw/tags.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/row_buffer_helper.hpp> +#include <boost/gil/io/reader_base.hpp> +#include <boost/gil/io/device.hpp> +#include <boost/gil/io/typedefs.hpp> + +#include <boost/gil/extension/io/raw/detail/is_allowed.hpp> +#include <boost/gil/extension/io/raw/detail/device.hpp> +#include <boost/gil/extension/io/raw/detail/reader_backend.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 + +#define BUILD_INTERLEAVED_VIEW(color_layout, bits_per_pixel) \ +{ \ + color_layout##bits_per_pixel##_view_t build = boost::gil::interleaved_view(processed_image->width, \ + processed_image->height, \ + (color_layout##bits_per_pixel##_pixel_t*)processed_image->data, \ + processed_image->colors*processed_image->width*processed_image->bits/8); \ + this->_cc_policy.read( build.begin(), build.end(), dst_view.begin() ); \ +} \ + + +template< typename Device + , typename ConversionPolicy + > +class reader< Device + , raw_tag + , ConversionPolicy + > + : public reader_base< raw_tag + , ConversionPolicy + > + , public reader_backend< Device + , raw_tag + > +{ +private: + + typedef reader< Device + , raw_tag + , ConversionPolicy + > this_t; + + typedef typename ConversionPolicy::color_converter_type cc_t; + +public: + + typedef reader_backend< Device, raw_tag > backend_t; + +public: + + // + // Constructor + // + reader( const Device& io_dev + , const image_read_settings< raw_tag >& settings + ) + : backend_t( io_dev + , settings + ) + {} + + // + // Constructor + // + reader( const Device& io_dev + , const cc_t& cc + , const image_read_settings< raw_tag >& settings + ) + : reader_base< raw_tag + , ConversionPolicy + >( cc ) + , backend_t( io_dev + , settings + ) + {} + + template< typename View > + void apply( const View& dst_view ) + { + if( this->_info._valid == false ) + { + io_error( "Image header was not read." ); + } + + typedef typename is_same< ConversionPolicy + , detail::read_and_no_convert + >::type is_read_and_convert_t; + + io_error_if( !detail::is_allowed< View >( this->_info + , is_read_and_convert_t() + ) + , "Image types aren't compatible." + ); + + // TODO: better error handling based on return code + int return_code = this->_io_dev.unpack(); + io_error_if( return_code != LIBRAW_SUCCESS, "Unable to unpack image" ); + this->_info._unpack_function_name = this->_io_dev.get_unpack_function_name(); + + return_code = this->_io_dev.dcraw_process(); + io_error_if( return_code != LIBRAW_SUCCESS, "Unable to emulate dcraw behavior to process image" ); + + libraw_processed_image_t* processed_image = this->_io_dev.dcraw_make_mem_image(&return_code); + io_error_if( return_code != LIBRAW_SUCCESS, "Unable to dcraw_make_mem_image" ); + + if(processed_image->colors!=1 && processed_image->colors!=3) + io_error( "Image is neither gray nor RGB" ); + + if(processed_image->bits!=8 && processed_image->bits!=16) + io_error( "Image is neither 8bit nor 16bit" ); + + // TODO Olivier Tournaire + // Here, we should use a metafunction to reduce code size and avoid a (compile time) macro + if(processed_image->bits==8) + { + if(processed_image->colors==1){ BUILD_INTERLEAVED_VIEW(gray, 8); } + else { BUILD_INTERLEAVED_VIEW(rgb, 8); } + } + else if(processed_image->bits==16) + { + if(processed_image->colors==1){ BUILD_INTERLEAVED_VIEW(gray, 16); } + else { BUILD_INTERLEAVED_VIEW(rgb, 16); } + } + } +}; + +namespace detail { + +struct raw_read_is_supported +{ + template< typename View > + struct apply : public is_read_supported< typename get_pixel_type< View >::type + , raw_tag + > + {}; +}; + +struct raw_type_format_checker +{ + raw_type_format_checker( const image_read_info< raw_tag >& info ) + : _info( info ) + {} + + template< typename Image > + bool apply() + { + typedef typename Image::view_t view_t; + + return is_allowed< view_t >( _info + , mpl::true_() + ); + } + +private: + ///todo: do we need this here. Should be part of reader_backend + const image_read_info< raw_tag >& _info; +}; + +} // namespace detail + +/// +/// RAW Dynamic Reader +/// +template< typename Device > +class dynamic_image_reader< Device + , raw_tag + > + : public reader< Device + , raw_tag + , detail::read_and_no_convert + > +{ + typedef reader< Device + , raw_tag + , detail::read_and_no_convert + > parent_t; + +public: + + dynamic_image_reader( const Device& io_dev + , const image_read_settings< raw_tag >& settings + ) + : parent_t( io_dev + , settings + ) + {} + + template< typename Images > + void apply( any_image< Images >& images ) + { + detail::raw_type_format_checker format_checker( this->_info ); + + if( !construct_matched( images + , format_checker + )) + { + std::ostringstream error_message; + error_message << "No matching image type between those of the given any_image and that of the file.\n"; + error_message << "Image type must be {gray||rgb}{8||16} unsigned for RAW image files."; + io_error( error_message.str().c_str() ); + } + else + { + if( !this->_info._valid ) + this->read_header(); + this->init_image(images, this->_settings); + + detail::dynamic_io_fnobj< detail::raw_read_is_supported + , parent_t + > op( this ); + + apply_operation( view( images ) + , op + ); + } + } +}; + +#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) +#pragma warning(pop) +#endif + +} // gil +} // boost + +#endif diff --git a/boost/gil/extension/io/raw/detail/reader_backend.hpp b/boost/gil/extension/io/raw/detail/reader_backend.hpp new file mode 100644 index 0000000000..ad03a946f7 --- /dev/null +++ b/boost/gil/extension/io/raw/detail/reader_backend.hpp @@ -0,0 +1,151 @@ +/* + Copyright 2012 Christian Henning + 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_RAW_DETAIL_READER_BACKEND_HPP +#define BOOST_GIL_EXTENSION_IO_RAW_DETAIL_READER_BACKEND_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file +/// \brief +/// \author Christian Henning \n +/// +/// \date 2012 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +#include <boost/gil/extension/io/raw/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 + +/// +/// RAW Backend +/// +template< typename Device > +struct reader_backend< Device + , raw_tag + > +{ +public: + + typedef raw_tag format_tag_t; + +public: + + reader_backend( const Device& io_dev + , const image_read_settings< raw_tag >& settings + ) + : _io_dev ( io_dev ) + , _settings( settings ) + , _info() + , _scanline_length( 0 ) + { + 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_dev.get_mem_image_format( &_info._width + , &_info._height + , &_info._samples_per_pixel + , &_info._bits_per_pixel + ); + + // iparams + _info._camera_manufacturer = _io_dev.get_camera_manufacturer(); + _info._camera_model = _io_dev.get_camera_model(); + _info._raw_images_count = _io_dev.get_raw_count(); + _info._dng_version = _io_dev.get_dng_version(); + _info._number_colors = _io_dev.get_colors(); + //_io_dev.get_filters(); + _info._colors_description = _io_dev.get_cdesc(); + + // image_sizes + _info._raw_width = _io_dev.get_raw_width(); + _info._raw_height = _io_dev.get_raw_height(); + _info._visible_width = _io_dev.get_image_width(); + _info._visible_height = _io_dev.get_image_height(); + _info._top_margin = _io_dev.get_top_margin(); + _info._left_margin = _io_dev.get_left_margin(); + _info._output_width = _io_dev.get_iwidth(); + _info._output_height = _io_dev.get_iheight(); + _info._pixel_aspect = _io_dev.get_pixel_aspect(); + _info._flip = _io_dev.get_flip(); + + // imgother + _info._iso_speed = _io_dev.get_iso_speed(); + _info._shutter = _io_dev.get_shutter(); + _info._aperture = _io_dev.get_aperture(); + _info._focal_length = _io_dev.get_focal_len(); + _info._timestamp = _io_dev.get_timestamp(); + _info._shot_order = static_cast< uint16_t >( _io_dev.get_shot_order() ); + //_io_dev.get_gpsdata(); + _info._image_description = _io_dev.get_desc(); + _info._artist = _io_dev.get_artist(); + + _info._libraw_version = _io_dev.get_version(); + + _info._valid = true; + } + + /// 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( 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( img_dim.y < _info._height ) { io_error( "Supplied image is too small" ); } + } + } + +public: + + Device _io_dev; + + image_read_settings< raw_tag > _settings; + image_read_info< raw_tag > _info; + + std::size_t _scanline_length; +}; + +#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) +#pragma warning(pop) +#endif + +} // namespace gil +} // namespace boost + +#endif diff --git a/boost/gil/extension/io/raw/detail/supported_types.hpp b/boost/gil/extension/io/raw/detail/supported_types.hpp new file mode 100644 index 0000000000..4175db9571 --- /dev/null +++ b/boost/gil/extension/io/raw/detail/supported_types.hpp @@ -0,0 +1,84 @@ +/* + Copyright 2008 Christian Henning + 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_RAW_DETAIL_SUPPORTED_TYPES_HPP +#define BOOST_GIL_EXTENSION_IO_RAW_DETAIL_SUPPORTED_TYPES_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file +/// \brief +/// \author Olivier Tournaire \n +/// +/// \date 2011 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +#include <boost/mpl/not.hpp> +#include <boost/type_traits/is_same.hpp> + +#include <boost/gil/channel.hpp> +#include <boost/gil/color_base.hpp> + +#include <boost/gil/io/base.hpp> + +namespace boost { namespace gil { namespace detail { + +// Read support + +template< typename Channel + , typename ColorSpace + > +struct raw_read_support : read_support_false {}; + +template<> +struct raw_read_support<uint8_t + , gray_t + > : read_support_true {}; + +template<> +struct raw_read_support<uint16_t + , gray_t + > : read_support_true {}; + +template<> +struct raw_read_support<uint8_t + , rgb_t + > : read_support_true {}; + +template<> +struct raw_read_support<uint16_t + , rgb_t + > : read_support_true {}; + +// Write support + +struct raw_write_support : write_support_false {}; + +} // namespace detail + +template< typename Pixel > +struct is_read_supported< Pixel, + raw_tag + > + : mpl::bool_< detail::raw_read_support< typename channel_type< Pixel >::type + , typename color_space_type< Pixel >::type + >::is_supported > {}; + +template< typename Pixel > +struct is_write_supported< Pixel + , raw_tag + > + : mpl::bool_< detail::raw_write_support::is_supported > +{}; + +} // namespace gil +} // namespace boost + + +#endif diff --git a/boost/gil/extension/io/raw/read.hpp b/boost/gil/extension/io/raw/read.hpp new file mode 100644 index 0000000000..f670d68576 --- /dev/null +++ b/boost/gil/extension/io/raw/read.hpp @@ -0,0 +1,40 @@ +/* + Copyright 2013 Christian Henning + 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_RAW_READ_HPP +#define BOOST_GIL_EXTENSION_IO_RAW_READ_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file +/// \brief +/// \author Olivier Tournaire \n +/// +/// \date 2011 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +#include <boost/gil/extension/io/raw/tags.hpp> +#include <boost/gil/extension/io/raw/detail/supported_types.hpp> +#include <boost/gil/extension/io/raw/detail/read.hpp> + +#include <boost/gil/io/get_reader.hpp> +#include <boost/gil/io/make_backend.hpp> +#include <boost/gil/io/make_reader.hpp> +#include <boost/gil/io/make_dynamic_image_reader.hpp> +#include <boost/gil/io/make_scanline_reader.hpp> + +#include <boost/gil/io/read_image_info.hpp> +#include <boost/gil/io/read_view.hpp> +#include <boost/gil/io/read_image.hpp> +#include <boost/gil/io/read_and_convert_image.hpp> +#include <boost/gil/io/read_and_convert_view.hpp> + +#include <boost/gil/io/scanline_read_iterator.hpp> + +#endif diff --git a/boost/gil/extension/io/raw/tags.hpp b/boost/gil/extension/io/raw/tags.hpp new file mode 100644 index 0000000000..684a24cbe0 --- /dev/null +++ b/boost/gil/extension/io/raw/tags.hpp @@ -0,0 +1,216 @@ +/* + Copyright 2013 Christian Henning + 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_RAW_TAGS_HPP +#define BOOST_GIL_EXTENSION_IO_RAW_TAGS_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file +/// \brief All supported raw tags by the gil io extension. +/// \author Olivier Tournaire \n +/// +/// \date 2011 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + + +#ifndef BOOST_GIL_EXTENSION_IO_RAW_C_LIB_COMPILED_AS_CPLUSPLUS + extern "C" { +#endif + +#include <libraw/libraw.h> + +#ifndef BOOST_GIL_EXTENSION_IO_RAW_C_LIB_COMPILED_AS_CPLUSPLUS + } +#endif + +#include <boost/gil/io/base.hpp> + +namespace boost { namespace gil { + +/// Defines tiff tag. +struct raw_tag : format_tag {}; + +/// Defines type for image width property. +struct raw_image_width : property_base< int32_t > {}; + +/// Defines type for image height property. +struct raw_image_height : property_base< int32_t > {}; + +/// Defines type for samples per pixel property. +struct raw_samples_per_pixel : property_base< int32_t > {}; + +/// Defines type for bits per pixel property. +struct raw_bits_per_pixel : property_base< int32_t > {}; + +/// Defines type for camera manufacturer. +struct raw_camera_manufacturer : property_base< std::string > {}; + +/// Defines type for camera model. +struct raw_camera_model : property_base< std::string > {}; + +/// Defines type for raw images count. +struct raw_raw_images_count : property_base< unsigned > {}; + +/// Defines type for dng version. +struct raw_dng_version : property_base< unsigned > {}; + +/// Defines type for number of colors. +struct raw_number_colors : property_base< int32_t > {}; + +/// Defines type for colors description. +struct raw_colors_description : property_base< std::string > {}; + +/// Defines type for raw height. +struct raw_raw_height : property_base< uint16_t > {}; + +/// Defines type for raw width. +struct raw_raw_width : property_base< uint16_t > {}; + +/// Defines type for visible height. +struct raw_visible_height : property_base< uint16_t > {}; + +/// Defines type for visible width. +struct raw_visible_width : property_base< uint16_t > {}; + +/// Defines type for top margin. +struct raw_top_margin : property_base< uint16_t > {}; + +/// Defines type for left margin. +struct raw_left_margin : property_base< uint16_t > {}; + +/// Defines type for output height. +struct raw_output_height : property_base< uint16_t > {}; + +/// Defines type for output width. +struct raw_output_width : property_base< uint16_t > {}; + +/// Defines type for pixel aspect. +struct raw_pixel_aspect : property_base< double > {}; + +/// Defines type for image orientation. +struct raw_flip : property_base< uint32_t > {}; + +/// Defines type for iso speed. +struct raw_iso_speed : property_base< float > {}; + +/// Defines type for shutter. +struct raw_shutter : property_base< float > {}; + +/// Defines type for aperture. +struct raw_aperture : property_base< float > {}; + +/// Defines type for focal length. +struct raw_focal_length : property_base< float > {}; + +/// Defines type for timestamp. +struct raw_timestamp : property_base< time_t > {}; + +/// Defines type for shot order. +struct raw_shot_order : property_base< uint16_t > {}; + +/// Defines type for image description. +struct raw_image_description : property_base< std::string > {}; + +/// Defines type for artist. +struct raw_artist : property_base< std::string > {}; + +/// Defines type for libraw version. +struct raw_libraw_version : property_base< std::string > {}; + +/// Defines type for unpack function name. +struct raw_unpack_function_name : property_base< std::string > {}; + +/// Read information for raw images. +/// +/// The structure is returned when using read_image_info. +template<> +struct image_read_info< raw_tag > +{ + /// Default contructor. + image_read_info< raw_tag >() + : _valid( false ) + {} + + // Here, width and height of the image are the ones of the output height (ie after having been processed by dcraw emulator) + raw_image_width::type _width; + raw_image_height::type _height; + raw_samples_per_pixel::type _samples_per_pixel; + raw_bits_per_pixel::type _bits_per_pixel; + + raw_camera_manufacturer::type _camera_manufacturer; + raw_camera_model::type _camera_model; + + raw_raw_images_count::type _raw_images_count; + raw_dng_version::type _dng_version; + raw_number_colors::type _number_colors; + raw_colors_description::type _colors_description; + + raw_raw_width::type _raw_width; + raw_raw_height::type _raw_height; + raw_visible_width::type _visible_width; + raw_visible_height::type _visible_height; + raw_top_margin::type _top_margin; + raw_left_margin::type _left_margin; + raw_output_width::type _output_width; + raw_output_height::type _output_height; + raw_pixel_aspect::type _pixel_aspect; + raw_flip::type _flip; + + raw_iso_speed::type _iso_speed; + raw_shutter::type _shutter; + raw_aperture::type _aperture; + raw_focal_length::type _focal_length; + raw_timestamp::type _timestamp; + raw_shot_order::type _shot_order; + raw_image_description::type _image_description; + raw_artist::type _artist; + + raw_libraw_version::type _libraw_version; + raw_unpack_function_name::type _unpack_function_name; + + /// Used internaly to identify if the header has been read. + bool _valid; +}; + +/// Read settings for raw images. +/// +/// The structure can be used for all read_xxx functions, except read_image_info. +template<> +struct image_read_settings< raw_tag > : public image_read_settings_base +{ + /// Default constructor + image_read_settings() + : image_read_settings_base() + {} + + /// Constructor + /// \param top_left Top left coordinate for reading partial image. + /// \param dim Dimensions for reading partial image. + image_read_settings( const point_t& top_left + , const point_t& dim + ) + : image_read_settings_base( top_left + , dim + ) + {} +}; + +/// Write information for raw images. +/// +/// The structure can be used for write_view() function. +template<> +struct image_write_info< raw_tag > +{ +}; + +} // namespace gil +} // namespace boost + +#endif diff --git a/boost/gil/extension/io/targa.hpp b/boost/gil/extension/io/targa.hpp new file mode 100644 index 0000000000..8ff4cb9302 --- /dev/null +++ b/boost/gil/extension/io/targa.hpp @@ -0,0 +1,25 @@ +/* + Copyright 2010 Kenneth Riddile + 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_TARGA_HPP +#define BOOST_GIL_EXTENSION_IO_TARGA_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file +/// \brief +/// \author Kenneth Riddile \n +/// +/// \date 2010 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +#include <boost/gil/extension/io/targa/read.hpp> +#include <boost/gil/extension/io/targa/write.hpp> + +#endif diff --git a/boost/gil/extension/io/targa/detail/is_allowed.hpp b/boost/gil/extension/io/targa/detail/is_allowed.hpp new file mode 100644 index 0000000000..0033ba6e54 --- /dev/null +++ b/boost/gil/extension/io/targa/detail/is_allowed.hpp @@ -0,0 +1,64 @@ +/* + Copyright 2010 Kenneth Riddile + 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_TARGA_DETAIL_IS_ALLOWED_HPP +#define BOOST_GIL_EXTENSION_IO_TARGA_DETAIL_IS_ALLOWED_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file +/// \brief +/// \author Kenneth Riddile \n +/// +/// \date 2010 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +namespace boost { namespace gil { namespace detail { + +template< typename View > +bool is_allowed( const image_read_info< targa_tag >& info + , mpl::true_ // is read_and_no_convert + ) +{ + targa_depth::type src_bits_per_pixel = 0; + + switch( info._bits_per_pixel ) + { + case 24: + case 32: + { + src_bits_per_pixel = info._bits_per_pixel; + break; + } + default: + { + io_error( "Pixel size not supported." ); + break; + } + } + + typedef typename channel_traits< typename element_type< typename View::value_type >::type >::value_type channel_t; + targa_depth::type dst_bits_per_pixel = detail::unsigned_integral_num_bits< channel_t >::value * num_channels< View >::value; + + return ( dst_bits_per_pixel == src_bits_per_pixel ); +} + +template< typename View > +bool is_allowed( const image_read_info< targa_tag >& /* info */ + , mpl::false_ // is read_and_convert + ) +{ + return true; +} + +} // namespace detail +} // namespace gil +} // namespace boost + +#endif diff --git a/boost/gil/extension/io/targa/detail/read.hpp b/boost/gil/extension/io/targa/detail/read.hpp new file mode 100644 index 0000000000..b208a679f4 --- /dev/null +++ b/boost/gil/extension/io/targa/detail/read.hpp @@ -0,0 +1,417 @@ +/* + Copyright 2012 Kenneth Riddile, Christian Henning + 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_TARGA_DETAIL_READ_HPP +#define BOOST_GIL_EXTENSION_IO_TARGA_DETAIL_READ_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file +/// \brief +/// \author Kenneth Riddile, Christian Henning \n +/// +/// \date 2012 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +#include <vector> + +#include <boost/gil/extension/io/targa/tags.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/row_buffer_helper.hpp> +#include <boost/gil/io/reader_base.hpp> +#include <boost/gil/io/device.hpp> +#include <boost/gil/io/typedefs.hpp> + +#include <boost/gil/extension/io/targa/detail/reader_backend.hpp> +#include <boost/gil/extension/io/targa/detail/is_allowed.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 + +/// +/// Targa Reader +/// +template< typename Device + , typename ConversionPolicy + > +class reader< Device + , targa_tag + , ConversionPolicy + > + : public reader_base< targa_tag + , ConversionPolicy + > + , public reader_backend< Device + , targa_tag + > +{ +private: + + typedef reader< Device + , targa_tag + , ConversionPolicy + > this_t; + + typedef typename ConversionPolicy::color_converter_type cc_t; + +public: + + typedef reader_backend< Device, targa_tag > backend_t; + +public: + + reader( const Device& io_dev + , const image_read_settings< targa_tag >& settings + ) + : reader_base< targa_tag + , ConversionPolicy + >() + , backend_t( io_dev + , settings + ) + {} + + reader( const Device& io_dev + , const cc_t& cc + , const image_read_settings< targa_tag >& settings + ) + : reader_base< targa_tag + , ConversionPolicy + >( cc ) + , backend_t( io_dev + , settings + ) + {} + + template< typename View > + void apply( const View& dst_view ) + { + typedef typename is_same< ConversionPolicy + , detail::read_and_no_convert + >::type is_read_and_convert_t; + + io_error_if( !detail::is_allowed< View >( this->_info, is_read_and_convert_t() ) + , "Image types aren't compatible." + ); + + switch( this->_info._image_type ) + { + case targa_image_type::_rgb: + { + if( this->_info._color_map_type != targa_color_map_type::_rgb ) + { + io_error( "Inconsistent color map type and image type in targa file." ); + } + + if( this->_info._color_map_length != 0 ) + { + io_error( "Non-indexed targa files containing a palette are not supported." ); + } + + switch( this->_info._bits_per_pixel ) + { + case 24: + { + this->_scanline_length = this->_info._width * ( this->_info._bits_per_pixel / 8 ); + + if( this->_info._screen_origin_bit ) + { + read_data< bgr8_view_t >( flipped_up_down_view( dst_view ) ); + } + else + { + read_data< bgr8_view_t >( dst_view ); + } + + break; + } + case 32: + { + this->_scanline_length = this->_info._width * ( this->_info._bits_per_pixel / 8 ); + + if( this->_info._screen_origin_bit ) + { + read_data< bgra8_view_t >( flipped_up_down_view( dst_view ) ); + } + else + { + read_data< bgra8_view_t >( dst_view ); + } + + break; + } + default: + { + io_error( "Unsupported bit depth in targa file." ); + break; + } + } + + break; + } + case targa_image_type::_rle_rgb: + { + if( this->_info._color_map_type != targa_color_map_type::_rgb ) + { + io_error( "Inconsistent color map type and image type in targa file." ); + } + + if( this->_info._color_map_length != 0 ) + { + io_error( "Non-indexed targa files containing a palette are not supported." ); + } + + switch( this->_info._bits_per_pixel ) + { + case 24: + { + if( this->_info._screen_origin_bit ) + { + read_rle_data< bgr8_view_t >( flipped_up_down_view( dst_view ) ); + } + else + { + read_rle_data< bgr8_view_t >( dst_view ); + } + break; + } + case 32: + { + if( this->_info._screen_origin_bit ) + { + read_rle_data< bgra8_view_t >( flipped_up_down_view( dst_view ) ); + } + else + { + read_rle_data< bgra8_view_t >( dst_view ); + } + break; + } + default: + { + io_error( "Unsupported bit depth in targa file." ); + break; + } + } + + break; + } + default: + { + io_error( "Unsupported image type in targa file." ); + break; + } + } + } + +private: + + // 8-8-8 BGR + // 8-8-8-8 BGRA + template< typename View_Src, typename View_Dst > + void read_data( const View_Dst& view ) + { + byte_vector_t row( this->_info._width * (this->_info._bits_per_pixel / 8) ); + + // jump to first scanline + this->_io_dev.seek( static_cast< long >( this->_info._offset )); + + View_Src v = interleaved_view( this->_info._width, + 1, + reinterpret_cast<typename View_Src::value_type*>( &row.front() ), + this->_info._width * num_channels< View_Src >::value + ); + + typename View_Src::x_iterator beg = v.row_begin( 0 ) + this->_settings._top_left.x; + typename View_Src::x_iterator end = beg + this->_settings._dim.x; + + // read bottom up since targa origin is bottom left + for( std::ptrdiff_t y = this->_settings._dim.y - 1; y > -1; --y ) + { + // @todo: For now we're reading the whole scanline which is + // slightly inefficient. Later versions should try to read + // only the bytes which are necessary. + this->_io_dev.read( &row.front(), row.size() ); + this->_cc_policy.read( beg, end, view.row_begin(y) ); + } + } + + // 8-8-8 BGR + // 8-8-8-8 BGRA + template< typename View_Src, typename View_Dst > + void read_rle_data( const View_Dst& view ) + { + targa_depth::type bytes_per_pixel = this->_info._bits_per_pixel / 8; + size_t image_size = this->_info._width * this->_info._height * bytes_per_pixel; + byte_vector_t image_data( image_size ); + + this->_io_dev.seek( static_cast< long >( this->_info._offset )); + + for( size_t pixel = 0; pixel < image_size; ) + { + targa_offset::type current_byte = this->_io_dev.read_uint8(); + + if( current_byte & 0x80 ) // run length chunk (high bit = 1) + { + uint8_t chunk_length = current_byte - 127; + uint8_t pixel_data[4]; + for( size_t channel = 0; channel < bytes_per_pixel; ++channel ) + { + pixel_data[channel] = this->_io_dev.read_uint8(); + } + + // Repeat the next pixel chunk_length times + for( uint8_t i = 0; i < chunk_length; ++i, pixel += bytes_per_pixel ) + { + memcpy( &image_data[pixel], pixel_data, bytes_per_pixel ); + } + } + else // raw chunk + { + uint8_t chunk_length = current_byte + 1; + + // Write the next chunk_length pixels directly + size_t pixels_written = chunk_length * bytes_per_pixel; + this->_io_dev.read( &image_data[pixel], pixels_written ); + pixel += pixels_written; + } + } + + View_Src v = flipped_up_down_view( interleaved_view( this->_info._width, + this->_info._height, + reinterpret_cast<typename View_Src::value_type*>( &image_data.front() ), + this->_info._width * num_channels< View_Src >::value ) ); + + for( std::ptrdiff_t y = 0; y != this->_settings._dim.y; ++y ) + { + typename View_Src::x_iterator beg = v.row_begin( y ) + this->_settings._top_left.x; + typename View_Src::x_iterator end = beg + this->_settings._dim.x; + this->_cc_policy.read( beg, end, view.row_begin(y) ); + } + } +}; + +namespace detail { + +class targa_type_format_checker +{ +public: + + targa_type_format_checker( const targa_depth::type& bpp ) + : _bpp( bpp ) + {} + + template< typename Image > + bool apply() + { + if( _bpp < 32 ) + { + return pixels_are_compatible< typename Image::value_type, rgb8_pixel_t >::value + ? true + : false; + } + else + { + return pixels_are_compatible< typename Image::value_type, rgba8_pixel_t >::value + ? true + : false; + } + } + +private: + + // to avoid C4512 + targa_type_format_checker& operator=( const targa_type_format_checker& ) { return *this; } + +private: + + const targa_depth::type _bpp; +}; + +struct targa_read_is_supported +{ + template< typename View > + struct apply : public is_read_supported< typename get_pixel_type< View >::type + , targa_tag + > + {}; +}; + +} // namespace detail + +/// +/// Targa Dynamic Image Reader +/// +template< typename Device > +class dynamic_image_reader< Device + , targa_tag + > + : public reader< Device + , targa_tag + , detail::read_and_no_convert + > +{ + typedef reader< Device + , targa_tag + , detail::read_and_no_convert + > parent_t; + +public: + + dynamic_image_reader( const Device& io_dev + , const image_read_settings< targa_tag >& settings + ) + : parent_t( io_dev + , settings + ) + {} + + template< typename Images > + void apply( any_image< Images >& images ) + { + detail::targa_type_format_checker format_checker( this->_info._bits_per_pixel ); + + 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::targa_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 diff --git a/boost/gil/extension/io/targa/detail/reader_backend.hpp b/boost/gil/extension/io/targa/detail/reader_backend.hpp new file mode 100644 index 0000000000..cbf216aacd --- /dev/null +++ b/boost/gil/extension/io/targa/detail/reader_backend.hpp @@ -0,0 +1,175 @@ +/* + Copyright 2012 Christian Henning + 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_TARGA_DETAIL_READER_BACKEND_HPP +#define BOOST_GIL_EXTENSION_IO_TARGA_DETAIL_READER_BACKEND_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file +/// \brief +/// \author Christian Henning \n +/// +/// \date 2012 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +#include <boost/gil/extension/io/targa/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 + +/// +/// Targa Backend +/// +template< typename Device > +struct reader_backend< Device + , targa_tag + > +{ +public: + + typedef targa_tag format_tag_t; + +public: + + reader_backend( const Device& io_dev + , const image_read_settings< targa_tag >& settings + ) + : _io_dev ( io_dev ) + , _scanline_length(0) + , _settings( settings ) + , _info() + { + 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() + { + _info._header_size = targa_header_size::_size; + + _info._offset = _io_dev.read_uint8() + _info._header_size; + + _info._color_map_type = _io_dev.read_uint8(); + _info._image_type = _io_dev.read_uint8(); + + _info._color_map_start = _io_dev.read_uint16(); + _info._color_map_length = _io_dev.read_uint16(); + _info._color_map_depth = _io_dev.read_uint8(); + + _info._x_origin = _io_dev.read_uint16(); + _info._y_origin = _io_dev.read_uint16(); + + _info._width = _io_dev.read_uint16(); + _info._height = _io_dev.read_uint16(); + + if( _info._width < 1 || _info._height < 1 ) + { + io_error( "Invalid dimension for targa file" ); + } + + _info._bits_per_pixel = _io_dev.read_uint8(); + if( _info._bits_per_pixel != 24 && _info._bits_per_pixel != 32 ) + { + io_error( "Unsupported bit depth for targa file" ); + } + + _info._descriptor = _io_dev.read_uint8(); + + // According to TGA specs, http://www.gamers.org/dEngine/quake3/TGA.txt, + // the image descriptor byte is: + // + // For Data Type 1, This entire byte should be set to 0. + if (_info._image_type == 1 && _info._descriptor != 0) + { + io_error("Unsupported descriptor for targa file"); + } + else if (_info._bits_per_pixel == 24) + { + // Bits 3-0 - For the Targa 24, it should be 0. + if ((_info._descriptor & 0x0FU) != 0) + { + io_error("Unsupported descriptor for targa file"); + } + } + else if (_info._bits_per_pixel == 32) + { + // Bits 3-0 - For Targa 32, it should be 8. + if (_info._descriptor != 8 && _info._descriptor != 40) + { + io_error("Unsupported descriptor for targa file"); + } + } + else + { + io_error("Unsupported descriptor for targa file"); + } + + if (_info._descriptor & 32) + { + _info._screen_origin_bit = true; + } + + _info._valid = true; + } + + /// 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( 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( img_dim.y < _info._height ) { io_error( "Supplied image is too small" ); } + } + } + +public: + + Device _io_dev; + + std::size_t _scanline_length; + + image_read_settings< targa_tag > _settings; + image_read_info< targa_tag > _info; +}; + +#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) +#pragma warning(pop) +#endif + +} // namespace gil +} // namespace boost + +#endif diff --git a/boost/gil/extension/io/targa/detail/scanline_read.hpp b/boost/gil/extension/io/targa/detail/scanline_read.hpp new file mode 100644 index 0000000000..7fbd0b05b0 --- /dev/null +++ b/boost/gil/extension/io/targa/detail/scanline_read.hpp @@ -0,0 +1,167 @@ +/* + Copyright 2012 Kenneth Riddile and Christian Henning + 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_TARGA_DETAIL_SCANLINE_READ_HPP +#define BOOST_GIL_EXTENSION_IO_TARGA_DETAIL_SCANLINE_READ_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file +/// \brief +/// \author Kenneth Riddile and Christian Henning \n +/// +/// \date 2012 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +#include <vector> + +#include <boost/gil/io/base.hpp> +#include <boost/gil/io/bit_operations.hpp> +#include <boost/gil/io/conversion_policies.hpp> +#include <boost/gil/io/row_buffer_helper.hpp> +#include <boost/gil/io/reader_base.hpp> +#include <boost/gil/io/device.hpp> +#include <boost/gil/io/scanline_read_iterator.hpp> +#include <boost/gil/io/typedefs.hpp> + +#include <boost/gil/extension/io/targa/detail/reader_backend.hpp> +#include <boost/gil/extension/io/targa/detail/is_allowed.hpp> + +namespace boost { namespace gil { + +/// +/// Targa Scanline Reader +/// +template< typename Device > +class scanline_reader< Device + , targa_tag + > + : public reader_backend< Device + , targa_tag + > +{ +public: + + + typedef targa_tag tag_t; + typedef reader_backend < Device, tag_t > backend_t; + typedef scanline_reader< Device, tag_t > this_t; + typedef scanline_read_iterator< this_t > iterator_t; + +public: + + // + // Constructor + // + scanline_reader( Device& device + , const image_read_settings< targa_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 ) + { + // jump to scanline + long offset = this->_info._offset + + ( this->_info._height - 1 - pos ) * static_cast< long >( this->_scanline_length ); + + this->_io_dev.seek( offset ); + + + read_row( dst ); + } + + /// Skip over a scanline. + void skip( byte_t*, int ) + { + this->_io_dev.seek( static_cast<long>( this->_scanline_length ) + , SEEK_CUR + ); + } + + iterator_t begin() { return iterator_t( *this ); } + iterator_t end() { return iterator_t( *this, this->_info._height ); } + +private: + + void initialize() + { + if( this->_info._color_map_type != targa_color_map_type::_rgb ) + { + io_error( "scanline reader cannot read indexed targa files." ); + } + + if( this->_info._image_type != targa_image_type::_rgb ) + { + io_error( "scanline reader cannot read this targa image type." ); + } + + switch( this->_info._image_type ) + { + case targa_image_type::_rgb: + { + if( this->_info._color_map_type != targa_color_map_type::_rgb ) + { + io_error( "Inconsistent color map type and image type in targa file." ); + } + + if( this->_info._color_map_length != 0 ) + { + io_error( "Non-indexed targa files containing a palette are not supported." ); + } + + if( this->_info._screen_origin_bit ) + { + io_error( "scanline reader cannot read targa files which have screen origin bit set." ); + } + + switch( this->_info._bits_per_pixel ) + { + case 24: + case 32: + { + this->_scanline_length = this->_info._width * ( this->_info._bits_per_pixel / 8 ); + + // jump to first scanline + this->_io_dev.seek( static_cast< long >( this->_info._offset )); + + break; + } + default: + { + io_error( "Unsupported bit depth in targa file." ); + break; + } + } + + break; + } + default: + { + io_error( "Unsupported image type in targa file." ); + break; + } + } + } + + void read_row( byte_t* dst ) + { + this->_io_dev.read( dst, this->_scanline_length ); + } +}; + +} // namespace gil +} // namespace boost + +#endif diff --git a/boost/gil/extension/io/targa/detail/supported_types.hpp b/boost/gil/extension/io/targa/detail/supported_types.hpp new file mode 100644 index 0000000000..0cefcb4a5b --- /dev/null +++ b/boost/gil/extension/io/targa/detail/supported_types.hpp @@ -0,0 +1,110 @@ +/* + Copyright 2010 Kenneth Riddile + 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_TARGA_DETAIL_SUPPORTED_TYPES_HPP +#define BOOST_GIL_EXTENSION_IO_TARGA_DETAIL_SUPPORTED_TYPES_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file +/// \brief +/// \author Kenneth Riddile \n +/// +/// \date 2010 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +#include <boost/mpl/not.hpp> +#include <boost/type_traits/is_same.hpp> + +#include <boost/gil/channel.hpp> +#include <boost/gil/color_base.hpp> + +#include <boost/gil/io/base.hpp> + +namespace boost { namespace gil { namespace detail { + +// Read support + +template< typename Channel + , typename ColorSpace + > +struct targa_read_support : read_support_false +{ + static const targa_depth::type bpp = 0; +}; + +template<> +struct targa_read_support<uint8_t + , rgb_t + > : read_support_true +{ + static const targa_depth::type bpp = 24; +}; + + +template<> +struct targa_read_support<uint8_t + , rgba_t + > : read_support_true +{ + static const targa_depth::type bpp = 32; +}; + + +// Write support + +template< typename Channel + , typename ColorSpace + > +struct targa_write_support : write_support_false +{}; + +template<> +struct targa_write_support<uint8_t + , rgb_t + > : write_support_true {}; + +template<> +struct targa_write_support<uint8_t + , rgba_t + > : write_support_true {}; + +} // namespace detail + + +template< typename Pixel > +struct is_read_supported< Pixel + , targa_tag + > + : mpl::bool_< detail::targa_read_support< typename channel_type< Pixel >::type + , typename color_space_type< Pixel >::type + >::is_supported + > +{ + typedef detail::targa_read_support< typename channel_type< Pixel >::type + , typename color_space_type< Pixel >::type + > parent_t; + + static const typename targa_depth::type bpp = parent_t::bpp; +}; + +template< typename Pixel > +struct is_write_supported< Pixel + , targa_tag + > + : mpl::bool_< detail::targa_write_support< typename channel_type< Pixel >::type + , typename color_space_type< Pixel >::type + >::is_supported + > {}; + +} // namespace gil +} // namespace boost + + +#endif diff --git a/boost/gil/extension/io/targa/detail/write.hpp b/boost/gil/extension/io/targa/detail/write.hpp new file mode 100644 index 0000000000..223c1b2161 --- /dev/null +++ b/boost/gil/extension/io/targa/detail/write.hpp @@ -0,0 +1,197 @@ +/* + Copyright 2010-2012 Kenneth Riddile, Christian Henning + 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_TARGA_DETAIL_WRITE_HPP +#define BOOST_GIL_EXTENSION_IO_TARGA_DETAIL_WRITE_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file +/// \brief +/// \author Kenneth Riddile, Christian Henning \n +/// +/// \date 2010-2012 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +#include <vector> + +#include <boost/gil/io/base.hpp> +#include <boost/gil/io/device.hpp> + +#include <boost/gil/extension/io/targa/tags.hpp> + +#include <boost/gil/extension/io/targa/detail/writer_backend.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 < int N > struct get_targa_view_type {}; +template <> struct get_targa_view_type< 3 > { typedef bgr8_view_t type; }; +template <> struct get_targa_view_type< 4 > { typedef bgra8_view_t type; }; + +struct targa_write_is_supported +{ + template< typename View > + struct apply + : public is_write_supported< typename get_pixel_type< View >::type + , targa_tag + > + {}; +}; + +} // detail + +/// +/// TARGA Writer +/// +template< typename Device > +class writer< Device + , targa_tag + > + : public writer_backend< Device + , targa_tag + > +{ +private: + typedef writer_backend< Device, targa_tag > backend_t; + +public: + + writer( const Device& io_dev + , const image_write_info< targa_tag >& info + ) + : backend_t( io_dev + , info + ) + {} + + template<typename View> + void apply( const View& view ) + { + write( view ); + } + +private: + + template< typename View > + void write( const View& view ) + { + uint8_t bit_depth = static_cast<uint8_t>( num_channels<View>::value * 8 ); + + // write the TGA header + this->_io_dev.write_uint8( 0 ); // offset + this->_io_dev.write_uint8( targa_color_map_type::_rgb ); + this->_io_dev.write_uint8( targa_image_type::_rgb ); + this->_io_dev.write_uint16( 0 ); // color map start + this->_io_dev.write_uint16( 0 ); // color map length + this->_io_dev.write_uint8( 0 ); // color map depth + this->_io_dev.write_uint16( 0 ); // x origin + this->_io_dev.write_uint16( 0 ); // y origin + this->_io_dev.write_uint16( static_cast<uint16_t>( view.width() ) ); // width in pixels + this->_io_dev.write_uint16( static_cast<uint16_t>( view.height() ) ); // height in pixels + this->_io_dev.write_uint8( bit_depth ); + + if( 32 == bit_depth ) + { + this->_io_dev.write_uint8( 8 ); // 8-bit alpha channel descriptor + } + else + { + this->_io_dev.write_uint8( 0 ); + } + + write_image< View + , typename detail::get_targa_view_type< num_channels< View >::value >::type + >( view ); + } + + + template< typename View + , typename TGA_View + > + void write_image( const View& view ) + { + size_t row_size = view.width() * num_channels<View>::value; + byte_vector_t buffer( row_size ); + std::fill( buffer.begin(), buffer.end(), 0 ); + + + TGA_View row = interleaved_view( view.width() + , 1 + , reinterpret_cast<typename TGA_View::value_type*>( &buffer.front() ) + , row_size + ); + + for( typename View::y_coord_t y = view.height() - 1; y > -1; --y ) + { + copy_pixels( subimage_view( view + , 0 + , static_cast<int>( y ) + , static_cast<int>( view.width() ) + , 1 + ) + , row + ); + + this->_io_dev.write( &buffer.front(), row_size ); + } + + } +}; + +/// +/// TARGA Dynamic Image Writer +/// +template< typename Device > +class dynamic_image_writer< Device + , targa_tag + > + : public writer< Device + , targa_tag + > +{ + typedef writer< Device + , targa_tag + > parent_t; + +public: + + dynamic_image_writer( const Device& io_dev + , const image_write_info< targa_tag >& info + ) + : parent_t( io_dev + , info + ) + {} + + template< typename Views > + void apply( const any_image_view< Views >& views ) + { + detail::dynamic_io_fnobj< detail::targa_write_is_supported + , parent_t + > op( this ); + + apply_operation( views, op ); + } +}; + +#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) +#pragma warning(pop) +#endif + +} // gil +} // boost + +#endif diff --git a/boost/gil/extension/io/targa/detail/writer_backend.hpp b/boost/gil/extension/io/targa/detail/writer_backend.hpp new file mode 100644 index 0000000000..0dfec2c185 --- /dev/null +++ b/boost/gil/extension/io/targa/detail/writer_backend.hpp @@ -0,0 +1,66 @@ +/* + Copyright 2012 Christian Henning + 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_TARGA_DETAIL_WRITER_BACKEND_HPP +#define BOOST_GIL_EXTENSION_IO_TARGA_DETAIL_WRITER_BACKEND_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file +/// \brief +/// \author Christian Henning \n +/// +/// \date 2012 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +#include <boost/gil/extension/io/targa/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 + +/// +/// TARGA Writer Backend +/// +template< typename Device > +struct writer_backend< Device + , targa_tag + > +{ +public: + + typedef targa_tag format_tag_t; + +public: + + writer_backend( const Device& io_dev + , const image_write_info< targa_tag >& info + ) + : _io_dev( io_dev ) + , _info( info ) + {} + +public: + + Device _io_dev; + + image_write_info< targa_tag > _info; +}; + +#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) +#pragma warning(pop) +#endif + +} // namespace gil +} // namespace boost + +#endif diff --git a/boost/gil/extension/io/targa/old.hpp b/boost/gil/extension/io/targa/old.hpp new file mode 100644 index 0000000000..05a3d680b5 --- /dev/null +++ b/boost/gil/extension/io/targa/old.hpp @@ -0,0 +1,181 @@ +/* + Copyright 2010 Christian Henning + 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_TARGA_OLD_HPP +#define BOOST_GIL_EXTENSION_IO_TARGA_OLD_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file +/// \brief +/// \author Christian Henning \n +/// +/// \date 2010 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +#include <boost/gil/extension/io/targa.hpp> + +namespace boost { namespace gil { + +/// \ingroup BMP_IO +/// \brief Returns the width and height of the BMP file at the specified location. +/// Throws std::ios_base::failure if the location does not correspond to a valid BMP file +template< typename String > +inline +point2< std::ptrdiff_t > targa_read_dimensions( const String& filename ) +{ + typedef typename get_reader_backend< String + , targa_tag + >::type backend_t; + + backend_t backend = read_image_info( filename + , targa_tag() + ); + + return point2< std::ptrdiff_t >( backend._info._width + , backend._info._height + ); +} + + +/// \ingroup BMP_IO +/// \brief Loads the image specified by the given targa image file name into the given view. +/// Triggers a compile assert if the view color space and channel depth are not supported by the BMP library or by the I/O extension. +/// Throws std::ios_base::failure if the file is not a valid BMP 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 targa_read_view( const String& filename + , const View& view + ) +{ + read_view( filename + , view + , targa_tag() + ); +} + +/// \ingroup BMP_IO +/// \brief Allocates a new image whose dimensions are determined by the given bmp 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 BMP library or by the I/O extension. +/// Throws std::ios_base::failure if the file is not a valid BMP 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 targa_read_image( const String& filename + , Image& img + ) +{ + read_image( filename + , img + , targa_tag() + ); +} + +/// \ingroup BMP_IO +/// \brief Loads and color-converts the image specified by the given targa image file name into the given view. +/// Throws std::ios_base::failure if the file is not a valid BMP file, or if its dimensions don't match the ones of the view. +template< typename String + , typename View + , typename CC + > +inline +void targa_read_and_convert_view( const String& filename + , const View& view + , CC cc + ) +{ + read_and_convert_view( filename + , view + , cc + , targa_tag() + ); +} + +/// \ingroup BMP_IO +/// \brief Loads and color-converts the image specified by the given targa image file name into the given view. +/// Throws std::ios_base::failure if the file is not a valid BMP file, or if its dimensions don't match the ones of the view. +template< typename String + , typename View + > +inline +void targa_read_and_convert_view( const String& filename + , const View& view + ) +{ + read_and_convert_view( filename + , view + , targa_tag() + ); +} + +/// \ingroup BMP_IO +/// \brief Allocates a new image whose dimensions are determined by the given targa image file, loads and color-converts the pixels into it. +/// Throws std::ios_base::failure if the file is not a valid BMP file +template< typename String + , typename Image + , typename CC + > +inline +void targa_read_and_convert_image( const String& filename + , Image& img + , CC cc + ) +{ + read_and_convert_image( filename + , img + , cc + , targa_tag() + ); +} + +/// \ingroup BMP_IO +/// \brief Allocates a new image whose dimensions are determined by the given targa image file, loads and color-converts the pixels into it. +/// Throws std::ios_base::failure if the file is not a valid BMP file +template< typename String + , typename Image + > +inline +void targa_read_and_convert_image( const String filename + , Image& img + ) +{ + read_and_convert_image( filename + , img + , targa_tag() + ); +} + + +/// \ingroup BMP_IO +/// \brief Saves the view to a targa file specified by the given targa image file name. +/// Triggers a compile assert if the view color space and channel depth are not supported by the BMP 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 targa_write_view( const String& filename + , const View& view + ) +{ + write_view( filename + , view + , targa_tag() + ); +} + +} // namespace gil +} // namespace boost + +#endif diff --git a/boost/gil/extension/io/targa/read.hpp b/boost/gil/extension/io/targa/read.hpp new file mode 100644 index 0000000000..41caaa7d58 --- /dev/null +++ b/boost/gil/extension/io/targa/read.hpp @@ -0,0 +1,41 @@ +/* + Copyright 2010-2012 Kenneth Riddile and Christian Henning + 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_TARGA_READ_HPP +#define BOOST_GIL_EXTENSION_IO_TARGA_READ_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file +/// \brief +/// \author Kenneth Riddile and Christian Henning \n +/// +/// \date 2010-2012 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +#include <boost/gil/extension/io/targa/tags.hpp> +#include <boost/gil/extension/io/targa/detail/supported_types.hpp> +#include <boost/gil/extension/io/targa/detail/read.hpp> +#include <boost/gil/extension/io/targa/detail/scanline_read.hpp> + +#include <boost/gil/io/get_reader.hpp> +#include <boost/gil/io/make_backend.hpp> +#include <boost/gil/io/make_reader.hpp> +#include <boost/gil/io/make_dynamic_image_reader.hpp> +#include <boost/gil/io/make_scanline_reader.hpp> + +#include <boost/gil/io/read_image.hpp> +#include <boost/gil/io/read_view.hpp> +#include <boost/gil/io/read_image_info.hpp> +#include <boost/gil/io/read_and_convert_image.hpp> +#include <boost/gil/io/read_and_convert_view.hpp> + +#include <boost/gil/io/scanline_read_iterator.hpp> + +#endif diff --git a/boost/gil/extension/io/targa/tags.hpp b/boost/gil/extension/io/targa/tags.hpp new file mode 100644 index 0000000000..dce128b32c --- /dev/null +++ b/boost/gil/extension/io/targa/tags.hpp @@ -0,0 +1,177 @@ +/* + Copyright 2010 Kenneth Riddile + 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_TARGA_TAGS_HPP +#define BOOST_GIL_EXTENSION_IO_TARGA_TAGS_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file +/// \brief +/// \author Kenneth Riddile \n +/// +/// \date 2010 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +#include <boost/gil/io/base.hpp> + +namespace boost { namespace gil { + +/// Defines targa tag. +struct targa_tag : format_tag {}; + +/// See http://en.wikipedia.org/wiki/Truevision_TGA#Header for reference. +/// http://local.wasp.uwa.edu.au/~pbourke/dataformats/tga/ + + +/// Defines type for header sizes. +struct targa_header_size : property_base< uint8_t > +{ + static const type _size = 18; /// Constant size for targa file header size. +}; + +/// Defines type for offset value. +struct targa_offset : property_base< uint8_t > {}; + +/// Defines type for color map type property. +struct targa_color_map_type : property_base< uint8_t > +{ + static const type _rgb = 0; + static const type _indexed = 1; +}; + +/// Defines type for image type property. +struct targa_image_type : property_base< uint8_t > +{ + static const type _none = 0; /// no image data + static const type _indexed = 1; /// indexed + static const type _rgb = 2; /// RGB + static const type _greyscale = 3; /// greyscale + static const type _rle_indexed = 9; /// indexed with RLE compression + static const type _rle_rgb = 10; /// RGB with RLE compression + static const type _rle_greyscale = 11; /// greyscale with RLE compression +}; + +/// Defines type for color map start property. +struct targa_color_map_start : property_base< uint16_t > {}; + +/// Defines type for color map length property. +struct targa_color_map_length : property_base< uint16_t > {}; + +/// Defines type for color map bit depth property. +struct targa_color_map_depth : property_base< uint8_t > {}; + +/// Defines type for origin x and y value properties. +struct targa_origin_element : property_base< uint16_t > {}; + +/// Defines type for image dimension properties. +struct targa_dimension : property_base< uint16_t > {}; + +/// Defines type for image bit depth property. +struct targa_depth : property_base< uint8_t > {}; + +/// Defines type for image descriptor property. +struct targa_descriptor : property_base< uint8_t > {}; + +struct targa_screen_origin_bit : property_base< bool > {}; + +/// Read information for targa images. +/// +/// The structure is returned when using read_image_info. +template<> +struct image_read_info< targa_tag > +{ + /// Default contructor. + image_read_info< targa_tag >() + : _screen_origin_bit(false) + , _valid( false ) + {} + + /// The size of this header: + targa_header_size::type _header_size; + + /// The offset, i.e. starting address, of the byte where the targa data can be found. + targa_offset::type _offset; + + /// The type of color map used by the image, i.e. RGB or indexed. + targa_color_map_type::type _color_map_type; + + /// The type of image data, i.e compressed, indexed, uncompressed RGB, etc. + targa_image_type::type _image_type; + + /// Index of first entry in the color map table. + targa_color_map_start::type _color_map_start; + + /// Number of entries in the color map table. + targa_color_map_length::type _color_map_length; + + /// Bit depth for each color map entry. + targa_color_map_depth::type _color_map_depth; + + /// X coordinate of the image origin. + targa_origin_element::type _x_origin; + + /// Y coordinate of the image origin. + targa_origin_element::type _y_origin; + + /// Width of the image in pixels. + targa_dimension::type _width; + + /// Height of the image in pixels. + targa_dimension::type _height; + + /// Bit depth of the image. + targa_depth::type _bits_per_pixel; + + /// The targa image descriptor. + targa_descriptor::type _descriptor; + + // false: Origin in lower left-hand corner. + // true: Origin in upper left-hand corner. + targa_screen_origin_bit::type _screen_origin_bit; + + /// Used internally to identify if the header has been read. + bool _valid; +}; + +/// Read settings for targa images. +/// +/// The structure can be used for all read_xxx functions, except read_image_info. +template<> +struct image_read_settings< targa_tag > : public image_read_settings_base +{ + /// Default constructor + image_read_settings() + : image_read_settings_base() + {} + + /// Constructor + /// \param top_left Top left coordinate for reading partial image. + /// \param dim Dimensions for reading partial image. + image_read_settings( const point_t& top_left + , const point_t& dim + ) + : image_read_settings_base( top_left + , dim + ) + {} +}; + +/// Write information for targa images. +/// +/// The structure can be used for write_view() function. +template<> +struct image_write_info< targa_tag > +{ +}; + +} // namespace gil +} // namespace boost + +#endif diff --git a/boost/gil/extension/io/targa/write.hpp b/boost/gil/extension/io/targa/write.hpp new file mode 100644 index 0000000000..3edecc7d63 --- /dev/null +++ b/boost/gil/extension/io/targa/write.hpp @@ -0,0 +1,31 @@ +/* + Copyright 2010 Kenneth Riddile + 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_TARGA_WRITE_HPP +#define BOOST_GIL_EXTENSION_IO_TARGA_WRITE_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file +/// \brief +/// \author Kenneth Riddile \n +/// +/// \date 2010 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +#include <boost/gil/extension/io/targa/tags.hpp> +#include <boost/gil/extension/io/targa/detail/supported_types.hpp> +#include <boost/gil/extension/io/targa/detail//write.hpp> + +#include <boost/gil/io/make_writer.hpp> +#include <boost/gil/io/make_dynamic_image_writer.hpp> + +#include <boost/gil/io/write_view.hpp> + +#endif diff --git a/boost/gil/extension/io/tiff.hpp b/boost/gil/extension/io/tiff.hpp new file mode 100644 index 0000000000..0d7e6c8cd5 --- /dev/null +++ b/boost/gil/extension/io/tiff.hpp @@ -0,0 +1,25 @@ +/* + Copyright 2007-2008 Christian Henning + 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_HPP +#define BOOST_GIL_EXTENSION_IO_TIFF_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file +/// \brief +/// \author Christian Henning \n +/// +/// \date 2007-2008 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +#include <boost/gil/extension/io/tiff/read.hpp> +#include <boost/gil/extension/io/tiff/write.hpp> + +#endif diff --git a/boost/gil/extension/io/tiff/detail/device.hpp b/boost/gil/extension/io/tiff/detail/device.hpp new file mode 100644 index 0000000000..aebc9846c8 --- /dev/null +++ b/boost/gil/extension/io/tiff/detail/device.hpp @@ -0,0 +1,489 @@ +/* + Copyright 2007-2008 Andreas Pokorny, Christian Henning + 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_DEVICE_HPP +#define BOOST_GIL_EXTENSION_IO_TIFF_DETAIL_DEVICE_HPP + +#include <algorithm> + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file +/// \brief +/// \author Andreas Pokorny, Christian Henning \n +/// +/// \date 2007-2008 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +// 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> + +#include <boost/mpl/size.hpp> +#include <boost/utility/enable_if.hpp> + +#include <boost/gil/io/base.hpp> +#include <boost/gil/io/device.hpp> +#include <boost/gil/extension/io/tiff/detail/log.hpp> + +#include <memory> + +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" )) == NULL + , "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" )) == NULL + , "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 + ) + ) == NULL + , "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 + ) + ) == NULL + , "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_ +{ + typedef file_stream_device< FormatTag > device_type; +}; + +template< typename FormatTag > +struct is_adaptable_output_device< FormatTag + , TIFF* + , void + > + : mpl::true_ +{ + typedef file_stream_device< FormatTag > device_type; +}; + + +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 diff --git a/boost/gil/extension/io/tiff/detail/is_allowed.hpp b/boost/gil/extension/io/tiff/detail/is_allowed.hpp new file mode 100644 index 0000000000..d88413a63e --- /dev/null +++ b/boost/gil/extension/io/tiff/detail/is_allowed.hpp @@ -0,0 +1,226 @@ +/* + Copyright 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_DETAIL_IS_ALLOWED_HPP +#define BOOST_GIL_EXTENSION_IO_TIFF_DETAIL_IS_ALLOWED_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file +/// \brief +/// \author Christian Henning \n +/// +/// \date 2008 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +#include <boost/mpl/for_each.hpp> + +#include <boost/gil/io/base.hpp> + +namespace boost { namespace gil { namespace detail { + +typedef std::vector< tiff_bits_per_sample::type > channel_sizes_t; + +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 boost::enable_if< typename is_bit_aligned< typename get_pixel_type< View >::type >::type >::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 boost::enable_if< mpl::and_< mpl::not_< typename is_bit_aligned< typename get_pixel_type< View >::type >::type > + , is_unsigned< Channel > + > + >::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 boost::enable_if< mpl::and_< mpl::not_< typename is_bit_aligned< typename get_pixel_type< View >::type >::type > + , is_signed< Channel > + > + >::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 boost::enable_if< mpl::and_< mpl::not_< typename is_bit_aligned< typename get_pixel_type< View >::type >::type > + , is_floating_point< Channel > + > + >::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 + ) +{ + typedef typename View::value_type pixel_t; + typedef typename channel_traits< + typename element_type< pixel_t >::type >::value_type channel_t; + + 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 + ) +{ + typedef typename View::reference ref_t; + + typedef typename channel_traits< typename element_type< ref_t >::type >::value_type channel_t; + 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 > > { typedef C type; }; + +template< typename B, typename C, typename L, bool M > +struct channel_sizes_type< const bit_aligned_pixel_reference< B, C, L, M > > { typedef C type; }; + +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 + + typedef typename View::reference ref_t; + typedef typename channel_sizes_type< ref_t >::type cs_t; + + 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 + ); + + typedef typename get_pixel_type< View >::type pixel_t; + typedef typename channel_traits< + typename element_type< pixel_t >::type >::value_type channel_t; + + typedef typename num_channels< pixel_t >::value_type num_channel_t; + + 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 diff --git a/boost/gil/extension/io/tiff/detail/log.hpp b/boost/gil/extension/io/tiff/detail/log.hpp new file mode 100644 index 0000000000..965a576d28 --- /dev/null +++ b/boost/gil/extension/io/tiff/detail/log.hpp @@ -0,0 +1,77 @@ +/* + Copyright 2009 Christian Henning + 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_LOG_HPP +#define BOOST_GIL_EXTENSION_IO_TIFF_DETAIL_LOG_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file +/// \brief +/// \author Christian Henning \n +/// +/// \date 2009 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +extern "C" { +#include "tiffio.h" +} + +#include <iostream> + +namespace boost { namespace gil { + +class tiff_no_log +{ +public: + + tiff_no_log() + { + TIFFSetErrorHandler ( NULL ); + TIFFSetWarningHandler( NULL ); + } +}; + +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 diff --git a/boost/gil/extension/io/tiff/detail/read.hpp b/boost/gil/extension/io/tiff/detail/read.hpp new file mode 100644 index 0000000000..2471ff544e --- /dev/null +++ b/boost/gil/extension/io/tiff/detail/read.hpp @@ -0,0 +1,801 @@ +/* + 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_READER_HPP +#define BOOST_GIL_EXTENSION_IO_TIFF_DETAIL_READER_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file +/// \brief +/// \author Christian Henning, Lubomir Bourdev \n +/// +/// \date 2007-2012 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +// 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 <algorithm> +#include <string> +#include <vector> + +#include <boost/static_assert.hpp> + +#include <boost/gil/io/base.hpp> +#include <boost/gil/io/conversion_policies.hpp> +#include <boost/gil/io/bit_operations.hpp> +#include <boost/gil/io/row_buffer_helper.hpp> +#include <boost/gil/io/device.hpp> +#include <boost/gil/io/reader_base.hpp> + +#include <boost/gil/extension/io/tiff/detail/reader_backend.hpp> +#include <boost/gil/extension/io/tiff/detail/device.hpp> +#include <boost/gil/extension/io/tiff/detail/is_allowed.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 + +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 + ) + { + typedef typename kth_channel_view_type< K, View >::type plane_t; + 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: + + typedef reader< Device + , tiff_tag + , ConversionPolicy + > this_t; + + typedef typename ConversionPolicy::color_converter_type cc_t; + +public: + + typedef reader_backend< Device, tiff_tag > backend_t; + +public: + + 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 + + typedef typename is_same< ConversionPolicy + , detail::read_and_no_convert + >::type is_read_only; + + 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 = NULL; + tiff_color_map::green_t green = NULL; + tiff_color_map::blue_t blue = NULL; + + this->_io_dev.get_field_defaulted( red, green, blue ); + + typedef typename channel_traits< + typename element_type< + typename Indices_View::value_type >::type >::value_type channel_t; + + 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 + /// typedef Buffer row_buffer_helper_t; + /// not working? I get compiler error with MSVC10. + /// read_stripped_data IS working. + typedef detail::row_buffer_helper_view< View > row_buffer_helper_t; + + typedef typename row_buffer_helper_t::iterator_t it_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; + + assert( tile_x0 >= 0 && tile_y0 >= 0 && tile_x1 >= 0 && tile_y1 >= 0 ); + assert( tile_x0 <= img_x1 && tile_y0 <= img_y1 ); + 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; + 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 + /// typedef Buffer row_buffer_helper_t; + /// not working? I get compiler error with MSVC10. + /// read_stripped_data IS working. + typedef detail::row_buffer_helper_view< View > row_buffer_helper_t; + + typedef typename row_buffer_helper_t::iterator_t it_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 ) + { + typedef typename is_bit_aligned< typename View::value_type >::type is_view_bit_aligned_t; + + //typedef detail::row_buffer_helper_view< View > row_buffer_helper_t; + typedef Buffer row_buffer_helper_t; + + typedef typename row_buffer_helper_t::iterator_t it_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() + { + typedef typename Image::view_t 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 + > +{ + typedef reader< Device + , tiff_tag + , detail::read_and_no_convert + > parent_t; + +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 diff --git a/boost/gil/extension/io/tiff/detail/reader_backend.hpp b/boost/gil/extension/io/tiff/detail/reader_backend.hpp new file mode 100644 index 0000000000..d2a308f7d7 --- /dev/null +++ b/boost/gil/extension/io/tiff/detail/reader_backend.hpp @@ -0,0 +1,173 @@ +/* + Copyright 2012 Christian Henning + 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_READER_BACKEND_HPP +#define BOOST_GIL_EXTENSION_IO_TIFF_DETAIL_READER_BACKEND_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file +/// \brief +/// \author Christian Henning \n +/// +/// \date 2012 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +#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: + + typedef tiff_tag format_tag_t; + +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 ( NULL ) + , _green( NULL ) + , _blue ( NULL ) + { + 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 diff --git a/boost/gil/extension/io/tiff/detail/scanline_read.hpp b/boost/gil/extension/io/tiff/detail/scanline_read.hpp new file mode 100644 index 0000000000..7e7e2cc8b7 --- /dev/null +++ b/boost/gil/extension/io/tiff/detail/scanline_read.hpp @@ -0,0 +1,465 @@ +/* + 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_SCANLINE_READ_HPP +#define BOOST_GIL_EXTENSION_IO_TIFF_DETAIL_SCANLINE_READ_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file +/// \brief +/// \author Christian Henning, Lubomir Bourdev \n +/// +/// \date 2007-2012 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +// 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 <algorithm> +#include <string> +#include <vector> + +#include <boost/function.hpp> +#include <boost/static_assert.hpp> + +#include <boost/gil/io/base.hpp> +#include <boost/gil/io/conversion_policies.hpp> +#include <boost/gil/io/bit_operations.hpp> +#include <boost/gil/io/row_buffer_helper.hpp> +#include <boost/gil/io/device.hpp> +#include <boost/gil/io/reader_base.hpp> +#include <boost/gil/io/scanline_read_iterator.hpp> + +#include <boost/gil/extension/io/tiff/detail/reader_backend.hpp> +#include <boost/gil/extension/io/tiff/detail/device.hpp> +#include <boost/gil/extension/io/tiff/detail/is_allowed.hpp> + + +namespace boost { namespace gil { + +/// +/// TIFF scanline reader +/// +template< typename Device > +class scanline_reader< Device + , tiff_tag + > + : public reader_backend< Device + , tiff_tag + > +{ +public: + + + typedef tiff_tag tag_t; + typedef reader_backend < Device, tag_t > backend_t; + typedef scanline_reader< Device, tag_t > this_t; + typedef scanline_read_iterator< this_t > iterator_t; + +public: + + 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: + { + typedef channel_type< get_pixel_type< gray1_image_t::view_t >::type >::type channel_t; + + 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 = boost::mem_fn( &this_t::read_1_bit_index_image ); + + break; + } + + case 2: + { + typedef channel_type< get_pixel_type< gray2_image_t::view_t >::type >::type channel_t; + + 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 = boost::mem_fn( &this_t::read_2_bits_index_image ); + + break; + } + case 4: + { + typedef channel_type< get_pixel_type< gray4_image_t::view_t >::type >::type channel_t; + + 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 = boost::mem_fn( &this_t::read_4_bits_index_image ); + + break; + } + + case 8: + { + typedef channel_type< get_pixel_type< gray8_image_t::view_t >::type >::type channel_t; + + 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 = boost::mem_fn( &this_t::read_8_bits_index_image ); + + break; + } + + case 16: + { + typedef channel_type< get_pixel_type< gray16_image_t::view_t >::type >::type channel_t; + + 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 = boost::mem_fn( &this_t::read_16_bits_index_image ); + + break; + } + + case 24: + { + typedef channel_type< get_pixel_type< gray24_image_t::view_t >::type >::type channel_t; + + 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 = boost::mem_fn( &this_t::read_24_bits_index_image ); + + break; + } + + case 32: + { + typedef channel_type< get_pixel_type< gray32_image_t::view_t >::type >::type channel_t; + + 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 = boost::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 = boost::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 = boost::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 = boost::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 = boost::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 ) + { + typedef rgb16_view_t dst_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 >, mpl::true_ > _mirror_bites; + + boost::function< void ( this_t*, byte_t*, int ) > _read_function; +}; + +} // namespace gil +} // namespace boost + +#endif diff --git a/boost/gil/extension/io/tiff/detail/supported_types.hpp b/boost/gil/extension/io/tiff/detail/supported_types.hpp new file mode 100644 index 0000000000..7e08dffb55 --- /dev/null +++ b/boost/gil/extension/io/tiff/detail/supported_types.hpp @@ -0,0 +1,62 @@ +/* + Copyright 2007-2008 Christian Henning, Andreas Pokorny, 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_SUPPORTED_TYPES_HPP +#define BOOST_GIL_EXTENSION_IO_TIFF_DETAIL_SUPPORTED_TYPES_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file +/// \brief +/// \author Christian Henning, Andreas Pokorny, Lubomir Bourdev \n +/// +/// \date 2007-2008 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +#include <boost/mpl/not.hpp> +#include <boost/type_traits/is_same.hpp> + +#include <boost/gil/channel.hpp> +#include <boost/gil/color_base.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 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 diff --git a/boost/gil/extension/io/tiff/detail/writer_backend.hpp b/boost/gil/extension/io/tiff/detail/writer_backend.hpp new file mode 100644 index 0000000000..c7ed63a3e5 --- /dev/null +++ b/boost/gil/extension/io/tiff/detail/writer_backend.hpp @@ -0,0 +1,145 @@ +/* + Copyright 2012 Christian Henning + 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_WRITER_BACKEND_HPP +#define BOOST_GIL_EXTENSION_IO_TIFF_DETAIL_WRITER_BACKEND_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file +/// \brief +/// \author Christian Henning \n +/// +/// \date 2012 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +#include <boost/mpl/contains.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 Writer Backend +/// +template< typename Device > +struct writer_backend< Device + , tiff_tag + > +{ +public: + + typedef tiff_tag format_tag_t; + +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 ) + { + 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; + typedef typename color_space_type< View >::type color_space_t; + + 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 >::type::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 diff --git a/boost/gil/extension/io/tiff/old.hpp b/boost/gil/extension/io/tiff/old.hpp new file mode 100644 index 0000000000..d0fa548a37 --- /dev/null +++ b/boost/gil/extension/io/tiff/old.hpp @@ -0,0 +1,180 @@ +/* + Copyright 2007-2008 Christian Henning + 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_OLD_HPP +#define BOOST_GIL_EXTENSION_IO_TIFF_OLD_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file +/// \brief +/// \author Christian Henning \n +/// +/// \date 2007-2008 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +#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 +point2< std::ptrdiff_t > tiff_read_dimensions( const String& filename ) +{ + typedef typename get_reader_backend< String + , tiff_tag + >::type backend_t; + + backend_t backend = read_image_info( filename + , tiff_tag() + ); + + return point2< std::ptrdiff_t >( 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 diff --git a/boost/gil/extension/io/tiff/read.hpp b/boost/gil/extension/io/tiff/read.hpp new file mode 100644 index 0000000000..285a8bf331 --- /dev/null +++ b/boost/gil/extension/io/tiff/read.hpp @@ -0,0 +1,43 @@ +/* + Copyright 2007-2008 Christian Henning + 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_READ_HPP +#define BOOST_GIL_EXTENSION_IO_TIFF_READ_HPP + +#define BOOST_GIL_EXTENSION_IO_TIFF_READ_ENABLED + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file +/// \brief +/// \author Christian Henning \n +/// +/// \date 2007-2008 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +#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/read.hpp> +#include <boost/gil/extension/io/tiff/detail/scanline_read.hpp> + +#include <boost/gil/io/get_reader.hpp> +#include <boost/gil/io/make_backend.hpp> +#include <boost/gil/io/make_reader.hpp> +#include <boost/gil/io/make_dynamic_image_reader.hpp> +#include <boost/gil/io/make_scanline_reader.hpp> + +#include <boost/gil/io/read_view.hpp> +#include <boost/gil/io/read_image.hpp> +#include <boost/gil/io/read_image_info.hpp> +#include <boost/gil/io/read_and_convert_image.hpp> +#include <boost/gil/io/read_and_convert_view.hpp> + +#include <boost/gil/io/scanline_read_iterator.hpp> + +#endif diff --git a/boost/gil/extension/io/tiff/tags.hpp b/boost/gil/extension/io/tiff/tags.hpp new file mode 100644 index 0000000000..2242e969ea --- /dev/null +++ b/boost/gil/extension/io/tiff/tags.hpp @@ -0,0 +1,359 @@ +/* + Copyright 2007-2008 Christian Henning, Andreas Pokorny, 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_TAGS_HPP +#define BOOST_GIL_EXTENSION_IO_TIFF_TAGS_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file +/// \brief All supported tiff tags by the gil io extension. +/// \author Christian Henning, Andreas Pokorny, Lubomir Bourdev \n +/// +/// \date 2007-2008 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +#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 + +#include <boost/gil/io/base.hpp> +#include <boost/gil/extension/io/tiff/detail/log.hpp> + +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 + typedef mpl:: vector <typename property_base <T>:: type> arg_types; +}; + +/// 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 +{ + typedef uint16_t* red_t; + typedef uint16_t* green_t; + typedef uint16_t* blue_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 > { + typedef mpl:: vector <uint16_t, uint16_t const *> arg_types; +}; + +/// 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 > +{ + typedef boost::mpl::integral_c< type, 0 > default_value; +}; + +/// Non-baseline tags + +/// Defines type for icc profile property. +struct tiff_icc_profile : tiff_property_base< std:: vector <uint8_t>, TIFFTAG_ICCPROFILE > { + typedef mpl:: vector <uint32_t, void const *> arg_types; +}; + +/// 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 diff --git a/boost/gil/extension/io/tiff/write.hpp b/boost/gil/extension/io/tiff/write.hpp new file mode 100644 index 0000000000..1969a951fe --- /dev/null +++ b/boost/gil/extension/io/tiff/write.hpp @@ -0,0 +1,32 @@ +/* + Copyright 2007-2008 Christian Henning + 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_WRITE_HPP +#define BOOST_GIL_EXTENSION_IO_TIFF_WRITE_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file +/// \brief +/// \author Christian Henning \n +/// +/// \date 2007-2008 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +#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_writer.hpp> +#include <boost/gil/io/make_dynamic_image_writer.hpp> + +#include <boost/gil/io/write_view.hpp> + + +#endif diff --git a/boost/gil/extension/io/tiff_dynamic_io.hpp b/boost/gil/extension/io/tiff_dynamic_io.hpp deleted file mode 100644 index bb3c8c3ca7..0000000000 --- a/boost/gil/extension/io/tiff_dynamic_io.hpp +++ /dev/null @@ -1,135 +0,0 @@ -/* - Copyright 2005-2007 Adobe Systems Incorporated - - 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). - - See http://opensource.adobe.com/gil for most recent version including documentation. -*/ - -/*************************************************************************************************/ - -#ifndef GIL_TIFF_DYNAMIC_IO_H -#define GIL_TIFF_DYNAMIC_IO_H - -/// \file -/// \brief Support for reading and writing TIFF files -/// Requires libtiff! -/// \author Hailin Jin and Lubomir Bourdev \n -/// Adobe Systems Incorporated -/// \date 2005-2007 \n Last updated June 10, 2006 -// -// We are currently providing the following functions: -// template <typename Images> void tiff_read_image(const char*,any_image<Images>) -// template <typename Views> void tiff_write_view(const char*,any_image_view<Views>) -// - -#include <string> -#include <boost/mpl/bool.hpp> -#include "../dynamic_image/dynamic_image_all.hpp" -#include "io_error.hpp" -#include "tiff_io.hpp" -#include "dynamic_io.hpp" - -namespace boost { namespace gil { - -namespace detail { - -struct tiff_write_is_supported { - template<typename View> struct apply - : public mpl::bool_<tiff_write_support<View>::is_supported> {}; -}; - -class tiff_writer_dynamic : public tiff_writer { -public: - typedef void result_type; - tiff_writer_dynamic(const char* filename) : tiff_writer(filename) {} - - template <typename Views> - void write_view(const any_image_view<Views>& runtime_view) { - dynamic_io_fnobj<tiff_write_is_supported, tiff_writer> op(this); - apply_operation(runtime_view,op); - } -}; - -class tiff_type_format_checker { - int _bit_depth; - int _color_type; -public: - tiff_type_format_checker(int bit_depth_in,int color_type_in) : - _bit_depth(bit_depth_in),_color_type(color_type_in) {} - template <typename Image> - bool apply() { - return tiff_read_support<typename Image::view_t>::bit_depth==_bit_depth && - tiff_read_support<typename Image::view_t>::color_type==_color_type; - } -}; - -struct tiff_read_is_supported { - template<typename View> struct apply - : public mpl::bool_<tiff_read_support<View>::is_supported> {}; -}; - -class tiff_reader_dynamic : public tiff_reader { -public: - tiff_reader_dynamic(const char* filename) : tiff_reader(filename) {} - - template <typename Images> - void read_image(any_image<Images>& im) { - int width,height; - unsigned short bps,photometric; - TIFFGetField(_tp,TIFFTAG_IMAGEWIDTH,&width); - TIFFGetField(_tp,TIFFTAG_IMAGELENGTH,&height); - TIFFGetField(_tp,TIFFTAG_BITSPERSAMPLE,&bps); - TIFFGetField(_tp,TIFFTAG_PHOTOMETRIC,&photometric); - if (!construct_matched(im,tiff_type_format_checker(bps,photometric))) { - io_error("tiff_reader_dynamic::read_image(): no matching image type between those of the given any_image and that of the file"); - } else { - im.recreate(width,height); - dynamic_io_fnobj<tiff_read_is_supported, tiff_reader> op(this); - apply_operation(view(im),op); - } - } -}; - -} // namespace detail - -/// \ingroup TIFF_IO -/// \brief reads a TIFF image into a run-time instantiated image -/// Opens the given tiff file name, selects the first type in Images whose color space and channel are compatible to those of the image file -/// and creates a new image of that type with the dimensions specified by the image file. -/// Throws std::ios_base::failure if none of the types in Images are compatible with the type on disk. -template <typename Images> -inline void tiff_read_image(const char* filename,any_image<Images>& im) { - detail::tiff_reader_dynamic m(filename); - m.read_image(im); -} - -/// \ingroup TIFF_IO -/// \brief reads a TIFF image into a run-time instantiated image -template <typename Images> -inline void tiff_read_image(const std::string& filename,any_image<Images>& im) { - tiff_read_image(filename.c_str(),im); -} - -/// \ingroup TIFF_IO -/// \brief Saves the currently instantiated view to a tiff file specified by the given tiff image file name. -/// Throws std::ios_base::failure if the currently instantiated view type is not supported for writing by the I/O extension -/// or if it fails to create the file. -template <typename Views> -inline void tiff_write_view(const char* filename,const any_image_view<Views>& runtime_view) { - detail::tiff_writer_dynamic m(filename); - m.write_view(runtime_view); -} - -/// \ingroup TIFF_IO -/// \brief Saves the currently instantiated view to a tiff file specified by the given tiff image file name. -template <typename Views> -inline void tiff_write_view(const std::string& filename,const any_image_view<Views>& runtime_view) { - tiff_write_view(filename.c_str(),runtime_view); -} - -} } // namespace boost::gil - -#endif diff --git a/boost/gil/extension/io/tiff_io.hpp b/boost/gil/extension/io/tiff_io.hpp deleted file mode 100644 index 4198a3f984..0000000000 --- a/boost/gil/extension/io/tiff_io.hpp +++ /dev/null @@ -1,511 +0,0 @@ -/* - Copyright 2005-2007 Adobe Systems Incorporated - - 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). - - See http://opensource.adobe.com/gil for most recent version including documentation. -*/ - -/*************************************************************************************************/ - -#ifndef GIL_TIFF_IO_H -#define GIL_TIFF_IO_H - -/// \file -/// \brief Support for reading and writing TIFF files -/// Requires libtiff! -/// \author Hailin Jin and Lubomir Bourdev \n -/// Adobe Systems Incorporated -/// \date 2005-2007 \n Last updated September 24, 2006 - -#include <vector> -#include <string> -#include <algorithm> -#include <boost/static_assert.hpp> -#include <tiffio.h> -#include "../../gil_all.hpp" -#include "io_error.hpp" - -namespace boost { namespace gil { - -namespace detail { - -template <typename Channel,typename ColorSpace> -struct tiff_read_support_private { - BOOST_STATIC_CONSTANT(bool,is_supported=false); - BOOST_STATIC_CONSTANT(int,bit_depth=0); - BOOST_STATIC_CONSTANT(int,color_type=0); -}; -template <> -struct tiff_read_support_private<bits8,gray_t> { - BOOST_STATIC_CONSTANT(bool,is_supported=true); - BOOST_STATIC_CONSTANT(int,bit_depth=8); - BOOST_STATIC_CONSTANT(int,color_type=PHOTOMETRIC_MINISBLACK); -}; -template <> -struct tiff_read_support_private<bits8,rgb_t> { - BOOST_STATIC_CONSTANT(bool,is_supported=true); - BOOST_STATIC_CONSTANT(int,bit_depth=8); - BOOST_STATIC_CONSTANT(int,color_type=PHOTOMETRIC_RGB); -}; -template <> -struct tiff_read_support_private<bits16,gray_t> { - BOOST_STATIC_CONSTANT(bool,is_supported=true); - BOOST_STATIC_CONSTANT(int,bit_depth=16); - BOOST_STATIC_CONSTANT(int,color_type=PHOTOMETRIC_MINISBLACK); -}; -template <> -struct tiff_read_support_private<bits16,rgb_t> { - BOOST_STATIC_CONSTANT(bool,is_supported=true); - BOOST_STATIC_CONSTANT(int,bit_depth=16); - BOOST_STATIC_CONSTANT(int,color_type=PHOTOMETRIC_RGB); -}; -template <> -struct tiff_read_support_private<bits32f,gray_t> { - BOOST_STATIC_CONSTANT(bool,is_supported=true); - BOOST_STATIC_CONSTANT(int,bit_depth=32); - BOOST_STATIC_CONSTANT(int,color_type=PHOTOMETRIC_MINISBLACK); -}; -template <> -struct tiff_read_support_private<bits32f,rgb_t> { - BOOST_STATIC_CONSTANT(bool,is_supported=true); - BOOST_STATIC_CONSTANT(int,bit_depth=32); - BOOST_STATIC_CONSTANT(int,color_type=PHOTOMETRIC_RGB); -}; - -template <typename Channel,typename ColorSpace> -struct tiff_write_support_private { - BOOST_STATIC_CONSTANT(bool,is_supported=false); - BOOST_STATIC_CONSTANT(int,bit_depth=0); - BOOST_STATIC_CONSTANT(int,color_type=0); -}; -template <> -struct tiff_write_support_private<bits8,gray_t> { - BOOST_STATIC_CONSTANT(bool,is_supported=true); - BOOST_STATIC_CONSTANT(int,bit_depth=8); - BOOST_STATIC_CONSTANT(int,color_type=PHOTOMETRIC_MINISBLACK); -}; -template <> -struct tiff_write_support_private<bits8,rgb_t> { - BOOST_STATIC_CONSTANT(bool,is_supported=true); - BOOST_STATIC_CONSTANT(int,bit_depth=8); - BOOST_STATIC_CONSTANT(int,color_type=PHOTOMETRIC_RGB); -}; -template <> -struct tiff_write_support_private<bits16,gray_t> { - BOOST_STATIC_CONSTANT(bool,is_supported=true); - BOOST_STATIC_CONSTANT(int,bit_depth=16); - BOOST_STATIC_CONSTANT(int,color_type=PHOTOMETRIC_MINISBLACK); -}; -template <> -struct tiff_write_support_private<bits16,rgb_t> { - BOOST_STATIC_CONSTANT(bool,is_supported=true); - BOOST_STATIC_CONSTANT(int,bit_depth=16); - BOOST_STATIC_CONSTANT(int,color_type=PHOTOMETRIC_RGB); -}; -template <> -struct tiff_write_support_private<bits32f,gray_t> { - BOOST_STATIC_CONSTANT(bool,is_supported=true); - BOOST_STATIC_CONSTANT(int,bit_depth=32); - BOOST_STATIC_CONSTANT(int,color_type=PHOTOMETRIC_MINISBLACK); -}; -template <> -struct tiff_write_support_private<bits32f,rgb_t> { - BOOST_STATIC_CONSTANT(bool,is_supported=true); - BOOST_STATIC_CONSTANT(int,bit_depth=32); - BOOST_STATIC_CONSTANT(int,color_type=PHOTOMETRIC_RGB); -}; - -class tiff_reader { -protected: - TIFF *_tp; -public: - tiff_reader(const char* filename,tdir_t dirnum=0) { - io_error_if((_tp=TIFFOpen(filename,"r"))==NULL, - "tiff_reader: fail to open file"); - if(dirnum>0) { - io_error_if(TIFFSetDirectory(_tp,dirnum)!=1, - "tiff_reader: fail to set directory"); - } - } - ~tiff_reader() { TIFFClose(_tp); } - template <typename View> - void apply(const View& view) { - unsigned short bps,photometric; - point2<std::ptrdiff_t> dims=get_dimensions(); - io_error_if(TIFFGetField(_tp,TIFFTAG_BITSPERSAMPLE,&bps)!=1); - io_error_if(TIFFGetField(_tp,TIFFTAG_PHOTOMETRIC,&photometric)!=1); - io_error_if(dims!=view.dimensions(), - "tiff_read_view: input view size does not match TIFF file size"); - io_error_if(tiff_read_support_private<typename channel_type<View>::type, - typename color_space_type<View>::type>::bit_depth!=bps || - tiff_read_support_private<typename channel_type<View>::type, - typename color_space_type<View>::type>::color_type!=photometric, - "tiff_read_view: input view type is incompatible with the image type"); - std::size_t element_size=sizeof(pixel<typename channel_type<View>::type, - layout<typename color_space_type<View>::type> >); - std::size_t size_to_allocate = (std::max)((std::size_t)view.width(), - (std::size_t)(TIFFScanlineSize(_tp)+element_size-1)/element_size); - std::vector<pixel<typename channel_type<View>::type, - layout<typename color_space_type<View>::type> > > row(size_to_allocate); - for (int y=0;y<view.height();++y) { - io_error_if(TIFFReadScanline(_tp,&row.front(), y)!=1); - std::copy(row.begin(),row.begin()+view.width(),view.row_begin(y)); - } - } - point2<std::ptrdiff_t> get_dimensions() { - int w,h; - io_error_if(TIFFGetField(_tp,TIFFTAG_IMAGEWIDTH, &w)!=1); - io_error_if(TIFFGetField(_tp,TIFFTAG_IMAGELENGTH,&h)!=1); - return point2<std::ptrdiff_t>(w,h); - } - - template <typename Image> - void read_image(Image& im) { - im.recreate(get_dimensions()); - apply(view(im)); - } -}; - -// This code will be simplified... -template <typename CC> -class tiff_reader_color_convert : public tiff_reader { -private: - CC _cc; -public: - tiff_reader_color_convert(const char* filename,tdir_t dirnum=0) : - tiff_reader(filename,dirnum) {} - tiff_reader_color_convert(const char* filename,CC cc_in,tdir_t dirnum=0) : - tiff_reader(filename,dirnum),_cc(cc_in) {} - template <typename View> - void apply(const View& view) { - point2<std::ptrdiff_t> dims=get_dimensions(); - unsigned short bps,photometric; - io_error_if(TIFFGetField(_tp,TIFFTAG_BITSPERSAMPLE,&bps)!=1); - io_error_if(TIFFGetField(_tp,TIFFTAG_PHOTOMETRIC,&photometric)!=1); - io_error_if(dims!=view.dimensions(), - "tiff_reader_color_convert::apply(): input view size does not match TIFF file size"); - switch (photometric) { - case PHOTOMETRIC_MINISBLACK: { - switch (bps) { - case 8: { - std::size_t element_size=sizeof(gray8_pixel_t); - std::size_t size_to_allocate = (std::max)((std::size_t)view.width(), - (std::size_t)(TIFFScanlineSize(_tp)+element_size-1)/element_size); - std::vector<gray8_pixel_t> row(size_to_allocate); - for (int y=0;y<view.height();++y) { - io_error_if(TIFFReadScanline(_tp,&row.front(), y)!=1); - std::transform(row.begin(),row.begin()+view.width(),view.row_begin(y), - color_convert_deref_fn<gray8_ref_t,typename View::value_type,CC>(_cc)); - } - break; - } - case 16: { - std::size_t element_size=sizeof(gray16_pixel_t); - std::size_t size_to_allocate = (std::max)((std::size_t)view.width(), - (std::size_t)(TIFFScanlineSize(_tp)+element_size-1)/element_size); - std::vector<gray16_pixel_t> row(size_to_allocate); - for (int y=0;y<view.height();++y) { - io_error_if(TIFFReadScanline(_tp,&row.front(), y)!=1); - std::transform(row.begin(),row.begin()+view.width(),view.row_begin(y), - color_convert_deref_fn<gray16_ref_t,typename View::value_type,CC>(_cc)); - } - break; - } - case 32: { - std::size_t element_size=sizeof(gray32f_pixel_t); - std::size_t size_to_allocate = (std::max)((std::size_t)view.width(), - (std::size_t)(TIFFScanlineSize(_tp)+element_size-1)/element_size); - std::vector<gray32f_pixel_t> row(size_to_allocate); - for (int y=0;y<view.height();++y) { - io_error_if(TIFFReadScanline(_tp,&row.front(), y)!=1); - std::transform(row.begin(),row.begin()+view.width(),view.row_begin(y), - color_convert_deref_fn<gray32f_ref_t,typename View::value_type,CC>(_cc)); - } - break; - } - default: - io_error("tiff_reader_color_convert::apply(): unknown combination of color type and bit depth"); - } - break; - } - case PHOTOMETRIC_RGB: { - switch (bps) { - case 8: { - std::size_t element_size=sizeof(rgb8_pixel_t); - std::size_t size_to_allocate = (std::max)((std::size_t)view.width(), - (std::size_t)(TIFFScanlineSize(_tp)+element_size-1)/element_size); - std::vector<rgb8_pixel_t> row(size_to_allocate); - for (int y=0;y<view.height();++y) { - io_error_if(TIFFReadScanline(_tp,&row.front(), y)!=1); - std::transform(row.begin(),row.begin()+view.width(),view.row_begin(y), - color_convert_deref_fn<rgb8_ref_t,typename View::value_type,CC>(_cc)); - } - break; - } - case 16: { - std::size_t element_size=sizeof(rgb16_pixel_t); - std::size_t size_to_allocate = (std::max)((std::size_t)view.width(), - (std::size_t)(TIFFScanlineSize(_tp)+element_size-1)/element_size); - std::vector<rgb16_pixel_t> row(size_to_allocate); - for (int y=0;y<view.height();++y) { - io_error_if(TIFFReadScanline(_tp,&row.front(), y)!=1); - std::transform(row.begin(),row.begin()+view.width(),view.row_begin(y), - color_convert_deref_fn<rgb16_ref_t,typename View::value_type,CC>(_cc)); - } - break; - } - case 32: { - std::size_t element_size=sizeof(rgb32f_pixel_t); - std::size_t size_to_allocate = (std::max)((std::size_t)view.width(), - (std::size_t)(TIFFScanlineSize(_tp)+element_size-1)/element_size); - std::vector<rgb32f_pixel_t> row(size_to_allocate); - for (int y=0;y<view.height();++y) { - io_error_if(TIFFReadScanline(_tp,&row.front(), y)!=1); - std::transform(row.begin(),row.begin()+view.width(),view.row_begin(y), - color_convert_deref_fn<rgb32f_ref_t,typename View::value_type,CC>(_cc)); - } - break; - } - default: - io_error("tiff_reader_color_convert::apply(): unknown combination of color type and bit depth"); - } - break; - } - default: { - // reads an image in incompatible format via TIFFReadRGBAImage - rgba8_image_t rgbaImg(dims); - io_error_if(!TIFFReadRGBAImage(_tp, dims.x, dims.y, (uint32*)&gil::view(rgbaImg)(0,0), 0), - "tiff_reader_color_convert::unsupported image format"); - copy_and_convert_pixels(flipped_up_down_view(const_view(rgbaImg)), view, _cc); - } - } - } - template <typename Image> - void read_image(Image& im) { - im.recreate(get_dimensions()); - apply(view(im)); - } -}; - -class tiff_writer { -protected: - TIFF* _tp; -public: - tiff_writer(const char *filename) { - io_error_if((_tp=TIFFOpen(filename,"w"))==NULL, - "tiff_writer: fail to open file"); - } - ~tiff_writer() {TIFFClose(_tp);} - template <typename View> - void apply(const View& view) { - io_error_if(TIFFSetField(_tp,TIFFTAG_IMAGELENGTH, view.height())!=1); - io_error_if(TIFFSetField(_tp,TIFFTAG_IMAGEWIDTH, view.width())!=1); - io_error_if(TIFFSetField(_tp,TIFFTAG_PHOTOMETRIC, tiff_write_support_private<typename channel_type<View>::type, - typename color_space_type<View>::type>::color_type)!=1); - io_error_if(TIFFSetField(_tp,TIFFTAG_RESOLUTIONUNIT, RESUNIT_NONE)!=1); - io_error_if(TIFFSetField(_tp,TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG)!=1); - io_error_if(TIFFSetField(_tp,TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT)!=1); - io_error_if(TIFFSetField(_tp,TIFFTAG_SAMPLESPERPIXEL,num_channels<View>::value)!=1); - io_error_if(TIFFSetField(_tp,TIFFTAG_BITSPERSAMPLE, tiff_write_support_private<typename channel_type<View>::type, - typename color_space_type<View>::type>::bit_depth)!=1); - io_error_if(TIFFSetField(_tp,TIFFTAG_ROWSPERSTRIP, TIFFDefaultStripSize(_tp, 0))!=1); - std::vector<pixel<typename channel_type<View>::type, - layout<typename color_space_type<View>::type> > > row(view.width()); - for (int y=0;y<view.height();++y) { - std::copy(view.row_begin(y),view.row_end(y),row.begin()); - io_error_if(TIFFWriteScanline(_tp,&row.front(),y,0)!=1, - "tiff_write_view: fail to write file"); - } - } -}; - -} // namespace detail - -/// \ingroup TIFF_IO -/// \brief Determines whether the given view type is supported for reading -template <typename View> -struct tiff_read_support { - BOOST_STATIC_CONSTANT(bool,is_supported= - (detail::tiff_read_support_private<typename channel_type<View>::type, - typename color_space_type<View>::type>::is_supported)); - BOOST_STATIC_CONSTANT(int,bit_depth= - (detail::tiff_read_support_private<typename channel_type<View>::type, - typename color_space_type<View>::type>::bit_depth)); - BOOST_STATIC_CONSTANT(int,color_type= - (detail::tiff_read_support_private<typename channel_type<View>::type, - typename color_space_type<View>::type>::color_type)); -}; - -/// \ingroup TIFF_IO -/// \brief Returns the number of directories in the TIFF file -inline int tiff_get_directory_count(const char* filename) { - TIFF *tif; - io_error_if((tif=TIFFOpen(filename,"r"))==NULL, - "tiff_get_count: fail to open file"); - - int dircount = 0; - do { - dircount++; - } while (TIFFReadDirectory(tif)); - - TIFFClose(tif); - return dircount; -} - -/// \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 -inline point2<std::ptrdiff_t> tiff_read_dimensions(const char* filename,tdir_t dirnum=0) { - detail::tiff_reader m(filename,dirnum); - return m.get_dimensions(); -} - -/// \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 -inline point2<std::ptrdiff_t> tiff_read_dimensions(const std::string& filename,tdir_t dirnum=0) { - return tiff_read_dimensions(filename.c_str(),dirnum); -} - -/// \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 View> -inline void tiff_read_view(const char* filename,const View& view,tdir_t dirnum=0) { - BOOST_STATIC_ASSERT(tiff_read_support<View>::is_supported); - detail::tiff_reader m(filename,dirnum); - m.apply(view); -} - -/// \ingroup TIFF_IO -/// \brief Loads the image specified by the given tiff image file name into the given view. -template <typename View> -inline void tiff_read_view(const std::string& filename,const View& view,tdir_t dirnum=0) { - tiff_read_view(filename.c_str(),view,dirnum); -} - -/// \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 Image> -void tiff_read_image(const char* filename,Image& im,tdir_t dirnum=0) { - BOOST_STATIC_ASSERT(tiff_read_support<typename Image::view_t>::is_supported); - detail::tiff_reader m(filename,dirnum); - m.read_image(im); -} - -/// \ingroup TIFF_IO -/// \brief Allocates a new image whose dimensions are determined by the given tiff image file, and loads the pixels into it. -template <typename Image> -inline void tiff_read_image(const std::string& filename,Image& im,tdir_t dirnum=0) { - tiff_read_image(filename.c_str(),im,dirnum); -} - -/// \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 View,typename CC> -inline void tiff_read_and_convert_view(const char* filename,const View& view,CC cc,tdir_t dirnum=0) { - detail::tiff_reader_color_convert<CC> m(filename,cc,dirnum); - m.apply(view); -} - -/// \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 View> -inline void tiff_read_and_convert_view(const char* filename,const View& view,tdir_t dirnum=0) { - detail::tiff_reader_color_convert<default_color_converter> m(filename,default_color_converter(),dirnum); - m.apply(view); -} - -/// \ingroup TIFF_IO -/// \brief Loads and color-converts the image specified by the given tiff image file name into the given view. -template <typename View,typename CC> -inline void tiff_read_and_convert_view(const std::string& filename,const View& view,CC cc,tdir_t dirnum=0) { - tiff_read_and_convert_view(filename.c_str(),view,cc,dirnum); -} - -/// \ingroup TIFF_IO -/// \brief Loads and color-converts the image specified by the given tiff image file name into the given view. -template <typename View> -inline void tiff_read_and_convert_view(const std::string& filename,const View& view,tdir_t dirnum=0) { - tiff_read_and_convert_view(filename.c_str(),view,dirnum); -} - -/// \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 Image,typename CC> -void tiff_read_and_convert_image(const char* filename,Image& im,CC cc,tdir_t dirnum=0) { - detail::tiff_reader_color_convert<CC> m(filename,cc,dirnum); - m.read_image(im); -} - -/// \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 Image> -void tiff_read_and_convert_image(const char* filename,Image& im,tdir_t dirnum=0) { - detail::tiff_reader_color_convert<default_color_converter> m(filename,default_color_converter(),dirnum); - m.read_image(im); -} - -/// \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. -template <typename Image,typename CC> -inline void tiff_read_and_convert_image(const std::string& filename,Image& im,CC cc,tdir_t dirnum=0) { - tiff_read_and_convert_image(filename.c_str(),im,cc,dirnum); -} - -/// \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. -template <typename Image> -inline void tiff_read_and_convert_image(const std::string& filename,Image& im,tdir_t dirnum=0) { - tiff_read_and_convert_image(filename.c_str(),im,dirnum); -} - -/// \ingroup TIFF_IO -/// \brief Determines whether the given view type is supported for writing -template <typename View> -struct tiff_write_support { - BOOST_STATIC_CONSTANT(bool,is_supported= - (detail::tiff_write_support_private<typename channel_type<View>::type, - typename color_space_type<View>::type>::is_supported)); - BOOST_STATIC_CONSTANT(int,bit_depth= - (detail::tiff_write_support_private<typename channel_type<View>::type, - typename color_space_type<View>::type>::bit_depth)); - BOOST_STATIC_CONSTANT(int,color_type= - (detail::tiff_write_support_private<typename channel_type<View>::type, - typename color_space_type<View>::type>::color_type)); - BOOST_STATIC_CONSTANT(bool, value=is_supported); -}; - -/// \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 View> -inline void tiff_write_view(const char* filename,const View& view) { - BOOST_STATIC_ASSERT(tiff_write_support<View>::is_supported); - detail::tiff_writer m(filename); - m.apply(view); -} - -/// \ingroup TIFF_IO -/// \brief Saves the view to a tiff file specified by the given tiff image file name. -template <typename View> -inline void tiff_write_view(const std::string& filename,const View& view) { - tiff_write_view(filename.c_str(),view); -} - -} } // namespace boost::gil - -#endif diff --git a/boost/gil/extension/numeric/affine.hpp b/boost/gil/extension/numeric/affine.hpp new file mode 100644 index 0000000000..6a77070063 --- /dev/null +++ b/boost/gil/extension/numeric/affine.hpp @@ -0,0 +1,93 @@ +/* + Copyright 2005-2007 Adobe Systems Incorporated + + 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_NUMERIC_AFFINE_HPP +#define BOOST_GIL_EXTENSION_NUMERIC_AFFINE_HPP + +#include <boost/gil/utilities.hpp> // point2 + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file +/// \brief support for affine transformations +/// \author Lubomir Bourdev and Hailin Jin \n +/// Adobe Systems Incorporated +/// \date 2005-2007 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +namespace boost { namespace gil { + +//////////////////////////////////////////////////////////////////////////////////////// +/// +/// Simple matrix to do 2D affine transformations. It is actually 3x3 but the last column is [0 0 1] +/// +//////////////////////////////////////////////////////////////////////////////////////// +template <typename T> +class matrix3x2 { +public: + matrix3x2() : a(1), b(0), c(0), d(1), e(0), f(0) {} + matrix3x2(T A, T B, T C, T D, T E, T F) : a(A),b(B),c(C),d(D),e(E),f(F) {} + matrix3x2(const matrix3x2& mat) : a(mat.a), b(mat.b), c(mat.c), d(mat.d), e(mat.e), f(mat.f) {} + matrix3x2& operator=(const matrix3x2& m) { a=m.a; b=m.b; c=m.c; d=m.d; e=m.e; f=m.f; return *this; } + + matrix3x2& operator*=(const matrix3x2& m) { (*this) = (*this)*m; return *this; } + + static matrix3x2 get_rotate(T rads) { T c=std::cos(rads); T s=std::sin(rads); return matrix3x2(c,s,-s,c,0,0); } + static matrix3x2 get_translate(const point2<T>& t) { return matrix3x2(1 ,0,0,1 ,t.x,t.y); } + static matrix3x2 get_translate(T x, T y) { return matrix3x2(1 ,0,0,1 ,x, y ); } + static matrix3x2 get_scale (const point2<T>& s) { return matrix3x2(s.x,0,0,s.y,0 ,0 ); } + static matrix3x2 get_scale (T x, T y) { return matrix3x2(x, 0,0,y, 0 ,0 ); } + static matrix3x2 get_scale (T s) { return matrix3x2(s ,0,0,s ,0 ,0 ); } + + T a,b,c,d,e,f; +}; + +template <typename T> BOOST_FORCEINLINE +matrix3x2<T> operator*(const matrix3x2<T>& m1, const matrix3x2<T>& m2) { + return matrix3x2<T>( + m1.a * m2.a + m1.b * m2.c, + m1.a * m2.b + m1.b * m2.d, + m1.c * m2.a + m1.d * m2.c, + m1.c * m2.b + m1.d * m2.d, + m1.e * m2.a + m1.f * m2.c + m2.e, + m1.e * m2.b + m1.f * m2.d + m2.f ); +} + +template <typename T, typename F> BOOST_FORCEINLINE +point2<F> operator*(const point2<T>& p, const matrix3x2<F>& m) { + return point2<F>(m.a*p.x + m.c*p.y + m.e, m.b*p.x + m.d*p.y + m.f); +} + +//////////////////////////////////////////////////////////////////////////////////////// +/// Define affine mapping that transforms the source coordinates by the affine transformation +//////////////////////////////////////////////////////////////////////////////////////// +/* +template <typename MapFn> +concept MappingFunctionConcept { + typename mapping_traits<MapFn>::result_type; where PointNDConcept<result_type>; + + template <typename Domain> { where PointNDConcept<Domain> } + result_type transform(MapFn&, const Domain& src); +}; +*/ + +template <typename T> struct mapping_traits; + +template <typename F> +struct mapping_traits<matrix3x2<F> > { + typedef point2<F> result_type; +}; + +template <typename F, typename F2> BOOST_FORCEINLINE +point2<F> transform(const matrix3x2<F>& mat, const point2<F2>& src) { return src * mat; } + +} } // namespace boost::gil + +#endif // BOOST_GIL_EXTENSION_NUMERIC_AFFINE_HPP diff --git a/boost/gil/extension/numeric/algorithm.hpp b/boost/gil/extension/numeric/algorithm.hpp new file mode 100644 index 0000000000..b7c175985f --- /dev/null +++ b/boost/gil/extension/numeric/algorithm.hpp @@ -0,0 +1,158 @@ +/* + Copyright 2005-2007 Adobe Systems Incorporated + + 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_NUMERIC_ALGORITHM_HPP +#define BOOST_GIL_EXTENSION_NUMERIC_ALGORITHM_HPP + +/*! +/// \file +/// \brief Numeric algorithms +/// \author Hailin Jin and Lubomir Bourdev \n +/// Adobe Systems Incorporated +/// \date 2005-2007 \n +*/ + +#include <cassert> +#include <iterator> +#include <algorithm> +#include <numeric> + +#include <boost/gil/gil_config.hpp> +#include <boost/gil/pixel_iterator.hpp> +#include <boost/gil/metafunctions.hpp> + +namespace boost { namespace gil { + +/// \brief Returns the reference proxy associated with a type that has a \p "reference" member typedef. +/// +/// The reference proxy is the reference type, but with stripped-out C++ reference. It models PixelConcept +template <typename T> +struct pixel_proxy : public remove_reference<typename T::reference> {}; + +/// \brief std::for_each for a pair of iterators +template <typename Iterator1,typename Iterator2,typename BinaryFunction> +BinaryFunction for_each(Iterator1 first1,Iterator1 last1,Iterator2 first2,BinaryFunction f) { + while(first1!=last1) + f(*first1++,*first2++); + return f; +} + +template <typename SrcIterator,typename DstIterator> +inline DstIterator assign_pixels(SrcIterator src,SrcIterator src_end,DstIterator dst) { + for_each(src,src_end,dst,pixel_assigns_t<typename pixel_proxy<typename std::iterator_traits<SrcIterator>::value_type>::type, + typename pixel_proxy<typename std::iterator_traits<DstIterator>::value_type>::type>()); + return dst+(src_end-src); +} + +namespace detail { +template <std::size_t Size> +struct inner_product_k_t { + template <class _InputIterator1, class _InputIterator2, class _Tp, + class _BinaryOperation1, class _BinaryOperation2> + static _Tp apply(_InputIterator1 __first1, + _InputIterator2 __first2, _Tp __init, + _BinaryOperation1 __binary_op1, + _BinaryOperation2 __binary_op2) { + __init = __binary_op1(__init, __binary_op2(*__first1, *__first2)); + return inner_product_k_t<Size-1>::template apply(__first1+1,__first2+1,__init, + __binary_op1, __binary_op2); + } +}; + +template <> +struct inner_product_k_t<0> { + template <class _InputIterator1, class _InputIterator2, class _Tp, + class _BinaryOperation1, class _BinaryOperation2> + static _Tp apply(_InputIterator1 __first1, + _InputIterator2 __first2, _Tp __init, + _BinaryOperation1 __binary_op1, + _BinaryOperation2 __binary_op2) { + return __init; + } +}; +} // namespace detail + +/// static version of std::inner_product +template <std::size_t Size, + class _InputIterator1, class _InputIterator2, class _Tp, + class _BinaryOperation1, class _BinaryOperation2> +BOOST_FORCEINLINE +_Tp inner_product_k(_InputIterator1 __first1, + _InputIterator2 __first2, + _Tp __init, + _BinaryOperation1 __binary_op1, + _BinaryOperation2 __binary_op2) { + return detail::inner_product_k_t<Size>::template apply(__first1,__first2,__init, + __binary_op1, __binary_op2); +} + +/// \brief 1D un-guarded correlation with a variable-size kernel +template <typename PixelAccum,typename SrcIterator,typename KernelIterator,typename Integer,typename DstIterator> +inline DstIterator correlate_pixels_n(SrcIterator src_begin,SrcIterator src_end, + KernelIterator ker_begin,Integer ker_size, + DstIterator dst_begin) { + typedef typename pixel_proxy<typename std::iterator_traits<SrcIterator>::value_type>::type PIXEL_SRC_REF; + typedef typename pixel_proxy<typename std::iterator_traits<DstIterator>::value_type>::type PIXEL_DST_REF; + typedef typename std::iterator_traits<KernelIterator>::value_type kernel_type; + PixelAccum acc_zero; pixel_zeros_t<PixelAccum>()(acc_zero); + while(src_begin!=src_end) { + pixel_assigns_t<PixelAccum,PIXEL_DST_REF>()( + std::inner_product(src_begin,src_begin+ker_size,ker_begin,acc_zero, + pixel_plus_t<PixelAccum,PixelAccum,PixelAccum>(), + pixel_multiplies_scalar_t<PIXEL_SRC_REF,kernel_type,PixelAccum>()), + *dst_begin); + ++src_begin; ++dst_begin; + } + return dst_begin; +} + +/// \brief 1D un-guarded correlation with a fixed-size kernel +template <std::size_t Size,typename PixelAccum,typename SrcIterator,typename KernelIterator,typename DstIterator> +inline DstIterator correlate_pixels_k(SrcIterator src_begin,SrcIterator src_end, + KernelIterator ker_begin, + DstIterator dst_begin) { + typedef typename pixel_proxy<typename std::iterator_traits<SrcIterator>::value_type>::type PIXEL_SRC_REF; + typedef typename pixel_proxy<typename std::iterator_traits<DstIterator>::value_type>::type PIXEL_DST_REF; + typedef typename std::iterator_traits<KernelIterator>::value_type kernel_type; + PixelAccum acc_zero; pixel_zeros_t<PixelAccum>()(acc_zero); + while(src_begin!=src_end) { + pixel_assigns_t<PixelAccum,PIXEL_DST_REF>()( + inner_product_k<Size>(src_begin,ker_begin,acc_zero, + pixel_plus_t<PixelAccum,PixelAccum,PixelAccum>(), + pixel_multiplies_scalar_t<PIXEL_SRC_REF,kernel_type,PixelAccum>()), + *dst_begin); + ++src_begin; ++dst_begin; + } + return dst_begin; +} + +/// \brief destination is set to be product of the source and a scalar +template <typename PixelAccum,typename SrcView,typename Scalar,typename DstView> +inline void view_multiplies_scalar(const SrcView& src,const Scalar& scalar,const DstView& dst) { + assert(src.dimensions()==dst.dimensions()); + typedef typename pixel_proxy<typename SrcView::value_type>::type PIXEL_SRC_REF; + typedef typename pixel_proxy<typename DstView::value_type>::type PIXEL_DST_REF; + int height=src.height(); + for(int rr=0;rr<height;++rr) { + typename SrcView::x_iterator it_src=src.row_begin(rr); + typename DstView::x_iterator it_dst=dst.row_begin(rr); + typename SrcView::x_iterator it_src_end=src.row_end(rr); + while(it_src!=it_src_end) { + pixel_assigns_t<PixelAccum,PIXEL_DST_REF>()( + pixel_multiplies_scalar_t<PIXEL_SRC_REF,Scalar,PixelAccum>()(*it_src,scalar), + *it_dst); + ++it_src; ++it_dst; + } + } +} + +} } // namespace boost::gil + +#endif // BOOST_GIL_EXTENSION_NUMERIC_ALGORITHM_HPP diff --git a/boost/gil/extension/numeric/channel_numeric_operations.hpp b/boost/gil/extension/numeric/channel_numeric_operations.hpp new file mode 100644 index 0000000000..d2407f9814 --- /dev/null +++ b/boost/gil/extension/numeric/channel_numeric_operations.hpp @@ -0,0 +1,159 @@ +/* + Copyright 2005-2007 Adobe Systems Incorporated + + 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_NUMERIC_CHANNEL_NUMERIC_OPERATIONS_HPP +#define BOOST_GIL_EXTENSION_NUMERIC_CHANNEL_NUMERIC_OPERATIONS_HPP + +/*! +/// \file +/// \brief Structures for channel-wise numeric operations +/// \author Hailin Jin and Lubomir Bourdev \n +/// Adobe Systems Incorporated +/// \date 2005-2007 \n +/// Currently defined structures: +/// channel_plus_t (+), channel_minus_t (-), +/// channel_multiplies_t (*), channel_divides_t (/), +/// channel_plus_scalar_t (+s), channel_minus_scalar_t (-s), +/// channel_multiplies_scalar_t (*s), channel_divides_scalar_t (/s), +/// channel_halves_t (/=2), channel_zeros_t (=0), channel_assigns_t (=) +*/ + +#include <functional> + +#include <boost/gil/gil_config.hpp> +#include <boost/gil/channel.hpp> + +namespace boost { namespace gil { + +/// \ingroup ChannelNumericOperations +/// structure for adding one channel to another +/// this is a generic implementation; user should specialize it for better performance +template <typename Channel1,typename Channel2,typename ChannelR> +struct channel_plus_t : public std::binary_function<Channel1,Channel2,ChannelR> { + ChannelR operator()(typename channel_traits<Channel1>::const_reference ch1, + typename channel_traits<Channel2>::const_reference ch2) const { + return ChannelR(ch1)+ChannelR(ch2); + } +}; + +/// \ingroup ChannelNumericOperations +/// structure for subtracting one channel from another +/// this is a generic implementation; user should specialize it for better performance +template <typename Channel1,typename Channel2,typename ChannelR> +struct channel_minus_t : public std::binary_function<Channel1,Channel2,ChannelR> { + ChannelR operator()(typename channel_traits<Channel1>::const_reference ch1, + typename channel_traits<Channel2>::const_reference ch2) const { + return ChannelR(ch1)-ChannelR(ch2); + } +}; + +/// \ingroup ChannelNumericOperations +/// structure for multiplying one channel to another +/// this is a generic implementation; user should specialize it for better performance +template <typename Channel1,typename Channel2,typename ChannelR> +struct channel_multiplies_t : public std::binary_function<Channel1,Channel2,ChannelR> { + ChannelR operator()(typename channel_traits<Channel1>::const_reference ch1, + typename channel_traits<Channel2>::const_reference ch2) const { + return ChannelR(ch1)*ChannelR(ch2); + } +}; + +/// \ingroup ChannelNumericOperations +/// structure for dividing channels +/// this is a generic implementation; user should specialize it for better performance +template <typename Channel1,typename Channel2,typename ChannelR> +struct channel_divides_t : public std::binary_function<Channel1,Channel2,ChannelR> { + ChannelR operator()(typename channel_traits<Channel1>::const_reference ch1, + typename channel_traits<Channel2>::const_reference ch2) const { + return ChannelR(ch1)/ChannelR(ch2); + } +}; + +/// \ingroup ChannelNumericOperations +/// structure for adding a scalar to a channel +/// this is a generic implementation; user should specialize it for better performance +template <typename Channel,typename Scalar,typename ChannelR> +struct channel_plus_scalar_t : public std::binary_function<Channel,Scalar,ChannelR> { + ChannelR operator()(typename channel_traits<Channel>::const_reference ch, + const Scalar& s) const { + return ChannelR(ch)+ChannelR(s); + } +}; + +/// \ingroup ChannelNumericOperations +/// structure for subtracting a scalar from a channel +/// this is a generic implementation; user should specialize it for better performance +template <typename Channel,typename Scalar,typename ChannelR> +struct channel_minus_scalar_t : public std::binary_function<Channel,Scalar,ChannelR> { + ChannelR operator()(typename channel_traits<Channel>::const_reference ch, + const Scalar& s) const { + return ChannelR(ch-s); + } +}; + +/// \ingroup ChannelNumericOperations +/// structure for multiplying a scalar to one channel +/// this is a generic implementation; user should specialize it for better performance +template <typename Channel,typename Scalar,typename ChannelR> +struct channel_multiplies_scalar_t : public std::binary_function<Channel,Scalar,ChannelR> { + ChannelR operator()(typename channel_traits<Channel>::const_reference ch, + const Scalar& s) const { + return ChannelR(ch)*ChannelR(s); + } +}; + +/// \ingroup ChannelNumericOperations +/// structure for dividing a channel by a scalar +/// this is a generic implementation; user should specialize it for better performance +template <typename Channel,typename Scalar,typename ChannelR> +struct channel_divides_scalar_t : public std::binary_function<Channel,Scalar,ChannelR> { + ChannelR operator()(typename channel_traits<Channel>::const_reference ch, + const Scalar& s) const { + return ChannelR(ch)/ChannelR(s); + } +}; + +/// \ingroup ChannelNumericOperations +/// structure for halving a channel +/// this is a generic implementation; user should specialize it for better performance +template <typename Channel> +struct channel_halves_t : public std::unary_function<Channel,Channel> { + typename channel_traits<Channel>::reference + operator()(typename channel_traits<Channel>::reference ch) const { + return ch/=2.0; + } +}; + +/// \ingroup ChannelNumericOperations +/// structure for setting a channel to zero +/// this is a generic implementation; user should specialize it for better performance +template <typename Channel> +struct channel_zeros_t : public std::unary_function<Channel,Channel> { + typename channel_traits<Channel>::reference + operator()(typename channel_traits<Channel>::reference ch) const { + return ch=Channel(0); + } +}; + +/// \ingroup ChannelNumericOperations +/// structure for assigning one channel to another +/// this is a generic implementation; user should specialize it for better performance +template <typename Channel1,typename Channel2> +struct channel_assigns_t : public std::binary_function<Channel1,Channel2,Channel2> { + typename channel_traits<Channel2>::reference + operator()(typename channel_traits<Channel1>::const_reference ch1, + typename channel_traits<Channel2>::reference ch2) const { + return ch2=Channel2(ch1); + } +}; + +} } // namespace boost::gil + +#endif // BOOST_GIL_EXTENSION_NUMERIC_CHANNEL_NUMERIC_OPERATIONS_HPP diff --git a/boost/gil/extension/numeric/convolve.hpp b/boost/gil/extension/numeric/convolve.hpp new file mode 100644 index 0000000000..ba840aec71 --- /dev/null +++ b/boost/gil/extension/numeric/convolve.hpp @@ -0,0 +1,219 @@ +/* + Copyright 2005-2007 Adobe Systems Incorporated + + 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_NUMERIC_CONVOLVE_HPP +#define BOOST_GIL_EXTENSION_NUMERIC_CONVOLVE_HPP + +/*! +/// \file +/// \brief 2D seperable convolutions and correlations +/// +/// \author Hailin Jin and Lubomir Bourdev \n +/// Adobe Systems Incorporated +/// \date 2005-2007 \n +*/ + + +#include <cstddef> +#include <cassert> +#include <algorithm> +#include <vector> +#include <functional> + +#include <boost/gil/gil_config.hpp> +#include <boost/gil/image_view_factory.hpp> +#include <boost/gil/algorithm.hpp> +#include <boost/gil/metafunctions.hpp> +#include <boost/gil/extension/numeric/pixel_numeric_operations.hpp> +#include <boost/gil/extension/numeric/algorithm.hpp> + +namespace boost { namespace gil { + +/// \ingroup ImageAlgorithms +/// Boundary options for 1D correlations/convolutions +enum convolve_boundary_option { + convolve_option_output_ignore, /// do nothing to the output + convolve_option_output_zero, /// set the output to zero + convolve_option_extend_padded, /// assume the source boundaries to be padded already + convolve_option_extend_zero, /// assume the source boundaries to be zero + convolve_option_extend_constant /// assume the source boundaries to be the boundary value +}; + +namespace detail { +/// compute the correlation of 1D kernel with the rows of an image +template <typename PixelAccum,typename SrcView,typename Kernel,typename DstView,typename Correlator> +void correlate_rows_imp(const SrcView& src, const Kernel& ker, const DstView& dst, + convolve_boundary_option option, + Correlator correlator) { + assert(src.dimensions()==dst.dimensions()); + assert(ker.size()!=0); + + typedef typename pixel_proxy<typename SrcView::value_type>::type PIXEL_SRC_REF; + typedef typename pixel_proxy<typename DstView::value_type>::type PIXEL_DST_REF; + typedef typename Kernel::value_type kernel_type; + + if(ker.size()==1) {//reduces to a multiplication + view_multiplies_scalar<PixelAccum>(src,*ker.begin(),dst); + return; + } + + int width=src.width(),height=src.height(); + PixelAccum acc_zero; pixel_zeros_t<PixelAccum>()(acc_zero); + if (width==0) return; + if (option==convolve_option_output_ignore || option==convolve_option_output_zero) { + typename DstView::value_type dst_zero; pixel_assigns_t<PixelAccum,PIXEL_DST_REF>()(acc_zero,dst_zero); + if (width<(int)ker.size()) { + if (option==convolve_option_output_zero) + fill_pixels(dst,dst_zero); + } else { + std::vector<PixelAccum> buffer(width); + for(int rr=0;rr<height;++rr) { + assign_pixels(src.row_begin(rr),src.row_end(rr),&buffer.front()); + typename DstView::x_iterator it_dst=dst.row_begin(rr); + if (option==convolve_option_output_zero) + std::fill_n(it_dst,ker.left_size(),dst_zero); + it_dst+=ker.left_size(); + correlator(&buffer.front(),&buffer.front()+width+1-ker.size(), + ker.begin(),it_dst); + it_dst+=width+1-ker.size(); + if (option==convolve_option_output_zero) + std::fill_n(it_dst,ker.right_size(),dst_zero); + } + } + } else { + std::vector<PixelAccum> buffer(width+ker.size()-1); + for(int rr=0;rr<height;++rr) { + PixelAccum* it_buffer=&buffer.front(); + if (option==convolve_option_extend_padded) { + assign_pixels(src.row_begin(rr)-ker.left_size(), + src.row_end(rr)+ker.right_size(), + it_buffer); + } else if (option==convolve_option_extend_zero) { + std::fill_n(it_buffer,ker.left_size(),acc_zero); + it_buffer+=ker.left_size(); + assign_pixels(src.row_begin(rr),src.row_end(rr),it_buffer); + it_buffer+=width; + std::fill_n(it_buffer,ker.right_size(),acc_zero); + } else if (option==convolve_option_extend_constant) { + PixelAccum filler; + pixel_assigns_t<PIXEL_SRC_REF,PixelAccum>()(*src.row_begin(rr),filler); + std::fill_n(it_buffer,ker.left_size(),filler); + it_buffer+=ker.left_size(); + assign_pixels(src.row_begin(rr),src.row_end(rr),it_buffer); + it_buffer+=width; + pixel_assigns_t<PIXEL_SRC_REF,PixelAccum>()(src.row_end(rr)[-1],filler); + std::fill_n(it_buffer,ker.right_size(),filler); + } + correlator(&buffer.front(),&buffer.front()+width, + ker.begin(), + dst.row_begin(rr)); + } + } +} +template <typename PixelAccum> +class correlator_n { +private: + std::size_t _size; +public: + correlator_n(std::size_t size_in) : _size(size_in) {} + template <typename SrcIterator,typename KernelIterator,typename DstIterator> + void operator()(SrcIterator src_begin,SrcIterator src_end, + KernelIterator ker_begin, + DstIterator dst_begin) { + correlate_pixels_n<PixelAccum>(src_begin,src_end,ker_begin,_size,dst_begin); + } +}; +template <std::size_t Size,typename PixelAccum> +struct correlator_k { +public: + template <typename SrcIterator,typename KernelIterator,typename DstIterator> + void operator()(SrcIterator src_begin,SrcIterator src_end, + KernelIterator ker_begin, + DstIterator dst_begin){ + correlate_pixels_k<Size,PixelAccum>(src_begin,src_end,ker_begin,dst_begin); + } +}; +} // namespace detail + +/// \ingroup ImageAlgorithms +///correlate a 1D variable-size kernel along the rows of an image +template <typename PixelAccum,typename SrcView,typename Kernel,typename DstView> +BOOST_FORCEINLINE +void correlate_rows(const SrcView& src, const Kernel& ker, const DstView& dst, + convolve_boundary_option option=convolve_option_extend_zero) { + detail::correlate_rows_imp<PixelAccum>(src,ker,dst,option,detail::correlator_n<PixelAccum>(ker.size())); +} + +/// \ingroup ImageAlgorithms +///correlate a 1D variable-size kernel along the columns of an image +template <typename PixelAccum,typename SrcView,typename Kernel,typename DstView> +BOOST_FORCEINLINE +void correlate_cols(const SrcView& src, const Kernel& ker, const DstView& dst, + convolve_boundary_option option=convolve_option_extend_zero) { + correlate_rows<PixelAccum>(transposed_view(src),ker,transposed_view(dst),option); +} + +/// \ingroup ImageAlgorithms +///convolve a 1D variable-size kernel along the rows of an image +template <typename PixelAccum,typename SrcView,typename Kernel,typename DstView> +BOOST_FORCEINLINE +void convolve_rows(const SrcView& src, const Kernel& ker, const DstView& dst, + convolve_boundary_option option=convolve_option_extend_zero) { + correlate_rows<PixelAccum>(src,reverse_kernel(ker),dst,option); +} + +/// \ingroup ImageAlgorithms +///convolve a 1D variable-size kernel along the columns of an image +template <typename PixelAccum,typename SrcView,typename Kernel,typename DstView> +BOOST_FORCEINLINE +void convolve_cols(const SrcView& src, const Kernel& ker, const DstView& dst, + convolve_boundary_option option=convolve_option_extend_zero) { + convolve_rows<PixelAccum>(transposed_view(src),ker,transposed_view(dst),option); +} + +/// \ingroup ImageAlgorithms +///correlate a 1D fixed-size kernel along the rows of an image +template <typename PixelAccum,typename SrcView,typename Kernel,typename DstView> +BOOST_FORCEINLINE +void correlate_rows_fixed(const SrcView& src, const Kernel& ker, const DstView& dst, + convolve_boundary_option option=convolve_option_extend_zero) { + detail::correlate_rows_imp<PixelAccum>(src,ker,dst,option,detail::correlator_k<Kernel::static_size,PixelAccum>()); +} + +/// \ingroup ImageAlgorithms +///correlate a 1D fixed-size kernel along the columns of an image +template <typename PixelAccum,typename SrcView,typename Kernel,typename DstView> +BOOST_FORCEINLINE +void correlate_cols_fixed(const SrcView& src, const Kernel& ker, const DstView& dst, + convolve_boundary_option option=convolve_option_extend_zero) { + correlate_rows_fixed<PixelAccum>(transposed_view(src),ker,transposed_view(dst),option); +} + +/// \ingroup ImageAlgorithms +///convolve a 1D fixed-size kernel along the rows of an image +template <typename PixelAccum,typename SrcView,typename Kernel,typename DstView> +BOOST_FORCEINLINE +void convolve_rows_fixed(const SrcView& src, const Kernel& ker, const DstView& dst, + convolve_boundary_option option=convolve_option_extend_zero) { + correlate_rows_fixed<PixelAccum>(src,reverse_kernel(ker),dst,option); +} + +/// \ingroup ImageAlgorithms +///convolve a 1D fixed-size kernel along the columns of an image +template <typename PixelAccum,typename SrcView,typename Kernel,typename DstView> +BOOST_FORCEINLINE +void convolve_cols_fixed(const SrcView& src, const Kernel& ker, const DstView& dst, + convolve_boundary_option option=convolve_option_extend_zero) { + convolve_rows_fixed<PixelAccum>(transposed_view(src),ker,transposed_view(dst),option); +} + +} } // namespace boost::gil + +#endif // BOOST_GIL_EXTENSION_NUMERIC_CONVOLVE_HPP diff --git a/boost/gil/extension/numeric/kernel.hpp b/boost/gil/extension/numeric/kernel.hpp new file mode 100644 index 0000000000..012874d72a --- /dev/null +++ b/boost/gil/extension/numeric/kernel.hpp @@ -0,0 +1,104 @@ +/* + Copyright 2005-2007 Adobe Systems Incorporated + + 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_NUMERIC_KERNEL_HPP +#define BOOST_GIL_EXTENSION_NUMERIC_KERNEL_HPP + +/*! +/// \file +/// \brief Definitions of 1D fixed-size and variable-size kernels and related operations +/// \author Hailin Jin and Lubomir Bourdev \n +/// Adobe Systems Incorporated +/// \date 2005-2007 \n +*/ + +#include <cstddef> +#include <cassert> +#include <array> +#include <algorithm> +#include <vector> +#include <memory> + +#include <boost/gil/gil_config.hpp> +#include <boost/gil/utilities.hpp> + +namespace boost { namespace gil { + +namespace detail { + +/// \brief kernel adaptor for one-dimensional cores +/// Core needs to provide size(),begin(),end(),operator[], +/// value_type,iterator,const_iterator,reference,const_reference +template <typename Core> +class kernel_1d_adaptor : public Core { +private: + std::size_t _center; +public: + kernel_1d_adaptor() : _center(0) {} + explicit kernel_1d_adaptor(std::size_t center_in) : _center(center_in) {assert(_center<this->size());} + kernel_1d_adaptor(std::size_t size_in,std::size_t center_in) : + Core(size_in), _center(center_in) {assert(_center<this->size());} + kernel_1d_adaptor(const kernel_1d_adaptor& k_in) : Core(k_in), _center(k_in._center) {} + + kernel_1d_adaptor& operator=(const kernel_1d_adaptor& k_in) { + Core::operator=(k_in); + _center=k_in._center; + return *this; + } + std::size_t left_size() const {assert(_center<this->size());return _center;} + std::size_t right_size() const {assert(_center<this->size());return this->size()-_center-1;} + std::size_t& center() {return _center;} + const std::size_t& center() const {return _center;} +}; + +} // namespace detail + +/// \brief variable-size kernel +template <typename T, typename Alloc = std::allocator<T> > +class kernel_1d : public detail::kernel_1d_adaptor<std::vector<T,Alloc> > { + typedef detail::kernel_1d_adaptor<std::vector<T,Alloc> > parent_t; +public: + kernel_1d() {} + kernel_1d(std::size_t size_in,std::size_t center_in) : parent_t(size_in,center_in) {} + template <typename FwdIterator> + kernel_1d(FwdIterator elements, std::size_t size_in, std::size_t center_in) : parent_t(size_in,center_in) { + detail::copy_n(elements,size_in,this->begin()); + } + kernel_1d(const kernel_1d& k_in) : parent_t(k_in) {} +}; + +/// \brief static-size kernel +template <typename T,std::size_t Size> +class kernel_1d_fixed : public detail::kernel_1d_adaptor<std::array<T,Size> > { + typedef detail::kernel_1d_adaptor<std::array<T,Size> > parent_t; +public: + kernel_1d_fixed() {} + explicit kernel_1d_fixed(std::size_t center_in) : parent_t(center_in) {} + + template <typename FwdIterator> + explicit kernel_1d_fixed(FwdIterator elements, std::size_t center_in) : parent_t(center_in) { + detail::copy_n(elements,Size,this->begin()); + } + kernel_1d_fixed(const kernel_1d_fixed& k_in) : parent_t(k_in) {} +}; + +/// \brief reverse a kernel +template <typename Kernel> +inline Kernel reverse_kernel(const Kernel& kernel) { + Kernel result(kernel); + result.center()=kernel.right_size(); + std::reverse(result.begin(), result.end()); + return result; +} + + +} } // namespace boost::gil + +#endif // BOOST_GIL_EXTENSION_NUMERIC_KERNEL_HPP diff --git a/boost/gil/extension/numeric/pixel_numeric_operations.hpp b/boost/gil/extension/numeric/pixel_numeric_operations.hpp new file mode 100644 index 0000000000..f5fc7c3e5a --- /dev/null +++ b/boost/gil/extension/numeric/pixel_numeric_operations.hpp @@ -0,0 +1,182 @@ +/* + Copyright 2005-2007 Adobe Systems Incorporated + + 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_NUMERIC_PIXEL_NUMERIC_OPERATIONS_HPP +#define BOOST_GIL_EXTENSION_NUMERIC_PIXEL_NUMERIC_OPERATIONS_HPP + +/*! +/// \file +/// \brief Structures for pixel-wise numeric operations +/// \author Lubomir Bourdev and Hailin Jin \n +/// Adobe Systems Incorporated +/// \date 2005-2007 \n +/// Currently defined structures: +/// pixel_plus_t (+), pixel_minus_t (-) +/// pixel_multiplies_scalar_t (*), pixel_divides_scalar_t (/) +/// pixel_halves_t (/=2), pixel_zeros_t (=0) +/// pixel_assigns_t (=) +*/ + +#include <functional> + +#include <boost/gil/gil_config.hpp> +#include <boost/gil/pixel.hpp> +#include <boost/gil/color_base_algorithm.hpp> + +#include <boost/gil/extension/numeric/channel_numeric_operations.hpp> + +namespace boost { namespace gil { + +/// \ingroup PixelNumericOperations +/// \brief construct for adding two pixels +template <typename PixelRef1, // models pixel concept + typename PixelRef2, // models pixel concept + typename PixelR> // models pixel value concept +struct pixel_plus_t { + PixelR operator() (const PixelRef1& p1, + const PixelRef2& p2) const { + PixelR result; + static_transform(p1,p2,result, + channel_plus_t<typename channel_type<PixelRef1>::type, + typename channel_type<PixelRef2>::type, + typename channel_type<PixelR>::type>()); + return result; + } +}; + +/// \ingroup PixelNumericOperations +/// \brief construct for subtracting two pixels +template <typename PixelRef1, // models pixel concept + typename PixelRef2, // models pixel concept + typename PixelR> // models pixel value concept +struct pixel_minus_t { + PixelR operator() (const PixelRef1& p1, + const PixelRef2& p2) const { + PixelR result; + static_transform(p1,p2,result, + channel_minus_t<typename channel_type<PixelRef1>::type, + typename channel_type<PixelRef2>::type, + typename channel_type<PixelR>::type>()); + return result; + } +}; + +/// \ingroup PixelNumericOperations +/// \brief construct for multiplying scalar to a pixel +template <typename PixelRef, // models pixel concept + typename Scalar, // models a scalar type + typename PixelR> // models pixel value concept +struct pixel_multiplies_scalar_t { + PixelR operator () (const PixelRef& p, + const Scalar& s) const { + PixelR result; + static_transform(p,result, + std::bind2nd(channel_multiplies_scalar_t<typename channel_type<PixelRef>::type, + Scalar, + typename channel_type<PixelR>::type>(),s)); + return result; + } +}; + +/// \ingroup PixelNumericOperations +/// \brief construct for dividing two pixels +template <typename PixelRef1, // models pixel concept + typename PixelRef2, // models pixel concept + typename PixelR> // models pixel value concept +struct pixel_multiply_t { + PixelR operator() (const PixelRef1& p1, + const PixelRef2& p2) const { + PixelR result; + static_transform(p1,p2,result, + channel_multiplies_t<typename channel_type<PixelRef1>::type, + typename channel_type<PixelRef2>::type, + typename channel_type<PixelR>::type>()); + return result; + } +}; + +/// \ingroup PixelNumericOperations +/// \brief construct for dividing a pixel by a scalar +template <typename PixelRef, // models pixel concept + typename Scalar, // models a scalar type + typename PixelR> // models pixel value concept +struct pixel_divides_scalar_t { + PixelR operator () (const PixelRef& p, + const Scalar& s) const { + PixelR result; + static_transform(p,result, + std::bind2nd(channel_divides_scalar_t<typename channel_type<PixelRef>::type, + Scalar, + typename channel_type<PixelR>::type>(),s)); + return result; + } +}; + +/// \ingroup PixelNumericOperations +/// \brief construct for dividing two pixels +template <typename PixelRef1, // models pixel concept + typename PixelRef2, // models pixel concept + typename PixelR> // models pixel value concept +struct pixel_divide_t { + PixelR operator() (const PixelRef1& p1, + const PixelRef2& p2) const { + PixelR result; + static_transform(p1,p2,result, + channel_divides_t<typename channel_type<PixelRef1>::type, + typename channel_type<PixelRef2>::type, + typename channel_type<PixelR>::type>()); + return result; + } +}; + +/// \ingroup PixelNumericOperations +/// \brief construct for dividing a pixel by 2 +template <typename PixelRef> // models pixel concept +struct pixel_halves_t { + PixelRef& operator () (PixelRef& p) const { + static_for_each(p,channel_halves_t<typename channel_type<PixelRef>::type>()); + return p; + } +}; + +/// \ingroup PixelNumericOperations +/// \brief construct for setting a pixel to zero (for whatever zero means) +template <typename PixelRef> // models pixel concept +struct pixel_zeros_t { + PixelRef& operator () (PixelRef& p) const { + static_for_each(p,channel_zeros_t<typename channel_type<PixelRef>::type>()); + return p; + } +}; + +// Hailin: This is how you can do it: +template <typename Pixel> +void zero_channels(Pixel& p) { + static_for_each(p,channel_zeros_t<typename channel_type<Pixel>::type>()); +} + + +/// \ingroup PixelNumericOperations +///definition and a generic implementation for casting and assigning a pixel to another +///user should specialize it for better performance +template <typename PixelRef, // models pixel concept + typename PixelRefR> // models pixel concept +struct pixel_assigns_t { + PixelRefR operator () (const PixelRef& src, + PixelRefR& dst) const { + static_for_each(src,dst,channel_assigns_t<typename channel_type<PixelRef>::type, + typename channel_type<PixelRefR>::type>()); + return dst; + } +}; + +} } // namespace boost::gil + +#endif // BOOST_GIL_EXTENSION_NUMERIC_PIXEL_NUMERIC_OPERATIONS_HPP diff --git a/boost/gil/extension/numeric/resample.hpp b/boost/gil/extension/numeric/resample.hpp new file mode 100644 index 0000000000..ec619d57a1 --- /dev/null +++ b/boost/gil/extension/numeric/resample.hpp @@ -0,0 +1,145 @@ +/* + Copyright 2005-2007 Adobe Systems Incorporated + + 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_NUMERIC_RESAMPLE_HPP +#define BOOST_GIL_EXTENSION_NUMERIC_RESAMPLE_HPP + +#include <boost/lambda/lambda.hpp> +#include <boost/lambda/bind.hpp> + +#include <boost/gil/extension/dynamic_image/dynamic_image_all.hpp> + +#include <boost/gil/extension/numeric/affine.hpp> + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file +/// \brief support for generic image resampling +/// NOTE: The code is for example use only. It is not optimized for performance +/// \author Lubomir Bourdev and Hailin Jin \n +/// Adobe Systems Incorporated +/// \date 2005-2007 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +namespace boost { namespace gil { + +/////////////////////////////////////////////////////////////////////////// +//// +//// resample_pixels: set each pixel in the destination view as the result of a sampling function over the transformed coordinates of the source view +//// +/////////////////////////////////////////////////////////////////////////// + +template <typename MapFn> struct mapping_traits {}; + +/// \brief Set each pixel in the destination view as the result of a sampling function over the transformed coordinates of the source view +/// \ingroup ImageAlgorithms +/// +/// The provided implementation works for 2D image views only +template <typename Sampler, // Models SamplerConcept + typename SrcView, // Models RandomAccess2DImageViewConcept + typename DstView, // Models MutableRandomAccess2DImageViewConcept + typename MapFn> // Models MappingFunctionConcept +void resample_pixels(const SrcView& src_view, const DstView& dst_view, const MapFn& dst_to_src, Sampler sampler=Sampler()) { + typename DstView::point_t dst_dims=dst_view.dimensions(); + typename DstView::point_t dst_p; + typename mapping_traits<MapFn>::result_type src_p; + + for (dst_p.y=0; dst_p.y<dst_dims.y; ++dst_p.y) { + typename DstView::x_iterator xit = dst_view.row_begin(dst_p.y); + for (dst_p.x=0; dst_p.x<dst_dims.x; ++dst_p.x) { + sample(sampler, src_view, transform(dst_to_src, dst_p), xit[dst_p.x]); + } + } +} + +/////////////////////////////////////////////////////////////////////////// +//// +//// resample_pixels when one or both image views are run-time instantiated. +//// +/////////////////////////////////////////////////////////////////////////// + +namespace detail { + template <typename Sampler, typename MapFn> + struct resample_pixels_fn : public binary_operation_obj<resample_pixels_fn<Sampler,MapFn> > { + MapFn _dst_to_src; + Sampler _sampler; + resample_pixels_fn(const MapFn& dst_to_src, const Sampler& sampler) : _dst_to_src(dst_to_src), _sampler(sampler) {} + + template <typename SrcView, typename DstView> BOOST_FORCEINLINE void apply_compatible(const SrcView& src, const DstView& dst) const { + resample_pixels(src, dst, _dst_to_src, _sampler); + } + }; +} + +/// \brief resample_pixels when the source is run-time specified +/// If invoked on incompatible views, throws std::bad_cast() +/// \ingroup ImageAlgorithms +template <typename Sampler, typename Types1, typename V2, typename MapFn> +void resample_pixels(const any_image_view<Types1>& src, const V2& dst, const MapFn& dst_to_src, Sampler sampler=Sampler()) { + apply_operation(src,bind(detail::resample_pixels_fn<Sampler,MapFn>(dst_to_src,sampler), _1, dst)); +} + +/// \brief resample_pixels when the destination is run-time specified +/// If invoked on incompatible views, throws std::bad_cast() +/// \ingroup ImageAlgorithms +template <typename Sampler, typename V1, typename Types2, typename MapFn> +void resample_pixels(const V1& src, const any_image_view<Types2>& dst, const MapFn& dst_to_src, Sampler sampler=Sampler()) { + apply_operation(dst,bind(detail::resample_pixels_fn<Sampler,MapFn>(dst_to_src,sampler), src, _1)); +} + +/// \brief resample_pixels when both the source and the destination are run-time specified +/// If invoked on incompatible views, throws std::bad_cast() +/// \ingroup ImageAlgorithms +template <typename Sampler, typename SrcTypes, typename DstTypes, typename MapFn> +void resample_pixels(const any_image_view<SrcTypes>& src, const any_image_view<DstTypes>& dst, const MapFn& dst_to_src, Sampler sampler=Sampler()) { + apply_operation(src,dst,detail::resample_pixels_fn<Sampler,MapFn>(dst_to_src,sampler)); +} + +/////////////////////////////////////////////////////////////////////////// +//// +//// resample_subimage: copy into the destination a rotated rectangular region from the source, rescaling it to fit into the destination +//// +/////////////////////////////////////////////////////////////////////////// + +// Extract into dst the rotated bounds [src_min..src_max] rotated at 'angle' from the source view 'src' +// The source coordinates are in the coordinate space of the source image +// Note that the views could also be variants (i.e. any_image_view) +template <typename Sampler, typename SrcMetaView, typename DstMetaView> +void resample_subimage(const SrcMetaView& src, const DstMetaView& dst, + double src_min_x, double src_min_y, + double src_max_x, double src_max_y, + double angle, const Sampler& sampler=Sampler()) { + double src_width = std::max<double>(src_max_x - src_min_x - 1,1); + double src_height = std::max<double>(src_max_y - src_min_y - 1,1); + double dst_width = std::max<double>((double)(dst.width()-1),1); + double dst_height = std::max<double>((double)(dst.height()-1),1); + + matrix3x2<double> mat = + matrix3x2<double>::get_translate(-dst_width/2.0, -dst_height/2.0) * + matrix3x2<double>::get_scale(src_width / dst_width, src_height / dst_height)* + matrix3x2<double>::get_rotate(-angle)* + matrix3x2<double>::get_translate(src_min_x + src_width/2.0, src_min_y + src_height/2.0); + resample_pixels(src,dst,mat,sampler); +} + +/////////////////////////////////////////////////////////////////////////// +//// +//// resize_view: Copy the source view into the destination, scaling to fit +//// +/////////////////////////////////////////////////////////////////////////// + +template <typename Sampler, typename SrcMetaView, typename DstMetaView> +void resize_view(const SrcMetaView& src, const DstMetaView& dst, const Sampler& sampler=Sampler()) { + resample_subimage(src,dst,0.0,0.0,(double)src.width(),(double)src.height(),0.0,sampler); +} + +} } // namespace boost::gil + +#endif // BOOST_GIL_EXTENSION_NUMERIC_RESAMPLE_HPP diff --git a/boost/gil/extension/numeric/sampler.hpp b/boost/gil/extension/numeric/sampler.hpp new file mode 100644 index 0000000000..494611a314 --- /dev/null +++ b/boost/gil/extension/numeric/sampler.hpp @@ -0,0 +1,200 @@ +/* + Copyright 2005-2007 Adobe Systems Incorporated + + 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_NUMERIC_SAMPLER_HPP +#define BOOST_GIL_EXTENSION_NUMERIC_SAMPLER_HPP + +#include <boost/gil/extension/dynamic_image/dynamic_image_all.hpp> + +#include <boost/gil/extension/numeric/pixel_numeric_operations.hpp> + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file +/// \brief Nearest-neighbor and bilinear image samplers. +/// NOTE: The code is for example use only. It is not optimized for performance +/// \author Lubomir Bourdev and Hailin Jin \n +/// Adobe Systems Incorporated +/// \date 2005-2007 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +namespace boost { namespace gil { + +/////////////////////////////////////////////////////////////////////////// +//// +//// resample_pixels: set each pixel in the destination view as the result of a sampling function over the transformed coordinates of the source view +//// +/////////////////////////////////////////////////////////////////////////// +/* +template <typename Sampler> +concept SamplerConcept { + template <typename DstP, // Models PixelConcept + typename SrcView, // Models RandomAccessNDImageViewConcept + typename S_COORDS> // Models PointNDConcept, where S_COORDS::num_dimensions == SrcView::num_dimensions + bool sample(const Sampler& s, const SrcView& src, const S_COORDS& p, DstP result); +}; +*/ + +/// \brief A sampler that sets the destination pixel to the closest one in the source. If outside the bounds, it doesn't change the destination +/// \ingroup ImageAlgorithms +struct nearest_neighbor_sampler {}; + +template <typename DstP, typename SrcView, typename F> +bool sample(nearest_neighbor_sampler, const SrcView& src, const point2<F>& p, DstP& result) { + typename SrcView::point_t center(iround(p)); + if (center.x>=0 && center.y>=0 && center.x<src.width() && center.y<src.height()) { + result=src(center.x,center.y); + return true; + } + return false; +} + +struct cast_channel_fn { + template <typename SrcChannel, typename DstChannel> + void operator()(const SrcChannel& src, DstChannel& dst) { + typedef typename channel_traits<DstChannel>::value_type dst_value_t; + dst = dst_value_t(src); + } +}; + +template <typename SrcPixel, typename DstPixel> +void cast_pixel(const SrcPixel& src, DstPixel& dst) { + static_for_each(src,dst,cast_channel_fn()); +} + +namespace detail { + +template <typename Weight> +struct add_dst_mul_src_channel { + Weight _w; + add_dst_mul_src_channel(Weight w) : _w(w) {} + + template <typename SrcChannel, typename DstChannel> + void operator()(const SrcChannel& src, DstChannel& dst) const { + dst += DstChannel(src*_w); + } +}; + +// dst += DST_TYPE(src * w) +template <typename SrcP,typename Weight,typename DstP> +struct add_dst_mul_src { + void operator()(const SrcP& src, Weight weight, DstP& dst) const { + static_for_each(src,dst, add_dst_mul_src_channel<Weight>(weight)); +// pixel_assigns_t<DstP,DstP&>()( +// pixel_plus_t<DstP,DstP,DstP>()( +// pixel_multiplies_scalar_t<SrcP,Weight,DstP>()(src,weight), +// dst), +// dst); + } +}; +} // namespace detail + +/// \brief A sampler that sets the destination pixel as the bilinear interpolation of the four closest pixels from the source. +/// If outside the bounds, it doesn't change the destination +/// \ingroup ImageAlgorithms +struct bilinear_sampler {}; + +template <typename DstP, typename SrcView, typename F> +bool sample(bilinear_sampler, const SrcView& src, const point2<F>& p, DstP& result) +{ + typedef typename SrcView::value_type SrcP; + + point2<ptrdiff_t> p0(ifloor(p.x), ifloor(p.y)); // the closest integer coordinate top left from p + point2<F> frac(p.x-p0.x, p.y-p0.y); + + if (p0.x < -1 || p0.y < -1 || p0.x>=src.width() || p0.y>=src.height()) + { + return false; + } + + pixel<F,devicen_layout_t<num_channels<SrcView>::value> > mp(0); // suboptimal + typename SrcView::xy_locator loc=src.xy_at(p0.x,p0.y); + + if (p0.x == -1) + { + if (p0.y == -1) + { + // the top-left corner pixel + ++loc.y(); + detail::add_dst_mul_src<SrcP,F,pixel<F,devicen_layout_t<num_channels<SrcView>::value> > >()(loc.x()[1], 1 ,mp); + } + else if (p0.y+1<src.height()) + { + // on the first column, but not the top-left nor bottom-left corner pixel + detail::add_dst_mul_src<SrcP,F,pixel<F,devicen_layout_t<num_channels<SrcView>::value> > >()(loc.x()[1], (1-frac.y),mp); + ++loc.y(); + detail::add_dst_mul_src<SrcP,F,pixel<F,devicen_layout_t<num_channels<SrcView>::value> > >()(loc.x()[1], frac.y ,mp); + } + else + { + // the bottom-left corner pixel + detail::add_dst_mul_src<SrcP,F,pixel<F,devicen_layout_t<num_channels<SrcView>::value> > >()(loc.x()[1], 1 ,mp); + } + } + else if (p0.x+1<src.width()) + { + if (p0.y == -1) + { + // on the first row, but not the top-left nor top-right corner pixel + ++loc.y(); + detail::add_dst_mul_src<SrcP,F,pixel<F,devicen_layout_t<num_channels<SrcView>::value> > >()(*loc, (1-frac.x) ,mp); + detail::add_dst_mul_src<SrcP,F,pixel<F,devicen_layout_t<num_channels<SrcView>::value> > >()(loc.x()[1], frac.x ,mp); + } + else if (p0.y+1<src.height()) + { + // most common case - inside the image, not on the frist nor last row/column + detail::add_dst_mul_src<SrcP,F,pixel<F,devicen_layout_t<num_channels<SrcView>::value> > >()(*loc, (1-frac.x)*(1-frac.y),mp); + detail::add_dst_mul_src<SrcP,F,pixel<F,devicen_layout_t<num_channels<SrcView>::value> > >()(loc.x()[1], frac.x *(1-frac.y),mp); + ++loc.y(); + detail::add_dst_mul_src<SrcP,F,pixel<F,devicen_layout_t<num_channels<SrcView>::value> > >()(*loc, (1-frac.x)* frac.y ,mp); + detail::add_dst_mul_src<SrcP,F,pixel<F,devicen_layout_t<num_channels<SrcView>::value> > >()(loc.x()[1], frac.x * frac.y ,mp); + } + else + { + // on the last row, but not the bottom-left nor bottom-right corner pixel + detail::add_dst_mul_src<SrcP,F,pixel<F,devicen_layout_t<num_channels<SrcView>::value> > >()(*loc, (1-frac.x) ,mp); + detail::add_dst_mul_src<SrcP,F,pixel<F,devicen_layout_t<num_channels<SrcView>::value> > >()(loc.x()[1], frac.x ,mp); + } + } + else + { + if (p0.y == -1) + { + // the top-right corner pixel + ++loc.y(); + detail::add_dst_mul_src<SrcP,F,pixel<F,devicen_layout_t<num_channels<SrcView>::value> > >()(*loc, 1 ,mp); + } + else if (p0.y+1<src.height()) + { + // on the last column, but not the top-right nor bottom-right corner pixel + detail::add_dst_mul_src<SrcP,F,pixel<F,devicen_layout_t<num_channels<SrcView>::value> > >()(*loc, (1-frac.y),mp); + ++loc.y(); + detail::add_dst_mul_src<SrcP,F,pixel<F,devicen_layout_t<num_channels<SrcView>::value> > >()(*loc, frac.y ,mp); + } + else + { + // the bottom-right corner pixel + detail::add_dst_mul_src<SrcP,F,pixel<F,devicen_layout_t<num_channels<SrcView>::value> > >()(*loc, 1 ,mp); + } + } + + // Convert from floating point average value to the source type + SrcP src_result; + cast_pixel(mp,src_result); + + color_convert(src_result, result); + + return true; +} + +} // namespace gil +} // namespace boost + +#endif // BOOST_GIL_EXTENSION_NUMERIC_SAMPLER_HPP diff --git a/boost/gil/extension/toolbox/color_converters.hpp b/boost/gil/extension/toolbox/color_converters.hpp new file mode 100644 index 0000000000..5286ac14d6 --- /dev/null +++ b/boost/gil/extension/toolbox/color_converters.hpp @@ -0,0 +1,25 @@ +/* + Copyright 2012 Christian Henning + 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_TOOLBOX_COLOR_CONVERTERS_HPP +#define BOOST_GIL_EXTENSION_TOOLBOX_COLOR_CONVERTERS_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file color_converters.hpp +/// \brief Color converters for toolbox extension. +/// \author Christian Henning \n +/// +/// \date 2012 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +#include <boost/gil/extension/toolbox/color_converters/gray_to_rgba.hpp> +#include <boost/gil/extension/toolbox/color_converters/rgb_to_luminance.hpp> + +#endif // BOOST_GIL_EXTENSION_TOOLBOX_COLOR_CONVERTERS_HPP diff --git a/boost/gil/extension/toolbox/color_converters/gray_to_rgba.hpp b/boost/gil/extension/toolbox/color_converters/gray_to_rgba.hpp new file mode 100644 index 0000000000..1cfc873ac6 --- /dev/null +++ b/boost/gil/extension/toolbox/color_converters/gray_to_rgba.hpp @@ -0,0 +1,49 @@ +/* + Copyright 2012 Christian Henning, Andreas Pokorny, 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_TOOLBOX_COLOR_CONVERTERS_GRAY_TO_RGBA_HPP +#define BOOST_GIL_EXTENSION_TOOLBOX_COLOR_CONVERTERS_GRAY_TO_RGBA_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file +/// \brief +/// \author Christian Henning, Andreas Pokorny, Lubomir Bourdev \n +/// +/// \date 2012 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +#include <boost/gil/color_convert.hpp> + +namespace boost{ namespace gil { + +/// This one is missing in gil ( color_convert.hpp ). +template <> +struct default_color_converter_impl<gray_t,rgba_t> +{ + template <typename P1, typename P2> + void operator()(const P1& src, P2& dst) const + { + get_color(dst,red_t()) = + channel_convert<typename color_element_type<P2, red_t >::type>(get_color(src,gray_color_t())); + get_color(dst,green_t())= + channel_convert<typename color_element_type<P2, green_t>::type>(get_color(src,gray_color_t())); + get_color(dst,blue_t()) = + channel_convert<typename color_element_type<P2, blue_t >::type>(get_color(src,gray_color_t())); + + typedef typename channel_type< P2 >::type channel_t; + get_color(dst,alpha_t()) = channel_traits< channel_t >::max_value(); + } +}; + +} // namespace gil +} // namespace boost + +#endif // BOOST_GIL_EXTENSION_TOOLBOX_COLOR_CONVERTERS_GRAY_TO_RGBA_HPP + diff --git a/boost/gil/extension/toolbox/color_converters/rgb_to_luminance.hpp b/boost/gil/extension/toolbox/color_converters/rgb_to_luminance.hpp new file mode 100644 index 0000000000..e4daa6570b --- /dev/null +++ b/boost/gil/extension/toolbox/color_converters/rgb_to_luminance.hpp @@ -0,0 +1,43 @@ +/* + Copyright 2012 Christian Henning, Andreas Pokorny, 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_TOOLBOX_COLOR_CONVERTERS_RGB_TO_LUMINANCE_HPP +#define BOOST_GIL_EXTENSION_TOOLBOX_COLOR_CONVERTERS_RGB_TO_LUMINANCE_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file +/// \brief +/// \author Christian Henning, Andreas Pokorny, Lubomir Bourdev \n +/// +/// \date 2012 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +#include <boost/gil/color_convert.hpp> + +namespace boost{ namespace gil { namespace detail { + +/// - performance specialization double +/// - to eliminate compiler warning 4244 +template <typename GrayChannelValue> +struct rgb_to_luminance_fn< double, double, double, GrayChannelValue > +{ + GrayChannelValue operator()( const double& red + , const double& green + , const double& blue ) const + { + return channel_convert<GrayChannelValue>( red * 0.30 + green * 0.59 + blue * 0.11 ); + } +}; + +} // namespace detail +} // namespace gil +} // namespace boost + +#endif // BOOST_GIL_EXTENSION_TOOLBOX_COLOR_CONVERTERS_RGB_TO_LUMINANCE_HPP diff --git a/boost/gil/extension/toolbox/color_spaces.hpp b/boost/gil/extension/toolbox/color_spaces.hpp new file mode 100644 index 0000000000..acb3a9dea3 --- /dev/null +++ b/boost/gil/extension/toolbox/color_spaces.hpp @@ -0,0 +1,29 @@ +/* + Copyright 2012 Christian Henning + 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_TOOLBOX_COLOR_SPACES_HPP +#define BOOST_GIL_EXTENSION_TOOLBOX_COLOR_SPACES_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file color_spaces.hpp +/// \brief Color spaces for toolbox extension. +/// \author Christian Henning \n +/// +/// \date 2012 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +#include <boost/gil/extension/toolbox/color_spaces/cmyka.hpp> +#include <boost/gil/extension/toolbox/color_spaces/gray_alpha.hpp> +#include <boost/gil/extension/toolbox/color_spaces/hsl.hpp> +#include <boost/gil/extension/toolbox/color_spaces/hsv.hpp> +#include <boost/gil/extension/toolbox/color_spaces/lab.hpp> +#include <boost/gil/extension/toolbox/color_spaces/xyz.hpp> + +#endif // BOOST_GIL_EXTENSION_TOOLBOX_COLOR_SPACES_HPP diff --git a/boost/gil/extension/toolbox/color_spaces/cmyka.hpp b/boost/gil/extension/toolbox/color_spaces/cmyka.hpp new file mode 100644 index 0000000000..e6c3572b92 --- /dev/null +++ b/boost/gil/extension/toolbox/color_spaces/cmyka.hpp @@ -0,0 +1,86 @@ +/* + Copyright 2012 Christian Henning + 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_TOOLBOX_COLOR_SPACES_CMYKA_HPP +#define BOOST_GIL_EXTENSION_TOOLBOX_COLOR_SPACES_CMYKA_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file cmyka.hpp +/// \brief Support for cmyka color space. +/// \author Christian Henning \n +/// +/// \date 2012 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +#include <boost/gil/rgba.hpp> +#include <boost/gil/cmyk.hpp> + +#include <boost/gil/color_convert.hpp> +#include <boost/gil/typedefs.hpp> + +namespace boost{ namespace gil { + +/// \ingroup ColorSpaceModel +using cmyka_t = mpl::vector5<cyan_t, magenta_t, yellow_t, black_t, alpha_t>; + +/// \ingroup LayoutModel +using cmyka_layout_t = layout<cmyka_t>; + +GIL_DEFINE_ALL_TYPEDEFS(8, uint8_t, cmyka) +GIL_DEFINE_ALL_TYPEDEFS(8s, int8_t, cmyka) +GIL_DEFINE_ALL_TYPEDEFS(16, uint16_t, cmyka) +GIL_DEFINE_ALL_TYPEDEFS(16s, int16_t, cmyka) +GIL_DEFINE_ALL_TYPEDEFS(32, uint32_t, cmyka) +GIL_DEFINE_ALL_TYPEDEFS(32s, int32_t, cmyka) +GIL_DEFINE_ALL_TYPEDEFS(32f, float32_t, cmyka) + +///// \ingroup ColorConvert +///// \brief Converting CMYKA to any pixel type. Note: Supports homogeneous pixels only. +//template <typename C2> +//struct default_color_converter_impl<cmyka_t,C2> { +// template <typename P1, typename P2> +// void operator()(const P1& src, P2& dst) const { +// typedef typename channel_type<P1>::type T1; +// default_color_converter_impl<cmyk_t,C2>()( +// pixel<T1,cmyk_layout_t>(channel_multiply(get_color(src,cyan_t()), get_color(src,alpha_t())), +// channel_multiply(get_color(src,magenta_t()),get_color(src,alpha_t())), +// channel_multiply(get_color(src,yellow_t()), get_color(src,alpha_t())), +// channel_multiply(get_color(src,black_t()), get_color(src,alpha_t()))) +// ,dst); +// } +//}; +template <> +struct default_color_converter_impl<cmyka_t,rgba_t> { + template <typename P1, typename P2> + void operator()(const P1& src, P2& dst) const { + typedef typename channel_type<P1>::type T1; + default_color_converter_impl<cmyk_t,rgba_t>()( + pixel<T1,cmyk_layout_t>(get_color(src,cyan_t()), + get_color(src,magenta_t()), + get_color(src,yellow_t()), + get_color(src,black_t())) + ,dst); + } +}; + +/// \ingroup ColorConvert +/// \brief Unfortunately CMYKA to CMYKA must be explicitly provided - otherwise we get ambiguous specialization error. +template <> +struct default_color_converter_impl<cmyka_t,cmyka_t> { + template <typename P1, typename P2> + void operator()(const P1& src, P2& dst) const { + static_for_each(src,dst,default_channel_converter()); + } +}; + +} // namespace gil +} // namespace boost + +#endif // BOOST_GIL_EXTENSION_TOOLBOX_COLOR_SPACES_CMYKA_HPP diff --git a/boost/gil/extension/toolbox/color_spaces/gray_alpha.hpp b/boost/gil/extension/toolbox/color_spaces/gray_alpha.hpp new file mode 100644 index 0000000000..f32a95a541 --- /dev/null +++ b/boost/gil/extension/toolbox/color_spaces/gray_alpha.hpp @@ -0,0 +1,104 @@ +/* + Copyright 2012 Andreas Pokorny + 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_TOOLBOX_COLOR_SPACES_GRAY_ALPHA_HPP +#define BOOST_GIL_EXTENSION_TOOLBOX_COLOR_SPACES_GRAY_ALPHA_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file gray_alpha.hpp +/// \brief Support for gray_alpha color space. +/// \author Andreas Pokorny \n +/// +/// \date 2012 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +#include <boost/mpl/contains.hpp> + +#include <boost/gil/gil_config.hpp> +#include <boost/gil/color_convert.hpp> +#include <boost/gil/gray.hpp> +#include <boost/gil/typedefs.hpp> + +namespace boost{ namespace gil { + +typedef mpl::vector2<gray_color_t,alpha_t> gray_alpha_t; + +typedef layout<gray_alpha_t> gray_alpha_layout_t; +typedef layout<gray_alpha_layout_t, mpl::vector2_c<int,1,0> > alpha_gray_layout_t; + +GIL_DEFINE_BASE_TYPEDEFS(8, uint8_t, alpha_gray) +GIL_DEFINE_BASE_TYPEDEFS(8s, int8_t, alpha_gray) +GIL_DEFINE_BASE_TYPEDEFS(16, uint16_t, alpha_gray) +GIL_DEFINE_BASE_TYPEDEFS(16s, int16_t, alpha_gray) +GIL_DEFINE_BASE_TYPEDEFS(32, uint32_t, alpha_gray) +GIL_DEFINE_BASE_TYPEDEFS(32s, int32_t, alpha_gray) +GIL_DEFINE_BASE_TYPEDEFS(32f, float32_t, alpha_gray) + +GIL_DEFINE_ALL_TYPEDEFS(8, uint8_t, gray_alpha) +GIL_DEFINE_ALL_TYPEDEFS(8s, int8_t, gray_alpha) +GIL_DEFINE_ALL_TYPEDEFS(16, uint16_t, gray_alpha) +GIL_DEFINE_ALL_TYPEDEFS(16s, int16_t, gray_alpha) +GIL_DEFINE_ALL_TYPEDEFS(32, uint32_t, gray_alpha) +GIL_DEFINE_ALL_TYPEDEFS(32s, int32_t, gray_alpha) +GIL_DEFINE_ALL_TYPEDEFS(32f, float32_t, gray_alpha) + +/// \ingroup ColorConvert +/// \brief Gray Alpha to RGBA +template <> +struct default_color_converter_impl<gray_alpha_t,rgba_t> { + template <typename P1, typename P2> + void operator()(const P1& src, P2& dst) const { + get_color(dst,red_t()) = + channel_convert<typename color_element_type<P2, red_t>::type>(get_color(src,gray_color_t())); + get_color(dst,green_t())= + channel_convert<typename color_element_type<P2, green_t>::type>(get_color(src,gray_color_t())); + get_color(dst,blue_t()) = + channel_convert<typename color_element_type<P2, blue_t>::type>(get_color(src,gray_color_t())); + get_color(dst,alpha_t()) = + channel_convert<typename color_element_type<P2, alpha_t>::type>(get_color(src,alpha_t())); + } +}; + +/// \brief Gray Alpha to RGB +template <> +struct default_color_converter_impl<gray_alpha_t,rgb_t> { + template <typename P1, typename P2> + void operator()(const P1& src, P2& dst) const { + get_color(dst,red_t()) = + channel_convert<typename color_element_type<P2, red_t>::type>( + channel_multiply(get_color(src,gray_color_t()),get_color(src,alpha_t()) ) + ); + get_color(dst,green_t()) = + channel_convert<typename color_element_type<P2, green_t>::type>( + channel_multiply(get_color(src,gray_color_t()),get_color(src,alpha_t()) ) + ); + get_color(dst,blue_t()) = + channel_convert<typename color_element_type<P2, blue_t>::type>( + channel_multiply(get_color(src,gray_color_t()),get_color(src,alpha_t()) ) + ); + } +}; + +/// \brief Gray Alpha to Gray +template <> +struct default_color_converter_impl<gray_alpha_t,gray_t> { + template <typename P1, typename P2> + void operator()(const P1& src, P2& dst) const { + get_color(dst,gray_color_t()) = + channel_convert<typename color_element_type<P2, gray_color_t>::type>( + channel_multiply(get_color(src,gray_color_t()),get_color(src,alpha_t()) ) + ); + } +}; + +} // namespace gil +} // namespace boost + +#endif // BOOST_GIL_EXTENSION_TOOLBOX_COLOR_SPACES_GRAY_ALPHA_HPP diff --git a/boost/gil/extension/toolbox/color_spaces/hsl.hpp b/boost/gil/extension/toolbox/color_spaces/hsl.hpp new file mode 100644 index 0000000000..d5fb48e3f4 --- /dev/null +++ b/boost/gil/extension/toolbox/color_spaces/hsl.hpp @@ -0,0 +1,268 @@ +/* + Copyright 2012 Christian Henning + 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_TOOLBOX_COLOR_SPACES_HSL_HPP +#define BOOST_GIL_EXTENSION_TOOLBOX_COLOR_SPACES_HSL_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file hsl.hpp +/// \brief Support for HSL color space +/// \author Christian Henning \n +/// +/// \date 2012 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +#include <boost/gil/typedefs.hpp> + +namespace boost{ namespace gil { + +/// \addtogroup ColorNameModel +/// \{ +namespace hsl_color_space +{ +/// \brief Hue +struct hue_t {}; +/// \brief Saturation +struct saturation_t {}; +/// \brief Lightness +struct lightness_t {}; +} +/// \} + +/// \ingroup ColorSpaceModel +typedef mpl::vector3< hsl_color_space::hue_t + , hsl_color_space::saturation_t + , hsl_color_space::lightness_t + > hsl_t; + +/// \ingroup LayoutModel +typedef layout<hsl_t> hsl_layout_t; + + +GIL_DEFINE_ALL_TYPEDEFS(32f, float32_t, hsl) + +/// \ingroup ColorConvert +/// \brief RGB to HSL +template <> +struct default_color_converter_impl< rgb_t, hsl_t > +{ + template <typename P1, typename P2> + void operator()( const P1& src, P2& dst ) const + { + using namespace hsl_color_space; + + // only float32_t for hsl is supported + float32_t temp_red = channel_convert<float32_t>( get_color( src, red_t() )); + float32_t temp_green = channel_convert<float32_t>( get_color( src, green_t() )); + float32_t temp_blue = channel_convert<float32_t>( get_color( src, blue_t() )); + + float32_t hue, saturation, lightness; + + float32_t min_color = (std::min)( temp_red, (std::min)( temp_green, temp_blue )); + float32_t max_color = (std::max)( temp_red, (std::max)( temp_green, temp_blue )); + + if( std::abs( min_color - max_color ) < 0.001 ) + { + // rgb color is gray + + hue = 0.f; + saturation = 0.f; + + // doesn't matter which rgb channel we use. + lightness = temp_red; + } + else + { + + float32_t diff = max_color - min_color; + + // lightness calculation + + lightness = ( min_color + max_color ) / 2.f; + + // saturation calculation + + if( lightness < 0.5f ) + { + saturation = diff + / ( min_color + max_color ); + } + else + { + saturation = ( max_color - min_color ) + / ( 2.f - diff ); + + } + + // hue calculation + if( std::abs( max_color - temp_red ) < 0.0001f ) + { + // max_color is red + hue = ( temp_green - temp_blue ) + / diff; + + } + else if( std::abs( max_color - temp_green) < 0.0001f ) + { + // max_color is green + // 2.0 + (b - r) / (maxColor - minColor); + hue = 2.f + + ( temp_blue - temp_red ) + / diff; + + } + else + { + // max_color is blue + hue = 4.f + + ( temp_red - temp_blue ) + / diff; + } + + hue /= 6.f; + + if( hue < 0.f ) + { + hue += 1.f; + } + } + + get_color( dst,hue_t() ) = hue; + get_color( dst,saturation_t() ) = saturation; + get_color( dst,lightness_t() ) = lightness; + } +}; + +/// \ingroup ColorConvert +/// \brief HSL to RGB +template <> +struct default_color_converter_impl<hsl_t,rgb_t> +{ + template <typename P1, typename P2> + void operator()( const P1& src, P2& dst) const + { + using namespace hsl_color_space; + + float32_t red, green, blue; + + if( std::abs( get_color( src, saturation_t() )) < 0.0001 ) + { + // If saturation is 0, the color is a shade of gray + red = get_color( src, lightness_t() ); + green = get_color( src, lightness_t() ); + blue = get_color( src, lightness_t() ); + } + else + { + float temp1, temp2; + float tempr, tempg, tempb; + + //Set the temporary values + if( get_color( src, lightness_t() ) < 0.5 ) + { + temp2 = get_color( src, lightness_t() ) + * ( 1.f + get_color( src, saturation_t() ) ); + } + else + { + temp2 = ( get_color( src, lightness_t() ) + get_color( src, saturation_t() )) + - ( get_color( src, lightness_t() ) * get_color( src, saturation_t() )); + } + + temp1 = 2.f + * get_color( src, lightness_t() ) + - temp2; + + tempr = get_color( src, hue_t() ) + 1.f / 3.f; + + if( tempr > 1.f ) + { + tempr--; + } + + tempg = get_color( src, hue_t() ); + tempb = get_color( src, hue_t() ) - 1.f / 3.f; + + if( tempb < 0.f ) + { + tempb++; + } + + //Red + if( tempr < 1.f / 6.f ) + { + red = temp1 + ( temp2 - temp1 ) * 6.f * tempr; + } + else if( tempr < 0.5f ) + { + red = temp2; + } + else if( tempr < 2.f / 3.f ) + { + red = temp1 + (temp2 - temp1) + * (( 2.f / 3.f ) - tempr) * 6.f; + } + else + { + red = temp1; + } + + //Green + if( tempg < 1.f / 6.f ) + { + green = temp1 + ( temp2 - temp1 ) * 6.f * tempg; + } + else if( tempg < 0.5f ) + { + green = temp2; + } + else if( tempg < 2.f / 3.f ) + { + green = temp1 + ( temp2 - temp1 ) + * (( 2.f / 3.f ) - tempg) * 6.f; + } + else + { + green = temp1; + } + + //Blue + if( tempb < 1.f / 6.f ) + { + blue = temp1 + (temp2 - temp1) * 6.f * tempb; + } + else if( tempb < 0.5f ) + { + blue = temp2; + } + else if( tempb < 2.f / 3.f ) + { + blue = temp1 + (temp2 - temp1) + * (( 2.f / 3.f ) - tempb) * 6.f; + } + else + { + blue = temp1; + } + } + + get_color(dst,red_t()) = + channel_convert<typename color_element_type< P2, red_t >::type>( red ); + get_color(dst,green_t())= + channel_convert<typename color_element_type< P2, green_t >::type>( green ); + get_color(dst,blue_t()) = + channel_convert<typename color_element_type< P2, blue_t >::type>( blue ); + } +}; + +} // namespace gil +} // namespace boost + +#endif // BOOST_GIL_EXTENSION_TOOLBOX_COLOR_SPACES_HSL_HPP diff --git a/boost/gil/extension/toolbox/color_spaces/hsv.hpp b/boost/gil/extension/toolbox/color_spaces/hsv.hpp new file mode 100644 index 0000000000..6e0b332c3f --- /dev/null +++ b/boost/gil/extension/toolbox/color_spaces/hsv.hpp @@ -0,0 +1,237 @@ +/* + Copyright 2012 Christian Henning + 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_TOOLBOX_COLOR_SPACES_HSV_HPP +#define BOOST_GIL_EXTENSION_TOOLBOX_COLOR_SPACES_HSV_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file hsv.hpp +/// \brief Support for HSV color space +/// \author Christian Henning \n +/// +/// \date 2012 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +#include <boost/numeric/conversion/cast.hpp> + +#include <boost/gil/typedefs.hpp> + +namespace boost{ namespace gil { + +/// \addtogroup ColorNameModel +/// \{ +namespace hsv_color_space +{ +/// \brief Hue +struct hue_t {}; +/// \brief Saturation +struct saturation_t{}; +/// \brief Value +struct value_t {}; +} +/// \} + +/// \ingroup ColorSpaceModel +typedef mpl::vector3< hsv_color_space::hue_t + , hsv_color_space::saturation_t + , hsv_color_space::value_t + > hsv_t; + +/// \ingroup LayoutModel +typedef layout<hsv_t> hsv_layout_t; + +GIL_DEFINE_ALL_TYPEDEFS(32f, float32_t, hsv) + +/// \ingroup ColorConvert +/// \brief RGB to HSV +template <> +struct default_color_converter_impl< rgb_t, hsv_t > +{ + template <typename P1, typename P2> + void operator()( const P1& src, P2& dst ) const + { + using namespace hsv_color_space; + + // only float32_t for hsv is supported + float32_t temp_red = channel_convert<float32_t>( get_color( src, red_t() )); + float32_t temp_green = channel_convert<float32_t>( get_color( src, green_t() )); + float32_t temp_blue = channel_convert<float32_t>( get_color( src, blue_t() )); + + float32_t hue, saturation, value; + + float32_t min_color = (std::min)( temp_red, (std::min)( temp_green, temp_blue )); + float32_t max_color = (std::max)( temp_red, (std::max)( temp_green, temp_blue )); + + value = max_color; + + float32_t diff = max_color - min_color; + + if( max_color < 0.0001f ) + { + saturation = 0.f; + } + else + { + saturation = diff / max_color; + } + + + if( saturation < 0.0001f ) + { + //it doesn't matter what value it has + hue = 0.f; + } + else + { + if( (std::abs)( boost::numeric_cast<float32_t>(temp_red - max_color) ) < 0.0001f ) + { + hue = ( temp_green - temp_blue ) + / diff; + } + else if( temp_green == max_color ) + { + hue = 2.f + ( temp_blue - temp_red ) + / diff; + } + else + { + hue = 4.f + ( temp_red - temp_green ) + / diff; + } + + //to bring it to a number between 0 and 1 + hue /= 6.f; + + if( hue < 0.f ) + { + hue++; + } + } + + get_color( dst, hue_t() ) = hue; + get_color( dst, saturation_t() ) = saturation; + get_color( dst, value_t() ) = value; + } +}; + +/// \ingroup ColorConvert +/// \brief HSV to RGB +template <> +struct default_color_converter_impl<hsv_t,rgb_t> +{ + template <typename P1, typename P2> + void operator()( const P1& src, P2& dst) const + { + using namespace hsv_color_space; + + float32_t red, green, blue; + + //If saturation is 0, the color is a shade of gray + if( abs( get_color( src, saturation_t() )) < 0.0001f ) + { + // If saturation is 0, the color is a shade of gray + red = get_color( src, value_t() ); + green = get_color( src, value_t() ); + blue = get_color( src, value_t() ); + } + else + { + float32_t frac, p, q, t, h; + uint32_t i; + + //to bring hue to a number between 0 and 6, better for the calculations + h = get_color( src, hue_t() ); + h *= 6.f; + + i = static_cast<uint32_t>(floor(h)); + + frac = h - i; + + p = get_color( src, value_t() ) + * ( 1.f - get_color( src, saturation_t() )); + + q = get_color( src, value_t() ) + * ( 1.f - ( get_color( src, saturation_t() ) * frac )); + + t = get_color( src, value_t() ) + * ( 1.f - ( get_color( src, saturation_t() ) * ( 1.f - frac ))); + + switch( i ) + { + case 0: + { + red = get_color( src, value_t() ); + green = t; + blue = p; + + break; + } + + case 1: + { + red = q; + green = get_color( src, value_t() ); + blue = p; + + break; + } + + case 2: + { + red = p; + green = get_color( src, value_t() ); + blue = t; + + break; + } + + case 3: + { + red = p; + green = q; + blue = get_color( src, value_t() ); + + break; + } + + case 4: + { + red = t; + green = p; + blue = get_color( src, value_t() ); + + break; + } + + case 5: + { + red = get_color( src, value_t() ); + green = p; + blue = q; + + break; + } + + } + } + + get_color(dst,red_t()) = + channel_convert<typename color_element_type< P2, red_t >::type>( red ); + get_color(dst,green_t())= + channel_convert<typename color_element_type< P2, green_t >::type>( green ); + get_color(dst,blue_t()) = + channel_convert<typename color_element_type< P2, blue_t >::type>( blue ); + } +}; + +} // namespace gil +} // namespace boost + +#endif // BOOST_GIL_EXTENSION_TOOLBOX_COLOR_SPACES_HSV_HPP diff --git a/boost/gil/extension/toolbox/color_spaces/lab.hpp b/boost/gil/extension/toolbox/color_spaces/lab.hpp new file mode 100644 index 0000000000..140c79f763 --- /dev/null +++ b/boost/gil/extension/toolbox/color_spaces/lab.hpp @@ -0,0 +1,178 @@ +/* + Copyright 2012 Chung-Lin Wen + 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_TOOLBOX_COLOR_SPACES_LAB_HPP +#define BOOST_GIL_EXTENSION_TOOLBOX_COLOR_SPACES_LAB_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file lab.hpp +/// \brief Support for CIE Lab color space +/// \author Chung-Lin Wen \n +/// +/// \date 2012 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +#include <boost/gil/gil_all.hpp> // FIXME: Include what you use, not everything, even in extensions! +#include <boost/gil/extension/toolbox/color_spaces/xyz.hpp> + +namespace boost{ namespace gil { + +/// \addtogroup ColorNameModel +/// \{ +namespace lab_color_space +{ +/// \brief Luminance +struct luminance_t {}; +/// \brief a Color Component +struct a_color_opponent_t {}; +/// \brief b Color Component +struct b_color_opponent_t {}; +} +/// \} + +/// \ingroup ColorSpaceModel +typedef mpl::vector3< lab_color_space::luminance_t + , lab_color_space::a_color_opponent_t + , lab_color_space::b_color_opponent_t + > lab_t; + +/// \ingroup LayoutModel +typedef layout<lab_t> lab_layout_t; + +GIL_DEFINE_ALL_TYPEDEFS(32f, float32_t, lab) + +/// \ingroup ColorConvert +/// \brief LAB to XYZ +template <> +struct default_color_converter_impl< lab_t, xyz_t > +{ + template <typename P1, typename P2> + void operator()( const P1& src, P2& dst ) const + { + using namespace lab_color_space; + using namespace xyz_color_space; + + float32_t p = ((get_color(src, luminance_t()) + 16.f)/116.f); + + get_color(dst, y_t()) = + 1.f * powf(p, 3.f); + + get_color(dst, x_t()) = + 0.95047f * powf((p + + (get_color(src, a_color_opponent_t())/500.f) + ), 3.f); + get_color(dst, z_t()) = + 1.08883f * powf((p - + (get_color(src, b_color_opponent_t())/200.f) + ), 3.f); + } +}; + +/// \ingroup ColorConvert +/// \brief XYZ to LAB +/// \note I assume \c xyz_t +template <> +struct default_color_converter_impl< xyz_t, lab_t > +{ +private: + /// \ref http://www.brucelindbloom.com/index.html?Eqn_XYZ_to_Lab.html + BOOST_FORCEINLINE + float32_t forward_companding(float32_t value) const + { + if (value > 216.f/24389.f) + { + return powf(value, 1.f/3.f); + } + else + { + return ((24389.f/27.f * value + 16.f)/116.f); + } + } + +public: + template <typename P1, typename P2> + void operator()( const P1& src, P2& dst ) const + { + using namespace lab_color_space; + + float32_t f_y = + forward_companding( + channel_convert<float32_t>( + get_color(src, xyz_color_space::y_t()) + ) + // / 1.f + ); + + float32_t f_x = + forward_companding( + channel_convert<float32_t>( + get_color(src, xyz_color_space::x_t()) + ) + * (1.f / 0.95047f) // if the compiler is smart, it should + // precalculate this, no? + ); + + float32_t f_z = + forward_companding( + channel_convert<float32_t>( + get_color(src, xyz_color_space::z_t()) + ) + * (1.f / 1.08883f) // if the compiler is smart, it should + // precalculate this, no? + ); + + get_color(dst, luminance_t()) = + 116.f * f_y - 16.f; + + get_color(dst, a_color_opponent_t()) = + 500.f * (f_x - f_y); + + get_color(dst, b_color_opponent_t()) = + 200.f * (f_y - f_z); + } +}; + + +/// \ingroup ColorConvert +/// \brief RGB to LAB +template <> +struct default_color_converter_impl< rgb_t, lab_t > +{ + template <typename P1, typename P2> + void operator()( const P1& src, P2& dst ) const + { + using namespace lab_color_space; + + xyz32f_pixel_t xyz32f_temp_pixel; + default_color_converter_impl<rgb_t, xyz_t>()(src, xyz32f_temp_pixel); + default_color_converter_impl<xyz_t, lab_t>()(xyz32f_temp_pixel, dst); + } +}; + +/// \ingroup ColorConvert +/// \brief LAB to RGB +template <> +struct default_color_converter_impl<lab_t,rgb_t> +{ + template <typename P1, typename P2> + void operator()( const P1& src, P2& dst) const + { + using namespace lab_color_space; + + xyz32f_pixel_t xyz32f_temp_pixel; + default_color_converter_impl<lab_t, xyz_t>()(src, xyz32f_temp_pixel); + default_color_converter_impl<xyz_t, rgb_t>()(xyz32f_temp_pixel, dst); + } +}; + +} // namespace gil +} // namespace boost + +#endif // BOOST_GIL_EXTENSION_TOOLBOX_COLOR_SPACES_LAB_HPP diff --git a/boost/gil/extension/toolbox/color_spaces/xyz.hpp b/boost/gil/extension/toolbox/color_spaces/xyz.hpp new file mode 100644 index 0000000000..a9973adf82 --- /dev/null +++ b/boost/gil/extension/toolbox/color_spaces/xyz.hpp @@ -0,0 +1,157 @@ +/* + Copyright 2012 Chung-Lin Wen, Davide Anastasia + 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_TOOLBOX_COLOR_SPACES_XYZ_HPP +#define BOOST_GIL_EXTENSION_TOOLBOX_COLOR_SPACES_XYZ_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file xyz.hpp +/// \brief Support for CIE XYZ color space +/// \author Chung-Lin Wen, Davide Anastasia \n +/// +/// \date 2012 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +#include <boost/gil/typedefs.hpp> + +namespace boost{ namespace gil { + +/// \addtogroup ColorNameModel +/// \{ +namespace xyz_color_space +{ +/// \brief x Color Component +struct x_t {}; +/// \brief y Color Component +struct y_t {}; +/// \brief z Color Component +struct z_t {}; +} +/// \} + +/// \ingroup ColorSpaceModel +typedef mpl::vector3< xyz_color_space::x_t + , xyz_color_space::y_t + , xyz_color_space::z_t + > xyz_t; + +/// \ingroup LayoutModel +typedef layout<xyz_t> xyz_layout_t; + +GIL_DEFINE_ALL_TYPEDEFS(32f, float32_t, xyz) + +/// \ingroup ColorConvert +/// \brief RGB to XYZ +/// <a href="http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html">Link</a> +/// \note rgb_t is assumed to be sRGB D65 +template <> +struct default_color_converter_impl< rgb_t, xyz_t > +{ +private: + BOOST_FORCEINLINE + float32_t inverse_companding(float32_t sample) const + { + if ( sample > 0.04045f ) + { + return powf((( sample + 0.055f ) / 1.055f ), 2.4f); + } + else + { + return ( sample / 12.92f ); + } + } + +public: + template <typename P1, typename P2> + void operator()( const P1& src, P2& dst ) const + { + using namespace xyz_color_space; + + float32_t red( + inverse_companding( + channel_convert<float32_t>(get_color(src, red_t())))); + float32_t green( + inverse_companding( + channel_convert<float32_t>(get_color(src, green_t())))); + float32_t blue( + inverse_companding( + channel_convert<float32_t>(get_color(src, blue_t())))); + + get_color( dst, x_t() ) = + red * 0.4124564f + + green * 0.3575761f + + blue * 0.1804375f; + get_color( dst, y_t() ) = + red * 0.2126729f + + green * 0.7151522f + + blue * 0.0721750f; + get_color( dst, z_t() ) = + red * 0.0193339f + + green * 0.1191920f + + blue * 0.9503041f; + } +}; + +/// \ingroup ColorConvert +/// \brief XYZ to RGB +template <> +struct default_color_converter_impl<xyz_t,rgb_t> +{ +private: + BOOST_FORCEINLINE + float32_t companding(float32_t sample) const + { + if ( sample > 0.0031308f ) + { + return ( 1.055f * powf( sample, 1.f/2.4f ) - 0.055f ); + } + else + { + return ( 12.92f * sample ); + } + } + +public: + template <typename P1, typename P2> + void operator()( const P1& src, P2& dst) const + { + using namespace xyz_color_space; + + // Note: ideally channel_convert should be compiled out, because xyz_t + // is float32_t natively only + float32_t x( channel_convert<float32_t>( get_color( src, x_t() ) ) ); + float32_t y( channel_convert<float32_t>( get_color( src, y_t() ) ) ); + float32_t z( channel_convert<float32_t>( get_color( src, z_t() ) ) ); + + get_color(dst,red_t()) = + channel_convert<typename color_element_type<P2, red_t>::type>( + companding( x * 3.2404542f + + y * -1.5371385f + + z * -0.4985314f ) + ); + get_color(dst,green_t()) = + channel_convert<typename color_element_type<P2, green_t>::type>( + companding( x * -0.9692660f + + y * 1.8760108f + + z * 0.0415560f ) + ); + get_color(dst,blue_t()) = + channel_convert<typename color_element_type<P2, blue_t>::type>( + companding( x * 0.0556434f + + y * -0.2040259f + + z * 1.0572252f ) + ); + } +}; + +} // namespace gil +} // namespace boost + +#endif // BOOST_GIL_EXTENSION_TOOLBOX_COLOR_SPACES_XYZ_HPP diff --git a/boost/gil/extension/toolbox/color_spaces/ycbcr.hpp b/boost/gil/extension/toolbox/color_spaces/ycbcr.hpp new file mode 100644 index 0000000000..e8e282f6a5 --- /dev/null +++ b/boost/gil/extension/toolbox/color_spaces/ycbcr.hpp @@ -0,0 +1,253 @@ +/* + Copyright 2013 Juan V. Puertos G-Cluster, Christian Henning + 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_TOOLBOX_COLOR_SPACES_YCBCR_HPP +#define BOOST_GIL_EXTENSION_TOOLBOX_COLOR_SPACES_YCBCR_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file ycbcr.hpp +/// \brief Support for ycbcr ITU.BT-601 color space +/// \author Juan V. Puertos G-Cluster 2013 \n +/// +/// \date 2013 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +#include <cstdint> +#include <boost/algorithm/clamp.hpp> +#include <boost/mpl/range_c.hpp> +#include <boost/mpl/vector_c.hpp> +#include <boost/gil/gil_all.hpp> + +#include <boost/gil/extension/toolbox/metafunctions/get_num_bits.hpp> + +namespace boost{ namespace gil { + +/// \addtogroup ColorNameModel +/// \{ +namespace ycbcr_601_color_space +{ +/// \brief Luminance +struct y_t {}; +/// \brief Blue chrominance component +struct cb_t {}; +/// \brief Red chrominance component +struct cr_t {}; +} + +namespace ycbcr_709_color_space +{ +/// \brief Luminance +struct y_t {}; +/// \brief Blue chrominance component +struct cb_t {}; +/// \brief Red chrominance component +struct cr_t {}; +} +/// \} + +/// \ingroup ColorSpaceModel +typedef boost::mpl::vector3< ycbcr_601_color_space::y_t, ycbcr_601_color_space::cb_t, ycbcr_601_color_space::cr_t > ycbcr_601__t; +typedef boost::mpl::vector3< ycbcr_709_color_space::y_t, ycbcr_709_color_space::cb_t, ycbcr_709_color_space::cr_t > ycbcr_709__t; + +/// \ingroup LayoutModel +typedef boost::gil::layout<ycbcr_601__t> ycbcr_601__layout_t; +typedef boost::gil::layout<ycbcr_709__t> ycbcr_709__layout_t; + +//The channel depth is ALWAYS 8bits ofr YCbCr! +GIL_DEFINE_ALL_TYPEDEFS(8, uint8_t, ycbcr_601_) +GIL_DEFINE_ALL_TYPEDEFS(8, uint8_t, ycbcr_709_) + +/* + * 601 Source: http://en.wikipedia.org/wiki/YCbCr#ITU-R_BT.601_conversion + * 709 Source: http://en.wikipedia.org/wiki/YCbCr#ITU-R_BT.709_conversion + * (using values coming directly from ITU-R BT.601 recommendation) + * (using values coming directly from ITU-R BT.709 recommendation) + */ + +/** +* @brief Convert YCbCr ITU.BT-601 to RGB. +*/ +template<> +struct default_color_converter_impl<ycbcr_601__t, rgb_t> +{ + // Note: the RGB_t channels range can be set later on by the users. We dont want to cast to uint8_t or anything here. + template < typename SRCP, typename DSTP > + void operator()( const SRCP& src, DSTP& dst ) const + { + typedef typename channel_type< DSTP >::type dst_channel_t; + convert( src, dst + , typename boost::is_same< typename mpl::int_< sizeof( dst_channel_t ) >::type + , typename mpl::int_<1>::type + >::type() + ); + } + +private: + + // optimization for bit8 channels + template< typename Src_Pixel + , typename Dst_Pixel + > + void convert( const Src_Pixel& src + , Dst_Pixel& dst + , mpl::true_ // is 8 bit channel + ) const + { + using namespace boost::algorithm; + using namespace ycbcr_601_color_space; + + typedef typename channel_type< Src_Pixel >::type src_channel_t; + typedef typename channel_type< Dst_Pixel >::type dst_channel_t; + + src_channel_t y = channel_convert<src_channel_t>( get_color(src, y_t())); + src_channel_t cb = channel_convert<src_channel_t>( get_color(src, cb_t())); + src_channel_t cr = channel_convert<src_channel_t>( get_color(src, cr_t())); + + // The intermediate results of the formulas require at least 16bits of precission. + std::int_fast16_t c = y - 16; + std::int_fast16_t d = cb - 128; + std::int_fast16_t e = cr - 128; + std::int_fast16_t red = clamp((( 298 * c + 409 * e + 128) >> 8), 0, 255); + std::int_fast16_t green = clamp((( 298 * c - 100 * d - 208 * e + 128) >> 8), 0, 255); + std::int_fast16_t blue = clamp((( 298 * c + 516 * d + 128) >> 8), 0, 255); + + get_color( dst, red_t() ) = (dst_channel_t) red; + get_color( dst, green_t() ) = (dst_channel_t) green; + get_color( dst, blue_t() ) = (dst_channel_t) blue; + } + + + template< typename Src_Pixel + , typename Dst_Pixel + > + void convert( const Src_Pixel& src + , Dst_Pixel& dst + , mpl::false_ // is 8 bit channel + ) const + { + using namespace boost::algorithm; + using namespace ycbcr_601_color_space; + + typedef typename channel_type< Dst_Pixel >::type dst_channel_t; + + double y = get_color( src, y_t() ); + double cb = get_color( src, cb_t() ); + double cr = get_color( src, cr_t() ); + + get_color(dst, red_t()) = (dst_channel_t) clamp( 1.6438 * ( y - 16.0 ) + 1.5960 * ( cr -128.0 ) + , 0.0 + , 255.0 + ); + + get_color(dst, green_t()) = (dst_channel_t) clamp( 1.6438 * ( y - 16.0 ) - 0.3917 * ( cb - 128.0 ) + 0.8129 * ( cr -128.0 ) + , 0.0 + , 255.0 + ); + + get_color(dst, blue_t()) = (dst_channel_t) clamp( 1.6438 * ( y - 16.0 ) - 2.0172 * ( cb -128.0 ) + , 0.0 + , 255.0 + ); + } +}; + +/* + * Source: http://en.wikipedia.org/wiki/YCbCr#ITU-R_BT.601_conversion + * digital Y′CbCr derived from digital R'dG'dB'd 8 bits per sample, each using the full range. + * with NO footroom wither headroom. + */ +/** +* @brief Convert RGB to YCbCr ITU.BT-601. +*/ +template<> +struct default_color_converter_impl<rgb_t, ycbcr_601__t> +{ + template < typename SRCP, typename DSTP > + void operator()( const SRCP& src, DSTP& dst ) const + { + using namespace ycbcr_601_color_space; + + typedef typename channel_type< SRCP >::type src_channel_t; + typedef typename channel_type< DSTP >::type dst_channel_t; + + src_channel_t red = channel_convert<src_channel_t>( get_color(src, red_t())); + src_channel_t green = channel_convert<src_channel_t>( get_color(src, green_t())); + src_channel_t blue = channel_convert<src_channel_t>( get_color(src, blue_t())); + + double y = 16.0 + 0.2567 * red + 0.5041 * green + 0.0979 * blue; + double cb = 128.0 - 0.1482 * red - 0.2909 * green + 0.4392 * blue; + double cr = 128.0 + 0.4392 * red - 0.3677 * green - 0.0714 * blue; + + get_color( dst, y_t() ) = (dst_channel_t) y; + get_color( dst, cb_t() ) = (dst_channel_t) cb; + get_color( dst, cr_t() ) = (dst_channel_t) cr; + } +}; + +/** +* @brief Convert RGB to YCbCr ITU.BT-709. +*/ +template<> +struct default_color_converter_impl<rgb_t, ycbcr_709__t> +{ + template < typename SRCP, typename DSTP > + void operator()( const SRCP& src, DSTP& dst ) const + { + using namespace ycbcr_709_color_space; + + typedef typename channel_type< SRCP >::type src_channel_t; + typedef typename channel_type< DSTP >::type dst_channel_t; + + src_channel_t red = channel_convert<src_channel_t>( get_color(src, red_t())); + src_channel_t green = channel_convert<src_channel_t>( get_color(src, green_t())); + src_channel_t blue = channel_convert<src_channel_t>( get_color(src, blue_t())); + + double y = 0.299 * red + 0.587 * green + 0.114 * blue; + double cb = 128.0 - 0.168736 * red - 0.331264 * green + 0.5 * blue; + double cr = 128.0 + 0.5 * red - 0.418688 * green - 0.081312 * blue; + + get_color( dst, y_t() ) = (dst_channel_t) y; + get_color( dst, cb_t() ) = (dst_channel_t) cb; + get_color( dst, cr_t() ) = (dst_channel_t) cr; + } +}; + +/** +* @brief Convert RGB to YCbCr ITU.BT-709. +*/ +template<> +struct default_color_converter_impl<ycbcr_709__t, rgb_t> +{ + template < typename SRCP, typename DSTP > + void operator()( const SRCP& src, DSTP& dst ) const + { + using namespace ycbcr_709_color_space; + + typedef typename channel_type< SRCP >::type src_channel_t; + typedef typename channel_type< DSTP >::type dst_channel_t; + + src_channel_t y = channel_convert<src_channel_t>( get_color(src, y_t()) ); + src_channel_t cb_clipped = channel_convert<src_channel_t>( get_color(src, cb_t()) - 128 ); + src_channel_t cr_clipped = channel_convert<src_channel_t>( get_color(src, cr_t()) - 128 ); + + double red = y + 1.042 * cr_clipped; + double green = y - 0.34414 * cb_clipped - 0.71414 * cr_clipped; + double blue = y + 1.772 * cb_clipped; + + get_color( dst, red_t() ) = (dst_channel_t) red; + get_color( dst, green_t() ) = (dst_channel_t) green; + get_color( dst, blue_t() ) = (dst_channel_t) blue; + } +}; + +} // namespace gil +} // namespace boost + +#endif diff --git a/boost/gil/extension/io/dynamic_io.hpp b/boost/gil/extension/toolbox/dynamic_images.hpp index 9f88e50d44..f0993599eb 100644 --- a/boost/gil/extension/io/dynamic_io.hpp +++ b/boost/gil/extension/toolbox/dynamic_images.hpp @@ -1,6 +1,6 @@ /* Copyright 2005-2007 Adobe Systems Incorporated - + 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). @@ -9,24 +9,30 @@ */ /*************************************************************************************************/ -#ifndef GIL_DYNAMIC_IO_H -#define GIL_DYNAMIC_IO_H +#ifndef BOOST_GIL_EXTENSION_TOOLBOX_DYNAMIC_IMAGES_HPP +#define BOOST_GIL_EXTENSION_TOOLBOX_DYNAMIC_IMAGES_HPP -/// \file -/// \brief Generic io functions for dealing with dynamic images -// -/// \author Hailin Jin and Lubomir Bourdev \n -/// Adobe Systems Incorporated -/// \date 2005-2007 \n Last updated May 30, 2006 +//////////////////////////////////////////////////////////////////////////////////////// +/// \file dynamic_images.hpp +/// \brief Generic io functions for dealing with dynamic images. +/// \author Hailin Jin, Lubomir Bourdev, and Christian Henning \n +/// +/// \date 2012 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// #include <boost/mpl/at.hpp> #include <boost/mpl/size.hpp> -#include "../../gil_config.hpp" -#include "io_error.hpp" -#include "../dynamic_image/any_image.hpp" +#include <boost/gil/gil_config.hpp> +#include <boost/gil/extension/dynamic_image/dynamic_image_all.hpp> namespace boost { namespace gil { +// need this for various meta functions. +struct any_image_pixel_t {}; +struct any_image_channel_t {}; +struct any_image_color_space_t {}; + namespace detail { template <long N> @@ -55,8 +61,31 @@ class dynamic_io_fnobj { template <typename View> void apply(const View& view,mpl::true_ ) {_op->apply(view);} + + template <typename View, typename Info > + void apply( const View& view + , const Info& info + , const mpl::true_ + ) + { + _op->apply( view, info ); + } + template <typename View> - void apply(const View& view,mpl::false_) {io_error("dynamic_io: unsupported view type for the given file format");} + void apply(const View& /* view */ ,mpl::false_) + { + throw std::ios_base::failure( "dynamic_io: unsupported view type for the given file format" ); + } + + template <typename View, typename Info > + void apply( const View& /* view */ + , const Info& /* info */ + , const mpl::false_ + ) + { + throw std::ios_base::failure( "dynamic_io: unsupported view type for the given file format" ); + } + public: dynamic_io_fnobj(OpClass* op) : _op(op) {} @@ -64,6 +93,16 @@ public: template <typename View> void operator()(const View& view) {apply(view,typename IsSupported::template apply<View>::type());} + + template< typename View, typename Info > + void operator()(const View& view, const Info& info ) + { + apply( view + , info + , typename IsSupported::template apply< View >::type() + ); + } + }; } // namespace detail @@ -75,6 +114,13 @@ inline bool construct_matched(any_image<Images>& im,Pred pred) { return detail::construct_matched_t<mpl::size<Images>::value>::apply(im,pred); } +template<> +struct color_space_type< any_image_pixel_t > +{ + typedef any_image_color_space_t type; +}; + + } } // namespace boost::gil -#endif +#endif // BOOST_GIL_EXTENSION_TOOLBOX_DYNAMIC_IMAGES_HPP diff --git a/boost/gil/extension/toolbox/image_types.hpp b/boost/gil/extension/toolbox/image_types.hpp new file mode 100644 index 0000000000..94d52fad63 --- /dev/null +++ b/boost/gil/extension/toolbox/image_types.hpp @@ -0,0 +1,24 @@ +/* + Copyright 2012 Christian Henning + 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_TOOLBOX_METAFUNCTIONS_IMAGE_TYPES_HPP +#define BOOST_GIL_EXTENSION_TOOLBOX_METAFUNCTIONS_IMAGE_TYPES_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file image_types.hpp +/// \brief Image Types for toolbox extension. +/// \author Christian Henning \n +/// +/// \date 2012 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +#include <boost/gil/extension/toolbox/image_types/indexed_image.hpp> + +#endif // BOOST_GIL_EXTENSION_TOOLBOX_METAFUNCTIONS_IMAGE_TYPES_HPP diff --git a/boost/gil/extension/toolbox/image_types/indexed_image.hpp b/boost/gil/extension/toolbox/image_types/indexed_image.hpp new file mode 100644 index 0000000000..c413f67533 --- /dev/null +++ b/boost/gil/extension/toolbox/image_types/indexed_image.hpp @@ -0,0 +1,392 @@ +/* + Copyright 2012 Christian Henning + 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_TOOLBOX_IMAGE_TYPES_INDEXED_IMAGE_HPP +#define BOOST_GIL_EXTENSION_TOOLBOX_IMAGE_TYPES_INDEXED_IMAGE_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file indexed_image.hpp +/// \brief Indexed Image extension +/// \author Christian Henning \n +/// +/// \date 2012 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +#include <boost/type_traits/is_integral.hpp> +#include <boost/utility/enable_if.hpp> + +#include <boost/gil/image.hpp> +#include <boost/gil/extension/toolbox/metafunctions/is_bit_aligned.hpp> + + +namespace boost{ namespace gil { + +typedef boost::gil::point2< std::ptrdiff_t > point_t; + +template< typename Locator > +struct get_pixel_type_locator : mpl::if_< typename is_bit_aligned< typename Locator::value_type >::type + , typename Locator::reference + , typename Locator::value_type + > {}; + +// used for virtual locator +template< typename IndicesLoc + , typename PaletteLoc + > +struct indexed_image_deref_fn_base +{ + typedef IndicesLoc indices_locator_t; + typedef PaletteLoc palette_locator_t; + //typedef typename get_pixel_type_locator< indices_locator_t >::type index_t; + + typedef indexed_image_deref_fn_base const_t; + typedef typename PaletteLoc::value_type value_type; + typedef value_type reference; + typedef value_type const_reference; + typedef point_t argument_type; + typedef reference result_type; + + static const bool is_mutable = false; + + indexed_image_deref_fn_base() {} + + indexed_image_deref_fn_base( const indices_locator_t& indices_loc + , const palette_locator_t& palette_loc + ) + : _indices_loc( indices_loc ) + , _palette_loc( palette_loc ) + {} + + void set_indices( const indices_locator_t& indices_loc ) { _indices_loc = indices_loc; } + void set_palette( const palette_locator_t& palette_loc ) { _palette_loc = palette_loc; } + + const indices_locator_t& indices() const { return _indices_loc; } + const palette_locator_t& palette() const { return _palette_loc; } + +protected: + + indices_locator_t _indices_loc; + palette_locator_t _palette_loc; +}; + + +// used for virtual locator +template< typename IndicesLoc + , typename PaletteLoc + , typename Enable = void // there is specialization for integral indices + > +struct indexed_image_deref_fn : indexed_image_deref_fn_base< IndicesLoc + , PaletteLoc + > +{ + typedef indexed_image_deref_fn_base< IndicesLoc + , PaletteLoc + > base_t; + + + indexed_image_deref_fn() + : base_t() + {} + + indexed_image_deref_fn( const typename base_t::indices_locator_t& indices_loc + , const typename base_t::palette_locator_t& palette_loc + ) + : base_t( indices_loc + , palette_loc + ) + {} + + typename base_t::result_type operator()( const point_t& p ) const + { + return * this->_palette_loc.xy_at( at_c<0>( *this->_indices_loc.xy_at( p )), 0 ); + } +}; + + +template< typename IndicesLoc + , typename PaletteLoc + > +struct indexed_image_deref_fn< IndicesLoc + , PaletteLoc + , typename boost::enable_if< boost::is_integral< typename IndicesLoc::value_type > >::type + > : indexed_image_deref_fn_base< IndicesLoc + , PaletteLoc + > +{ + typedef indexed_image_deref_fn_base< IndicesLoc + , PaletteLoc + > base_t; + + indexed_image_deref_fn() + : base_t() + {} + + indexed_image_deref_fn( const typename base_t::indices_locator_t& indices_loc + , const typename base_t::palette_locator_t& palette_loc + ) + : base_t( indices_loc + , palette_loc + ) + {} + + typename base_t::result_type operator()( const point_t& p ) const + { + return *this->_palette_loc.xy_at( *this->_indices_loc.xy_at( p ), 0 ); + } +}; + +template< typename IndicesLoc + , typename PaletteLoc + > +struct indexed_image_locator_type +{ + typedef virtual_2d_locator< indexed_image_deref_fn< IndicesLoc + , PaletteLoc + > + , false + > type; +}; + +template< typename Locator > // indexed_image_locator_type< ... >::type +class indexed_image_view : public image_view< Locator > +{ +public: + + typedef typename Locator::deref_fn_t deref_fn_t; + typedef typename deref_fn_t::indices_locator_t indices_locator_t; + typedef typename deref_fn_t::palette_locator_t palette_locator_t; + + typedef indexed_image_view< Locator > const_t; + + typedef image_view< indices_locator_t > indices_view_t; + typedef image_view< palette_locator_t > palette_view_t; + + indexed_image_view() + : image_view< Locator >() + , _num_colors( 0 ) + {} + + indexed_image_view( const point_t& dimensions + , std::size_t num_colors + , const Locator& locator + ) + : image_view< Locator >( dimensions, locator ) + , _num_colors( num_colors ) + {} + + template< typename IndexedView > + indexed_image_view( const IndexedView& iv ) + : image_view< Locator >( iv ) + , _num_colors( iv._num_colors ) + {} + + std::size_t num_colors() const { return _num_colors; } + + + const indices_locator_t& indices() const { return get_deref_fn().indices(); } + const palette_locator_t& palette() const { return get_deref_fn().palette(); } + + indices_view_t get_indices_view() const { return indices_view_t(this->dimensions(), indices() );} + palette_view_t get_palette_view() const { return palette_view_t(point_t(num_colors(), 1), palette());} + +private: + + const deref_fn_t& get_deref_fn() const { return this->pixels().deref_fn(); } + +private: + + template< typename Locator2 > friend class indexed_image_view; + + std::size_t _num_colors; +}; + +// build an indexed_image_view from two views +template<typename Index_View, typename Palette_View> +indexed_image_view +< + typename indexed_image_locator_type + < + typename Index_View::locator + , typename Palette_View::locator + >::type +> + view(Index_View iv, Palette_View pv) +{ + typedef indexed_image_view< + typename indexed_image_locator_type< + typename Index_View::locator + , typename Palette_View::locator + >::type + > view_t; + + typedef indexed_image_deref_fn< + typename Index_View::locator + , typename Palette_View::locator + > defer_fn_t; + + return view_t( + iv.dimensions() + , pv.dimensions().x + , typename view_t::locator(point_t(0, 0), point_t(1, 1), defer_fn_t(iv.xy_at(0, 0), pv.xy_at(0, 0))) + ); +} + +template< typename Index + , typename Pixel + , typename IndicesAllocator = std::allocator< unsigned char > + , typename PalleteAllocator = std::allocator< unsigned char > + > +class indexed_image +{ +public: + + typedef image< Index, false, IndicesAllocator > indices_t; + typedef image< Pixel, false, PalleteAllocator > palette_t; + + typedef typename indices_t::view_t indices_view_t; + typedef typename palette_t::view_t palette_view_t; + + typedef typename indices_t::const_view_t indices_const_view_t; + typedef typename palette_t::const_view_t palette_const_view_t; + + typedef typename indices_view_t::locator indices_locator_t; + typedef typename palette_view_t::locator palette_locator_t; + + typedef typename indexed_image_locator_type< indices_locator_t + , palette_locator_t + >::type locator_t; + + typedef typename indices_t::coord_t x_coord_t; + typedef typename indices_t::coord_t y_coord_t; + + + typedef indexed_image_view< locator_t > view_t; + typedef typename view_t::const_t const_view_t; + + indexed_image( const x_coord_t width = 0 + , const y_coord_t height = 0 + , const std::size_t num_colors = 1 + , const std::size_t indices_alignment = 0 + , const std::size_t palette_alignment = 0 + ) + : _indices( width , height, indices_alignment, IndicesAllocator() ) + , _palette( num_colors, 1, palette_alignment, PalleteAllocator() ) + { + init( point_t( width, height ), num_colors ); + } + + indexed_image( const point_t& dimensions + , const std::size_t num_colors = 1 + , const std::size_t indices_alignment = 0 + , const std::size_t palette_alignment = 0 + ) + : _indices( dimensions, indices_alignment, IndicesAllocator() ) + , _palette( num_colors, 1, palette_alignment, PalleteAllocator() ) + { + init( dimensions, num_colors ); + } + + indexed_image( const indexed_image& img ) + : _indices( img._indices ) + , _palette( img._palette ) + {} + + template <typename Pixel2, typename Index2> + indexed_image( const indexed_image< Pixel2, Index2 >& img ) + { + _indices = img._indices; + _palette = img._palette; + } + + indexed_image& operator= ( const indexed_image& img ) + { + _indices = img._indices; + _palette = img._palette; + + return *this; + } + + indices_const_view_t get_indices_const_view() const { return static_cast< indices_const_view_t >( _view.get_indices_view()); } + palette_const_view_t get_palette_const_view() const { return static_cast< palette_const_view_t >( _view.get_palette_view()); } + + indices_view_t get_indices_view() { return _view.get_indices_view(); } + palette_view_t get_palette_view() { return _view.get_palette_view(); } + +public: + + view_t _view; + +private: + + void init( const point_t& dimensions + , const std::size_t num_colors + ) + { + typedef indexed_image_deref_fn< indices_locator_t + , palette_locator_t + > defer_fn_t; + + defer_fn_t deref_fn( view( _indices ).xy_at( 0, 0 ) + , view( _palette ).xy_at( 0, 0 ) + ); + + locator_t locator( point_t( 0, 0 ) // p + , point_t( 1, 1 ) // step + , deref_fn + ); + + _view = view_t( dimensions + , num_colors + , locator + ); + } + +private: + + indices_t _indices; + palette_t _palette; +}; + +template< typename Index + , typename Pixel + > +inline +const typename indexed_image< Index, Pixel >::view_t& view( indexed_image< Index, Pixel >& img ) +{ + return img._view; +} + +template< typename Index + , typename Pixel + > +inline +const typename indexed_image< Index, Pixel >::const_view_t const_view( indexed_image< Index, Pixel >& img ) +{ + return static_cast< const typename indexed_image< Index, Pixel >::const_view_t>( img._view ); +} + +// Whole image has one color and all indices are set to 0. +template< typename Locator + , typename Value + > +void fill_pixels( const indexed_image_view< Locator >& view + , const Value& value + ) +{ + typedef indexed_image_view< Locator > view_t; + + fill_pixels( view.get_indices_view(), typename view_t::indices_view_t::value_type( 0 )); + *view.get_palette_view().begin() = value; +} + +} // namespace gil +} // namespace boost + +#endif // BOOST_GIL_EXTENSION_TOOLBOX_IMAGE_TYPES_INDEXED_IMAGE_HPP diff --git a/boost/gil/extension/toolbox/image_types/subchroma_image.hpp b/boost/gil/extension/toolbox/image_types/subchroma_image.hpp new file mode 100644 index 0000000000..e98abe0f1c --- /dev/null +++ b/boost/gil/extension/toolbox/image_types/subchroma_image.hpp @@ -0,0 +1,577 @@ +/* + Copyright 2013 Christian Henning and Juan V. Puertos + 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_TOOLBOX_IMAGE_TYPES_SUBCHROMA_IMAGE_HPP +#define BOOST_GIL_EXTENSION_TOOLBOX_IMAGE_TYPES_SUBCHROMA_IMAGE_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file subchroma_image.hpp +/// \brief Subchroma Image extension +/// \author Christian Henning and Juan V. Puertos\n +/// +/// \date 2013 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +#include <boost/mpl/divides.hpp> +#include <boost/mpl/equal_to.hpp> +#include <boost/mpl/int.hpp> +#include <boost/mpl/if.hpp> +#include <boost/mpl/or.hpp> +#include <boost/mpl/vector_c.hpp> + +#include <boost/gil/image.hpp> + +namespace boost{ namespace gil { + +typedef boost::gil::point2< std::ptrdiff_t > point_t; + +//////////////////////////////////////////////////////////////////////////////////////// +/// \class subchroma_image_deref_fn +/// \ingroup PixelLocatorModel PixelBasedModel +/// \brief Used for virtual_2D_locator +/// +//////////////////////////////////////////////////////////////////////////////////////// +template< typename Locator + , typename Factors + > +struct subchroma_image_deref_fn +{ + typedef gray8_view_t::locator plane_locator_t; + + typedef subchroma_image_deref_fn const_t; + typedef typename Locator::value_type value_type; + typedef value_type reference; + typedef value_type const_reference; + typedef point_t argument_type; + typedef reference result_type; + + static const bool is_mutable = false; + + /// default constructor + subchroma_image_deref_fn() {} + + /// constructor + subchroma_image_deref_fn( const plane_locator_t& y_locator + , const plane_locator_t& v_locator + , const plane_locator_t& u_locator + ) + : _y_locator( y_locator ) + , _v_locator( v_locator ) + , _u_locator( u_locator ) + {} + + /// operator() + typename result_type operator()( const point_t& p ) const + { + typedef Scaling_Factors< mpl::at_c< Factors, 0 >::type::value + , mpl::at_c< Factors, 1 >::type::value + , mpl::at_c< Factors, 2 >::type::value + > scaling_factors_t; + + plane_locator_t y = _y_locator.xy_at( p ); + plane_locator_t v = _v_locator.xy_at( p.x / scaling_factors_t::ss_X, p.y / scaling_factors_t::ss_X ); + plane_locator_t u = _u_locator.xy_at( p.x / scaling_factors_t::ss_X, p.y / scaling_factors_t::ss_X ); + + return value_type( at_c< 0 >( *y ) + , at_c< 0 >( *v ) + , at_c< 0 >( *u ) + ); + } + + /// + const plane_locator_t& y_locator() const { return _y_locator; } + const plane_locator_t& v_locator() const { return _v_locator; } + const plane_locator_t& u_locator() const { return _u_locator; } + +private: + + plane_locator_t _y_locator; + plane_locator_t _v_locator; + plane_locator_t _u_locator; +}; + + +//////////////////////////////////////////////////////////////////////////////////////// +/// \class subchroma_image_locator_type +/// \ingroup PixelLocatorModel PixelBasedModel +/// \brief +/// +//////////////////////////////////////////////////////////////////////////////////////// +template< typename Locator + , typename Factors + > +struct subchroma_image_locator +{ + typedef virtual_2d_locator< subchroma_image_deref_fn< Locator + , Factors + > // Deref + , false // IsTransposed + > type; +}; + + +///////////////////////////// +// PixelBasedConcept +///////////////////////////// + +template < typename Locator, typename Factors > +struct channel_type< subchroma_image_locator< Locator, Factors > > + : public channel_type< typename subchroma_image_locator< Locator, Factors >::type > {}; + +template < typename Locator, typename Factors > +struct color_space_type< subchroma_image_locator< Locator, Factors > > + : public color_space_type< typename subchroma_image_locator< Locator, Factors >::type > {}; + +template < typename Locator, typename Factors > +struct channel_mapping_type< subchroma_image_locator< Locator, Factors > > + : public channel_mapping_type< typename subchroma_image_locator< Locator, Factors >::type > {}; + +template < typename Locator, typename Factors > +struct is_planar< subchroma_image_locator< Locator, Factors > > + : public is_planar< typename subchroma_image_locator< Locator, Factors >::type > {}; + +///////////////////////////// +// HasDynamicXStepTypeConcept +///////////////////////////// + +template < typename Locator, typename Factors > +struct dynamic_x_step_type< subchroma_image_locator< Locator, Factors > > +{ + typedef typename subchroma_image_locator< Locator, Factors >::type type; +}; + +///////////////////////////// +// HasDynamicYStepTypeConcept +///////////////////////////// + +template < typename Locator, typename Factors > +struct dynamic_y_step_type< subchroma_image_locator< Locator, Factors > > +{ + typedef typename subchroma_image_locator< Locator, Factors >::type type; +}; + +///////////////////////////// +// HasTransposedTypeConcept +///////////////////////////// + +template < typename Locator, typename Factors > +struct transposed_type< subchroma_image_locator< Locator, Factors > > +{ + typedef typename subchroma_image_locator< Locator, Factors >::type type; +}; + +////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////////////// +/// \class subchroma_image_view +/// \ingroup ImageViewModel PixelBasedModel +/// \brief A lightweight object that interprets a subchroma image. +/// +//////////////////////////////////////////////////////////////////////////////////////// +template< typename Locator + , typename Factors = mpl::vector_c< int, 4, 4, 4 > + > +class subchroma_image_view : public image_view< Locator > +{ +public: + + typedef typename Locator locator; + typedef typename locator::deref_fn_t deref_fn_t; + typedef typename deref_fn_t::plane_locator_t plane_locator_t; + + + typedef subchroma_image_view const_t; + + typedef image_view< plane_locator_t > plane_view_t; + + /// default constructor + subchroma_image_view() + : image_view< Locator >() + {} + + /// constructor + subchroma_image_view( const point_t& y_dimensions + , const point_t& v_dimensions + , const point_t& u_dimensions + , const Locator& locator + ) + : image_view< Locator >( y_dimensions, locator ) + , _y_dimensions( y_dimensions ) + , _v_dimensions( v_dimensions ) + , _u_dimensions( u_dimensions ) + {} + + /// copy constructor + template< typename Subchroma_View > + subchroma_image_view( const Subchroma_View& v ) + : image_view< locator >( v ) + {} + + const point_t& v_ssfactors() const { return point_t( get_deref_fn().vx_ssfactor(), get_deref_fn().vx_ssfactor() ); } + const point_t& u_ssfactors() const { return point_t( get_deref_fn().ux_ssfactor(), get_deref_fn().ux_ssfactor() ); } + + const point_t& y_dimension() const { return _y_dimensions; } + const point_t& v_dimension() const { return _v_dimensions; } + const point_t& u_dimension() const { return _u_dimensions; } + + const plane_locator_t& y_plane() const { return get_deref_fn().y_locator(); } + const plane_locator_t& v_plane() const { return get_deref_fn().v_locator(); } + const plane_locator_t& u_plane() const { return get_deref_fn().u_locator(); } + + const plane_view_t y_plane_view() const { return plane_view_t( _y_dimensions, y_plane() ); } + const plane_view_t v_plane_view() const { return plane_view_t( _v_dimensions, v_plane() ); } + const plane_view_t u_plane_view() const { return plane_view_t( _u_dimensions, u_plane() ); } + + +private: + + const deref_fn_t& get_deref_fn() const { return this->pixels().deref_fn(); } + +private: + + template< typename Locator, typename Factors > friend class subchroma_image_view; + + point_t _y_dimensions; + point_t _v_dimensions; + point_t _u_dimensions; +}; + + +///////////////////////////// +// PixelBasedConcept +///////////////////////////// + +template < typename Locator, typename Factors > +struct channel_type< subchroma_image_view< Locator, Factors > > + : public channel_type< Locator > {}; + +template < typename Locator, typename Factors > +struct color_space_type< subchroma_image_view< Locator, Factors > > + : public color_space_type< Locator > {}; + +template < typename Locator, typename Factors > +struct channel_mapping_type< subchroma_image_view< Locator, Factors > > + : public channel_mapping_type< Locator > {}; + +template < typename Locator, typename Factors > +struct is_planar< subchroma_image_view< Locator, Factors > > + : public is_planar< Locator > {}; + +///////////////////////////// +// HasDynamicXStepTypeConcept +///////////////////////////// + +template < typename Locator, typename Factors > +struct dynamic_x_step_type< subchroma_image_view< Locator, Factors > > +{ + typedef image_view< typename dynamic_x_step_type< Locator >::type > type; +}; + +///////////////////////////// +// HasDynamicYStepTypeConcept +///////////////////////////// + +template < typename Locator, typename Factors > +struct dynamic_y_step_type< subchroma_image_view< Locator, Factors > > +{ + typedef image_view< typename dynamic_y_step_type< Locator >::type > type; +}; + +///////////////////////////// +// HasTransposedTypeConcept +///////////////////////////// + +template < typename Locator, typename Factors > +struct transposed_type< subchroma_image_view< Locator, Factors > > +{ + typedef image_view< typename transposed_type< Locator >::type > type; +}; + + +///////////////////////////////////////////////////////////// +template< int J + , int a + , int b + > +struct Scaling_Factors +{ + BOOST_STATIC_ASSERT(( mpl::equal_to< mpl::int_< J >, mpl::int_< 4 > >::type::value )); + + BOOST_STATIC_ASSERT(( mpl::or_< mpl::equal_to< mpl::int_< a >, mpl::int_< 4 > > + , mpl::or_< mpl::equal_to< mpl::int_< a >, mpl::int_< 2 > > + , mpl::equal_to< mpl::int_< a >, mpl::int_< 1 > > + > + >::type::value + )); + + BOOST_STATIC_ASSERT(( mpl::or_< mpl::equal_to< mpl::int_< b >, mpl::int_< 4 > > + , mpl::or_< mpl::equal_to< mpl::int_< b >, mpl::int_< 2 > > + , mpl::or_< mpl::equal_to< mpl::int_< b >, mpl::int_< 1 > > + , mpl::equal_to< mpl::int_< b >, mpl::int_< 0 > > + > + > + >::type::value + )); + + BOOST_STATIC_CONSTANT( int, ss_X = ( mpl::divides< mpl::int_< J > + , mpl::int_< a > + >::type::value ) + ); + + BOOST_STATIC_CONSTANT( int, ss_Y = ( mpl::if_< mpl::equal_to< mpl::int_< b >, mpl::int_< 0 > > + , mpl::int_< 2 > + , mpl::if_< mpl::equal_to< mpl::int_< a >, mpl::int_< b > > + , mpl::int_< 1 > + , mpl::int_< 4 > + >::type + >::type::value ) + ); +}; + + + +//////////////////////////////////////////////////////////////////////////////////////// +/// \ingroup ImageModel PixelBasedModel +/// \brief container interface over image view. Models ImageConcept, PixelBasedConcept +/// +/// A subchroma image holds a bunch of planes which don't need to have the same resolution. +/// +//////////////////////////////////////////////////////////////////////////////////////// +template< typename Pixel + , typename Factors = mpl::vector_c< int, 4, 4, 4 > + , typename Allocator = std::allocator< unsigned char > + > +class subchroma_image : public Scaling_Factors< mpl::at_c< Factors, 0 >::type::value + , mpl::at_c< Factors, 1 >::type::value + , mpl::at_c< Factors, 2 >::type::value + > +{ + +public: + + typedef typename channel_type< Pixel >::type channel_t; + typedef pixel< channel_t, gray_layout_t> pixel_t; + + typedef image< pixel_t, false, Allocator > plane_image_t; + + typedef typename plane_image_t::view_t plane_view_t; + typedef typename plane_image_t::const_view_t plane_const_view_t; + typedef typename plane_view_t::locator plane_locator_t; + + typedef typename view_type_from_pixel< Pixel >::type pixel_view_t; + typedef typename pixel_view_t::locator pixel_locator_t; + + typedef typename subchroma_image_locator< pixel_locator_t + , Factors + >::type locator_t; + + typedef typename plane_image_t::coord_t x_coord_t; + typedef typename plane_image_t::coord_t y_coord_t; + + typedef subchroma_image_view< locator_t, Factors > view_t; + typedef typename view_t::const_t const_view_t; + + + /// constructor + subchroma_image( const x_coord_t y_width + , const y_coord_t y_height + ) + : _y_plane( y_width, y_height, 0, Allocator() ) + , _v_plane( y_width / ss_X, y_height / ss_Y, 0, Allocator() ) + , _u_plane( y_width / ss_X, y_height / ss_Y, 0, Allocator() ) + { + init(); + } + +public: + + view_t _view; + +private: + + void init() + { + typedef subchroma_image_deref_fn< pixel_locator_t + , Factors + > defer_fn_t; + + defer_fn_t deref_fn( view( _y_plane ).xy_at( 0, 0 ) + , view( _v_plane ).xy_at( 0, 0 ) + , view( _u_plane ).xy_at( 0, 0 ) + ); + + // init a virtual_2d_locator + locator_t locator( point_t( 0, 0 ) // p + , point_t( 1, 1 ) // step + , deref_fn + ); + + _view = view_t( _y_plane.dimensions() + , _v_plane.dimensions() + , _u_plane.dimensions() + , locator + ); + } + + +private: + + plane_image_t _y_plane; + plane_image_t _v_plane; + plane_image_t _u_plane; +}; + + +///////////////////////////// +// PixelBasedConcept +///////////////////////////// + +template < typename Pixel, typename Factors, typename Alloc > +struct channel_type< subchroma_image< Pixel, Factors, Alloc > > + : public channel_type< Pixel > {}; + +template < typename Pixel, typename Factors, typename Alloc > +struct color_space_type< subchroma_image< Pixel, Factors, Alloc > > + : public color_space_type< Pixel > {}; + +template < typename Pixel, typename Factors, typename Alloc > +struct channel_mapping_type< subchroma_image< Pixel, Factors, Alloc > > + : public channel_mapping_type< Pixel > {}; + +template < typename Pixel, typename Factors, typename Alloc > +struct is_planar< subchroma_image< Pixel, Factors, Alloc > > + : public mpl::bool_< false > {}; + + +///////////////////////////////////////////////////////////////////////////////////////// +/// \name view, const_view +/// \brief Get an image view from an subchroma_image +/// \ingroup ImageModel +/// \brief Returns the non-constant-pixel view of an image +///////////////////////////////////////////////////////////////////////////////////////// +template< typename Pixel + , typename Factors + > +inline +const typename subchroma_image< Pixel, Factors >::view_t& view( subchroma_image< Pixel, Factors >& img ) +{ + return img._view; +} + +template< typename Pixel + , typename Factors + > +inline +const typename subchroma_image< Pixel, Factors >::const_view_t const_view( subchroma_image< Pixel, Factors >& img ) +{ + return static_cast< const typename subchroma_image< Pixel, Factors >::const_view_t>( img._view ); +} + +///////////////////////////////////////////////////////////////////////////////////////// +/// \ingroup ImageViewSTLAlgorithmsFillPixels +/// \brief std::fill for subchroma_image views +///////////////////////////////////////////////////////////////////////////////////////// +template< typename Locator + , typename Factors + , typename Pixel + > +void fill_pixels( const subchroma_image_view< Locator, Factors >& view + , const Pixel& value + ) +{ + typedef typename subchroma_image< Pixel, Factors >::plane_view_t::value_type channel_t; + + fill_pixels( view.y_plane_view(), channel_t( at_c< 0 >( value ))); + fill_pixels( view.v_plane_view(), channel_t( at_c< 1 >( value ))); + fill_pixels( view.u_plane_view(), channel_t( at_c< 2 >( value ))); +} + +///////////////////////////////////////////////////////////////////////////////////////// +/// \ingroup ImageViewConstructors +/// \brief Creates a subchroma view from a raw memory +///////////////////////////////////////////////////////////////////////////////////////// +template< typename Pixel + , typename Factors + > +typename subchroma_image< Pixel + , Factors + >::view_t subchroma_view( std::size_t y_width + , std::size_t y_height + , unsigned char* y_base + ) +{ + typedef Scaling_Factors< mpl::at_c< Factors, 0 >::type::value + , mpl::at_c< Factors, 1 >::type::value + , mpl::at_c< Factors, 2 >::type::value + > scaling_factors_t; + + std::size_t y_channel_size = 1; + std::size_t u_channel_size = 1; + + unsigned char* u_base = y_base + ( y_width * y_height * y_channel_size ); + unsigned char* v_base = u_base + ( y_width / scaling_factors_t::ss_X ) + * u_channel_size; + + typedef subchroma_image< Pixel, Factors >::plane_view_t plane_view_t; + + plane_view_t y_plane = interleaved_view( y_width + , y_height + , (plane_view_t::value_type*) y_base // pixels + , y_width // rowsize_in_bytes + ); + + plane_view_t v_plane = interleaved_view( y_width / scaling_factors_t::ss_X + , y_height / scaling_factors_t::ss_Y + , (plane_view_t::value_type*) v_base // pixels + , y_width // rowsize_in_bytes + ); + + plane_view_t u_plane = interleaved_view( y_width / scaling_factors_t::ss_X + , y_height / scaling_factors_t::ss_Y + , (plane_view_t::value_type*) u_base // pixels + , y_width // rowsize_in_bytes + ); + + typedef subchroma_image_deref_fn< typename subchroma_image< Pixel + , Factors + >::pixel_locator_t + , Factors + > defer_fn_t; + + defer_fn_t deref_fn( y_plane.xy_at( 0, 0 ) + , v_plane.xy_at( 0, 0 ) + , u_plane.xy_at( 0, 0 ) + ); + + + typedef subchroma_image< Pixel + , Factors + >::locator_t locator_t; + + locator_t locator( point_t( 0, 0 ) // p + , point_t( 1, 1 ) // step + , deref_fn + ); + + typedef subchroma_image< Pixel + , Factors + >::view_t view_t; + + return view_t( point_t( y_width, y_height ) + , point_t( y_width / scaling_factors_t::ss_X, y_height / scaling_factors_t::ss_Y ) + , point_t( y_width / scaling_factors_t::ss_X, y_height / scaling_factors_t::ss_Y ) + , locator + ); +} + +} // namespace gil +} // namespace boost + +#endif // BOOST_GIL_EXTENSION_TOOLBOX_IMAGE_TYPES_SUBCHROMA_IMAGE_HPP diff --git a/boost/gil/extension/toolbox/metafunctions.hpp b/boost/gil/extension/toolbox/metafunctions.hpp new file mode 100644 index 0000000000..1912ed0023 --- /dev/null +++ b/boost/gil/extension/toolbox/metafunctions.hpp @@ -0,0 +1,31 @@ +/* + Copyright 2012 Christian Henning + 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_TOOLBOX_METAFUNCTIONS_HPP +#define BOOST_GIL_EXTENSION_TOOLBOX_METAFUNCTIONS_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file metafunctions.hpp +/// \brief Header for toolbox's metafunctions. +/// \author Christian Henning \n +/// +/// \date 2012 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +#include <boost/gil/extension/toolbox/metafunctions/channel_type.hpp> +#include <boost/gil/extension/toolbox/metafunctions/channel_view.hpp> +#include <boost/gil/extension/toolbox/metafunctions/get_num_bits.hpp> +#include <boost/gil/extension/toolbox/metafunctions/get_pixel_type.hpp> +#include <boost/gil/extension/toolbox/metafunctions/is_bit_aligned.hpp> +#include <boost/gil/extension/toolbox/metafunctions/is_homogeneous.hpp> +#include <boost/gil/extension/toolbox/metafunctions/is_similar.hpp> +#include <boost/gil/extension/toolbox/metafunctions/pixel_bit_size.hpp> + +#endif // BOOST_GIL_EXTENSION_TOOLBOX_METAFUNCTIONS_HPP diff --git a/boost/gil/extension/toolbox/metafunctions/channel_type.hpp b/boost/gil/extension/toolbox/metafunctions/channel_type.hpp new file mode 100644 index 0000000000..13550b43e3 --- /dev/null +++ b/boost/gil/extension/toolbox/metafunctions/channel_type.hpp @@ -0,0 +1,111 @@ +/* + Copyright 2012 Christian Henning, Andreas Pokorny, 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_TOOLBOX_METAFUNCTIONS_CHANNEL_TYPE_HPP +#define BOOST_GIL_EXTENSION_TOOLBOX_METAFUNCTIONS_CHANNEL_TYPE_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file channel_type.hpp +/// \brief channel_type metafunction. +/// \author Christian Henning, Andreas Pokorny, Lubomir Bourdev \n +/// +/// \date 2012 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +#include <boost/utility/enable_if.hpp> + +#include <boost/mpl/at.hpp> + +#include <boost/gil/bit_aligned_pixel_reference.hpp> +#include <boost/gil/channel.hpp> + +#include <boost/gil/extension/toolbox/dynamic_images.hpp> + +#include <boost/gil/extension/toolbox/metafunctions/get_num_bits.hpp> +#include <boost/gil/extension/toolbox/metafunctions/is_homogeneous.hpp> + +namespace boost{ namespace gil { + +/// channel_type metafunction +/// \brief Generates the channel type for + +template <typename B, typename C, typename L, bool M> +struct gen_chan_ref +{ + typedef packed_dynamic_channel_reference< B + , mpl::at_c< C, 0 >::type::value + , M + > type; +}; + +//! This implementation works for bit_algined_pixel_reference +//! with a homogeneous channel layout. +//! The result type will be a packed_dynamic_channel_reference, since the +//! offset info will be missing. + +// bit_aligned_pixel_reference +template <typename B, typename C, typename L, bool M> +struct channel_type< bit_aligned_pixel_reference<B,C,L,M> > + : lazy_enable_if< is_homogeneous< bit_aligned_pixel_reference< B, C, L, M > > + , gen_chan_ref< B, C, L, M > + > {}; + +template <typename B, typename C, typename L, bool M> +struct channel_type<const bit_aligned_pixel_reference<B,C,L,M> > + : lazy_enable_if< is_homogeneous< bit_aligned_pixel_reference< B, C, L, M > > + , gen_chan_ref< B, C, L, M > + > {}; + +template <typename B, typename C, typename L> +struct gen_chan_ref_p +{ + typedef packed_dynamic_channel_reference< B + , get_num_bits< typename mpl::at_c<C,0>::type>::value + , true + > type; +}; + +// packed_pixel +template < typename BitField + , typename ChannelRefVec + , typename Layout + > +struct channel_type< packed_pixel< BitField + , ChannelRefVec + , Layout + > + > : lazy_enable_if< is_homogeneous< packed_pixel< BitField + , ChannelRefVec + , Layout + > + > + , gen_chan_ref_p< BitField + , ChannelRefVec + , Layout + > + > {}; + +template <typename B, typename C, typename L> +struct channel_type< const packed_pixel< B, C, L > > + : lazy_enable_if< is_homogeneous<packed_pixel< B, C, L > > + , gen_chan_ref_p< B, C, L > + > +{}; + +template<> +struct channel_type< any_image_pixel_t > +{ + typedef any_image_channel_t type; +}; + +} // namespace gil +} // namespace boost + +#endif // BOOST_GIL_EXTENSION_TOOLBOX_METAFUNCTIONS_CHANNEL_TYPE_HPP diff --git a/boost/gil/extension/toolbox/metafunctions/channel_view.hpp b/boost/gil/extension/toolbox/metafunctions/channel_view.hpp new file mode 100644 index 0000000000..4d42ff3ac1 --- /dev/null +++ b/boost/gil/extension/toolbox/metafunctions/channel_view.hpp @@ -0,0 +1,79 @@ +/* + Copyright 2010 Fabien Castan, Christian Henning + 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_TOOLBOX_CHANNEL_VIEW_HPP_INCLUDED +#define BOOST_GIL_EXTENSION_TOOLBOX_CHANNEL_VIEW_HPP_INCLUDED + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file channel_view.hpp +/// \brief Helper to generate channel_view type. +/// \author Fabien Castan, Christian Henning \n +/// +/// \date 2010 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +#include <boost/gil/image_view_factory.hpp> + +namespace boost { +namespace gil { + +template < typename Channel + , typename View + > +struct channel_type_to_index +{ + static const int value = detail::type_to_index< typename color_space_type< View >::type // color (mpl::vector) + , Channel // channel type + >::type::value; //< index of the channel in the color (mpl::vector) +}; + +template< typename Channel + , typename View + > +struct channel_view_type : public kth_channel_view_type< channel_type_to_index< Channel + , View + >::value + , View + > +{ + static const int index = channel_type_to_index< Channel + , View + >::value; + + typedef kth_channel_view_type< index + , View + > parent_t; + + typedef typename parent_t::type type; + + + static type make( const View& src ) + { + return parent_t::make( src ); + } +}; + +/// \ingroup ImageViewTransformationsKthChannel +template< typename Channel + , typename View + > +typename channel_view_type< Channel + , View + >::type channel_view( const View& src ) +{ + return channel_view_type< Channel + , View + >::make( src ); +} + +} // namespace gil +} // namespace boost + +#endif // BOOST_GIL_EXTENSION_TOOLBOX_CHANNEL_VIEW_HPP_INCLUDED diff --git a/boost/gil/extension/toolbox/metafunctions/get_num_bits.hpp b/boost/gil/extension/toolbox/metafunctions/get_num_bits.hpp new file mode 100644 index 0000000000..9cec37eac4 --- /dev/null +++ b/boost/gil/extension/toolbox/metafunctions/get_num_bits.hpp @@ -0,0 +1,73 @@ +/* + Copyright 2012 Christian Henning, Andreas Pokorny, 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_TOOLBOX_METAFUNCTIONS_GET_NUM_BITS_HPP +#define BOOST_GIL_EXTENSION_TOOLBOX_METAFUNCTIONS_GET_NUM_BITS_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file get_num_bits.hpp +/// \brief get_num_bits metafunction. +/// \author Christian Henning, Andreas Pokorny, Lubomir Bourdev \n +/// +/// \date 2012 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +#include <boost/gil/channel.hpp> + +#include <boost/mpl/int.hpp> +#include <boost/type_traits/is_integral.hpp> +#include <boost/type_traits/is_class.hpp> +#include <boost/utility/enable_if.hpp> + +namespace boost{ namespace gil { + +/// get_num_bits metafunctions +/// \brief Determines the numbers of bits for the given channel type. + +template <typename T, class = void > +struct get_num_bits; + +template< typename B, int I, int S, bool M > +struct get_num_bits< packed_channel_reference< B, I, S, M > > : mpl::int_< S > +{}; + +template< typename B, int I, int S, bool M > +struct get_num_bits< const packed_channel_reference< B, I, S, M > > : mpl::int_< S > +{}; + +template<typename B, int I, bool M> +struct get_num_bits< packed_dynamic_channel_reference< B, I, M > > : mpl::int_< I > +{}; + +template<typename B, int I, bool M> +struct get_num_bits< const packed_dynamic_channel_reference< B, I, M > > : mpl::int_< I > +{}; + +template< int N > +struct get_num_bits< packed_channel_value< N > > : mpl::int_< N > +{}; + +template< int N > +struct get_num_bits< const packed_channel_value< N > > : mpl::int_< N > +{}; + +template< typename T > +struct get_num_bits< T + , typename enable_if< mpl::and_< is_integral< T > + , mpl::not_< is_class< T > > + > + >::type + > : mpl::int_< sizeof(T) * 8 > +{}; + +} // namespace gil +} // namespace boost + +#endif // BOOST_GIL_EXTENSION_TOOLBOX_METAFUNCTIONS_GET_NUM_BITS_HPP diff --git a/boost/gil/extension/toolbox/metafunctions/get_pixel_type.hpp b/boost/gil/extension/toolbox/metafunctions/get_pixel_type.hpp new file mode 100644 index 0000000000..dc0876c1ae --- /dev/null +++ b/boost/gil/extension/toolbox/metafunctions/get_pixel_type.hpp @@ -0,0 +1,46 @@ +/* + Copyright 2012 Christian Henning, Andreas Pokorny, 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_TOOLBOX_METAFUNCTIONS_GET_PIXEL_TYPE_HPP +#define BOOST_GIL_EXTENSION_TOOLBOX_METAFUNCTIONS_GET_PIXEL_TYPE_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file get_pixel_type.hpp +/// \brief get_pixel_type metafunction. +/// \author Christian Henning, Andreas Pokorny, Lubomir Bourdev \n +/// +/// \date 2012 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +#include <boost/gil/extension/toolbox/dynamic_images.hpp> +#include <boost/gil/extension/toolbox/metafunctions/is_bit_aligned.hpp> + +namespace boost{ namespace gil { + +/// get_pixel_type metafunction +/// \brief Depending on Image this function generates either +/// the pixel type or the reference type in case +/// the image is bit_aligned. +template< typename View > +struct get_pixel_type : mpl::if_< typename is_bit_aligned< typename View::value_type >::type + , typename View::reference + , typename View::value_type + > {}; + +template< typename ImageViewTypes > +struct get_pixel_type< any_image_view< ImageViewTypes > > +{ + typedef any_image_pixel_t type; +}; + +} // namespace gil +} // namespace boost + +#endif // BOOST_GIL_EXTENSION_TOOLBOX_METAFUNCTIONS_GET_PIXEL_TYPE_HPP diff --git a/boost/gil/extension/toolbox/metafunctions/gil_extensions.hpp b/boost/gil/extension/toolbox/metafunctions/gil_extensions.hpp new file mode 100644 index 0000000000..927a2194c7 --- /dev/null +++ b/boost/gil/extension/toolbox/metafunctions/gil_extensions.hpp @@ -0,0 +1,42 @@ +/* + Copyright 2010 Christian Henning, Andreas Pokorny, 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_TOOLBOX_GIL_EXTENSIONS_HPP_INCLUDED +#define BOOST_GIL_EXTENSION_TOOLBOX_GIL_EXTENSIONS_HPP_INCLUDED + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file +/// \brief Definitions of is_bit_aligned, is_homogeneous, and is_similar metafunctions and +/// some other goodies. +/// \author Christian Henning, Andreas Pokorny, Lubomir Bourdev \n +/// +/// \date 2008 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +#include <boost/gil/gil_all.hpp> + + +#include <boost/mpl/if.hpp> + +#include <boost/gil/extension/toolbox/dynamic_images.hpp> + +namespace boost { namespace gil { + + +/// other goodies + + + + + +} // namespace gil +} // namespace boost + +#endif // BOOST_GIL_EXTENSION_TOOLBOX_GIL_EXTENSIONS_HPP_INCLUDED diff --git a/boost/gil/extension/toolbox/metafunctions/is_bit_aligned.hpp b/boost/gil/extension/toolbox/metafunctions/is_bit_aligned.hpp new file mode 100644 index 0000000000..369f8cbab5 --- /dev/null +++ b/boost/gil/extension/toolbox/metafunctions/is_bit_aligned.hpp @@ -0,0 +1,47 @@ +/* + Copyright 2012 Christian Henning, Andreas Pokorny, 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_TOOLBOX_METAFUNCTIONS_IS_BIT_ALIGNED_TYPE_HPP +#define BOOST_GIL_EXTENSION_TOOLBOX_METAFUNCTIONS_IS_BIT_ALIGNED_TYPE_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file is_bit_aligned.hpp +/// \brief is_bit_aligned metafunction. +/// \author Christian Henning, Andreas Pokorny, Lubomir Bourdev \n +/// +/// \date 2012 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +#include <boost/gil/bit_aligned_pixel_reference.hpp> + +namespace boost{ namespace gil { + +/// is_bit_aligned metafunctions +/// \brief Determines whether the given type is bit_aligned. + +template< typename PixelRef > +struct is_bit_aligned : mpl::false_{}; + +template <typename B, typename C, typename L, bool M> +struct is_bit_aligned<bit_aligned_pixel_reference<B,C,L,M> > : mpl::true_{}; + +template <typename B, typename C, typename L, bool M> +struct is_bit_aligned<const bit_aligned_pixel_reference<B,C,L,M> > : mpl::true_{}; + +template <typename B, typename C, typename L> +struct is_bit_aligned<packed_pixel<B,C,L> > : mpl::true_{}; + +template <typename B, typename C, typename L> +struct is_bit_aligned<const packed_pixel<B,C,L> > : mpl::true_{}; + +} // namespace gil +} // namespace boost + +#endif // BOOST_GIL_EXTENSION_TOOLBOX_METAFUNCTIONS_IS_BIT_ALIGNED_TYPE_HPP diff --git a/boost/gil/extension/toolbox/metafunctions/is_homogeneous.hpp b/boost/gil/extension/toolbox/metafunctions/is_homogeneous.hpp new file mode 100644 index 0000000000..9770d2bb2b --- /dev/null +++ b/boost/gil/extension/toolbox/metafunctions/is_homogeneous.hpp @@ -0,0 +1,93 @@ +/* + Copyright 2012 Christian Henning, Andreas Pokorny, 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_TOOLBOX_METAFUNCTIONS_IS_HOMOGENEOUS_HPP +#define BOOST_GIL_EXTENSION_TOOLBOX_METAFUNCTIONS_IS_HOMOGENEOUS_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file is_homogeneous.hpp +/// \brief is_homogeneous metafunction +/// \author Christian Henning, Andreas Pokorny, Lubomir Bourdev \n +/// +/// \date 2012 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +#include <boost/mpl/at.hpp> + +#include <boost/gil/pixel.hpp> + + +namespace boost{ namespace gil { + +/// is_homogeneous metafunctions +/// \brief Determines if a pixel types are homogeneous. + +template<typename C,typename CMP, int Next, int Last> struct is_homogeneous_impl; + +template<typename C,typename CMP, int Last> +struct is_homogeneous_impl<C,CMP,Last,Last> : mpl::true_{}; + +template<typename C,typename CMP, int Next, int Last> +struct is_homogeneous_impl : mpl::and_< is_homogeneous_impl< C, CMP,Next + 1, Last > + , is_same< CMP, typename mpl::at_c<C,Next>::type + > > {}; + +template < typename P > struct is_homogeneous : mpl::false_ {}; + +// pixel +template < typename C, typename L > struct is_homogeneous< pixel<C,L> > : mpl::true_ {}; +template < typename C, typename L > struct is_homogeneous<const pixel<C,L> > : mpl::true_ {}; +template < typename C, typename L > struct is_homogeneous< pixel<C,L>& > : mpl::true_ {}; +template < typename C, typename L > struct is_homogeneous<const pixel<C,L>& > : mpl::true_ {}; + +// planar pixel reference +template <typename Channel, typename ColorSpace> +struct is_homogeneous< planar_pixel_reference< Channel, ColorSpace > > : mpl::true_ {}; +template <typename Channel, typename ColorSpace> +struct is_homogeneous< const planar_pixel_reference< Channel, ColorSpace > > : mpl::true_ {}; + +template<typename C,typename CMP, int I,int Last> +struct is_homogeneous_impl_p {}; + +// for packed_pixel +template <typename B, typename C, typename L > +struct is_homogeneous<packed_pixel< B, C, L > > + : is_homogeneous_impl_p< C + , typename mpl::at_c< C, 0 >::type + , 1 + , mpl::size< C >::type::value + > {}; + +template< typename B + , typename C + , typename L + > +struct is_homogeneous< const packed_pixel< B, C, L > > + : is_homogeneous_impl_p< C + , typename mpl::at_c<C,0>::type + , 1 + , mpl::size< C >::type::value + > {}; + +// for bit_aligned_pixel_reference +template <typename B, typename C, typename L, bool M> +struct is_homogeneous<bit_aligned_pixel_reference<B,C,L,M> > + : is_homogeneous_impl<C,typename mpl::at_c<C,0>::type,1,mpl::size<C>::type::value> +{}; + +template <typename B, typename C, typename L, bool M> +struct is_homogeneous<const bit_aligned_pixel_reference<B,C,L,M> > + : is_homogeneous_impl<C,typename mpl::at_c<C,0>::type,1,mpl::size<C>::type::value> +{}; + +} // namespace gil +} // namespace boost + +#endif // BOOST_GIL_EXTENSION_TOOLBOX_METAFUNCTIONS_IS_HOMOGENEOUS_HPP diff --git a/boost/gil/extension/toolbox/metafunctions/is_similar.hpp b/boost/gil/extension/toolbox/metafunctions/is_similar.hpp new file mode 100644 index 0000000000..74af5c915d --- /dev/null +++ b/boost/gil/extension/toolbox/metafunctions/is_similar.hpp @@ -0,0 +1,43 @@ +/* + Copyright 2012 Christian Henning, Andreas Pokorny, 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_TOOLBOX_METAFUNCTIONS_IS_SIMILAR_HPP +#define BOOST_GIL_EXTENSION_TOOLBOX_METAFUNCTIONS_IS_SIMILAR_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file is_similar.hpp +/// \brief is_similar metafunction. +/// \author Christian Henning, Andreas Pokorny, Lubomir Bourdev \n +/// +/// \date 2012 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +#include <boost/gil/channel.hpp> + +namespace boost{ namespace gil { + +/// is_similar metafunctions +/// \brief Determines if two pixel types are similar. + +template< typename A, typename B > +struct is_similar : mpl::false_ {}; + +template<typename A> +struct is_similar< A, A > : mpl::true_ {}; + +template<typename B,int I, int S, bool M, int I2> +struct is_similar< packed_channel_reference< B, I, S, M > + , packed_channel_reference< B, I2, S, M > + > : mpl::true_ {}; + +} // namespace gil +} // namespace boost + +#endif // BOOST_GIL_EXTENSION_TOOLBOX_METAFUNCTIONS_IS_SIMILAR_HPP diff --git a/boost/gil/extension/toolbox/metafunctions/pixel_bit_size.hpp b/boost/gil/extension/toolbox/metafunctions/pixel_bit_size.hpp new file mode 100644 index 0000000000..cff9a49bb7 --- /dev/null +++ b/boost/gil/extension/toolbox/metafunctions/pixel_bit_size.hpp @@ -0,0 +1,55 @@ +/* + Copyright 2012 Christian Henning, Andreas Pokorny, 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_TOOLBOX_METAFUNCTIONS_PIXEL_BIT_SIZE_HPP +#define BOOST_GIL_EXTENSION_TOOLBOX_METAFUNCTIONS_PIXEL_BIT_SIZE_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file pixel_bit_size.hpp +/// \brief pixel_bit_size metafunction. +/// \author Christian Henning, Andreas Pokorny, Lubomir Bourdev \n +/// +/// \date 2012 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +#include <boost/mpl/int.hpp> +#include <boost/mpl/accumulate.hpp> + +#include <boost/gil/bit_aligned_pixel_reference.hpp> +#include <boost/gil/packed_pixel.hpp> + +namespace boost{ namespace gil { + +/// pixel_bit_size metafunctions +/// \brief Accumulates the all channel size. +/// +/// \code +/// typedef bit_aligned_image5_type< 16, 16, 16, 8, 8, devicen_layout_t< 5 > >::type image_t; +/// const int size = pixel_bit_size<image_t::view_t::reference>::value; +/// \endcode +template< typename PixelRef > +struct pixel_bit_size : mpl::int_<0> {}; + +template <typename B, typename C, typename L, bool M> +struct pixel_bit_size<bit_aligned_pixel_reference<B,C,L,M> > : mpl::int_< mpl::accumulate< C, mpl::int_<0>, mpl::plus<mpl::_1, mpl::_2> >::type::value >{}; + +template <typename B, typename C, typename L, bool M> +struct pixel_bit_size<const bit_aligned_pixel_reference<B,C,L,M> > : mpl::int_< mpl::accumulate< C, mpl::int_<0>, mpl::plus<mpl::_1, mpl::_2> >::type::value >{}; + +template <typename B, typename C, typename L> +struct pixel_bit_size<packed_pixel<B,C,L> > : mpl::int_< mpl::accumulate< C, mpl::int_<0>, mpl::plus<mpl::_1, mpl::_2> >::type::value >{}; + +template <typename B, typename C, typename L> +struct pixel_bit_size<const packed_pixel<B,C,L> > : mpl::int_< mpl::accumulate< C, mpl::int_<0>, mpl::plus<mpl::_1, mpl::_2> >::type::value >{}; + +} // namespace gil +} // namespace boost + +#endif // BOOST_GIL_EXTENSION_TOOLBOX_METAFUNCTIONS_PIXEL_BIT_SIZE_HPP diff --git a/boost/gil/extension/toolbox/toolbox.hpp b/boost/gil/extension/toolbox/toolbox.hpp new file mode 100644 index 0000000000..07f10736db --- /dev/null +++ b/boost/gil/extension/toolbox/toolbox.hpp @@ -0,0 +1,29 @@ +/* + Copyright 2012 Christian Henning + 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_TOOLBOX_TOOLBOX_HPP +#define BOOST_GIL_EXTENSION_TOOLBOX_TOOLBOX_HPP + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file toolbox.hpp +/// \brief Main header for toolbox extension. +/// \author Christian Henning \n +/// +/// \date 2012 \n +/// +//////////////////////////////////////////////////////////////////////////////////////// + +#include <boost/gil/extension/toolbox/color_converters.hpp> +#include <boost/gil/extension/toolbox/color_spaces.hpp> +#include <boost/gil/extension/toolbox/image_types.hpp> +#include <boost/gil/extension/toolbox/metafunctions.hpp> + +#include <boost/gil/extension/toolbox/dynamic_images.hpp> + +#endif // BOOST_GIL_EXTENSION_TOOLBOX_TOOLBOX_HPP |