feat():initial version
This commit is contained in:
@@ -0,0 +1,235 @@
|
||||
//
|
||||
// Copyright 2005-2007 Adobe Systems Incorporated
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
#ifndef BOOST_GIL_EXTENSION_DYNAMIC_IMAGE_ALGORITHM_HPP
|
||||
#define BOOST_GIL_EXTENSION_DYNAMIC_IMAGE_ALGORITHM_HPP
|
||||
|
||||
#include <boost/gil/extension/dynamic_image/any_image.hpp>
|
||||
|
||||
#include <boost/gil/algorithm.hpp>
|
||||
|
||||
#include <functional>
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// \file
|
||||
/// \brief Some basic STL-style algorithms when applied to runtime type specified image views
|
||||
/// \author Lubomir Bourdev and Hailin Jin \n
|
||||
/// Adobe Systems Incorporated
|
||||
/// \date 2005-2007 \n Last updated on September 24, 2006
|
||||
///
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace boost { namespace gil {
|
||||
|
||||
namespace detail {
|
||||
|
||||
struct equal_pixels_fn : binary_operation_obj<equal_pixels_fn, bool>
|
||||
{
|
||||
template <typename V1, typename V2>
|
||||
BOOST_FORCEINLINE
|
||||
bool apply_compatible(V1 const& v1, V2 const& v2) const
|
||||
{
|
||||
return equal_pixels(v1, v2);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/// \ingroup ImageViewSTLAlgorithmsEqualPixels
|
||||
/// \tparam Types Model Boost.MP11-compatible list of models of ImageViewConcept
|
||||
/// \tparam View Model MutableImageViewConcept
|
||||
template <typename ...Types, typename View>
|
||||
bool equal_pixels(any_image_view<Types...> const& src, View const& dst)
|
||||
{
|
||||
return apply_operation(
|
||||
src,
|
||||
std::bind(detail::equal_pixels_fn(), std::placeholders::_1, dst));
|
||||
}
|
||||
|
||||
/// \ingroup ImageViewSTLAlgorithmsEqualPixels
|
||||
/// \tparam View Model ImageViewConcept
|
||||
/// \tparam Types Model Boost.MP11-compatible list of models of MutableImageViewConcept
|
||||
template <typename View, typename ...Types>
|
||||
bool equal_pixels(View const& src, any_image_view<Types...> const& dst)
|
||||
{
|
||||
return apply_operation(
|
||||
dst,
|
||||
std::bind(detail::equal_pixels_fn(), src, std::placeholders::_1));
|
||||
}
|
||||
|
||||
/// \ingroup ImageViewSTLAlgorithmsEqualPixels
|
||||
/// \tparam Types1 Model Boost.MP11-compatible list of models of ImageViewConcept
|
||||
/// \tparam Types2 Model Boost.MP11-compatible list of models of MutableImageViewConcept
|
||||
template <typename ...Types1, typename ...Types2>
|
||||
bool equal_pixels(any_image_view<Types1...> const& src, any_image_view<Types2...> const& dst)
|
||||
{
|
||||
return apply_operation(src, dst, detail::equal_pixels_fn());
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
|
||||
struct copy_pixels_fn : public binary_operation_obj<copy_pixels_fn>
|
||||
{
|
||||
template <typename View1, typename View2>
|
||||
BOOST_FORCEINLINE
|
||||
void apply_compatible(View1 const& src, View2 const& dst) const
|
||||
{
|
||||
copy_pixels(src,dst);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/// \ingroup ImageViewSTLAlgorithmsCopyPixels
|
||||
/// \tparam Types Model Boost.MP11-compatible list of models of ImageViewConcept
|
||||
/// \tparam View Model MutableImageViewConcept
|
||||
template <typename ...Types, typename View>
|
||||
void copy_pixels(any_image_view<Types...> const& src, View const& dst)
|
||||
{
|
||||
apply_operation(src, std::bind(detail::copy_pixels_fn(), std::placeholders::_1, dst));
|
||||
}
|
||||
|
||||
/// \ingroup ImageViewSTLAlgorithmsCopyPixels
|
||||
/// \tparam Types Model Boost.MP11-compatible list of models of MutableImageViewConcept
|
||||
/// \tparam View Model ImageViewConcept
|
||||
template <typename ...Types, typename View>
|
||||
void copy_pixels(View const& src, any_image_view<Types...> const& dst)
|
||||
{
|
||||
apply_operation(dst, std::bind(detail::copy_pixels_fn(), src, std::placeholders::_1));
|
||||
}
|
||||
|
||||
/// \ingroup ImageViewSTLAlgorithmsCopyPixels
|
||||
/// \tparam Types1 Model Boost.MP11-compatible list of models of ImageViewConcept
|
||||
/// \tparam Types2 Model Boost.MP11-compatible list of models of MutableImageViewConcept
|
||||
template <typename ...Types1, typename ...Types2>
|
||||
void copy_pixels(any_image_view<Types1...> const& src, any_image_view<Types2...> const& dst)
|
||||
{
|
||||
apply_operation(src, dst, detail::copy_pixels_fn());
|
||||
}
|
||||
|
||||
//forward declaration for default_color_converter (see full definition in color_convert.hpp)
|
||||
struct default_color_converter;
|
||||
|
||||
/// \ingroup ImageViewSTLAlgorithmsCopyAndConvertPixels
|
||||
/// \tparam Types Model Boost.MP11-compatible list of models of ImageViewConcept
|
||||
/// \tparam View Model MutableImageViewConcept
|
||||
/// \tparam CC Model ColorConverterConcept
|
||||
template <typename ...Types, typename View, typename CC>
|
||||
void copy_and_convert_pixels(any_image_view<Types...> const& src, View const& dst, CC cc)
|
||||
{
|
||||
using cc_fn = detail::copy_and_convert_pixels_fn<CC>;
|
||||
apply_operation(src, std::bind(cc_fn{cc}, std::placeholders::_1, dst));
|
||||
}
|
||||
|
||||
/// \ingroup ImageViewSTLAlgorithmsCopyAndConvertPixels
|
||||
/// \tparam Types Model Boost.MP11-compatible list of models of ImageViewConcept
|
||||
/// \tparam View Model MutableImageViewConcept
|
||||
template <typename ...Types, typename View>
|
||||
void copy_and_convert_pixels(any_image_view<Types...> const& src, View const& dst)
|
||||
{
|
||||
using cc_fn = detail::copy_and_convert_pixels_fn<default_color_converter>;
|
||||
apply_operation(src, std::bind(cc_fn{}, std::placeholders::_1, dst));
|
||||
}
|
||||
|
||||
/// \ingroup ImageViewSTLAlgorithmsCopyAndConvertPixels
|
||||
/// \tparam View Model ImageViewConcept
|
||||
/// \tparam Types Model Boost.MP11-compatible list of models of MutableImageViewConcept
|
||||
/// \tparam CC Model ColorConverterConcept
|
||||
template <typename View, typename ...Types, typename CC>
|
||||
void copy_and_convert_pixels(View const& src, any_image_view<Types...> const& dst, CC cc)
|
||||
{
|
||||
using cc_fn = detail::copy_and_convert_pixels_fn<CC>;
|
||||
apply_operation(dst, std::bind(cc_fn{cc}, src, std::placeholders::_1));
|
||||
}
|
||||
|
||||
/// \ingroup ImageViewSTLAlgorithmsCopyAndConvertPixels
|
||||
/// \tparam View Model ImageViewConcept
|
||||
/// \tparam Type Model Boost.MP11-compatible list of models of MutableImageViewConcept
|
||||
template <typename View, typename ...Types>
|
||||
void copy_and_convert_pixels(View const& src, any_image_view<Types...> const& dst)
|
||||
{
|
||||
using cc_fn = detail::copy_and_convert_pixels_fn<default_color_converter>;
|
||||
apply_operation(dst, std::bind(cc_fn{}, src, std::placeholders::_1));
|
||||
}
|
||||
|
||||
/// \ingroup ImageViewSTLAlgorithmsCopyAndConvertPixels
|
||||
/// \tparam Types1 Model Boost.MP11-compatible list of models of ImageViewConcept
|
||||
/// \tparam Types2 Model Boost.MP11-compatible list of models of MutableImageViewConcept
|
||||
/// \tparam CC Model ColorConverterConcept
|
||||
template <typename ...Types1, typename ...Types2, typename CC>
|
||||
void copy_and_convert_pixels(
|
||||
any_image_view<Types1...> const& src,
|
||||
any_image_view<Types2...> const& dst, CC cc)
|
||||
{
|
||||
apply_operation(src, dst, detail::copy_and_convert_pixels_fn<CC>(cc));
|
||||
}
|
||||
|
||||
/// \ingroup ImageViewSTLAlgorithmsCopyAndConvertPixels
|
||||
/// \tparam Types1 Model Boost.MP11-compatible list of models of ImageViewConcept
|
||||
/// \tparam Types2 Model Boost.MP11-compatible list of models of MutableImageViewConcept
|
||||
template <typename ...Types1, typename ...Types2>
|
||||
void copy_and_convert_pixels(
|
||||
any_image_view<Types1...> const& src,
|
||||
any_image_view<Types2...> const& dst)
|
||||
{
|
||||
apply_operation(src, dst,
|
||||
detail::copy_and_convert_pixels_fn<default_color_converter>());
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <bool IsCompatible>
|
||||
struct fill_pixels_fn1
|
||||
{
|
||||
template <typename V, typename Value>
|
||||
static void apply(V const &src, Value const &val) { fill_pixels(src, val); }
|
||||
};
|
||||
|
||||
// copy_pixels invoked on incompatible images
|
||||
template <>
|
||||
struct fill_pixels_fn1<false>
|
||||
{
|
||||
template <typename V, typename Value>
|
||||
static void apply(V const &, Value const &) { throw std::bad_cast();}
|
||||
};
|
||||
|
||||
template <typename Value>
|
||||
struct fill_pixels_fn
|
||||
{
|
||||
fill_pixels_fn(Value const& val) : val_(val) {}
|
||||
|
||||
using result_type = void;
|
||||
template <typename V>
|
||||
result_type operator()(V const& view) const
|
||||
{
|
||||
fill_pixels_fn1
|
||||
<
|
||||
pixels_are_compatible
|
||||
<
|
||||
typename V::value_type,
|
||||
Value
|
||||
>::value
|
||||
>::apply(view, val_);
|
||||
}
|
||||
|
||||
Value val_;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/// \ingroup ImageViewSTLAlgorithmsFillPixels
|
||||
/// \brief fill_pixels for any image view. The pixel to fill with must be compatible with the current view
|
||||
/// \tparam Types Model Boost.MP11-compatible list of models of MutableImageViewConcept
|
||||
template <typename ...Types, typename Value>
|
||||
void fill_pixels(any_image_view<Types...> const& view, Value const& val)
|
||||
{
|
||||
apply_operation(view, detail::fill_pixels_fn<Value>(val));
|
||||
}
|
||||
|
||||
}} // namespace boost::gil
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,193 @@
|
||||
//
|
||||
// Copyright 2005-2007 Adobe Systems Incorporated
|
||||
// Copyright 2020 Samuel Debionne
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
#ifndef BOOST_GIL_EXTENSION_DYNAMIC_IMAGE_ANY_IMAGE_HPP
|
||||
#define BOOST_GIL_EXTENSION_DYNAMIC_IMAGE_ANY_IMAGE_HPP
|
||||
|
||||
#include <boost/gil/extension/dynamic_image/any_image_view.hpp>
|
||||
#include <boost/gil/extension/dynamic_image/apply_operation.hpp>
|
||||
|
||||
#include <boost/gil/image.hpp>
|
||||
#include <boost/gil/detail/mp11.hpp>
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/variant2/variant.hpp>
|
||||
|
||||
#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 {
|
||||
|
||||
template <typename T>
|
||||
using get_view_t = typename T::view_t;
|
||||
|
||||
template <typename Images>
|
||||
using images_get_views_t = mp11::mp_transform<get_view_t, Images>;
|
||||
|
||||
template <typename T>
|
||||
using get_const_view_t = typename T::const_view_t;
|
||||
|
||||
template <typename Images>
|
||||
using images_get_const_views_t = mp11::mp_transform<get_const_view_t, Images>;
|
||||
|
||||
struct recreate_image_fnobj
|
||||
{
|
||||
using result_type = void;
|
||||
point<std::ptrdiff_t> const& _dimensions;
|
||||
unsigned _alignment;
|
||||
|
||||
recreate_image_fnobj(point<std::ptrdiff_t> const& dims, unsigned alignment)
|
||||
: _dimensions(dims), _alignment(alignment)
|
||||
{}
|
||||
|
||||
template <typename Image>
|
||||
result_type operator()(Image& img) const { img.recreate(_dimensions,_alignment); }
|
||||
};
|
||||
|
||||
template <typename AnyView> // Models AnyViewConcept
|
||||
struct any_image_get_view
|
||||
{
|
||||
using result_type = AnyView;
|
||||
template <typename Image>
|
||||
result_type operator()(Image& img) const
|
||||
{
|
||||
return result_type(view(img));
|
||||
}
|
||||
};
|
||||
|
||||
template <typename AnyConstView> // Models AnyConstViewConcept
|
||||
struct any_image_get_const_view
|
||||
{
|
||||
using result_type = AnyConstView;
|
||||
template <typename Image>
|
||||
result_type operator()(Image const& img) const { return result_type{const_view(img)}; }
|
||||
};
|
||||
|
||||
} // namespce detail
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// \ingroup ImageModel
|
||||
/// \brief Represents a run-time specified image. Note it does NOT model ImageConcept
|
||||
///
|
||||
/// Represents an image whose type (color space, layout, planar/interleaved organization, etc) can be specified at run time.
|
||||
/// It is the runtime equivalent of \p image.
|
||||
/// Some of the requirements of ImageConcept, such as the \p value_type alias cannot be fulfilled, since the language does not allow runtime type specification.
|
||||
/// Other requirements, such as access to the pixels, would be inefficient to provide. Thus \p any_image does not fully model ImageConcept.
|
||||
/// In particular, its \p view and \p const_view methods return \p any_image_view, which does not fully model ImageViewConcept. See \p any_image_view for more.
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <typename ...Images>
|
||||
class any_image : public variant2::variant<Images...>
|
||||
{
|
||||
using parent_t = variant2::variant<Images...>;
|
||||
public:
|
||||
using view_t = mp11::mp_rename<detail::images_get_views_t<any_image>, any_image_view>;
|
||||
using const_view_t = mp11::mp_rename<detail::images_get_const_views_t<any_image>, any_image_view>;
|
||||
using x_coord_t = std::ptrdiff_t;
|
||||
using y_coord_t = std::ptrdiff_t;
|
||||
using point_t = point<std::ptrdiff_t>;
|
||||
|
||||
any_image() = default;
|
||||
any_image(any_image const& img) : parent_t((parent_t const&)img) {}
|
||||
|
||||
template <typename Image>
|
||||
explicit any_image(Image const& img) : parent_t(img) {}
|
||||
|
||||
template <typename Image>
|
||||
any_image(Image&& img) : parent_t(std::move(img)) {}
|
||||
|
||||
template <typename Image>
|
||||
explicit any_image(Image& img, bool do_swap) : parent_t(img, do_swap) {}
|
||||
|
||||
template <typename ...OtherImages>
|
||||
any_image(any_image<OtherImages...> const& img)
|
||||
: parent_t((variant2::variant<OtherImages...> const&)img)
|
||||
{}
|
||||
|
||||
any_image& operator=(any_image const& img)
|
||||
{
|
||||
parent_t::operator=((parent_t const&)img);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename Image>
|
||||
any_image& operator=(Image const& img)
|
||||
{
|
||||
parent_t::operator=(img);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename ...OtherImages>
|
||||
any_image& operator=(any_image<OtherImages...> const& img)
|
||||
{
|
||||
parent_t::operator=((typename variant2::variant<OtherImages...> const&)img);
|
||||
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({ width, height }, alignment);
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
x_coord_t width() const { return dimensions().x; }
|
||||
y_coord_t height() const { return dimensions().y; }
|
||||
};
|
||||
|
||||
///@{
|
||||
/// \name view, const_view
|
||||
/// \brief Get an image view from a run-time instantiated image
|
||||
|
||||
/// \ingroup ImageModel
|
||||
|
||||
/// \brief Returns the non-constant-pixel view of any image. The returned view is any view.
|
||||
/// \tparam Images Models ImageVectorConcept
|
||||
template <typename ...Images>
|
||||
BOOST_FORCEINLINE
|
||||
auto view(any_image<Images...>& img) -> typename any_image<Images...>::view_t
|
||||
{
|
||||
using view_t = typename any_image<Images...>::view_t;
|
||||
return apply_operation(img, detail::any_image_get_view<view_t>());
|
||||
}
|
||||
|
||||
/// \brief Returns the constant-pixel view of any image. The returned view is any view.
|
||||
/// \tparam Types Models ImageVectorConcept
|
||||
template <typename ...Images>
|
||||
BOOST_FORCEINLINE
|
||||
auto const_view(any_image<Images...> const& img) -> typename any_image<Images...>::const_view_t
|
||||
{
|
||||
using view_t = typename any_image<Images...>::const_view_t;
|
||||
return apply_operation(img, detail::any_image_get_const_view<view_t>());
|
||||
}
|
||||
///@}
|
||||
|
||||
}} // namespace boost::gil
|
||||
|
||||
#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,193 @@
|
||||
//
|
||||
// Copyright 2005-2007 Adobe Systems Incorporated
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
#ifndef BOOST_GIL_EXTENSION_DYNAMIC_IMAGE_ANY_IMAGE_VIEW_HPP
|
||||
#define BOOST_GIL_EXTENSION_DYNAMIC_IMAGE_ANY_IMAGE_VIEW_HPP
|
||||
|
||||
#include <boost/gil/dynamic_step.hpp>
|
||||
#include <boost/gil/image.hpp>
|
||||
#include <boost/gil/image_view.hpp>
|
||||
#include <boost/gil/point.hpp>
|
||||
#include <boost/gil/detail/mp11.hpp>
|
||||
|
||||
#include <boost/variant2/variant.hpp>
|
||||
|
||||
namespace boost { namespace gil {
|
||||
|
||||
template <typename View>
|
||||
struct dynamic_xy_step_transposed_type;
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename View>
|
||||
struct get_const_t { using type = typename View::const_t; };
|
||||
|
||||
template <typename Views>
|
||||
struct views_get_const_t : mp11::mp_transform<get_const_t, Views> {};
|
||||
|
||||
// works for both image_view and image
|
||||
struct any_type_get_num_channels
|
||||
{
|
||||
using result_type = int;
|
||||
template <typename T>
|
||||
result_type operator()(const T&) const { return num_channels<T>::value; }
|
||||
};
|
||||
|
||||
// works for both image_view and image
|
||||
struct any_type_get_dimensions
|
||||
{
|
||||
using result_type = point<std::ptrdiff_t>;
|
||||
template <typename T>
|
||||
result_type operator()(const T& v) const { return v.dimensions(); }
|
||||
};
|
||||
|
||||
// works for image_view
|
||||
struct any_type_get_size
|
||||
{
|
||||
using result_type = std::size_t;
|
||||
template <typename T>
|
||||
result_type operator()(const T& v) const { return v.size(); }
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// CLASS any_image_view
|
||||
///
|
||||
/// \ingroup ImageViewModel
|
||||
/// \brief Represents a run-time specified image view. Models HasDynamicXStepTypeConcept, HasDynamicYStepTypeConcept, Note that this class does NOT model ImageViewConcept
|
||||
///
|
||||
/// Represents a view whose type (color space, layout, planar/interleaved organization, etc) can be specified at run time.
|
||||
/// It is the runtime equivalent of \p image_view.
|
||||
/// Some of the requirements of ImageViewConcept, such as the \p value_type alias cannot be fulfilled, since the language does not allow runtime type specification.
|
||||
/// Other requirements, such as access to the pixels, would be inefficient to provide. Thus \p any_image_view does not fully model ImageViewConcept.
|
||||
/// However, many algorithms provide overloads taking runtime specified views and thus in many cases \p any_image_view can be used in places taking a view.
|
||||
///
|
||||
/// To perform an algorithm on any_image_view, put the algorithm in a function object and invoke it by calling \p apply_operation(runtime_view, algorithm_fn);
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <typename ...Views>
|
||||
class any_image_view : public variant2::variant<Views...>
|
||||
{
|
||||
using parent_t = variant2::variant<Views...>;
|
||||
|
||||
public:
|
||||
using const_t = detail::views_get_const_t<any_image_view>;
|
||||
using x_coord_t = std::ptrdiff_t;
|
||||
using y_coord_t = std::ptrdiff_t;
|
||||
using point_t = point<std::ptrdiff_t>;
|
||||
using size_type = std::size_t;
|
||||
|
||||
any_image_view() = default;
|
||||
any_image_view(any_image_view const& view) : parent_t((parent_t const&)view) {}
|
||||
|
||||
template <typename View>
|
||||
explicit any_image_view(View const& view) : parent_t(view) {}
|
||||
|
||||
template <typename ...OtherViews>
|
||||
any_image_view(any_image_view<OtherViews...> const& view)
|
||||
: parent_t((variant2::variant<OtherViews...> const&)view)
|
||||
{}
|
||||
|
||||
any_image_view& operator=(any_image_view const& view)
|
||||
{
|
||||
parent_t::operator=((parent_t const&)view);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename View>
|
||||
any_image_view& operator=(View const& view)
|
||||
{
|
||||
parent_t::operator=(view);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename ...OtherViews>
|
||||
any_image_view& operator=(any_image_view<OtherViews...> const& view)
|
||||
{
|
||||
parent_t::operator=((variant2::variant<OtherViews...> const&)view);
|
||||
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()); }
|
||||
size_type size() const { return apply_operation(*this, detail::any_type_get_size()); }
|
||||
x_coord_t width() const { return dimensions().x; }
|
||||
y_coord_t height() const { return dimensions().y; }
|
||||
};
|
||||
|
||||
/////////////////////////////
|
||||
// HasDynamicXStepTypeConcept
|
||||
/////////////////////////////
|
||||
|
||||
template <typename ...Views>
|
||||
struct dynamic_x_step_type<any_image_view<Views...>>
|
||||
{
|
||||
private:
|
||||
// FIXME: Remove class name injection with gil:: qualification
|
||||
// Required as workaround for Boost.MP11 issue that treats unqualified metafunction
|
||||
// in the class definition of the same name as the specialization (Peter Dimov):
|
||||
// invalid template argument for template parameter 'F', expected a class template
|
||||
template <typename T>
|
||||
using dynamic_step_view = typename gil::dynamic_x_step_type<T>::type;
|
||||
|
||||
public:
|
||||
using type = mp11::mp_transform<dynamic_step_view, any_image_view<Views...>>;
|
||||
};
|
||||
|
||||
/////////////////////////////
|
||||
// HasDynamicYStepTypeConcept
|
||||
/////////////////////////////
|
||||
|
||||
template <typename ...Views>
|
||||
struct dynamic_y_step_type<any_image_view<Views...>>
|
||||
{
|
||||
private:
|
||||
// FIXME: Remove class name injection with gil:: qualification
|
||||
// Required as workaround for Boost.MP11 issue that treats unqualified metafunction
|
||||
// in the class definition of the same name as the specialization (Peter Dimov):
|
||||
// invalid template argument for template parameter 'F', expected a class template
|
||||
template <typename T>
|
||||
using dynamic_step_view = typename gil::dynamic_y_step_type<T>::type;
|
||||
|
||||
public:
|
||||
using type = mp11::mp_transform<dynamic_step_view, any_image_view<Views...>>;
|
||||
};
|
||||
|
||||
template <typename ...Views>
|
||||
struct dynamic_xy_step_type<any_image_view<Views...>>
|
||||
{
|
||||
private:
|
||||
// FIXME: Remove class name injection with gil:: qualification
|
||||
// Required as workaround for Boost.MP11 issue that treats unqualified metafunction
|
||||
// in the class definition of the same name as the specialization (Peter Dimov):
|
||||
// invalid template argument for template parameter 'F', expected a class template
|
||||
template <typename T>
|
||||
using dynamic_step_view = typename gil::dynamic_xy_step_type<T>::type;
|
||||
|
||||
public:
|
||||
using type = mp11::mp_transform<dynamic_step_view, any_image_view<Views...>>;
|
||||
};
|
||||
|
||||
template <typename ...Views>
|
||||
struct dynamic_xy_step_transposed_type<any_image_view<Views...>>
|
||||
{
|
||||
private:
|
||||
// FIXME: Remove class name injection with gil:: qualification
|
||||
// Required as workaround for Boost.MP11 issue that treats unqualified metafunction
|
||||
// in the class definition of the same name as the specialization (Peter Dimov):
|
||||
// invalid template argument for template parameter 'F', expected a class template
|
||||
template <typename T>
|
||||
using dynamic_step_view = typename gil::dynamic_xy_step_type<T>::type;
|
||||
|
||||
public:
|
||||
using type = mp11::mp_transform<dynamic_step_view, any_image_view<Views...>>;
|
||||
};
|
||||
|
||||
}} // namespace boost::gil
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,41 @@
|
||||
//
|
||||
// Copyright 2005-2007 Adobe Systems Incorporated
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
#ifndef BOOST_GIL_EXTENSION_DYNAMIC_IMAGE_APPLY_OPERATION_HPP
|
||||
#define BOOST_GIL_EXTENSION_DYNAMIC_IMAGE_APPLY_OPERATION_HPP
|
||||
|
||||
#include <boost/variant2/variant.hpp>
|
||||
|
||||
namespace boost { namespace gil {
|
||||
|
||||
/// \ingroup Variant
|
||||
/// \brief Applies the visitor op to the variants
|
||||
template <typename Variant1, typename Visitor>
|
||||
BOOST_FORCEINLINE
|
||||
auto apply_operation(Variant1&& arg1, Visitor&& op)
|
||||
#if defined(BOOST_NO_CXX14_DECLTYPE_AUTO) || defined(BOOST_NO_CXX11_DECLTYPE_N3276)
|
||||
-> decltype(variant2::visit(std::forward<Visitor>(op), std::forward<Variant1>(arg1)))
|
||||
#endif
|
||||
{
|
||||
return variant2::visit(std::forward<Visitor>(op), std::forward<Variant1>(arg1));
|
||||
}
|
||||
|
||||
/// \ingroup Variant
|
||||
/// \brief Applies the visitor op to the variants
|
||||
template <typename Variant1, typename Variant2, typename Visitor>
|
||||
BOOST_FORCEINLINE
|
||||
auto apply_operation(Variant1&& arg1, Variant2&& arg2, Visitor&& op)
|
||||
#if defined(BOOST_NO_CXX14_DECLTYPE_AUTO) || defined(BOOST_NO_CXX11_DECLTYPE_N3276)
|
||||
-> decltype(variant2::visit(std::forward<Visitor>(op), std::forward<Variant1>(arg1), std::forward<Variant2>(arg2)))
|
||||
#endif
|
||||
{
|
||||
return variant2::visit(std::forward<Visitor>(op), std::forward<Variant1>(arg1), std::forward<Variant2>(arg2));
|
||||
}
|
||||
|
||||
}} // namespace boost::gil
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,119 @@
|
||||
//
|
||||
// Copyright 2005-2007 Adobe Systems Incorporated
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
#ifndef BOOST_GIL_EXTENSION_DYNAMIC_IMAGE_DYNAMIC_AT_C_HPP
|
||||
#define BOOST_GIL_EXTENSION_DYNAMIC_IMAGE_DYNAMIC_AT_C_HPP
|
||||
|
||||
#include <boost/gil/detail/mp11.hpp>
|
||||
|
||||
#include <boost/preprocessor/facilities/empty.hpp>
|
||||
#include <boost/preprocessor/repetition/repeat.hpp>
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
namespace boost { namespace gil {
|
||||
|
||||
// Constructs for static-to-dynamic integer convesion
|
||||
|
||||
#define BOOST_GIL_AT_C_VALUE(z, N, text) mp11::mp_at_c<IntTypes, S+N>::value,
|
||||
#define BOOST_GIL_DYNAMIC_AT_C_LIMIT 226 // size of the maximum vector to handle
|
||||
|
||||
#define BOOST_GIL_AT_C_LOOKUP(z, NUM, text) \
|
||||
template<std::size_t S> \
|
||||
struct at_c_fn<S,NUM> { \
|
||||
template <typename IntTypes, typename ValueType> inline \
|
||||
static ValueType apply(std::size_t index) { \
|
||||
static ValueType table[] = { \
|
||||
BOOST_PP_REPEAT(NUM, BOOST_GIL_AT_C_VALUE, BOOST_PP_EMPTY) \
|
||||
}; \
|
||||
return table[index]; \
|
||||
} \
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
namespace at_c {
|
||||
template <std::size_t START, std::size_t NUM> struct at_c_fn;
|
||||
BOOST_PP_REPEAT(BOOST_GIL_DYNAMIC_AT_C_LIMIT, BOOST_GIL_AT_C_LOOKUP, BOOST_PP_EMPTY)
|
||||
|
||||
template <std::size_t QUOT> struct at_c_impl;
|
||||
|
||||
template <>
|
||||
struct at_c_impl<0> {
|
||||
template <typename IntTypes, typename ValueType> inline
|
||||
static ValueType apply(std::size_t index) {
|
||||
return at_c_fn<0, mp11::mp_size<IntTypes>::value>::template apply<IntTypes,ValueType>(index);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct at_c_impl<1> {
|
||||
template <typename IntTypes, typename ValueType> inline
|
||||
static ValueType apply(std::size_t index) {
|
||||
const std::size_t SIZE = mp11::mp_size<IntTypes>::value;
|
||||
const std::size_t REM = SIZE % BOOST_GIL_DYNAMIC_AT_C_LIMIT;
|
||||
switch (index / BOOST_GIL_DYNAMIC_AT_C_LIMIT) {
|
||||
case 0: return at_c_fn<0 ,BOOST_GIL_DYNAMIC_AT_C_LIMIT-1>::template apply<IntTypes,ValueType>(index);
|
||||
case 1: return at_c_fn<BOOST_GIL_DYNAMIC_AT_C_LIMIT ,REM >::template apply<IntTypes,ValueType>(index - BOOST_GIL_DYNAMIC_AT_C_LIMIT);
|
||||
};
|
||||
throw;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct at_c_impl<2> {
|
||||
template <typename IntTypes, typename ValueType> inline
|
||||
static ValueType apply(std::size_t index) {
|
||||
const std::size_t SIZE = mp11::mp_size<IntTypes>::value;
|
||||
const std::size_t REM = SIZE % BOOST_GIL_DYNAMIC_AT_C_LIMIT;
|
||||
switch (index / BOOST_GIL_DYNAMIC_AT_C_LIMIT) {
|
||||
case 0: return at_c_fn<0 ,BOOST_GIL_DYNAMIC_AT_C_LIMIT-1>::template apply<IntTypes,ValueType>(index);
|
||||
case 1: return at_c_fn<BOOST_GIL_DYNAMIC_AT_C_LIMIT ,BOOST_GIL_DYNAMIC_AT_C_LIMIT-1>::template apply<IntTypes,ValueType>(index - BOOST_GIL_DYNAMIC_AT_C_LIMIT);
|
||||
case 2: return at_c_fn<BOOST_GIL_DYNAMIC_AT_C_LIMIT*2,REM >::template apply<IntTypes,ValueType>(index - BOOST_GIL_DYNAMIC_AT_C_LIMIT*2);
|
||||
};
|
||||
throw;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct at_c_impl<3> {
|
||||
template <typename IntTypes, typename ValueType> inline
|
||||
static ValueType apply(std::size_t index) {
|
||||
const std::size_t SIZE = mp11::mp_size<IntTypes>::value;
|
||||
const std::size_t REM = SIZE % BOOST_GIL_DYNAMIC_AT_C_LIMIT;
|
||||
switch (index / BOOST_GIL_DYNAMIC_AT_C_LIMIT) {
|
||||
case 0: return at_c_fn<0 ,BOOST_GIL_DYNAMIC_AT_C_LIMIT-1>::template apply<IntTypes,ValueType>(index);
|
||||
case 1: return at_c_fn<BOOST_GIL_DYNAMIC_AT_C_LIMIT ,BOOST_GIL_DYNAMIC_AT_C_LIMIT-1>::template apply<IntTypes,ValueType>(index - BOOST_GIL_DYNAMIC_AT_C_LIMIT);
|
||||
case 2: return at_c_fn<BOOST_GIL_DYNAMIC_AT_C_LIMIT*2,BOOST_GIL_DYNAMIC_AT_C_LIMIT-1>::template apply<IntTypes,ValueType>(index - BOOST_GIL_DYNAMIC_AT_C_LIMIT*2);
|
||||
case 3: return at_c_fn<BOOST_GIL_DYNAMIC_AT_C_LIMIT*3,REM >::template apply<IntTypes,ValueType>(index - BOOST_GIL_DYNAMIC_AT_C_LIMIT*3);
|
||||
};
|
||||
throw;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////
|
||||
///
|
||||
/// \brief Given an Boost.MP11-compatible list and a dynamic index n,
|
||||
/// returns the value of the n-th element.
|
||||
/// It constructs a lookup table at compile time.
|
||||
///
|
||||
////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <typename IntTypes, typename ValueType> inline
|
||||
ValueType at_c(std::size_t index) {
|
||||
const std::size_t Size=mp11::mp_size<IntTypes>::value;
|
||||
return detail::at_c::at_c_impl<Size/BOOST_GIL_DYNAMIC_AT_C_LIMIT>::template apply<IntTypes,ValueType>(index);
|
||||
}
|
||||
|
||||
#undef BOOST_GIL_AT_C_VALUE
|
||||
#undef BOOST_GIL_DYNAMIC_AT_C_LIMIT
|
||||
#undef BOOST_GIL_AT_C_LOOKUP
|
||||
|
||||
}} // namespace boost::gil
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// Copyright 2005-2007 Adobe Systems Incorporated
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
#ifndef BOOST_GIL_EXTENSION_DYNAMIC_IMAGE_DYNAMIC_IMAGE_ALL_HPP
|
||||
#define BOOST_GIL_EXTENSION_DYNAMIC_IMAGE_DYNAMIC_IMAGE_ALL_HPP
|
||||
|
||||
#include <boost/gil/extension/dynamic_image/algorithm.hpp>
|
||||
#include <boost/gil/extension/dynamic_image/any_image.hpp>
|
||||
#include <boost/gil/extension/dynamic_image/apply_operation.hpp>
|
||||
#include <boost/gil/extension/dynamic_image/image_view_factory.hpp>
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,407 @@
|
||||
//
|
||||
// Copyright 2005-2007 Adobe Systems Incorporated
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
#ifndef BOOST_GIL_EXTENSION_DYNAMIC_IMAGE_IMAGE_VIEW_FACTORY_HPP
|
||||
#define BOOST_GIL_EXTENSION_DYNAMIC_IMAGE_IMAGE_VIEW_FACTORY_HPP
|
||||
|
||||
#include <boost/gil/extension/dynamic_image/any_image_view.hpp>
|
||||
|
||||
#include <boost/gil/dynamic_step.hpp>
|
||||
#include <boost/gil/image_view_factory.hpp>
|
||||
#include <boost/gil/point.hpp>
|
||||
#include <boost/gil/detail/mp11.hpp>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace boost { namespace gil {
|
||||
|
||||
// Methods for constructing any image views from other any image views
|
||||
// Extends image view factory to runtime type-specified views (any_image_view)
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename ResultView>
|
||||
struct flipped_up_down_view_fn
|
||||
{
|
||||
using result_type = ResultView;
|
||||
|
||||
template <typename View>
|
||||
auto operator()(View const& src) const -> result_type
|
||||
{
|
||||
return result_type{flipped_up_down_view(src)};
|
||||
}
|
||||
};
|
||||
|
||||
template <typename ResultView>
|
||||
struct flipped_left_right_view_fn
|
||||
{
|
||||
using result_type = ResultView;
|
||||
|
||||
template <typename View>
|
||||
auto operator()(View const& src) const -> result_type
|
||||
{
|
||||
return result_type{flipped_left_right_view(src)};
|
||||
}
|
||||
};
|
||||
|
||||
template <typename ResultView>
|
||||
struct rotated90cw_view_fn
|
||||
{
|
||||
using result_type = ResultView;
|
||||
|
||||
template <typename View>
|
||||
auto operator()(View const& src) const -> result_type
|
||||
{
|
||||
return result_type{rotated90cw_view(src)};
|
||||
}
|
||||
};
|
||||
|
||||
template <typename ResultView>
|
||||
struct rotated90ccw_view_fn
|
||||
{
|
||||
using result_type = ResultView;
|
||||
|
||||
template <typename View>
|
||||
auto operator()(View const& src) const -> result_type
|
||||
{
|
||||
return result_type{rotated90ccw_view(src)};
|
||||
}
|
||||
};
|
||||
|
||||
template <typename ResultView>
|
||||
struct tranposed_view_fn
|
||||
{
|
||||
using result_type = ResultView;
|
||||
|
||||
template <typename View>
|
||||
auto operator()(View const& src) const -> result_type
|
||||
{
|
||||
return result_type{tranposed_view(src)};
|
||||
}
|
||||
};
|
||||
|
||||
template <typename ResultView>
|
||||
struct rotated180_view_fn
|
||||
{
|
||||
using result_type = ResultView;
|
||||
|
||||
template <typename View>
|
||||
auto operator()(View const& src) const -> result_type
|
||||
{
|
||||
return result_type{rotated180_view(src)};
|
||||
}
|
||||
};
|
||||
|
||||
template <typename ResultView>
|
||||
struct subimage_view_fn
|
||||
{
|
||||
using result_type = ResultView;
|
||||
|
||||
subimage_view_fn(point_t const& topleft, point_t const& dimensions)
|
||||
: _topleft(topleft), _size2(dimensions)
|
||||
{}
|
||||
|
||||
template <typename View>
|
||||
auto operator()(View const& src) const -> result_type
|
||||
{
|
||||
return result_type{subimage_view(src,_topleft,_size2)};
|
||||
}
|
||||
|
||||
point_t _topleft;
|
||||
point_t _size2;
|
||||
};
|
||||
|
||||
template <typename ResultView>
|
||||
struct subsampled_view_fn
|
||||
{
|
||||
using result_type = ResultView;
|
||||
|
||||
subsampled_view_fn(point_t const& step) : _step(step) {}
|
||||
|
||||
template <typename View>
|
||||
auto operator()(View const& src) const -> result_type
|
||||
{
|
||||
return result_type{subsampled_view(src,_step)};
|
||||
}
|
||||
|
||||
point_t _step;
|
||||
};
|
||||
|
||||
template <typename ResultView>
|
||||
struct nth_channel_view_fn
|
||||
{
|
||||
using result_type = ResultView;
|
||||
|
||||
nth_channel_view_fn(int n) : _n(n) {}
|
||||
|
||||
template <typename View>
|
||||
auto operator()(View const& src) const -> result_type
|
||||
{
|
||||
return result_type(nth_channel_view(src,_n));
|
||||
}
|
||||
|
||||
int _n;
|
||||
};
|
||||
|
||||
template <typename DstP, typename ResultView, typename CC = default_color_converter>
|
||||
struct color_converted_view_fn
|
||||
{
|
||||
using result_type = ResultView;
|
||||
|
||||
color_converted_view_fn(CC cc = CC()): _cc(cc) {}
|
||||
|
||||
template <typename View>
|
||||
auto operator()(View const& src) const -> result_type
|
||||
{
|
||||
return result_type{color_converted_view<DstP>(src, _cc)};
|
||||
}
|
||||
|
||||
private:
|
||||
CC _cc;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/// \ingroup ImageViewTransformationsFlipUD
|
||||
/// \tparam Views Models Boost.MP11-compatible list of models of ImageViewConcept
|
||||
template <typename ...Views>
|
||||
inline
|
||||
auto flipped_up_down_view(any_image_view<Views...> const& src)
|
||||
-> typename dynamic_y_step_type<any_image_view<Views...>>::type
|
||||
{
|
||||
using result_view_t = typename dynamic_y_step_type<any_image_view<Views...>>::type;
|
||||
return apply_operation(src, detail::flipped_up_down_view_fn<result_view_t>());
|
||||
}
|
||||
|
||||
/// \ingroup ImageViewTransformationsFlipLR
|
||||
/// \tparam Views Models Boost.MP11-compatible list of models of ImageViewConcept
|
||||
template <typename ...Views>
|
||||
inline
|
||||
auto flipped_left_right_view(any_image_view<Views...> const& src)
|
||||
-> typename dynamic_x_step_type<any_image_view<Views...>>::type
|
||||
{
|
||||
using result_view_t = typename dynamic_x_step_type<any_image_view<Views...>>::type;
|
||||
return apply_operation(src, detail::flipped_left_right_view_fn<result_view_t>());
|
||||
}
|
||||
|
||||
/// \ingroup ImageViewTransformationsTransposed
|
||||
/// \tparam Views Models Boost.MP11-compatible list of models of ImageViewConcept
|
||||
template <typename ...Views>
|
||||
inline
|
||||
auto transposed_view(const any_image_view<Views...>& src)
|
||||
-> typename dynamic_xy_step_transposed_type<any_image_view<Views...>>::type
|
||||
{
|
||||
using result_view_t = typename dynamic_xy_step_transposed_type<any_image_view<Views...>>::type;
|
||||
return apply_operation(src, detail::tranposed_view_fn<result_view_t>());
|
||||
}
|
||||
|
||||
/// \ingroup ImageViewTransformations90CW
|
||||
/// \tparam Views Models Boost.MP11-compatible list of models of ImageViewConcept
|
||||
template <typename ...Views>
|
||||
inline
|
||||
auto rotated90cw_view(const any_image_view<Views...>& src)
|
||||
-> typename dynamic_xy_step_transposed_type<any_image_view<Views...>>::type
|
||||
{
|
||||
using result_view_t = typename dynamic_xy_step_transposed_type<any_image_view<Views...>>::type;
|
||||
return apply_operation(src,detail::rotated90cw_view_fn<result_view_t>());
|
||||
}
|
||||
|
||||
/// \ingroup ImageViewTransformations90CCW
|
||||
/// \tparam Views Models Boost.MP11-compatible list of models of ImageViewConcept
|
||||
template <typename ...Views>
|
||||
inline
|
||||
auto rotated90ccw_view(const any_image_view<Views...>& src)
|
||||
-> typename dynamic_xy_step_transposed_type<any_image_view<Views...>>::type
|
||||
{
|
||||
return apply_operation(src,detail::rotated90ccw_view_fn<typename dynamic_xy_step_transposed_type<any_image_view<Views...>>::type>());
|
||||
}
|
||||
|
||||
/// \ingroup ImageViewTransformations180
|
||||
/// \tparam Views Models Boost.MP11-compatible list of models of ImageViewConcept
|
||||
template <typename ...Views>
|
||||
inline
|
||||
auto rotated180_view(any_image_view<Views...> const& src)
|
||||
-> typename dynamic_xy_step_type<any_image_view<Views...>>::type
|
||||
{
|
||||
using step_type = typename dynamic_xy_step_type<any_image_view<Views...>>::type;
|
||||
return apply_operation(src, detail::rotated180_view_fn<step_type>());
|
||||
}
|
||||
|
||||
/// \ingroup ImageViewTransformationsSubimage
|
||||
/// \tparam Views Models Boost.MP11-compatible list of models of ImageViewConcept
|
||||
template <typename ...Views>
|
||||
inline
|
||||
auto subimage_view(
|
||||
any_image_view<Views...> const& src,
|
||||
point_t const& topleft,
|
||||
point_t const& dimensions)
|
||||
-> any_image_view<Views...>
|
||||
{
|
||||
using subimage_view_fn = detail::subimage_view_fn<any_image_view<Views...>>;
|
||||
return apply_operation(src, subimage_view_fn(topleft, dimensions));
|
||||
}
|
||||
|
||||
/// \ingroup ImageViewTransformationsSubimage
|
||||
/// \tparam Views Models Boost.MP11-compatible list of models of ImageViewConcept
|
||||
template <typename ...Views>
|
||||
inline
|
||||
auto subimage_view(
|
||||
any_image_view<Views...> const& src,
|
||||
std::ptrdiff_t x_min, std::ptrdiff_t y_min, std::ptrdiff_t width, std::ptrdiff_t height)
|
||||
-> any_image_view<Views...>
|
||||
{
|
||||
using subimage_view_fn = detail::subimage_view_fn<any_image_view<Views...>>;
|
||||
return apply_operation(src, subimage_view_fn(point_t(x_min, y_min),point_t(width, height)));
|
||||
}
|
||||
|
||||
/// \ingroup ImageViewTransformationsSubsampled
|
||||
/// \tparam Views Models Boost.MP11-compatible list of models of ImageViewConcept
|
||||
template <typename ...Views>
|
||||
inline
|
||||
auto subsampled_view(any_image_view<Views...> const& src, point_t const& step)
|
||||
-> typename dynamic_xy_step_type<any_image_view<Views...>>::type
|
||||
{
|
||||
using step_type = typename dynamic_xy_step_type<any_image_view<Views...>>::type;
|
||||
using subsampled_view = detail::subsampled_view_fn<step_type>;
|
||||
return apply_operation(src, subsampled_view(step));
|
||||
}
|
||||
|
||||
/// \ingroup ImageViewTransformationsSubsampled
|
||||
/// \tparam Views Models Boost.MP11-compatible list of models of ImageViewConcept
|
||||
template <typename ...Views>
|
||||
inline
|
||||
auto subsampled_view(any_image_view<Views...> const& src, std::ptrdiff_t x_step, std::ptrdiff_t y_step)
|
||||
-> typename dynamic_xy_step_type<any_image_view<Views...>>::type
|
||||
{
|
||||
using step_type = typename dynamic_xy_step_type<any_image_view<Views...>>::type;
|
||||
using subsampled_view_fn = detail::subsampled_view_fn<step_type>;
|
||||
return apply_operation(src, subsampled_view_fn(point_t(x_step, y_step)));
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename View>
|
||||
struct get_nthchannel_type { using type = typename nth_channel_view_type<View>::type; };
|
||||
|
||||
template <typename Views>
|
||||
struct views_get_nthchannel_type : mp11::mp_transform<get_nthchannel_type, Views> {};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/// \ingroup ImageViewTransformationsNthChannel
|
||||
/// \brief Given a runtime source image view, returns the type of a runtime image view over a single channel of the source view
|
||||
template <typename ...Views>
|
||||
struct nth_channel_view_type<any_image_view<Views...>>
|
||||
{
|
||||
using type = typename detail::views_get_nthchannel_type<any_image_view<Views...>>;
|
||||
};
|
||||
|
||||
/// \ingroup ImageViewTransformationsNthChannel
|
||||
/// \tparam Views Models Boost.MP11-compatible list of models of ImageViewConcept
|
||||
template <typename ...Views>
|
||||
inline
|
||||
auto nth_channel_view(const any_image_view<Views...>& src, int n)
|
||||
-> typename nth_channel_view_type<any_image_view<Views...>>::type
|
||||
{
|
||||
using result_view_t = typename nth_channel_view_type<any_image_view<Views...>>::type;
|
||||
return apply_operation(src,detail::nth_channel_view_fn<result_view_t>(n));
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename View, typename DstP, typename CC>
|
||||
struct get_ccv_type : color_converted_view_type<View, DstP, CC> {};
|
||||
|
||||
template <typename Views, typename DstP, typename CC>
|
||||
struct views_get_ccv_type
|
||||
{
|
||||
private:
|
||||
// FIXME: Remove class name injection with detail:: qualification
|
||||
// Required as workaround for MP11 issue that treats unqualified metafunction
|
||||
// in the class definition of the same name as the specialization (Peter Dimov):
|
||||
// invalid template argument for template parameter 'F', expected a class template
|
||||
template <typename T>
|
||||
using ccvt = detail::get_ccv_type<T, DstP, CC>;
|
||||
|
||||
public:
|
||||
using type = mp11::mp_transform<ccvt, Views>;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/// \ingroup ImageViewTransformationsColorConvert
|
||||
/// \brief Returns the type of a runtime-specified view, color-converted to a given pixel type with user specified color converter
|
||||
template <typename ...Views, typename DstP, typename CC>
|
||||
struct color_converted_view_type<any_image_view<Views...>,DstP,CC>
|
||||
{
|
||||
//using type = any_image_view<typename detail::views_get_ccv_type<Views, DstP, CC>::type>;
|
||||
using type = detail::views_get_ccv_type<any_image_view<Views...>, DstP, CC>;
|
||||
};
|
||||
|
||||
/// \ingroup ImageViewTransformationsColorConvert
|
||||
/// \brief overload of generic color_converted_view with user defined color-converter
|
||||
/// \tparam Views Models Boost.MP11-compatible list of models of ImageViewConcept
|
||||
template <typename DstP, typename ...Views, typename CC>
|
||||
inline
|
||||
auto color_converted_view(const any_image_view<Views...>& src, CC)
|
||||
-> typename color_converted_view_type<any_image_view<Views...>, DstP, CC>::type
|
||||
{
|
||||
using cc_view_t = typename color_converted_view_type<any_image_view<Views...>, DstP, CC>::type;
|
||||
return apply_operation(src, detail::color_converted_view_fn<DstP, cc_view_t>());
|
||||
}
|
||||
|
||||
/// \ingroup ImageViewTransformationsColorConvert
|
||||
/// \brief Returns the type of a runtime-specified view, color-converted to a given pixel type with the default coor converter
|
||||
template <typename ...Views, typename DstP>
|
||||
struct color_converted_view_type<any_image_view<Views...>,DstP>
|
||||
{
|
||||
using type = detail::views_get_ccv_type<any_image_view<Views...>, DstP, default_color_converter>;
|
||||
};
|
||||
|
||||
/// \ingroup ImageViewTransformationsColorConvert
|
||||
/// \brief overload of generic color_converted_view with the default color-converter
|
||||
/// \tparam Views Models Boost.MP11-compatible list of models of ImageViewConcept
|
||||
template <typename DstP, typename ...Views>
|
||||
inline
|
||||
auto color_converted_view(any_image_view<Views...> const& src)
|
||||
-> typename color_converted_view_type<any_image_view<Views...>, DstP>::type
|
||||
{
|
||||
using cc_view_t = typename color_converted_view_type<any_image_view<Views...>, DstP>::type;
|
||||
return apply_operation(src, detail::color_converted_view_fn<DstP, cc_view_t>());
|
||||
}
|
||||
|
||||
/// \ingroup ImageViewTransformationsColorConvert
|
||||
/// \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)
|
||||
/// \tparam Views Models Boost.MP11-compatible list of models of ImageViewConcept
|
||||
template <typename DstP, typename ...Views, typename CC>
|
||||
inline
|
||||
auto any_color_converted_view(const any_image_view<Views...>& src, CC)
|
||||
-> typename color_converted_view_type<any_image_view<Views...>, DstP, CC>::type
|
||||
{
|
||||
using cc_view_t = typename color_converted_view_type<any_image_view<Views...>, DstP, CC>::type;
|
||||
return apply_operation(src, detail::color_converted_view_fn<DstP, cc_view_t>());
|
||||
}
|
||||
|
||||
/// \ingroup ImageViewTransformationsColorConvert
|
||||
/// \brief overload of generic color_converted_view with the default 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)
|
||||
/// \tparam Views Models Boost.MP11-compatible list of models of ImageViewConcept
|
||||
template <typename DstP, typename ...Views>
|
||||
inline
|
||||
auto any_color_converted_view(const any_image_view<Views...>& src)
|
||||
-> typename color_converted_view_type<any_image_view<Views...>, DstP>::type
|
||||
{
|
||||
using cc_view_t = typename color_converted_view_type<any_image_view<Views...>, DstP>::type;
|
||||
return apply_operation(src, detail::color_converted_view_fn<DstP, cc_view_t>());
|
||||
}
|
||||
|
||||
/// \}
|
||||
|
||||
}} // namespace boost::gil
|
||||
|
||||
#endif
|
||||
14
install/boost_1_75_0/include/boost/gil/extension/io/bmp.hpp
Normal file
14
install/boost_1_75_0/include/boost/gil/extension/io/bmp.hpp
Normal file
@@ -0,0 +1,14 @@
|
||||
//
|
||||
// Copyright 2008 Christian Henning
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
#ifndef BOOST_GIL_EXTENSION_IO_BMP_HPP
|
||||
#define BOOST_GIL_EXTENSION_IO_BMP_HPP
|
||||
|
||||
#include <boost/gil/extension/io/bmp/read.hpp>
|
||||
#include <boost/gil/extension/io/bmp/write.hpp>
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,86 @@
|
||||
//
|
||||
// Copyright 2009 Christian Henning
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
#ifndef BOOST_GIL_EXTENSION_IO_BMP_DETAIL_IS_ALLOWED_HPP
|
||||
#define BOOST_GIL_EXTENSION_IO_BMP_DETAIL_IS_ALLOWED_HPP
|
||||
|
||||
#include <boost/gil/extension/io/bmp/tags.hpp>
|
||||
#include <boost/gil/channel.hpp>
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
namespace boost { namespace gil { namespace detail {
|
||||
|
||||
template< typename View >
|
||||
bool is_allowed( const image_read_info< bmp_tag >& info
|
||||
, std::true_type // 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." );
|
||||
}
|
||||
}
|
||||
|
||||
using channel_t = typename channel_traits<typename element_type<typename View::value_type>::type>::value_type;
|
||||
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 */
|
||||
, std::false_type // is read_and_convert
|
||||
)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
} // namespace gil
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,742 @@
|
||||
//
|
||||
// Copyright 2012 Christian Henning
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
#ifndef BOOST_GIL_EXTENSION_IO_BMP_DETAIL_READ_HPP
|
||||
#define BOOST_GIL_EXTENSION_IO_BMP_DETAIL_READ_HPP
|
||||
|
||||
#include <boost/gil/extension/io/bmp/detail/is_allowed.hpp>
|
||||
#include <boost/gil/extension/io/bmp/detail/reader_backend.hpp>
|
||||
|
||||
#include <boost/gil/io/base.hpp>
|
||||
#include <boost/gil/io/bit_operations.hpp>
|
||||
#include <boost/gil/io/conversion_policies.hpp>
|
||||
#include <boost/gil/io/device.hpp>
|
||||
#include <boost/gil/io/dynamic_io_new.hpp>
|
||||
#include <boost/gil/io/reader_base.hpp>
|
||||
#include <boost/gil/io/row_buffer_helper.hpp>
|
||||
#include <boost/gil/io/typedefs.hpp>
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
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:
|
||||
|
||||
using this_t = reader<Device, bmp_tag, ConversionPolicy>;
|
||||
using cc_t = typename ConversionPolicy::color_converter_type;
|
||||
|
||||
public:
|
||||
|
||||
using backend_t = reader_backend< Device, bmp_tag>;
|
||||
|
||||
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." );
|
||||
}
|
||||
|
||||
using is_read_and_convert_t = typename std::is_same
|
||||
<
|
||||
ConversionPolicy,
|
||||
detail::read_and_no_convert
|
||||
>::type;
|
||||
|
||||
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, std::true_type>
|
||||
>(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, std::true_type>
|
||||
>(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();
|
||||
|
||||
using rh_t = detail::row_buffer_helper_view<View_Src>;
|
||||
using it_t = typename rh_t::iterator_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" );
|
||||
}
|
||||
|
||||
using image_t = rgb8_image_t;
|
||||
using it_t = typename image_t::view_t::x_iterator;
|
||||
|
||||
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 )
|
||||
{
|
||||
BOOST_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;
|
||||
|
||||
using Buf_type = std::vector<rgba8_pixel_t>;
|
||||
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
|
||||
>
|
||||
{
|
||||
using parent_t = reader<Device, bmp_tag, detail::read_and_no_convert>;
|
||||
|
||||
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
|
||||
@@ -0,0 +1,247 @@
|
||||
//
|
||||
// Copyright 2012 Christian Henning
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
#ifndef BOOST_GIL_EXTENSION_IO_BMP_DETAIL_READER_BACKEND_HPP
|
||||
#define BOOST_GIL_EXTENSION_IO_BMP_DETAIL_READER_BACKEND_HPP
|
||||
|
||||
#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:
|
||||
|
||||
using format_tag_t = bmp_tag;
|
||||
|
||||
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
|
||||
@@ -0,0 +1,414 @@
|
||||
//
|
||||
// Copyright 2008 Christian Henning
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
#ifndef BOOST_GIL_EXTENSION_IO_BMP_DETAIL_SCANLINE_READ_HPP
|
||||
#define BOOST_GIL_EXTENSION_IO_BMP_DETAIL_SCANLINE_READ_HPP
|
||||
|
||||
#include <boost/gil/extension/io/bmp/detail/is_allowed.hpp>
|
||||
#include <boost/gil/extension/io/bmp/detail/reader_backend.hpp>
|
||||
|
||||
#include <boost/gil/io/base.hpp>
|
||||
#include <boost/gil/io/bit_operations.hpp>
|
||||
#include <boost/gil/io/conversion_policies.hpp>
|
||||
#include <boost/gil/io/device.hpp>
|
||||
#include <boost/gil/io/reader_base.hpp>
|
||||
#include <boost/gil/io/row_buffer_helper.hpp>
|
||||
#include <boost/gil/io/scanline_read_iterator.hpp>
|
||||
#include <boost/gil/io/typedefs.hpp>
|
||||
|
||||
#include <functional>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
namespace boost { namespace gil {
|
||||
|
||||
///
|
||||
/// BMP Scanline Reader
|
||||
///
|
||||
template< typename Device >
|
||||
class scanline_reader< Device
|
||||
, bmp_tag
|
||||
>
|
||||
: public reader_backend< Device
|
||||
, bmp_tag
|
||||
>
|
||||
{
|
||||
public:
|
||||
|
||||
using tag_t = bmp_tag;
|
||||
using backend_t = reader_backend<Device, tag_t>;
|
||||
using this_t = scanline_reader<Device, tag_t>;
|
||||
using iterator_t = scanline_read_iterator<this_t>;
|
||||
|
||||
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 = std::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 = std::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 = std::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 = std::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 = std::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 = std::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 )
|
||||
{
|
||||
using src_view_t = View;
|
||||
using dst_view_t = rgba8_image_t::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 )
|
||||
{
|
||||
using dst_view_t = rgb8_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>, std::true_type> _mirror_bits;
|
||||
detail::swap_half_bytes<std::vector<byte_t>, std::true_type> _swap_half_bytes;
|
||||
|
||||
std::function<void(this_t*, byte_t*)> _read_function;
|
||||
};
|
||||
|
||||
} // namespace gil
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,145 @@
|
||||
//
|
||||
// Copyright 2008 Christian Henning
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
#ifndef BOOST_GIL_EXTENSION_IO_BMP_DETAIL_SUPPORTED_TYPES_HPP
|
||||
#define BOOST_GIL_EXTENSION_IO_BMP_DETAIL_SUPPORTED_TYPES_HPP
|
||||
|
||||
#include <boost/gil/extension/io/bmp/tags.hpp>
|
||||
|
||||
#include <boost/gil/bit_aligned_pixel_reference.hpp>
|
||||
#include <boost/gil/channel.hpp>
|
||||
#include <boost/gil/color_base.hpp>
|
||||
#include <boost/gil/packed_pixel.hpp>
|
||||
#include <boost/gil/io/base.hpp>
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
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>
|
||||
: std::integral_constant
|
||||
<
|
||||
bool,
|
||||
detail::bmp_read_support
|
||||
<
|
||||
typename channel_type<Pixel>::type,
|
||||
typename color_space_type<Pixel>::type
|
||||
>::is_supported
|
||||
>
|
||||
{
|
||||
using parent_t = detail::bmp_read_support
|
||||
<
|
||||
typename channel_type<Pixel>::type,
|
||||
typename color_space_type<Pixel>::type
|
||||
>;
|
||||
|
||||
static const typename bmp_bits_per_pixel::type bpp = parent_t::bpp;
|
||||
};
|
||||
|
||||
template<typename Pixel>
|
||||
struct is_write_supported<Pixel, bmp_tag>
|
||||
: std::integral_constant
|
||||
<
|
||||
bool,
|
||||
detail::bmp_write_support
|
||||
<
|
||||
typename channel_type<Pixel>::type,
|
||||
typename color_space_type<Pixel>::type
|
||||
>::is_supported
|
||||
>
|
||||
{};
|
||||
|
||||
} // namespace gil
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,217 @@
|
||||
//
|
||||
// Copyright 2012 Christian Henning
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
#ifndef BOOST_GIL_EXTENSION_IO_BMP_DETAIL_WRITE_HPP
|
||||
#define BOOST_GIL_EXTENSION_IO_BMP_DETAIL_WRITE_HPP
|
||||
|
||||
#include <boost/gil/extension/io/bmp/tags.hpp>
|
||||
#include <boost/gil/extension/io/bmp/detail/writer_backend.hpp>
|
||||
|
||||
#include <boost/gil/io/base.hpp>
|
||||
#include <boost/gil/io/device.hpp>
|
||||
#include <boost/gil/io/dynamic_io_new.hpp>
|
||||
|
||||
#include <vector>
|
||||
|
||||
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 > { using type = gray8_view_t; };
|
||||
template <> struct get_bgr_cs< 3 > { using type = bgr8_view_t; };
|
||||
template <> struct get_bgr_cs< 4 > { using type = bgra8_view_t; };
|
||||
|
||||
} // 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:
|
||||
|
||||
using backend_t = writer_backend<Device, bmp_tag>;
|
||||
|
||||
template< typename View >
|
||||
void write( const View& view )
|
||||
{
|
||||
// using channel_t = typename channel_type<
|
||||
// typename get_pixel_type<View>::type>::type;
|
||||
|
||||
// using color_space_t = typename color_space_type<View>::type;
|
||||
|
||||
// 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
|
||||
>
|
||||
{
|
||||
using parent_t = writer<Device, bmp_tag>;
|
||||
|
||||
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
|
||||
@@ -0,0 +1,55 @@
|
||||
//
|
||||
// Copyright 2012 Christian Henning
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
#ifndef BOOST_GIL_EXTENSION_IO_BMP_DETAIL_WRITER_BACKEND_HPP
|
||||
#define BOOST_GIL_EXTENSION_IO_BMP_DETAIL_WRITER_BACKEND_HPP
|
||||
|
||||
#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:
|
||||
|
||||
using format_tag_t = bmp_tag;
|
||||
|
||||
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
|
||||
160
install/boost_1_75_0/include/boost/gil/extension/io/bmp/old.hpp
Normal file
160
install/boost_1_75_0/include/boost/gil/extension/io/bmp/old.hpp
Normal file
@@ -0,0 +1,160 @@
|
||||
//
|
||||
// Copyright 2008 Christian Henning
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
#ifndef BOOST_GIL_EXTENSION_IO_BMP_OLD_HPP
|
||||
#define BOOST_GIL_EXTENSION_IO_BMP_OLD_HPP
|
||||
|
||||
#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 point_t bmp_read_dimensions(String const& filename)
|
||||
{
|
||||
using backend_t = typename get_reader_backend<String, bmp_tag>::type;
|
||||
backend_t backend = read_image_info(filename, bmp_tag());
|
||||
return { 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
|
||||
@@ -0,0 +1,30 @@
|
||||
//
|
||||
// Copyright 2008 Christian Henning
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
#ifndef BOOST_GIL_EXTENSION_IO_BMP_READ_HPP
|
||||
#define BOOST_GIL_EXTENSION_IO_BMP_READ_HPP
|
||||
|
||||
#define BOOST_GIL_EXTENSION_IO_BMP_READ_ENABLED // TODO: Document, explain, review
|
||||
|
||||
#include <boost/gil/extension/io/bmp/tags.hpp>
|
||||
#include <boost/gil/extension/io/bmp/detail/read.hpp>
|
||||
#include <boost/gil/extension/io/bmp/detail/scanline_read.hpp>
|
||||
#include <boost/gil/extension/io/bmp/detail/supported_types.hpp>
|
||||
|
||||
#include <boost/gil/io/get_reader.hpp>
|
||||
#include <boost/gil/io/make_backend.hpp>
|
||||
#include <boost/gil/io/make_dynamic_image_reader.hpp>
|
||||
#include <boost/gil/io/make_reader.hpp>
|
||||
#include <boost/gil/io/make_scanline_reader.hpp>
|
||||
#include <boost/gil/io/read_and_convert_image.hpp>
|
||||
#include <boost/gil/io/read_and_convert_view.hpp>
|
||||
#include <boost/gil/io/read_image.hpp>
|
||||
#include <boost/gil/io/read_image_info.hpp>
|
||||
#include <boost/gil/io/read_view.hpp>
|
||||
#include <boost/gil/io/scanline_read_iterator.hpp>
|
||||
|
||||
#endif
|
||||
159
install/boost_1_75_0/include/boost/gil/extension/io/bmp/tags.hpp
Normal file
159
install/boost_1_75_0/include/boost/gil/extension/io/bmp/tags.hpp
Normal file
@@ -0,0 +1,159 @@
|
||||
//
|
||||
// Copyright 2008 Christian Henning
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
#ifndef BOOST_GIL_EXTENSION_IO_BMP_TAGS_HPP
|
||||
#define BOOST_GIL_EXTENSION_IO_BMP_TAGS_HPP
|
||||
|
||||
#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
|
||||
@@ -0,0 +1,19 @@
|
||||
//
|
||||
// Copyright 2008 Christian Henning
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
#ifndef BOOST_GIL_EXTENSION_IO_BMP_WRITE_HPP
|
||||
#define BOOST_GIL_EXTENSION_IO_BMP_WRITE_HPP
|
||||
|
||||
#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
|
||||
14
install/boost_1_75_0/include/boost/gil/extension/io/jpeg.hpp
Normal file
14
install/boost_1_75_0/include/boost/gil/extension/io/jpeg.hpp
Normal file
@@ -0,0 +1,14 @@
|
||||
//
|
||||
// Copyright 2007-2008 Christian Henning
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
#ifndef BOOST_GIL_EXTENSION_IO_JPEG_HPP
|
||||
#define BOOST_GIL_EXTENSION_IO_JPEG_HPP
|
||||
|
||||
#include <boost/gil/extension/io/jpeg/read.hpp>
|
||||
#include <boost/gil/extension/io/jpeg/write.hpp>
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,38 @@
|
||||
//
|
||||
// Copyright 2010 Christian Henning
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
#ifndef BOOST_GIL_EXTENSION_IO_JPEG_DETAIL_BASE_HPP
|
||||
#define BOOST_GIL_EXTENSION_IO_JPEG_DETAIL_BASE_HPP
|
||||
|
||||
#include <boost/gil/extension/io/jpeg/tags.hpp>
|
||||
|
||||
#include <csetjmp>
|
||||
|
||||
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
|
||||
@@ -0,0 +1,47 @@
|
||||
//
|
||||
// Copyright 2009 Christian Henning
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
#ifndef BOOST_GIL_EXTENSION_IO_JPEG_DETAIL_IS_ALLOWED_HPP
|
||||
#define BOOST_GIL_EXTENSION_IO_JPEG_DETAIL_IS_ALLOWED_HPP
|
||||
|
||||
#include <boost/gil/extension/io/jpeg/tags.hpp>
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
namespace boost { namespace gil { namespace detail {
|
||||
|
||||
template< typename View >
|
||||
bool is_allowed( const image_read_info< jpeg_tag >& info
|
||||
, std::true_type // 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 */
|
||||
, std::false_type // is read_and_convert
|
||||
)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
} // namespace gil
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,317 @@
|
||||
//
|
||||
// Copyright 2007-2012 Christian Henning, Andreas Pokorny, Lubomir Bourdev
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
#ifndef BOOST_GIL_EXTENSION_IO_JPEG_DETAIL_READ_HPP
|
||||
#define BOOST_GIL_EXTENSION_IO_JPEG_DETAIL_READ_HPP
|
||||
|
||||
#include <boost/gil/extension/io/jpeg/tags.hpp>
|
||||
#include <boost/gil/extension/io/jpeg/detail/base.hpp>
|
||||
#include <boost/gil/extension/io/jpeg/detail/is_allowed.hpp>
|
||||
|
||||
#include <boost/gil/io/base.hpp>
|
||||
#include <boost/gil/io/conversion_policies.hpp>
|
||||
#include <boost/gil/io/device.hpp>
|
||||
#include <boost/gil/io/dynamic_io_new.hpp>
|
||||
#include <boost/gil/io/reader_base.hpp>
|
||||
#include <boost/gil/io/typedefs.hpp>
|
||||
|
||||
#include <csetjmp>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
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:
|
||||
|
||||
using this_t = reader<Device, jpeg_tag, ConversionPolicy>;
|
||||
using cc_t = typename ConversionPolicy::color_converter_type;
|
||||
|
||||
public:
|
||||
|
||||
using backend_t = reader_backend<Device, jpeg_tag>;
|
||||
|
||||
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;
|
||||
|
||||
using is_read_and_convert_t = typename std::is_same
|
||||
<
|
||||
ConversionPolicy,
|
||||
detail::read_and_no_convert
|
||||
>::type;
|
||||
|
||||
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 )
|
||||
{
|
||||
using buffer_t = std::vector<ImagePixel>;
|
||||
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
|
||||
>
|
||||
{
|
||||
using parent_t = reader<Device, jpeg_tag, detail::read_and_no_convert>;
|
||||
|
||||
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
|
||||
@@ -0,0 +1,320 @@
|
||||
//
|
||||
// Copyright 2012 Christian Henning
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
#ifndef BOOST_GIL_EXTENSION_IO_JPEG_DETAIL_READER_BACKEND_HPP
|
||||
#define BOOST_GIL_EXTENSION_IO_JPEG_DETAIL_READER_BACKEND_HPP
|
||||
|
||||
#include <boost/gil/extension/io/jpeg/tags.hpp>
|
||||
#include <boost/gil/extension/io/jpeg/detail/base.hpp>
|
||||
|
||||
#include <csetjmp>
|
||||
#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 = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
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:
|
||||
|
||||
using format_tag_t = jpeg_tag;
|
||||
|
||||
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
|
||||
@@ -0,0 +1,152 @@
|
||||
//
|
||||
// Copyright 2007-2012 Christian Henning, Andreas Pokorny, Lubomir Bourdev
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
#ifndef BOOST_GIL_EXTENSION_IO_JPEG_DETAIL_SCANLINE_READ_HPP
|
||||
#define BOOST_GIL_EXTENSION_IO_JPEG_DETAIL_SCANLINE_READ_HPP
|
||||
|
||||
|
||||
#include <boost/gil/extension/io/jpeg/detail/base.hpp>
|
||||
#include <boost/gil/extension/io/jpeg/detail/is_allowed.hpp>
|
||||
#include <boost/gil/extension/io/jpeg/detail/reader_backend.hpp>
|
||||
|
||||
#include <boost/gil/io/base.hpp>
|
||||
#include <boost/gil/io/conversion_policies.hpp>
|
||||
#include <boost/gil/io/device.hpp>
|
||||
#include <boost/gil/io/reader_base.hpp>
|
||||
#include <boost/gil/io/scanline_read_iterator.hpp>
|
||||
#include <boost/gil/io/typedefs.hpp>
|
||||
|
||||
#include <csetjmp>
|
||||
#include <vector>
|
||||
|
||||
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:
|
||||
|
||||
using tag_t = jpeg_tag;
|
||||
using backend_t = reader_backend<Device, tag_t>;
|
||||
using this_t = scanline_reader<Device, tag_t>;
|
||||
using iterator_t = scanline_read_iterator<this_t>;
|
||||
|
||||
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
|
||||
@@ -0,0 +1,117 @@
|
||||
//
|
||||
// Copyright 2007-2008 Christian Henning, Andreas Pokorny, Lubomir Bourdev
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
#ifndef BOOST_GIL_EXTENSION_IO_JPEG_DETAIL_SUPPORTED_TYPES_HPP
|
||||
#define BOOST_GIL_EXTENSION_IO_JPEG_DETAIL_SUPPORTED_TYPES_HPP
|
||||
|
||||
#include <boost/gil/extension/io/jpeg/tags.hpp>
|
||||
|
||||
#include <boost/gil/channel.hpp>
|
||||
#include <boost/gil/color_base.hpp>
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
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>
|
||||
: std::integral_constant
|
||||
<
|
||||
bool,
|
||||
detail::jpeg_read_support
|
||||
<
|
||||
typename channel_type<Pixel>::type,
|
||||
typename color_space_type<Pixel>::type
|
||||
>::is_supported
|
||||
>
|
||||
{
|
||||
using parent_t = detail::jpeg_read_support
|
||||
<
|
||||
typename channel_type<Pixel>::type,
|
||||
typename color_space_type<Pixel>::type
|
||||
>;
|
||||
|
||||
static const typename jpeg_color_space::type _color_space = parent_t::_color_space;
|
||||
};
|
||||
|
||||
template<typename Pixel>
|
||||
struct is_write_supported<Pixel, jpeg_tag>
|
||||
: std::integral_constant
|
||||
<
|
||||
bool,
|
||||
detail::jpeg_write_support
|
||||
<
|
||||
typename channel_type<Pixel>::type,
|
||||
typename color_space_type<Pixel>::type
|
||||
>::is_supported
|
||||
>
|
||||
{};
|
||||
|
||||
} // namespace gil
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,181 @@
|
||||
//
|
||||
// Copyright 2007-2008 Christian Henning, Andreas Pokorny, Lubomir Bourdev
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
#ifndef BOOST_GIL_EXTENSION_IO_JPEG_DETAIL_WRITE_HPP
|
||||
#define BOOST_GIL_EXTENSION_IO_JPEG_DETAIL_WRITE_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>
|
||||
|
||||
#include <boost/gil/io/base.hpp>
|
||||
#include <boost/gil/io/device.hpp>
|
||||
#include <boost/gil/io/dynamic_io_new.hpp>
|
||||
|
||||
#include <vector>
|
||||
|
||||
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:
|
||||
|
||||
using backend_t = writer_backend<Device, jpeg_tag>;
|
||||
|
||||
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(); }
|
||||
|
||||
using channel_t = typename channel_type<typename View::value_type>::type;
|
||||
|
||||
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_finish_compress ( this->get() );
|
||||
}
|
||||
};
|
||||
|
||||
///
|
||||
/// JPEG Dyamic Image Writer
|
||||
///
|
||||
template< typename Device >
|
||||
class dynamic_image_writer< Device
|
||||
, jpeg_tag
|
||||
>
|
||||
: public writer< Device
|
||||
, jpeg_tag
|
||||
>
|
||||
{
|
||||
using parent_t = writer<Device, jpeg_tag>;
|
||||
|
||||
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
|
||||
@@ -0,0 +1,194 @@
|
||||
//
|
||||
// Copyright 2012 Christian Henning
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
#ifndef BOOST_GIL_EXTENSION_IO_JPEG_DETAIL_WRITER_BACKEND_HPP
|
||||
#define BOOST_GIL_EXTENSION_IO_JPEG_DETAIL_WRITER_BACKEND_HPP
|
||||
|
||||
#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 = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
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:
|
||||
|
||||
using format_tag_t = jpeg_tag;
|
||||
|
||||
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_backend< 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_backend< Device, jpeg_tag >::init_device );
|
||||
_dest._jdest.empty_output_buffer = reinterpret_cast< boolean(*)( j_compress_ptr ) >( &writer_backend< Device, jpeg_tag >::empty_buffer );
|
||||
_dest._jdest.term_destination = reinterpret_cast< void(*) ( j_compress_ptr ) >( &writer_backend< Device, jpeg_tag >::close_device );
|
||||
_dest._this = this;
|
||||
|
||||
jpeg_create_compress( get() );
|
||||
get()->dest = &_dest._jdest;
|
||||
}
|
||||
|
||||
~writer_backend()
|
||||
{
|
||||
// JPEG compression object destruction does not signal errors,
|
||||
// unlike jpeg_finish_compress called elsewhere,
|
||||
// so there is no need for the setjmp bookmark here.
|
||||
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_backend<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_backend< Device, jpeg_tag >* mgr = reinterpret_cast< writer_backend< 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
|
||||
161
install/boost_1_75_0/include/boost/gil/extension/io/jpeg/old.hpp
Normal file
161
install/boost_1_75_0/include/boost/gil/extension/io/jpeg/old.hpp
Normal file
@@ -0,0 +1,161 @@
|
||||
//
|
||||
// Copyright 2007-2008 Christian Henning
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
#ifndef BOOST_GIL_EXTENSION_IO_JPEG_OLD_HPP
|
||||
#define BOOST_GIL_EXTENSION_IO_JPEG_OLD_HPP
|
||||
|
||||
#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 point_t jpeg_read_dimensions(String const& filename)
|
||||
{
|
||||
using backend_t = typename get_reader_backend<String, jpeg_tag>::type;
|
||||
backend_t backend = read_image_info(filename, jpeg_tag());
|
||||
return { 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
|
||||
@@ -0,0 +1,30 @@
|
||||
//
|
||||
// Copyright 2007-2008 Christian Henning
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
#ifndef BOOST_GIL_EXTENSION_IO_JPEG_READ_HPP
|
||||
#define BOOST_GIL_EXTENSION_IO_JPEG_READ_HPP
|
||||
|
||||
#define BOOST_GIL_EXTENSION_IO_JPEG_READ_ENABLED // TODO: Document, explain, review
|
||||
|
||||
#include <boost/gil/extension/io/jpeg/tags.hpp>
|
||||
#include <boost/gil/extension/io/jpeg/detail/read.hpp>
|
||||
#include <boost/gil/extension/io/jpeg/detail/scanline_read.hpp>
|
||||
#include <boost/gil/extension/io/jpeg/detail/supported_types.hpp>
|
||||
|
||||
#include <boost/gil/io/get_reader.hpp>
|
||||
#include <boost/gil/io/make_backend.hpp>
|
||||
#include <boost/gil/io/make_dynamic_image_reader.hpp>
|
||||
#include <boost/gil/io/make_reader.hpp>
|
||||
#include <boost/gil/io/make_scanline_reader.hpp>
|
||||
#include <boost/gil/io/read_and_convert_image.hpp>
|
||||
#include <boost/gil/io/read_and_convert_view.hpp>
|
||||
#include <boost/gil/io/read_image.hpp>
|
||||
#include <boost/gil/io/read_image_info.hpp>
|
||||
#include <boost/gil/io/read_view.hpp>
|
||||
#include <boost/gil/io/scanline_read_iterator.hpp>
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,231 @@
|
||||
//
|
||||
// Copyright 2007-2012 Christian Henning, Andreas Pokorny, Lubomir Bourdev
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
#ifndef BOOST_GIL_EXTENSION_IO_JPEG_TAGS_HPP
|
||||
#define BOOST_GIL_EXTENSION_IO_JPEG_TAGS_HPP
|
||||
|
||||
// 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
|
||||
|
||||
#include <cstdio> // jpeglib doesn't know about FILE
|
||||
|
||||
#include <jerror.h>
|
||||
#include <jpeglib.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
|
||||
@@ -0,0 +1,19 @@
|
||||
//
|
||||
// Copyright 2007-2008 Christian Henning
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
#ifndef BOOST_GIL_EXTENSION_IO_JPEG_WRITE_HPP
|
||||
#define BOOST_GIL_EXTENSION_IO_JPEG_WRITE_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/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
|
||||
14
install/boost_1_75_0/include/boost/gil/extension/io/png.hpp
Normal file
14
install/boost_1_75_0/include/boost/gil/extension/io/png.hpp
Normal file
@@ -0,0 +1,14 @@
|
||||
//
|
||||
// Copyright 2007-2008 Christian Henning
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
#ifndef BOOST_GIL_EXTENSION_IO_PNG_HPP
|
||||
#define BOOST_GIL_EXTENSION_IO_PNG_HPP
|
||||
|
||||
#include <boost/gil/extension/io/png/read.hpp>
|
||||
#include <boost/gil/extension/io/png/write.hpp>
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,104 @@
|
||||
//
|
||||
// Copyright 2012 Christian Henning
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
#ifndef BOOST_GIL_EXTENSION_IO_PNG_DETAIL_BASE_HPP
|
||||
#define BOOST_GIL_EXTENSION_IO_PNG_DETAIL_BASE_HPP
|
||||
|
||||
#include <boost/gil/extension/io/png/tags.hpp>
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace boost { namespace gil { namespace detail {
|
||||
|
||||
struct png_ptr_wrapper
|
||||
{
|
||||
png_ptr_wrapper()
|
||||
: _struct( nullptr )
|
||||
, _info ( nullptr )
|
||||
{}
|
||||
|
||||
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(); }
|
||||
png_ptr_wrapper const* get() const { return _png_ptr.get(); }
|
||||
|
||||
png_struct* get_struct() { return get()->_struct; }
|
||||
png_struct const* get_struct() const { return get()->_struct; }
|
||||
|
||||
png_info* get_info() { return get()->_info; }
|
||||
png_info const* get_info() const { return get()->_info; }
|
||||
|
||||
private:
|
||||
|
||||
static void png_ptr_read_deleter( png_ptr_wrapper* png_ptr )
|
||||
{
|
||||
if( png_ptr )
|
||||
{
|
||||
if( png_ptr->_struct && png_ptr->_info )
|
||||
{
|
||||
png_destroy_read_struct( &png_ptr->_struct
|
||||
, &png_ptr->_info
|
||||
, nullptr
|
||||
);
|
||||
}
|
||||
|
||||
delete png_ptr;
|
||||
png_ptr = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
static void png_ptr_write_deleter( png_ptr_wrapper* png_ptr )
|
||||
{
|
||||
if( png_ptr )
|
||||
{
|
||||
if( png_ptr->_struct && png_ptr->_info )
|
||||
{
|
||||
png_destroy_write_struct( &png_ptr->_struct
|
||||
, &png_ptr->_info
|
||||
);
|
||||
}
|
||||
|
||||
delete png_ptr;
|
||||
png_ptr = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
|
||||
png_ptr_t _png_ptr;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
} // namespace gil
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,45 @@
|
||||
//
|
||||
// Copyright 2008 Christian Henning, Lubomir Bourdev
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
#ifndef BOOST_GIL_EXTENSION_IO_PNG_DETAIL_IS_ALLOWED_HPP
|
||||
#define BOOST_GIL_EXTENSION_IO_PNG_DETAIL_IS_ALLOWED_HPP
|
||||
|
||||
#include <boost/gil/extension/io/png/tags.hpp>
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
namespace boost { namespace gil { namespace detail {
|
||||
|
||||
template< typename View >
|
||||
bool is_allowed( const image_read_info< png_tag >& info
|
||||
, std::true_type // is read_and_no_convert
|
||||
)
|
||||
{
|
||||
using pixel_t = typename get_pixel_type<View>::type;
|
||||
|
||||
using channel_t = typename channel_traits<typename element_type<pixel_t>::type>::value_type;
|
||||
|
||||
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 */
|
||||
, std::false_type // is read_and_convert
|
||||
)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
} // namespace gil
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,449 @@
|
||||
//
|
||||
// Copyright 2007-2012 Christian Henning, Andreas Pokorny, Lubomir Bourdev
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
#ifndef BOOST_GIL_EXTENSION_IO_PNG_DETAIL_READ_HPP
|
||||
#define BOOST_GIL_EXTENSION_IO_PNG_DETAIL_READ_HPP
|
||||
|
||||
#include <boost/gil/extension/io/png/tags.hpp>
|
||||
#include <boost/gil/extension/io/png/detail/reader_backend.hpp>
|
||||
#include <boost/gil/extension/io/png/detail/is_allowed.hpp>
|
||||
|
||||
#include <boost/gil.hpp> // FIXME: Include what you use!
|
||||
#include <boost/gil/io/base.hpp>
|
||||
#include <boost/gil/io/conversion_policies.hpp>
|
||||
#include <boost/gil/io/device.hpp>
|
||||
#include <boost/gil/io/dynamic_io_new.hpp>
|
||||
#include <boost/gil/io/error.hpp>
|
||||
#include <boost/gil/io/reader_base.hpp>
|
||||
#include <boost/gil/io/row_buffer_helper.hpp>
|
||||
#include <boost/gil/io/typedefs.hpp>
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
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:
|
||||
|
||||
using this_t = reader<Device, png_tag, ConversionPolicy>;
|
||||
using cc_t = typename ConversionPolicy::color_converter_type;
|
||||
|
||||
public:
|
||||
|
||||
using backend_t = reader_backend<Device, png_tag>;
|
||||
|
||||
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 )
|
||||
{
|
||||
// guard from errors in the following functions
|
||||
if (setjmp( png_jmpbuf( this->get_struct() )))
|
||||
{
|
||||
io_error("png is invalid");
|
||||
}
|
||||
|
||||
// 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. Define BOOST_GIL_IO_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()
|
||||
, nullptr
|
||||
);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
template< typename ImagePixel
|
||||
, typename View
|
||||
>
|
||||
void read_rows( const View& view )
|
||||
{
|
||||
// guard from errors in the following functions
|
||||
if (setjmp( png_jmpbuf( this->get_struct() )))
|
||||
{
|
||||
io_error("png is invalid");
|
||||
}
|
||||
|
||||
using row_buffer_helper_t = detail::row_buffer_helper_view<ImagePixel>;
|
||||
|
||||
using it_t = typename row_buffer_helper_t::iterator_t;
|
||||
|
||||
using is_read_and_convert_t = typename std::is_same
|
||||
<
|
||||
ConversionPolicy,
|
||||
detail::read_and_no_convert
|
||||
>::type;
|
||||
|
||||
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
|
||||
, nullptr
|
||||
, 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
|
||||
, nullptr
|
||||
, 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
|
||||
, nullptr
|
||||
, 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
|
||||
, nullptr
|
||||
, 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()
|
||||
{
|
||||
using is_supported_t = is_read_supported
|
||||
<
|
||||
typename get_pixel_type<typename Image::view_t>::type,
|
||||
png_tag
|
||||
>;
|
||||
|
||||
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
|
||||
>
|
||||
{
|
||||
using parent_t = reader
|
||||
<
|
||||
Device,
|
||||
png_tag,
|
||||
detail::read_and_no_convert
|
||||
>;
|
||||
|
||||
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
|
||||
@@ -0,0 +1,678 @@
|
||||
//
|
||||
// Copyright 2012 Christian Henning
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
#ifndef BOOST_GIL_EXTENSION_IO_DETAIL_READER_BACKEND_HPP
|
||||
#define BOOST_GIL_EXTENSION_IO_DETAIL_READER_BACKEND_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 Backend
|
||||
///
|
||||
template<typename Device >
|
||||
struct reader_backend< Device
|
||||
, png_tag
|
||||
>
|
||||
: public detail::png_struct_info_wrapper
|
||||
{
|
||||
public:
|
||||
|
||||
using format_tag_t = png_tag;
|
||||
using this_t = reader_backend<Device, png_tag>;
|
||||
|
||||
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
|
||||
, nullptr // user_error_ptr
|
||||
, nullptr // user_error_fn
|
||||
, nullptr // user_warning_fn
|
||||
);
|
||||
|
||||
io_error_if( get()->_struct == nullptr
|
||||
, "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() == nullptr )
|
||||
{
|
||||
png_destroy_read_struct( &get()->_struct
|
||||
, nullptr
|
||||
, nullptr
|
||||
);
|
||||
|
||||
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
|
||||
, nullptr
|
||||
);
|
||||
|
||||
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( nullptr )
|
||||
);
|
||||
|
||||
png_set_keep_unknown_chunks( get_struct()
|
||||
, PNG_HANDLE_CHUNK_ALWAYS
|
||||
, nullptr
|
||||
, 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( nullptr );
|
||||
png_bytep profile = png_bytep( nullptr );
|
||||
|
||||
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( nullptr );
|
||||
|
||||
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( nullptr );
|
||||
|
||||
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( nullptr );
|
||||
|
||||
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( nullptr );
|
||||
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 ( nullptr );
|
||||
png_charp units = png_charp ( nullptr );
|
||||
png_charpp params = png_charpp( nullptr );
|
||||
|
||||
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( nullptr );
|
||||
|
||||
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 = nullptr;
|
||||
png_charp scale_height = nullptr;
|
||||
|
||||
this->_info._valid_scale_factors = png_get_sCAL_s(
|
||||
get_struct(), get_info(), &this->_info._scale_unit, &scale_width, &scale_height);
|
||||
|
||||
if (this->_info._valid_scale_factors)
|
||||
{
|
||||
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( nullptr );
|
||||
|
||||
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( nullptr );
|
||||
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 ( nullptr );
|
||||
png_color_16p trans_values = png_color_16p( nullptr );
|
||||
|
||||
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
|
||||
@@ -0,0 +1,167 @@
|
||||
//
|
||||
// Copyright 2007-2012 Christian Henning, Andreas Pokorny, Lubomir Bourdev
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
#ifndef BOOST_GIL_EXTENSION_IO_PNG_DETAIL_SCANLINE_READ_HPP
|
||||
#define BOOST_GIL_EXTENSION_IO_PNG_DETAIL_SCANLINE_READ_HPP
|
||||
|
||||
#include <boost/gil/extension/io/png/detail/is_allowed.hpp>
|
||||
#include <boost/gil/extension/io/png/detail/reader_backend.hpp>
|
||||
|
||||
#include <boost/gil.hpp> // FIXME: Include what you use!
|
||||
#include <boost/gil/io/base.hpp>
|
||||
#include <boost/gil/io/conversion_policies.hpp>
|
||||
#include <boost/gil/io/device.hpp>
|
||||
#include <boost/gil/io/reader_base.hpp>
|
||||
#include <boost/gil/io/row_buffer_helper.hpp>
|
||||
#include <boost/gil/io/scanline_read_iterator.hpp>
|
||||
#include <boost/gil/io/typedefs.hpp>
|
||||
|
||||
namespace boost { namespace gil {
|
||||
|
||||
///
|
||||
/// PNG Reader
|
||||
///
|
||||
template< typename Device >
|
||||
class scanline_reader< Device
|
||||
, png_tag
|
||||
>
|
||||
: public reader_backend< Device
|
||||
, png_tag
|
||||
>
|
||||
{
|
||||
public:
|
||||
|
||||
using tag_t = png_tag;
|
||||
using backend_t = reader_backend<Device, tag_t>;
|
||||
using this_t = scanline_reader<Device, tag_t>;
|
||||
using iterator_t = scanline_read_iterator<this_t>;
|
||||
|
||||
//
|
||||
// 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
|
||||
@@ -0,0 +1,369 @@
|
||||
//
|
||||
// Copyright 2007-2008 Christian Henning, Andreas Pokorny, Lubomir Bourdev
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
#ifndef BOOST_GIL_EXTENSION_IO_PNG_DETAIL_SUPPORTED_TYPES_HPP
|
||||
#define BOOST_GIL_EXTENSION_IO_PNG_DETAIL_SUPPORTED_TYPES_HPP
|
||||
|
||||
#include <boost/gil/extension/io/png/tags.hpp>
|
||||
|
||||
#ifdef BOOST_GIL_IO_ENABLE_GRAY_ALPHA
|
||||
#include <boost/gil/extension/toolbox/color_spaces/gray_alpha.hpp>
|
||||
#endif // BOOST_GIL_IO_ENABLE_GRAY_ALPHA
|
||||
|
||||
#include <cstddef>
|
||||
#include <type_traits>
|
||||
|
||||
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>
|
||||
: std::integral_constant
|
||||
<
|
||||
bool,
|
||||
detail::png_read_support
|
||||
<
|
||||
typename channel_type<Pixel>::type,
|
||||
typename color_space_type<Pixel>::type
|
||||
>::is_supported
|
||||
>
|
||||
{
|
||||
using parent_t = detail::png_read_support
|
||||
<
|
||||
typename channel_type<Pixel>::type,
|
||||
typename color_space_type<Pixel>::type
|
||||
>;
|
||||
|
||||
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>
|
||||
: std::integral_constant
|
||||
<
|
||||
bool,
|
||||
detail::png_write_support
|
||||
<
|
||||
typename channel_type<Pixel>::type,
|
||||
typename color_space_type<Pixel>::type
|
||||
>::is_supported
|
||||
>
|
||||
{
|
||||
using parent_t = detail::png_write_support
|
||||
<
|
||||
typename channel_type<Pixel>::type,
|
||||
typename color_space_type<Pixel>::type
|
||||
>;
|
||||
|
||||
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
|
||||
@@ -0,0 +1,248 @@
|
||||
//
|
||||
// Copyright 2007-2012 Christian Henning, Andreas Pokorny, Lubomir Bourdev
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
#ifndef BOOST_GIL_EXTENSION_IO_PNG_DETAIL_WRITE_HPP
|
||||
#define BOOST_GIL_EXTENSION_IO_PNG_DETAIL_WRITE_HPP
|
||||
|
||||
#include <boost/gil/extension/io/png/detail/writer_backend.hpp>
|
||||
|
||||
#include <boost/gil/io/device.hpp>
|
||||
#include <boost/gil/io/dynamic_io_new.hpp>
|
||||
#include <boost/gil/io/row_buffer_helper.hpp>
|
||||
#include <boost/gil/detail/mp11.hpp>
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
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:
|
||||
|
||||
using backend_t = writer_backend<Device, png_tag>;
|
||||
|
||||
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
|
||||
, std::false_type // is bit aligned
|
||||
)
|
||||
{
|
||||
using pixel_t = typename get_pixel_type<View>::type;
|
||||
|
||||
using png_rw_info = detail::png_write_support
|
||||
<
|
||||
typename channel_type<pixel_t>::type,
|
||||
typename color_space_type<pixel_t>::type
|
||||
>;
|
||||
|
||||
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
|
||||
, std::true_type // is bit aligned
|
||||
)
|
||||
{
|
||||
using png_rw_info = detail::png_write_support
|
||||
<
|
||||
typename kth_semantic_element_type<typename View::value_type, 0>::type,
|
||||
typename color_space_type<View>::type
|
||||
>;
|
||||
|
||||
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 : mp11::mp_less
|
||||
<
|
||||
std::integral_constant<int, Info::_bit_depth>,
|
||||
std::integral_constant<int, 8>
|
||||
>
|
||||
{};
|
||||
|
||||
template<typename Info>
|
||||
struct is_equal_to_sixteen : mp11::mp_less
|
||||
<
|
||||
std::integral_constant<int, Info::_bit_depth>,
|
||||
std::integral_constant<int, 16>
|
||||
>
|
||||
{};
|
||||
|
||||
template <typename Info>
|
||||
void set_swap(typename std::enable_if<is_less_than_eight<Info>::value>::type* /*ptr*/ = 0)
|
||||
{
|
||||
png_set_packswap(this->get_struct());
|
||||
}
|
||||
|
||||
template <typename Info>
|
||||
void set_swap(typename std::enable_if<is_equal_to_sixteen<Info>::value>::type* /*ptr*/ = 0)
|
||||
{
|
||||
png_set_swap(this->get_struct());
|
||||
}
|
||||
|
||||
template <typename Info>
|
||||
void set_swap(
|
||||
typename std::enable_if
|
||||
<
|
||||
mp11::mp_and
|
||||
<
|
||||
mp11::mp_not<is_less_than_eight<Info>>,
|
||||
mp11::mp_not<is_equal_to_sixteen<Info>>
|
||||
>::value
|
||||
>::type* /*ptr*/ = nullptr)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
///
|
||||
/// PNG Dynamic Image Writer
|
||||
///
|
||||
template< typename Device >
|
||||
class dynamic_image_writer< Device
|
||||
, png_tag
|
||||
>
|
||||
: public writer< Device
|
||||
, png_tag
|
||||
>
|
||||
{
|
||||
using parent_t = writer<Device, png_tag>;
|
||||
|
||||
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
|
||||
@@ -0,0 +1,502 @@
|
||||
//
|
||||
// Copyright 2012 Christian Henning
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
#ifndef BOOST_GIL_EXTENSION_IO_PNG_DETAIL_WRITER_BACKEND_HPP
|
||||
#define BOOST_GIL_EXTENSION_IO_PNG_DETAIL_WRITER_BACKEND_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>
|
||||
|
||||
#include <boost/gil/io/base.hpp>
|
||||
#include <boost/gil/io/typedefs.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:
|
||||
|
||||
using this_t = writer_backend<Device, png_tag>;
|
||||
|
||||
public:
|
||||
|
||||
using format_tag_t = png_tag;
|
||||
|
||||
///
|
||||
/// 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
|
||||
, nullptr // user_error_ptr
|
||||
, nullptr // user_error_fn
|
||||
, nullptr // user_warning_fn
|
||||
);
|
||||
|
||||
io_error_if( get_struct() == nullptr
|
||||
, "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() == nullptr )
|
||||
{
|
||||
png_destroy_write_struct( &get()->_struct
|
||||
, nullptr
|
||||
);
|
||||
|
||||
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 )
|
||||
{
|
||||
using png_rw_info_t = detail::png_write_support
|
||||
<
|
||||
typename channel_type<typename get_pixel_type<View>::type>::type,
|
||||
typename color_space_type<View>::type
|
||||
>;
|
||||
|
||||
// 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
|
||||
159
install/boost_1_75_0/include/boost/gil/extension/io/png/old.hpp
Normal file
159
install/boost_1_75_0/include/boost/gil/extension/io/png/old.hpp
Normal file
@@ -0,0 +1,159 @@
|
||||
//
|
||||
// Copyright 2007-2008 Christian Henning
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
#ifndef BOOST_GIL_EXTENSION_IO_PNG_OLD_HPP
|
||||
#define BOOST_GIL_EXTENSION_IO_PNG_OLD_HPP
|
||||
|
||||
#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 point_t png_read_dimensions(String const& filename)
|
||||
{
|
||||
using backend_t = typename get_reader_backend<String, png_tag>::type;
|
||||
backend_t backend = read_image_info(filename, png_tag());
|
||||
return { static_cast<std::ptrdiff_t>(backend._info._width), static_cast<std::ptrdiff_t>(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
|
||||
@@ -0,0 +1,30 @@
|
||||
//
|
||||
// Copyright 2007-2008 Christian Henning
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
#ifndef BOOST_GIL_EXTENSION_IO_PNG_READ_HPP
|
||||
#define BOOST_GIL_EXTENSION_IO_PNG_READ_HPP
|
||||
|
||||
#define BOOST_GIL_EXTENSION_IO_PNG_READ_ENABLED // TODO: Document, explain, review
|
||||
|
||||
#include <boost/gil/extension/io/png/tags.hpp>
|
||||
#include <boost/gil/extension/io/png/detail/read.hpp>
|
||||
#include <boost/gil/extension/io/png/detail/scanline_read.hpp>
|
||||
#include <boost/gil/extension/io/png/detail/supported_types.hpp>
|
||||
|
||||
#include <boost/gil/io/get_reader.hpp>
|
||||
#include <boost/gil/io/make_backend.hpp>
|
||||
#include <boost/gil/io/make_dynamic_image_reader.hpp>
|
||||
#include <boost/gil/io/make_reader.hpp>
|
||||
#include <boost/gil/io/make_scanline_reader.hpp>
|
||||
#include <boost/gil/io/read_and_convert_image.hpp>
|
||||
#include <boost/gil/io/read_and_convert_view.hpp>
|
||||
#include <boost/gil/io/read_image.hpp>
|
||||
#include <boost/gil/io/read_image_info.hpp>
|
||||
#include <boost/gil/io/read_view.hpp>
|
||||
#include <boost/gil/io/scanline_read_iterator.hpp>
|
||||
|
||||
#endif
|
||||
833
install/boost_1_75_0/include/boost/gil/extension/io/png/tags.hpp
Normal file
833
install/boost_1_75_0/include/boost/gil/extension/io/png/tags.hpp
Normal file
@@ -0,0 +1,833 @@
|
||||
//
|
||||
// Copyright 2007-2008 Christian Henning, Andreas Pokorny, Lubomir Bourdev
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
#ifndef BOOST_GIL_EXTENSION_IO_PNG_TAGS_HPP
|
||||
#define BOOST_GIL_EXTENSION_IO_PNG_TAGS_HPP
|
||||
|
||||
#include <boost/gil/io/base.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#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
|
||||
|
||||
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
|
||||
@@ -0,0 +1,19 @@
|
||||
//
|
||||
// Copyright 2007-2008 Christian Henning
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
#ifndef BOOST_GIL_EXTENSION_IO_PNG_WRITE_HPP
|
||||
#define BOOST_GIL_EXTENSION_IO_PNG_WRITE_HPP
|
||||
|
||||
#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_dynamic_image_writer.hpp>
|
||||
#include <boost/gil/io/make_writer.hpp>
|
||||
#include <boost/gil/io/write_view.hpp>
|
||||
|
||||
#endif
|
||||
14
install/boost_1_75_0/include/boost/gil/extension/io/pnm.hpp
Normal file
14
install/boost_1_75_0/include/boost/gil/extension/io/pnm.hpp
Normal file
@@ -0,0 +1,14 @@
|
||||
//
|
||||
// Copyright 2008 Christian Henning
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
#ifndef BOOST_GIL_EXTENSION_IO_PNM_HPP
|
||||
#define BOOST_GIL_EXTENSION_IO_PNM_HPP
|
||||
|
||||
#include <boost/gil/extension/io/pnm/read.hpp>
|
||||
#include <boost/gil/extension/io/pnm/write.hpp>
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,53 @@
|
||||
//
|
||||
// Copyright 2009 Christian Henning
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
#ifndef BOOST_GIL_EXTENSION_IO_PNM_DETAIL_IS_ALLOWED_HPP
|
||||
#define BOOST_GIL_EXTENSION_IO_PNM_DETAIL_IS_ALLOWED_HPP
|
||||
|
||||
#include <boost/gil/extension/io/pnm/tags.hpp>
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
namespace boost { namespace gil { namespace detail {
|
||||
|
||||
template< typename View >
|
||||
bool is_allowed( const image_read_info< pnm_tag >& info
|
||||
, std::true_type // 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 */
|
||||
, std::false_type // is read_and_convert
|
||||
)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
} // namespace gil
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,454 @@
|
||||
//
|
||||
// Copyright 2012 Christian Henning
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
#ifndef BOOST_GIL_EXTENSION_IO_PNM_DETAIL_READ_HPP
|
||||
#define BOOST_GIL_EXTENSION_IO_PNM_DETAIL_READ_HPP
|
||||
|
||||
#include <boost/gil/extension/io/pnm/tags.hpp>
|
||||
#include <boost/gil/extension/io/pnm/detail/reader_backend.hpp>
|
||||
#include <boost/gil/extension/io/pnm/detail/is_allowed.hpp>
|
||||
|
||||
#include <boost/gil.hpp> // FIXME: Include what you use!
|
||||
#include <boost/gil/io/base.hpp>
|
||||
#include <boost/gil/io/bit_operations.hpp>
|
||||
#include <boost/gil/io/conversion_policies.hpp>
|
||||
#include <boost/gil/io/device.hpp>
|
||||
#include <boost/gil/io/dynamic_io_new.hpp>
|
||||
#include <boost/gil/io/reader_base.hpp>
|
||||
#include <boost/gil/io/row_buffer_helper.hpp>
|
||||
#include <boost/gil/io/typedefs.hpp>
|
||||
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
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:
|
||||
|
||||
using this_t = reader<Device, pnm_tag, ConversionPolicy>;
|
||||
using cc_t = typename ConversionPolicy::color_converter_type;
|
||||
|
||||
public:
|
||||
|
||||
using backend_t = reader_backend<Device, pnm_tag>;
|
||||
|
||||
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 )
|
||||
{
|
||||
using is_read_and_convert_t = typename std::is_same
|
||||
<
|
||||
ConversionPolicy,
|
||||
detail::read_and_no_convert
|
||||
>::type;
|
||||
|
||||
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 )
|
||||
{
|
||||
using y_t = typename View_Dst::y_coord_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 )
|
||||
{
|
||||
using channel_t = typename channel_type<typename get_pixel_type<View_Dst>::type>::type;
|
||||
|
||||
// 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 std::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
|
||||
, std::true_type // 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, std::false_type{});
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
, std::false_type // 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 )
|
||||
{
|
||||
using y_t = typename View_Dst::y_coord_t;
|
||||
using is_bit_aligned_t = typename is_bit_aligned<typename View_Src::value_type>::type;
|
||||
|
||||
using rh_t = detail::row_buffer_helper_view<View_Src>;
|
||||
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,
|
||||
std::integral_constant<bool, is_bit_aligned_t::value> // TODO: Simplify after MPL removal
|
||||
> neg;
|
||||
|
||||
detail::swap_half_bytes
|
||||
<
|
||||
typename rh_t::buffer_t,
|
||||
std::integral_constant<bool, is_bit_aligned_t::value> // TODO: Simplify after MPL removal
|
||||
> 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()
|
||||
{
|
||||
using is_supported_t = is_read_supported
|
||||
<
|
||||
typename get_pixel_type<typename Image::view_t>::type,
|
||||
pnm_tag
|
||||
>;
|
||||
|
||||
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
|
||||
>
|
||||
{
|
||||
using parent_t = reader
|
||||
<
|
||||
Device,
|
||||
pnm_tag,
|
||||
detail::read_and_no_convert
|
||||
>;
|
||||
|
||||
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
|
||||
@@ -0,0 +1,181 @@
|
||||
//
|
||||
// Copyright 2012 Christian Henning
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
#ifndef BOOST_GIL_EXTENSION_IO_PNM_DETAIL_READER_BACKEND_HPP
|
||||
#define BOOST_GIL_EXTENSION_IO_PNM_DETAIL_READER_BACKEND_HPP
|
||||
|
||||
#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:
|
||||
|
||||
using format_tag_t = pnm_tag;
|
||||
|
||||
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
|
||||
@@ -0,0 +1,246 @@
|
||||
//
|
||||
// Copyright 2012 Christian Henning
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
#ifndef BOOST_GIL_EXTENSION_IO_PNM_DETAIL_SCANLINE_READ_HPP
|
||||
#define BOOST_GIL_EXTENSION_IO_PNM_DETAIL_SCANLINE_READ_HPP
|
||||
|
||||
#include <boost/gil/extension/io/pnm/detail/is_allowed.hpp>
|
||||
#include <boost/gil/extension/io/pnm/detail/reader_backend.hpp>
|
||||
|
||||
#include <boost/gil.hpp> // FIXME: Include what you use!
|
||||
#include <boost/gil/io/base.hpp>
|
||||
#include <boost/gil/io/bit_operations.hpp>
|
||||
#include <boost/gil/io/conversion_policies.hpp>
|
||||
#include <boost/gil/io/device.hpp>
|
||||
#include <boost/gil/io/reader_base.hpp>
|
||||
#include <boost/gil/io/row_buffer_helper.hpp>
|
||||
#include <boost/gil/io/scanline_read_iterator.hpp>
|
||||
#include <boost/gil/io/typedefs.hpp>
|
||||
|
||||
#include <functional>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
namespace boost { namespace gil {
|
||||
|
||||
///
|
||||
/// PNM Reader
|
||||
///
|
||||
template< typename Device >
|
||||
class scanline_reader< Device
|
||||
, pnm_tag
|
||||
>
|
||||
: public reader_backend< Device
|
||||
, pnm_tag
|
||||
>
|
||||
{
|
||||
public:
|
||||
|
||||
using tag_t = pnm_tag;
|
||||
using backend_t = reader_backend<Device, tag_t>;
|
||||
using this_t = scanline_reader<Device, tag_t>;
|
||||
using iterator_t = scanline_read_iterator<this_t>;
|
||||
|
||||
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 = std::mem_fn(&this_t::read_text_row);
|
||||
_skip_function = std::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 = std::mem_fn(&this_t::read_text_row);
|
||||
_skip_function = std::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 = std::mem_fn(&this_t::read_binary_bit_row);
|
||||
_skip_function = std::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 = std::mem_fn(&this_t::read_binary_byte_row);
|
||||
_skip_function = std::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 = std::mem_fn(&this_t::read_binary_byte_row);
|
||||
_skip_function = std::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>, std::true_type> _negate_bits;
|
||||
detail::swap_half_bytes<std::vector<byte_t>, std::true_type> _swap_half_bytes;
|
||||
|
||||
std::function<void(this_t*, byte_t*)> _read_function;
|
||||
std::function<void(this_t*)> _skip_function;
|
||||
};
|
||||
|
||||
|
||||
} // namespace gil
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,145 @@
|
||||
//
|
||||
// Copyright 2008 Christian Henning
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
#ifndef BOOST_GIL_EXTENSION_IO_PNM_DETAIL_SUPPORTED_TYPES_HPP
|
||||
#define BOOST_GIL_EXTENSION_IO_PNM_DETAIL_SUPPORTED_TYPES_HPP
|
||||
|
||||
#include <boost/gil/extension/io/pnm/tags.hpp>
|
||||
|
||||
#include <boost/gil/channel.hpp>
|
||||
#include <boost/gil/color_base.hpp>
|
||||
#include <boost/gil/io/base.hpp>
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
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>
|
||||
: std::integral_constant
|
||||
<
|
||||
bool,
|
||||
detail::pnm_read_support
|
||||
<
|
||||
typename channel_type<Pixel>::type,
|
||||
typename color_space_type<Pixel>::type
|
||||
>::is_supported
|
||||
>
|
||||
{
|
||||
using parent_t = detail::pnm_read_support
|
||||
<
|
||||
typename channel_type<Pixel>::type,
|
||||
typename color_space_type<Pixel>::type
|
||||
>;
|
||||
|
||||
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>
|
||||
: std::integral_constant
|
||||
<
|
||||
bool,
|
||||
detail::pnm_write_support
|
||||
<
|
||||
typename channel_type<Pixel>::type,
|
||||
typename color_space_type<Pixel>::type
|
||||
>::is_supported
|
||||
>
|
||||
{};
|
||||
|
||||
} // namespace gil
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,247 @@
|
||||
//
|
||||
// Copyright 2012 Christian Henning
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
#ifndef BOOST_GIL_EXTENSION_IO_PNM_DETAIL_WRITE_HPP
|
||||
#define BOOST_GIL_EXTENSION_IO_PNM_DETAIL_WRITE_HPP
|
||||
|
||||
#include <boost/gil/extension/io/pnm/tags.hpp>
|
||||
#include <boost/gil/extension/io/pnm/detail/writer_backend.hpp>
|
||||
|
||||
#include <boost/gil/io/base.hpp>
|
||||
#include <boost/gil/io/bit_operations.hpp>
|
||||
#include <boost/gil/io/device.hpp>
|
||||
#include <boost/gil/io/dynamic_io_new.hpp>
|
||||
#include <boost/gil/detail/mp11.hpp>
|
||||
|
||||
#include <cstdlib>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
|
||||
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:
|
||||
using backend_t = writer_backend<Device, pnm_tag>;
|
||||
|
||||
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 )
|
||||
{
|
||||
using pixel_t = typename get_pixel_type<View>::type;
|
||||
|
||||
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( std::true_type /* is_bit_aligned */ )
|
||||
{
|
||||
return mp11::mp_if_c
|
||||
<
|
||||
Channels == 1,
|
||||
pnm_image_type::mono_bin_t,
|
||||
pnm_image_type::color_bin_t
|
||||
>::value;
|
||||
}
|
||||
|
||||
template< int Channels >
|
||||
unsigned int get_type( std::false_type /* is_bit_aligned */ )
|
||||
{
|
||||
return mp11::mp_if_c
|
||||
<
|
||||
Channels == 1,
|
||||
pnm_image_type::gray_bin_t,
|
||||
pnm_image_type::color_bin_t
|
||||
>::value;
|
||||
}
|
||||
|
||||
template< typename View >
|
||||
void write_data( const View& src
|
||||
, std::size_t pitch
|
||||
, const std::true_type& // bit_aligned
|
||||
)
|
||||
{
|
||||
static_assert(std::is_same<View, typename gray1_image_t::view_t>::value, "");
|
||||
|
||||
byte_vector_t row( pitch / 8 );
|
||||
|
||||
using x_it_t = typename View::x_iterator;
|
||||
x_it_t row_it = x_it_t( &( *row.begin() ));
|
||||
|
||||
detail::negate_bits<byte_vector_t, std::true_type> negate;
|
||||
detail::mirror_bits<byte_vector_t, std::true_type> 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);
|
||||
negate(row);
|
||||
|
||||
this->_io_dev.write(&row.front(), pitch / 8);
|
||||
}
|
||||
}
|
||||
|
||||
template< typename View >
|
||||
void write_data( const View& src
|
||||
, std::size_t pitch
|
||||
, const std::false_type& // bit_aligned
|
||||
)
|
||||
{
|
||||
std::vector< pixel< typename channel_type< View >::type
|
||||
, layout<typename color_space_type< View >::type >
|
||||
>
|
||||
> buf( src.width() );
|
||||
|
||||
// using pixel_t = typename View::value_type;
|
||||
// using view_t = typename view_type_from_pixel< pixel_t >::type;
|
||||
|
||||
//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
|
||||
>
|
||||
{
|
||||
using parent_t = writer<Device, pnm_tag>;
|
||||
|
||||
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
|
||||
@@ -0,0 +1,55 @@
|
||||
//
|
||||
// Copyright 2012 Christian Henning
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
#ifndef BOOST_GIL_EXTENSION_IO_PNM_DETAIL_WRITER_BACKEND_HPP
|
||||
#define BOOST_GIL_EXTENSION_IO_PNM_DETAIL_WRITER_BACKEND_HPP
|
||||
|
||||
#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:
|
||||
|
||||
using format_tag_t = pnm_tag;
|
||||
|
||||
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
|
||||
160
install/boost_1_75_0/include/boost/gil/extension/io/pnm/old.hpp
Normal file
160
install/boost_1_75_0/include/boost/gil/extension/io/pnm/old.hpp
Normal file
@@ -0,0 +1,160 @@
|
||||
//
|
||||
// Copyright 2008 Christian Henning
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
#ifndef BOOST_GIL_EXTENSION_IO_PNM_OLD_HPP
|
||||
#define BOOST_GIL_EXTENSION_IO_PNM_OLD_HPP
|
||||
|
||||
#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 point_t pnm_read_dimensions(String const& filename)
|
||||
{
|
||||
using backend_t = typename get_reader_backend<String, pnm_tag>::type;
|
||||
backend_t backend = read_image_info(filename, pnm_tag());
|
||||
return { 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
|
||||
@@ -0,0 +1,28 @@
|
||||
//
|
||||
// Copyright 2008 Christian Henning
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
#ifndef BOOST_GIL_EXTENSION_IO_PNM_READ_HPP
|
||||
#define BOOST_GIL_EXTENSION_IO_PNM_READ_HPP
|
||||
|
||||
#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_dynamic_image_reader.hpp>
|
||||
#include <boost/gil/io/make_reader.hpp>
|
||||
#include <boost/gil/io/make_scanline_reader.hpp>
|
||||
#include <boost/gil/io/read_and_convert_image.hpp>
|
||||
#include <boost/gil/io/read_and_convert_view.hpp>
|
||||
#include <boost/gil/io/read_image.hpp>
|
||||
#include <boost/gil/io/read_image_info.hpp>
|
||||
#include <boost/gil/io/read_view.hpp>
|
||||
#include <boost/gil/io/scanline_read_iterator.hpp>
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,95 @@
|
||||
//
|
||||
// Copyright 2008 Christian Henning
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
#ifndef BOOST_GIL_EXTENSION_IO_PNM_TAGS_HPP
|
||||
#define BOOST_GIL_EXTENSION_IO_PNM_TAGS_HPP
|
||||
|
||||
#define BOOST_GIL_EXTENSION_IO_PNM_READ_ENABLED // TODO: Document, explain, review
|
||||
|
||||
#include <boost/gil/io/base.hpp>
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
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 >
|
||||
{
|
||||
using mono_asc_t = std::integral_constant<type, 1>;
|
||||
using gray_asc_t = std::integral_constant<type, 2>;
|
||||
using color_asc_t = std::integral_constant<type, 3>;
|
||||
|
||||
using mono_bin_t = std::integral_constant<type, 4>;
|
||||
using gray_bin_t = std::integral_constant<type, 5>;
|
||||
using color_bin_t = std::integral_constant<type, 6>;
|
||||
};
|
||||
|
||||
/// 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
|
||||
@@ -0,0 +1,19 @@
|
||||
//
|
||||
// Copyright 2008 Christian Henning
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
#ifndef BOOST_GIL_EXTENSION_IO_PNM_WRITE_HPP
|
||||
#define BOOST_GIL_EXTENSION_IO_PNM_WRITE_HPP
|
||||
|
||||
#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_dynamic_image_writer.hpp>
|
||||
#include <boost/gil/io/make_writer.hpp>
|
||||
#include <boost/gil/io/write_view.hpp>
|
||||
|
||||
#endif
|
||||
13
install/boost_1_75_0/include/boost/gil/extension/io/raw.hpp
Normal file
13
install/boost_1_75_0/include/boost/gil/extension/io/raw.hpp
Normal file
@@ -0,0 +1,13 @@
|
||||
//
|
||||
// Copyright 2013 Christian Henning
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
#ifndef BOOST_GIL_EXTENSION_IO_RAW_HPP
|
||||
#define BOOST_GIL_EXTENSION_IO_RAW_HPP
|
||||
|
||||
#include <boost/gil/extension/io/raw/read.hpp>
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,131 @@
|
||||
//
|
||||
// Copyright 2012 Olivier Tournaire
|
||||
// Copyright 2007 Christian Henning
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
#ifndef BOOST_GIL_EXTENSION_IO_RAW_DETAIL_DEVICE_HPP
|
||||
#define BOOST_GIL_EXTENSION_IO_RAW_DETAIL_DEVICE_HPP
|
||||
|
||||
#include <boost/gil/extension/io/raw/tags.hpp>
|
||||
|
||||
#include <boost/gil/io/base.hpp>
|
||||
#include <boost/gil/io/device.hpp>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
|
||||
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=nullptr) { 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> : std::true_type
|
||||
{
|
||||
using device_type = file_stream_device<FormatTag>;
|
||||
};
|
||||
|
||||
|
||||
} // namespace detail
|
||||
} // namespace gil
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,48 @@
|
||||
//
|
||||
// Copyright 2009 Christian Henning
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
#ifndef BOOST_GIL_EXTENSION_IO_RAW_DETAIL_IS_ALLOWED_HPP
|
||||
#define BOOST_GIL_EXTENSION_IO_RAW_DETAIL_IS_ALLOWED_HPP
|
||||
|
||||
#include <boost/gil/extension/io/raw/tags.hpp>
|
||||
#include <boost/gil/io/base.hpp>
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
namespace boost { namespace gil { namespace detail {
|
||||
|
||||
template< typename View >
|
||||
bool is_allowed( const image_read_info< raw_tag >& info
|
||||
, std::true_type // is read_and_no_convert
|
||||
)
|
||||
{
|
||||
using pixel_t = typename get_pixel_type<View>::type;
|
||||
using num_channel_t = typename num_channels<pixel_t>::value_type;
|
||||
using channel_t = typename channel_traits<typename element_type<typename View::value_type>::type>::value_type;
|
||||
|
||||
constexpr num_channel_t dst_samples_per_pixel = num_channels<pixel_t>::value;
|
||||
constexpr unsigned int dst_bits_per_pixel = detail::unsigned_integral_num_bits<channel_t>::value;
|
||||
constexpr bool is_type_signed = std::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 */
|
||||
, std::false_type // is read_and_convert
|
||||
)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
} // namespace gil
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,241 @@
|
||||
//
|
||||
// Copyright 2012 Olivier Tournaire, Christian Henning
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
#ifndef BOOST_GIL_EXTENSION_IO_RAW_DETAIL_READ_HPP
|
||||
#define BOOST_GIL_EXTENSION_IO_RAW_DETAIL_READ_HPP
|
||||
|
||||
#include <boost/gil/extension/io/raw/tags.hpp>
|
||||
#include <boost/gil/extension/io/raw/detail/device.hpp>
|
||||
#include <boost/gil/extension/io/raw/detail/is_allowed.hpp>
|
||||
#include <boost/gil/extension/io/raw/detail/reader_backend.hpp>
|
||||
|
||||
#include <boost/gil/io/base.hpp>
|
||||
#include <boost/gil/io/bit_operations.hpp>
|
||||
#include <boost/gil/io/conversion_policies.hpp>
|
||||
#include <boost/gil/io/device.hpp>
|
||||
#include <boost/gil/io/dynamic_io_new.hpp>
|
||||
#include <boost/gil/io/reader_base.hpp>
|
||||
#include <boost/gil/io/row_buffer_helper.hpp>
|
||||
#include <boost/gil/io/typedefs.hpp>
|
||||
|
||||
#include <cstdio>
|
||||
#include <sstream>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
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:
|
||||
|
||||
using this_t = reader<Device, raw_tag, ConversionPolicy>;
|
||||
using cc_t = typename ConversionPolicy::color_converter_type;
|
||||
|
||||
public:
|
||||
|
||||
using backend_t = reader_backend<Device, raw_tag>;
|
||||
|
||||
//
|
||||
// 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." );
|
||||
}
|
||||
|
||||
using is_read_and_convert_t = typename std::is_same
|
||||
<
|
||||
ConversionPolicy,
|
||||
detail::read_and_no_convert
|
||||
>::type;
|
||||
|
||||
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()
|
||||
{
|
||||
using view_t = typename Image::view_t;
|
||||
return is_allowed<view_t>(_info, std::true_type{});
|
||||
}
|
||||
|
||||
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
|
||||
>
|
||||
{
|
||||
using parent_t = reader<Device, raw_tag, detail::read_and_no_convert>;
|
||||
|
||||
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
|
||||
@@ -0,0 +1,140 @@
|
||||
//
|
||||
// Copyright 2012 Christian Henning
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
#ifndef BOOST_GIL_EXTENSION_IO_RAW_DETAIL_READER_BACKEND_HPP
|
||||
#define BOOST_GIL_EXTENSION_IO_RAW_DETAIL_READER_BACKEND_HPP
|
||||
|
||||
#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:
|
||||
|
||||
using format_tag_t = raw_tag;
|
||||
|
||||
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
|
||||
@@ -0,0 +1,74 @@
|
||||
//
|
||||
// Copyright 2008 Christian Henning
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
#ifndef BOOST_GIL_EXTENSION_IO_RAW_DETAIL_SUPPORTED_TYPES_HPP
|
||||
#define BOOST_GIL_EXTENSION_IO_RAW_DETAIL_SUPPORTED_TYPES_HPP
|
||||
|
||||
#include <boost/gil/extension/io/raw/tags.hpp>
|
||||
|
||||
#include <boost/gil/channel.hpp>
|
||||
#include <boost/gil/color_base.hpp>
|
||||
#include <boost/gil/io/base.hpp>
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
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>
|
||||
: std::integral_constant
|
||||
<
|
||||
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>
|
||||
: std::integral_constant<bool, detail::raw_write_support::is_supported>
|
||||
{};
|
||||
|
||||
}} // namespace boost::gil
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,28 @@
|
||||
//
|
||||
// Copyright 2013 Christian Henning
|
||||
// Copyright 2012 Olivier Tournaire
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
#ifndef BOOST_GIL_EXTENSION_IO_RAW_READ_HPP
|
||||
#define BOOST_GIL_EXTENSION_IO_RAW_READ_HPP
|
||||
|
||||
#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_dynamic_image_reader.hpp>
|
||||
#include <boost/gil/io/make_reader.hpp>
|
||||
#include <boost/gil/io/make_scanline_reader.hpp>
|
||||
#include <boost/gil/io/read_and_convert_image.hpp>
|
||||
#include <boost/gil/io/read_and_convert_view.hpp>
|
||||
#include <boost/gil/io/read_image.hpp>
|
||||
#include <boost/gil/io/read_image_info.hpp>
|
||||
#include <boost/gil/io/read_view.hpp>
|
||||
#include <boost/gil/io/scanline_read_iterator.hpp>
|
||||
|
||||
#endif
|
||||
208
install/boost_1_75_0/include/boost/gil/extension/io/raw/tags.hpp
Normal file
208
install/boost_1_75_0/include/boost/gil/extension/io/raw/tags.hpp
Normal file
@@ -0,0 +1,208 @@
|
||||
//
|
||||
// Copyright 2013 Christian Henning
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
#ifndef BOOST_GIL_EXTENSION_IO_RAW_TAGS_HPP
|
||||
#define BOOST_GIL_EXTENSION_IO_RAW_TAGS_HPP
|
||||
|
||||
#include <boost/gil/io/base.hpp>
|
||||
|
||||
// Historically, LibRaw expects WIN32, not _WIN32 (see https://github.com/LibRaw/LibRaw/pull/206)
|
||||
#ifdef _MSC_VER
|
||||
#ifndef WIN32
|
||||
#define WIN32
|
||||
#endif
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4251) // 'type' needs to have dll-interface to be used by clients of class
|
||||
#endif
|
||||
|
||||
#include <libraw/libraw.h>
|
||||
|
||||
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 boost::gil
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,14 @@
|
||||
//
|
||||
// Copyright 2010 Kenneth Riddile
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
#ifndef BOOST_GIL_EXTENSION_IO_TARGA_HPP
|
||||
#define BOOST_GIL_EXTENSION_IO_TARGA_HPP
|
||||
|
||||
#include <boost/gil/extension/io/targa/read.hpp>
|
||||
#include <boost/gil/extension/io/targa/write.hpp>
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,57 @@
|
||||
//
|
||||
// Copyright 2010 Kenneth Riddile
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
#ifndef BOOST_GIL_EXTENSION_IO_TARGA_DETAIL_IS_ALLOWED_HPP
|
||||
#define BOOST_GIL_EXTENSION_IO_TARGA_DETAIL_IS_ALLOWED_HPP
|
||||
|
||||
#include <boost/gil/extension/io/targa/tags.hpp>
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
namespace boost { namespace gil { namespace detail {
|
||||
|
||||
template< typename View >
|
||||
bool is_allowed( const image_read_info< targa_tag >& info
|
||||
, std::true_type // 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;
|
||||
}
|
||||
}
|
||||
|
||||
using channel_t = typename channel_traits<typename element_type<typename View::value_type>::type>::value_type;
|
||||
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 */
|
||||
, std::false_type // is read_and_convert
|
||||
)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
} // namespace gil
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,400 @@
|
||||
//
|
||||
// Copyright 2012 Kenneth Riddile, Christian Henning
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
#ifndef BOOST_GIL_EXTENSION_IO_TARGA_DETAIL_READ_HPP
|
||||
#define BOOST_GIL_EXTENSION_IO_TARGA_DETAIL_READ_HPP
|
||||
|
||||
#include <boost/gil/extension/io/targa/tags.hpp>
|
||||
#include <boost/gil/extension/io/targa/detail/reader_backend.hpp>
|
||||
#include <boost/gil/extension/io/targa/detail/is_allowed.hpp>
|
||||
|
||||
#include <boost/gil/io/base.hpp>
|
||||
#include <boost/gil/io/bit_operations.hpp>
|
||||
#include <boost/gil/io/conversion_policies.hpp>
|
||||
#include <boost/gil/io/device.hpp>
|
||||
#include <boost/gil/io/dynamic_io_new.hpp>
|
||||
#include <boost/gil/io/reader_base.hpp>
|
||||
#include <boost/gil/io/row_buffer_helper.hpp>
|
||||
#include <boost/gil/io/typedefs.hpp>
|
||||
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
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:
|
||||
|
||||
using this_t = reader<Device, targa_tag, ConversionPolicy>;
|
||||
using cc_t = typename ConversionPolicy::color_converter_type;
|
||||
|
||||
public:
|
||||
|
||||
using backend_t = reader_backend<Device, targa_tag>;
|
||||
|
||||
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 )
|
||||
{
|
||||
using is_read_and_convert_t = typename std::is_same
|
||||
<
|
||||
ConversionPolicy,
|
||||
detail::read_and_no_convert
|
||||
>::type;
|
||||
|
||||
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
|
||||
>
|
||||
{
|
||||
using parent_t = reader<Device, targa_tag, detail::read_and_no_convert>;
|
||||
|
||||
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
|
||||
@@ -0,0 +1,164 @@
|
||||
//
|
||||
// Copyright 2012 Christian Henning
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
#ifndef BOOST_GIL_EXTENSION_IO_TARGA_DETAIL_READER_BACKEND_HPP
|
||||
#define BOOST_GIL_EXTENSION_IO_TARGA_DETAIL_READER_BACKEND_HPP
|
||||
|
||||
#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:
|
||||
|
||||
using format_tag_t = targa_tag;
|
||||
|
||||
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
|
||||
@@ -0,0 +1,153 @@
|
||||
//
|
||||
// Copyright 2012 Kenneth Riddile, Christian Henning
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
#ifndef BOOST_GIL_EXTENSION_IO_TARGA_DETAIL_SCANLINE_READ_HPP
|
||||
#define BOOST_GIL_EXTENSION_IO_TARGA_DETAIL_SCANLINE_READ_HPP
|
||||
|
||||
#include <boost/gil/extension/io/targa/detail/is_allowed.hpp>
|
||||
#include <boost/gil/extension/io/targa/detail/reader_backend.hpp>
|
||||
|
||||
#include <boost/gil/io/base.hpp>
|
||||
#include <boost/gil/io/bit_operations.hpp>
|
||||
#include <boost/gil/io/conversion_policies.hpp>
|
||||
#include <boost/gil/io/device.hpp>
|
||||
#include <boost/gil/io/reader_base.hpp>
|
||||
#include <boost/gil/io/row_buffer_helper.hpp>
|
||||
#include <boost/gil/io/scanline_read_iterator.hpp>
|
||||
#include <boost/gil/io/typedefs.hpp>
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace boost { namespace gil {
|
||||
|
||||
///
|
||||
/// Targa Scanline Reader
|
||||
///
|
||||
template< typename Device >
|
||||
class scanline_reader< Device
|
||||
, targa_tag
|
||||
>
|
||||
: public reader_backend< Device
|
||||
, targa_tag
|
||||
>
|
||||
{
|
||||
public:
|
||||
|
||||
using tag_t = targa_tag;
|
||||
using backend_t = reader_backend<Device, tag_t>;
|
||||
using this_t = scanline_reader<Device, tag_t>;
|
||||
using iterator_t = scanline_read_iterator<this_t>;
|
||||
|
||||
//
|
||||
// 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
|
||||
@@ -0,0 +1,105 @@
|
||||
//
|
||||
// Copyright 2010 Kenneth Riddile
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
#ifndef BOOST_GIL_EXTENSION_IO_TARGA_DETAIL_SUPPORTED_TYPES_HPP
|
||||
#define BOOST_GIL_EXTENSION_IO_TARGA_DETAIL_SUPPORTED_TYPES_HPP
|
||||
|
||||
#include <boost/gil/extension/io/targa/tags.hpp>
|
||||
|
||||
#include <boost/gil/channel.hpp>
|
||||
#include <boost/gil/color_base.hpp>
|
||||
#include <boost/gil/io/base.hpp>
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
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>
|
||||
: std::integral_constant
|
||||
<
|
||||
bool,
|
||||
detail::targa_read_support
|
||||
<
|
||||
typename channel_type<Pixel>::type,
|
||||
typename color_space_type<Pixel>::type
|
||||
>::is_supported
|
||||
>
|
||||
{
|
||||
using parent_t = detail::targa_read_support
|
||||
<
|
||||
typename channel_type<Pixel>::type,
|
||||
typename color_space_type<Pixel>::type
|
||||
>;
|
||||
|
||||
static const typename targa_depth::type bpp = parent_t::bpp;
|
||||
};
|
||||
|
||||
template<typename Pixel>
|
||||
struct is_write_supported<Pixel, targa_tag>
|
||||
: std::integral_constant
|
||||
<
|
||||
bool,
|
||||
detail::targa_write_support
|
||||
<
|
||||
typename channel_type<Pixel>::type,
|
||||
typename color_space_type<Pixel>::type
|
||||
>::is_supported
|
||||
>
|
||||
{};
|
||||
|
||||
}} // namespace boost::gil
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,184 @@
|
||||
//
|
||||
// Copyright 2010-2012 Kenneth Riddile, Christian Henning
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
#ifndef BOOST_GIL_EXTENSION_IO_TARGA_DETAIL_WRITE_HPP
|
||||
#define BOOST_GIL_EXTENSION_IO_TARGA_DETAIL_WRITE_HPP
|
||||
|
||||
#include <boost/gil/extension/io/targa/tags.hpp>
|
||||
#include <boost/gil/extension/io/targa/detail/writer_backend.hpp>
|
||||
|
||||
#include <boost/gil/io/base.hpp>
|
||||
#include <boost/gil/io/device.hpp>
|
||||
#include <boost/gil/io/dynamic_io_new.hpp>
|
||||
|
||||
#include <vector>
|
||||
|
||||
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 > { using type = bgr8_view_t; };
|
||||
template <> struct get_targa_view_type< 4 > { using type = bgra8_view_t; };
|
||||
|
||||
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:
|
||||
using backend_t = writer_backend<Device, targa_tag>;
|
||||
|
||||
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
|
||||
>
|
||||
{
|
||||
using parent_t = writer<Device, targa_tag>;
|
||||
|
||||
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
|
||||
@@ -0,0 +1,55 @@
|
||||
//
|
||||
// Copyright 2012 Christian Henning
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
#ifndef BOOST_GIL_EXTENSION_IO_TARGA_DETAIL_WRITER_BACKEND_HPP
|
||||
#define BOOST_GIL_EXTENSION_IO_TARGA_DETAIL_WRITER_BACKEND_HPP
|
||||
|
||||
#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:
|
||||
|
||||
using format_tag_t = targa_tag;
|
||||
|
||||
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
|
||||
@@ -0,0 +1,160 @@
|
||||
//
|
||||
// Copyright 2010 Christian Henning
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
#ifndef BOOST_GIL_EXTENSION_IO_TARGA_OLD_HPP
|
||||
#define BOOST_GIL_EXTENSION_IO_TARGA_OLD_HPP
|
||||
|
||||
#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 point_t targa_read_dimensions(String const& filename)
|
||||
{
|
||||
using backend_t = typename get_reader_backend<String, targa_tag>::type;
|
||||
backend_t backend = read_image_info(filename, targa_tag());
|
||||
return { 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
|
||||
@@ -0,0 +1,28 @@
|
||||
//
|
||||
// Copyright 2010-2012 Kenneth Riddile, Christian Henning
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
#ifndef BOOST_GIL_EXTENSION_IO_TARGA_READ_HPP
|
||||
#define BOOST_GIL_EXTENSION_IO_TARGA_READ_HPP
|
||||
|
||||
#include <boost/gil/extension/io/targa/tags.hpp>
|
||||
#include <boost/gil/extension/io/targa/detail/read.hpp>
|
||||
#include <boost/gil/extension/io/targa/detail/scanline_read.hpp>
|
||||
#include <boost/gil/extension/io/targa/detail/supported_types.hpp>
|
||||
|
||||
#include <boost/gil/io/get_reader.hpp>
|
||||
#include <boost/gil/io/make_backend.hpp>
|
||||
#include <boost/gil/io/make_dynamic_image_reader.hpp>
|
||||
#include <boost/gil/io/make_reader.hpp>
|
||||
#include <boost/gil/io/make_scanline_reader.hpp>
|
||||
#include <boost/gil/io/read_and_convert_image.hpp>
|
||||
#include <boost/gil/io/read_and_convert_view.hpp>
|
||||
#include <boost/gil/io/read_image.hpp>
|
||||
#include <boost/gil/io/read_image_info.hpp>
|
||||
#include <boost/gil/io/read_view.hpp>
|
||||
#include <boost/gil/io/scanline_read_iterator.hpp>
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,166 @@
|
||||
//
|
||||
// Copyright 2010 Kenneth Riddile
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
#ifndef BOOST_GIL_EXTENSION_IO_TARGA_TAGS_HPP
|
||||
#define BOOST_GIL_EXTENSION_IO_TARGA_TAGS_HPP
|
||||
|
||||
#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
|
||||
@@ -0,0 +1,19 @@
|
||||
//
|
||||
// Copyright 2010 Kenneth Riddile
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
#ifndef BOOST_GIL_EXTENSION_IO_TARGA_WRITE_HPP
|
||||
#define BOOST_GIL_EXTENSION_IO_TARGA_WRITE_HPP
|
||||
|
||||
#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_dynamic_image_writer.hpp>
|
||||
#include <boost/gil/io/make_writer.hpp>
|
||||
#include <boost/gil/io/write_view.hpp>
|
||||
|
||||
#endif
|
||||
14
install/boost_1_75_0/include/boost/gil/extension/io/tiff.hpp
Normal file
14
install/boost_1_75_0/include/boost/gil/extension/io/tiff.hpp
Normal file
@@ -0,0 +1,14 @@
|
||||
//
|
||||
// Copyright 2007-2008 Christian Henning
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
#ifndef BOOST_GIL_EXTENSION_IO_TIFF_HPP
|
||||
#define BOOST_GIL_EXTENSION_IO_TIFF_HPP
|
||||
|
||||
#include <boost/gil/extension/io/tiff/read.hpp>
|
||||
#include <boost/gil/extension/io/tiff/write.hpp>
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,486 @@
|
||||
//
|
||||
// Copyright 2007-2008 Andreas Pokorny, Christian Henning
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
#ifndef BOOST_GIL_EXTENSION_IO_TIFF_DETAIL_DEVICE_HPP
|
||||
#define BOOST_GIL_EXTENSION_IO_TIFF_DETAIL_DEVICE_HPP
|
||||
|
||||
#include <boost/gil/extension/io/tiff/tags.hpp>
|
||||
#include <boost/gil/extension/io/tiff/detail/log.hpp>
|
||||
#include <boost/gil/detail/mp11.hpp>
|
||||
#include <boost/gil/io/base.hpp>
|
||||
#include <boost/gil/io/device.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
#include <type_traits>
|
||||
|
||||
// taken from jpegxx - https://bitbucket.org/edd/jpegxx/src/ea2492a1a4a6/src/ijg_headers.hpp
|
||||
#ifndef BOOST_GIL_EXTENSION_IO_TIFF_C_LIB_COMPILED_AS_CPLUSPLUS
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <tiff.h>
|
||||
#include <tiffio.h>
|
||||
|
||||
#ifndef BOOST_GIL_EXTENSION_IO_TIFF_C_LIB_COMPILED_AS_CPLUSPLUS
|
||||
}
|
||||
#endif
|
||||
|
||||
#include <tiffio.hxx>
|
||||
|
||||
namespace boost { namespace gil { namespace detail {
|
||||
|
||||
template <int n_args>
|
||||
struct get_property_f {
|
||||
template <typename Property>
|
||||
bool call_me(typename Property:: type& value, std::shared_ptr<TIFF>& file);
|
||||
};
|
||||
|
||||
template <int n_args>
|
||||
struct set_property_f {
|
||||
template <typename Property>
|
||||
bool call_me(const typename Property:: type& value, std::shared_ptr<TIFF>& file) const;
|
||||
};
|
||||
|
||||
template <> struct get_property_f <1>
|
||||
{
|
||||
// For single-valued properties
|
||||
template <typename Property>
|
||||
bool call_me(typename Property::type & value, std::shared_ptr<TIFF>& file) const
|
||||
{
|
||||
// @todo: defaulted, really?
|
||||
return (1 == TIFFGetFieldDefaulted( file.get()
|
||||
, Property:: tag
|
||||
, & value));
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct get_property_f <2>
|
||||
{
|
||||
// Specialisation for multi-valued properties. @todo: add one of
|
||||
// these for the three-parameter fields too.
|
||||
template <typename Property>
|
||||
bool call_me(typename Property::type& vs, std::shared_ptr<TIFF>& file) const
|
||||
{
|
||||
mp11::mp_at<typename Property::arg_types, std::integral_constant<int, 0>> length;
|
||||
mp11::mp_at<typename Property::arg_types, std::integral_constant<int, 1>> 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
|
||||
{
|
||||
using length_t = mp11::mp_at_c<typename Property::arg_types, 0>;
|
||||
auto const length = static_cast<length_t>(values.size());
|
||||
|
||||
using pointer_t = mp11::mp_at_c<typename Property::arg_types, 1>;
|
||||
auto const pointer = static_cast<pointer_t>(&(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<mp11::mp_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<mp11::mp_size<typename Property::arg_types>::value>().template call_me<Property>(value, _tiff_file);
|
||||
}
|
||||
|
||||
// TIFFIsByteSwapped returns a non-zero value if the image data was in a different
|
||||
// byte-order than the host machine. Zero is returned if the TIFF file and local
|
||||
// host byte-orders are the same. Note that TIFFReadTile(), TIFFReadStrip() and TIFFReadScanline()
|
||||
// functions already normally perform byte swapping to local host order if needed.
|
||||
bool are_bytes_swapped()
|
||||
{
|
||||
return ( TIFFIsByteSwapped( _tiff_file.get() )) ? true : false;
|
||||
}
|
||||
|
||||
bool is_tiled() const
|
||||
{
|
||||
return ( TIFFIsTiled( _tiff_file.get() )) ? true : false;
|
||||
}
|
||||
|
||||
unsigned int get_default_strip_size()
|
||||
{
|
||||
return TIFFDefaultStripSize( _tiff_file.get()
|
||||
, 0 );
|
||||
}
|
||||
|
||||
std::size_t get_scanline_size()
|
||||
{
|
||||
return TIFFScanlineSize( _tiff_file.get() );
|
||||
}
|
||||
|
||||
std::size_t get_tile_size()
|
||||
{
|
||||
return TIFFTileSize( _tiff_file.get() );
|
||||
}
|
||||
|
||||
|
||||
int get_field_defaulted( uint16_t*& red
|
||||
, uint16_t*& green
|
||||
, uint16_t*& blue
|
||||
)
|
||||
{
|
||||
return TIFFGetFieldDefaulted( _tiff_file.get()
|
||||
, TIFFTAG_COLORMAP
|
||||
, &red
|
||||
, &green
|
||||
, &blue
|
||||
);
|
||||
}
|
||||
|
||||
template< typename Buffer >
|
||||
void read_scanline( Buffer& buffer
|
||||
, std::ptrdiff_t row
|
||||
, tsample_t plane
|
||||
)
|
||||
{
|
||||
io_error_if( TIFFReadScanline( _tiff_file.get()
|
||||
, reinterpret_cast< tdata_t >( &buffer.front() )
|
||||
, (uint32) row
|
||||
, plane ) == -1
|
||||
, "Read error."
|
||||
);
|
||||
}
|
||||
|
||||
void read_scanline( byte_t* buffer
|
||||
, std::ptrdiff_t row
|
||||
, tsample_t plane
|
||||
)
|
||||
{
|
||||
io_error_if( TIFFReadScanline( _tiff_file.get()
|
||||
, reinterpret_cast< tdata_t >( buffer )
|
||||
, (uint32) row
|
||||
, plane ) == -1
|
||||
, "Read error."
|
||||
);
|
||||
}
|
||||
|
||||
template< typename Buffer >
|
||||
void read_tile( Buffer& buffer
|
||||
, std::ptrdiff_t x
|
||||
, std::ptrdiff_t y
|
||||
, std::ptrdiff_t z
|
||||
, tsample_t plane
|
||||
)
|
||||
{
|
||||
if( TIFFReadTile( _tiff_file.get()
|
||||
, reinterpret_cast< tdata_t >( &buffer.front() )
|
||||
, (uint32) x
|
||||
, (uint32) y
|
||||
, (uint32) z
|
||||
, plane
|
||||
) == -1 )
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << "Read tile error (" << x << "," << y << "," << z << "," << plane << ").";
|
||||
io_error(oss.str().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
template< typename Buffer >
|
||||
void write_scaline( Buffer& buffer
|
||||
, uint32 row
|
||||
, tsample_t plane
|
||||
)
|
||||
{
|
||||
io_error_if( TIFFWriteScanline( _tiff_file.get()
|
||||
, &buffer.front()
|
||||
, row
|
||||
, plane
|
||||
) == -1
|
||||
, "Write error"
|
||||
);
|
||||
}
|
||||
|
||||
void write_scaline( byte_t* buffer
|
||||
, uint32 row
|
||||
, tsample_t plane
|
||||
)
|
||||
{
|
||||
io_error_if( TIFFWriteScanline( _tiff_file.get()
|
||||
, buffer
|
||||
, row
|
||||
, plane
|
||||
) == -1
|
||||
, "Write error"
|
||||
);
|
||||
}
|
||||
|
||||
template< typename Buffer >
|
||||
void write_tile( Buffer& buffer
|
||||
, uint32 x
|
||||
, uint32 y
|
||||
, uint32 z
|
||||
, tsample_t plane
|
||||
)
|
||||
{
|
||||
if( TIFFWriteTile( _tiff_file.get()
|
||||
, &buffer.front()
|
||||
, x
|
||||
, y
|
||||
, z
|
||||
, plane
|
||||
) == -1 )
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << "Write tile error (" << x << "," << y << "," << z << "," << plane << ").";
|
||||
io_error(oss.str().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void set_directory( tdir_t directory )
|
||||
{
|
||||
io_error_if( TIFFSetDirectory( _tiff_file.get()
|
||||
, directory
|
||||
) != 1
|
||||
, "Failing to set directory"
|
||||
);
|
||||
}
|
||||
|
||||
// return false if the given tile width or height is not TIFF compliant (multiple of 16) or larger than image size, true otherwise
|
||||
bool check_tile_size( tiff_tile_width::type& width
|
||||
, tiff_tile_length::type& height
|
||||
|
||||
)
|
||||
{
|
||||
bool result = true;
|
||||
uint32 tw = static_cast< uint32 >( width );
|
||||
uint32 th = static_cast< uint32 >( height );
|
||||
|
||||
TIFFDefaultTileSize( _tiff_file.get()
|
||||
, &tw
|
||||
, &th
|
||||
);
|
||||
|
||||
if(width==0 || width%16!=0)
|
||||
{
|
||||
width = tw;
|
||||
result = false;
|
||||
}
|
||||
if(height==0 || height%16!=0)
|
||||
{
|
||||
height = th;
|
||||
result = false;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
tiff_file_t _tiff_file;
|
||||
|
||||
Log _log;
|
||||
};
|
||||
|
||||
/*!
|
||||
*
|
||||
* file_stream_device specialization for tiff images, which are based on TIFF*.
|
||||
*/
|
||||
template<>
|
||||
class file_stream_device< tiff_tag > : public tiff_device_base< tiff_no_log >
|
||||
{
|
||||
public:
|
||||
|
||||
struct read_tag {};
|
||||
struct write_tag {};
|
||||
|
||||
file_stream_device( std::string const& file_name, read_tag )
|
||||
{
|
||||
TIFF* tiff;
|
||||
|
||||
io_error_if( ( tiff = TIFFOpen( file_name.c_str(), "r" )) == nullptr
|
||||
, "file_stream_device: failed to open file" );
|
||||
|
||||
_tiff_file = tiff_file_t( tiff, TIFFClose );
|
||||
}
|
||||
|
||||
file_stream_device( std::string const& file_name, write_tag )
|
||||
{
|
||||
TIFF* tiff;
|
||||
|
||||
io_error_if( ( tiff = TIFFOpen( file_name.c_str(), "w" )) == nullptr
|
||||
, "file_stream_device: failed to open file" );
|
||||
|
||||
_tiff_file = tiff_file_t( tiff, TIFFClose );
|
||||
}
|
||||
|
||||
file_stream_device( TIFF* tiff_file )
|
||||
: tiff_device_base( tiff_file )
|
||||
{}
|
||||
};
|
||||
|
||||
/*!
|
||||
*
|
||||
* ostream_device specialization for tiff images.
|
||||
*/
|
||||
template<>
|
||||
class ostream_device< tiff_tag > : public tiff_device_base< tiff_no_log >
|
||||
{
|
||||
public:
|
||||
ostream_device( std::ostream & out )
|
||||
: _out( out )
|
||||
{
|
||||
TIFF* tiff;
|
||||
|
||||
io_error_if( ( tiff = TIFFStreamOpen( ""
|
||||
, &_out
|
||||
)
|
||||
) == nullptr
|
||||
, "ostream_device: failed to stream"
|
||||
);
|
||||
|
||||
_tiff_file = tiff_file_t( tiff, TIFFClose );
|
||||
}
|
||||
|
||||
private:
|
||||
ostream_device& operator=( const ostream_device& ) { return *this; }
|
||||
|
||||
private:
|
||||
|
||||
std::ostream& _out;
|
||||
};
|
||||
|
||||
/*!
|
||||
*
|
||||
* ostream_device specialization for tiff images.
|
||||
*/
|
||||
template<>
|
||||
class istream_device< tiff_tag > : public tiff_device_base< tiff_no_log >
|
||||
{
|
||||
public:
|
||||
istream_device( std::istream & in )
|
||||
: _in( in )
|
||||
{
|
||||
TIFF* tiff;
|
||||
|
||||
io_error_if( ( tiff = TIFFStreamOpen( ""
|
||||
, &_in
|
||||
)
|
||||
) == nullptr
|
||||
, "istream_device: failed to stream"
|
||||
);
|
||||
|
||||
_tiff_file = tiff_file_t( tiff, TIFFClose );
|
||||
}
|
||||
|
||||
private:
|
||||
istream_device& operator=( const istream_device& ) { return *this; }
|
||||
|
||||
private:
|
||||
|
||||
std::istream& _in;
|
||||
};
|
||||
|
||||
/*
|
||||
template< typename T, typename D >
|
||||
struct is_adaptable_input_device< tiff_tag, T, D > : std::false_type {};
|
||||
*/
|
||||
|
||||
template<typename FormatTag>
|
||||
struct is_adaptable_input_device<FormatTag, TIFF*, void> : std::true_type
|
||||
{
|
||||
using device_type = file_stream_device<FormatTag>;
|
||||
};
|
||||
|
||||
template<typename FormatTag>
|
||||
struct is_adaptable_output_device<FormatTag, TIFF*, void> : std::true_type
|
||||
{
|
||||
using device_type = file_stream_device<FormatTag>;
|
||||
};
|
||||
|
||||
|
||||
template <typename Channel>
|
||||
struct sample_format : std::integral_constant<int, SAMPLEFORMAT_UINT> {};
|
||||
template<>
|
||||
struct sample_format<uint8_t> : std::integral_constant<int, SAMPLEFORMAT_UINT> {};
|
||||
template<>
|
||||
struct sample_format<uint16_t> : std::integral_constant<int, SAMPLEFORMAT_UINT> {};
|
||||
template<>
|
||||
struct sample_format<uint32_t> : std::integral_constant<int, SAMPLEFORMAT_UINT> {};
|
||||
template<>
|
||||
struct sample_format<float32_t> : std::integral_constant<int, SAMPLEFORMAT_IEEEFP> {};
|
||||
template<>
|
||||
struct sample_format<double> : std::integral_constant<int, SAMPLEFORMAT_IEEEFP> {};
|
||||
template<>
|
||||
struct sample_format<int8_t> : std::integral_constant<int, SAMPLEFORMAT_INT> {};
|
||||
template<>
|
||||
struct sample_format<int16_t> : std::integral_constant<int, SAMPLEFORMAT_INT> {};
|
||||
template<>
|
||||
struct sample_format<int32_t> : std::integral_constant<int, SAMPLEFORMAT_INT> {};
|
||||
|
||||
template <typename Channel>
|
||||
struct photometric_interpretation {};
|
||||
template<>
|
||||
struct photometric_interpretation<gray_t>
|
||||
: std::integral_constant<int, PHOTOMETRIC_MINISBLACK> {};
|
||||
template<>
|
||||
struct photometric_interpretation<rgb_t>
|
||||
: std::integral_constant<int, PHOTOMETRIC_RGB> {};
|
||||
template<>
|
||||
struct photometric_interpretation<rgba_t>
|
||||
: std::integral_constant<int, PHOTOMETRIC_RGB> {};
|
||||
template<>
|
||||
struct photometric_interpretation<cmyk_t>
|
||||
: std::integral_constant<int, PHOTOMETRIC_SEPARATED> {};
|
||||
|
||||
} // namespace detail
|
||||
} // namespace gil
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,253 @@
|
||||
//
|
||||
// Copyright 2008 Christian Henning, Lubomir Bourdev
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
#ifndef BOOST_GIL_EXTENSION_IO_TIFF_DETAIL_IS_ALLOWED_HPP
|
||||
#define BOOST_GIL_EXTENSION_IO_TIFF_DETAIL_IS_ALLOWED_HPP
|
||||
|
||||
#include <boost/gil/extension/io/tiff/tags.hpp>
|
||||
#include <boost/gil/extension/toolbox/metafunctions/is_bit_aligned.hpp>
|
||||
#include <boost/gil/detail/mp11.hpp>
|
||||
#include <boost/gil/io/base.hpp>
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
namespace boost { namespace gil { namespace detail {
|
||||
|
||||
using channel_sizes_t = std::vector<tiff_bits_per_sample::type>;
|
||||
|
||||
template <typename View, typename Channel, typename Enable = void>
|
||||
struct Format_Type {};
|
||||
|
||||
// is_bit_aligned< View >
|
||||
template <typename View, typename Channel>
|
||||
struct Format_Type
|
||||
<
|
||||
View,
|
||||
Channel,
|
||||
typename std::enable_if
|
||||
<
|
||||
is_bit_aligned
|
||||
<
|
||||
typename get_pixel_type<View>::type
|
||||
>::value
|
||||
>::type
|
||||
>
|
||||
{
|
||||
static const int value = SAMPLEFORMAT_UINT;
|
||||
};
|
||||
|
||||
// is_not_bit_aligned< View > && is_unsigned< Channel >
|
||||
template <typename View, typename Channel>
|
||||
struct Format_Type
|
||||
<
|
||||
View,
|
||||
Channel,
|
||||
typename std::enable_if
|
||||
<
|
||||
mp11::mp_and
|
||||
<
|
||||
mp11::mp_not
|
||||
<
|
||||
typename is_bit_aligned<typename get_pixel_type<View>::type>::type
|
||||
>,
|
||||
std::is_unsigned<Channel>
|
||||
>::value
|
||||
>::type
|
||||
>
|
||||
{
|
||||
static const int value = SAMPLEFORMAT_UINT;
|
||||
};
|
||||
|
||||
// is_not_bit_aligned< View > && is_signed< Channel >
|
||||
template <typename View, typename Channel>
|
||||
struct Format_Type
|
||||
<
|
||||
View,
|
||||
Channel,
|
||||
typename std::enable_if
|
||||
<
|
||||
mp11::mp_and
|
||||
<
|
||||
mp11::mp_not
|
||||
<
|
||||
typename is_bit_aligned<typename get_pixel_type<View>::type>::type
|
||||
>,
|
||||
std::is_signed<Channel>
|
||||
>::value
|
||||
>::type
|
||||
>
|
||||
{
|
||||
static const int value = SAMPLEFORMAT_INT;
|
||||
};
|
||||
|
||||
// is_not_bit_aligned< View > && is_floating_point< Channel >
|
||||
template <typename View, typename Channel>
|
||||
struct Format_Type
|
||||
<
|
||||
View,
|
||||
Channel,
|
||||
typename std::enable_if
|
||||
<
|
||||
mp11::mp_and
|
||||
<
|
||||
mp11::mp_not
|
||||
<
|
||||
typename is_bit_aligned<typename get_pixel_type<View>::type>::type
|
||||
>,
|
||||
is_floating_point<Channel>
|
||||
>::value
|
||||
>::type
|
||||
>
|
||||
{
|
||||
static const int value = SAMPLEFORMAT_IEEEFP;
|
||||
};
|
||||
|
||||
//template< typename Channel >
|
||||
//int format_value( std::true_type ) // is_bit_aligned
|
||||
//{
|
||||
// return SAMPLEFORMAT_UINT;
|
||||
//}
|
||||
//
|
||||
//template< typename Channel >
|
||||
//int format_value( std::false_type ) // 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
|
||||
, std::false_type // is_bit_aligned
|
||||
, std::true_type // is_homogeneous
|
||||
)
|
||||
{
|
||||
using pixel_t = typename View::value_type;
|
||||
using channel_t = typename channel_traits<typename element_type<pixel_t>::type>::value_type;
|
||||
|
||||
unsigned int s = detail::unsigned_integral_num_bits< channel_t >::value;
|
||||
|
||||
return ( s == channel_sizes[0] );
|
||||
}
|
||||
|
||||
|
||||
template< typename View >
|
||||
bool compare_channel_sizes( const channel_sizes_t& channel_sizes // in bits
|
||||
, std::true_type // is_bit_aligned
|
||||
, std::true_type // is_homogeneous
|
||||
)
|
||||
{
|
||||
using ref_t = typename View::reference;
|
||||
using channel_t = typename channel_traits<typename element_type<ref_t>::type>::value_type;
|
||||
|
||||
unsigned int s = detail::unsigned_integral_num_bits< channel_t >::value;
|
||||
return ( s == channel_sizes[0] );
|
||||
}
|
||||
|
||||
struct compare_channel_sizes_fn
|
||||
{
|
||||
compare_channel_sizes_fn( uint16_t* a )
|
||||
: _a( a )
|
||||
, _b( true )
|
||||
{}
|
||||
|
||||
template< typename ChannelSize >
|
||||
void operator()( ChannelSize x)
|
||||
{
|
||||
if( x != *_a++ )
|
||||
{
|
||||
_b = false;
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t* _a;
|
||||
bool _b;
|
||||
};
|
||||
|
||||
template< typename T >
|
||||
struct channel_sizes_type {};
|
||||
|
||||
template< typename B, typename C, typename L, bool M >
|
||||
struct channel_sizes_type< bit_aligned_pixel_reference< B, C, L, M > > { using type = C; };
|
||||
|
||||
template< typename B, typename C, typename L, bool M >
|
||||
struct channel_sizes_type< const bit_aligned_pixel_reference< B, C, L, M > > { using type = C; };
|
||||
|
||||
template< typename View >
|
||||
bool compare_channel_sizes( channel_sizes_t& channel_sizes // in bits
|
||||
, std::true_type // is_bit_aligned
|
||||
, std::false_type // is_homogeneous
|
||||
)
|
||||
{
|
||||
// loop through all channels and compare
|
||||
|
||||
using ref_t = typename View::reference;
|
||||
using cs_t = typename channel_sizes_type<ref_t>::type;
|
||||
|
||||
compare_channel_sizes_fn fn( &channel_sizes.front() );
|
||||
mp11::mp_for_each<cs_t>(fn);
|
||||
|
||||
return fn._b;
|
||||
}
|
||||
|
||||
template< typename View >
|
||||
bool is_allowed( const image_read_info< tiff_tag >& info
|
||||
, std::true_type // is read_and_no_convert
|
||||
)
|
||||
{
|
||||
channel_sizes_t channel_sizes( info._samples_per_pixel
|
||||
, info._bits_per_sample
|
||||
);
|
||||
|
||||
using pixel_t = typename get_pixel_type<View>::type;
|
||||
using channel_t = typename channel_traits<typename element_type<pixel_t>::type>::value_type;
|
||||
|
||||
using num_channel_t = typename num_channels<pixel_t>::value_type;
|
||||
|
||||
const num_channel_t dst_samples_per_pixel = num_channels< pixel_t >::value;
|
||||
|
||||
//const num_channel_t dst_sample_format = format_value< channel_t >( typename is_bit_aligned< pixel_t >::type() );
|
||||
const num_channel_t dst_sample_format = Format_Type<View, channel_t>::value;
|
||||
|
||||
|
||||
return ( dst_samples_per_pixel == info._samples_per_pixel
|
||||
&& compare_channel_sizes< View >( channel_sizes
|
||||
, typename is_bit_aligned< pixel_t >::type()
|
||||
, typename is_homogeneous< pixel_t >::type()
|
||||
)
|
||||
&& dst_sample_format == info._sample_format
|
||||
);
|
||||
}
|
||||
|
||||
template< typename View >
|
||||
bool is_allowed( const image_read_info< tiff_tag >& /* info */
|
||||
, std::false_type // is read_and_no_convert
|
||||
)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
} // namespace gil
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,66 @@
|
||||
//
|
||||
// Copyright 2009 Christian Henning
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
#ifndef BOOST_GIL_EXTENSION_IO_TIFF_DETAIL_LOG_HPP
|
||||
#define BOOST_GIL_EXTENSION_IO_TIFF_DETAIL_LOG_HPP
|
||||
|
||||
#include <iostream>
|
||||
|
||||
extern "C" {
|
||||
#include "tiffio.h"
|
||||
}
|
||||
|
||||
namespace boost { namespace gil {
|
||||
|
||||
class tiff_no_log
|
||||
{
|
||||
public:
|
||||
|
||||
tiff_no_log()
|
||||
{
|
||||
TIFFSetErrorHandler ( nullptr );
|
||||
TIFFSetWarningHandler( nullptr );
|
||||
}
|
||||
};
|
||||
|
||||
class console_log
|
||||
{
|
||||
public:
|
||||
|
||||
console_log()
|
||||
{
|
||||
TIFFSetErrorHandler ( console_log::error );
|
||||
TIFFSetWarningHandler( console_log::warning );
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
static void error( const char* /* module */
|
||||
, const char* fmt
|
||||
, va_list ap
|
||||
)
|
||||
{
|
||||
char buf[1000];
|
||||
sprintf(buf, fmt, ap);
|
||||
std::cout << "error: " << buf << std::endl;
|
||||
}
|
||||
|
||||
static void warning( char const* /* module */
|
||||
, char const* fmt
|
||||
, va_list ap
|
||||
)
|
||||
{
|
||||
char buf[1000];
|
||||
sprintf(buf, fmt, ap);
|
||||
std::cout << "warning: " << fmt << std::endl;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace gil
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,783 @@
|
||||
//
|
||||
// Copyright 2007-2012 Christian Henning, Lubomir Bourdev
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
#ifndef BOOST_GIL_EXTENSION_IO_TIFF_DETAIL_READER_HPP
|
||||
#define BOOST_GIL_EXTENSION_IO_TIFF_DETAIL_READER_HPP
|
||||
|
||||
#include <boost/gil/extension/io/tiff/detail/device.hpp>
|
||||
#include <boost/gil/extension/io/tiff/detail/is_allowed.hpp>
|
||||
#include <boost/gil/extension/io/tiff/detail/reader_backend.hpp>
|
||||
|
||||
#include <boost/gil/io/base.hpp>
|
||||
#include <boost/gil/io/bit_operations.hpp>
|
||||
#include <boost/gil/io/conversion_policies.hpp>
|
||||
#include <boost/gil/io/device.hpp>
|
||||
#include <boost/gil/io/dynamic_io_new.hpp>
|
||||
#include <boost/gil/io/reader_base.hpp>
|
||||
#include <boost/gil/io/row_buffer_helper.hpp>
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
// taken from jpegxx - https://bitbucket.org/edd/jpegxx/src/ea2492a1a4a6/src/ijg_headers.hpp
|
||||
#ifndef BOOST_GIL_EXTENSION_IO_TIFF_C_LIB_COMPILED_AS_CPLUSPLUS
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <tiff.h>
|
||||
#include <tiffio.h>
|
||||
|
||||
#ifndef BOOST_GIL_EXTENSION_IO_TIFF_C_LIB_COMPILED_AS_CPLUSPLUS
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace boost { namespace gil {
|
||||
|
||||
#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4512) //assignment operator could not be generated
|
||||
#endif
|
||||
|
||||
template < int K >
|
||||
struct plane_recursion
|
||||
{
|
||||
template< typename View
|
||||
, typename Device
|
||||
, typename ConversionPolicy
|
||||
>
|
||||
static
|
||||
void read_plane( const View& dst_view
|
||||
, reader< Device
|
||||
, tiff_tag
|
||||
, ConversionPolicy >* p
|
||||
)
|
||||
{
|
||||
using plane_t = typename kth_channel_view_type<K, View>::type;
|
||||
plane_t plane = kth_channel_view<K>( dst_view );
|
||||
|
||||
p->template read_data< detail::row_buffer_helper_view< plane_t > >( plane, K );
|
||||
|
||||
plane_recursion< K - 1 >::read_plane( dst_view, p );
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct plane_recursion< -1 >
|
||||
{
|
||||
template< typename View
|
||||
, typename Device
|
||||
, typename ConversionPolicy
|
||||
>
|
||||
static
|
||||
void read_plane( const View& /* dst_view */
|
||||
, reader< Device
|
||||
, tiff_tag
|
||||
, ConversionPolicy
|
||||
>* /* p */
|
||||
)
|
||||
{}
|
||||
};
|
||||
|
||||
///
|
||||
/// Tiff Reader
|
||||
///
|
||||
template< typename Device
|
||||
, typename ConversionPolicy
|
||||
>
|
||||
class reader< Device
|
||||
, tiff_tag
|
||||
, ConversionPolicy
|
||||
>
|
||||
: public reader_base< tiff_tag
|
||||
, ConversionPolicy >
|
||||
|
||||
, public reader_backend< Device
|
||||
, tiff_tag
|
||||
>
|
||||
{
|
||||
private:
|
||||
|
||||
using this_t = reader<Device, tiff_tag, ConversionPolicy>;
|
||||
using cc_t = typename ConversionPolicy::color_converter_type;
|
||||
|
||||
public:
|
||||
|
||||
using backend_t = reader_backend<Device, tiff_tag>;
|
||||
|
||||
reader( const Device& io_dev
|
||||
, const image_read_settings< tiff_tag >& settings
|
||||
)
|
||||
: reader_base< tiff_tag
|
||||
, ConversionPolicy
|
||||
>()
|
||||
, backend_t( io_dev
|
||||
, settings
|
||||
)
|
||||
{}
|
||||
|
||||
reader( const Device& io_dev
|
||||
, const typename ConversionPolicy::color_converter_type& cc
|
||||
, const image_read_settings< tiff_tag >& settings
|
||||
)
|
||||
: reader_base< tiff_tag
|
||||
, ConversionPolicy
|
||||
>( cc )
|
||||
, backend_t( io_dev
|
||||
, settings
|
||||
)
|
||||
{}
|
||||
|
||||
// only works for homogeneous image types
|
||||
template< typename View >
|
||||
void apply( View& dst_view )
|
||||
{
|
||||
if( this->_info._photometric_interpretation == PHOTOMETRIC_PALETTE )
|
||||
{
|
||||
this->_scanline_length = this->_info._width
|
||||
* num_channels< rgb16_view_t >::value
|
||||
* sizeof( channel_type<rgb16_view_t>::type );
|
||||
|
||||
// Steps:
|
||||
// 1. Read indices. It's an array of grayX_pixel_t.
|
||||
// 2. Read palette. It's an array of rgb16_pixel_t.
|
||||
// 3. ??? Create virtual image or transform the two arrays
|
||||
// into a rgb16_image_t object. The latter might
|
||||
// be a good first solution.
|
||||
|
||||
switch( this->_info._bits_per_sample )
|
||||
{
|
||||
case 1: { read_palette_image< gray1_image_t >( dst_view ); break; }
|
||||
case 2: { read_palette_image< gray2_image_t >( dst_view ); break; }
|
||||
case 4: { read_palette_image< gray4_image_t >( dst_view ); break; }
|
||||
case 8: { read_palette_image< gray8_image_t >( dst_view ); break; }
|
||||
case 16: { read_palette_image< gray16_image_t >( dst_view ); break; }
|
||||
|
||||
default: { io_error( "Not supported palette " ); }
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
this->_scanline_length = this->_io_dev.get_scanline_size();
|
||||
|
||||
// In case we only read the image the user's type and
|
||||
// the tiff type need to compatible. Which means:
|
||||
// color_spaces_are_compatible && channels_are_pairwise_compatible
|
||||
|
||||
using is_read_only = typename std::is_same
|
||||
<
|
||||
ConversionPolicy,
|
||||
detail::read_and_no_convert
|
||||
>::type;
|
||||
|
||||
io_error_if( !detail::is_allowed< View >( this->_info
|
||||
, is_read_only()
|
||||
)
|
||||
, "Image types aren't compatible."
|
||||
);
|
||||
|
||||
if( this->_info._planar_configuration == PLANARCONFIG_SEPARATE )
|
||||
{
|
||||
plane_recursion< num_channels< View >::value - 1 >::read_plane( dst_view
|
||||
, this
|
||||
);
|
||||
}
|
||||
else if( this->_info._planar_configuration == PLANARCONFIG_CONTIG )
|
||||
{
|
||||
read( dst_view
|
||||
, typename is_read_only::type()
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
io_error( "Wrong planar configuration setting." );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
template< typename View >
|
||||
void read( View v
|
||||
, std::true_type // is_read_only
|
||||
)
|
||||
{
|
||||
read_data< detail::row_buffer_helper_view< View > >( v, 0 );
|
||||
}
|
||||
|
||||
template< typename View >
|
||||
void read( View v
|
||||
, std::false_type // is_read_only
|
||||
)
|
||||
{
|
||||
// the read_data function needs to know what gil type the source image is
|
||||
// to have the default color converter function correctly
|
||||
|
||||
switch( this->_info._photometric_interpretation )
|
||||
{
|
||||
case PHOTOMETRIC_MINISWHITE:
|
||||
case PHOTOMETRIC_MINISBLACK:
|
||||
{
|
||||
switch( this->_info._bits_per_sample )
|
||||
{
|
||||
case 1: { read_data< detail::row_buffer_helper_view< gray1_image_t::view_t > >( v, 0 ); break; }
|
||||
case 2: { read_data< detail::row_buffer_helper_view< gray2_image_t::view_t > >( v, 0 ); break; }
|
||||
case 4: { read_data< detail::row_buffer_helper_view< gray4_image_t::view_t > >( v, 0 ); break; }
|
||||
case 8: { read_data< detail::row_buffer_helper_view< gray8_view_t > >( v, 0 ); break; }
|
||||
case 16: { read_data< detail::row_buffer_helper_view< gray16_view_t > >( v, 0 ); break; }
|
||||
case 32: { read_data< detail::row_buffer_helper_view< gray32_view_t > >( v, 0 ); break; }
|
||||
default: { io_error( "Image type is not supported." ); }
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case PHOTOMETRIC_RGB:
|
||||
{
|
||||
switch( this->_info._samples_per_pixel )
|
||||
{
|
||||
case 3:
|
||||
{
|
||||
switch( this->_info._bits_per_sample )
|
||||
{
|
||||
case 8: { read_data< detail::row_buffer_helper_view< rgb8_view_t > >( v, 0 ); break; }
|
||||
case 16: { read_data< detail::row_buffer_helper_view< rgb16_view_t > >( v, 0 ); break; }
|
||||
case 32: { read_data< detail::row_buffer_helper_view< rgb32_view_t > >( v, 0 ); break; }
|
||||
default: { io_error( "Image type is not supported." ); }
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 4:
|
||||
{
|
||||
switch( this->_info._bits_per_sample )
|
||||
{
|
||||
case 8: { read_data< detail::row_buffer_helper_view< rgba8_view_t > >( v, 0 ); break; }
|
||||
case 16: { read_data< detail::row_buffer_helper_view< rgba16_view_t > >( v, 0 ); break; }
|
||||
case 32: { read_data< detail::row_buffer_helper_view< rgba32_view_t > >( v, 0 ); break; }
|
||||
default: { io_error( "Image type is not supported." ); }
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default: { io_error( "Image type is not supported." ); }
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case PHOTOMETRIC_SEPARATED: // CYMK
|
||||
{
|
||||
switch( this->_info._bits_per_sample )
|
||||
{
|
||||
case 8: { read_data< detail::row_buffer_helper_view< cmyk8_view_t > >( v, 0 ); break; }
|
||||
case 16: { read_data< detail::row_buffer_helper_view< cmyk16_view_t > >( v, 0 ); break; }
|
||||
case 32: { read_data< detail::row_buffer_helper_view< cmyk32_view_t > >( v, 0 ); break; }
|
||||
default: { io_error( "Image type is not supported." ); }
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default: { io_error( "Image type is not supported." ); }
|
||||
}
|
||||
}
|
||||
|
||||
template< typename PaletteImage
|
||||
, typename View
|
||||
>
|
||||
void read_palette_image( const View& dst_view )
|
||||
{
|
||||
PaletteImage indices( this->_info._width - this->_settings._top_left.x
|
||||
, this->_info._height - this->_settings._top_left.y );
|
||||
|
||||
// read the palette first
|
||||
read_data< detail::row_buffer_helper_view
|
||||
<
|
||||
typename PaletteImage::view_t>
|
||||
>(view(indices), 0);
|
||||
|
||||
read_palette_image(dst_view, view(indices),
|
||||
typename std::is_same<View, rgb16_view_t>::type());
|
||||
}
|
||||
|
||||
template< typename View
|
||||
, typename Indices_View
|
||||
>
|
||||
void read_palette_image( const View& dst_view
|
||||
, const Indices_View& indices_view
|
||||
, std::true_type // is View rgb16_view_t
|
||||
)
|
||||
{
|
||||
tiff_color_map::red_t red = nullptr;
|
||||
tiff_color_map::green_t green = nullptr;
|
||||
tiff_color_map::blue_t blue = nullptr;
|
||||
|
||||
this->_io_dev.get_field_defaulted( red, green, blue );
|
||||
|
||||
using channel_t = typename channel_traits<typename element_type<typename Indices_View::value_type>::type>::value_type;
|
||||
|
||||
int num_colors = channel_traits< channel_t >::max_value();
|
||||
|
||||
rgb16_planar_view_t palette = planar_rgb_view( num_colors
|
||||
, 1
|
||||
, red
|
||||
, green
|
||||
, blue
|
||||
, sizeof(uint16_t) * num_colors );
|
||||
|
||||
for( typename rgb16_view_t::y_coord_t y = 0; y < dst_view.height(); ++y )
|
||||
{
|
||||
typename rgb16_view_t::x_iterator it = dst_view.row_begin( y );
|
||||
typename rgb16_view_t::x_iterator end = dst_view.row_end( y );
|
||||
|
||||
typename Indices_View::x_iterator indices_it = indices_view.row_begin( y );
|
||||
|
||||
for( ; it != end; ++it, ++indices_it )
|
||||
{
|
||||
uint16_t i = gil::at_c<0>( *indices_it );
|
||||
|
||||
*it = palette[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template< typename View
|
||||
, typename Indices_View
|
||||
>
|
||||
inline
|
||||
void read_palette_image( const View& /* dst_view */
|
||||
, const Indices_View& /* indices_view */
|
||||
, std::false_type // is View rgb16_view_t
|
||||
)
|
||||
{
|
||||
io_error( "User supplied image type must be rgb16_image_t." );
|
||||
}
|
||||
|
||||
template< typename Buffer >
|
||||
void skip_over_rows( Buffer& buffer
|
||||
, int plane
|
||||
)
|
||||
{
|
||||
if( this->_info._compression != COMPRESSION_NONE )
|
||||
{
|
||||
// Skipping over rows is not possible for compressed images( no random access ). See man
|
||||
// page ( diagnostics section ) for more information.
|
||||
for( std::ptrdiff_t row = 0; row < this->_settings._top_left.y; ++row )
|
||||
{
|
||||
this->_io_dev.read_scanline( buffer
|
||||
, row
|
||||
, static_cast< tsample_t >( plane ));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template< typename Buffer
|
||||
, typename View
|
||||
>
|
||||
void read_data( const View& dst_view
|
||||
, int /* plane */ )
|
||||
{
|
||||
if( this->_io_dev.is_tiled() )
|
||||
{
|
||||
read_tiled_data< Buffer >( dst_view, 0 );
|
||||
}
|
||||
else
|
||||
{
|
||||
read_stripped_data< Buffer >( dst_view, 0 );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template< typename Buffer
|
||||
, typename View
|
||||
>
|
||||
void read_tiled_data( const View& dst_view
|
||||
, int plane
|
||||
)
|
||||
{
|
||||
if( dst_view.width() != this->_info._width
|
||||
|| dst_view.height() != this->_info._height
|
||||
)
|
||||
{
|
||||
// read a subimage
|
||||
read_tiled_data_subimage< Buffer >( dst_view, plane );
|
||||
}
|
||||
else
|
||||
{
|
||||
// read full image
|
||||
read_tiled_data_full< Buffer >( dst_view, plane );
|
||||
}
|
||||
}
|
||||
|
||||
template< typename Buffer
|
||||
, typename View
|
||||
>
|
||||
void read_tiled_data_subimage( const View& dst_view
|
||||
, int plane
|
||||
)
|
||||
{
|
||||
///@todo: why is
|
||||
/// using row_buffer_helper_t = Buffer;
|
||||
/// not working? I get compiler error with MSVC10.
|
||||
/// read_stripped_data IS working.
|
||||
using row_buffer_helper_t = detail::row_buffer_helper_view<View>;
|
||||
|
||||
using it_t = typename row_buffer_helper_t::iterator_t;
|
||||
|
||||
tiff_image_width::type image_width = this->_info._width;
|
||||
tiff_image_height::type image_height = this->_info._height;
|
||||
|
||||
tiff_tile_width::type tile_width = this->_info._tile_width;
|
||||
tiff_tile_length::type tile_height = this->_info._tile_length;
|
||||
|
||||
std::ptrdiff_t subimage_x = this->_settings._top_left.x;
|
||||
std::ptrdiff_t subimage_y = this->_settings._top_left.y;
|
||||
|
||||
std::ptrdiff_t subimage_width = this->_settings._dim.x;
|
||||
std::ptrdiff_t subimage_height = this->_settings._dim.y;
|
||||
|
||||
row_buffer_helper_t row_buffer_helper(this->_io_dev.get_tile_size(), true );
|
||||
|
||||
for( unsigned int y = 0; y < image_height; y += tile_height )
|
||||
{
|
||||
for( unsigned int x = 0; x < image_width; x += tile_width )
|
||||
{
|
||||
uint32_t current_tile_width = ( x + tile_width < image_width ) ? tile_width : image_width - x;
|
||||
uint32_t current_tile_length = ( y + tile_height < image_height ) ? tile_height : image_height - y;
|
||||
|
||||
this->_io_dev.read_tile( row_buffer_helper.buffer()
|
||||
, x
|
||||
, y
|
||||
, 0
|
||||
, static_cast< tsample_t >( plane )
|
||||
);
|
||||
|
||||
// these are all whole image coordinates
|
||||
point_t tile_top_left ( x, y );
|
||||
point_t tile_lower_right( x + current_tile_width - 1, y + current_tile_length - 1 );
|
||||
|
||||
point_t view_top_left ( subimage_x, subimage_y );
|
||||
point_t view_lower_right( subimage_x + subimage_width - 1
|
||||
, subimage_y + subimage_height - 1 );
|
||||
|
||||
if( tile_top_left.x > view_lower_right.x
|
||||
|| tile_top_left.y > view_lower_right.y
|
||||
|| tile_lower_right.x < view_top_left.x
|
||||
|| tile_lower_right.y < view_top_left.y
|
||||
)
|
||||
{
|
||||
// current tile and dst_view do not overlap
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
// dst_view is overlapping the current tile
|
||||
|
||||
// next is to define the portion in the tile that needs to be copied
|
||||
|
||||
// get the whole image coordinates
|
||||
std::ptrdiff_t img_x0 = ( tile_top_left.x >= view_top_left.x ) ? tile_top_left.x : view_top_left.x;
|
||||
std::ptrdiff_t img_y0 = ( tile_top_left.y >= view_top_left.y ) ? tile_top_left.y : view_top_left.y;
|
||||
|
||||
std::ptrdiff_t img_x1 = ( tile_lower_right.x <= view_lower_right.x ) ? tile_lower_right.x : view_lower_right.x;
|
||||
std::ptrdiff_t img_y1 = ( tile_lower_right.y <= view_lower_right.y ) ? tile_lower_right.y : view_lower_right.y;
|
||||
|
||||
// convert to tile coordinates
|
||||
std::ptrdiff_t tile_x0 = img_x0 - x;
|
||||
std::ptrdiff_t tile_y0 = img_y0 - y;
|
||||
std::ptrdiff_t tile_x1 = img_x1 - x;
|
||||
std::ptrdiff_t tile_y1 = img_y1 - y;
|
||||
|
||||
BOOST_ASSERT(tile_x0 >= 0 && tile_y0 >= 0 && tile_x1 >= 0 && tile_y1 >= 0);
|
||||
BOOST_ASSERT(tile_x0 <= img_x1 && tile_y0 <= img_y1);
|
||||
BOOST_ASSERT(tile_x0 < tile_width && tile_y0 < tile_height && tile_x1 < tile_width && tile_y1 < tile_height);
|
||||
|
||||
std::ptrdiff_t tile_subimage_view_width = tile_x1 - tile_x0 + 1;
|
||||
std::ptrdiff_t tile_subimage_view_height = tile_y1 - tile_y0 + 1;
|
||||
|
||||
// convert to dst_view coordinates
|
||||
std::ptrdiff_t dst_x0 = img_x0 - subimage_x;
|
||||
std::ptrdiff_t dst_y0 = img_y0 - subimage_y;
|
||||
BOOST_ASSERT(dst_x0 >= 0 && dst_y0 >= 0);
|
||||
|
||||
View dst_subimage_view = subimage_view( dst_view
|
||||
, (int) dst_x0
|
||||
, (int) dst_y0
|
||||
, (int) tile_subimage_view_width
|
||||
, (int) tile_subimage_view_height
|
||||
);
|
||||
|
||||
// the row_buffer is a 1D array which represents a 2D image. We cannot
|
||||
// use interleaved_view here, since row_buffer could be bit_aligned.
|
||||
// Interleaved_view's fourth parameter "rowsize_in_bytes" doesn't work
|
||||
// for bit_aligned pixels.
|
||||
|
||||
for( std::ptrdiff_t dst_row = 0; dst_row < dst_subimage_view.height(); ++dst_row )
|
||||
{
|
||||
std::ptrdiff_t tile_row = dst_row + tile_y0;
|
||||
|
||||
// jump to the beginning of the current tile row
|
||||
it_t begin = row_buffer_helper.begin() + tile_row * tile_width;
|
||||
|
||||
begin += tile_x0;
|
||||
it_t end = begin + dst_subimage_view.width();
|
||||
|
||||
this->_cc_policy.read( begin
|
||||
, end
|
||||
, dst_subimage_view.row_begin( dst_row )
|
||||
);
|
||||
} //for
|
||||
}
|
||||
} // for
|
||||
} // for
|
||||
}
|
||||
|
||||
template< typename Buffer
|
||||
, typename View
|
||||
>
|
||||
void read_tiled_data_full( const View& dst_view
|
||||
, int plane
|
||||
)
|
||||
{
|
||||
///@todo: why is
|
||||
/// using row_buffer_helper_t = Buffer;
|
||||
/// not working? I get compiler error with MSVC10.
|
||||
/// read_stripped_data IS working.
|
||||
using row_buffer_helper_t = detail::row_buffer_helper_view<View>;
|
||||
|
||||
using it_t = typename row_buffer_helper_t::iterator_t;
|
||||
|
||||
tiff_image_width::type image_width = this->_info._width;
|
||||
tiff_image_height::type image_height = this->_info._height;
|
||||
|
||||
tiff_tile_width::type tile_width = this->_info._tile_width;
|
||||
tiff_tile_length::type tile_height = this->_info._tile_length;
|
||||
|
||||
row_buffer_helper_t row_buffer_helper(this->_io_dev.get_tile_size(), true );
|
||||
|
||||
for( unsigned int y = 0; y < image_height; y += tile_height )
|
||||
{
|
||||
for( unsigned int x = 0; x < image_width; x += tile_width )
|
||||
{
|
||||
uint32_t current_tile_width = ( x + tile_width < image_width ) ? tile_width : image_width - x;
|
||||
uint32_t current_tile_length = ( y + tile_height < image_height ) ? tile_height : image_height - y;
|
||||
|
||||
this->_io_dev.read_tile( row_buffer_helper.buffer()
|
||||
, x
|
||||
, y
|
||||
, 0
|
||||
, static_cast< tsample_t >( plane )
|
||||
);
|
||||
|
||||
View dst_subimage_view = subimage_view( dst_view
|
||||
, x
|
||||
, y
|
||||
, current_tile_width
|
||||
, current_tile_length
|
||||
);
|
||||
|
||||
// the row_buffer is a 1D array which represents a 2D image. We cannot
|
||||
// use interleaved_view here, since row_buffer could be bit_aligned.
|
||||
// Interleaved_view's fourth parameter "rowsize_in_bytes" doesn't work
|
||||
// for bit_aligned pixels.
|
||||
|
||||
for( int row = 0; row < dst_subimage_view.height(); ++row )
|
||||
{
|
||||
it_t begin = row_buffer_helper.begin() + row * tile_width;
|
||||
it_t end = begin + dst_subimage_view.width();
|
||||
|
||||
this->_cc_policy.read( begin
|
||||
, end
|
||||
, dst_subimage_view.row_begin( row )
|
||||
);
|
||||
} //for
|
||||
} // for
|
||||
} // for
|
||||
}
|
||||
|
||||
template< typename Buffer
|
||||
, typename View
|
||||
>
|
||||
void read_stripped_data( const View& dst_view
|
||||
, int plane )
|
||||
{
|
||||
using is_view_bit_aligned_t = typename is_bit_aligned<typename View::value_type>::type;
|
||||
|
||||
//using row_buffer_helper_t =detail::row_buffer_helper_view<View>;
|
||||
using row_buffer_helper_t = Buffer;
|
||||
using it_t = typename row_buffer_helper_t::iterator_t;
|
||||
|
||||
std::size_t size_to_allocate = buffer_size< typename View::value_type >( dst_view.width()
|
||||
, is_view_bit_aligned_t() );
|
||||
row_buffer_helper_t row_buffer_helper( size_to_allocate, true );
|
||||
|
||||
it_t begin = row_buffer_helper.begin();
|
||||
|
||||
it_t first = begin + this->_settings._top_left.x;
|
||||
it_t last = first + this->_settings._dim.x; // one after last element
|
||||
|
||||
// I don't think tiff allows for random access of row, that's why we need
|
||||
// to read and discard rows when reading subimages.
|
||||
skip_over_rows( row_buffer_helper.buffer()
|
||||
, plane
|
||||
);
|
||||
|
||||
std::ptrdiff_t row = this->_settings._top_left.y;
|
||||
std::ptrdiff_t row_end = row + this->_settings._dim.y;
|
||||
std::ptrdiff_t dst_row = 0;
|
||||
|
||||
for(
|
||||
; row < row_end
|
||||
; ++row, ++dst_row
|
||||
)
|
||||
{
|
||||
this->_io_dev.read_scanline( row_buffer_helper.buffer()
|
||||
, row
|
||||
, static_cast< tsample_t >( plane )
|
||||
);
|
||||
|
||||
this->_cc_policy.read( first
|
||||
, last
|
||||
, dst_view.row_begin( dst_row ));
|
||||
}
|
||||
}
|
||||
|
||||
template< typename Pixel >
|
||||
std::size_t buffer_size( std::size_t width
|
||||
, std::false_type // is_bit_aligned
|
||||
)
|
||||
{
|
||||
std::size_t scanline_size_in_bytes = this->_io_dev.get_scanline_size();
|
||||
|
||||
std::size_t element_size = sizeof( Pixel );
|
||||
|
||||
std::size_t ret = std::max( width
|
||||
, (( scanline_size_in_bytes + element_size - 1 ) / element_size )
|
||||
);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
template< typename Pixel >
|
||||
std::size_t buffer_size( std::size_t /* width */
|
||||
, std::true_type // is_bit_aligned
|
||||
)
|
||||
{
|
||||
return this->_io_dev.get_scanline_size();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
template < int K > friend struct plane_recursion;
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
|
||||
struct tiff_type_format_checker
|
||||
{
|
||||
tiff_type_format_checker( const image_read_info< tiff_tag >& info )
|
||||
: _info( info )
|
||||
{}
|
||||
|
||||
template< typename Image >
|
||||
bool apply()
|
||||
{
|
||||
using view_t = typename Image::view_t;
|
||||
|
||||
return is_allowed< view_t >( _info
|
||||
, std::true_type()
|
||||
);
|
||||
}
|
||||
|
||||
private:
|
||||
tiff_type_format_checker& operator=( const tiff_type_format_checker& ) { return *this; }
|
||||
|
||||
private:
|
||||
|
||||
const image_read_info< tiff_tag > _info;
|
||||
};
|
||||
|
||||
struct tiff_read_is_supported
|
||||
{
|
||||
template< typename View >
|
||||
struct apply : public is_read_supported< typename get_pixel_type< View >::type
|
||||
, tiff_tag
|
||||
>
|
||||
{};
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
|
||||
///
|
||||
/// Tiff Dynamic Image Reader
|
||||
///
|
||||
template< typename Device >
|
||||
class dynamic_image_reader< Device
|
||||
, tiff_tag
|
||||
>
|
||||
: public reader< Device
|
||||
, tiff_tag
|
||||
, detail::read_and_no_convert
|
||||
>
|
||||
{
|
||||
using parent_t = reader<Device, tiff_tag, detail::read_and_no_convert>;
|
||||
|
||||
public:
|
||||
|
||||
dynamic_image_reader( const Device& io_dev
|
||||
, const image_read_settings< tiff_tag >& settings
|
||||
)
|
||||
: parent_t( io_dev
|
||||
, settings
|
||||
)
|
||||
{}
|
||||
|
||||
template< typename ...Images >
|
||||
void apply( any_image< Images... >& images )
|
||||
{
|
||||
detail::tiff_type_format_checker format_checker( this->_info );
|
||||
|
||||
if( !construct_matched( images
|
||||
, format_checker
|
||||
))
|
||||
{
|
||||
io_error( "No matching image type between those of the given any_image and that of the file" );
|
||||
}
|
||||
else
|
||||
{
|
||||
this->init_image( images
|
||||
, this->_settings
|
||||
);
|
||||
|
||||
detail::dynamic_io_fnobj< detail::tiff_read_is_supported
|
||||
, parent_t
|
||||
> op( this );
|
||||
|
||||
apply_operation( view( images )
|
||||
, op
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
} // namespace gil
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,162 @@
|
||||
//
|
||||
// Copyright 2012 Christian Henning
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
#ifndef BOOST_GIL_EXTENSION_IO_TIFF_DETAIL_READER_BACKEND_HPP
|
||||
#define BOOST_GIL_EXTENSION_IO_TIFF_DETAIL_READER_BACKEND_HPP
|
||||
|
||||
#include <boost/gil/extension/io/tiff/tags.hpp>
|
||||
|
||||
namespace boost { namespace gil {
|
||||
|
||||
#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4512) //assignment operator could not be generated
|
||||
#endif
|
||||
|
||||
///
|
||||
/// TIFF Backend
|
||||
///
|
||||
template< typename Device >
|
||||
struct reader_backend< Device
|
||||
, tiff_tag
|
||||
>
|
||||
{
|
||||
public:
|
||||
|
||||
using format_tag_t = tiff_tag;
|
||||
|
||||
public:
|
||||
|
||||
reader_backend( const Device& io_dev
|
||||
, const image_read_settings< tiff_tag >& settings
|
||||
)
|
||||
: _io_dev ( io_dev )
|
||||
, _settings( settings )
|
||||
, _info()
|
||||
|
||||
, _scanline_length( 0 )
|
||||
|
||||
, _red ( nullptr )
|
||||
, _green( nullptr )
|
||||
, _blue ( nullptr )
|
||||
{
|
||||
init_multipage_read( settings );
|
||||
|
||||
read_header();
|
||||
|
||||
if( _settings._dim.x == 0 )
|
||||
{
|
||||
_settings._dim.x = _info._width;
|
||||
}
|
||||
|
||||
if( _settings._dim.y == 0 )
|
||||
{
|
||||
_settings._dim.y = _info._height;
|
||||
}
|
||||
}
|
||||
|
||||
void read_header()
|
||||
{
|
||||
io_error_if( _io_dev.template get_property<tiff_image_width> ( _info._width ) == false
|
||||
, "cannot read tiff tag." );
|
||||
io_error_if( _io_dev.template get_property<tiff_image_height> ( _info._height ) == false
|
||||
, "cannot read tiff tag." );
|
||||
io_error_if( _io_dev.template get_property<tiff_compression> ( _info._compression ) == false
|
||||
, "cannot read tiff tag." );
|
||||
io_error_if( _io_dev.template get_property<tiff_samples_per_pixel> ( _info._samples_per_pixel ) == false
|
||||
, "cannot read tiff tag." );
|
||||
io_error_if( _io_dev.template get_property<tiff_bits_per_sample> ( _info._bits_per_sample ) == false
|
||||
, "cannot read tiff tag." );
|
||||
io_error_if( _io_dev.template get_property<tiff_sample_format> ( _info._sample_format ) == false
|
||||
, "cannot read tiff tag." );
|
||||
io_error_if( _io_dev.template get_property<tiff_planar_configuration> ( _info._planar_configuration ) == false
|
||||
, "cannot read tiff tag." );
|
||||
io_error_if( _io_dev.template get_property<tiff_photometric_interpretation>( _info._photometric_interpretation ) == false
|
||||
, "cannot read tiff tag." );
|
||||
|
||||
_info._is_tiled = false;
|
||||
|
||||
// Tile tags
|
||||
if( _io_dev.is_tiled() )
|
||||
{
|
||||
_info._is_tiled = true;
|
||||
|
||||
io_error_if( !_io_dev.template get_property< tiff_tile_width >( _info._tile_width )
|
||||
, "cannot read tiff_tile_width tag." );
|
||||
io_error_if( !_io_dev.template get_property< tiff_tile_length >( _info._tile_length )
|
||||
, "cannot read tiff_tile_length tag." );
|
||||
}
|
||||
|
||||
io_error_if( _io_dev.template get_property<tiff_resolution_unit>( _info._resolution_unit) == false
|
||||
, "cannot read tiff tag");
|
||||
io_error_if( _io_dev. template get_property<tiff_x_resolution>( _info._x_resolution ) == false
|
||||
, "cannot read tiff tag" );
|
||||
io_error_if( _io_dev. template get_property<tiff_y_resolution>( _info._y_resolution ) == false
|
||||
, "cannot read tiff tag" );
|
||||
|
||||
/// optional and non-baseline properties below here
|
||||
_io_dev. template get_property <tiff_icc_profile> ( _info._icc_profile );
|
||||
}
|
||||
|
||||
/// Check if image is large enough.
|
||||
void check_image_size( const point_t& img_dim )
|
||||
{
|
||||
if( _settings._dim.x > 0 )
|
||||
{
|
||||
if( img_dim.x < _settings._dim.x ) { io_error( "Supplied image is too small" ); }
|
||||
}
|
||||
else
|
||||
{
|
||||
if( (tiff_image_width::type) img_dim.x < _info._width ) { io_error( "Supplied image is too small" ); }
|
||||
}
|
||||
|
||||
|
||||
if( _settings._dim.y > 0 )
|
||||
{
|
||||
if( img_dim.y < _settings._dim.y ) { io_error( "Supplied image is too small" ); }
|
||||
}
|
||||
else
|
||||
{
|
||||
if( (tiff_image_height::type) img_dim.y < _info._height ) { io_error( "Supplied image is too small" ); }
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
void init_multipage_read( const image_read_settings< tiff_tag >& settings )
|
||||
{
|
||||
if( settings._directory > 0 )
|
||||
{
|
||||
_io_dev.set_directory( settings._directory );
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
Device _io_dev;
|
||||
|
||||
image_read_settings< tiff_tag > _settings;
|
||||
image_read_info< tiff_tag > _info;
|
||||
|
||||
std::size_t _scanline_length;
|
||||
|
||||
// palette
|
||||
tiff_color_map::red_t _red;
|
||||
tiff_color_map::green_t _green;
|
||||
tiff_color_map::blue_t _blue;
|
||||
|
||||
rgb16_planar_view_t _palette;
|
||||
};
|
||||
|
||||
#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
} // namespace gil
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,447 @@
|
||||
//
|
||||
// Copyright 2007-2012 Christian Henning, Lubomir Bourdev
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
#ifndef BOOST_GIL_EXTENSION_IO_TIFF_DETAIL_SCANLINE_READ_HPP
|
||||
#define BOOST_GIL_EXTENSION_IO_TIFF_DETAIL_SCANLINE_READ_HPP
|
||||
|
||||
#include <boost/gil/extension/io/tiff/detail/device.hpp>
|
||||
#include <boost/gil/extension/io/tiff/detail/is_allowed.hpp>
|
||||
#include <boost/gil/extension/io/tiff/detail/reader_backend.hpp>
|
||||
|
||||
#include <boost/gil/io/base.hpp>
|
||||
#include <boost/gil/io/bit_operations.hpp>
|
||||
#include <boost/gil/io/conversion_policies.hpp>
|
||||
#include <boost/gil/io/device.hpp>
|
||||
#include <boost/gil/io/reader_base.hpp>
|
||||
#include <boost/gil/io/row_buffer_helper.hpp>
|
||||
#include <boost/gil/io/scanline_read_iterator.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
// taken from jpegxx - https://bitbucket.org/edd/jpegxx/src/ea2492a1a4a6/src/ijg_headers.hpp
|
||||
#ifndef BOOST_GIL_EXTENSION_IO_TIFF_C_LIB_COMPILED_AS_CPLUSPLUS
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <tiff.h>
|
||||
#include <tiffio.h>
|
||||
|
||||
#ifndef BOOST_GIL_EXTENSION_IO_TIFF_C_LIB_COMPILED_AS_CPLUSPLUS
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace boost { namespace gil {
|
||||
|
||||
///
|
||||
/// TIFF scanline reader
|
||||
///
|
||||
template< typename Device >
|
||||
class scanline_reader< Device
|
||||
, tiff_tag
|
||||
>
|
||||
: public reader_backend< Device
|
||||
, tiff_tag
|
||||
>
|
||||
{
|
||||
public:
|
||||
|
||||
using tag_t = tiff_tag;
|
||||
using backend_t = reader_backend<Device, tag_t>;
|
||||
using this_t = scanline_reader<Device, tag_t>;
|
||||
using iterator_t = scanline_read_iterator<this_t>;
|
||||
|
||||
scanline_reader( Device& device
|
||||
, const image_read_settings< tiff_tag >& settings
|
||||
)
|
||||
: backend_t( device
|
||||
, settings
|
||||
)
|
||||
{
|
||||
initialize();
|
||||
}
|
||||
|
||||
/// Read part of image defined by View and return the data.
|
||||
void read( byte_t* dst, int pos )
|
||||
{
|
||||
_read_function( this, dst, pos );
|
||||
}
|
||||
|
||||
/// Skip over a scanline.
|
||||
void skip( byte_t* dst, int pos )
|
||||
{
|
||||
this->_read_function( this, dst, pos );
|
||||
}
|
||||
|
||||
iterator_t begin() { return iterator_t( *this ); }
|
||||
iterator_t end() { return iterator_t( *this, this->_info._height ); }
|
||||
|
||||
private:
|
||||
|
||||
void initialize()
|
||||
{
|
||||
io_error_if( this->_info._is_tiled
|
||||
, "scanline_reader doesn't support tiled tiff images."
|
||||
);
|
||||
|
||||
if( this->_info._photometric_interpretation == PHOTOMETRIC_PALETTE )
|
||||
{
|
||||
|
||||
this->_scanline_length = this->_info._width
|
||||
* num_channels< rgb16_view_t >::value
|
||||
* sizeof( channel_type<rgb16_view_t>::type );
|
||||
|
||||
this->_io_dev.get_field_defaulted( this->_red
|
||||
, this->_green
|
||||
, this->_blue
|
||||
);
|
||||
|
||||
_buffer = std::vector< byte_t >( this->_io_dev.get_scanline_size() );
|
||||
|
||||
switch( this->_info._bits_per_sample )
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
using channel_t = channel_type<get_pixel_type<gray1_image_t::view_t>::type>::type;
|
||||
|
||||
int num_colors = channel_traits< channel_t >::max_value() + 1;
|
||||
|
||||
this->_palette = planar_rgb_view( num_colors
|
||||
, 1
|
||||
, this->_red
|
||||
, this->_green
|
||||
, this->_blue
|
||||
, sizeof(uint16_t) * num_colors
|
||||
);
|
||||
|
||||
_read_function = std::mem_fn(&this_t::read_1_bit_index_image);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 2:
|
||||
{
|
||||
using channel_t = channel_type<get_pixel_type<gray2_image_t::view_t>::type>::type;
|
||||
|
||||
int num_colors = channel_traits< channel_t >::max_value() + 1;
|
||||
|
||||
this->_palette = planar_rgb_view( num_colors
|
||||
, 1
|
||||
, this->_red
|
||||
, this->_green
|
||||
, this->_blue
|
||||
, sizeof(uint16_t) * num_colors
|
||||
);
|
||||
|
||||
_read_function = std::mem_fn(&this_t::read_2_bits_index_image);
|
||||
|
||||
break;
|
||||
}
|
||||
case 4:
|
||||
{
|
||||
using channel_t = channel_type<get_pixel_type<gray4_image_t::view_t>::type>::type;
|
||||
|
||||
int num_colors = channel_traits< channel_t >::max_value() + 1;
|
||||
|
||||
this->_palette = planar_rgb_view( num_colors
|
||||
, 1
|
||||
, this->_red
|
||||
, this->_green
|
||||
, this->_blue
|
||||
, sizeof(uint16_t) * num_colors
|
||||
);
|
||||
|
||||
_read_function = std::mem_fn(&this_t::read_4_bits_index_image);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 8:
|
||||
{
|
||||
using channel_t = channel_type<get_pixel_type<gray8_image_t::view_t>::type>::type;
|
||||
|
||||
int num_colors = channel_traits< channel_t >::max_value() + 1;
|
||||
|
||||
this->_palette = planar_rgb_view( num_colors
|
||||
, 1
|
||||
, this->_red
|
||||
, this->_green
|
||||
, this->_blue
|
||||
, sizeof(uint16_t) * num_colors
|
||||
);
|
||||
|
||||
_read_function = std::mem_fn(&this_t::read_8_bits_index_image);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 16:
|
||||
{
|
||||
using channel_t = channel_type<get_pixel_type<gray16_image_t::view_t>::type>::type;
|
||||
|
||||
int num_colors = channel_traits< channel_t >::max_value() + 1;
|
||||
|
||||
this->_palette = planar_rgb_view( num_colors
|
||||
, 1
|
||||
, this->_red
|
||||
, this->_green
|
||||
, this->_blue
|
||||
, sizeof(uint16_t) * num_colors
|
||||
);
|
||||
|
||||
_read_function = std::mem_fn(&this_t::read_16_bits_index_image);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 24:
|
||||
{
|
||||
using channel_t = channel_type<get_pixel_type<gray24_image_t::view_t>::type>::type;
|
||||
|
||||
int num_colors = channel_traits< channel_t >::max_value() + 1;
|
||||
|
||||
this->_palette = planar_rgb_view( num_colors
|
||||
, 1
|
||||
, this->_red
|
||||
, this->_green
|
||||
, this->_blue
|
||||
, sizeof(uint16_t) * num_colors
|
||||
);
|
||||
|
||||
_read_function = std::mem_fn(&this_t::read_24_bits_index_image);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 32:
|
||||
{
|
||||
using channel_t = channel_type<get_pixel_type<gray32_image_t::view_t>::type>::type;
|
||||
|
||||
int num_colors = channel_traits< channel_t >::max_value() + 1;
|
||||
|
||||
this->_palette = planar_rgb_view( num_colors
|
||||
, 1
|
||||
, this->_red
|
||||
, this->_green
|
||||
, this->_blue
|
||||
, sizeof(uint16_t) * num_colors
|
||||
);
|
||||
|
||||
_read_function = std::mem_fn(&this_t::read_32_bits_index_image);
|
||||
|
||||
break;
|
||||
}
|
||||
default: { io_error( "Not supported palette " ); }
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this->_scanline_length = this->_io_dev.get_scanline_size();
|
||||
|
||||
if( this->_info._planar_configuration == PLANARCONFIG_SEPARATE )
|
||||
{
|
||||
io_error( "scanline_reader doesn't support planar tiff images." );
|
||||
}
|
||||
else if( this->_info._planar_configuration == PLANARCONFIG_CONTIG )
|
||||
{
|
||||
|
||||
// the read_data function needs to know what gil type the source image is
|
||||
// to have the default color converter function correctly
|
||||
|
||||
switch( this->_info._photometric_interpretation )
|
||||
{
|
||||
case PHOTOMETRIC_MINISWHITE:
|
||||
case PHOTOMETRIC_MINISBLACK:
|
||||
{
|
||||
switch( this->_info._bits_per_sample )
|
||||
{
|
||||
case 1:
|
||||
case 2:
|
||||
case 4:
|
||||
case 6:
|
||||
case 8:
|
||||
case 10:
|
||||
case 12:
|
||||
case 14:
|
||||
case 16:
|
||||
case 24:
|
||||
case 32: { _read_function = std::mem_fn(&this_t::read_row); break; }
|
||||
default: { io_error( "Image type is not supported." ); }
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case PHOTOMETRIC_RGB:
|
||||
{
|
||||
switch( this->_info._samples_per_pixel )
|
||||
{
|
||||
case 3:
|
||||
{
|
||||
switch( this->_info._bits_per_sample )
|
||||
{
|
||||
case 2:
|
||||
case 4:
|
||||
case 8:
|
||||
case 10:
|
||||
case 12:
|
||||
case 14:
|
||||
case 16:
|
||||
case 24:
|
||||
case 32: { _read_function = std::mem_fn(&this_t::read_row); break; }
|
||||
default: { io_error( "Image type is not supported." ); }
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 4:
|
||||
{
|
||||
switch( this->_info._bits_per_sample )
|
||||
{
|
||||
case 2:
|
||||
case 4:
|
||||
case 8:
|
||||
case 10:
|
||||
case 12:
|
||||
case 14:
|
||||
case 16:
|
||||
case 24:
|
||||
case 32: { _read_function = std::mem_fn(&this_t::read_row); break; }
|
||||
default: { io_error( "Image type is not supported." ); }
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default: { io_error( "Image type is not supported." ); }
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case PHOTOMETRIC_SEPARATED: // CYMK
|
||||
{
|
||||
switch( this->_info._bits_per_sample )
|
||||
{
|
||||
case 2:
|
||||
case 4:
|
||||
case 8:
|
||||
case 10:
|
||||
case 12:
|
||||
case 14:
|
||||
case 16:
|
||||
case 24:
|
||||
case 32: { _read_function = std::mem_fn(&this_t::read_row); break; }
|
||||
default: { io_error( "Image type is not supported." ); }
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default: { io_error( "Image type is not supported." ); }
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
io_error( "Wrong planar configuration setting." );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template< typename Src_View >
|
||||
void read_n_bits_row( byte_t* dst, int pos )
|
||||
{
|
||||
using dst_view_t = rgb16_view_t;
|
||||
|
||||
this->_io_dev.read_scanline( _buffer
|
||||
, pos
|
||||
, 0
|
||||
);
|
||||
|
||||
Src_View src_view = interleaved_view( this->_info._width
|
||||
, 1
|
||||
, (typename Src_View::x_iterator) &_buffer.front()
|
||||
, this->_scanline_length
|
||||
);
|
||||
|
||||
dst_view_t dst_view = interleaved_view( this->_info._width
|
||||
, 1
|
||||
, (typename dst_view_t::value_type*) dst
|
||||
, num_channels< dst_view_t >::value * 2 * this->_info._width
|
||||
);
|
||||
|
||||
|
||||
typename Src_View::x_iterator src_it = src_view.row_begin( 0 );
|
||||
typename dst_view_t::x_iterator dst_it = dst_view.row_begin( 0 );
|
||||
|
||||
for( dst_view_t::x_coord_t i = 0
|
||||
; i < this->_info._width
|
||||
; ++i, src_it++, dst_it++
|
||||
)
|
||||
{
|
||||
auto const c = static_cast<std::uint16_t>(get_color(*src_it, gray_color_t()));
|
||||
*dst_it = this->_palette[c];
|
||||
}
|
||||
}
|
||||
|
||||
void read_1_bit_index_image( byte_t* dst, int pos )
|
||||
{
|
||||
read_n_bits_row< gray1_image_t::view_t >( dst, pos );
|
||||
}
|
||||
|
||||
void read_2_bits_index_image( byte_t* dst, int pos )
|
||||
{
|
||||
read_n_bits_row< gray2_image_t::view_t >( dst, pos );
|
||||
}
|
||||
|
||||
void read_4_bits_index_image( byte_t* dst, int pos )
|
||||
{
|
||||
read_n_bits_row< gray4_image_t::view_t >( dst, pos );
|
||||
}
|
||||
|
||||
void read_8_bits_index_image( byte_t* dst, int pos )
|
||||
{
|
||||
read_n_bits_row< gray8_image_t::view_t >( dst, pos );
|
||||
}
|
||||
|
||||
void read_16_bits_index_image( byte_t* dst, int pos )
|
||||
{
|
||||
read_n_bits_row< gray16_image_t::view_t >( dst, pos );
|
||||
}
|
||||
|
||||
void read_24_bits_index_image( byte_t* dst, int pos )
|
||||
{
|
||||
read_n_bits_row< gray24_image_t::view_t >( dst, pos );
|
||||
}
|
||||
|
||||
void read_32_bits_index_image( byte_t* dst, int pos )
|
||||
{
|
||||
read_n_bits_row< gray32_image_t::view_t >( dst, pos );
|
||||
}
|
||||
|
||||
void read_row(byte_t* dst, int pos )
|
||||
{
|
||||
this->_io_dev.read_scanline( dst
|
||||
, pos
|
||||
, 0
|
||||
);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
std::vector< byte_t> _buffer;
|
||||
detail::mirror_bits<std::vector<byte_t>, std::true_type> _mirror_bites;
|
||||
std::function<void(this_t*, byte_t*, int)> _read_function;
|
||||
};
|
||||
|
||||
} // namespace gil
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,49 @@
|
||||
//
|
||||
// Copyright 2007-2008 Christian Henning, Andreas Pokorny, Lubomir Bourdev
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
#ifndef BOOST_GIL_EXTENSION_IO_TIFF_DETAIL_SUPPORTED_TYPES_HPP
|
||||
#define BOOST_GIL_EXTENSION_IO_TIFF_DETAIL_SUPPORTED_TYPES_HPP
|
||||
|
||||
#include <boost/gil/extension/io/tiff/tags.hpp>
|
||||
|
||||
#include <boost/gil/channel.hpp>
|
||||
#include <boost/gil/color_base.hpp>
|
||||
#include <boost/gil/io/base.hpp>
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
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>
|
||||
: std::integral_constant<bool, detail::tiff_read_support::is_supported>
|
||||
{};
|
||||
|
||||
template<typename Pixel>
|
||||
struct is_write_supported<Pixel, tiff_tag>
|
||||
: std::integral_constant<bool, detail::tiff_write_support::is_supported>
|
||||
{};
|
||||
|
||||
}} // namespace boost::gil
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,451 @@
|
||||
//
|
||||
// Copyright 2007-2012 Christian Henning, Lubomir Bourdev
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
#ifndef BOOST_GIL_EXTENSION_IO_TIFF_DETAIL_WRITE_HPP
|
||||
#define BOOST_GIL_EXTENSION_IO_TIFF_DETAIL_WRITE_HPP
|
||||
|
||||
#include <boost/gil/extension/io/tiff/tags.hpp>
|
||||
#include <boost/gil/extension/io/tiff/detail/writer_backend.hpp>
|
||||
#include <boost/gil/extension/io/tiff/detail/device.hpp>
|
||||
|
||||
#include <boost/gil/premultiply.hpp>
|
||||
#include <boost/gil/io/base.hpp>
|
||||
#include <boost/gil/io/device.hpp>
|
||||
#include <boost/gil/io/dynamic_io_new.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
extern "C" {
|
||||
#include "tiff.h"
|
||||
#include "tiffio.h"
|
||||
}
|
||||
|
||||
namespace boost { namespace gil {
|
||||
|
||||
#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4512) //assignment operator could not be generated
|
||||
#endif
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename PixelReference>
|
||||
struct my_interleaved_pixel_iterator_type_from_pixel_reference
|
||||
{
|
||||
private:
|
||||
using pixel_t = typename std::remove_reference<PixelReference>::type::value_type;
|
||||
|
||||
public:
|
||||
using type = typename iterator_type_from_pixel
|
||||
<
|
||||
pixel_t,
|
||||
false,
|
||||
false,
|
||||
true
|
||||
>::type;
|
||||
};
|
||||
|
||||
|
||||
template< typename Channel
|
||||
, typename Layout
|
||||
, bool Mutable
|
||||
>
|
||||
struct my_interleaved_pixel_iterator_type_from_pixel_reference< const bit_aligned_pixel_reference< byte_t
|
||||
, Channel
|
||||
, Layout
|
||||
, Mutable
|
||||
>
|
||||
>
|
||||
: public iterator_type_from_pixel< const bit_aligned_pixel_reference< uint8_t
|
||||
, Channel
|
||||
, Layout
|
||||
, Mutable
|
||||
>
|
||||
,false
|
||||
,false
|
||||
,true
|
||||
> {};
|
||||
|
||||
struct tiff_write_is_supported
|
||||
{
|
||||
template< typename View >
|
||||
struct apply
|
||||
: public is_write_supported< typename get_pixel_type< View >::type
|
||||
, tiff_tag
|
||||
>
|
||||
{};
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
///
|
||||
/// TIFF Writer
|
||||
///
|
||||
template < typename Device, typename Log >
|
||||
class writer< Device
|
||||
, tiff_tag
|
||||
, Log
|
||||
>
|
||||
: public writer_backend< Device
|
||||
, tiff_tag
|
||||
>
|
||||
{
|
||||
private:
|
||||
using backend_t = writer_backend<Device, tiff_tag>;
|
||||
|
||||
public:
|
||||
|
||||
writer( const Device& io_dev
|
||||
, const image_write_info< tiff_tag >& info
|
||||
)
|
||||
: backend_t( io_dev
|
||||
, info
|
||||
)
|
||||
{}
|
||||
|
||||
template<typename View>
|
||||
void apply( const View& view )
|
||||
{
|
||||
write_view( view );
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
template< typename View >
|
||||
void write_view( const View& view )
|
||||
{
|
||||
using pixel_t = typename View::value_type;
|
||||
// get the type of the first channel (heterogeneous pixels might be broken for now!)
|
||||
using channel_t = typename channel_traits<typename element_type<pixel_t>::type>::value_type;
|
||||
tiff_bits_per_sample::type bits_per_sample = detail::unsigned_integral_num_bits< channel_t >::value;
|
||||
|
||||
tiff_samples_per_pixel::type samples_per_pixel = num_channels< pixel_t >::value;
|
||||
|
||||
this->write_header( view );
|
||||
|
||||
if( this->_info._is_tiled == false )
|
||||
{
|
||||
write_data( view
|
||||
, (view.width() * samples_per_pixel * bits_per_sample + 7) / 8
|
||||
, typename is_bit_aligned< pixel_t >::type()
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
tiff_tile_width::type tw = this->_info._tile_width;
|
||||
tiff_tile_length::type th = this->_info._tile_length;
|
||||
|
||||
if(!this->_io_dev.check_tile_size( tw, th ))
|
||||
{
|
||||
io_error( "Tile sizes need to be multiples of 16." );
|
||||
}
|
||||
|
||||
// tile related tags
|
||||
this->_io_dev.template set_property<tiff_tile_width> ( tw );
|
||||
this->_io_dev.template set_property<tiff_tile_length>( th );
|
||||
|
||||
write_tiled_data( view
|
||||
, tw
|
||||
, th
|
||||
, typename is_bit_aligned< pixel_t >::type()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
|
||||
template<typename View>
|
||||
void write_bit_aligned_view_to_dev( const View& view
|
||||
, const std::size_t row_size_in_bytes
|
||||
, const std::true_type& // has_alpha
|
||||
)
|
||||
{
|
||||
byte_vector_t row( row_size_in_bytes );
|
||||
|
||||
using x_it_t = typename View::x_iterator;
|
||||
x_it_t row_it = x_it_t( &(*row.begin()));
|
||||
|
||||
auto pm_view = premultiply_view <typename View:: value_type> (view);
|
||||
|
||||
for( typename View::y_coord_t y = 0; y < pm_view.height(); ++y )
|
||||
{
|
||||
std::copy( pm_view.row_begin( y )
|
||||
, pm_view.row_end( y )
|
||||
, row_it
|
||||
);
|
||||
|
||||
|
||||
this->_io_dev.write_scaline( row
|
||||
, (uint32) y
|
||||
, 0
|
||||
);
|
||||
|
||||
// @todo: do optional bit swapping here if you need to...
|
||||
}
|
||||
}
|
||||
|
||||
template<typename View>
|
||||
void write_bit_aligned_view_to_dev( const View& view
|
||||
, const std::size_t row_size_in_bytes
|
||||
, const std::false_type& // has_alpha
|
||||
)
|
||||
{
|
||||
byte_vector_t row( row_size_in_bytes );
|
||||
|
||||
using x_it_t = typename View::x_iterator;
|
||||
x_it_t row_it = x_it_t( &(*row.begin()));
|
||||
|
||||
for( typename View::y_coord_t y = 0; y < view.height(); ++y )
|
||||
{
|
||||
std::copy( view.row_begin( y )
|
||||
, view.row_end( y )
|
||||
, row_it
|
||||
);
|
||||
|
||||
|
||||
this->_io_dev.write_scaline( row
|
||||
, (uint32) y
|
||||
, 0
|
||||
);
|
||||
|
||||
// @todo: do optional bit swapping here if you need to...
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////
|
||||
|
||||
template< typename View >
|
||||
void write_data( const View& view
|
||||
, std::size_t row_size_in_bytes
|
||||
, const std::true_type& // bit_aligned
|
||||
)
|
||||
{
|
||||
using colour_space_t = typename color_space_type<typename View::value_type>::type;
|
||||
using has_alpha_t = mp11::mp_contains<colour_space_t, 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 std::true_type& // bit_aligned
|
||||
)
|
||||
{
|
||||
byte_vector_t row( this->_io_dev.get_tile_size() );
|
||||
|
||||
using x_it_t = typename View::x_iterator;
|
||||
x_it_t row_it = x_it_t( &(*row.begin()));
|
||||
|
||||
internal_write_tiled_data(view, tw, th, row, row_it);
|
||||
}
|
||||
|
||||
template< typename View >
|
||||
void write_data( const View& view
|
||||
, std::size_t
|
||||
, const std::false_type& // 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 std::false_type& // bit_aligned
|
||||
)
|
||||
{
|
||||
byte_vector_t row( this->_io_dev.get_tile_size() );
|
||||
|
||||
using x_iterator = typename detail::my_interleaved_pixel_iterator_type_from_pixel_reference<typename View::reference>::type;
|
||||
x_iterator row_it = x_iterator( &(*row.begin()));
|
||||
|
||||
internal_write_tiled_data(view, tw, th, row, row_it);
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////
|
||||
|
||||
template< typename View
|
||||
, typename IteratorType
|
||||
>
|
||||
void write_tiled_view_to_dev( const View& view
|
||||
, IteratorType it
|
||||
, const std::true_type& // 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 std::false_type& // has_alpha
|
||||
)
|
||||
{
|
||||
std::copy( view.begin()
|
||||
, view.end()
|
||||
, it
|
||||
);
|
||||
}
|
||||
|
||||
/////////////////////////////
|
||||
|
||||
|
||||
|
||||
template< typename View,
|
||||
typename IteratorType
|
||||
>
|
||||
void internal_write_tiled_data( const View& view
|
||||
, tiff_tile_width::type tw
|
||||
, tiff_tile_length::type th
|
||||
, byte_vector_t& row
|
||||
, IteratorType it
|
||||
)
|
||||
{
|
||||
std::ptrdiff_t i = 0, j = 0;
|
||||
View tile_subimage_view;
|
||||
while( i < view.height() )
|
||||
{
|
||||
while( j < view.width() )
|
||||
{
|
||||
if( j + tw < view.width() && i + th < view.height() )
|
||||
{
|
||||
// a tile is fully included in the image: just copy values
|
||||
tile_subimage_view = subimage_view( view
|
||||
, static_cast< int >( j )
|
||||
, static_cast< int >( i )
|
||||
, static_cast< int >( tw )
|
||||
, static_cast< int >( th )
|
||||
);
|
||||
|
||||
using colour_space_t = typename color_space_type<typename View::value_type>::type;
|
||||
using has_alpha_t = mp11::mp_contains<colour_space_t, 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
|
||||
>
|
||||
{
|
||||
using parent_t = writer<Device, tiff_tag>;
|
||||
|
||||
public:
|
||||
|
||||
dynamic_image_writer( const Device& io_dev
|
||||
, const image_write_info< tiff_tag >& info
|
||||
)
|
||||
: parent_t( io_dev
|
||||
, info
|
||||
)
|
||||
{}
|
||||
|
||||
template< typename ...Views >
|
||||
void apply( const any_image_view< Views... >& views )
|
||||
{
|
||||
detail::dynamic_io_fnobj< detail::tiff_write_is_supported
|
||||
, parent_t
|
||||
> op( this );
|
||||
|
||||
apply_operation( views, op );
|
||||
}
|
||||
};
|
||||
|
||||
#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
} // namespace gil
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,137 @@
|
||||
//
|
||||
// Copyright 2012 Christian Henning
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
#ifndef BOOST_GIL_EXTENSION_IO_TIFF_DETAIL_WRITER_BACKEND_HPP
|
||||
#define BOOST_GIL_EXTENSION_IO_TIFF_DETAIL_WRITER_BACKEND_HPP
|
||||
|
||||
#include <boost/gil/extension/io/tiff/tags.hpp>
|
||||
#include <boost/gil/extension/io/tiff/detail/device.hpp>
|
||||
|
||||
#include <boost/gil/detail/mp11.hpp>
|
||||
|
||||
namespace boost { namespace gil {
|
||||
|
||||
#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4512) //assignment operator could not be generated
|
||||
#endif
|
||||
|
||||
///
|
||||
/// TIFF Writer Backend
|
||||
///
|
||||
template< typename Device >
|
||||
struct writer_backend< Device
|
||||
, tiff_tag
|
||||
>
|
||||
{
|
||||
public:
|
||||
|
||||
using format_tag_t = tiff_tag;
|
||||
|
||||
public:
|
||||
|
||||
writer_backend( const Device& io_dev
|
||||
, const image_write_info< tiff_tag >& info
|
||||
)
|
||||
: _io_dev( io_dev )
|
||||
, _info( info )
|
||||
{}
|
||||
|
||||
protected:
|
||||
|
||||
template< typename View >
|
||||
void write_header( const View& view )
|
||||
{
|
||||
using pixel_t = typename View::value_type;
|
||||
|
||||
// get the type of the first channel (heterogeneous pixels might be broken for now!)
|
||||
using channel_t = typename channel_traits<typename element_type<pixel_t>::type>::value_type;
|
||||
using color_space_t = typename color_space_type<View>::type;
|
||||
|
||||
if(! this->_info._photometric_interpretation_user_defined )
|
||||
{
|
||||
// write photometric interpretion - Warning: This value is rather
|
||||
// subjective. The user should better set this value itself. There
|
||||
// is no way to decide if a image is PHOTOMETRIC_MINISWHITE or
|
||||
// PHOTOMETRIC_MINISBLACK. If the user has not manually set it, then
|
||||
// this writer will assume PHOTOMETRIC_MINISBLACK for gray_t images,
|
||||
// PHOTOMETRIC_RGB for rgb_t images, and PHOTOMETRIC_SEPARATED (as
|
||||
// is conventional) for cmyk_t images.
|
||||
this->_info._photometric_interpretation = detail::photometric_interpretation< color_space_t >::value;
|
||||
}
|
||||
|
||||
// write dimensions
|
||||
tiff_image_width::type width = (tiff_image_width::type) view.width();
|
||||
tiff_image_height::type height = (tiff_image_height::type) view.height();
|
||||
|
||||
this->_io_dev.template set_property< tiff_image_width >( width );
|
||||
this->_io_dev.template set_property< tiff_image_height >( height );
|
||||
|
||||
// write planar configuration
|
||||
this->_io_dev.template set_property<tiff_planar_configuration>( this->_info._planar_configuration );
|
||||
|
||||
// write samples per pixel
|
||||
tiff_samples_per_pixel::type samples_per_pixel = num_channels< pixel_t >::value;
|
||||
this->_io_dev.template set_property<tiff_samples_per_pixel>( samples_per_pixel );
|
||||
|
||||
if /*constexpr*/ (mp11::mp_contains<color_space_t, alpha_t>::value)
|
||||
{
|
||||
std:: vector <uint16_t> extra_samples {EXTRASAMPLE_ASSOCALPHA};
|
||||
this->_io_dev.template set_property<tiff_extra_samples>( extra_samples );
|
||||
}
|
||||
|
||||
// write bits per sample
|
||||
// @todo: Settings this value usually requires to write for each sample the bit
|
||||
// value seperately in case they are different, like rgb556.
|
||||
tiff_bits_per_sample::type bits_per_sample = detail::unsigned_integral_num_bits< channel_t >::value;
|
||||
this->_io_dev.template set_property<tiff_bits_per_sample>( bits_per_sample );
|
||||
|
||||
// write sample format
|
||||
tiff_sample_format::type sampl_format = detail::sample_format< channel_t >::value;
|
||||
this->_io_dev.template set_property<tiff_sample_format>( sampl_format );
|
||||
|
||||
// write photometric format
|
||||
this->_io_dev.template set_property<tiff_photometric_interpretation>( this->_info._photometric_interpretation );
|
||||
|
||||
// write compression
|
||||
this->_io_dev.template set_property<tiff_compression>( this->_info._compression );
|
||||
|
||||
// write orientation
|
||||
this->_io_dev.template set_property<tiff_orientation>( this->_info._orientation );
|
||||
|
||||
// write rows per strip
|
||||
this->_io_dev.template set_property<tiff_rows_per_strip>( this->_io_dev.get_default_strip_size() );
|
||||
|
||||
// write x, y resolution and units
|
||||
this->_io_dev.template set_property<tiff_resolution_unit>( this->_info._resolution_unit );
|
||||
this->_io_dev.template set_property<tiff_x_resolution>( this->_info._x_resolution );
|
||||
this->_io_dev.template set_property<tiff_y_resolution>( this->_info._y_resolution );
|
||||
|
||||
/// Optional and / or non-baseline tags below here
|
||||
|
||||
// write ICC colour profile, if it's there
|
||||
// http://www.color.org/icc_specs2.xalter
|
||||
if ( 0 != this->_info._icc_profile.size())
|
||||
this->_io_dev.template set_property<tiff_icc_profile>( this->_info._icc_profile );
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
|
||||
Device _io_dev;
|
||||
|
||||
image_write_info< tiff_tag > _info;
|
||||
};
|
||||
|
||||
#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
} // namespace gil
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
160
install/boost_1_75_0/include/boost/gil/extension/io/tiff/old.hpp
Normal file
160
install/boost_1_75_0/include/boost/gil/extension/io/tiff/old.hpp
Normal file
@@ -0,0 +1,160 @@
|
||||
//
|
||||
// Copyright 2007-2008 Christian Henning
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
#ifndef BOOST_GIL_EXTENSION_IO_TIFF_OLD_HPP
|
||||
#define BOOST_GIL_EXTENSION_IO_TIFF_OLD_HPP
|
||||
|
||||
#include <boost/gil/extension/io/tiff.hpp>
|
||||
|
||||
namespace boost { namespace gil {
|
||||
|
||||
/// \ingroup TIFF_IO
|
||||
/// \brief Returns the width and height of the TIFF file at the specified location.
|
||||
/// Throws std::ios_base::failure if the location does not correspond to a valid TIFF file
|
||||
template<typename String>
|
||||
inline point_t tiff_read_dimensions(String const& filename)
|
||||
{
|
||||
using backend_t = typename get_reader_backend<String, tiff_tag>::type;
|
||||
backend_t backend = read_image_info(filename, tiff_tag());
|
||||
return { backend._info._width, backend._info._height };
|
||||
}
|
||||
|
||||
/// \ingroup TIFF_IO
|
||||
/// \brief Loads the image specified by the given tiff image file name into the given view.
|
||||
/// Triggers a compile assert if the view color space and channel depth are not supported by the TIFF library or by the I/O extension.
|
||||
/// Throws std::ios_base::failure if the file is not a valid TIFF file, or if its color space or channel depth are not
|
||||
/// compatible with the ones specified by View, or if its dimensions don't match the ones of the view.
|
||||
template< typename String
|
||||
, typename View
|
||||
>
|
||||
inline
|
||||
void tiff_read_view( const String& filename
|
||||
, const View& view
|
||||
)
|
||||
{
|
||||
read_view( filename
|
||||
, view
|
||||
, tiff_tag()
|
||||
);
|
||||
}
|
||||
|
||||
/// \ingroup TIFF_IO
|
||||
/// \brief Allocates a new image whose dimensions are determined by the given tiff image file, and loads the pixels into it.
|
||||
/// Triggers a compile assert if the image color space or channel depth are not supported by the TIFF library or by the I/O extension.
|
||||
/// Throws std::ios_base::failure if the file is not a valid TIFF file, or if its color space or channel depth are not
|
||||
/// compatible with the ones specified by Image
|
||||
template< typename String
|
||||
, typename Image
|
||||
>
|
||||
inline
|
||||
void tiff_read_image( const String& filename
|
||||
, Image& img
|
||||
)
|
||||
{
|
||||
read_image( filename
|
||||
, img
|
||||
, tiff_tag()
|
||||
);
|
||||
}
|
||||
|
||||
/// \ingroup TIFF_IO
|
||||
/// \brief Loads and color-converts the image specified by the given tiff image file name into the given view.
|
||||
/// Throws std::ios_base::failure if the file is not a valid TIFF file, or if its dimensions don't match the ones of the view.
|
||||
template< typename String
|
||||
, typename View
|
||||
, typename CC
|
||||
>
|
||||
inline
|
||||
void tiff_read_and_convert_view( const String& filename
|
||||
, const View& view
|
||||
, CC cc
|
||||
)
|
||||
{
|
||||
read_and_convert_view( filename
|
||||
, view
|
||||
, cc
|
||||
, tiff_tag()
|
||||
);
|
||||
}
|
||||
|
||||
/// \ingroup TIFF_IO
|
||||
/// \brief Loads and color-converts the image specified by the given tiff image file name into the given view.
|
||||
/// Throws std::ios_base::failure if the file is not a valid TIFF file, or if its dimensions don't match the ones of the view.
|
||||
template< typename String
|
||||
, typename View
|
||||
>
|
||||
inline
|
||||
void tiff_read_and_convert_view( const String& filename
|
||||
, const View& view
|
||||
)
|
||||
{
|
||||
read_and_convert_view( filename
|
||||
, view
|
||||
, tiff_tag()
|
||||
);
|
||||
}
|
||||
|
||||
/// \ingroup TIFF_IO
|
||||
/// \brief Allocates a new image whose dimensions are determined by the given tiff image file, loads and color-converts the pixels into it.
|
||||
/// Throws std::ios_base::failure if the file is not a valid TIFF file
|
||||
template< typename String
|
||||
, typename Image
|
||||
, typename CC
|
||||
>
|
||||
inline
|
||||
void tiff_read_and_convert_image( const String& filename
|
||||
, Image& img
|
||||
, CC cc
|
||||
)
|
||||
{
|
||||
read_and_convert_image( filename
|
||||
, img
|
||||
, cc
|
||||
, tiff_tag()
|
||||
);
|
||||
}
|
||||
|
||||
/// \ingroup TIFF_IO
|
||||
/// \brief Allocates a new image whose dimensions are determined by the given tiff image file, loads and color-converts the pixels into it.
|
||||
/// Throws std::ios_base::failure if the file is not a valid TIFF file
|
||||
template< typename String
|
||||
, typename Image
|
||||
>
|
||||
inline
|
||||
void tiff_read_and_convert_image( const String filename
|
||||
, Image& img
|
||||
)
|
||||
{
|
||||
read_and_convert_image( filename
|
||||
, img
|
||||
, tiff_tag()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/// \ingroup TIFF_IO
|
||||
/// \brief Saves the view to a tiff file specified by the given tiff image file name.
|
||||
/// Triggers a compile assert if the view color space and channel depth are not supported by the TIFF library or by the I/O extension.
|
||||
/// Throws std::ios_base::failure if it fails to create the file.
|
||||
template< typename String
|
||||
, typename View
|
||||
>
|
||||
inline
|
||||
void tiff_write_view( const String& filename
|
||||
, const View& view
|
||||
)
|
||||
{
|
||||
write_view( filename
|
||||
, view
|
||||
, tiff_tag()
|
||||
);
|
||||
}
|
||||
|
||||
} // namespace gil
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,30 @@
|
||||
//
|
||||
// Copyright 2007-2008 Christian Henning
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
#ifndef BOOST_GIL_EXTENSION_IO_TIFF_READ_HPP
|
||||
#define BOOST_GIL_EXTENSION_IO_TIFF_READ_HPP
|
||||
|
||||
#define BOOST_GIL_EXTENSION_IO_TIFF_READ_ENABLED // TODO: Document, explain, review
|
||||
|
||||
#include <boost/gil/extension/io/tiff/tags.hpp>
|
||||
#include <boost/gil/extension/io/tiff/detail/read.hpp>
|
||||
#include <boost/gil/extension/io/tiff/detail/scanline_read.hpp>
|
||||
#include <boost/gil/extension/io/tiff/detail/supported_types.hpp>
|
||||
|
||||
#include <boost/gil/io/get_reader.hpp>
|
||||
#include <boost/gil/io/make_backend.hpp>
|
||||
#include <boost/gil/io/make_dynamic_image_reader.hpp>
|
||||
#include <boost/gil/io/make_reader.hpp>
|
||||
#include <boost/gil/io/make_scanline_reader.hpp>
|
||||
#include <boost/gil/io/read_and_convert_image.hpp>
|
||||
#include <boost/gil/io/read_and_convert_view.hpp>
|
||||
#include <boost/gil/io/read_image.hpp>
|
||||
#include <boost/gil/io/read_image_info.hpp>
|
||||
#include <boost/gil/io/read_view.hpp>
|
||||
#include <boost/gil/io/scanline_read_iterator.hpp>
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,351 @@
|
||||
//
|
||||
// Copyright 2007-2008 Christian Henning, Andreas Pokorny, Lubomir Bourdev
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
#ifndef BOOST_GIL_EXTENSION_IO_TIFF_TAGS_HPP
|
||||
#define BOOST_GIL_EXTENSION_IO_TIFF_TAGS_HPP
|
||||
|
||||
#include <boost/gil/extension/io/tiff/detail/log.hpp>
|
||||
|
||||
#include <boost/gil/detail/mp11.hpp>
|
||||
#include <boost/gil/io/base.hpp>
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
// taken from jpegxx - https://bitbucket.org/edd/jpegxx/src/ea2492a1a4a6/src/ijg_headers.hpp
|
||||
#ifndef BOOST_GIL_EXTENSION_IO_TIFF_C_LIB_COMPILED_AS_CPLUSPLUS
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <tiff.h>
|
||||
|
||||
#ifndef BOOST_GIL_EXTENSION_IO_TIFF_C_LIB_COMPILED_AS_CPLUSPLUS
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace boost { namespace gil {
|
||||
|
||||
/// Defines tiff tag.
|
||||
struct tiff_tag : format_tag {};
|
||||
|
||||
/// http://www.awaresystems.be/imaging/tiff/tifftags/baseline.html
|
||||
/// http://www.remotesensing.org/libtiff/
|
||||
|
||||
/// TIFF property base class
|
||||
template< typename T, int Value >
|
||||
struct tiff_property_base : property_base< T >
|
||||
{
|
||||
/// Tag, needed when reading or writing image properties.
|
||||
static const ttag_t tag = Value;
|
||||
/// The list of argument types used in the interface of LibTIFF
|
||||
/// for
|
||||
/// this property:
|
||||
/// http://www.remotesensing.org/libtiff/man/TIFFGetField.3tiff.html
|
||||
/// http://www.remotesensing.org/libtiff/man/TIFFSetField.3tiff.html
|
||||
using arg_types = mp11::mp_list<typename property_base<unsigned short>::type>;
|
||||
};
|
||||
|
||||
/// baseline tags
|
||||
|
||||
/// Defines type for new subfile property.
|
||||
struct tiff_new_subfile_type : tiff_property_base< uint32_t, TIFFTAG_SUBFILETYPE > {};
|
||||
|
||||
/// Defines type for subfile property.
|
||||
struct tiff_subfile_type : tiff_property_base< uint16_t, TIFFTAG_OSUBFILETYPE > {};
|
||||
|
||||
/// Defines type for image width property.
|
||||
struct tiff_image_width : tiff_property_base< uint32_t, TIFFTAG_IMAGEWIDTH > {};
|
||||
|
||||
/// Defines type for image height property.
|
||||
struct tiff_image_height : tiff_property_base< uint32_t, TIFFTAG_IMAGELENGTH > {};
|
||||
|
||||
/// Defines type for bits per sample property.
|
||||
struct tiff_bits_per_sample : tiff_property_base< uint16_t, TIFFTAG_BITSPERSAMPLE > {};
|
||||
|
||||
/// Defines type for compression property.
|
||||
struct tiff_compression : tiff_property_base< uint16_t, TIFFTAG_COMPRESSION > {};
|
||||
|
||||
/// Defines type for photometric interpretation property.
|
||||
struct tiff_photometric_interpretation : tiff_property_base< uint16_t, TIFFTAG_PHOTOMETRIC > {};
|
||||
|
||||
/// Defines type for threshold property.
|
||||
struct tiff_thresholding : tiff_property_base< uint16_t, TIFFTAG_THRESHHOLDING > {};
|
||||
|
||||
/// Defines type for cell width property.
|
||||
struct tiff_cell_width : tiff_property_base< uint16_t, TIFFTAG_CELLWIDTH > {};
|
||||
|
||||
/// Defines type for cell length property.
|
||||
struct tiff_cell_length : tiff_property_base< uint16_t, TIFFTAG_CELLLENGTH > {};
|
||||
|
||||
/// Defines type for fill order property.
|
||||
struct tiff_fill_order : tiff_property_base< std::string, TIFFTAG_FILLORDER > {};
|
||||
|
||||
/// Defines type for image description.
|
||||
struct tiff_image_description : tiff_property_base< std::string, TIFFTAG_IMAGEDESCRIPTION > {};
|
||||
|
||||
/// Defines type for make property.
|
||||
struct tiff_make : tiff_property_base< std::string, TIFFTAG_MAKE > {};
|
||||
|
||||
/// Defines type for model property.
|
||||
struct tiff_model : tiff_property_base< std::string, TIFFTAG_MODEL > {};
|
||||
|
||||
/// Defines type for image orientation.
|
||||
struct tiff_orientation : tiff_property_base< uint16_t, TIFFTAG_ORIENTATION > {};
|
||||
|
||||
/// Defines type for samples per pixel property.
|
||||
struct tiff_samples_per_pixel : tiff_property_base< uint16_t, TIFFTAG_SAMPLESPERPIXEL > {};
|
||||
|
||||
/// Defines type for rows per strip property.
|
||||
struct tiff_rows_per_strip : tiff_property_base< uint32_t, TIFFTAG_ROWSPERSTRIP > {};
|
||||
|
||||
/// Defines type for min sample property.
|
||||
struct tiff_min_sample_value : tiff_property_base< uint16_t, TIFFTAG_MINSAMPLEVALUE > {};
|
||||
|
||||
/// Defines type for max sample property.
|
||||
struct tiff_max_sample_value : tiff_property_base< uint16_t, TIFFTAG_MAXSAMPLEVALUE > {};
|
||||
|
||||
/// Defines type for x resolution property.
|
||||
struct tiff_x_resolution : tiff_property_base< float, TIFFTAG_XRESOLUTION > {};
|
||||
|
||||
/// Defines type for y resolution property.
|
||||
struct tiff_y_resolution : tiff_property_base< float, TIFFTAG_YRESOLUTION > {};
|
||||
|
||||
/// Defines type for resolution unit property.
|
||||
enum class tiff_resolution_unit_value: std:: uint16_t {
|
||||
NONE = RESUNIT_NONE,
|
||||
INCH = RESUNIT_INCH,
|
||||
CENTIMETER = RESUNIT_CENTIMETER
|
||||
};
|
||||
|
||||
struct tiff_resolution_unit : tiff_property_base< tiff_resolution_unit_value, TIFFTAG_RESOLUTIONUNIT > {};
|
||||
|
||||
/// Defines type for planar configuration property.
|
||||
struct tiff_planar_configuration : tiff_property_base< uint16_t, TIFFTAG_PLANARCONFIG > {};
|
||||
|
||||
/// Defines type for gray response unit property.
|
||||
struct tiff_gray_response_unit : tiff_property_base< uint16_t, TIFFTAG_GRAYRESPONSEUNIT > {};
|
||||
|
||||
/// Defines type for gray response curve property.
|
||||
struct tiff_gray_response_curve : tiff_property_base< uint16_t*, TIFFTAG_GRAYRESPONSECURVE > {};
|
||||
|
||||
/// Defines type for software vendor property.
|
||||
struct tiff_software : tiff_property_base< std::string, TIFFTAG_SOFTWARE > {};
|
||||
|
||||
/// Defines type for date time property.
|
||||
struct tiff_date_time : tiff_property_base< std::string, TIFFTAG_DATETIME > {};
|
||||
|
||||
/// Defines type for artist information property.
|
||||
struct tiff_artist : tiff_property_base< std::string, TIFFTAG_ARTIST > {};
|
||||
|
||||
/// Defines type for host computer property.
|
||||
struct tiff_host_computer : tiff_property_base< std::string, TIFFTAG_HOSTCOMPUTER > {};
|
||||
|
||||
/// Helper structure for reading a color mapper.
|
||||
struct tiff_color_map
|
||||
{
|
||||
using red_t = uint16_t *;
|
||||
using green_t = uint16_t *;
|
||||
using blue_t = uint16_t *;
|
||||
|
||||
static const unsigned int tag = TIFFTAG_COLORMAP;
|
||||
};
|
||||
|
||||
/// Defines type for extra samples property.
|
||||
struct tiff_extra_samples : tiff_property_base<std::vector<uint16_t>, TIFFTAG_EXTRASAMPLES>
|
||||
{
|
||||
using arg_types = mp11::mp_list<uint16_t, uint16_t const*>;
|
||||
};
|
||||
|
||||
/// Defines type for copyright property.
|
||||
struct tiff_copyright : tiff_property_base< std::string, TIFFTAG_COPYRIGHT > {};
|
||||
|
||||
/// non-baseline tags
|
||||
|
||||
/// Defines type for sample format property.
|
||||
struct tiff_sample_format : tiff_property_base< uint16_t, TIFFTAG_SAMPLEFORMAT > {};
|
||||
|
||||
/// Defines type for indexed property.
|
||||
/// Not supported yet
|
||||
//struct tiff_indexed : tiff_property_base< bool, TIFFTAG_INDEXED > {};
|
||||
|
||||
/// Tile related tags
|
||||
|
||||
/// Defines type for a (not) tiled tiff image
|
||||
struct tiff_is_tiled : tiff_property_base< bool, false > {};
|
||||
|
||||
/// Defines type for tile width
|
||||
struct tiff_tile_width : tiff_property_base< long, TIFFTAG_TILEWIDTH > {};
|
||||
|
||||
/// Defines type for tile length
|
||||
struct tiff_tile_length : tiff_property_base< long, TIFFTAG_TILELENGTH > {};
|
||||
|
||||
/// Defines the page to read in a multipage tiff file.
|
||||
struct tiff_directory : property_base< tdir_t >
|
||||
{
|
||||
using default_value = std::integral_constant<type, 0>;
|
||||
};
|
||||
|
||||
/// Non-baseline tags
|
||||
|
||||
/// Defines type for icc profile property.
|
||||
struct tiff_icc_profile : tiff_property_base<std::vector<uint8_t>, TIFFTAG_ICCPROFILE>
|
||||
{
|
||||
using arg_types = mp11::mp_list<uint32_t, void const*>;
|
||||
};
|
||||
|
||||
/// Read information for tiff images.
|
||||
///
|
||||
/// The structure is returned when using read_image_info.
|
||||
template<>
|
||||
struct image_read_info< tiff_tag >
|
||||
{
|
||||
image_read_info()
|
||||
: _width( 0 )
|
||||
, _height( 0 )
|
||||
|
||||
, _compression( COMPRESSION_NONE )
|
||||
|
||||
, _bits_per_sample( 0 )
|
||||
, _samples_per_pixel( 0 )
|
||||
, _sample_format( SAMPLEFORMAT_UINT )
|
||||
|
||||
, _planar_configuration( PLANARCONFIG_CONTIG )
|
||||
|
||||
, _photometric_interpretation( PHOTOMETRIC_MINISWHITE )
|
||||
|
||||
, _is_tiled( false )
|
||||
|
||||
, _tile_width ( 0 )
|
||||
, _tile_length( 0 )
|
||||
|
||||
, _x_resolution( 1 )
|
||||
, _y_resolution( 1 )
|
||||
, _resolution_unit( tiff_resolution_unit_value:: NONE )
|
||||
|
||||
, _icc_profile( )
|
||||
{}
|
||||
|
||||
/// The number of rows of pixels in the image.
|
||||
tiff_image_width::type _width;
|
||||
/// The number of columns in the image, i.e., the number of pixels per row.
|
||||
tiff_image_height::type _height;
|
||||
|
||||
/// Compression scheme used on the image data.
|
||||
tiff_compression::type _compression;
|
||||
|
||||
/// Number of bits per component.
|
||||
tiff_bits_per_sample::type _bits_per_sample;
|
||||
/// The number of components per pixel.
|
||||
tiff_samples_per_pixel::type _samples_per_pixel;
|
||||
/// Specifies how to interpret each data sample in a pixel.
|
||||
tiff_sample_format::type _sample_format;
|
||||
|
||||
/// How the components of each pixel are stored.
|
||||
tiff_planar_configuration::type _planar_configuration;
|
||||
|
||||
/// The color space of the image data.
|
||||
tiff_photometric_interpretation::type _photometric_interpretation;
|
||||
|
||||
/// Is tiled?
|
||||
tiff_is_tiled::type _is_tiled;
|
||||
/// Tile width
|
||||
tiff_tile_width::type _tile_width;
|
||||
/// Tile length
|
||||
tiff_tile_length::type _tile_length;
|
||||
|
||||
tiff_x_resolution::type _x_resolution;
|
||||
tiff_y_resolution::type _y_resolution;
|
||||
tiff_resolution_unit::type _resolution_unit;
|
||||
|
||||
tiff_icc_profile:: type _icc_profile;
|
||||
};
|
||||
|
||||
/// Read settings for tiff images.
|
||||
///
|
||||
/// The structure can be used for all read_xxx functions, except read_image_info.
|
||||
template<>
|
||||
struct image_read_settings< tiff_tag > : public image_read_settings_base
|
||||
{
|
||||
/// Default constructor
|
||||
image_read_settings< tiff_tag >()
|
||||
: image_read_settings_base()
|
||||
, _directory( tiff_directory::default_value::value )
|
||||
{}
|
||||
|
||||
/// Constructor
|
||||
/// \param top_left Top left coordinate for reading partial image.
|
||||
/// \param dim Dimensions for reading partial image.
|
||||
/// \param directory Defines the page to read in a multipage tiff file.
|
||||
image_read_settings( const point_t& top_left
|
||||
, const point_t& dim
|
||||
, const tiff_directory::type& directory = tiff_directory::default_value::value
|
||||
)
|
||||
: image_read_settings_base( top_left
|
||||
, dim
|
||||
)
|
||||
, _directory( directory )
|
||||
{}
|
||||
|
||||
/// Defines the page to read in a multipage tiff file.
|
||||
tiff_directory::type _directory;
|
||||
};
|
||||
|
||||
/// Write settings for tiff images.
|
||||
///
|
||||
/// The structure can be used for all write_xxx functions, except write_image_info.
|
||||
template< typename Log >
|
||||
struct image_write_info< tiff_tag, Log >
|
||||
{
|
||||
/// Default constructor
|
||||
image_write_info()
|
||||
: _photometric_interpretation ( PHOTOMETRIC_MINISBLACK )
|
||||
, _photometric_interpretation_user_defined( false )
|
||||
|
||||
, _compression ( COMPRESSION_NONE )
|
||||
, _orientation ( ORIENTATION_TOPLEFT )
|
||||
, _planar_configuration ( PLANARCONFIG_CONTIG )
|
||||
, _is_tiled ( false )
|
||||
, _tile_width ( 0 )
|
||||
, _tile_length ( 0 )
|
||||
, _x_resolution ( 1 )
|
||||
, _y_resolution ( 1 )
|
||||
, _resolution_unit ( tiff_resolution_unit_value::NONE )
|
||||
, _icc_profile ( )
|
||||
{}
|
||||
|
||||
/// The color space of the image data.
|
||||
tiff_photometric_interpretation::type _photometric_interpretation;
|
||||
bool _photometric_interpretation_user_defined;
|
||||
|
||||
/// Compression scheme used on the image data.
|
||||
tiff_compression::type _compression;
|
||||
/// The orientation of the image with respect to the rows and columns.
|
||||
tiff_orientation::type _orientation;
|
||||
/// How the components of each pixel are stored.
|
||||
tiff_planar_configuration::type _planar_configuration;
|
||||
|
||||
/// Is the image tiled?
|
||||
tiff_is_tiled::type _is_tiled;
|
||||
/// Tiles width
|
||||
tiff_tile_width::type _tile_width;
|
||||
/// Tiles length
|
||||
tiff_tile_length::type _tile_length;
|
||||
|
||||
/// x, y resolution
|
||||
tiff_x_resolution::type _x_resolution;
|
||||
tiff_y_resolution::type _y_resolution;
|
||||
tiff_resolution_unit::type _resolution_unit;
|
||||
|
||||
tiff_icc_profile:: type _icc_profile;
|
||||
|
||||
/// A log to transcript error and warning messages issued by libtiff.
|
||||
Log _log;
|
||||
};
|
||||
|
||||
} // namespace gil
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,19 @@
|
||||
//
|
||||
// Copyright 2007-2008 Christian Henning
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
#ifndef BOOST_GIL_EXTENSION_IO_TIFF_WRITE_HPP
|
||||
#define BOOST_GIL_EXTENSION_IO_TIFF_WRITE_HPP
|
||||
|
||||
#include <boost/gil/extension/io/tiff/tags.hpp>
|
||||
#include <boost/gil/extension/io/tiff/detail/supported_types.hpp>
|
||||
#include <boost/gil/extension/io/tiff/detail/write.hpp>
|
||||
|
||||
#include <boost/gil/io/make_dynamic_image_writer.hpp>
|
||||
#include <boost/gil/io/make_writer.hpp>
|
||||
#include <boost/gil/io/write_view.hpp>
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,94 @@
|
||||
//
|
||||
// Copyright 2005-2007 Adobe Systems Incorporated
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
#ifndef BOOST_GIL_EXTENSION_NUMERIC_AFFINE_HPP
|
||||
#define BOOST_GIL_EXTENSION_NUMERIC_AFFINE_HPP
|
||||
|
||||
#include <boost/gil/point.hpp>
|
||||
|
||||
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(point<T> const& 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(point<T> const& 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
|
||||
point<F> operator*(point<T> const& p, matrix3x2<F> const& m)
|
||||
{
|
||||
return { 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>>
|
||||
{
|
||||
using result_type = point<F>;
|
||||
};
|
||||
|
||||
template <typename F, typename F2>
|
||||
BOOST_FORCEINLINE
|
||||
point<F> transform(matrix3x2<F> const& mat, point<F2> const& src)
|
||||
{
|
||||
return src * mat;
|
||||
}
|
||||
|
||||
}} // namespace boost::gil
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,442 @@
|
||||
//
|
||||
// Copyright 2005-2007 Adobe Systems Incorporated
|
||||
// Copyright 2019 Pranam Lashkari <plashkari628@gmail.com>
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
#ifndef BOOST_GIL_EXTENSION_NUMERIC_ALGORITHM_HPP
|
||||
#define BOOST_GIL_EXTENSION_NUMERIC_ALGORITHM_HPP
|
||||
|
||||
#include <boost/gil/extension/numeric/pixel_numeric_operations.hpp>
|
||||
|
||||
#include <boost/gil/metafunctions.hpp>
|
||||
#include <boost/gil/pixel_iterator.hpp>
|
||||
#include <boost/gil/image.hpp>
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include <numeric>
|
||||
#include <type_traits>
|
||||
|
||||
namespace boost { namespace gil {
|
||||
|
||||
/// \brief Reference proxy associated with a type that has a \p "reference" member type alias.
|
||||
///
|
||||
/// The reference proxy is the reference type, but with stripped-out C++ reference.
|
||||
/// Models PixelConcept.
|
||||
template <typename T>
|
||||
struct pixel_proxy : std::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
|
||||
auto assign_pixels(SrcIterator src, SrcIterator src_end, DstIterator dst) -> DstIterator
|
||||
{
|
||||
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 T,
|
||||
class BinaryOperation1,
|
||||
class BinaryOperation2
|
||||
>
|
||||
static T apply(
|
||||
InputIterator1 first1,
|
||||
InputIterator2 first2, T 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 T,
|
||||
class BinaryOperation1,
|
||||
class BinaryOperation2
|
||||
>
|
||||
static T apply(
|
||||
InputIterator1 first1,
|
||||
InputIterator2 first2,
|
||||
T 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 T,
|
||||
class BinaryOperation1,
|
||||
class BinaryOperation2
|
||||
>
|
||||
BOOST_FORCEINLINE
|
||||
T inner_product_k(
|
||||
InputIterator1 first1,
|
||||
InputIterator2 first2,
|
||||
T 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 cross-correlation with a variable-size kernel
|
||||
template
|
||||
<
|
||||
typename PixelAccum,
|
||||
typename SrcIterator,
|
||||
typename KernelIterator,
|
||||
typename Size,
|
||||
typename DstIterator
|
||||
>
|
||||
inline
|
||||
auto correlate_pixels_n(
|
||||
SrcIterator src_begin,
|
||||
SrcIterator src_end,
|
||||
KernelIterator kernel_begin,
|
||||
Size kernel_size,
|
||||
DstIterator dst_begin)
|
||||
-> DstIterator
|
||||
{
|
||||
using src_pixel_ref_t = typename pixel_proxy
|
||||
<
|
||||
typename std::iterator_traits<SrcIterator>::value_type
|
||||
>::type;
|
||||
using dst_pixel_ref_t = typename pixel_proxy
|
||||
<
|
||||
typename std::iterator_traits<DstIterator>::value_type
|
||||
>::type;
|
||||
using kernel_value_t = typename std::iterator_traits<KernelIterator>::value_type;
|
||||
|
||||
PixelAccum accum_zero;
|
||||
pixel_zeros_t<PixelAccum>()(accum_zero);
|
||||
while (src_begin != src_end)
|
||||
{
|
||||
pixel_assigns_t<PixelAccum, dst_pixel_ref_t>()(
|
||||
std::inner_product(
|
||||
src_begin,
|
||||
src_begin + kernel_size,
|
||||
kernel_begin,
|
||||
accum_zero,
|
||||
pixel_plus_t<PixelAccum, PixelAccum, PixelAccum>(),
|
||||
pixel_multiplies_scalar_t<src_pixel_ref_t, kernel_value_t, PixelAccum>()),
|
||||
*dst_begin);
|
||||
|
||||
++src_begin;
|
||||
++dst_begin;
|
||||
}
|
||||
return dst_begin;
|
||||
}
|
||||
|
||||
/// \brief 1D un-guarded cross-correlation with a fixed-size kernel
|
||||
template
|
||||
<
|
||||
std::size_t Size,
|
||||
typename PixelAccum,
|
||||
typename SrcIterator,
|
||||
typename KernelIterator,
|
||||
typename DstIterator
|
||||
>
|
||||
inline
|
||||
auto correlate_pixels_k(
|
||||
SrcIterator src_begin,
|
||||
SrcIterator src_end,
|
||||
KernelIterator kernel_begin,
|
||||
DstIterator dst_begin)
|
||||
-> DstIterator
|
||||
{
|
||||
using src_pixel_ref_t = typename pixel_proxy
|
||||
<
|
||||
typename std::iterator_traits<SrcIterator>::value_type
|
||||
>::type;
|
||||
using dst_pixel_ref_t = typename pixel_proxy
|
||||
<
|
||||
typename std::iterator_traits<DstIterator>::value_type
|
||||
>::type;
|
||||
using kernel_type = typename std::iterator_traits<KernelIterator>::value_type;
|
||||
|
||||
PixelAccum accum_zero;
|
||||
pixel_zeros_t<PixelAccum>()(accum_zero);
|
||||
while (src_begin != src_end)
|
||||
{
|
||||
pixel_assigns_t<PixelAccum, dst_pixel_ref_t>()(
|
||||
inner_product_k<Size>(
|
||||
src_begin,
|
||||
kernel_begin,
|
||||
accum_zero,
|
||||
pixel_plus_t<PixelAccum, PixelAccum, PixelAccum>(),
|
||||
pixel_multiplies_scalar_t<src_pixel_ref_t, 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
|
||||
/// \tparam PixelAccum - TODO
|
||||
/// \tparam SrcView Models ImageViewConcept
|
||||
/// \tparam DstView Models MutableImageViewConcept
|
||||
template <typename PixelAccum, typename SrcView, typename Scalar, typename DstView>
|
||||
inline
|
||||
void view_multiplies_scalar(SrcView const& src_view, Scalar const& scalar, DstView const& dst_view)
|
||||
{
|
||||
static_assert(std::is_scalar<Scalar>::value, "Scalar is not scalar");
|
||||
BOOST_ASSERT(src_view.dimensions() == dst_view.dimensions());
|
||||
using src_pixel_ref_t = typename pixel_proxy<typename SrcView::value_type>::type;
|
||||
using dst_pixel_ref_t = typename pixel_proxy<typename DstView::value_type>::type;
|
||||
using y_coord_t = typename SrcView::y_coord_t;
|
||||
|
||||
y_coord_t const height = src_view.height();
|
||||
for (y_coord_t y = 0; y < height; ++y)
|
||||
{
|
||||
typename SrcView::x_iterator it_src = src_view.row_begin(y);
|
||||
typename DstView::x_iterator it_dst = dst_view.row_begin(y);
|
||||
typename SrcView::x_iterator it_src_end = src_view.row_end(y);
|
||||
while (it_src != it_src_end)
|
||||
{
|
||||
pixel_assigns_t<PixelAccum, dst_pixel_ref_t>()(
|
||||
pixel_multiplies_scalar_t<src_pixel_ref_t, Scalar, PixelAccum>()(*it_src, scalar),
|
||||
*it_dst);
|
||||
|
||||
++it_src;
|
||||
++it_dst;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// \ingroup ImageAlgorithms
|
||||
/// \brief Boundary options for image boundary extension
|
||||
enum class boundary_option
|
||||
{
|
||||
output_ignore, /// do nothing to the output
|
||||
output_zero, /// set the output to zero
|
||||
extend_padded, /// assume the source boundaries to be padded already
|
||||
extend_zero, /// assume the source boundaries to be zero
|
||||
extend_constant /// assume the source boundaries to be the boundary value
|
||||
};
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template <typename SrcView, typename RltView>
|
||||
void extend_row_impl(
|
||||
SrcView const& src_view,
|
||||
RltView result_view,
|
||||
std::size_t extend_count,
|
||||
boundary_option option)
|
||||
{
|
||||
std::ptrdiff_t extend_count_ = static_cast<std::ptrdiff_t>(extend_count);
|
||||
|
||||
if (option == boundary_option::extend_constant)
|
||||
{
|
||||
for (std::ptrdiff_t i = 0; i < result_view.height(); i++)
|
||||
{
|
||||
if(i >= extend_count_ && i < extend_count_ + src_view.height())
|
||||
{
|
||||
assign_pixels(
|
||||
src_view.row_begin(i - extend_count_),
|
||||
src_view.row_end(i - extend_count_),
|
||||
result_view.row_begin(i)
|
||||
);
|
||||
}
|
||||
else if(i < extend_count_)
|
||||
{
|
||||
assign_pixels(src_view.row_begin(0), src_view.row_end(0), result_view.row_begin(i));
|
||||
}
|
||||
else
|
||||
{
|
||||
assign_pixels(
|
||||
src_view.row_begin(src_view.height() - 1),
|
||||
src_view.row_end(src_view.height() - 1),
|
||||
result_view.row_begin(i)
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
else if (option == boundary_option::extend_zero)
|
||||
{
|
||||
typename SrcView::value_type acc_zero;
|
||||
pixel_zeros_t<typename SrcView::value_type>()(acc_zero);
|
||||
|
||||
for (std::ptrdiff_t i = 0; i < result_view.height(); i++)
|
||||
{
|
||||
if (i >= extend_count_ && i < extend_count_ + src_view.height())
|
||||
{
|
||||
assign_pixels(
|
||||
src_view.row_begin(i - extend_count_),
|
||||
src_view.row_end(i - extend_count_),
|
||||
result_view.row_begin(i)
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::fill_n(result_view.row_begin(i), result_view.width(), acc_zero);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (option == boundary_option::extend_padded)
|
||||
{
|
||||
auto original_view = subimage_view(
|
||||
src_view,
|
||||
0,
|
||||
-extend_count,
|
||||
src_view.width(),
|
||||
src_view.height() + (2 * extend_count)
|
||||
);
|
||||
for (std::ptrdiff_t i = 0; i < result_view.height(); i++)
|
||||
{
|
||||
assign_pixels(
|
||||
original_view.row_begin(i),
|
||||
original_view.row_end(i),
|
||||
result_view.row_begin(i)
|
||||
);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_ASSERT_MSG(false, "Invalid boundary option");
|
||||
}
|
||||
}
|
||||
|
||||
} //namespace detail
|
||||
|
||||
|
||||
/// \brief adds new row at top and bottom.
|
||||
/// Image padding introduces new pixels around the edges of an image.
|
||||
/// The border provides space for annotations or acts as a boundary when using advanced filtering techniques.
|
||||
/// \tparam SrcView Models ImageViewConcept
|
||||
/// \tparam extend_count number of rows to be added each side
|
||||
/// \tparam option - TODO
|
||||
template <typename SrcView>
|
||||
auto extend_row(
|
||||
SrcView const& src_view,
|
||||
std::size_t extend_count,
|
||||
boundary_option option
|
||||
) -> typename gil::image<typename SrcView::value_type>
|
||||
{
|
||||
typename gil::image<typename SrcView::value_type>
|
||||
result_img(src_view.width(), src_view.height() + (2 * extend_count));
|
||||
|
||||
auto result_view = view(result_img);
|
||||
detail::extend_row_impl(src_view, result_view, extend_count, option);
|
||||
return result_img;
|
||||
}
|
||||
|
||||
|
||||
/// \brief adds new column at left and right.
|
||||
/// Image padding introduces new pixels around the edges of an image.
|
||||
/// The border provides space for annotations or acts as a boundary when using advanced filtering techniques.
|
||||
/// \tparam SrcView Models ImageViewConcept
|
||||
/// \tparam extend_count number of columns to be added each side
|
||||
/// \tparam option - TODO
|
||||
template <typename SrcView>
|
||||
auto extend_col(
|
||||
SrcView const& src_view,
|
||||
std::size_t extend_count,
|
||||
boundary_option option
|
||||
) -> typename gil::image<typename SrcView::value_type>
|
||||
{
|
||||
auto src_view_rotate = rotated90cw_view(src_view);
|
||||
|
||||
typename gil::image<typename SrcView::value_type>
|
||||
result_img(src_view.width() + (2 * extend_count), src_view.height());
|
||||
|
||||
auto result_view = rotated90cw_view(view(result_img));
|
||||
detail::extend_row_impl(src_view_rotate, result_view, extend_count, option);
|
||||
return result_img;
|
||||
}
|
||||
|
||||
/// \brief adds new row and column at all sides.
|
||||
/// Image padding introduces new pixels around the edges of an image.
|
||||
/// The border provides space for annotations or acts as a boundary when using advanced filtering techniques.
|
||||
/// \tparam SrcView Models ImageViewConcept
|
||||
/// \tparam extend_count number of rows/column to be added each side
|
||||
/// \tparam option - TODO
|
||||
template <typename SrcView>
|
||||
auto extend_boundary(
|
||||
SrcView const& src_view,
|
||||
std::size_t extend_count,
|
||||
boundary_option option
|
||||
) -> typename gil::image<typename SrcView::value_type>
|
||||
{
|
||||
if (option == boundary_option::extend_padded)
|
||||
{
|
||||
typename gil::image<typename SrcView::value_type>
|
||||
result_img(src_view.width()+(2 * extend_count), src_view.height()+(2 * extend_count));
|
||||
typename gil::image<typename SrcView::value_type>::view_t result_view = view(result_img);
|
||||
|
||||
auto original_view = subimage_view(
|
||||
src_view,
|
||||
-extend_count,
|
||||
-extend_count,
|
||||
src_view.width() + (2 * extend_count),
|
||||
src_view.height() + (2 * extend_count)
|
||||
);
|
||||
|
||||
for (std::ptrdiff_t i = 0; i < result_view.height(); i++)
|
||||
{
|
||||
assign_pixels(
|
||||
original_view.row_begin(i),
|
||||
original_view.row_end(i),
|
||||
result_view.row_begin(i)
|
||||
);
|
||||
}
|
||||
|
||||
return result_img;
|
||||
}
|
||||
|
||||
auto auxilary_img = extend_col(src_view, extend_count, option);
|
||||
return extend_row(view(auxilary_img), extend_count, option);
|
||||
}
|
||||
|
||||
}} // namespace boost::gil
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,252 @@
|
||||
//
|
||||
// Copyright 2005-2007 Adobe Systems Incorporated
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
#ifndef BOOST_GIL_EXTENSION_NUMERIC_CHANNEL_NUMERIC_OPERATIONS_HPP
|
||||
#define BOOST_GIL_EXTENSION_NUMERIC_CHANNEL_NUMERIC_OPERATIONS_HPP
|
||||
|
||||
#include <boost/gil/channel.hpp>
|
||||
|
||||
namespace boost { namespace gil {
|
||||
|
||||
// Function objects and utilities for channel-wise numeric operations.
|
||||
//
|
||||
// List of currently defined functors:
|
||||
// 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 (=)
|
||||
|
||||
/// \ingroup ChannelNumericOperations
|
||||
/// \brief Arithmetic operation of addition of two channel values.
|
||||
/// \note This is a generic implementation; user should specialize it for better performance.
|
||||
template <typename Channel1, typename Channel2, typename ChannelResult>
|
||||
struct channel_plus_t
|
||||
{
|
||||
using ChannelRef1 = typename channel_traits<Channel1>::const_reference;
|
||||
using ChannelRef2 = typename channel_traits<Channel2>::const_reference;
|
||||
static_assert(std::is_convertible<ChannelRef1, ChannelResult>::value,
|
||||
"ChannelRef1 not convertible to ChannelResult");
|
||||
static_assert(std::is_convertible<ChannelRef2, ChannelResult>::value,
|
||||
"ChannelRef2 not convertible to ChannelResult");
|
||||
|
||||
/// \param ch1 - first of the two addends (augend).
|
||||
/// \param ch2 - second of the two addends.
|
||||
auto operator()(ChannelRef1 ch1, ChannelRef2 ch2) const -> ChannelResult
|
||||
{
|
||||
return ChannelResult(ch1) + ChannelResult(ch2);
|
||||
}
|
||||
};
|
||||
|
||||
/// \ingroup ChannelNumericOperations
|
||||
/// \brief Arithmetic operation of subtraction of two channel values.
|
||||
/// \note This is a generic implementation; user should specialize it for better performance.
|
||||
template <typename Channel1, typename Channel2, typename ChannelResult>
|
||||
struct channel_minus_t
|
||||
{
|
||||
using ChannelRef1 = typename channel_traits<Channel1>::const_reference;
|
||||
using ChannelRef2 = typename channel_traits<Channel2>::const_reference;
|
||||
static_assert(std::is_convertible<ChannelRef1, ChannelResult>::value,
|
||||
"ChannelRef1 not convertible to ChannelResult");
|
||||
static_assert(std::is_convertible<ChannelRef2, ChannelResult>::value,
|
||||
"ChannelRef2 not convertible to ChannelResult");
|
||||
|
||||
/// \param ch1 - minuend operand of the subtraction.
|
||||
/// \param ch2 - subtrahend operand of the subtraction.
|
||||
auto operator()(ChannelRef1 ch1, ChannelRef2 ch2) const -> ChannelResult
|
||||
{
|
||||
return ChannelResult(ch1) - ChannelResult(ch2);
|
||||
}
|
||||
};
|
||||
|
||||
/// \ingroup ChannelNumericOperations
|
||||
/// \brief Arithmetic operation of multiplication of two channel values.
|
||||
/// \note This is a generic implementation; user should specialize it for better performance.
|
||||
template <typename Channel1, typename Channel2, typename ChannelResult>
|
||||
struct channel_multiplies_t
|
||||
{
|
||||
using ChannelRef1 = typename channel_traits<Channel1>::const_reference;
|
||||
using ChannelRef2 = typename channel_traits<Channel2>::const_reference;
|
||||
static_assert(std::is_convertible<ChannelRef1, ChannelResult>::value,
|
||||
"ChannelRef1 not convertible to ChannelResult");
|
||||
static_assert(std::is_convertible<ChannelRef2, ChannelResult>::value,
|
||||
"ChannelRef2 not convertible to ChannelResult");
|
||||
|
||||
/// \param ch1 - first of the two factors (multiplicand).
|
||||
/// \param ch2 - second of the two factors (multiplier).
|
||||
auto operator()(ChannelRef1 ch1, ChannelRef2 ch2) const -> ChannelResult
|
||||
{
|
||||
return ChannelResult(ch1) * ChannelResult(ch2);
|
||||
}
|
||||
};
|
||||
|
||||
/// \ingroup ChannelNumericOperations
|
||||
/// \brief Arithmetic operation of division of two channel values.
|
||||
/// \note This is a generic implementation; user should specialize it for better performance.
|
||||
template <typename Channel1, typename Channel2, typename ChannelResult>
|
||||
struct channel_divides_t
|
||||
{
|
||||
using ChannelRef1 = typename channel_traits<Channel1>::const_reference;
|
||||
using ChannelRef2 = typename channel_traits<Channel2>::const_reference;
|
||||
static_assert(std::is_convertible<ChannelRef1, ChannelResult>::value,
|
||||
"ChannelRef1 not convertible to ChannelResult");
|
||||
static_assert(std::is_convertible<ChannelRef2, ChannelResult>::value,
|
||||
"ChannelRef2 not convertible to ChannelResult");
|
||||
|
||||
/// \param ch1 - dividend operand of the two division operation.
|
||||
/// \param ch2 - divisor operand of the two division operation.
|
||||
auto operator()(ChannelRef1 ch1, ChannelRef2 ch2) const -> ChannelResult
|
||||
{
|
||||
return ChannelResult(ch1) / ChannelResult(ch2);
|
||||
}
|
||||
};
|
||||
|
||||
/// \ingroup ChannelNumericOperations
|
||||
/// \brief Arithmetic operation of adding scalar to channel value.
|
||||
/// \note This is a generic implementation; user should specialize it for better performance.
|
||||
template <typename Channel, typename Scalar, typename ChannelResult>
|
||||
struct channel_plus_scalar_t
|
||||
{
|
||||
using ChannelRef = typename channel_traits<Channel>::const_reference;
|
||||
static_assert(std::is_convertible<ChannelRef, ChannelResult>::value,
|
||||
"ChannelRef not convertible to ChannelResult");
|
||||
static_assert(std::is_scalar<Scalar>::value, "Scalar not a scalar");
|
||||
static_assert(std::is_convertible<Scalar, ChannelResult>::value,
|
||||
"Scalar not convertible to ChannelResult");
|
||||
|
||||
auto operator()(ChannelRef channel, Scalar const& scalar) const -> ChannelResult
|
||||
{
|
||||
return ChannelResult(channel) + ChannelResult(scalar);
|
||||
}
|
||||
};
|
||||
|
||||
/// \ingroup ChannelNumericOperations
|
||||
/// \brief Arithmetic operation of subtracting scalar from channel value.
|
||||
/// \note This is a generic implementation; user should specialize it for better performance.
|
||||
template <typename Channel, typename Scalar, typename ChannelResult>
|
||||
struct channel_minus_scalar_t
|
||||
{
|
||||
using ChannelRef = typename channel_traits<Channel>::const_reference;
|
||||
static_assert(std::is_convertible<ChannelRef, ChannelResult>::value,
|
||||
"ChannelRef not convertible to ChannelResult");
|
||||
static_assert(std::is_scalar<Scalar>::value, "Scalar not a scalar");
|
||||
static_assert(std::is_convertible<Scalar, ChannelResult>::value,
|
||||
"Scalar not convertible to ChannelResult");
|
||||
|
||||
/// \param channel - minuend operand of the subtraction.
|
||||
/// \param scalar - subtrahend operand of the subtraction.
|
||||
auto operator()(ChannelRef channel, Scalar const& scalar) const -> ChannelResult
|
||||
{
|
||||
// TODO: Convertion after subtraction vs conversion of operands in channel_minus_t?
|
||||
return ChannelResult(channel - scalar);
|
||||
}
|
||||
};
|
||||
|
||||
/// \ingroup ChannelNumericOperations
|
||||
/// \brief Arithmetic operation of channel value by a scalar.
|
||||
/// \note This is a generic implementation; user should specialize it for better performance.
|
||||
template <typename Channel, typename Scalar, typename ChannelResult>
|
||||
struct channel_multiplies_scalar_t
|
||||
{
|
||||
using ChannelRef = typename channel_traits<Channel>::const_reference;
|
||||
static_assert(std::is_convertible<ChannelRef, ChannelResult>::value,
|
||||
"ChannelRef not convertible to ChannelResult");
|
||||
static_assert(std::is_scalar<Scalar>::value, "Scalar not a scalar");
|
||||
static_assert(std::is_convertible<Scalar, ChannelResult>::value,
|
||||
"Scalar not convertible to ChannelResult");
|
||||
|
||||
/// \param channel - first of the two factors (multiplicand).
|
||||
/// \param scalar - second of the two factors (multiplier).
|
||||
auto operator()(ChannelRef channel, Scalar const& scalar) const -> ChannelResult
|
||||
{
|
||||
return ChannelResult(channel) * ChannelResult(scalar);
|
||||
}
|
||||
};
|
||||
|
||||
/// \ingroup ChannelNumericOperations
|
||||
/// \brief Arithmetic operation of dividing channel value by scalar.
|
||||
/// \note This is a generic implementation; user should specialize it for better performance.
|
||||
template <typename Channel, typename Scalar, typename ChannelResult>
|
||||
struct channel_divides_scalar_t
|
||||
{
|
||||
using ChannelRef = typename channel_traits<Channel>::const_reference;
|
||||
static_assert(std::is_convertible<ChannelRef, ChannelResult>::value,
|
||||
"ChannelRef not convertible to ChannelResult");
|
||||
static_assert(std::is_scalar<Scalar>::value, "Scalar not a scalar");
|
||||
static_assert(std::is_convertible<Scalar, ChannelResult>::value,
|
||||
"Scalar not convertible to ChannelResult");
|
||||
|
||||
/// \param channel - dividend operand of the two division operation.
|
||||
/// \param scalar - divisor operand of the two division operation.
|
||||
auto operator()(ChannelRef channel, Scalar const& scalar) const -> ChannelResult
|
||||
{
|
||||
return ChannelResult(channel) / ChannelResult(scalar);
|
||||
}
|
||||
};
|
||||
|
||||
/// \ingroup ChannelNumericOperations
|
||||
/// \brief Arithmetic operation of dividing channel value by 2
|
||||
/// \note This is a generic implementation; user should specialize it for better performance.
|
||||
template <typename Channel>
|
||||
struct channel_halves_t
|
||||
{
|
||||
using ChannelRef = typename channel_traits<Channel>::reference;
|
||||
|
||||
auto operator()(ChannelRef channel) const -> ChannelRef
|
||||
{
|
||||
// TODO: Split into steps: extract with explicit conversion to double, divide and assign?
|
||||
//double const v = ch;
|
||||
//ch = static_cast<Channel>(v / 2.0);
|
||||
channel /= 2.0;
|
||||
return channel;
|
||||
}
|
||||
};
|
||||
|
||||
/// \ingroup ChannelNumericOperations
|
||||
/// \brief Operation of setting channel value to zero
|
||||
/// \note This is a generic implementation; user should specialize it for better performance.
|
||||
template <typename Channel>
|
||||
struct channel_zeros_t
|
||||
{
|
||||
using ChannelRef = typename channel_traits<Channel>::reference;
|
||||
|
||||
auto operator()(ChannelRef channel) const -> ChannelRef
|
||||
{
|
||||
channel = Channel(0);
|
||||
return channel;
|
||||
}
|
||||
};
|
||||
|
||||
/// \ingroup ChannelNumericOperations
|
||||
/// structure for assigning one channel to another
|
||||
/// \note This is a generic implementation; user should specialize it for better performance.
|
||||
template <typename Channel1, typename Channel2>
|
||||
struct channel_assigns_t
|
||||
{
|
||||
using ChannelRef1 = typename channel_traits<Channel1>::const_reference;
|
||||
using ChannelRef2 = typename channel_traits<Channel2>::reference;
|
||||
static_assert(std::is_convertible<ChannelRef1, Channel2>::value,
|
||||
"ChannelRef1 not convertible to Channel2");
|
||||
|
||||
/// \param ch1 - assignor side (input) of the assignment operation
|
||||
/// \param ch2 - assignee side (output) of the assignment operation
|
||||
auto operator()(ChannelRef1 ch1, ChannelRef2 ch2) const -> ChannelRef2
|
||||
{
|
||||
ch2 = Channel2(ch1);
|
||||
return ch2;
|
||||
}
|
||||
};
|
||||
|
||||
}} // namespace boost::gil
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,419 @@
|
||||
//
|
||||
// Copyright 2005-2007 Adobe Systems Incorporated
|
||||
// Copyright 2019 Miral Shah <miralshah2211@gmail.com>
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
#ifndef BOOST_GIL_EXTENSION_NUMERIC_CONVOLVE_HPP
|
||||
#define BOOST_GIL_EXTENSION_NUMERIC_CONVOLVE_HPP
|
||||
|
||||
#include <boost/gil/extension/numeric/algorithm.hpp>
|
||||
#include <boost/gil/extension/numeric/kernel.hpp>
|
||||
#include <boost/gil/extension/numeric/pixel_numeric_operations.hpp>
|
||||
|
||||
#include <boost/gil/algorithm.hpp>
|
||||
#include <boost/gil/image_view_factory.hpp>
|
||||
#include <boost/gil/metafunctions.hpp>
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <functional>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
namespace boost { namespace gil {
|
||||
|
||||
// 2D spatial seperable convolutions and cross-correlations
|
||||
|
||||
namespace detail {
|
||||
|
||||
/// \brief Compute the cross-correlation of 1D kernel with the rows of an image
|
||||
/// \tparam PixelAccum - TODO
|
||||
/// \tparam SrcView Models ImageViewConcept
|
||||
/// \tparam Kernel - TODO
|
||||
/// \tparam DstView Models MutableImageViewConcept
|
||||
/// \tparam Correlator - TODO
|
||||
/// \param src_view
|
||||
/// \param kernel - TODO
|
||||
/// \param dst_view Destination where new computed values of pixels are assigned to
|
||||
/// \param option - TODO
|
||||
/// \param correlator - TODO
|
||||
template
|
||||
<
|
||||
typename PixelAccum,
|
||||
typename SrcView,
|
||||
typename Kernel,
|
||||
typename DstView,
|
||||
typename Correlator
|
||||
>
|
||||
void correlate_rows_impl(
|
||||
SrcView const& src_view,
|
||||
Kernel const& kernel,
|
||||
DstView const& dst_view,
|
||||
boundary_option option,
|
||||
Correlator correlator)
|
||||
{
|
||||
BOOST_ASSERT(src_view.dimensions() == dst_view.dimensions());
|
||||
BOOST_ASSERT(kernel.size() != 0);
|
||||
|
||||
if(kernel.size() == 1)
|
||||
{
|
||||
// Reduces to a multiplication
|
||||
view_multiplies_scalar<PixelAccum>(src_view, *kernel.begin(), dst_view);
|
||||
return;
|
||||
}
|
||||
|
||||
using src_pixel_ref_t = typename pixel_proxy<typename SrcView::value_type>::type;
|
||||
using dst_pixel_ref_t = typename pixel_proxy<typename DstView::value_type>::type;
|
||||
using x_coord_t = typename SrcView::x_coord_t;
|
||||
using y_coord_t = typename SrcView::y_coord_t;
|
||||
|
||||
x_coord_t const width = src_view.width();
|
||||
y_coord_t const height = src_view.height();
|
||||
if (width == 0)
|
||||
return;
|
||||
|
||||
PixelAccum acc_zero;
|
||||
pixel_zeros_t<PixelAccum>()(acc_zero);
|
||||
if (option == boundary_option::output_ignore || option == boundary_option::output_zero)
|
||||
{
|
||||
typename DstView::value_type dst_zero;
|
||||
pixel_assigns_t<PixelAccum, dst_pixel_ref_t>()(acc_zero, dst_zero);
|
||||
if (width < static_cast<x_coord_t>(kernel.size()))
|
||||
{
|
||||
if (option == boundary_option::output_zero)
|
||||
fill_pixels(dst_view, dst_zero);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::vector<PixelAccum> buffer(width);
|
||||
for (y_coord_t y = 0; y < height; ++y)
|
||||
{
|
||||
assign_pixels(src_view.row_begin(y), src_view.row_end(y), &buffer.front());
|
||||
typename DstView::x_iterator it_dst = dst_view.row_begin(y);
|
||||
if (option == boundary_option::output_zero)
|
||||
std::fill_n(it_dst, kernel.left_size(), dst_zero);
|
||||
it_dst += kernel.left_size();
|
||||
correlator(&buffer.front(), &buffer.front() + width + 1 - kernel.size(),
|
||||
kernel.begin(), it_dst);
|
||||
it_dst += width + 1 - kernel.size();
|
||||
if (option == boundary_option::output_zero)
|
||||
std::fill_n(it_dst, kernel.right_size(), dst_zero);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::vector<PixelAccum> buffer(width + kernel.size() - 1);
|
||||
for (y_coord_t y = 0; y < height; ++y)
|
||||
{
|
||||
PixelAccum *it_buffer = &buffer.front();
|
||||
if (option == boundary_option::extend_padded)
|
||||
{
|
||||
assign_pixels(
|
||||
src_view.row_begin(y) - kernel.left_size(),
|
||||
src_view.row_end(y) + kernel.right_size(),
|
||||
it_buffer);
|
||||
}
|
||||
else if (option == boundary_option::extend_zero)
|
||||
{
|
||||
std::fill_n(it_buffer, kernel.left_size(), acc_zero);
|
||||
it_buffer += kernel.left_size();
|
||||
assign_pixels(src_view.row_begin(y), src_view.row_end(y), it_buffer);
|
||||
it_buffer += width;
|
||||
std::fill_n(it_buffer, kernel.right_size(), acc_zero);
|
||||
}
|
||||
else if (option == boundary_option::extend_constant)
|
||||
{
|
||||
PixelAccum filler;
|
||||
pixel_assigns_t<src_pixel_ref_t, PixelAccum>()(*src_view.row_begin(y), filler);
|
||||
std::fill_n(it_buffer, kernel.left_size(), filler);
|
||||
it_buffer += kernel.left_size();
|
||||
assign_pixels(src_view.row_begin(y), src_view.row_end(y), it_buffer);
|
||||
it_buffer += width;
|
||||
pixel_assigns_t<src_pixel_ref_t, PixelAccum>()(src_view.row_end(y)[-1], filler);
|
||||
std::fill_n(it_buffer, kernel.right_size(), filler);
|
||||
}
|
||||
|
||||
correlator(
|
||||
&buffer.front(), &buffer.front() + width,
|
||||
kernel.begin(),
|
||||
dst_view.row_begin(y));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename PixelAccum>
|
||||
class correlator_n
|
||||
{
|
||||
public:
|
||||
correlator_n(std::size_t size) : size_(size) {}
|
||||
|
||||
template <typename SrcIterator, typename KernelIterator, typename DstIterator>
|
||||
void operator()(
|
||||
SrcIterator src_begin,
|
||||
SrcIterator src_end,
|
||||
KernelIterator kernel_begin,
|
||||
DstIterator dst_begin)
|
||||
{
|
||||
correlate_pixels_n<PixelAccum>(src_begin, src_end, kernel_begin, size_, dst_begin);
|
||||
}
|
||||
|
||||
private:
|
||||
std::size_t size_{0};
|
||||
};
|
||||
|
||||
template <std::size_t Size, typename PixelAccum>
|
||||
struct correlator_k
|
||||
{
|
||||
template <typename SrcIterator, typename KernelIterator, typename DstIterator>
|
||||
void operator()(
|
||||
SrcIterator src_begin,
|
||||
SrcIterator src_end,
|
||||
KernelIterator kernel_begin,
|
||||
DstIterator dst_begin)
|
||||
{
|
||||
correlate_pixels_k<Size, PixelAccum>(src_begin, src_end, kernel_begin, dst_begin);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/// \ingroup ImageAlgorithms
|
||||
/// \brief Correlate 1D variable-size kernel along the rows of image
|
||||
/// \tparam PixelAccum TODO
|
||||
/// \tparam SrcView Models ImageViewConcept
|
||||
/// \tparam Kernel TODO
|
||||
/// \tparam DstView Models MutableImageViewConcept
|
||||
template <typename PixelAccum, typename SrcView, typename Kernel, typename DstView>
|
||||
BOOST_FORCEINLINE
|
||||
void correlate_rows(
|
||||
SrcView const& src_view,
|
||||
Kernel const& kernel,
|
||||
DstView const& dst_view,
|
||||
boundary_option option = boundary_option::extend_zero)
|
||||
{
|
||||
detail::correlate_rows_impl<PixelAccum>(
|
||||
src_view, kernel, dst_view, option, detail::correlator_n<PixelAccum>(kernel.size()));
|
||||
}
|
||||
|
||||
/// \ingroup ImageAlgorithms
|
||||
/// \brief Correlate 1D variable-size kernel along the columns of image
|
||||
/// \tparam PixelAccum TODO
|
||||
/// \tparam SrcView Models ImageViewConcept
|
||||
/// \tparam Kernel TODO
|
||||
/// \tparam DstView Models MutableImageViewConcept
|
||||
template <typename PixelAccum, typename SrcView, typename Kernel, typename DstView>
|
||||
BOOST_FORCEINLINE
|
||||
void correlate_cols(
|
||||
SrcView const& src_view,
|
||||
Kernel const& kernel,
|
||||
DstView const& dst_view,
|
||||
boundary_option option = boundary_option::extend_zero)
|
||||
{
|
||||
correlate_rows<PixelAccum>(
|
||||
transposed_view(src_view), kernel, transposed_view(dst_view), option);
|
||||
}
|
||||
|
||||
/// \ingroup ImageAlgorithms
|
||||
/// \brief Convolve 1D variable-size kernel along the rows of image
|
||||
/// \tparam PixelAccum TODO
|
||||
/// \tparam SrcView Models ImageViewConcept
|
||||
/// \tparam Kernel TODO
|
||||
/// \tparam DstView Models MutableImageViewConcept
|
||||
template <typename PixelAccum, typename SrcView, typename Kernel, typename DstView>
|
||||
BOOST_FORCEINLINE
|
||||
void convolve_rows(
|
||||
SrcView const& src_view,
|
||||
Kernel const& kernel,
|
||||
DstView const& dst_view,
|
||||
boundary_option option = boundary_option::extend_zero)
|
||||
{
|
||||
correlate_rows<PixelAccum>(src_view, reverse_kernel(kernel), dst_view, option);
|
||||
}
|
||||
|
||||
/// \ingroup ImageAlgorithms
|
||||
/// \brief Convolve 1D variable-size kernel along the columns of image
|
||||
/// \tparam PixelAccum TODO
|
||||
/// \tparam SrcView Models ImageViewConcept
|
||||
/// \tparam Kernel TODO
|
||||
/// \tparam DstView Models MutableImageViewConcept
|
||||
template <typename PixelAccum, typename SrcView, typename Kernel, typename DstView>
|
||||
BOOST_FORCEINLINE
|
||||
void convolve_cols(
|
||||
SrcView const& src_view,
|
||||
Kernel const& kernel,
|
||||
DstView const& dst_view,
|
||||
boundary_option option = boundary_option::extend_zero)
|
||||
{
|
||||
convolve_rows<PixelAccum>(
|
||||
transposed_view(src_view), kernel, transposed_view(dst_view), option);
|
||||
}
|
||||
|
||||
/// \ingroup ImageAlgorithms
|
||||
/// \brief Correlate 1D fixed-size kernel along the rows of image
|
||||
/// \tparam PixelAccum TODO
|
||||
/// \tparam SrcView Models ImageViewConcept
|
||||
/// \tparam Kernel TODO
|
||||
/// \tparam DstView Models MutableImageViewConcept
|
||||
template <typename PixelAccum, typename SrcView, typename Kernel, typename DstView>
|
||||
BOOST_FORCEINLINE
|
||||
void correlate_rows_fixed(
|
||||
SrcView const& src_view,
|
||||
Kernel const& kernel,
|
||||
DstView const& dst_view,
|
||||
boundary_option option = boundary_option::extend_zero)
|
||||
{
|
||||
using correlator = detail::correlator_k<Kernel::static_size, PixelAccum>;
|
||||
detail::correlate_rows_impl<PixelAccum>(src_view, kernel, dst_view, option, correlator{});
|
||||
}
|
||||
|
||||
/// \ingroup ImageAlgorithms
|
||||
/// \brief Correlate 1D fixed-size kernel along the columns of image
|
||||
/// \tparam PixelAccum TODO
|
||||
/// \tparam SrcView Models ImageViewConcept
|
||||
/// \tparam Kernel TODO
|
||||
/// \tparam DstView Models MutableImageViewConcept
|
||||
template <typename PixelAccum,typename SrcView,typename Kernel,typename DstView>
|
||||
BOOST_FORCEINLINE
|
||||
void correlate_cols_fixed(
|
||||
SrcView const& src_view,
|
||||
Kernel const& kernel,
|
||||
DstView const& dst_view,
|
||||
boundary_option option = boundary_option::extend_zero)
|
||||
{
|
||||
correlate_rows_fixed<PixelAccum>(
|
||||
transposed_view(src_view), kernel, transposed_view(dst_view), option);
|
||||
}
|
||||
|
||||
/// \ingroup ImageAlgorithms
|
||||
/// \brief Convolve 1D fixed-size kernel along the rows of image
|
||||
/// \tparam PixelAccum TODO
|
||||
/// \tparam SrcView Models ImageViewConcept
|
||||
/// \tparam Kernel TODO
|
||||
/// \tparam DstView Models MutableImageViewConcept
|
||||
template <typename PixelAccum, typename SrcView, typename Kernel, typename DstView>
|
||||
BOOST_FORCEINLINE
|
||||
void convolve_rows_fixed(
|
||||
SrcView const& src_view,
|
||||
Kernel const& kernel,
|
||||
DstView const& dst_view,
|
||||
boundary_option option = boundary_option::extend_zero)
|
||||
{
|
||||
correlate_rows_fixed<PixelAccum>(src_view, reverse_kernel(kernel), dst_view, option);
|
||||
}
|
||||
|
||||
/// \ingroup ImageAlgorithms
|
||||
/// \brief Convolve 1D fixed-size kernel along the columns of image
|
||||
/// \tparam PixelAccum TODO
|
||||
/// \tparam SrcView Models ImageViewConcept
|
||||
/// \tparam Kernel TODO
|
||||
/// \tparam DstView Models MutableImageViewConcept
|
||||
template <typename PixelAccum, typename SrcView, typename Kernel, typename DstView>
|
||||
BOOST_FORCEINLINE
|
||||
void convolve_cols_fixed(
|
||||
SrcView const& src_view,
|
||||
Kernel const& kernel,
|
||||
DstView const& dst_view,
|
||||
boundary_option option = boundary_option::extend_zero)
|
||||
{
|
||||
convolve_rows_fixed<PixelAccum>(
|
||||
transposed_view(src_view), kernel, transposed_view(dst_view), option);
|
||||
}
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
/// \ingroup ImageAlgorithms
|
||||
/// \brief Convolve 1D variable-size kernel along both rows and columns of image
|
||||
/// \tparam PixelAccum TODO
|
||||
/// \tparam SrcView Models ImageViewConcept
|
||||
/// \tparam Kernel TODO
|
||||
/// \tparam DstView Models MutableImageViewConcept
|
||||
template <typename PixelAccum, typename SrcView, typename Kernel, typename DstView>
|
||||
BOOST_FORCEINLINE
|
||||
void convolve_1d(
|
||||
SrcView const& src_view,
|
||||
Kernel const& kernel,
|
||||
DstView const& dst_view,
|
||||
boundary_option option = boundary_option::extend_zero)
|
||||
{
|
||||
convolve_rows<PixelAccum>(src_view, kernel, dst_view, option);
|
||||
convolve_cols<PixelAccum>(dst_view, kernel, dst_view, option);
|
||||
}
|
||||
|
||||
template <typename SrcView, typename DstView, typename Kernel>
|
||||
void convolve_2d_impl(SrcView const& src_view, DstView const& dst_view, Kernel const& kernel)
|
||||
{
|
||||
int flip_ker_row, flip_ker_col, row_boundary, col_boundary;
|
||||
float aux_total;
|
||||
for (std::ptrdiff_t view_row = 0; view_row < src_view.height(); ++view_row)
|
||||
{
|
||||
for (std::ptrdiff_t view_col = 0; view_col < src_view.width(); ++view_col)
|
||||
{
|
||||
aux_total = 0.0f;
|
||||
for (std::size_t kernel_row = 0; kernel_row < kernel.size(); ++kernel_row)
|
||||
{
|
||||
flip_ker_row = kernel.size() - 1 - kernel_row; // row index of flipped kernel
|
||||
|
||||
for (std::size_t kernel_col = 0; kernel_col < kernel.size(); ++kernel_col)
|
||||
{
|
||||
flip_ker_col = kernel.size() - 1 - kernel_col; // column index of flipped kernel
|
||||
|
||||
// index of input signal, used for checking boundary
|
||||
row_boundary = view_row + (kernel.center_y() - flip_ker_row);
|
||||
col_boundary = view_col + (kernel.center_x() - flip_ker_col);
|
||||
|
||||
// ignore input samples which are out of bound
|
||||
if (row_boundary >= 0 && row_boundary < src_view.height() &&
|
||||
col_boundary >= 0 && col_boundary < src_view.width())
|
||||
{
|
||||
aux_total +=
|
||||
src_view(col_boundary, row_boundary) *
|
||||
kernel.at(flip_ker_row, flip_ker_col);
|
||||
}
|
||||
}
|
||||
}
|
||||
dst_view(view_col, view_row) = aux_total;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// \ingroup ImageAlgorithms
|
||||
/// \brief convolve_2d can only use convolve_option_extend_zero as convolve_boundary_option
|
||||
/// this is the default option and cannot be changed for now
|
||||
/// (In future there are plans to improve the algorithm and allow user to use other options as well)
|
||||
/// \tparam SrcView Models ImageViewConcept
|
||||
/// \tparam Kernel TODO
|
||||
/// \tparam DstView Models MutableImageViewConcept
|
||||
template <typename SrcView, typename DstView, typename Kernel>
|
||||
void convolve_2d(SrcView const& src_view, Kernel const& kernel, DstView const& dst_view)
|
||||
{
|
||||
BOOST_ASSERT(src_view.dimensions() == dst_view.dimensions());
|
||||
BOOST_ASSERT(kernel.size() != 0);
|
||||
|
||||
gil_function_requires<ImageViewConcept<SrcView>>();
|
||||
gil_function_requires<MutableImageViewConcept<DstView>>();
|
||||
static_assert(color_spaces_are_compatible
|
||||
<
|
||||
typename color_space_type<SrcView>::type,
|
||||
typename color_space_type<DstView>::type
|
||||
>::value, "Source and destination views must have pixels with the same color space");
|
||||
|
||||
for (std::size_t i = 0; i < src_view.num_channels(); i++)
|
||||
{
|
||||
detail::convolve_2d_impl(
|
||||
nth_channel_view(src_view, i),
|
||||
nth_channel_view(dst_view, i),
|
||||
kernel
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
}}} // namespace boost::gil::detail
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,361 @@
|
||||
//
|
||||
// Copyright 2005-2007 Adobe Systems Incorporated
|
||||
// Copyright 2019 Miral Shah <miralshah2211@gmail.com>
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
|
||||
#ifndef BOOST_GIL_EXTENSION_NUMERIC_KERNEL_HPP
|
||||
#define BOOST_GIL_EXTENSION_NUMERIC_KERNEL_HPP
|
||||
|
||||
#include <boost/gil/utilities.hpp>
|
||||
#include <boost/gil/point.hpp>
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <cmath>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace boost { namespace gil {
|
||||
|
||||
// Definitions of 1D fixed-size and variable-size kernels and related operations
|
||||
|
||||
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
|
||||
{
|
||||
public:
|
||||
kernel_1d_adaptor() = default;
|
||||
|
||||
explicit kernel_1d_adaptor(std::size_t center)
|
||||
: center_(center)
|
||||
{
|
||||
BOOST_ASSERT(center_ < this->size());
|
||||
}
|
||||
|
||||
kernel_1d_adaptor(std::size_t size, std::size_t center)
|
||||
: Core(size) , center_(center)
|
||||
{
|
||||
BOOST_ASSERT(this->size() > 0);
|
||||
BOOST_ASSERT(center_ < this->size()); // also implies `size() > 0`
|
||||
}
|
||||
|
||||
kernel_1d_adaptor(kernel_1d_adaptor const& other)
|
||||
: Core(other), center_(other.center_)
|
||||
{
|
||||
BOOST_ASSERT(this->size() > 0);
|
||||
BOOST_ASSERT(center_ < this->size()); // also implies `size() > 0`
|
||||
}
|
||||
|
||||
kernel_1d_adaptor& operator=(kernel_1d_adaptor const& other)
|
||||
{
|
||||
Core::operator=(other);
|
||||
center_ = other.center_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::size_t left_size() const
|
||||
{
|
||||
BOOST_ASSERT(center_ < this->size());
|
||||
return center_;
|
||||
}
|
||||
|
||||
std::size_t right_size() const
|
||||
{
|
||||
BOOST_ASSERT(center_ < this->size());
|
||||
return this->size() - center_ - 1;
|
||||
}
|
||||
|
||||
auto center() -> std::size_t&
|
||||
{
|
||||
BOOST_ASSERT(center_ < this->size());
|
||||
return center_;
|
||||
}
|
||||
|
||||
auto center() const -> std::size_t const&
|
||||
{
|
||||
BOOST_ASSERT(center_ < this->size());
|
||||
return center_;
|
||||
}
|
||||
|
||||
private:
|
||||
std::size_t center_{0};
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/// \brief variable-size kernel
|
||||
template <typename T, typename Allocator = std::allocator<T> >
|
||||
class kernel_1d : public detail::kernel_1d_adaptor<std::vector<T, Allocator>>
|
||||
{
|
||||
using parent_t = detail::kernel_1d_adaptor<std::vector<T, Allocator>>;
|
||||
public:
|
||||
|
||||
kernel_1d() = default;
|
||||
kernel_1d(std::size_t size, std::size_t center) : parent_t(size, center) {}
|
||||
|
||||
template <typename FwdIterator>
|
||||
kernel_1d(FwdIterator elements, std::size_t size, std::size_t center)
|
||||
: parent_t(size, center)
|
||||
{
|
||||
detail::copy_n(elements, size, this->begin());
|
||||
}
|
||||
|
||||
kernel_1d(kernel_1d const& other) : parent_t(other) {}
|
||||
kernel_1d& operator=(kernel_1d const& other) = default;
|
||||
};
|
||||
|
||||
/// \brief static-size kernel
|
||||
template <typename T,std::size_t Size>
|
||||
class kernel_1d_fixed : public detail::kernel_1d_adaptor<std::array<T, Size>>
|
||||
{
|
||||
using parent_t = detail::kernel_1d_adaptor<std::array<T, Size>>;
|
||||
public:
|
||||
static constexpr std::size_t static_size = Size;
|
||||
static_assert(static_size > 0, "kernel must have size greater than 0");
|
||||
static_assert(static_size % 2 == 1, "kernel size must be odd to ensure validity at the center");
|
||||
|
||||
kernel_1d_fixed() = default;
|
||||
explicit kernel_1d_fixed(std::size_t center) : parent_t(center) {}
|
||||
|
||||
template <typename FwdIterator>
|
||||
explicit kernel_1d_fixed(FwdIterator elements, std::size_t center)
|
||||
: parent_t(center)
|
||||
{
|
||||
detail::copy_n(elements, Size, this->begin());
|
||||
}
|
||||
|
||||
kernel_1d_fixed(kernel_1d_fixed const& other) : parent_t(other) {}
|
||||
kernel_1d_fixed& operator=(kernel_1d_fixed const& other) = default;
|
||||
};
|
||||
|
||||
// TODO: This data member is odr-used and definition at namespace scope
|
||||
// is required by C++11. Redundant and deprecated in C++17.
|
||||
template <typename T,std::size_t Size>
|
||||
constexpr std::size_t kernel_1d_fixed<T, Size>::static_size;
|
||||
|
||||
/// \brief reverse a kernel
|
||||
template <typename Kernel>
|
||||
inline Kernel reverse_kernel(Kernel const& kernel)
|
||||
{
|
||||
Kernel result(kernel);
|
||||
result.center() = kernel.right_size();
|
||||
std::reverse(result.begin(), result.end());
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename Core>
|
||||
class kernel_2d_adaptor : public Core
|
||||
{
|
||||
public:
|
||||
kernel_2d_adaptor() = default;
|
||||
|
||||
explicit kernel_2d_adaptor(std::size_t center_y, std::size_t center_x)
|
||||
: center_(center_x, center_y)
|
||||
{
|
||||
BOOST_ASSERT(center_.y < this->size() && center_.x < this->size());
|
||||
}
|
||||
|
||||
kernel_2d_adaptor(std::size_t size, std::size_t center_y, std::size_t center_x)
|
||||
: Core(size * size), square_size(size), center_(center_x, center_y)
|
||||
{
|
||||
BOOST_ASSERT(this->size() > 0);
|
||||
BOOST_ASSERT(center_.y < this->size() && center_.x < this->size()); // implies `size() > 0`
|
||||
}
|
||||
|
||||
kernel_2d_adaptor(kernel_2d_adaptor const& other)
|
||||
: Core(other), square_size(other.square_size), center_(other.center_.x, other.center_.y)
|
||||
{
|
||||
BOOST_ASSERT(this->size() > 0);
|
||||
BOOST_ASSERT(center_.y < this->size() && center_.x < this->size()); // implies `size() > 0`
|
||||
}
|
||||
|
||||
kernel_2d_adaptor& operator=(kernel_2d_adaptor const& other)
|
||||
{
|
||||
Core::operator=(other);
|
||||
center_.y = other.center_.y;
|
||||
center_.x = other.center_.x;
|
||||
square_size = other.square_size;
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::size_t upper_size() const
|
||||
{
|
||||
BOOST_ASSERT(center_.y < this->size());
|
||||
return center_.y;
|
||||
}
|
||||
|
||||
std::size_t lower_size() const
|
||||
{
|
||||
BOOST_ASSERT(center_.y < this->size());
|
||||
return this->size() - center_.y - 1;
|
||||
}
|
||||
|
||||
std::size_t left_size() const
|
||||
{
|
||||
BOOST_ASSERT(center_.x < this->size());
|
||||
return center_.x;
|
||||
}
|
||||
|
||||
std::size_t right_size() const
|
||||
{
|
||||
BOOST_ASSERT(center_.x < this->size());
|
||||
return this->size() - center_.x - 1;
|
||||
}
|
||||
|
||||
auto center_y() -> std::size_t&
|
||||
{
|
||||
BOOST_ASSERT(center_.y < this->size());
|
||||
return center_.y;
|
||||
}
|
||||
|
||||
auto center_y() const -> std::size_t const&
|
||||
{
|
||||
BOOST_ASSERT(center_.y < this->size());
|
||||
return center_.y;
|
||||
}
|
||||
|
||||
auto center_x() -> std::size_t&
|
||||
{
|
||||
BOOST_ASSERT(center_.x < this->size());
|
||||
return center_.x;
|
||||
}
|
||||
|
||||
auto center_x() const -> std::size_t const&
|
||||
{
|
||||
BOOST_ASSERT(center_.x < this->size());
|
||||
return center_.x;
|
||||
}
|
||||
|
||||
std::size_t size() const
|
||||
{
|
||||
return square_size;
|
||||
}
|
||||
|
||||
typename Core::value_type at(std::size_t x, std::size_t y) const
|
||||
{
|
||||
if (x >= this->size() || y >= this->size())
|
||||
{
|
||||
throw std::out_of_range("Index out of range");
|
||||
}
|
||||
return this->begin()[y * this->size() + x];
|
||||
}
|
||||
|
||||
protected:
|
||||
std::size_t square_size{0};
|
||||
|
||||
private:
|
||||
point<std::size_t> center_{0, 0};
|
||||
};
|
||||
|
||||
/// \brief variable-size kernel
|
||||
template
|
||||
<
|
||||
typename T,
|
||||
typename Allocator = std::allocator<T>
|
||||
>
|
||||
class kernel_2d : public detail::kernel_2d_adaptor<std::vector<T, Allocator>>
|
||||
{
|
||||
using parent_t = detail::kernel_2d_adaptor<std::vector<T, Allocator>>;
|
||||
|
||||
public:
|
||||
|
||||
kernel_2d() = default;
|
||||
kernel_2d(std::size_t size,std::size_t center_y, std::size_t center_x)
|
||||
: parent_t(size, center_y, center_x)
|
||||
{}
|
||||
|
||||
template <typename FwdIterator>
|
||||
kernel_2d(FwdIterator elements, std::size_t size, std::size_t center_y, std::size_t center_x)
|
||||
: parent_t(static_cast<int>(std::sqrt(size)), center_y, center_x)
|
||||
{
|
||||
detail::copy_n(elements, size, this->begin());
|
||||
}
|
||||
|
||||
kernel_2d(kernel_2d const& other) : parent_t(other) {}
|
||||
kernel_2d& operator=(kernel_2d const& other) = default;
|
||||
};
|
||||
|
||||
/// \brief static-size kernel
|
||||
template <typename T, std::size_t Size>
|
||||
class kernel_2d_fixed :
|
||||
public detail::kernel_2d_adaptor<std::array<T, Size * Size>>
|
||||
{
|
||||
using parent_t = detail::kernel_2d_adaptor<std::array<T, Size * Size>>;
|
||||
public:
|
||||
static constexpr std::size_t static_size = Size;
|
||||
static_assert(static_size > 0, "kernel must have size greater than 0");
|
||||
static_assert(static_size % 2 == 1, "kernel size must be odd to ensure validity at the center");
|
||||
|
||||
kernel_2d_fixed()
|
||||
{
|
||||
this->square_size = Size;
|
||||
}
|
||||
|
||||
explicit kernel_2d_fixed(std::size_t center_y, std::size_t center_x) :
|
||||
parent_t(center_y, center_x)
|
||||
{
|
||||
this->square_size = Size;
|
||||
}
|
||||
|
||||
template <typename FwdIterator>
|
||||
explicit kernel_2d_fixed(FwdIterator elements, std::size_t center_y, std::size_t center_x)
|
||||
: parent_t(center_y, center_x)
|
||||
{
|
||||
this->square_size = Size;
|
||||
detail::copy_n(elements, Size * Size, this->begin());
|
||||
}
|
||||
|
||||
kernel_2d_fixed(kernel_2d_fixed const& other) : parent_t(other) {}
|
||||
kernel_2d_fixed& operator=(kernel_2d_fixed const& other) = default;
|
||||
};
|
||||
|
||||
// TODO: This data member is odr-used and definition at namespace scope
|
||||
// is required by C++11. Redundant and deprecated in C++17.
|
||||
template <typename T, std::size_t Size>
|
||||
constexpr std::size_t kernel_2d_fixed<T, Size>::static_size;
|
||||
|
||||
template <typename Kernel>
|
||||
inline Kernel reverse_kernel_2d(Kernel const& kernel)
|
||||
{
|
||||
Kernel result(kernel);
|
||||
result.center_x() = kernel.lower_size();
|
||||
result.center_y() = kernel.right_size();
|
||||
std::reverse(result.begin(), result.end());
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/// \brief reverse a kernel_2d
|
||||
template<typename T, typename Allocator>
|
||||
inline kernel_2d<T, Allocator> reverse_kernel(kernel_2d<T, Allocator> const& kernel)
|
||||
{
|
||||
return reverse_kernel_2d(kernel);
|
||||
}
|
||||
|
||||
/// \brief reverse a kernel_2d
|
||||
template<typename T, std::size_t Size>
|
||||
inline kernel_2d_fixed<T, Size> reverse_kernel(kernel_2d_fixed<T, Size> const& kernel)
|
||||
{
|
||||
return reverse_kernel_2d(kernel);
|
||||
}
|
||||
|
||||
} //namespace detail
|
||||
|
||||
}} // namespace boost::gil
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,217 @@
|
||||
//
|
||||
// Copyright 2005-2007 Adobe Systems Incorporated
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
#ifndef BOOST_GIL_EXTENSION_NUMERIC_PIXEL_NUMERIC_OPERATIONS_HPP
|
||||
#define BOOST_GIL_EXTENSION_NUMERIC_PIXEL_NUMERIC_OPERATIONS_HPP
|
||||
|
||||
#include <boost/gil/extension/numeric/channel_numeric_operations.hpp>
|
||||
|
||||
#include <boost/gil/color_base_algorithm.hpp>
|
||||
#include <boost/gil/pixel.hpp>
|
||||
|
||||
namespace boost { namespace gil {
|
||||
|
||||
// Function objects and utilities for pixel-wise numeric operations.
|
||||
//
|
||||
// List of currently defined functors:
|
||||
// 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 (=)
|
||||
|
||||
/// \ingroup PixelNumericOperations
|
||||
/// \brief Performs channel-wise addition of two pixels.
|
||||
/// \tparam PixelRef1 - models PixelConcept
|
||||
/// \tparam PixelRef2 - models PixelConcept
|
||||
/// \tparam PixelResult - models PixelValueConcept
|
||||
template <typename PixelRef1, typename PixelRef2, typename PixelResult>
|
||||
struct pixel_plus_t
|
||||
{
|
||||
auto operator()(PixelRef1 const& p1, PixelRef2 const& p2) const -> PixelResult
|
||||
{
|
||||
PixelResult result;
|
||||
static_transform(p1, p2, result,
|
||||
channel_plus_t
|
||||
<
|
||||
typename channel_type<PixelRef1>::type,
|
||||
typename channel_type<PixelRef2>::type,
|
||||
typename channel_type<PixelResult>::type
|
||||
>());
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
/// \ingroup PixelNumericOperations
|
||||
/// \brief Performs channel-wise subtraction of two pixels.
|
||||
/// \tparam PixelRef1 - models PixelConcept
|
||||
/// \tparam PixelRef2 - models PixelConcept
|
||||
/// \tparam PixelResult - models PixelValueConcept
|
||||
template <typename PixelRef1, typename PixelRef2, typename PixelResult>
|
||||
struct pixel_minus_t
|
||||
{
|
||||
auto operator()(PixelRef1 const& p1, PixelRef2 const& p2) const -> PixelResult
|
||||
{
|
||||
PixelResult result;
|
||||
static_transform(p1, p2, result,
|
||||
channel_minus_t
|
||||
<
|
||||
typename channel_type<PixelRef1>::type,
|
||||
typename channel_type<PixelRef2>::type,
|
||||
typename channel_type<PixelResult>::type
|
||||
>());
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
/// \ingroup PixelNumericOperations
|
||||
/// \brief Performs channel-wise multiplication of pixel elements by scalar.
|
||||
/// \tparam PixelRef - models PixelConcept
|
||||
/// \tparam Scalar - models a scalar type
|
||||
/// \tparam PixelResult - models PixelValueConcept
|
||||
template <typename PixelRef, typename Scalar, typename PixelResult>
|
||||
struct pixel_multiplies_scalar_t
|
||||
{
|
||||
auto operator()(PixelRef const& p, Scalar const& s) const -> PixelResult
|
||||
{
|
||||
PixelResult result;
|
||||
static_transform(p, result,
|
||||
std::bind(
|
||||
channel_multiplies_scalar_t<typename channel_type<PixelRef>::type,
|
||||
Scalar,
|
||||
typename channel_type<PixelResult>::type>(),
|
||||
std::placeholders::_1, s));
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
/// \ingroup PixelNumericOperations
|
||||
/// \brief Performs channel-wise multiplication of two pixels.
|
||||
/// \tparam PixelRef1 - models PixelConcept
|
||||
/// \tparam PixelRef1 - models PixelConcept
|
||||
/// \tparam PixelResult - models PixelValueConcept
|
||||
template <typename PixelRef1, typename PixelRef2, typename PixelResult>
|
||||
struct pixel_multiply_t
|
||||
{
|
||||
auto operator()(PixelRef1 const& p1, PixelRef2 const& p2) const -> PixelResult
|
||||
{
|
||||
PixelResult result;
|
||||
static_transform(p1, p2, result,
|
||||
channel_multiplies_t
|
||||
<
|
||||
typename channel_type<PixelRef1>::type,
|
||||
typename channel_type<PixelRef2>::type,
|
||||
typename channel_type<PixelResult>::type
|
||||
>());
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
/// \ingroup PixelNumericOperations
|
||||
/// \brief Performs channel-wise division of pixel elements by scalar.
|
||||
/// \tparam PixelRef - models PixelConcept
|
||||
/// \tparam Scalar - models a scalar type
|
||||
/// \tparam PixelResult - models PixelValueConcept
|
||||
template <typename PixelRef, typename Scalar, typename PixelResult>
|
||||
struct pixel_divides_scalar_t
|
||||
{
|
||||
auto operator()(PixelRef const& p, Scalar const& s) const -> PixelResult
|
||||
{
|
||||
PixelResult result;
|
||||
static_transform(p, result,
|
||||
std::bind(channel_divides_scalar_t<typename channel_type<PixelRef>::type,
|
||||
Scalar,
|
||||
typename channel_type<PixelResult>::type>(),
|
||||
std::placeholders::_1, s));
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
/// \ingroup PixelNumericOperations
|
||||
/// \brief Performs channel-wise division of two pixels.
|
||||
/// \tparam PixelRef1 - models PixelConcept
|
||||
/// \tparam PixelRef1 - models PixelConcept
|
||||
/// \tparam PixelResult - models PixelValueConcept
|
||||
template <typename PixelRef1, typename PixelRef2, typename PixelResult>
|
||||
struct pixel_divide_t
|
||||
{
|
||||
auto operator()(PixelRef1 const& p1, PixelRef2 const& p2) const -> PixelResult
|
||||
{
|
||||
PixelResult result;
|
||||
static_transform(p1, p2, result,
|
||||
channel_divides_t
|
||||
<
|
||||
typename channel_type<PixelRef1>::type,
|
||||
typename channel_type<PixelRef2>::type,
|
||||
typename channel_type<PixelResult>::type
|
||||
>());
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
/// \ingroup PixelNumericOperations
|
||||
/// \brief Performs channel-wise division by 2
|
||||
/// \tparam PixelRef - models PixelConcept
|
||||
template <typename PixelRef>
|
||||
struct pixel_halves_t
|
||||
{
|
||||
auto operator()(PixelRef& p) const -> PixelRef&
|
||||
{
|
||||
static_for_each(p, channel_halves_t<typename channel_type<PixelRef>::type>());
|
||||
return p;
|
||||
}
|
||||
};
|
||||
|
||||
/// \ingroup PixelNumericOperations
|
||||
/// \brief Sets pixel elements to zero (for whatever zero means)
|
||||
/// \tparam PixelRef - models PixelConcept
|
||||
template <typename PixelRef>
|
||||
struct pixel_zeros_t
|
||||
{
|
||||
auto operator()(PixelRef& p) const -> PixelRef&
|
||||
{
|
||||
static_for_each(p, channel_zeros_t<typename channel_type<PixelRef>::type>());
|
||||
return p;
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief Sets pixel elements to zero (for whatever zero means)
|
||||
/// \tparam Pixel - models PixelConcept
|
||||
template <typename Pixel>
|
||||
void zero_channels(Pixel& p)
|
||||
{
|
||||
static_for_each(p, channel_zeros_t<typename channel_type<Pixel>::type>());
|
||||
}
|
||||
|
||||
/// \ingroup PixelNumericOperations
|
||||
/// \brief Casts and assigns a pixel to another
|
||||
///
|
||||
/// A generic implementation for casting and assigning a pixel to another.
|
||||
/// User should specialize it for better performance.
|
||||
///
|
||||
/// \tparam PixelRef - models PixelConcept
|
||||
/// \tparam PixelResult - models PixelValueConcept
|
||||
template <typename PixelRef, typename PixelResult>
|
||||
struct pixel_assigns_t
|
||||
{
|
||||
auto operator()(PixelRef const& src, PixelResult& dst) const -> PixelResult
|
||||
{
|
||||
static_for_each(src, dst,
|
||||
channel_assigns_t
|
||||
<
|
||||
typename channel_type<PixelRef>::type,
|
||||
typename channel_type<PixelResult>::type
|
||||
>());
|
||||
return dst;
|
||||
}
|
||||
};
|
||||
|
||||
}} // namespace boost::gil
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,143 @@
|
||||
//
|
||||
// Copyright 2005-2007 Adobe Systems Incorporated
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
#ifndef BOOST_GIL_EXTENSION_NUMERIC_RESAMPLE_HPP
|
||||
#define BOOST_GIL_EXTENSION_NUMERIC_RESAMPLE_HPP
|
||||
|
||||
#include <boost/gil/extension/numeric/affine.hpp>
|
||||
#include <boost/gil/extension/dynamic_image/dynamic_image_all.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
|
||||
namespace boost { namespace gil {
|
||||
|
||||
// Support for generic image resampling
|
||||
// NOTE: The code is for example use only. It is not optimized for performance
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
////
|
||||
//// 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;
|
||||
|
||||
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, std::bind(
|
||||
detail::resample_pixels_fn<Sampler, MapFn>(dst_to_src, sampler),
|
||||
std::placeholders::_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())
|
||||
{
|
||||
using namespace std::placeholders;
|
||||
apply_operation(dst, std::bind(
|
||||
detail::resample_pixels_fn<Sampler, MapFn>(dst_to_src, sampler),
|
||||
src,
|
||||
std::placeholders::_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
|
||||
@@ -0,0 +1,188 @@
|
||||
//
|
||||
// Copyright 2005-2007 Adobe Systems Incorporated
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
#ifndef BOOST_GIL_EXTENSION_NUMERIC_SAMPLER_HPP
|
||||
#define BOOST_GIL_EXTENSION_NUMERIC_SAMPLER_HPP
|
||||
|
||||
#include <boost/gil/extension/numeric/pixel_numeric_operations.hpp>
|
||||
#include <boost/gil/extension/dynamic_image/dynamic_image_all.hpp>
|
||||
|
||||
namespace boost { namespace gil {
|
||||
|
||||
// Nearest-neighbor and bilinear image samplers.
|
||||
// NOTE: The code is for example use only. It is not optimized for performance
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
////
|
||||
//// 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, SrcView const& src, point<F> const& 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) {
|
||||
using dst_value_t = typename channel_traits<DstChannel>::value_type;
|
||||
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, SrcView const& src, point<F> const& p, DstP& result)
|
||||
{
|
||||
using SrcP = typename SrcView::value_type;
|
||||
point_t p0(ifloor(p.x), ifloor(p.y)); // the closest integer coordinate top left from p
|
||||
point<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 boost::gil
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,14 @@
|
||||
//
|
||||
// Copyright 2012 Christian Henning
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0
|
||||
// See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
#ifndef BOOST_GIL_EXTENSION_TOOLBOX_COLOR_CONVERTERS_HPP
|
||||
#define BOOST_GIL_EXTENSION_TOOLBOX_COLOR_CONVERTERS_HPP
|
||||
|
||||
#include <boost/gil/extension/toolbox/color_converters/gray_to_rgba.hpp>
|
||||
#include <boost/gil/extension/toolbox/color_converters/rgb_to_luminance.hpp>
|
||||
|
||||
#endif
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user