feat():initial version

This commit is contained in:
2026-06-09 20:16:47 +08:00
commit 85fbb3188c
14809 changed files with 3044607 additions and 0 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -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_BIT_ALIGNED_PIXEL_ITERATOR_HPP
#define BOOST_GIL_BIT_ALIGNED_PIXEL_ITERATOR_HPP
#include <boost/gil/bit_aligned_pixel_reference.hpp>
#include <boost/gil/pixel_iterator.hpp>
#include <boost/config.hpp>
#include <boost/iterator/iterator_facade.hpp>
#include <functional>
#include <type_traits>
namespace boost { namespace gil {
/// A model of a heterogeneous pixel that is not byte aligned.
/// Examples are bitmap (1-bit pixels) or 6-bit RGB (222).
/// \defgroup PixelIteratorNonAlignedPixelIterator bit_aligned_pixel_iterator
/// \ingroup PixelIteratorModel
/// \brief An iterator over non-byte-aligned pixels. Models PixelIteratorConcept, PixelBasedConcept, MemoryBasedIteratorConcept, HasDynamicXStepTypeConcept
////////////////////////////////////////////////////////////////////////////////////////
/// \brief An iterator over non-byte-aligned pixels. Models PixelIteratorConcept, PixelBasedConcept, MemoryBasedIteratorConcept, HasDynamicXStepTypeConcept
///
/// An iterator over pixels that correspond to non-byte-aligned bit ranges. Examples of such pixels are single bit grayscale pixel, or a 6-bit RGB 222 pixel.
///
/// \ingroup PixelIteratorNonAlignedPixelIterator PixelBasedModel
template <typename NonAlignedPixelReference>
struct bit_aligned_pixel_iterator : public iterator_facade<bit_aligned_pixel_iterator<NonAlignedPixelReference>,
typename NonAlignedPixelReference::value_type,
std::random_access_iterator_tag,
const NonAlignedPixelReference,
typename NonAlignedPixelReference::bit_range_t::difference_type> {
private:
using parent_t = iterator_facade<bit_aligned_pixel_iterator<NonAlignedPixelReference>,
typename NonAlignedPixelReference::value_type,
std::random_access_iterator_tag,
const NonAlignedPixelReference,
typename NonAlignedPixelReference::bit_range_t::difference_type>;
template <typename Ref> friend struct bit_aligned_pixel_iterator;
using bit_range_t = typename NonAlignedPixelReference::bit_range_t;
public:
using difference_type = typename parent_t::difference_type;
using reference = typename parent_t::reference;
bit_aligned_pixel_iterator() {}
bit_aligned_pixel_iterator(const bit_aligned_pixel_iterator& p) : _bit_range(p._bit_range) {}
bit_aligned_pixel_iterator& operator=(const bit_aligned_pixel_iterator& p) { _bit_range=p._bit_range; return *this; }
template <typename Ref> bit_aligned_pixel_iterator(const bit_aligned_pixel_iterator<Ref>& p) : _bit_range(p._bit_range) {}
bit_aligned_pixel_iterator(reference* ref) : _bit_range(ref->bit_range()) {}
explicit bit_aligned_pixel_iterator(typename bit_range_t::byte_t* data, int bit_offset=0) : _bit_range(data,bit_offset) {}
/// For some reason operator[] provided by iterator_adaptor returns a custom class that is convertible to reference
/// We require our own reference because it is registered in iterator_traits
reference operator[](difference_type d) const { bit_aligned_pixel_iterator it=*this; it.advance(d); return *it; }
reference operator->() const { return **this; }
const bit_range_t& bit_range() const { return _bit_range; }
bit_range_t& bit_range() { return _bit_range; }
private:
bit_range_t _bit_range;
static constexpr int bit_size = NonAlignedPixelReference::bit_size;
friend class boost::iterator_core_access;
reference dereference() const { return NonAlignedPixelReference(_bit_range); }
void increment() { ++_bit_range; }
void decrement() { --_bit_range; }
void advance(difference_type d) { _bit_range.bit_advance(d*bit_size); }
difference_type distance_to(const bit_aligned_pixel_iterator& it) const { return _bit_range.bit_distance_to(it._bit_range) / bit_size; }
bool equal(const bit_aligned_pixel_iterator& it) const { return _bit_range==it._bit_range; }
};
template <typename NonAlignedPixelReference>
struct const_iterator_type<bit_aligned_pixel_iterator<NonAlignedPixelReference>>
{
using type =
bit_aligned_pixel_iterator<typename NonAlignedPixelReference::const_reference>;
};
template <typename NonAlignedPixelReference>
struct iterator_is_mutable<bit_aligned_pixel_iterator<NonAlignedPixelReference>>
: std::integral_constant<bool, NonAlignedPixelReference::is_mutable>
{};
template <typename NonAlignedPixelReference>
struct is_iterator_adaptor<bit_aligned_pixel_iterator<NonAlignedPixelReference>>
: std::false_type
{};
/////////////////////////////
// PixelBasedConcept
/////////////////////////////
template <typename NonAlignedPixelReference>
struct color_space_type<bit_aligned_pixel_iterator<NonAlignedPixelReference> > : public color_space_type<NonAlignedPixelReference> {};
template <typename NonAlignedPixelReference>
struct channel_mapping_type<bit_aligned_pixel_iterator<NonAlignedPixelReference> > : public channel_mapping_type<NonAlignedPixelReference> {};
template <typename NonAlignedPixelReference>
struct is_planar<bit_aligned_pixel_iterator<NonAlignedPixelReference> > : public is_planar<NonAlignedPixelReference> {}; // == false
/////////////////////////////
// MemoryBasedIteratorConcept
/////////////////////////////
template <typename NonAlignedPixelReference>
struct byte_to_memunit<bit_aligned_pixel_iterator<NonAlignedPixelReference>>
: std::integral_constant<int, 8>
{};
template <typename NonAlignedPixelReference>
inline std::ptrdiff_t memunit_step(const bit_aligned_pixel_iterator<NonAlignedPixelReference>&) {
return NonAlignedPixelReference::bit_size;
}
template <typename NonAlignedPixelReference>
inline std::ptrdiff_t memunit_distance(const bit_aligned_pixel_iterator<NonAlignedPixelReference>& p1, const bit_aligned_pixel_iterator<NonAlignedPixelReference>& p2) {
return (p2.bit_range().current_byte() - p1.bit_range().current_byte())*8 + p2.bit_range().bit_offset() - p1.bit_range().bit_offset();
}
template <typename NonAlignedPixelReference>
inline void memunit_advance(bit_aligned_pixel_iterator<NonAlignedPixelReference>& p, std::ptrdiff_t diff) {
p.bit_range().bit_advance(diff);
}
template <typename NonAlignedPixelReference>
inline bit_aligned_pixel_iterator<NonAlignedPixelReference> memunit_advanced(const bit_aligned_pixel_iterator<NonAlignedPixelReference>& p, std::ptrdiff_t diff) {
bit_aligned_pixel_iterator<NonAlignedPixelReference> ret=p;
memunit_advance(ret, diff);
return ret;
}
template <typename NonAlignedPixelReference> inline
NonAlignedPixelReference memunit_advanced_ref(bit_aligned_pixel_iterator<NonAlignedPixelReference> it, std::ptrdiff_t diff) {
return *memunit_advanced(it,diff);
}
/////////////////////////////
// HasDynamicXStepTypeConcept
/////////////////////////////
template <typename NonAlignedPixelReference>
struct dynamic_x_step_type<bit_aligned_pixel_iterator<NonAlignedPixelReference> > {
using type = memory_based_step_iterator<bit_aligned_pixel_iterator<NonAlignedPixelReference> >;
};
/////////////////////////////
// iterator_type_from_pixel
/////////////////////////////
template <typename B, typename C, typename L, bool M>
struct iterator_type_from_pixel<const bit_aligned_pixel_reference<B,C,L,M>,false,false,false>
{
using type = bit_aligned_pixel_iterator<bit_aligned_pixel_reference<B,C,L,false>> ;
};
template <typename B, typename C, typename L, bool M>
struct iterator_type_from_pixel<const bit_aligned_pixel_reference<B,C,L,M>,false,false,true>
{
using type = bit_aligned_pixel_iterator<bit_aligned_pixel_reference<B,C,L,true>>;
};
template <typename B, typename C, typename L, bool M, bool IsPlanar, bool IsStep, bool IsMutable>
struct iterator_type_from_pixel<bit_aligned_pixel_reference<B,C,L,M>,IsPlanar,IsStep,IsMutable>
: public iterator_type_from_pixel<const bit_aligned_pixel_reference<B,C,L,M>,IsPlanar,IsStep,IsMutable> {};
} } // namespace boost::gil
namespace std {
// It is important to provide an overload of uninitialized_copy for bit_aligned_pixel_iterator. The default STL implementation calls placement new,
// which is not defined for bit_aligned_pixel_iterator.
template <typename NonAlignedPixelReference>
boost::gil::bit_aligned_pixel_iterator<NonAlignedPixelReference> uninitialized_copy(boost::gil::bit_aligned_pixel_iterator<NonAlignedPixelReference> first,
boost::gil::bit_aligned_pixel_iterator<NonAlignedPixelReference> last,
boost::gil::bit_aligned_pixel_iterator<NonAlignedPixelReference> dst) {
return std::copy(first,last,dst);
}
} // namespace std
#endif

View File

@@ -0,0 +1,390 @@
//
// Copyright 2005-2007 Adobe Systems Incorporated
// Copyright 2019 Mateusz Loskot <mateusz at loskot dot net>
//
// 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_BIT_ALIGNED_PIXEL_REFERENCE_HPP
#define BOOST_GIL_BIT_ALIGNED_PIXEL_REFERENCE_HPP
#include <boost/gil/pixel.hpp>
#include <boost/gil/channel.hpp>
#include <boost/gil/detail/mp11.hpp>
#include <boost/assert.hpp>
#include <boost/config.hpp>
#include <functional>
#include <type_traits>
namespace boost { namespace gil {
/// A model of a heterogeneous pixel that is not byte aligned.
/// Examples are bitmap (1-bit pixels) or 6-bit RGB (222).
/////////////////////////////
// bit_range
//
// Represents a range of bits that can span multiple consecutive bytes. The range has a size fixed at compile time, but the offset is specified at run time.
/////////////////////////////
template <int RangeSize, bool IsMutable>
class bit_range {
public:
using byte_t = mp11::mp_if_c<IsMutable, unsigned char, unsigned char const>;
using difference_type = std::ptrdiff_t;
template <int RS, bool M> friend class bit_range;
private:
byte_t* _current_byte; // the starting byte of the bit range
int _bit_offset; // offset from the beginning of the current byte. 0<=_bit_offset<=7
public:
bit_range() : _current_byte(nullptr), _bit_offset(0) {}
bit_range(byte_t* current_byte, int bit_offset)
: _current_byte(current_byte)
, _bit_offset(bit_offset)
{
BOOST_ASSERT(bit_offset >= 0 && bit_offset < 8);
}
bit_range(const bit_range& br) : _current_byte(br._current_byte), _bit_offset(br._bit_offset) {}
template <bool M> bit_range(const bit_range<RangeSize,M>& br) : _current_byte(br._current_byte), _bit_offset(br._bit_offset) {}
bit_range& operator=(const bit_range& br) { _current_byte = br._current_byte; _bit_offset=br._bit_offset; return *this; }
bool operator==(const bit_range& br) const { return _current_byte==br._current_byte && _bit_offset==br._bit_offset; }
bit_range& operator++() {
_current_byte += (_bit_offset+RangeSize) / 8;
_bit_offset = (_bit_offset+RangeSize) % 8;
return *this;
}
bit_range& operator--() { bit_advance(-RangeSize); return *this; }
void bit_advance(difference_type num_bits) {
int new_offset = int(_bit_offset+num_bits);
_current_byte += new_offset / 8;
_bit_offset = new_offset % 8;
if (_bit_offset<0) {
_bit_offset+=8;
--_current_byte;
}
}
difference_type bit_distance_to(const bit_range& b) const {
return (b.current_byte() - current_byte())*8 + b.bit_offset()-bit_offset();
}
byte_t* current_byte() const { return _current_byte; }
int bit_offset() const { return _bit_offset; }
};
/// \defgroup ColorBaseModelNonAlignedPixel bit_aligned_pixel_reference
/// \ingroup ColorBaseModel
/// \brief A heterogeneous color base representing pixel that may not be byte aligned, i.e. it may correspond to a bit range that does not start/end at a byte boundary. Models ColorBaseConcept.
///
/// \defgroup PixelModelNonAlignedPixel bit_aligned_pixel_reference
/// \ingroup PixelModel
/// \brief A heterogeneous pixel reference used to represent non-byte-aligned pixels. Models PixelConcept
///
/// Example:
/// \code
/// unsigned char data=0;
///
/// // A mutable reference to a 6-bit BGR pixel in "123" format (1 bit for red, 2 bits for green, 3 bits for blue)
/// using rgb123_ref_t = bit_aligned_pixel_reference<unsigned char, mp11::mp_list_c<int,1,2,3>, rgb_layout_t, true> const;
///
/// // create the pixel reference at bit offset 2
/// // (i.e. red = [2], green = [3,4], blue = [5,6,7] bits)
/// rgb123_ref_t ref(&data, 2);
/// get_color(ref, red_t()) = 1;
/// assert(data == 0x04);
/// get_color(ref, green_t()) = 3;
/// assert(data == 0x1C);
/// get_color(ref, blue_t()) = 7;
/// assert(data == 0xFC);
/// \endcode
///
/// \ingroup ColorBaseModelNonAlignedPixel PixelModelNonAlignedPixel PixelBasedModel
/// \brief Heterogeneous pixel reference corresponding to non-byte-aligned bit range. Models ColorBaseConcept, PixelConcept, PixelBasedConcept
///
/// \tparam BitField
/// \tparam ChannelBitSizes Boost.MP11-compatible list of integral types defining the number of bits for each channel. For example, for 565RGB, mp_list_c<int,5,6,5>
/// \tparam Layout
/// \tparam IsMutable
template <typename BitField, typename ChannelBitSizes, typename Layout, bool IsMutable>
struct bit_aligned_pixel_reference
{
static constexpr int bit_size =
mp11::mp_fold
<
ChannelBitSizes,
std::integral_constant<int, 0>,
mp11::mp_plus
>::value;
using bit_range_t = boost::gil::bit_range<bit_size,IsMutable>;
using bitfield_t = BitField;
using data_ptr_t = mp11::mp_if_c<IsMutable, unsigned char*, const unsigned char*>;
using layout_t = Layout;
using value_type = typename packed_pixel_type<bitfield_t,ChannelBitSizes,Layout>::type;
using reference = const bit_aligned_pixel_reference<BitField, ChannelBitSizes, Layout, IsMutable>;
using const_reference = bit_aligned_pixel_reference<BitField,ChannelBitSizes,Layout,false> const;
static constexpr bool is_mutable = IsMutable;
bit_aligned_pixel_reference(){}
bit_aligned_pixel_reference(data_ptr_t data_ptr, int bit_offset) : _bit_range(data_ptr, bit_offset) {}
explicit bit_aligned_pixel_reference(const bit_range_t& bit_range) : _bit_range(bit_range) {}
template <bool IsMutable2> bit_aligned_pixel_reference(const bit_aligned_pixel_reference<BitField,ChannelBitSizes,Layout,IsMutable2>& p) : _bit_range(p._bit_range) {}
// Grayscale references can be constructed from the channel reference
explicit bit_aligned_pixel_reference(typename kth_element_type<bit_aligned_pixel_reference,0>::type const channel0)
: _bit_range(static_cast<data_ptr_t>(&channel0), channel0.first_bit())
{
static_assert(num_channels<bit_aligned_pixel_reference>::value == 1, "");
}
// Construct from another compatible pixel type
bit_aligned_pixel_reference(bit_aligned_pixel_reference const& p)
: _bit_range(p._bit_range) {}
// TODO: Why p by non-const reference?
template <typename BF, typename CR>
bit_aligned_pixel_reference(packed_pixel<BF, CR, Layout>& p)
: _bit_range(static_cast<data_ptr_t>(&gil::at_c<0>(p)), gil::at_c<0>(p).first_bit())
{
check_compatible<packed_pixel<BF, CR, Layout>>();
}
auto operator=(bit_aligned_pixel_reference const& p) const
-> bit_aligned_pixel_reference const&
{
static_copy(p, *this);
return *this;
}
template <typename P>
auto operator=(P const& p) const -> bit_aligned_pixel_reference const&
{
assign(p, is_pixel<P>());
return *this;
}
template <typename P>
bool operator==(P const& p) const
{
return equal(p, is_pixel<P>());
}
template <typename P>
bool operator!=(P const& p) const { return !(*this==p); }
auto operator->() const -> bit_aligned_pixel_reference const* { return this; }
bit_range_t const& bit_range() const { return _bit_range; }
private:
mutable bit_range_t _bit_range;
template <typename B, typename C, typename L, bool M> friend struct bit_aligned_pixel_reference;
template <typename Pixel> static void check_compatible() { gil_function_requires<PixelsCompatibleConcept<Pixel,bit_aligned_pixel_reference> >(); }
template <typename Pixel>
void assign(Pixel const& p, std::true_type) const
{
check_compatible<Pixel>();
static_copy(p, *this);
}
template <typename Pixel>
bool equal(Pixel const& p, std::true_type) const
{
check_compatible<Pixel>();
return static_equal(*this, p);
}
private:
static void check_gray()
{
static_assert(std::is_same<typename Layout::color_space_t, gray_t>::value, "");
}
template <typename Channel>
void assign(Channel const& channel, std::false_type) const
{
check_gray();
gil::at_c<0>(*this) = channel;
}
template <typename Channel>
bool equal (Channel const& channel, std::false_type) const
{
check_gray();
return gil::at_c<0>(*this) == channel;
}
};
/////////////////////////////
// ColorBasedConcept
/////////////////////////////
template <typename BitField, typename ChannelBitSizes, typename L, bool IsMutable, int K>
struct kth_element_type
<
bit_aligned_pixel_reference<BitField, ChannelBitSizes, L, IsMutable>,
K
>
{
using type = packed_dynamic_channel_reference
<
BitField,
mp11::mp_at_c<ChannelBitSizes, K>::value,
IsMutable
> const;
};
template <typename B, typename C, typename L, bool M, int K>
struct kth_element_reference_type<bit_aligned_pixel_reference<B,C,L,M>, K>
: public kth_element_type<bit_aligned_pixel_reference<B,C,L,M>, K> {};
template <typename B, typename C, typename L, bool M, int K>
struct kth_element_const_reference_type<bit_aligned_pixel_reference<B,C,L,M>, K>
: public kth_element_type<bit_aligned_pixel_reference<B,C,L,M>, K> {};
namespace detail {
// returns sum of IntegralVector[0] ... IntegralVector[K-1]
template <typename IntegralVector, int K>
struct sum_k
: mp11::mp_plus
<
sum_k<IntegralVector, K - 1>,
typename mp11::mp_at_c<IntegralVector, K - 1>::type
>
{};
template <typename IntegralVector>
struct sum_k<IntegralVector, 0> : std::integral_constant<int, 0> {};
} // namespace detail
// at_c required by MutableColorBaseConcept
template <int K, typename BitField, typename ChannelBitSizes, typename L, bool IsMutable>
inline
auto at_c(const bit_aligned_pixel_reference<BitField, ChannelBitSizes, L, IsMutable>& p)
-> typename kth_element_reference_type<bit_aligned_pixel_reference<BitField, ChannelBitSizes, L, IsMutable>, K>::type
{
using pixel_t = bit_aligned_pixel_reference<BitField, ChannelBitSizes, L, IsMutable>;
using channel_t = typename kth_element_reference_type<pixel_t, K>::type;
using bit_range_t = typename pixel_t::bit_range_t;
bit_range_t bit_range(p.bit_range());
bit_range.bit_advance(detail::sum_k<ChannelBitSizes, K>::value);
return channel_t(bit_range.current_byte(), bit_range.bit_offset());
}
/////////////////////////////
// PixelConcept
/////////////////////////////
/// Metafunction predicate that flags bit_aligned_pixel_reference as a model of PixelConcept. Required by PixelConcept
template <typename B, typename C, typename L, bool M>
struct is_pixel<bit_aligned_pixel_reference<B, C, L, M> > : std::true_type {};
/////////////////////////////
// PixelBasedConcept
/////////////////////////////
template <typename B, typename C, typename L, bool M>
struct color_space_type<bit_aligned_pixel_reference<B, C, L, M>>
{
using type = typename L::color_space_t;
};
template <typename B, typename C, typename L, bool M>
struct channel_mapping_type<bit_aligned_pixel_reference<B, C, L, M>>
{
using type = typename L::channel_mapping_t;
};
template <typename B, typename C, typename L, bool M>
struct is_planar<bit_aligned_pixel_reference<B, C, L, M>> : std::false_type {};
/////////////////////////////
// pixel_reference_type
/////////////////////////////
// Constructs a homogeneous bit_aligned_pixel_reference given a channel reference
template <typename BitField, int NumBits, typename Layout>
struct pixel_reference_type
<
packed_dynamic_channel_reference<BitField, NumBits, false> const,
Layout, false, false
>
{
private:
using channel_bit_sizes_t = mp11::mp_repeat
<
mp11::mp_list<std::integral_constant<unsigned, NumBits>>,
mp11::mp_size<typename Layout::color_space_t>
>;
public:
using type =
bit_aligned_pixel_reference<BitField, channel_bit_sizes_t, Layout, false>;
};
// Same but for the mutable case. We cannot combine the mutable
// and read-only cases because this triggers ambiguity
template <typename BitField, int NumBits, typename Layout>
struct pixel_reference_type
<
packed_dynamic_channel_reference<BitField, NumBits, true> const,
Layout, false, true
>
{
private:
using channel_bit_sizes_t = mp11::mp_repeat
<
mp11::mp_list<std::integral_constant<unsigned, NumBits>>,
mp11::mp_size<typename Layout::color_space_t>
>;
public:
using type = bit_aligned_pixel_reference<BitField, channel_bit_sizes_t, Layout, true>;
};
} } // namespace boost::gil
namespace std {
// We are forced to define swap inside std namespace because on some platforms (Visual Studio 8) STL calls swap qualified.
// swap with 'left bias':
// - swap between proxy and anything
// - swap between value type and proxy
// - swap between proxy and proxy
// Having three overloads allows us to swap between different (but compatible) models of PixelConcept
template <typename B, typename C, typename L, typename R> inline
void swap(const boost::gil::bit_aligned_pixel_reference<B,C,L,true> x, R& y) {
boost::gil::swap_proxy<typename boost::gil::bit_aligned_pixel_reference<B,C,L,true>::value_type>(x,y);
}
template <typename B, typename C, typename L> inline
void swap(typename boost::gil::bit_aligned_pixel_reference<B,C,L,true>::value_type& x, const boost::gil::bit_aligned_pixel_reference<B,C,L,true> y) {
boost::gil::swap_proxy<typename boost::gil::bit_aligned_pixel_reference<B,C,L,true>::value_type>(x,y);
}
template <typename B, typename C, typename L> inline
void swap(const boost::gil::bit_aligned_pixel_reference<B,C,L,true> x, const boost::gil::bit_aligned_pixel_reference<B,C,L,true> y) {
boost::gil::swap_proxy<typename boost::gil::bit_aligned_pixel_reference<B,C,L,true>::value_type>(x,y);
}
} // namespace std
#endif

View File

@@ -0,0 +1,723 @@
//
// 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_CHANNEL_HPP
#define BOOST_GIL_CHANNEL_HPP
#include <boost/gil/utilities.hpp>
#include <boost/assert.hpp>
#include <boost/config.hpp>
#include <boost/config/pragma_message.hpp>
#include <boost/integer/integer_mask.hpp>
#include <cstdint>
#include <limits>
#include <type_traits>
#ifdef BOOST_GIL_DOXYGEN_ONLY
/// \def BOOST_GIL_CONFIG_HAS_UNALIGNED_ACCESS
/// \brief Define to allow unaligned memory access for models of packed channel value.
/// Theoretically (or historically?) on platforms which support dereferencing on
/// non-word memory boundary, unaligned access may result in performance improvement.
/// \warning Unfortunately, this optimization may be a C/C++ strict aliasing rules
/// violation, if accessed data buffer has effective type that cannot be aliased
/// without leading to undefined behaviour.
#define BOOST_GIL_CONFIG_HAS_UNALIGNED_ACCESS
#endif
#ifdef BOOST_GIL_CONFIG_HAS_UNALIGNED_ACCESS
#if defined(sun) || defined(__sun) || \ // SunOS
defined(__osf__) || defined(__osf) || \ // Tru64
defined(_hpux) || defined(hpux) || \ // HP-UX
defined(__arm__) || defined(__ARM_ARCH) || \ // ARM
defined(_AIX) // AIX
#error Unaligned access strictly disabled for some UNIX platforms or ARM architecture
#elif defined(__i386__) || defined(__x86_64__) || defined(__vax__)
// The check for little-endian architectures that tolerate unaligned memory
// accesses is just an optimization. Nothing will break if it fails to detect
// a suitable architecture.
//
// Unfortunately, this optimization may be a C/C++ strict aliasing rules violation
// if accessed data buffer has effective type that cannot be aliased
// without leading to undefined behaviour.
BOOST_PRAGMA_MESSAGE("CAUTION: Unaligned access tolerated on little-endian may cause undefined behaviour")
#else
#error Unaligned access disabled for unknown platforms and architectures
#endif
#endif // defined(BOOST_GIL_CONFIG_HAS_UNALIGNED_ACCESS)
namespace boost { namespace gil {
///////////////////////////////////////////
//// channel_traits
////
//// \ingroup ChannelModel
//// \class channel_traits
//// \brief defines properties of channels, such as their range and associated types
////
//// The channel traits must be defined for every model of ChannelConcept
//// Default traits are provided. For built-in types the default traits use
//// built-in pointer and reference and the channel range is the physical
//// range of the type. For classes, the default traits forward the associated types
//// and range to the class.
////
///////////////////////////////////////////
namespace detail {
template <typename T, bool IsClass>
struct channel_traits_impl;
// channel traits for custom class
template <typename T>
struct channel_traits_impl<T, true>
{
using value_type = typename T::value_type;
using reference = typename T::reference;
using pointer = typename T::pointer;
using const_reference = typename T::const_reference;
using const_pointer = typename T::const_pointer;
static constexpr bool is_mutable = T::is_mutable;
static value_type min_value() { return T::min_value(); }
static value_type max_value() { return T::max_value(); }
};
// channel traits implementation for built-in integral or floating point channel type
template <typename T>
struct channel_traits_impl<T, false>
{
using value_type = T;
using reference = T&;
using pointer = T*;
using const_reference = T const&;
using const_pointer = T const*;
static constexpr bool is_mutable = true;
static value_type min_value() { return (std::numeric_limits<T>::min)(); }
static value_type max_value() { return (std::numeric_limits<T>::max)(); }
};
// channel traits implementation for constant built-in scalar or floating point type
template <typename T>
struct channel_traits_impl<T const, false> : channel_traits_impl<T, false>
{
using reference = T const&;
using pointer = T const*;
static constexpr bool is_mutable = false;
};
} // namespace detail
/**
\ingroup ChannelModel
\brief Traits for channels. Contains the following members:
\code
template <typename Channel>
struct channel_traits {
using value_type = ...;
using reference = ...;
using pointer = ...;
using const_reference = ...;
using const_pointer = ...;
static const bool is_mutable;
static value_type min_value();
static value_type max_value();
};
\endcode
*/
template <typename T>
struct channel_traits : detail::channel_traits_impl<T, std::is_class<T>::value> {};
// Channel traits for C++ reference type - remove the reference
template <typename T>
struct channel_traits<T&> : channel_traits<T> {};
// Channel traits for constant C++ reference type
template <typename T>
struct channel_traits<T const&> : channel_traits<T>
{
using reference = typename channel_traits<T>::const_reference;
using pointer = typename channel_traits<T>::const_pointer;
static constexpr bool is_mutable = false;
};
///////////////////////////////////////////
//// scoped_channel_value
///////////////////////////////////////////
/// \defgroup ScopedChannelValue scoped_channel_value
/// \ingroup ChannelModel
/// \brief A channel adaptor that modifies the range of the source channel. Models: ChannelValueConcept
///
/// Example:
/// \code
/// // Create a double channel with range [-0.5 .. 0.5]
/// struct double_minus_half { static double apply() { return -0.5; } };
/// struct double_plus_half { static double apply() { return 0.5; } };
/// using bits64custom_t = scoped_channel_value<double, double_minus_half, double_plus_half>;
///
/// // channel_convert its maximum should map to the maximum
/// bits64custom_t x = channel_traits<bits64custom_t>::max_value();
/// assert(x == 0.5);
/// uint16_t y = channel_convert<uint16_t>(x);
/// assert(y == 65535);
/// \endcode
/// \ingroup ScopedChannelValue
/// \brief A channel adaptor that modifies the range of the source channel. Models: ChannelValueConcept
/// \tparam BaseChannelValue base channel (models ChannelValueConcept)
/// \tparam MinVal class with a static apply() function returning the minimum channel values
/// \tparam MaxVal class with a static apply() function returning the maximum channel values
template <typename BaseChannelValue, typename MinVal, typename MaxVal>
struct scoped_channel_value
{
using value_type = scoped_channel_value<BaseChannelValue, MinVal, MaxVal>;
using reference = value_type&;
using pointer = value_type*;
using const_reference = value_type const&;
using const_pointer = value_type const*;
static constexpr bool is_mutable = channel_traits<BaseChannelValue>::is_mutable;
using base_channel_t = BaseChannelValue;
static value_type min_value() { return MinVal::apply(); }
static value_type max_value() { return MaxVal::apply(); }
scoped_channel_value() = default;
scoped_channel_value(scoped_channel_value const& other) : value_(other.value_) {}
scoped_channel_value& operator=(scoped_channel_value const& other) = default;
scoped_channel_value(BaseChannelValue value) : value_(value) {}
scoped_channel_value& operator=(BaseChannelValue value)
{
value_ = value;
return *this;
}
scoped_channel_value& operator++() { ++value_; return *this; }
scoped_channel_value& operator--() { --value_; return *this; }
scoped_channel_value operator++(int) { scoped_channel_value tmp=*this; this->operator++(); return tmp; }
scoped_channel_value operator--(int) { scoped_channel_value tmp=*this; this->operator--(); return tmp; }
template <typename Scalar2> scoped_channel_value& operator+=(Scalar2 v) { value_+=v; return *this; }
template <typename Scalar2> scoped_channel_value& operator-=(Scalar2 v) { value_-=v; return *this; }
template <typename Scalar2> scoped_channel_value& operator*=(Scalar2 v) { value_*=v; return *this; }
template <typename Scalar2> scoped_channel_value& operator/=(Scalar2 v) { value_/=v; return *this; }
operator BaseChannelValue() const { return value_; }
private:
BaseChannelValue value_{};
};
template <typename T>
struct float_point_zero
{
static constexpr T apply() { return 0.0f; }
};
template <typename T>
struct float_point_one
{
static constexpr T apply() { return 1.0f; }
};
///////////////////////////////////////////
//// Support for sub-byte channels. These are integral channels whose value is contained in a range of bits inside an integral type
///////////////////////////////////////////
// It is necessary for packed channels to have their own value type. They cannot simply use an integral large enough to store the data. Here is why:
// - Any operation that requires returning the result by value will otherwise return the built-in integral type, which will have incorrect range
// That means that after getting the value of the channel we cannot properly do channel_convert, channel_invert, etc.
// - Two channels are declared compatible if they have the same value type. That means that a packed channel is incorrectly declared compatible with an integral type
namespace detail {
// returns the smallest fast unsigned integral type that has at least NumBits bits
template <int NumBits>
struct min_fast_uint :
std::conditional
<
NumBits <= 8,
std::uint_least8_t,
typename std::conditional
<
NumBits <= 16,
std::uint_least16_t,
typename std::conditional
<
NumBits <= 32,
std::uint_least32_t,
std::uintmax_t
>::type
>::type
>
{};
template <int NumBits>
struct num_value_fn
: std::conditional<NumBits < 32, std::uint32_t, std::uint64_t>
{};
template <int NumBits>
struct max_value_fn
: std::conditional<NumBits <= 32, std::uint32_t, std::uint64_t>
{};
} // namespace detail
/// \defgroup PackedChannelValueModel packed_channel_value
/// \ingroup ChannelModel
/// \brief Represents the value of an unsigned integral channel operating over a bit range. Models: ChannelValueConcept
/// Example:
/// \code
/// // A 4-bit unsigned integral channel.
/// using bits4 = packed_channel_value<4>;
///
/// assert(channel_traits<bits4>::min_value()==0);
/// assert(channel_traits<bits4>::max_value()==15);
/// assert(sizeof(bits4)==1);
/// static_assert(gil::is_channel_integral<bits4>::value, "");
/// \endcode
/// \ingroup PackedChannelValueModel
/// \brief The value of a subbyte channel. Models: ChannelValueConcept
template <int NumBits>
class packed_channel_value
{
public:
using integer_t = typename detail::min_fast_uint<NumBits>::type;
using value_type = packed_channel_value<NumBits>;
using reference = value_type&;
using const_reference = value_type const&;
using pointer = value_type*;
using const_pointer = value_type const*;
static constexpr bool is_mutable = true;
static value_type min_value() { return 0; }
static value_type max_value() { return low_bits_mask_t< NumBits >::sig_bits; }
packed_channel_value() = default;
packed_channel_value(integer_t v)
{
value_ = static_cast<integer_t>(v & low_bits_mask_t<NumBits>::sig_bits_fast);
}
template <typename Scalar>
packed_channel_value(Scalar v)
{
value_ = packed_channel_value(static_cast<integer_t>(v));
}
static unsigned int num_bits() { return NumBits; }
operator integer_t() const { return value_; }
private:
integer_t value_{};
};
namespace detail {
template <std::size_t K>
struct static_copy_bytes
{
void operator()(unsigned char const* from, unsigned char* to) const
{
*to = *from;
static_copy_bytes<K - 1>()(++from, ++to);
}
};
template <>
struct static_copy_bytes<0>
{
void operator()(unsigned char const*, unsigned char*) const {}
};
template <typename Derived, typename BitField, int NumBits, bool IsMutable>
class packed_channel_reference_base
{
protected:
using data_ptr_t = typename std::conditional<IsMutable, void*, void const*>::type;
public:
data_ptr_t _data_ptr; // void* pointer to the first byte of the bit range
using value_type = packed_channel_value<NumBits>;
using reference = const Derived;
using pointer = value_type *;
using const_pointer = const value_type *;
static constexpr int num_bits = NumBits;
static constexpr bool is_mutable = IsMutable;
static value_type min_value() { return channel_traits<value_type>::min_value(); }
static value_type max_value() { return channel_traits<value_type>::max_value(); }
using bitfield_t = BitField;
using integer_t = typename value_type::integer_t;
packed_channel_reference_base(data_ptr_t data_ptr) : _data_ptr(data_ptr) {}
packed_channel_reference_base(const packed_channel_reference_base& ref) : _data_ptr(ref._data_ptr) {}
const Derived& operator=(integer_t v) const { set(v); return derived(); }
const Derived& operator++() const { set(get()+1); return derived(); }
const Derived& operator--() const { set(get()-1); return derived(); }
Derived operator++(int) const { Derived tmp=derived(); this->operator++(); return tmp; }
Derived operator--(int) const { Derived tmp=derived(); this->operator--(); return tmp; }
template <typename Scalar2> const Derived& operator+=(Scalar2 v) const { set( static_cast<integer_t>( get() + v )); return derived(); }
template <typename Scalar2> const Derived& operator-=(Scalar2 v) const { set( static_cast<integer_t>( get() - v )); return derived(); }
template <typename Scalar2> const Derived& operator*=(Scalar2 v) const { set( static_cast<integer_t>( get() * v )); return derived(); }
template <typename Scalar2> const Derived& operator/=(Scalar2 v) const { set( static_cast<integer_t>( get() / v )); return derived(); }
operator integer_t() const { return get(); }
data_ptr_t operator &() const {return _data_ptr;}
protected:
using num_value_t = typename detail::num_value_fn<NumBits>::type;
using max_value_t = typename detail::max_value_fn<NumBits>::type;
static const num_value_t num_values = static_cast< num_value_t >( 1 ) << NumBits ;
static const max_value_t max_val = static_cast< max_value_t >( num_values - 1 );
#if defined(BOOST_GIL_CONFIG_HAS_UNALIGNED_ACCESS)
const bitfield_t& get_data() const { return *static_cast<const bitfield_t*>(_data_ptr); }
void set_data(const bitfield_t& val) const { *static_cast< bitfield_t*>(_data_ptr) = val; }
#else
bitfield_t get_data() const {
bitfield_t ret;
static_copy_bytes<sizeof(bitfield_t) >()(gil_reinterpret_cast_c<const unsigned char*>(_data_ptr),gil_reinterpret_cast<unsigned char*>(&ret));
return ret;
}
void set_data(const bitfield_t& val) const {
static_copy_bytes<sizeof(bitfield_t) >()(gil_reinterpret_cast_c<const unsigned char*>(&val),gil_reinterpret_cast<unsigned char*>(_data_ptr));
}
#endif
private:
void set(integer_t value) const { // can this be done faster??
this->derived().set_unsafe(((value % num_values) + num_values) % num_values);
}
integer_t get() const { return derived().get(); }
const Derived& derived() const { return static_cast<const Derived&>(*this); }
};
} // namespace detail
/// \defgroup PackedChannelReferenceModel packed_channel_reference
/// \ingroup ChannelModel
/// \brief Represents a reference proxy to a channel operating over a bit range whose offset is fixed at compile time. Models ChannelConcept
/// Example:
/// \code
/// // Reference to a 2-bit channel starting at bit 1 (i.e. the second bit)
/// using bits2_1_ref_t = packed_channel_reference<uint16_t,1,2,true> const;
///
/// uint16_t data=0;
/// bits2_1_ref_t channel_ref(&data);
/// channel_ref = channel_traits<bits2_1_ref_t>::max_value(); // == 3
/// assert(data == 6); // == 3<<1 == 6
/// \endcode
/// \tparam BitField A type that holds the bits of the pixel from which the channel is referenced. Typically an integral type, like std::uint16_t
/// \tparam Defines the sequence of bits in the data value that contain the channel
/// \tparam true if the reference is mutable
template <typename BitField, int FirstBit, int NumBits, bool IsMutable>
class packed_channel_reference;
/// \tparam A type that holds the bits of the pixel from which the channel is referenced. Typically an integral type, like std::uint16_t
/// \tparam Defines the sequence of bits in the data value that contain the channel
/// \tparam true if the reference is mutable
template <typename BitField, int NumBits, bool IsMutable>
class packed_dynamic_channel_reference;
/// \ingroup PackedChannelReferenceModel
/// \brief A constant subbyte channel reference whose bit offset is fixed at compile time. Models ChannelConcept
template <typename BitField, int FirstBit, int NumBits>
class packed_channel_reference<BitField, FirstBit, NumBits, false>
: public detail::packed_channel_reference_base
<
packed_channel_reference<BitField, FirstBit, NumBits, false>,
BitField,
NumBits,
false
>
{
using parent_t = detail::packed_channel_reference_base
<
packed_channel_reference<BitField, FirstBit, NumBits, false>,
BitField,
NumBits,
false
>;
friend class packed_channel_reference<BitField, FirstBit, NumBits, true>;
static const BitField channel_mask = static_cast<BitField>(parent_t::max_val) << FirstBit;
void operator=(packed_channel_reference const&);
public:
using const_reference = packed_channel_reference<BitField,FirstBit,NumBits,false> const;
using mutable_reference = packed_channel_reference<BitField,FirstBit,NumBits,true> const;
using integer_t = typename parent_t::integer_t;
explicit packed_channel_reference(const void* data_ptr) : parent_t(data_ptr) {}
packed_channel_reference(const packed_channel_reference& ref) : parent_t(ref._data_ptr) {}
packed_channel_reference(const mutable_reference& ref) : parent_t(ref._data_ptr) {}
unsigned first_bit() const { return FirstBit; }
integer_t get() const { return integer_t((this->get_data()&channel_mask) >> FirstBit); }
};
/// \ingroup PackedChannelReferenceModel
/// \brief A mutable subbyte channel reference whose bit offset is fixed at compile time. Models ChannelConcept
template <typename BitField, int FirstBit, int NumBits>
class packed_channel_reference<BitField,FirstBit,NumBits,true>
: public detail::packed_channel_reference_base<packed_channel_reference<BitField,FirstBit,NumBits,true>,BitField,NumBits,true>
{
using parent_t = detail::packed_channel_reference_base<packed_channel_reference<BitField,FirstBit,NumBits,true>,BitField,NumBits,true>;
friend class packed_channel_reference<BitField,FirstBit,NumBits,false>;
static const BitField channel_mask = static_cast< BitField >( parent_t::max_val ) << FirstBit;
public:
using const_reference = packed_channel_reference<BitField,FirstBit,NumBits,false> const;
using mutable_reference = packed_channel_reference<BitField,FirstBit,NumBits,true> const;
using integer_t = typename parent_t::integer_t;
explicit packed_channel_reference(void* data_ptr) : parent_t(data_ptr) {}
packed_channel_reference(const packed_channel_reference& ref) : parent_t(ref._data_ptr) {}
packed_channel_reference const& operator=(integer_t value) const
{
BOOST_ASSERT(value <= parent_t::max_val);
set_unsafe(value);
return *this;
}
const packed_channel_reference& operator=(const mutable_reference& ref) const { set_from_reference(ref.get_data()); return *this; }
const packed_channel_reference& operator=(const const_reference& ref) const { set_from_reference(ref.get_data()); return *this; }
template <bool Mutable1>
const packed_channel_reference& operator=(const packed_dynamic_channel_reference<BitField,NumBits,Mutable1>& ref) const { set_unsafe(ref.get()); return *this; }
unsigned first_bit() const { return FirstBit; }
integer_t get() const { return integer_t((this->get_data()&channel_mask) >> FirstBit); }
void set_unsafe(integer_t value) const { this->set_data((this->get_data() & ~channel_mask) | (( static_cast< BitField >( value )<<FirstBit))); }
private:
void set_from_reference(const BitField& other_bits) const { this->set_data((this->get_data() & ~channel_mask) | (other_bits & channel_mask)); }
};
}} // namespace boost::gil
namespace std {
// We are forced to define swap inside std namespace because on some platforms (Visual Studio 8) STL calls swap qualified.
// swap with 'left bias':
// - swap between proxy and anything
// - swap between value type and proxy
// - swap between proxy and proxy
/// \ingroup PackedChannelReferenceModel
/// \brief swap for packed_channel_reference
template <typename BF, int FB, int NB, bool M, typename R>
inline
void swap(boost::gil::packed_channel_reference<BF, FB, NB, M> const x, R& y)
{
boost::gil::swap_proxy
<
typename boost::gil::packed_channel_reference<BF, FB, NB, M>::value_type
>(x, y);
}
/// \ingroup PackedChannelReferenceModel
/// \brief swap for packed_channel_reference
template <typename BF, int FB, int NB, bool M>
inline
void swap(
typename boost::gil::packed_channel_reference<BF, FB, NB, M>::value_type& x,
boost::gil::packed_channel_reference<BF, FB, NB, M> const y)
{
boost::gil::swap_proxy
<
typename boost::gil::packed_channel_reference<BF, FB, NB, M>::value_type
>(x,y);
}
/// \ingroup PackedChannelReferenceModel
/// \brief swap for packed_channel_reference
template <typename BF, int FB, int NB, bool M> inline
void swap(
boost::gil::packed_channel_reference<BF, FB, NB, M> const x,
boost::gil::packed_channel_reference<BF, FB, NB, M> const y)
{
boost::gil::swap_proxy
<
typename boost::gil::packed_channel_reference<BF, FB, NB, M>::value_type
>(x,y);
}
} // namespace std
namespace boost { namespace gil {
/// \defgroup PackedChannelDynamicReferenceModel packed_dynamic_channel_reference
/// \ingroup ChannelModel
/// \brief Represents a reference proxy to a channel operating over a bit range whose offset is specified at run time. Models ChannelConcept
///
/// Example:
/// \code
/// // Reference to a 2-bit channel whose offset is specified at construction time
/// using bits2_dynamic_ref_t = packed_dynamic_channel_reference<uint8_t,2,true> const;
///
/// uint16_t data=0;
/// bits2_dynamic_ref_t channel_ref(&data,1);
/// channel_ref = channel_traits<bits2_dynamic_ref_t>::max_value(); // == 3
/// assert(data == 6); // == (3<<1) == 6
/// \endcode
/// \brief Models a constant subbyte channel reference whose bit offset is a runtime parameter. Models ChannelConcept
/// Same as packed_channel_reference, except that the offset is a runtime parameter
/// \ingroup PackedChannelDynamicReferenceModel
template <typename BitField, int NumBits>
class packed_dynamic_channel_reference<BitField,NumBits,false>
: public detail::packed_channel_reference_base<packed_dynamic_channel_reference<BitField,NumBits,false>,BitField,NumBits,false>
{
using parent_t = detail::packed_channel_reference_base<packed_dynamic_channel_reference<BitField,NumBits,false>,BitField,NumBits,false>;
friend class packed_dynamic_channel_reference<BitField,NumBits,true>;
unsigned _first_bit; // 0..7
void operator=(const packed_dynamic_channel_reference&);
public:
using const_reference = packed_dynamic_channel_reference<BitField,NumBits,false> const;
using mutable_reference = packed_dynamic_channel_reference<BitField,NumBits,true> const;
using integer_t = typename parent_t::integer_t;
packed_dynamic_channel_reference(const void* data_ptr, unsigned first_bit) : parent_t(data_ptr), _first_bit(first_bit) {}
packed_dynamic_channel_reference(const const_reference& ref) : parent_t(ref._data_ptr), _first_bit(ref._first_bit) {}
packed_dynamic_channel_reference(const mutable_reference& ref) : parent_t(ref._data_ptr), _first_bit(ref._first_bit) {}
unsigned first_bit() const { return _first_bit; }
integer_t get() const {
const BitField channel_mask = static_cast< integer_t >( parent_t::max_val ) <<_first_bit;
return static_cast< integer_t >(( this->get_data()&channel_mask ) >> _first_bit );
}
};
/// \brief Models a mutable subbyte channel reference whose bit offset is a runtime parameter. Models ChannelConcept
/// Same as packed_channel_reference, except that the offset is a runtime parameter
/// \ingroup PackedChannelDynamicReferenceModel
template <typename BitField, int NumBits>
class packed_dynamic_channel_reference<BitField,NumBits,true>
: public detail::packed_channel_reference_base<packed_dynamic_channel_reference<BitField,NumBits,true>,BitField,NumBits,true>
{
using parent_t = detail::packed_channel_reference_base<packed_dynamic_channel_reference<BitField,NumBits,true>,BitField,NumBits,true>;
friend class packed_dynamic_channel_reference<BitField,NumBits,false>;
unsigned _first_bit;
public:
using const_reference = packed_dynamic_channel_reference<BitField,NumBits,false> const;
using mutable_reference = packed_dynamic_channel_reference<BitField,NumBits,true> const;
using integer_t = typename parent_t::integer_t;
packed_dynamic_channel_reference(void* data_ptr, unsigned first_bit) : parent_t(data_ptr), _first_bit(first_bit) {}
packed_dynamic_channel_reference(const packed_dynamic_channel_reference& ref) : parent_t(ref._data_ptr), _first_bit(ref._first_bit) {}
packed_dynamic_channel_reference const& operator=(integer_t value) const
{
BOOST_ASSERT(value <= parent_t::max_val);
set_unsafe(value);
return *this;
}
const packed_dynamic_channel_reference& operator=(const mutable_reference& ref) const { set_unsafe(ref.get()); return *this; }
const packed_dynamic_channel_reference& operator=(const const_reference& ref) const { set_unsafe(ref.get()); return *this; }
template <typename BitField1, int FirstBit1, bool Mutable1>
const packed_dynamic_channel_reference& operator=(const packed_channel_reference<BitField1, FirstBit1, NumBits, Mutable1>& ref) const
{ set_unsafe(ref.get()); return *this; }
unsigned first_bit() const { return _first_bit; }
integer_t get() const {
const BitField channel_mask = static_cast< integer_t >( parent_t::max_val ) << _first_bit;
return static_cast< integer_t >(( this->get_data()&channel_mask ) >> _first_bit );
}
void set_unsafe(integer_t value) const {
const BitField channel_mask = static_cast< integer_t >( parent_t::max_val ) << _first_bit;
this->set_data((this->get_data() & ~channel_mask) | value<<_first_bit);
}
};
} } // namespace boost::gil
namespace std {
// We are forced to define swap inside std namespace because on some platforms (Visual Studio 8) STL calls swap qualified.
// swap with 'left bias':
// - swap between proxy and anything
// - swap between value type and proxy
// - swap between proxy and proxy
/// \ingroup PackedChannelDynamicReferenceModel
/// \brief swap for packed_dynamic_channel_reference
template <typename BF, int NB, bool M, typename R> inline
void swap(const boost::gil::packed_dynamic_channel_reference<BF,NB,M> x, R& y) {
boost::gil::swap_proxy<typename boost::gil::packed_dynamic_channel_reference<BF,NB,M>::value_type>(x,y);
}
/// \ingroup PackedChannelDynamicReferenceModel
/// \brief swap for packed_dynamic_channel_reference
template <typename BF, int NB, bool M> inline
void swap(typename boost::gil::packed_dynamic_channel_reference<BF,NB,M>::value_type& x, const boost::gil::packed_dynamic_channel_reference<BF,NB,M> y) {
boost::gil::swap_proxy<typename boost::gil::packed_dynamic_channel_reference<BF,NB,M>::value_type>(x,y);
}
/// \ingroup PackedChannelDynamicReferenceModel
/// \brief swap for packed_dynamic_channel_reference
template <typename BF, int NB, bool M> inline
void swap(const boost::gil::packed_dynamic_channel_reference<BF,NB,M> x, const boost::gil::packed_dynamic_channel_reference<BF,NB,M> y) {
boost::gil::swap_proxy<typename boost::gil::packed_dynamic_channel_reference<BF,NB,M>::value_type>(x,y);
}
} // namespace std
// \brief Determines the fundamental type which may be used, e.g., to cast from larger to smaller channel types.
namespace boost { namespace gil {
template <typename T>
struct base_channel_type_impl { using type = T; };
template <int N>
struct base_channel_type_impl<packed_channel_value<N> >
{ using type = typename packed_channel_value<N>::integer_t; };
template <typename B, int F, int N, bool M>
struct base_channel_type_impl<packed_channel_reference<B, F, N, M> >
{
using type = typename packed_channel_reference<B,F,N,M>::integer_t;
};
template <typename B, int N, bool M>
struct base_channel_type_impl<packed_dynamic_channel_reference<B, N, M> >
{
using type = typename packed_dynamic_channel_reference<B,N,M>::integer_t;
};
template <typename ChannelValue, typename MinV, typename MaxV>
struct base_channel_type_impl<scoped_channel_value<ChannelValue, MinV, MaxV> >
{ using type = ChannelValue; };
template <typename T>
struct base_channel_type : base_channel_type_impl<typename std::remove_cv<T>::type> {};
}} //namespace boost::gil
#endif

View File

@@ -0,0 +1,573 @@
//
// 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_GIL_CHANNEL_ALGORITHM_HPP
#define BOOST_GIL_GIL_CHANNEL_ALGORITHM_HPP
#include <boost/gil/channel.hpp>
#include <boost/gil/promote_integral.hpp>
#include <boost/gil/typedefs.hpp>
#include <boost/gil/detail/is_channel_integral.hpp>
#include <boost/gil/detail/mp11.hpp>
#include <limits>
#include <type_traits>
namespace boost { namespace gil {
namespace detail {
// some forward declarations
template <typename SrcChannelV, typename DstChannelV, bool SrcIsIntegral, bool DstIsIntegral>
struct channel_converter_unsigned_impl;
template <typename SrcChannelV, typename DstChannelV, bool SrcIsGreater>
struct channel_converter_unsigned_integral;
template <typename SrcChannelV, typename DstChannelV, bool SrcLessThanDst, bool SrcDivisible>
struct channel_converter_unsigned_integral_impl;
template <typename SrcChannelV, typename DstChannelV, bool SrcLessThanDst, bool CannotFitInInteger>
struct channel_converter_unsigned_integral_nondivisible;
//////////////////////////////////////
//// unsigned_integral_max_value - given an unsigned integral channel type,
//// returns its maximum value as an integral constant
//////////////////////////////////////
template <typename UnsignedIntegralChannel>
struct unsigned_integral_max_value
: std::integral_constant
<
UnsignedIntegralChannel,
(std::numeric_limits<UnsignedIntegralChannel>::max)()
>
{};
template <>
struct unsigned_integral_max_value<uint8_t>
: std::integral_constant<uint32_t, 0xFF>
{};
template <>
struct unsigned_integral_max_value<uint16_t>
: std::integral_constant<uint32_t, 0xFFFF>
{};
template <>
struct unsigned_integral_max_value<uint32_t>
: std::integral_constant<uintmax_t, 0xFFFFFFFF>
{};
template <int K>
struct unsigned_integral_max_value<packed_channel_value<K>>
: std::integral_constant
<
typename packed_channel_value<K>::integer_t,
(uint64_t(1)<<K)-1
>
{};
//////////////////////////////////////
//// unsigned_integral_num_bits - given an unsigned integral channel type,
//// returns the minimum number of bits needed to represent it
//////////////////////////////////////
template <typename UnsignedIntegralChannel>
struct unsigned_integral_num_bits
: std::integral_constant<int, sizeof(UnsignedIntegralChannel) * 8>
{};
template <int K>
struct unsigned_integral_num_bits<packed_channel_value<K>>
: std::integral_constant<int, K>
{};
} // namespace detail
/// \defgroup ChannelConvertAlgorithm channel_convert
/// \brief Converting from one channel type to another
/// \ingroup ChannelAlgorithm
///
/// Conversion is done as a simple linear mapping of one channel range to the other,
/// such that the minimum/maximum value of the source maps to the minimum/maximum value of the destination.
/// One implication of this is that the value 0 of signed channels may not be preserved!
///
/// When creating new channel models, it is often a good idea to provide specializations for the channel conversion algorithms, for
/// example, for performance optimizations. If the new model is an integral type that can be signed, it is easier to define the conversion
/// only for the unsigned type (\p channel_converter_unsigned) and provide specializations of \p detail::channel_convert_to_unsigned
/// and \p detail::channel_convert_from_unsigned to convert between the signed and unsigned type.
///
/// Example:
/// \code
/// // float32_t is a floating point channel with range [0.0f ... 1.0f]
/// float32_t src_channel = channel_traits<float32_t>::max_value();
/// assert(src_channel == 1);
///
/// // uint8_t is 8-bit unsigned integral channel (aliased from unsigned char)
/// uint8_t dst_channel = channel_convert<uint8_t>(src_channel);
/// assert(dst_channel == 255); // max value goes to max value
/// \endcode
///
/// \defgroup ChannelConvertUnsignedAlgorithm channel_converter_unsigned
/// \ingroup ChannelConvertAlgorithm
/// \brief Convert one unsigned/floating point channel to another. Converts both the channel type and range
/// @{
//////////////////////////////////////
//// channel_converter_unsigned
//////////////////////////////////////
template <typename SrcChannelV, typename DstChannelV> // Model ChannelValueConcept
struct channel_converter_unsigned
: detail::channel_converter_unsigned_impl
<
SrcChannelV,
DstChannelV,
detail::is_channel_integral<SrcChannelV>::value,
detail::is_channel_integral<DstChannelV>::value
>
{};
/// \brief Converting a channel to itself - identity operation
template <typename T> struct channel_converter_unsigned<T,T> : public detail::identity<T> {};
namespace detail {
//////////////////////////////////////
//// channel_converter_unsigned_impl
//////////////////////////////////////
/// \brief This is the default implementation. Performance specializatons are provided
template <typename SrcChannelV, typename DstChannelV, bool SrcIsIntegral, bool DstIsIntegral>
struct channel_converter_unsigned_impl {
using argument_type = SrcChannelV;
using result_type = DstChannelV;
DstChannelV operator()(SrcChannelV src) const {
return DstChannelV(channel_traits<DstChannelV>::min_value() +
(src - channel_traits<SrcChannelV>::min_value()) / channel_range<SrcChannelV>() * channel_range<DstChannelV>());
}
private:
template <typename C>
static double channel_range() {
return double(channel_traits<C>::max_value()) - double(channel_traits<C>::min_value());
}
};
// When both the source and the destination are integral channels, perform a faster conversion
template <typename SrcChannelV, typename DstChannelV>
struct channel_converter_unsigned_impl<SrcChannelV, DstChannelV, true, true>
: channel_converter_unsigned_integral
<
SrcChannelV,
DstChannelV,
mp11::mp_less
<
unsigned_integral_max_value<SrcChannelV>,
unsigned_integral_max_value<DstChannelV>
>::value
>
{};
//////////////////////////////////////
//// channel_converter_unsigned_integral
//////////////////////////////////////
template <typename SrcChannelV, typename DstChannelV>
struct channel_converter_unsigned_integral<SrcChannelV,DstChannelV,true>
: public channel_converter_unsigned_integral_impl<SrcChannelV,DstChannelV,true,
!(unsigned_integral_max_value<DstChannelV>::value % unsigned_integral_max_value<SrcChannelV>::value) > {};
template <typename SrcChannelV, typename DstChannelV>
struct channel_converter_unsigned_integral<SrcChannelV,DstChannelV,false>
: public channel_converter_unsigned_integral_impl<SrcChannelV,DstChannelV,false,
!(unsigned_integral_max_value<SrcChannelV>::value % unsigned_integral_max_value<DstChannelV>::value) > {};
//////////////////////////////////////
//// channel_converter_unsigned_integral_impl
//////////////////////////////////////
// Both source and destination are unsigned integral channels,
// the src max value is less than the dst max value,
// and the dst max value is divisible by the src max value
template <typename SrcChannelV, typename DstChannelV>
struct channel_converter_unsigned_integral_impl<SrcChannelV,DstChannelV,true,true> {
DstChannelV operator()(SrcChannelV src) const {
using integer_t = typename unsigned_integral_max_value<DstChannelV>::value_type;
static const integer_t mul = unsigned_integral_max_value<DstChannelV>::value / unsigned_integral_max_value<SrcChannelV>::value;
return DstChannelV(src * mul);
}
};
// Both source and destination are unsigned integral channels,
// the dst max value is less than (or equal to) the src max value,
// and the src max value is divisible by the dst max value
template <typename SrcChannelV, typename DstChannelV>
struct channel_converter_unsigned_integral_impl<SrcChannelV,DstChannelV,false,true> {
DstChannelV operator()(SrcChannelV src) const {
using integer_t = typename unsigned_integral_max_value<SrcChannelV>::value_type;
static const integer_t div = unsigned_integral_max_value<SrcChannelV>::value / unsigned_integral_max_value<DstChannelV>::value;
static const integer_t div2 = div/2;
return DstChannelV((src + div2) / div);
}
};
// Prevent overflow for the largest integral type
template <typename DstChannelV>
struct channel_converter_unsigned_integral_impl<uintmax_t,DstChannelV,false,true> {
DstChannelV operator()(uintmax_t src) const {
static const uintmax_t div = unsigned_integral_max_value<uint32_t>::value / unsigned_integral_max_value<DstChannelV>::value;
static const uintmax_t div2 = div/2;
if (src > unsigned_integral_max_value<uintmax_t>::value - div2)
return unsigned_integral_max_value<DstChannelV>::value;
return DstChannelV((src + div2) / div);
}
};
// Both source and destination are unsigned integral channels,
// and the dst max value is not divisible by the src max value
// See if you can represent the expression (src * dst_max) / src_max in integral form
template <typename SrcChannelV, typename DstChannelV, bool SrcLessThanDst>
struct channel_converter_unsigned_integral_impl<SrcChannelV, DstChannelV, SrcLessThanDst, false>
: channel_converter_unsigned_integral_nondivisible
<
SrcChannelV,
DstChannelV,
SrcLessThanDst,
mp11::mp_less
<
unsigned_integral_num_bits<uintmax_t>,
mp11::mp_plus
<
unsigned_integral_num_bits<SrcChannelV>,
unsigned_integral_num_bits<DstChannelV>
>
>::value
>
{};
// Both source and destination are unsigned integral channels,
// the src max value is less than the dst max value,
// and the dst max value is not divisible by the src max value
// The expression (src * dst_max) / src_max fits in an integer
template <typename SrcChannelV, typename DstChannelV>
struct channel_converter_unsigned_integral_nondivisible<SrcChannelV, DstChannelV, true, false>
{
DstChannelV operator()(SrcChannelV src) const
{
using dest_t = typename base_channel_type<DstChannelV>::type;
return DstChannelV(
static_cast<dest_t>(src * unsigned_integral_max_value<DstChannelV>::value)
/ unsigned_integral_max_value<SrcChannelV>::value);
}
};
// Both source and destination are unsigned integral channels,
// the src max value is less than the dst max value,
// and the dst max value is not divisible by the src max value
// The expression (src * dst_max) / src_max cannot fit in an integer (overflows). Use a double
template <typename SrcChannelV, typename DstChannelV>
struct channel_converter_unsigned_integral_nondivisible<SrcChannelV, DstChannelV, true, true>
{
DstChannelV operator()(SrcChannelV src) const
{
static const double mul
= unsigned_integral_max_value<DstChannelV>::value
/ double(unsigned_integral_max_value<SrcChannelV>::value);
return DstChannelV(src * mul);
}
};
// Both source and destination are unsigned integral channels,
// the dst max value is less than (or equal to) the src max value,
// and the src max value is not divisible by the dst max value
template <typename SrcChannelV, typename DstChannelV, bool CannotFit>
struct channel_converter_unsigned_integral_nondivisible<SrcChannelV,DstChannelV,false,CannotFit> {
DstChannelV operator()(SrcChannelV src) const {
using src_integer_t = typename detail::unsigned_integral_max_value<SrcChannelV>::value_type;
using dst_integer_t = typename detail::unsigned_integral_max_value<DstChannelV>::value_type;
static const double div = unsigned_integral_max_value<SrcChannelV>::value
/ static_cast< double >( unsigned_integral_max_value<DstChannelV>::value );
static const src_integer_t div2 = static_cast< src_integer_t >( div / 2.0 );
return DstChannelV( static_cast< dst_integer_t >(( static_cast< double >( src + div2 ) / div )));
}
};
} // namespace detail
/////////////////////////////////////////////////////
/// float32_t conversion
/////////////////////////////////////////////////////
template <typename DstChannelV> struct channel_converter_unsigned<float32_t,DstChannelV> {
using argument_type = float32_t;
using result_type = DstChannelV;
DstChannelV operator()(float32_t x) const
{
using dst_integer_t = typename detail::unsigned_integral_max_value<DstChannelV>::value_type;
return DstChannelV( static_cast< dst_integer_t >(x*channel_traits<DstChannelV>::max_value()+0.5f ));
}
};
template <typename SrcChannelV> struct channel_converter_unsigned<SrcChannelV,float32_t> {
using argument_type = float32_t;
using result_type = SrcChannelV;
float32_t operator()(SrcChannelV x) const { return float32_t(x/float(channel_traits<SrcChannelV>::max_value())); }
};
template <> struct channel_converter_unsigned<float32_t,float32_t> {
using argument_type = float32_t;
using result_type = float32_t;
float32_t operator()(float32_t x) const { return x; }
};
/// \brief 32 bit <-> float channel conversion
template <> struct channel_converter_unsigned<uint32_t,float32_t> {
using argument_type = uint32_t;
using result_type = float32_t;
float32_t operator()(uint32_t x) const {
// unfortunately without an explicit check it is possible to get a round-off error. We must ensure that max_value of uint32_t matches max_value of float32_t
if (x>=channel_traits<uint32_t>::max_value()) return channel_traits<float32_t>::max_value();
return float(x) / float(channel_traits<uint32_t>::max_value());
}
};
/// \brief 32 bit <-> float channel conversion
template <> struct channel_converter_unsigned<float32_t,uint32_t> {
using argument_type = float32_t;
using result_type = uint32_t;
uint32_t operator()(float32_t x) const {
// unfortunately without an explicit check it is possible to get a round-off error. We must ensure that max_value of uint32_t matches max_value of float32_t
if (x>=channel_traits<float32_t>::max_value())
return channel_traits<uint32_t>::max_value();
auto const max_value = channel_traits<uint32_t>::max_value();
auto const result = x * static_cast<float32_t::base_channel_t>(max_value) + 0.5f;
return static_cast<uint32_t>(result);
}
};
/// @}
namespace detail {
// Converting from signed to unsigned integral channel.
// It is both a unary function, and a metafunction (thus requires the 'type' nested alias, which equals result_type)
template <typename ChannelValue> // Model ChannelValueConcept
struct channel_convert_to_unsigned : public detail::identity<ChannelValue> {
using type = ChannelValue;
};
template <> struct channel_convert_to_unsigned<int8_t> {
using argument_type = int8_t;
using result_type = uint8_t;
using type = uint8_t;
type operator()(int8_t val) const {
return static_cast<uint8_t>(static_cast<uint32_t>(val) + 128u);
}
};
template <> struct channel_convert_to_unsigned<int16_t> {
using argument_type = int16_t;
using result_type = uint16_t;
using type = uint16_t;
type operator()(int16_t val) const {
return static_cast<uint16_t>(static_cast<uint32_t>(val) + 32768u);
}
};
template <> struct channel_convert_to_unsigned<int32_t> {
using argument_type = int32_t;
using result_type = uint32_t;
using type = uint32_t;
type operator()(int32_t val) const {
return static_cast<uint32_t>(val)+(1u<<31);
}
};
// Converting from unsigned to signed integral channel
// It is both a unary function, and a metafunction (thus requires the 'type' nested alias, which equals result_type)
template <typename ChannelValue> // Model ChannelValueConcept
struct channel_convert_from_unsigned : public detail::identity<ChannelValue> {
using type = ChannelValue;
};
template <> struct channel_convert_from_unsigned<int8_t> {
using argument_type = uint8_t;
using result_type = int8_t;
using type = int8_t;
type operator()(uint8_t val) const {
return static_cast<int8_t>(static_cast<int32_t>(val) - 128);
}
};
template <> struct channel_convert_from_unsigned<int16_t> {
using argument_type = uint16_t;
using result_type = int16_t;
using type = int16_t;
type operator()(uint16_t val) const {
return static_cast<int16_t>(static_cast<int32_t>(val) - 32768);
}
};
template <> struct channel_convert_from_unsigned<int32_t> {
using argument_type = uint32_t;
using result_type = int32_t;
using type = int32_t;
type operator()(uint32_t val) const {
return static_cast<int32_t>(val - (1u<<31));
}
};
} // namespace detail
/// \ingroup ChannelConvertAlgorithm
/// \brief A unary function object converting between channel types
template <typename SrcChannelV, typename DstChannelV> // Model ChannelValueConcept
struct channel_converter {
using argument_type = SrcChannelV;
using result_type = DstChannelV;
DstChannelV operator()(const SrcChannelV& src) const {
using to_unsigned = detail::channel_convert_to_unsigned<SrcChannelV>;
using from_unsigned = detail::channel_convert_from_unsigned<DstChannelV>;
using converter_unsigned = channel_converter_unsigned<typename to_unsigned::result_type, typename from_unsigned::argument_type>;
return from_unsigned()(converter_unsigned()(to_unsigned()(src)));
}
};
/// \ingroup ChannelConvertAlgorithm
/// \brief Converting from one channel type to another.
template <typename DstChannel, typename SrcChannel> // Model ChannelConcept (could be channel references)
inline typename channel_traits<DstChannel>::value_type channel_convert(const SrcChannel& src) {
return channel_converter<typename channel_traits<SrcChannel>::value_type,
typename channel_traits<DstChannel>::value_type>()(src);
}
/// \ingroup ChannelConvertAlgorithm
/// \brief Same as channel_converter, except it takes the destination channel by reference, which allows
/// us to move the templates from the class level to the method level. This is important when invoking it
/// on heterogeneous pixels.
struct default_channel_converter {
template <typename Ch1, typename Ch2>
void operator()(const Ch1& src, Ch2& dst) const {
dst=channel_convert<Ch2>(src);
}
};
namespace detail {
// fast integer division by 255
inline uint32_t div255(uint32_t in) { uint32_t tmp=in+128; return (tmp + (tmp>>8))>>8; }
// fast integer divison by 32768
inline uint32_t div32768(uint32_t in) { return (in+16384)>>15; }
}
/// \defgroup ChannelMultiplyAlgorithm channel_multiply
/// \ingroup ChannelAlgorithm
/// \brief Multiplying unsigned channel values of the same type. Performs scaled multiplication result = a * b / max_value
///
/// Example:
/// \code
/// uint8_t x=128;
/// uint8_t y=128;
/// uint8_t mul = channel_multiply(x,y);
/// assert(mul == 64); // 64 = 128 * 128 / 255
/// \endcode
/// @{
/// \brief This is the default implementation. Performance specializatons are provided
template <typename ChannelValue>
struct channel_multiplier_unsigned {
using first_argument_type = ChannelValue;
using second_argument_type = ChannelValue;
using result_type = ChannelValue;
ChannelValue operator()(ChannelValue a, ChannelValue b) const {
return ChannelValue(static_cast<typename base_channel_type<ChannelValue>::type>(a / double(channel_traits<ChannelValue>::max_value()) * b));
}
};
/// \brief Specialization of channel_multiply for 8-bit unsigned channels
template<> struct channel_multiplier_unsigned<uint8_t> {
using first_argument_type = uint8_t;
using second_argument_type = uint8_t;
using result_type = uint8_t;
uint8_t operator()(uint8_t a, uint8_t b) const { return uint8_t(detail::div255(uint32_t(a) * uint32_t(b))); }
};
/// \brief Specialization of channel_multiply for 16-bit unsigned channels
template<> struct channel_multiplier_unsigned<uint16_t> {
using first_argument_type = uint16_t;
using second_argument_type = uint16_t;
using result_type = uint16_t;
uint16_t operator()(uint16_t a, uint16_t b) const { return uint16_t((uint32_t(a) * uint32_t(b))/65535); }
};
/// \brief Specialization of channel_multiply for float 0..1 channels
template<> struct channel_multiplier_unsigned<float32_t> {
using first_argument_type = float32_t;
using second_argument_type = float32_t;
using result_type = float32_t;
float32_t operator()(float32_t a, float32_t b) const { return a*b; }
};
/// \brief A function object to multiply two channels. result = a * b / max_value
template <typename ChannelValue>
struct channel_multiplier {
using first_argument_type = ChannelValue;
using second_argument_type = ChannelValue;
using result_type = ChannelValue;
ChannelValue operator()(ChannelValue a, ChannelValue b) const {
using to_unsigned = detail::channel_convert_to_unsigned<ChannelValue>;
using from_unsigned = detail::channel_convert_from_unsigned<ChannelValue>;
using multiplier_unsigned = channel_multiplier_unsigned<typename to_unsigned::result_type>;
return from_unsigned()(multiplier_unsigned()(to_unsigned()(a), to_unsigned()(b)));
}
};
/// \brief A function multiplying two channels. result = a * b / max_value
template <typename Channel> // Models ChannelConcept (could be a channel reference)
inline typename channel_traits<Channel>::value_type channel_multiply(Channel a, Channel b) {
return channel_multiplier<typename channel_traits<Channel>::value_type>()(a,b);
}
/// @}
/// \defgroup ChannelInvertAlgorithm channel_invert
/// \ingroup ChannelAlgorithm
/// \brief Returns the inverse of a channel. result = max_value - x + min_value
///
/// Example:
/// \code
/// // uint8_t == uint8_t == unsigned char
/// uint8_t x=255;
/// uint8_t inv = channel_invert(x);
/// assert(inv == 0);
/// \endcode
/// \brief Default implementation. Provide overloads for performance
/// \ingroup ChannelInvertAlgorithm channel_invert
template <typename Channel> // Models ChannelConcept (could be a channel reference)
inline typename channel_traits<Channel>::value_type channel_invert(Channel x) {
using base_t = typename base_channel_type<Channel>::type;
using promoted_t = typename promote_integral<base_t>::type;
promoted_t const promoted_x = x;
promoted_t const promoted_max = channel_traits<Channel>::max_value();
promoted_t const promoted_min = channel_traits<Channel>::min_value();
promoted_t const promoted_inverted_x = promoted_max - promoted_x + promoted_min;
auto const inverted_x = static_cast<base_t>(promoted_inverted_x);
return inverted_x;
}
} } // namespace boost::gil
#endif

View File

@@ -0,0 +1,52 @@
//
// 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_CMYK_HPP
#define BOOST_GIL_CMYK_HPP
#include <boost/gil/metafunctions.hpp>
#include <boost/gil/detail/mp11.hpp>
#include <cstddef>
namespace boost { namespace gil {
/// \addtogroup ColorNameModel
/// \{
/// \brief Cyan
struct cyan_t {};
/// \brief Magenta
struct magenta_t {};
/// \brief Yellow
struct yellow_t {};
/// \brief Black
struct black_t {};
/// \}
/// \ingroup ColorSpaceModel
using cmyk_t = mp11::mp_list<cyan_t, magenta_t, yellow_t, black_t>;
/// \ingroup LayoutModel
using cmyk_layout_t = layout<cmyk_t>;
/// \ingroup ImageViewConstructors
/// \brief from raw CMYK planar data
template <typename IC>
inline typename type_from_x_iterator<planar_pixel_iterator<IC,cmyk_t> >::view_t
planar_cmyk_view(std::size_t width, std::size_t height, IC c, IC m, IC y, IC k, std::ptrdiff_t rowsize_in_bytes)
{
using view_t = typename type_from_x_iterator<planar_pixel_iterator<IC,cmyk_t> >::view_t;
return view_t(width, height, typename view_t::locator(planar_pixel_iterator<IC,cmyk_t>(c,m,y,k), rowsize_in_bytes));
}
} } // namespace gil
#endif

View File

@@ -0,0 +1,639 @@
//
// Copyright 2005-2007 Adobe Systems Incorporated
// Copyright 2019 Mateusz Loskot <mateusz at loskot dot net>
//
// 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_COLOR_BASE_HPP
#define BOOST_GIL_COLOR_BASE_HPP
#include <boost/gil/utilities.hpp>
#include <boost/gil/concepts.hpp>
#include <boost/gil/detail/mp11.hpp>
#include <boost/assert.hpp>
#include <boost/config.hpp>
#include <type_traits>
namespace boost { namespace gil {
// Forward-declare
template <typename P> P* memunit_advanced(const P* p, std::ptrdiff_t diff);
// Forward-declare semantic_at_c
template <int K, typename ColorBase>
auto semantic_at_c(ColorBase& p)
-> typename std::enable_if
<
!std::is_const<ColorBase>::value,
typename kth_semantic_element_reference_type<ColorBase, K>::type
>::type;
template <int K, typename ColorBase>
typename kth_semantic_element_const_reference_type<ColorBase,K>::type semantic_at_c(const ColorBase& p);
// Forward declare element_reference_type
template <typename ColorBase> struct element_reference_type;
template <typename ColorBase> struct element_const_reference_type;
template <typename ColorBase, int K> struct kth_element_type;
template <typename ColorBase, int K> struct kth_element_type<const ColorBase,K> : public kth_element_type<ColorBase,K> {};
template <typename ColorBase, int K> struct kth_element_reference_type;
template <typename ColorBase, int K> struct kth_element_reference_type<const ColorBase,K> : public kth_element_reference_type<ColorBase,K> {};
template <typename ColorBase, int K> struct kth_element_const_reference_type;
template <typename ColorBase, int K> struct kth_element_const_reference_type<const ColorBase,K> : public kth_element_const_reference_type<ColorBase,K> {};
namespace detail {
template <typename DstLayout, typename SrcLayout, int K>
struct mapping_transform : mp11::mp_at
<
typename SrcLayout::channel_mapping_t,
typename detail::type_to_index
<
typename DstLayout::channel_mapping_t,
std::integral_constant<int, K>
>
>::type
{};
/// \defgroup ColorBaseModelHomogeneous detail::homogeneous_color_base
/// \ingroup ColorBaseModel
/// \brief A homogeneous color base holding one color element.
/// Models HomogeneousColorBaseConcept or HomogeneousColorBaseValueConcept
/// If the element type models Regular, this class models HomogeneousColorBaseValueConcept.
#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
#pragma warning(push)
#pragma warning(disable:4512) //assignment operator could not be generated
#endif
/// \brief A homogeneous color base holding one color element.
/// Models HomogeneousColorBaseConcept or HomogeneousColorBaseValueConcept
/// \ingroup ColorBaseModelHomogeneous
template <typename Element, typename Layout>
struct homogeneous_color_base<Element, Layout, 1>
{
using layout_t = Layout;
homogeneous_color_base() = default;
homogeneous_color_base(Element v) : v0_(v) {}
template <typename E2, typename L2>
homogeneous_color_base(homogeneous_color_base<E2, L2, 1> const& c)
: v0_(gil::at_c<0>(c))
{}
auto at(std::integral_constant<int, 0>)
-> typename element_reference_type<homogeneous_color_base>::type
{ return v0_; }
auto at(std::integral_constant<int, 0>) const
-> typename element_const_reference_type<homogeneous_color_base>::type
{ return v0_; }
// grayscale pixel values are convertible to channel type
// FIXME: explicit?
operator Element() const { return v0_; }
private:
Element v0_{};
};
/// \brief A homogeneous color base holding two color elements
/// Models HomogeneousColorBaseConcept or HomogeneousColorBaseValueConcept
/// \ingroup ColorBaseModelHomogeneous
template <typename Element, typename Layout>
struct homogeneous_color_base<Element, Layout, 2>
{
using layout_t = Layout;
homogeneous_color_base() = default;
explicit homogeneous_color_base(Element v) : v0_(v), v1_(v) {}
homogeneous_color_base(Element v0, Element v1) : v0_(v0), v1_(v1) {}
template <typename E2, typename L2>
homogeneous_color_base(homogeneous_color_base<E2, L2, 2> const& c)
: v0_(gil::at_c<mapping_transform<Layout, L2, 0>::value>(c))
, v1_(gil::at_c<mapping_transform<Layout, L2, 1>::value>(c))
{}
// Support for l-value reference proxy copy construction
template <typename E2, typename L2>
homogeneous_color_base(homogeneous_color_base<E2, L2, 2>& c)
: v0_(gil::at_c<mapping_transform<Layout, L2, 0>::value>(c))
, v1_(gil::at_c<mapping_transform<Layout, L2, 1>::value>(c))
{}
// Support for planar_pixel_iterator construction and dereferencing
template <typename P>
homogeneous_color_base(P* p, bool)
: v0_(&semantic_at_c<0>(*p))
, v1_(&semantic_at_c<1>(*p))
{}
// Support for planar_pixel_reference offset constructor
template <typename Ptr>
homogeneous_color_base(Ptr const& ptr, std::ptrdiff_t diff)
: v0_(*memunit_advanced(semantic_at_c<0>(ptr), diff))
, v1_(*memunit_advanced(semantic_at_c<1>(ptr), diff))
{}
template <typename Ref>
Ref deref() const
{
return Ref(*semantic_at_c<0>(*this), *semantic_at_c<1>(*this));
}
auto at(std::integral_constant<int, 0>)
-> typename element_reference_type<homogeneous_color_base>::type
{ return v0_; }
auto at(std::integral_constant<int, 0>) const
-> typename element_const_reference_type<homogeneous_color_base>::type
{ return v0_; }
auto at(std::integral_constant<int, 1>)
-> typename element_reference_type<homogeneous_color_base>::type
{ return v1_; }
auto at(std::integral_constant<int, 1>) const
-> typename element_const_reference_type<homogeneous_color_base>::type
{ return v1_; }
// Support for planar_pixel_reference operator[]
Element at_c_dynamic(std::size_t i) const
{
if (i == 0)
return v0_;
else
return v1_;
}
private:
Element v0_{};
Element v1_{};
};
/// \brief A homogeneous color base holding three color elements.
/// Models HomogeneousColorBaseConcept or HomogeneousColorBaseValueConcept
/// \ingroup ColorBaseModelHomogeneous
template <typename Element, typename Layout>
struct homogeneous_color_base<Element, Layout, 3>
{
using layout_t = Layout;
homogeneous_color_base() = default;
explicit homogeneous_color_base(Element v) : v0_(v), v1_(v), v2_(v) {}
homogeneous_color_base(Element v0, Element v1, Element v2)
: v0_(v0), v1_(v1), v2_(v2)
{}
template <typename E2, typename L2>
homogeneous_color_base(homogeneous_color_base<E2, L2, 3> const& c)
: v0_(gil::at_c<mapping_transform<Layout, L2, 0>::value>(c))
, v1_(gil::at_c<mapping_transform<Layout, L2, 1>::value>(c))
, v2_(gil::at_c<mapping_transform<Layout, L2, 2>::value>(c))
{}
// Support for l-value reference proxy copy construction
template <typename E2, typename L2>
homogeneous_color_base(homogeneous_color_base<E2, L2, 3>& c)
: v0_(gil::at_c<mapping_transform<Layout, L2, 0>::value>(c))
, v1_(gil::at_c<mapping_transform<Layout, L2, 1>::value>(c))
, v2_(gil::at_c<mapping_transform<Layout, L2, 2>::value>(c))
{}
// Support for planar_pixel_iterator construction and dereferencing
template <typename P>
homogeneous_color_base(P* p, bool)
: v0_(&semantic_at_c<0>(*p))
, v1_(&semantic_at_c<1>(*p))
, v2_(&semantic_at_c<2>(*p))
{}
// Support for planar_pixel_reference offset constructor
template <typename Ptr>
homogeneous_color_base(Ptr const& ptr, std::ptrdiff_t diff)
: v0_(*memunit_advanced(semantic_at_c<0>(ptr), diff))
, v1_(*memunit_advanced(semantic_at_c<1>(ptr), diff))
, v2_(*memunit_advanced(semantic_at_c<2>(ptr), diff))
{}
template <typename Ref>
Ref deref() const
{
return Ref(
*semantic_at_c<0>(*this),
*semantic_at_c<1>(*this),
*semantic_at_c<2>(*this));
}
auto at(std::integral_constant<int, 0>)
-> typename element_reference_type<homogeneous_color_base>::type
{ return v0_; }
auto at(std::integral_constant<int, 0>) const
-> typename element_const_reference_type<homogeneous_color_base>::type
{ return v0_; }
auto at(std::integral_constant<int, 1>)
-> typename element_reference_type<homogeneous_color_base>::type
{ return v1_; }
auto at(std::integral_constant<int, 1>) const
-> typename element_const_reference_type<homogeneous_color_base>::type
{ return v1_; }
auto at(std::integral_constant<int, 2>)
-> typename element_reference_type<homogeneous_color_base>::type
{ return v2_; }
auto at(std::integral_constant<int, 2>) const
-> typename element_const_reference_type<homogeneous_color_base>::type
{ return v2_; }
// Support for planar_pixel_reference operator[]
Element at_c_dynamic(std::size_t i) const
{
switch (i)
{
case 0: return v0_;
case 1: return v1_;
}
return v2_;
}
private:
Element v0_{};
Element v1_{};
Element v2_{};
};
/// \brief A homogeneous color base holding four color elements.
/// Models HomogeneousColorBaseConcept or HomogeneousColorBaseValueConcept
/// \ingroup ColorBaseModelHomogeneous
template <typename Element, typename Layout>
struct homogeneous_color_base<Element, Layout, 4>
{
using layout_t = Layout;
homogeneous_color_base() = default;
explicit homogeneous_color_base(Element v) : v0_(v), v1_(v), v2_(v), v3_(v) {}
homogeneous_color_base(Element v0, Element v1, Element v2, Element v3)
: v0_(v0), v1_(v1), v2_(v2), v3_(v3)
{}
template <typename E2, typename L2>
homogeneous_color_base(homogeneous_color_base<E2, L2, 4> const& c)
: v0_(gil::at_c<mapping_transform<Layout, L2, 0>::value>(c))
, v1_(gil::at_c<mapping_transform<Layout, L2, 1>::value>(c))
, v2_(gil::at_c<mapping_transform<Layout, L2, 2>::value>(c))
, v3_(gil::at_c<mapping_transform<Layout, L2, 3>::value>(c))
{}
// Support for l-value reference proxy copy construction
template <typename E2, typename L2>
homogeneous_color_base(homogeneous_color_base<E2, L2, 4>& c)
: v0_(gil::at_c<mapping_transform<Layout, L2, 0>::value>(c))
, v1_(gil::at_c<mapping_transform<Layout, L2, 1>::value>(c))
, v2_(gil::at_c<mapping_transform<Layout, L2, 2>::value>(c))
, v3_(gil::at_c<mapping_transform<Layout, L2, 3>::value>(c))
{}
// Support for planar_pixel_iterator construction and dereferencing
template <typename P>
homogeneous_color_base(P * p, bool)
: v0_(&semantic_at_c<0>(*p))
, v1_(&semantic_at_c<1>(*p))
, v2_(&semantic_at_c<2>(*p))
, v3_(&semantic_at_c<3>(*p))
{}
// Support for planar_pixel_reference offset constructor
template <typename Ptr>
homogeneous_color_base(Ptr const& ptr, std::ptrdiff_t diff)
: v0_(*memunit_advanced(semantic_at_c<0>(ptr), diff))
, v1_(*memunit_advanced(semantic_at_c<1>(ptr), diff))
, v2_(*memunit_advanced(semantic_at_c<2>(ptr), diff))
, v3_(*memunit_advanced(semantic_at_c<3>(ptr), diff))
{}
template <typename Ref>
Ref deref() const
{
return Ref(
*semantic_at_c<0>(*this),
*semantic_at_c<1>(*this),
*semantic_at_c<2>(*this),
*semantic_at_c<3>(*this));
}
auto at(std::integral_constant<int, 0>)
-> typename element_reference_type<homogeneous_color_base>::type
{ return v0_; }
auto at(std::integral_constant<int, 0>) const
-> typename element_const_reference_type<homogeneous_color_base>::type
{ return v0_; }
auto at(std::integral_constant<int, 1>)
-> typename element_reference_type<homogeneous_color_base>::type
{ return v1_; }
auto at(std::integral_constant<int, 1>) const
-> typename element_const_reference_type<homogeneous_color_base>::type
{ return v1_; }
auto at(std::integral_constant<int, 2>)
-> typename element_reference_type<homogeneous_color_base>::type
{ return v2_; }
auto at(std::integral_constant<int, 2>) const
-> typename element_const_reference_type<homogeneous_color_base>::type
{ return v2_; }
auto at(std::integral_constant<int, 3>)
-> typename element_reference_type<homogeneous_color_base>::type
{ return v3_; }
auto at(std::integral_constant<int, 3>) const
-> typename element_const_reference_type<homogeneous_color_base>::type
{ return v3_; }
// Support for planar_pixel_reference operator[]
Element at_c_dynamic(std::size_t i) const
{
switch (i)
{
case 0: return v0_;
case 1: return v1_;
case 2: return v2_;
}
return v3_;
}
private:
Element v0_{};
Element v1_{};
Element v2_{};
Element v3_{};
};
/// \brief A homogeneous color base holding five color elements.
/// Models HomogeneousColorBaseConcept or HomogeneousColorBaseValueConcept
/// \ingroup ColorBaseModelHomogeneous
template <typename Element, typename Layout>
struct homogeneous_color_base<Element, Layout, 5>
{
using layout_t = Layout;
homogeneous_color_base() = default;
explicit homogeneous_color_base(Element v)
: v0_(v), v1_(v), v2_(v), v3_(v), v4_(v)
{}
homogeneous_color_base(Element v0, Element v1, Element v2, Element v3, Element v4)
: v0_(v0), v1_(v1), v2_(v2), v3_(v3), v4_(v4)
{}
template <typename E2, typename L2>
homogeneous_color_base(homogeneous_color_base<E2, L2, 5> const& c)
: v0_(gil::at_c<mapping_transform<Layout, L2, 0>::value>(c))
, v1_(gil::at_c<mapping_transform<Layout, L2, 1>::value>(c))
, v2_(gil::at_c<mapping_transform<Layout, L2, 2>::value>(c))
, v3_(gil::at_c<mapping_transform<Layout, L2, 3>::value>(c))
, v4_(gil::at_c<mapping_transform<Layout, L2, 4>::value>(c))
{}
// Support for l-value reference proxy copy construction
template <typename E2, typename L2>
homogeneous_color_base(homogeneous_color_base<E2, L2, 5>& c)
: v0_(gil::at_c<mapping_transform<Layout, L2, 0>::value>(c))
, v1_(gil::at_c<mapping_transform<Layout, L2, 1>::value>(c))
, v2_(gil::at_c<mapping_transform<Layout, L2, 2>::value>(c))
, v3_(gil::at_c<mapping_transform<Layout, L2, 3>::value>(c))
, v4_(gil::at_c<mapping_transform<Layout, L2, 4>::value>(c))
{}
// Support for planar_pixel_iterator construction and dereferencing
template <typename P>
homogeneous_color_base(P* p, bool)
: v0_(&semantic_at_c<0>(*p))
, v1_(&semantic_at_c<1>(*p))
, v2_(&semantic_at_c<2>(*p))
, v3_(&semantic_at_c<3>(*p))
, v4_(&semantic_at_c<4>(*p))
{}
// Support for planar_pixel_reference offset constructor
template <typename Ptr>
homogeneous_color_base(Ptr const& ptr, std::ptrdiff_t diff)
: v0_(*memunit_advanced(semantic_at_c<0>(ptr), diff))
, v1_(*memunit_advanced(semantic_at_c<1>(ptr), diff))
, v2_(*memunit_advanced(semantic_at_c<2>(ptr), diff))
, v3_(*memunit_advanced(semantic_at_c<3>(ptr), diff))
, v4_(*memunit_advanced(semantic_at_c<4>(ptr), diff))
{}
auto at(std::integral_constant<int, 0>)
-> typename element_reference_type<homogeneous_color_base>::type
{ return v0_; }
auto at(std::integral_constant<int, 0>) const
-> typename element_const_reference_type<homogeneous_color_base>::type
{ return v0_; }
auto at(std::integral_constant<int, 1>)
-> typename element_reference_type<homogeneous_color_base>::type
{ return v1_; }
auto at(std::integral_constant<int, 1>) const
-> typename element_const_reference_type<homogeneous_color_base>::type
{ return v1_; }
auto at(std::integral_constant<int, 2>)
-> typename element_reference_type<homogeneous_color_base>::type
{ return v2_; }
auto at(std::integral_constant<int, 2>) const
-> typename element_const_reference_type<homogeneous_color_base>::type
{ return v2_; }
auto at(std::integral_constant<int, 3>)
-> typename element_reference_type<homogeneous_color_base>::type
{ return v3_; }
auto at(std::integral_constant<int, 3>) const
-> typename element_const_reference_type<homogeneous_color_base>::type
{ return v3_; }
auto at(std::integral_constant<int, 4>)
-> typename element_reference_type<homogeneous_color_base>::type
{ return v4_; }
auto at(std::integral_constant<int, 4>) const
-> typename element_const_reference_type<homogeneous_color_base>::type
{ return v4_; }
template <typename Ref>
Ref deref() const
{
return Ref(
*semantic_at_c<0>(*this),
*semantic_at_c<1>(*this),
*semantic_at_c<2>(*this),
*semantic_at_c<3>(*this),
*semantic_at_c<4>(*this));
}
// Support for planar_pixel_reference operator[]
Element at_c_dynamic(std::size_t i) const
{
switch (i)
{
case 0: return v0_;
case 1: return v1_;
case 2: return v2_;
case 3: return v3_;
}
return v4_;
}
private:
Element v0_{};
Element v1_{};
Element v2_{};
Element v3_{};
Element v4_{};
};
#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
#pragma warning(pop)
#endif
// The following way of casting adjacent channels (the contents of color_base) into an array appears to be unsafe
// -- there is no guarantee that the compiler won't add any padding between adjacent channels.
// Note, however, that GIL _must_ be compiled with compiler settings ensuring there is no padding in the color base structs.
// This is because the color base structs must model the interleaved organization in memory. In other words, the client may
// have existing RGB image in the form "RGBRGBRGB..." and we must be able to represent it with an array of RGB color bases (i.e. RGB pixels)
// with no padding. We have tested with char/int/float/double channels on gcc and VC and have so far discovered no problem.
// We have even tried using strange channels consisting of short + char (3 bytes). With the default 4-byte alignment on VC, the size
// of this channel is padded to 4 bytes, so an RGB pixel of it will be 4x3=12 bytes. The code below will still work properly.
// However, the client must nevertheless ensure that proper compiler settings are used for their compiler and their channel types.
template <typename Element, typename Layout, int K>
auto dynamic_at_c(homogeneous_color_base<Element,Layout,K>& cb, std::size_t i)
-> typename element_reference_type<homogeneous_color_base<Element, Layout, K>>::type
{
BOOST_ASSERT(i < K);
return (gil_reinterpret_cast<Element*>(&cb))[i];
}
template <typename Element, typename Layout, int K>
auto dynamic_at_c(homogeneous_color_base<Element, Layout, K> const& cb, std::size_t i)
-> typename element_const_reference_type
<
homogeneous_color_base<Element, Layout, K>
>::type
{
BOOST_ASSERT(i < K);
return (gil_reinterpret_cast_c<const Element*>(&cb))[i];
}
template <typename Element, typename Layout, int K>
auto dynamic_at_c(homogeneous_color_base<Element&, Layout, K> const& cb, std::size_t i)
-> typename element_reference_type
<
homogeneous_color_base<Element&, Layout, K>
>::type
{
BOOST_ASSERT(i < K);
return cb.at_c_dynamic(i);
}
template <typename Element, typename Layout, int K>
auto dynamic_at_c(
homogeneous_color_base<Element const&, Layout, K>const& cb, std::size_t i)
-> typename element_const_reference_type
<
homogeneous_color_base<Element const&, Layout, K>
>::type
{
BOOST_ASSERT(i < K);
return cb.at_c_dynamic(i);
}
} // namespace detail
template <typename Element, typename Layout, int K1, int K>
struct kth_element_type<detail::homogeneous_color_base<Element, Layout, K1>, K>
{
using type = Element;
};
template <typename Element, typename Layout, int K1, int K>
struct kth_element_reference_type<detail::homogeneous_color_base<Element, Layout, K1>, K>
: std::add_lvalue_reference<Element>
{};
template <typename Element, typename Layout, int K1, int K>
struct kth_element_const_reference_type
<
detail::homogeneous_color_base<Element, Layout, K1>,
K
>
: std::add_lvalue_reference<typename std::add_const<Element>::type>
{};
/// \brief Provides mutable access to the K-th element, in physical order
/// \ingroup ColorBaseModelHomogeneous
template <int K, typename E, typename L, int N>
inline
auto at_c(detail::homogeneous_color_base<E, L, N>& p)
-> typename std::add_lvalue_reference<E>::type
{
return p.at(std::integral_constant<int, K>());
}
/// \brief Provides constant access to the K-th element, in physical order
/// \ingroup ColorBaseModelHomogeneous
template <int K, typename E, typename L, int N>
inline
auto at_c(const detail::homogeneous_color_base<E, L, N>& p)
-> typename std::add_lvalue_reference<typename std::add_const<E>::type>::type
{
return p.at(std::integral_constant<int, K>());
}
namespace detail
{
struct swap_fn
{
template <typename T>
void operator()(T& x, T& y) const
{
using std::swap;
swap(x, y);
}
};
} // namespace detail
template <typename E, typename L, int N>
inline
void swap(
detail::homogeneous_color_base<E, L, N>& x,
detail::homogeneous_color_base<E, L, N>& y)
{
static_for_each(x, y, detail::swap_fn());
}
}} // namespace boost::gil
#endif

View File

@@ -0,0 +1,713 @@
//
// Copyright 2005-2007 Adobe Systems Incorporated
// Copyright 2019 Mateusz Loskot <mateusz at loskot dot net>
//
// 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_COLOR_BASE_ALGORITHM_HPP
#define BOOST_GIL_COLOR_BASE_ALGORITHM_HPP
#include <boost/gil/concepts.hpp>
#include <boost/gil/utilities.hpp>
#include <boost/gil/detail/mp11.hpp>
#include <boost/config.hpp>
#include <algorithm>
#include <type_traits>
namespace boost { namespace gil {
///////////////////////////////////////
/// size: Semantic channel size
///////////////////////////////////////
/**
\defgroup ColorBaseAlgorithmSize size
\ingroup ColorBaseAlgorithm
\brief Returns an integral constant type specifying the number of elements in a color base
Example:
\code
static_assert(size<rgb8_pixel_t>::value == 3, "");
static_assert(size<cmyk8_planar_ptr_t>::value == 4, "");
\endcode
*/
/// \brief Returns an integral constant type specifying the number of elements in a color base
/// \ingroup ColorBaseAlgorithmSize
template <typename ColorBase>
struct size : public mp11::mp_size<typename ColorBase::layout_t::color_space_t> {};
///////////////////////////////////////
/// semantic_at_c: Semantic channel accessors
///////////////////////////////////////
/**
\defgroup ColorBaseAlgorithmSemanticAtC kth_semantic_element_type, kth_semantic_element_reference_type, kth_semantic_element_const_reference_type, semantic_at_c
\ingroup ColorBaseAlgorithm
\brief Support for accessing the elements of a color base by semantic index
The semantic index of an element is the index of its color in the color space. Semantic indexing allows for proper pairing of elements of color bases
independent on their layout. For example, red is the first semantic element of a color base regardless of whether it has an RGB layout or a BGR layout.
All GIL color base algorithms taking multiple color bases use semantic indexing to access their elements.
Example:
\code
// 16-bit BGR pixel, 4 bits for the blue, 3 bits for the green, 2 bits for the red channel and 7 unused bits
using bgr432_pixel_t = packed_pixel_type<uint16_t, mp11::mp_list_c<unsigned,4,3,2>, bgr_layout_t>::type;
// A reference to its red channel. Although the red channel is the third, its semantic index is 0 in the RGB color space
using red_channel_reference_t = kth_semantic_element_reference_type<bgr432_pixel_t, 0>::type;
// Initialize the pixel to black
bgr432_pixel_t red_pixel(0,0,0);
// Set the red channel to 100%
red_channel_reference_t red_channel = semantic_at_c<0>(red_pixel);
red_channel = channel_traits<red_channel_reference_t>::max_value();
\endcode
*/
/// \brief Specifies the type of the K-th semantic element of a color base
/// \ingroup ColorBaseAlgorithmSemanticAtC
template <typename ColorBase, int K>
struct kth_semantic_element_type
{
using channel_mapping_t = typename ColorBase::layout_t::channel_mapping_t;
static_assert(K < mp11::mp_size<channel_mapping_t>::value,
"K index should be less than size of channel_mapping_t sequence");
static constexpr int semantic_index = mp11::mp_at_c<channel_mapping_t, K>::type::value;
using type = typename kth_element_type<ColorBase, semantic_index>::type;
};
/// \brief Specifies the return type of the mutable semantic_at_c<K>(color_base);
/// \ingroup ColorBaseAlgorithmSemanticAtC
template <typename ColorBase, int K>
struct kth_semantic_element_reference_type
{
using channel_mapping_t = typename ColorBase::layout_t::channel_mapping_t;
static_assert(K < mp11::mp_size<channel_mapping_t>::value,
"K index should be less than size of channel_mapping_t sequence");
static constexpr int semantic_index = mp11::mp_at_c<channel_mapping_t, K>::type::value;
using type = typename kth_element_reference_type<ColorBase, semantic_index>::type;
static type get(ColorBase& cb) { return gil::at_c<semantic_index>(cb); }
};
/// \brief Specifies the return type of the constant semantic_at_c<K>(color_base);
/// \ingroup ColorBaseAlgorithmSemanticAtC
template <typename ColorBase, int K>
struct kth_semantic_element_const_reference_type
{
using channel_mapping_t = typename ColorBase::layout_t::channel_mapping_t;
static_assert(K < mp11::mp_size<channel_mapping_t>::value,
"K index should be less than size of channel_mapping_t sequence");
static constexpr int semantic_index = mp11::mp_at_c<channel_mapping_t, K>::type::value;
using type = typename kth_element_const_reference_type<ColorBase,semantic_index>::type;
static type get(const ColorBase& cb) { return gil::at_c<semantic_index>(cb); }
};
/// \brief A mutable accessor to the K-th semantic element of a color base
/// \ingroup ColorBaseAlgorithmSemanticAtC
template <int K, typename ColorBase>
inline
auto semantic_at_c(ColorBase& p)
-> typename std::enable_if
<
!std::is_const<ColorBase>::value,
typename kth_semantic_element_reference_type<ColorBase, K>::type
>::type
{
return kth_semantic_element_reference_type<ColorBase, K>::get(p);
}
/// \brief A constant accessor to the K-th semantic element of a color base
/// \ingroup ColorBaseAlgorithmSemanticAtC
template <int K, typename ColorBase>
inline
auto semantic_at_c(ColorBase const& p)
-> typename kth_semantic_element_const_reference_type<ColorBase, K>::type
{
return kth_semantic_element_const_reference_type<ColorBase, K>::get(p);
}
///////////////////////////////////////
/// get_color: Named channel accessors
///////////////////////////////////////
/**
\defgroup ColorBaseAlgorithmColor color_element_type, color_element_reference_type, color_element_const_reference_type, get_color, contains_color
\ingroup ColorBaseAlgorithm
\brief Support for accessing the elements of a color base by color name
Example: A function that takes a generic pixel containing a red channel and sets it to 100%:
\code
template <typename Pixel>
void set_red_to_max(Pixel& pixel) {
boost::function_requires<MutablePixelConcept<Pixel> >();
static_assert(contains_color<Pixel, red_t>::value, "");
using red_channel_t = typename color_element_type<Pixel, red_t>::type;
get_color(pixel, red_t()) = channel_traits<red_channel_t>::max_value();
}
\endcode
*/
/// \brief A predicate metafunction determining whether a given color base contains a given color
/// \ingroup ColorBaseAlgorithmColor
template <typename ColorBase, typename Color>
struct contains_color
: mp11::mp_contains<typename ColorBase::layout_t::color_space_t, Color>
{};
template <typename ColorBase, typename Color>
struct color_index_type : public detail::type_to_index<typename ColorBase::layout_t::color_space_t,Color> {};
/// \brief Specifies the type of the element associated with a given color tag
/// \ingroup ColorBaseAlgorithmColor
template <typename ColorBase, typename Color>
struct color_element_type : public kth_semantic_element_type<ColorBase,color_index_type<ColorBase,Color>::value> {};
/// \brief Specifies the return type of the mutable element accessor by color name, get_color(color_base, Color());
/// \ingroup ColorBaseAlgorithmColor
template <typename ColorBase, typename Color>
struct color_element_reference_type : public kth_semantic_element_reference_type<ColorBase,color_index_type<ColorBase,Color>::value> {};
/// \brief Specifies the return type of the constant element accessor by color name, get_color(color_base, Color());
/// \ingroup ColorBaseAlgorithmColor
template <typename ColorBase, typename Color>
struct color_element_const_reference_type : public kth_semantic_element_const_reference_type<ColorBase,color_index_type<ColorBase,Color>::value> {};
/// \brief Mutable accessor to the element associated with a given color name
/// \ingroup ColorBaseAlgorithmColor
template <typename ColorBase, typename Color>
typename color_element_reference_type<ColorBase,Color>::type get_color(ColorBase& cb, Color=Color()) {
return color_element_reference_type<ColorBase,Color>::get(cb);
}
/// \brief Constant accessor to the element associated with a given color name
/// \ingroup ColorBaseAlgorithmColor
template <typename ColorBase, typename Color>
typename color_element_const_reference_type<ColorBase,Color>::type get_color(const ColorBase& cb, Color=Color()) {
return color_element_const_reference_type<ColorBase,Color>::get(cb);
}
///////////////////////////////////////
///
/// element_type, element_reference_type, element_const_reference_type: Support for homogeneous color bases
///
///////////////////////////////////////
/**
\defgroup ColorBaseAlgorithmHomogeneous element_type, element_reference_type, element_const_reference_type
\ingroup ColorBaseAlgorithm
\brief Types for homogeneous color bases
Example:
\code
using element_t = element_type<rgb8c_planar_ptr_t>::type;
static_assert(std::is_same<element_t, const uint8_t*>::value, "");
\endcode
*/
/// \brief Specifies the element type of a homogeneous color base
/// \ingroup ColorBaseAlgorithmHomogeneous
template <typename ColorBase>
struct element_type : public kth_element_type<ColorBase, 0> {};
/// \brief Specifies the return type of the mutable element accessor at_c of a homogeneous color base
/// \ingroup ColorBaseAlgorithmHomogeneous
template <typename ColorBase>
struct element_reference_type : public kth_element_reference_type<ColorBase, 0> {};
/// \brief Specifies the return type of the constant element accessor at_c of a homogeneous color base
/// \ingroup ColorBaseAlgorithmHomogeneous
template <typename ColorBase>
struct element_const_reference_type : public kth_element_const_reference_type<ColorBase, 0> {};
namespace detail {
// compile-time recursion for per-element operations on color bases
template <int N>
struct element_recursion
{
#if defined(BOOST_GCC) && (BOOST_GCC >= 40900)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wconversion"
#pragma GCC diagnostic ignored "-Wfloat-equal"
#endif
template <typename P1,typename P2>
static bool static_equal(const P1& p1, const P2& p2)
{
return element_recursion<N-1>::static_equal(p1,p2) &&
semantic_at_c<N-1>(p1)==semantic_at_c<N-1>(p2);
}
template <typename P1,typename P2>
static void static_copy(const P1& p1, P2& p2)
{
element_recursion<N-1>::static_copy(p1,p2);
semantic_at_c<N-1>(p2)=semantic_at_c<N-1>(p1);
}
template <typename P,typename T2>
static void static_fill(P& p, T2 v)
{
element_recursion<N-1>::static_fill(p,v);
semantic_at_c<N-1>(p)=v;
}
template <typename Dst,typename Op>
static void static_generate(Dst& dst, Op op)
{
element_recursion<N-1>::static_generate(dst,op);
semantic_at_c<N-1>(dst)=op();
}
#if defined(BOOST_GCC) && (BOOST_GCC >= 40900)
#pragma GCC diagnostic pop
#endif
//static_for_each with one source
template <typename P1,typename Op>
static Op static_for_each(P1& p1, Op op) {
Op op2(element_recursion<N-1>::static_for_each(p1,op));
op2(semantic_at_c<N-1>(p1));
return op2;
}
template <typename P1,typename Op>
static Op static_for_each(const P1& p1, Op op) {
Op op2(element_recursion<N-1>::static_for_each(p1,op));
op2(semantic_at_c<N-1>(p1));
return op2;
}
//static_for_each with two sources
template <typename P1,typename P2,typename Op>
static Op static_for_each(P1& p1, P2& p2, Op op) {
Op op2(element_recursion<N-1>::static_for_each(p1,p2,op));
op2(semantic_at_c<N-1>(p1), semantic_at_c<N-1>(p2));
return op2;
}
template <typename P1,typename P2,typename Op>
static Op static_for_each(P1& p1, const P2& p2, Op op) {
Op op2(element_recursion<N-1>::static_for_each(p1,p2,op));
op2(semantic_at_c<N-1>(p1), semantic_at_c<N-1>(p2));
return op2;
}
template <typename P1,typename P2,typename Op>
static Op static_for_each(const P1& p1, P2& p2, Op op) {
Op op2(element_recursion<N-1>::static_for_each(p1,p2,op));
op2(semantic_at_c<N-1>(p1), semantic_at_c<N-1>(p2));
return op2;
}
template <typename P1,typename P2,typename Op>
static Op static_for_each(const P1& p1, const P2& p2, Op op) {
Op op2(element_recursion<N-1>::static_for_each(p1,p2,op));
op2(semantic_at_c<N-1>(p1), semantic_at_c<N-1>(p2));
return op2;
}
//static_for_each with three sources
template <typename P1,typename P2,typename P3,typename Op>
static Op static_for_each(P1& p1, P2& p2, P3& p3, Op op) {
Op op2(element_recursion<N-1>::static_for_each(p1,p2,p3,op));
op2(semantic_at_c<N-1>(p1), semantic_at_c<N-1>(p2), semantic_at_c<N-1>(p3));
return op2;
}
template <typename P1,typename P2,typename P3,typename Op>
static Op static_for_each(P1& p1, P2& p2, const P3& p3, Op op) {
Op op2(element_recursion<N-1>::static_for_each(p1,p2,p3,op));
op2(semantic_at_c<N-1>(p1), semantic_at_c<N-1>(p2), semantic_at_c<N-1>(p3));
return op2;
}
template <typename P1,typename P2,typename P3,typename Op>
static Op static_for_each(P1& p1, const P2& p2, P3& p3, Op op) {
Op op2(element_recursion<N-1>::static_for_each(p1,p2,p3,op));
op2(semantic_at_c<N-1>(p1), semantic_at_c<N-1>(p2), semantic_at_c<N-1>(p3));
return op2;
}
template <typename P1,typename P2,typename P3,typename Op>
static Op static_for_each(P1& p1, const P2& p2, const P3& p3, Op op) {
Op op2(element_recursion<N-1>::static_for_each(p1,p2,p3,op));
op2(semantic_at_c<N-1>(p1), semantic_at_c<N-1>(p2), semantic_at_c<N-1>(p3));
return op2;
}
template <typename P1,typename P2,typename P3,typename Op>
static Op static_for_each(const P1& p1, P2& p2, P3& p3, Op op) {
Op op2(element_recursion<N-1>::static_for_each(p1,p2,p3,op));
op2(semantic_at_c<N-1>(p1), semantic_at_c<N-1>(p2), semantic_at_c<N-1>(p3));
return op2;
}
template <typename P1,typename P2,typename P3,typename Op>
static Op static_for_each(const P1& p1, P2& p2, const P3& p3, Op op) {
Op op2(element_recursion<N-1>::static_for_each(p1,p2,p3,op));
op2(semantic_at_c<N-1>(p1), semantic_at_c<N-1>(p2), semantic_at_c<N-1>(p3));
return op2;
}
template <typename P1,typename P2,typename P3,typename Op>
static Op static_for_each(const P1& p1, const P2& p2, P3& p3, Op op) {
Op op2(element_recursion<N-1>::static_for_each(p1,p2,p3,op));
op2(semantic_at_c<N-1>(p1), semantic_at_c<N-1>(p2), semantic_at_c<N-1>(p3));
return op2;
}
template <typename P1,typename P2,typename P3,typename Op>
static Op static_for_each(const P1& p1, const P2& p2, const P3& p3, Op op) {
Op op2(element_recursion<N-1>::static_for_each(p1,p2,p3,op));
op2(semantic_at_c<N-1>(p1), semantic_at_c<N-1>(p2), semantic_at_c<N-1>(p3));
return op2;
}
//static_transform with one source
template <typename P1,typename Dst,typename Op>
static Op static_transform(P1& src, Dst& dst, Op op) {
Op op2(element_recursion<N-1>::static_transform(src,dst,op));
semantic_at_c<N-1>(dst)=op2(semantic_at_c<N-1>(src));
return op2;
}
template <typename P1,typename Dst,typename Op>
static Op static_transform(const P1& src, Dst& dst, Op op) {
Op op2(element_recursion<N-1>::static_transform(src,dst,op));
semantic_at_c<N-1>(dst)=op2(semantic_at_c<N-1>(src));
return op2;
}
//static_transform with two sources
template <typename P1,typename P2,typename Dst,typename Op>
static Op static_transform(P1& src1, P2& src2, Dst& dst, Op op) {
Op op2(element_recursion<N-1>::static_transform(src1,src2,dst,op));
semantic_at_c<N-1>(dst)=op2(semantic_at_c<N-1>(src1), semantic_at_c<N-1>(src2));
return op2;
}
template <typename P1,typename P2,typename Dst,typename Op>
static Op static_transform(P1& src1, const P2& src2, Dst& dst, Op op) {
Op op2(element_recursion<N-1>::static_transform(src1,src2,dst,op));
semantic_at_c<N-1>(dst)=op2(semantic_at_c<N-1>(src1), semantic_at_c<N-1>(src2));
return op2;
}
template <typename P1,typename P2,typename Dst,typename Op>
static Op static_transform(const P1& src1, P2& src2, Dst& dst, Op op) {
Op op2(element_recursion<N-1>::static_transform(src1,src2,dst,op));
semantic_at_c<N-1>(dst)=op2(semantic_at_c<N-1>(src1), semantic_at_c<N-1>(src2));
return op2;
}
template <typename P1,typename P2,typename Dst,typename Op>
static Op static_transform(const P1& src1, const P2& src2, Dst& dst, Op op) {
Op op2(element_recursion<N-1>::static_transform(src1,src2,dst,op));
semantic_at_c<N-1>(dst)=op2(semantic_at_c<N-1>(src1), semantic_at_c<N-1>(src2));
return op2;
}
};
// Termination condition of the compile-time recursion for element operations on a color base
template<> struct element_recursion<0> {
//static_equal
template <typename P1,typename P2>
static bool static_equal(const P1&, const P2&) { return true; }
//static_copy
template <typename P1,typename P2>
static void static_copy(const P1&, const P2&) {}
//static_fill
template <typename P, typename T2>
static void static_fill(const P&, T2) {}
//static_generate
template <typename Dst,typename Op>
static void static_generate(const Dst&,Op){}
//static_for_each with one source
template <typename P1,typename Op>
static Op static_for_each(const P1&,Op op){return op;}
//static_for_each with two sources
template <typename P1,typename P2,typename Op>
static Op static_for_each(const P1&,const P2&,Op op){return op;}
//static_for_each with three sources
template <typename P1,typename P2,typename P3,typename Op>
static Op static_for_each(const P1&,const P2&,const P3&,Op op){return op;}
//static_transform with one source
template <typename P1,typename Dst,typename Op>
static Op static_transform(const P1&,const Dst&,Op op){return op;}
//static_transform with two sources
template <typename P1,typename P2,typename Dst,typename Op>
static Op static_transform(const P1&,const P2&,const Dst&,Op op){return op;}
};
// std::min and std::max don't have the mutable overloads...
template <typename Q> inline const Q& mutable_min(const Q& x, const Q& y) { return x<y ? x : y; }
template <typename Q> inline Q& mutable_min( Q& x, Q& y) { return x<y ? x : y; }
template <typename Q> inline const Q& mutable_max(const Q& x, const Q& y) { return x<y ? y : x; }
template <typename Q> inline Q& mutable_max( Q& x, Q& y) { return x<y ? y : x; }
// compile-time recursion for min/max element
template <int N>
struct min_max_recur {
template <typename P> static typename element_const_reference_type<P>::type max_(const P& p) {
return mutable_max(min_max_recur<N-1>::max_(p),semantic_at_c<N-1>(p));
}
template <typename P> static typename element_reference_type<P>::type max_( P& p) {
return mutable_max(min_max_recur<N-1>::max_(p),semantic_at_c<N-1>(p));
}
template <typename P> static typename element_const_reference_type<P>::type min_(const P& p) {
return mutable_min(min_max_recur<N-1>::min_(p),semantic_at_c<N-1>(p));
}
template <typename P> static typename element_reference_type<P>::type min_( P& p) {
return mutable_min(min_max_recur<N-1>::min_(p),semantic_at_c<N-1>(p));
}
};
// termination condition of the compile-time recursion for min/max element
template <>
struct min_max_recur<1> {
template <typename P> static typename element_const_reference_type<P>::type max_(const P& p) { return semantic_at_c<0>(p); }
template <typename P> static typename element_reference_type<P>::type max_( P& p) { return semantic_at_c<0>(p); }
template <typename P> static typename element_const_reference_type<P>::type min_(const P& p) { return semantic_at_c<0>(p); }
template <typename P> static typename element_reference_type<P>::type min_( P& p) { return semantic_at_c<0>(p); }
};
} // namespace detail
/// \defgroup ColorBaseAlgorithmMinMax static_min, static_max
/// \ingroup ColorBaseAlgorithm
/// \brief Equivalents to std::min_element and std::max_element for homogeneous color bases
///
/// Example:
/// \code
/// rgb8_pixel_t pixel(10,20,30);
/// assert(pixel[2] == 30);
/// static_max(pixel) = static_min(pixel);
/// assert(pixel[2] == 10);
/// \endcode
/// \{
template <typename P>
BOOST_FORCEINLINE
typename element_const_reference_type<P>::type static_max(const P& p) { return detail::min_max_recur<size<P>::value>::max_(p); }
template <typename P>
BOOST_FORCEINLINE
typename element_reference_type<P>::type static_max( P& p) { return detail::min_max_recur<size<P>::value>::max_(p); }
template <typename P>
BOOST_FORCEINLINE
typename element_const_reference_type<P>::type static_min(const P& p) { return detail::min_max_recur<size<P>::value>::min_(p); }
template <typename P>
BOOST_FORCEINLINE
typename element_reference_type<P>::type static_min( P& p) { return detail::min_max_recur<size<P>::value>::min_(p); }
/// \}
/// \defgroup ColorBaseAlgorithmEqual static_equal
/// \ingroup ColorBaseAlgorithm
/// \brief Equivalent to std::equal. Pairs the elements semantically
///
/// Example:
/// \code
/// rgb8_pixel_t rgb_red(255,0,0);
/// bgr8_pixel_t bgr_red(0,0,255);
/// assert(rgb_red[0]==255 && bgr_red[0]==0);
///
/// assert(static_equal(rgb_red,bgr_red));
/// assert(rgb_red==bgr_red); // operator== invokes static_equal
/// \endcode
/// \{
template <typename P1,typename P2>
BOOST_FORCEINLINE
bool static_equal(const P1& p1, const P2& p2) { return detail::element_recursion<size<P1>::value>::static_equal(p1,p2); }
/// \}
/// \defgroup ColorBaseAlgorithmCopy static_copy
/// \ingroup ColorBaseAlgorithm
/// \brief Equivalent to std::copy. Pairs the elements semantically
///
/// Example:
/// \code
/// rgb8_pixel_t rgb_red(255,0,0);
/// bgr8_pixel_t bgr_red;
/// static_copy(rgb_red, bgr_red); // same as bgr_red = rgb_red
///
/// assert(rgb_red[0] == 255 && bgr_red[0] == 0);
/// assert(rgb_red == bgr_red);
/// \endcode
/// \{
template <typename Src,typename Dst>
BOOST_FORCEINLINE
void static_copy(const Src& src, Dst& dst)
{
detail::element_recursion<size<Dst>::value>::static_copy(src, dst);
}
/// \}
/// \defgroup ColorBaseAlgorithmFill static_fill
/// \ingroup ColorBaseAlgorithm
/// \brief Equivalent to std::fill.
///
/// Example:
/// \code
/// rgb8_pixel_t p;
/// static_fill(p, 10);
/// assert(p == rgb8_pixel_t(10,10,10));
/// \endcode
/// \{
template <typename P,typename V>
BOOST_FORCEINLINE
void static_fill(P& p, const V& v)
{
detail::element_recursion<size<P>::value>::static_fill(p,v);
}
/// \}
/// \defgroup ColorBaseAlgorithmGenerate static_generate
/// \ingroup ColorBaseAlgorithm
/// \brief Equivalent to std::generate.
///
/// Example: Set each channel of a pixel to its semantic index. The channels must be assignable from an integer.
/// \code
/// struct consecutive_fn {
/// int& _current;
/// consecutive_fn(int& start) : _current(start) {}
/// int operator()() { return _current++; }
/// };
/// rgb8_pixel_t p;
/// int start=0;
/// static_generate(p, consecutive_fn(start));
/// assert(p == rgb8_pixel_t(0,1,2));
/// \endcode
///
/// \{
template <typename P1,typename Op>
BOOST_FORCEINLINE
void static_generate(P1& dst,Op op) { detail::element_recursion<size<P1>::value>::static_generate(dst,op); }
/// \}
/// \defgroup ColorBaseAlgorithmTransform static_transform
/// \ingroup ColorBaseAlgorithm
/// \brief Equivalent to std::transform. Pairs the elements semantically
///
/// Example: Write a generic function that adds two pixels into a homogeneous result pixel.
/// \code
/// template <typename Result>
/// struct my_plus {
/// template <typename T1, typename T2>
/// Result operator()(T1 f1, T2 f2) const { return f1+f2; }
/// };
///
/// template <typename Pixel1, typename Pixel2, typename Pixel3>
/// void sum_channels(const Pixel1& p1, const Pixel2& p2, Pixel3& result) {
/// using result_channel_t = typename channel_type<Pixel3>::type;
/// static_transform(p1,p2,result,my_plus<result_channel_t>());
/// }
///
/// rgb8_pixel_t p1(1,2,3);
/// bgr8_pixel_t p2(3,2,1);
/// rgb8_pixel_t result;
/// sum_channels(p1,p2,result);
/// assert(result == rgb8_pixel_t(2,4,6));
/// \endcode
/// \{
//static_transform with one source
template <typename Src,typename Dst,typename Op>
BOOST_FORCEINLINE
Op static_transform(Src& src,Dst& dst,Op op) { return detail::element_recursion<size<Dst>::value>::static_transform(src,dst,op); }
template <typename Src,typename Dst,typename Op>
BOOST_FORCEINLINE
Op static_transform(const Src& src,Dst& dst,Op op) { return detail::element_recursion<size<Dst>::value>::static_transform(src,dst,op); }
//static_transform with two sources
template <typename P2,typename P3,typename Dst,typename Op>
BOOST_FORCEINLINE
Op static_transform(P2& p2,P3& p3,Dst& dst,Op op) { return detail::element_recursion<size<Dst>::value>::static_transform(p2,p3,dst,op); }
template <typename P2,typename P3,typename Dst,typename Op>
BOOST_FORCEINLINE
Op static_transform(P2& p2,const P3& p3,Dst& dst,Op op) { return detail::element_recursion<size<Dst>::value>::static_transform(p2,p3,dst,op); }
template <typename P2,typename P3,typename Dst,typename Op>
BOOST_FORCEINLINE
Op static_transform(const P2& p2,P3& p3,Dst& dst,Op op) { return detail::element_recursion<size<Dst>::value>::static_transform(p2,p3,dst,op); }
template <typename P2,typename P3,typename Dst,typename Op>
BOOST_FORCEINLINE
Op static_transform(const P2& p2,const P3& p3,Dst& dst,Op op) { return detail::element_recursion<size<Dst>::value>::static_transform(p2,p3,dst,op); }
/// \}
/// \defgroup ColorBaseAlgorithmForEach static_for_each
/// \ingroup ColorBaseAlgorithm
/// \brief Equivalent to std::for_each. Pairs the elements semantically
///
/// Example: Use static_for_each to increment a planar pixel iterator
/// \code
/// struct increment {
/// template <typename Incrementable>
/// void operator()(Incrementable& x) const { ++x; }
/// };
///
/// template <typename ColorBase>
/// void increment_elements(ColorBase& cb) {
/// static_for_each(cb, increment());
/// }
///
/// uint8_t red[2], green[2], blue[2];
/// rgb8c_planar_ptr_t p1(red,green,blue);
/// rgb8c_planar_ptr_t p2=p1;
/// increment_elements(p1);
/// ++p2;
/// assert(p1 == p2);
/// \endcode
/// \{
//static_for_each with one source
template <typename P1,typename Op>
BOOST_FORCEINLINE
Op static_for_each( P1& p1, Op op) { return detail::element_recursion<size<P1>::value>::static_for_each(p1,op); }
template <typename P1,typename Op>
BOOST_FORCEINLINE
Op static_for_each(const P1& p1, Op op) { return detail::element_recursion<size<P1>::value>::static_for_each(p1,op); }
//static_for_each with two sources
template <typename P1,typename P2,typename Op>
BOOST_FORCEINLINE
Op static_for_each(P1& p1, P2& p2, Op op) { return detail::element_recursion<size<P1>::value>::static_for_each(p1,p2,op); }
template <typename P1,typename P2,typename Op>
BOOST_FORCEINLINE
Op static_for_each(P1& p1,const P2& p2, Op op) { return detail::element_recursion<size<P1>::value>::static_for_each(p1,p2,op); }
template <typename P1,typename P2,typename Op>
BOOST_FORCEINLINE
Op static_for_each(const P1& p1, P2& p2, Op op) { return detail::element_recursion<size<P1>::value>::static_for_each(p1,p2,op); }
template <typename P1,typename P2,typename Op>
BOOST_FORCEINLINE
Op static_for_each(const P1& p1,const P2& p2, Op op) { return detail::element_recursion<size<P1>::value>::static_for_each(p1,p2,op); }
//static_for_each with three sources
template <typename P1,typename P2,typename P3,typename Op>
BOOST_FORCEINLINE
Op static_for_each(P1& p1,P2& p2,P3& p3,Op op) { return detail::element_recursion<size<P1>::value>::static_for_each(p1,p2,p3,op); }
template <typename P1,typename P2,typename P3,typename Op>
BOOST_FORCEINLINE
Op static_for_each(P1& p1,P2& p2,const P3& p3,Op op) { return detail::element_recursion<size<P1>::value>::static_for_each(p1,p2,p3,op); }
template <typename P1,typename P2,typename P3,typename Op>
BOOST_FORCEINLINE
Op static_for_each(P1& p1,const P2& p2,P3& p3,Op op) { return detail::element_recursion<size<P1>::value>::static_for_each(p1,p2,p3,op); }
template <typename P1,typename P2,typename P3,typename Op>
BOOST_FORCEINLINE
Op static_for_each(P1& p1,const P2& p2,const P3& p3,Op op) { return detail::element_recursion<size<P1>::value>::static_for_each(p1,p2,p3,op); }
template <typename P1,typename P2,typename P3,typename Op>
BOOST_FORCEINLINE
Op static_for_each(const P1& p1,P2& p2,P3& p3,Op op) { return detail::element_recursion<size<P1>::value>::static_for_each(p1,p2,p3,op); }
template <typename P1,typename P2,typename P3,typename Op>
BOOST_FORCEINLINE
Op static_for_each(const P1& p1,P2& p2,const P3& p3,Op op) { return detail::element_recursion<size<P1>::value>::static_for_each(p1,p2,p3,op); }
template <typename P1,typename P2,typename P3,typename Op>
BOOST_FORCEINLINE
Op static_for_each(const P1& p1,const P2& p2,P3& p3,Op op) { return detail::element_recursion<size<P1>::value>::static_for_each(p1,p2,p3,op); }
template <typename P1,typename P2,typename P3,typename Op>
BOOST_FORCEINLINE
Op static_for_each(const P1& p1,const P2& p2,const P3& p3,Op op) { return detail::element_recursion<size<P1>::value>::static_for_each(p1,p2,p3,op); }
///\}
} } // namespace boost::gil
#endif

View File

@@ -0,0 +1,342 @@
//
// 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_COLOR_CONVERT_HPP
#define BOOST_GIL_COLOR_CONVERT_HPP
#include <boost/gil/channel_algorithm.hpp>
#include <boost/gil/cmyk.hpp>
#include <boost/gil/color_base_algorithm.hpp>
#include <boost/gil/gray.hpp>
#include <boost/gil/metafunctions.hpp>
#include <boost/gil/pixel.hpp>
#include <boost/gil/rgb.hpp>
#include <boost/gil/rgba.hpp>
#include <boost/gil/utilities.hpp>
#include <algorithm>
#include <functional>
#include <type_traits>
namespace boost { namespace gil {
/// Support for fast and simple color conversion.
/// Accurate color conversion using color profiles can be supplied separately in a dedicated module.
// Forward-declare
template <typename P> struct channel_type;
////////////////////////////////////////////////////////////////////////////////////////
///
/// COLOR SPACE CONVERSION
///
////////////////////////////////////////////////////////////////////////////////////////
/// \ingroup ColorConvert
/// \brief Color Convertion function object. To be specialized for every src/dst color space
template <typename C1, typename C2>
struct default_color_converter_impl
{
static_assert(
std::is_same<C1, C2>::value,
"default_color_converter_impl not specialized for given color spaces");
};
/// \ingroup ColorConvert
/// \brief When the color space is the same, color convertion performs channel depth conversion
template <typename C>
struct default_color_converter_impl<C,C> {
template <typename P1, typename P2>
void operator()(const P1& src, P2& dst) const {
static_for_each(src,dst,default_channel_converter());
}
};
namespace detail {
/// red * .3 + green * .59 + blue * .11 + .5
// The default implementation of to_luminance uses float0..1 as the intermediate channel type
template <typename RedChannel, typename GreenChannel, typename BlueChannel, typename GrayChannelValue>
struct rgb_to_luminance_fn {
GrayChannelValue operator()(const RedChannel& red, const GreenChannel& green, const BlueChannel& blue) const {
return channel_convert<GrayChannelValue>(float32_t(
channel_convert<float32_t>(red )*0.30f +
channel_convert<float32_t>(green)*0.59f +
channel_convert<float32_t>(blue )*0.11f) );
}
};
// performance specialization for unsigned char
template <typename GrayChannelValue>
struct rgb_to_luminance_fn<uint8_t,uint8_t,uint8_t, GrayChannelValue> {
GrayChannelValue operator()(uint8_t red, uint8_t green, uint8_t blue) const {
return channel_convert<GrayChannelValue>(uint8_t(
((uint32_t(red )*4915 + uint32_t(green)*9667 + uint32_t(blue )*1802) + 8192) >> 14));
}
};
template <typename GrayChannel, typename RedChannel, typename GreenChannel, typename BlueChannel>
typename channel_traits<GrayChannel>::value_type rgb_to_luminance(const RedChannel& red, const GreenChannel& green, const BlueChannel& blue) {
return rgb_to_luminance_fn<RedChannel,GreenChannel,BlueChannel,
typename channel_traits<GrayChannel>::value_type>()(red,green,blue);
}
} // namespace detail
/// \ingroup ColorConvert
/// \brief Gray to RGB
template <>
struct default_color_converter_impl<gray_t,rgb_t> {
template <typename P1, typename P2>
void operator()(const P1& src, P2& dst) const {
get_color(dst,red_t()) =
channel_convert<typename color_element_type<P2, red_t >::type>(get_color(src,gray_color_t()));
get_color(dst,green_t())=
channel_convert<typename color_element_type<P2, green_t>::type>(get_color(src,gray_color_t()));
get_color(dst,blue_t()) =
channel_convert<typename color_element_type<P2, blue_t >::type>(get_color(src,gray_color_t()));
}
};
/// \ingroup ColorConvert
/// \brief Gray to CMYK
/// \todo FIXME: Where does this calculation come from? Shouldn't gray be inverted?
/// Currently, white becomes black and black becomes white.
template <>
struct default_color_converter_impl<gray_t,cmyk_t> {
template <typename P1, typename P2>
void operator()(const P1& src, P2& dst) const {
get_color(dst,cyan_t())=
channel_traits<typename color_element_type<P2, cyan_t >::type>::min_value();
get_color(dst,magenta_t())=
channel_traits<typename color_element_type<P2, magenta_t>::type>::min_value();
get_color(dst,yellow_t())=
channel_traits<typename color_element_type<P2, yellow_t >::type>::min_value();
get_color(dst,black_t())=
channel_convert<typename color_element_type<P2, black_t >::type>(get_color(src,gray_color_t()));
}
};
/// \ingroup ColorConvert
/// \brief RGB to Gray
template <>
struct default_color_converter_impl<rgb_t,gray_t> {
template <typename P1, typename P2>
void operator()(const P1& src, P2& dst) const {
get_color(dst,gray_color_t()) =
detail::rgb_to_luminance<typename color_element_type<P2,gray_color_t>::type>(
get_color(src,red_t()), get_color(src,green_t()), get_color(src,blue_t())
);
}
};
/// \ingroup ColorConvert
/// \brief RGB to CMYK (not the fastest code in the world)
///
/// k = min(1 - r, 1 - g, 1 - b)
/// c = (1 - r - k) / (1 - k)
/// m = (1 - g - k) / (1 - k)
/// y = (1 - b - k) / (1 - k)
/// where `1` denotes max value of channel type of destination pixel.
///
/// The conversion from RGB to CMYK is based on CMY->CMYK (Version 2)
/// from the Principles of Digital Image Processing - Fundamental Techniques
/// by Burger, Wilhelm, Burge, Mark J.
/// and it is a gross approximation not precise enough for professional work.
///
/// \todo FIXME: The original implementation did not handle properly signed CMYK pixels as destination
///
template <>
struct default_color_converter_impl<rgb_t, cmyk_t>
{
template <typename SrcPixel, typename DstPixel>
void operator()(SrcPixel const& src, DstPixel& dst) const
{
using src_t = typename channel_type<SrcPixel>::type;
src_t const r = get_color(src, red_t());
src_t const g = get_color(src, green_t());
src_t const b = get_color(src, blue_t());
using dst_t = typename channel_type<DstPixel>::type;
dst_t const c = channel_invert(channel_convert<dst_t>(r)); // c = 1 - r
dst_t const m = channel_invert(channel_convert<dst_t>(g)); // m = 1 - g
dst_t const y = channel_invert(channel_convert<dst_t>(b)); // y = 1 - b
dst_t const k = (std::min)(c, (std::min)(m, y)); // k = minimum(c, m, y)
// Apply color correction, strengthening, reducing non-zero components by
// s = 1 / (1 - k) for k < 1, where 1 denotes dst_t max, otherwise s = 1 (literal).
dst_t const dst_max = channel_traits<dst_t>::max_value();
dst_t const s_div = dst_max - k;
if (s_div != 0)
{
double const s = dst_max / static_cast<double>(s_div);
get_color(dst, cyan_t()) = static_cast<dst_t>((c - k) * s);
get_color(dst, magenta_t()) = static_cast<dst_t>((m - k) * s);
get_color(dst, yellow_t()) = static_cast<dst_t>((y - k) * s);
}
else
{
// Black only for k = 1 (max of dst_t)
get_color(dst, cyan_t()) = channel_traits<dst_t>::min_value();
get_color(dst, magenta_t()) = channel_traits<dst_t>::min_value();
get_color(dst, yellow_t()) = channel_traits<dst_t>::min_value();
}
get_color(dst, black_t()) = k;
}
};
/// \ingroup ColorConvert
/// \brief CMYK to RGB (not the fastest code in the world)
///
/// r = 1 - min(1, c*(1-k)+k)
/// g = 1 - min(1, m*(1-k)+k)
/// b = 1 - min(1, y*(1-k)+k)
template <>
struct default_color_converter_impl<cmyk_t,rgb_t> {
template <typename P1, typename P2>
void operator()(const P1& src, P2& dst) const {
using T1 = typename channel_type<P1>::type;
get_color(dst,red_t()) =
channel_convert<typename color_element_type<P2,red_t>::type>(
channel_invert<T1>(
(std::min)(channel_traits<T1>::max_value(),
T1(channel_multiply(get_color(src,cyan_t()),channel_invert(get_color(src,black_t())))+get_color(src,black_t())))));
get_color(dst,green_t())=
channel_convert<typename color_element_type<P2,green_t>::type>(
channel_invert<T1>(
(std::min)(channel_traits<T1>::max_value(),
T1(channel_multiply(get_color(src,magenta_t()),channel_invert(get_color(src,black_t())))+get_color(src,black_t())))));
get_color(dst,blue_t()) =
channel_convert<typename color_element_type<P2,blue_t>::type>(
channel_invert<T1>(
(std::min)(channel_traits<T1>::max_value(),
T1(channel_multiply(get_color(src,yellow_t()),channel_invert(get_color(src,black_t())))+get_color(src,black_t())))));
}
};
/// \ingroup ColorConvert
/// \brief CMYK to Gray
///
/// gray = (1 - 0.212c - 0.715m - 0.0722y) * (1 - k)
template <>
struct default_color_converter_impl<cmyk_t,gray_t> {
template <typename P1, typename P2>
void operator()(const P1& src, P2& dst) const {
get_color(dst,gray_color_t())=
channel_convert<typename color_element_type<P2,gray_color_t>::type>(
channel_multiply(
channel_invert(
detail::rgb_to_luminance<typename color_element_type<P1,black_t>::type>(
get_color(src,cyan_t()),
get_color(src,magenta_t()),
get_color(src,yellow_t())
)
),
channel_invert(get_color(src,black_t()))));
}
};
namespace detail {
template <typename Pixel>
auto alpha_or_max_impl(Pixel const& p, std::true_type) -> typename channel_type<Pixel>::type
{
return get_color(p,alpha_t());
}
template <typename Pixel>
auto alpha_or_max_impl(Pixel const&, std::false_type) -> typename channel_type<Pixel>::type
{
return channel_traits<typename channel_type<Pixel>::type>::max_value();
}
} // namespace detail
// Returns max_value if the pixel has no alpha channel. Otherwise returns the alpha.
template <typename Pixel>
auto alpha_or_max(Pixel const& p) -> typename channel_type<Pixel>::type
{
return detail::alpha_or_max_impl(
p,
mp11::mp_contains<typename color_space_type<Pixel>::type, alpha_t>());
}
/// \ingroup ColorConvert
/// \brief Converting any pixel type to RGBA. Note: Supports homogeneous pixels only.
template <typename C1>
struct default_color_converter_impl<C1,rgba_t> {
template <typename P1, typename P2>
void operator()(const P1& src, P2& dst) const {
using T2 = typename channel_type<P2>::type;
pixel<T2,rgb_layout_t> tmp;
default_color_converter_impl<C1,rgb_t>()(src,tmp);
get_color(dst,red_t()) =get_color(tmp,red_t());
get_color(dst,green_t())=get_color(tmp,green_t());
get_color(dst,blue_t()) =get_color(tmp,blue_t());
get_color(dst,alpha_t())=channel_convert<T2>(alpha_or_max(src));
}
};
/// \ingroup ColorConvert
/// \brief Converting RGBA to any pixel type. Note: Supports homogeneous pixels only.
///
/// Done by multiplying the alpha to get to RGB, then converting the RGB to the target pixel type
/// Note: This may be slower if the compiler doesn't optimize out constructing/destructing a temporary RGB pixel.
/// Consider rewriting if performance is an issue
template <typename C2>
struct default_color_converter_impl<rgba_t,C2> {
template <typename P1, typename P2>
void operator()(const P1& src, P2& dst) const {
using T1 = typename channel_type<P1>::type;
default_color_converter_impl<rgb_t,C2>()(
pixel<T1,rgb_layout_t>(channel_multiply(get_color(src,red_t()), get_color(src,alpha_t())),
channel_multiply(get_color(src,green_t()),get_color(src,alpha_t())),
channel_multiply(get_color(src,blue_t()), get_color(src,alpha_t())))
,dst);
}
};
/// \ingroup ColorConvert
/// \brief Unfortunately RGBA to RGBA must be explicitly provided - otherwise we get ambiguous specialization error.
template <>
struct default_color_converter_impl<rgba_t,rgba_t> {
template <typename P1, typename P2>
void operator()(const P1& src, P2& dst) const {
static_for_each(src,dst,default_channel_converter());
}
};
/// @defgroup ColorConvert Color Space Converion
/// \ingroup ColorSpaces
/// \brief Support for conversion between pixels of different color spaces and channel depths
/// \ingroup PixelAlgorithm ColorConvert
/// \brief class for color-converting one pixel to another
struct default_color_converter {
template <typename SrcP, typename DstP>
void operator()(const SrcP& src,DstP& dst) const {
using SrcColorSpace = typename color_space_type<SrcP>::type;
using DstColorSpace = typename color_space_type<DstP>::type;
default_color_converter_impl<SrcColorSpace,DstColorSpace>()(src,dst);
}
};
/// \ingroup PixelAlgorithm
/// \brief helper function for converting one pixel to another using GIL default color-converters
/// where ScrP models HomogeneousPixelConcept
/// DstP models HomogeneousPixelValueConcept
template <typename SrcP, typename DstP>
inline void color_convert(const SrcP& src, DstP& dst) {
default_color_converter()(src,dst);
}
} } // namespace boost::gil
#endif

View File

@@ -0,0 +1,26 @@
//
// 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_CONCEPTS_HPP
#define BOOST_GIL_CONCEPTS_HPP
// TODO: Remove and prefer individual includes from boost/gil/concepts/*.hpp?
#include <boost/gil/concepts/channel.hpp>
#include <boost/gil/concepts/color.hpp>
#include <boost/gil/concepts/color_base.hpp>
#include <boost/gil/concepts/concept_check.hpp>
#include <boost/gil/concepts/image.hpp>
#include <boost/gil/concepts/image_view.hpp>
#include <boost/gil/concepts/pixel.hpp>
#include <boost/gil/concepts/pixel_based.hpp>
#include <boost/gil/concepts/pixel_dereference.hpp>
#include <boost/gil/concepts/pixel_iterator.hpp>
#include <boost/gil/concepts/pixel_locator.hpp>
#include <boost/gil/concepts/point.hpp>
#endif

View File

@@ -0,0 +1,196 @@
//
// 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_CONCEPTS_BASIC_HPP
#define BOOST_GIL_CONCEPTS_BASIC_HPP
#include <boost/config.hpp>
#if defined(BOOST_CLANG)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunknown-pragmas"
#pragma clang diagnostic ignored "-Wunused-local-typedefs"
#pragma clang diagnostic ignored "-Wuninitialized"
#endif
#if defined(BOOST_GCC) && (BOOST_GCC >= 40900)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#pragma GCC diagnostic ignored "-Wuninitialized"
#endif
#include <boost/gil/concepts/concept_check.hpp>
#include <type_traits>
#include <utility> // std::swap
namespace boost { namespace gil {
/// \brief Concept of default construction requirement.
/// \code
/// auto concept DefaultConstructible<typename T>
/// {
/// T::T();
/// };
/// \endcode
/// \ingroup BasicConcepts
///
template <typename T>
struct DefaultConstructible
{
void constraints()
{
function_requires<boost::DefaultConstructibleConcept<T>>();
}
};
/// \brief Concept of copy construction requirement.
/// \code
/// auto concept CopyConstructible<typename T>
/// {
/// T::T(T);
/// T::~T();
/// };
/// \endcode
/// \ingroup BasicConcepts
///
template <typename T>
struct CopyConstructible
{
void constraints()
{
function_requires<boost::CopyConstructibleConcept<T>>();
}
};
/// \brief Concept of copy assignment requirement.
/// \code
/// auto concept Assignable<typename T, typename U = T>
/// {
/// typename result_type;
/// result_type operator=(T&, U);
/// };
/// \endcode
/// \ingroup BasicConcepts
///
template <typename T>
struct Assignable
{
void constraints()
{
function_requires<boost::AssignableConcept<T>>();
}
};
/// \brief Concept of == and != comparability requirement.
/// \code
/// auto concept EqualityComparable<typename T, typename U = T>
/// {
/// bool operator==(T x, T y);
/// bool operator!=(T x, T y) { return !(x==y); }
/// };
/// \endcode
/// \ingroup BasicConcepts
///
template <typename T>
struct EqualityComparable
{
void constraints()
{
function_requires<boost::EqualityComparableConcept<T>>();
}
};
/// \brief Concept of swap operation requirement.
/// \code
/// auto concept Swappable<typename T>
/// {
/// void swap(T&,T&);
/// };
/// \endcode
/// \ingroup BasicConcepts
///
template <typename T>
struct Swappable
{
void constraints()
{
using std::swap;
swap(x,y);
}
T x,y;
};
/// \brief Concept for type regularity requirement.
/// \code
/// auto concept Regular<typename T>
/// : DefaultConstructible<T>
/// , CopyConstructible<T>
/// , EqualityComparable<T>
/// , Assignable<T>
/// , Swappable<T>
/// {};
/// \endcode
/// \ingroup BasicConcepts
///
template <typename T>
struct Regular
{
void constraints()
{
gil_function_requires< boost::DefaultConstructibleConcept<T>>();
gil_function_requires< boost::CopyConstructibleConcept<T>>();
gil_function_requires< boost::EqualityComparableConcept<T>>(); // ==, !=
gil_function_requires< boost::AssignableConcept<T>>();
gil_function_requires< Swappable<T>>();
}
};
/// \brief Concept for type as metafunction requirement.
/// \code
/// auto concept Metafunction<typename T>
/// {
/// typename type;
/// };
/// \endcode
/// \ingroup BasicConcepts
///
template <typename T>
struct Metafunction
{
void constraints()
{
using type = typename T::type;
}
};
/// \brief Concept of types equivalence requirement.
/// \code
/// auto concept SameType<typename T, typename U>; // unspecified
/// \endcode
/// \ingroup BasicConcepts
///
template <typename T, typename U>
struct SameType
{
void constraints()
{
static_assert(std::is_same<T, U>::value, "");
}
};
}} // namespace boost::gil
#if defined(BOOST_CLANG)
#pragma clang diagnostic pop
#endif
#if defined(BOOST_GCC) && (BOOST_GCC >= 40900)
#pragma GCC diagnostic pop
#endif
#endif

View File

@@ -0,0 +1,216 @@
//
// 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_CONCEPTS_CHANNEL_HPP
#define BOOST_GIL_CONCEPTS_CHANNEL_HPP
#include <boost/gil/concepts/basic.hpp>
#include <boost/gil/concepts/concept_check.hpp>
#include <boost/gil/concepts/fwd.hpp>
#include <boost/concept_check.hpp>
#include <utility> // std::swap
#include <type_traits>
#if defined(BOOST_CLANG)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunknown-pragmas"
#pragma clang diagnostic ignored "-Wunused-local-typedefs"
#endif
#if defined(BOOST_GCC) && (BOOST_GCC >= 40900)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#endif
namespace boost { namespace gil {
// Forward declarations
template <typename T>
struct channel_traits;
template <typename DstT, typename SrcT>
auto channel_convert(SrcT const& val)
-> typename channel_traits<DstT>::value_type;
/// \ingroup ChannelConcept
/// \brief A channel is the building block of a color.
/// Color is defined as a mixture of primary colors and a channel defines
/// the degree to which each primary color is used in the mixture.
///
/// For example, in the RGB color space, using 8-bit unsigned channels,
/// the color red is defined as [255 0 0], which means maximum of Red,
/// and no Green and Blue.
///
/// Built-in scalar types, such as \p int and \p float, are valid GIL channels.
/// In more complex scenarios, channels may be represented as bit ranges or
/// even individual bits.
/// In such cases special classes are needed to represent the value and
/// reference to a channel.
///
/// Channels have a traits class, \p channel_traits, which defines their
/// associated types as well as their operating ranges.
///
/// \code
/// concept ChannelConcept<typename T> : EqualityComparable<T>
/// {
/// typename value_type = T; // use channel_traits<T>::value_type to access it
/// typename reference = T&; // use channel_traits<T>::reference to access it
/// typename pointer = T*; // use channel_traits<T>::pointer to access it
/// typename const_reference = const T&; // use channel_traits<T>::const_reference to access it
/// typename const_pointer = const T*; // use channel_traits<T>::const_pointer to access it
/// static const bool is_mutable; // use channel_traits<T>::is_mutable to access it
///
/// static T min_value(); // use channel_traits<T>::min_value to access it
/// static T max_value(); // use channel_traits<T>::max_value to access it
/// };
/// \endcode
template <typename T>
struct ChannelConcept
{
void constraints()
{
gil_function_requires<boost::EqualityComparableConcept<T>>();
using v = typename channel_traits<T>::value_type;
using r = typename channel_traits<T>::reference;
using p = typename channel_traits<T>::pointer;
using cr = typename channel_traits<T>::const_reference;
using cp = typename channel_traits<T>::const_pointer;
channel_traits<T>::min_value();
channel_traits<T>::max_value();
}
T c;
};
namespace detail
{
/// \tparam T models ChannelConcept
template <typename T>
struct ChannelIsMutableConcept
{
void constraints()
{
c1 = c2;
using std::swap;
swap(c1, c2);
}
T c1;
T c2;
};
} // namespace detail
/// \brief A channel that allows for modifying its value
/// \code
/// concept MutableChannelConcept<ChannelConcept T> : Assignable<T>, Swappable<T> {};
/// \endcode
/// \ingroup ChannelConcept
template <typename T>
struct MutableChannelConcept
{
void constraints()
{
gil_function_requires<ChannelConcept<T>>();
gil_function_requires<detail::ChannelIsMutableConcept<T>>();
}
};
/// \brief A channel that supports default construction.
/// \code
/// concept ChannelValueConcept<ChannelConcept T> : Regular<T> {};
/// \endcode
/// \ingroup ChannelConcept
template <typename T>
struct ChannelValueConcept
{
void constraints()
{
gil_function_requires<ChannelConcept<T>>();
gil_function_requires<Regular<T>>();
}
};
/// \brief Predicate metafunction returning whether two channels are compatible
///
/// Channels are considered compatible if their value types
/// (ignoring constness and references) are the same.
///
/// Example:
///
/// \code
/// static_assert(channels_are_compatible<uint8_t, const uint8_t&>::value, "");
/// \endcode
/// \ingroup ChannelAlgorithm
template <typename T1, typename T2> // Models GIL Pixel
struct channels_are_compatible
: std::is_same
<
typename channel_traits<T1>::value_type,
typename channel_traits<T2>::value_type
>
{
};
/// \brief Channels are compatible if their associated value types (ignoring constness and references) are the same
///
/// \code
/// concept ChannelsCompatibleConcept<ChannelConcept T1, ChannelConcept T2>
/// {
/// where SameType<T1::value_type, T2::value_type>;
/// };
/// \endcode
/// \ingroup ChannelConcept
template <typename Channel1, typename Channel2>
struct ChannelsCompatibleConcept
{
void constraints()
{
static_assert(channels_are_compatible<Channel1, Channel2>::value, "");
}
};
/// \brief A channel is convertible to another one if the \p channel_convert algorithm is defined for the two channels.
///
/// Convertibility is non-symmetric and implies that one channel can be
/// converted to another. Conversion is explicit and often lossy operation.
///
/// concept ChannelConvertibleConcept<ChannelConcept SrcChannel, ChannelValueConcept DstChannel>
/// {
/// DstChannel channel_convert(const SrcChannel&);
/// };
/// \endcode
/// \ingroup ChannelConcept
template <typename SrcChannel, typename DstChannel>
struct ChannelConvertibleConcept
{
void constraints()
{
gil_function_requires<ChannelConcept<SrcChannel>>();
gil_function_requires<MutableChannelConcept<DstChannel>>();
dst = channel_convert<DstChannel, SrcChannel>(src);
ignore_unused_variable_warning(dst);
}
SrcChannel src;
DstChannel dst;
};
}} // namespace boost::gil
#if defined(BOOST_CLANG)
#pragma clang diagnostic pop
#endif
#if defined(BOOST_GCC) && (BOOST_GCC >= 40900)
#pragma GCC diagnostic pop
#endif
#endif

View File

@@ -0,0 +1,99 @@
//
// 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_CONCEPTS_COLOR_HPP
#define BOOST_GIL_CONCEPTS_COLOR_HPP
#include <boost/gil/concepts/concept_check.hpp>
#include <type_traits>
#if defined(BOOST_CLANG)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunknown-pragmas"
#pragma clang diagnostic ignored "-Wunused-local-typedefs"
#endif
#if defined(BOOST_GCC) && (BOOST_GCC >= 40900)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#endif
namespace boost { namespace gil {
/// \ingroup ColorSpaceAndLayoutConcept
/// \brief Color space type concept
/// \code
/// concept ColorSpaceConcept<MPLRandomAccessSequence CS>
/// {
/// // Boost.MP11-compatible list, whose elements are color tags.
/// };
/// \endcode
template <typename CS>
struct ColorSpaceConcept
{
void constraints()
{
// Boost.MP11-compatible list, whose elements are color tags
// TODO: Is this incomplete?
}
};
// Models ColorSpaceConcept
template <typename CS1, typename CS2>
struct color_spaces_are_compatible : std::is_same<CS1, CS2> {};
/// \ingroup ColorSpaceAndLayoutConcept
/// \brief Two color spaces are compatible if they are the same
/// \code
/// concept ColorSpacesCompatibleConcept<ColorSpaceConcept CS1, ColorSpaceConcept CS2>
/// {
/// where SameType<CS1, CS2>;
/// };
/// \endcode
template <typename CS1, typename CS2>
struct ColorSpacesCompatibleConcept
{
void constraints()
{
static_assert(color_spaces_are_compatible<CS1, CS2>::value, "");
}
};
/// \ingroup ColorSpaceAndLayoutConcept
/// \brief Channel mapping concept
/// \code
/// concept ChannelMappingConcept<MPLRandomAccessSequence CM>
/// {
/// // Boost.MP11-compatible list, whose elements
/// // model MPLIntegralConstant representing a permutation
/// };
/// \endcode
template <typename CM>
struct ChannelMappingConcept
{
void constraints()
{
// Boost.MP11-compatible list, whose elements model
// MPLIntegralConstant representing a permutation.
// TODO: Is this incomplete?
}
};
}} // namespace boost::gil
#if defined(BOOST_CLANG)
#pragma clang diagnostic pop
#endif
#if defined(BOOST_GCC) && (BOOST_GCC >= 40900)
#pragma GCC diagnostic pop
#endif
#endif

View File

@@ -0,0 +1,329 @@
//
// 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_CONCEPTS_COLOR_BASE_HPP
#define BOOST_GIL_CONCEPTS_COLOR_BASE_HPP
#include <boost/gil/concepts/basic.hpp>
#include <boost/gil/concepts/color.hpp>
#include <boost/gil/concepts/concept_check.hpp>
#include <boost/gil/concepts/fwd.hpp>
#include <boost/core/ignore_unused.hpp>
#include <type_traits>
#if defined(BOOST_CLANG)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunknown-pragmas"
#pragma clang diagnostic ignored "-Wunused-local-typedefs"
#endif
#if defined(BOOST_GCC) && (BOOST_GCC >= 40900)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#endif
namespace boost { namespace gil {
// Forward declarations of at_c
namespace detail {
template <typename Element, typename Layout, int K>
struct homogeneous_color_base;
} // namespace detail
template <int K, typename E, typename L, int N>
auto at_c(detail::homogeneous_color_base<E, L, N>& p)
-> typename std::add_lvalue_reference<E>::type;
template <int K, typename E, typename L, int N>
auto at_c(detail::homogeneous_color_base<E, L, N> const& p)
-> typename std::add_lvalue_reference<typename std::add_const<E>::type>::type;
template <typename P, typename C, typename L>
struct packed_pixel;
template <int K, typename P, typename C, typename L>
auto at_c(packed_pixel<P, C, L>& p)
-> typename kth_element_reference_type<packed_pixel<P, C, L>, K>::type;
template <int K, typename P, typename C, typename L>
auto at_c(packed_pixel<P, C, L> const& p)
-> typename kth_element_const_reference_type<packed_pixel<P, C, L>, K>::type;
template <typename B, typename C, typename L, bool M>
struct bit_aligned_pixel_reference;
template <int K, typename B, typename C, typename L, bool M>
inline auto at_c(bit_aligned_pixel_reference<B, C, L, M> const& p)
-> typename kth_element_reference_type
<
bit_aligned_pixel_reference<B, C, L, M>,
K
>::type;
// Forward declarations of semantic_at_c
template <int K, typename ColorBase>
auto semantic_at_c(ColorBase& p)
-> typename std::enable_if
<
!std::is_const<ColorBase>::value,
typename kth_semantic_element_reference_type<ColorBase, K>::type
>::type;
template <int K, typename ColorBase>
auto semantic_at_c(ColorBase const& p)
-> typename kth_semantic_element_const_reference_type<ColorBase, K>::type;
/// \ingroup ColorBaseConcept
/// \brief A color base is a container of color elements (such as channels, channel references or channel pointers).
///
/// The most common use of color base is in the implementation of a pixel,
/// in which case the color elements are channel values. The color base concept,
/// however, can be used in other scenarios. For example, a planar pixel has
/// channels that are not contiguous in memory. Its reference is a proxy class
/// that uses a color base whose elements are channel references. Its iterator
/// uses a color base whose elements are channel iterators.
///
/// A color base must have an associated layout (which consists of a color space,
/// as well as an ordering of the channels).
/// There are two ways to index the elements of a color base: A physical index
/// corresponds to the way they are ordered in memory, and a semantic index
/// corresponds to the way the elements are ordered in their color space.
/// For example, in the RGB color space the elements are ordered as
/// {red_t, green_t, blue_t}. For a color base with a BGR layout, the first element
/// in physical ordering is the blue element, whereas the first semantic element
/// is the red one.
/// Models of \p ColorBaseConcept are required to provide the \p at_c<K>(ColorBase)
/// function, which allows for accessing the elements based on their physical order.
/// GIL provides a \p semantic_at_c<K>(ColorBase) function (described later)
/// which can operate on any model of ColorBaseConcept and returns the corresponding
/// semantic element.
///
/// \code
/// concept ColorBaseConcept<typename T> : CopyConstructible<T>, EqualityComparable<T>
/// {
/// // a GIL layout (the color space and element permutation)
/// typename layout_t;
///
/// // The type of K-th element
/// template <int K>
/// struct kth_element_type;
/// where Metafunction<kth_element_type>;
///
/// // The result of at_c
/// template <int K>
/// struct kth_element_const_reference_type;
/// where Metafunction<kth_element_const_reference_type>;
///
/// template <int K>
/// kth_element_const_reference_type<T,K>::type at_c(T);
///
/// // Copy-constructible and equality comparable with other compatible color bases
/// template <ColorBaseConcept T2> where { ColorBasesCompatibleConcept<T,T2> }
/// T::T(T2);
/// template <ColorBaseConcept T2> where { ColorBasesCompatibleConcept<T,T2> }
/// bool operator==(const T&, const T2&);
/// template <ColorBaseConcept T2> where { ColorBasesCompatibleConcept<T,T2> }
/// bool operator!=(const T&, const T2&);
/// };
/// \endcode
template <typename ColorBase>
struct ColorBaseConcept
{
void constraints()
{
gil_function_requires<CopyConstructible<ColorBase>>();
gil_function_requires<EqualityComparable<ColorBase>>();
using color_space_t = typename ColorBase::layout_t::color_space_t;
gil_function_requires<ColorSpaceConcept<color_space_t>>();
using channel_mapping_t = typename ColorBase::layout_t::channel_mapping_t;
// TODO: channel_mapping_t must be an Boost.MP11-compatible random access sequence
static const int num_elements = size<ColorBase>::value;
using TN = typename kth_element_type<ColorBase, num_elements - 1>::type;
using RN = typename kth_element_const_reference_type<ColorBase, num_elements - 1>::type;
RN r = gil::at_c<num_elements - 1>(cb);
boost::ignore_unused(r);
// functions that work for every pixel (no need to require them)
semantic_at_c<0>(cb);
semantic_at_c<num_elements-1>(cb);
// also static_max(cb), static_min(cb), static_fill(cb,value),
// and all variations of static_for_each(), static_generate(), static_transform()
}
ColorBase cb;
};
/// \ingroup ColorBaseConcept
/// \brief Color base which allows for modifying its elements
/// \code
/// concept MutableColorBaseConcept<ColorBaseConcept T> : Assignable<T>, Swappable<T>
/// {
/// template <int K>
/// struct kth_element_reference_type; where Metafunction<kth_element_reference_type>;
///
/// template <int K>
/// kth_element_reference_type<kth_element_type<T,K>::type>::type at_c(T);
///
/// template <ColorBaseConcept T2> where { ColorBasesCompatibleConcept<T,T2> }
/// T& operator=(T&, const T2&);
/// };
/// \endcode
template <typename ColorBase>
struct MutableColorBaseConcept
{
void constraints()
{
gil_function_requires<ColorBaseConcept<ColorBase>>();
gil_function_requires<Assignable<ColorBase>>();
gil_function_requires<Swappable<ColorBase>>();
using R0 = typename kth_element_reference_type<ColorBase, 0>::type;
R0 r = gil::at_c<0>(cb);
gil::at_c<0>(cb) = r;
}
ColorBase cb;
};
/// \ingroup ColorBaseConcept
/// \brief Color base that also has a default-constructor. Refines Regular
/// \code
/// concept ColorBaseValueConcept<typename T> : MutableColorBaseConcept<T>, Regular<T>
/// {
/// };
/// \endcode
template <typename ColorBase>
struct ColorBaseValueConcept
{
void constraints()
{
gil_function_requires<MutableColorBaseConcept<ColorBase>>();
gil_function_requires<Regular<ColorBase>>();
}
};
/// \ingroup ColorBaseConcept
/// \brief Color base whose elements all have the same type
/// \code
/// concept HomogeneousColorBaseConcept<ColorBaseConcept CB>
/// {
/// // For all K in [0 ... size<C1>::value-1):
/// // where SameType<kth_element_type<CB,K>::type, kth_element_type<CB,K+1>::type>;
/// kth_element_const_reference_type<CB,0>::type dynamic_at_c(CB const&, std::size_t n) const;
/// };
/// \endcode
template <typename ColorBase>
struct HomogeneousColorBaseConcept
{
void constraints()
{
gil_function_requires<ColorBaseConcept<ColorBase>>();
static const int num_elements = size<ColorBase>::value;
using T0 = typename kth_element_type<ColorBase, 0>::type;
using TN = typename kth_element_type<ColorBase, num_elements - 1>::type;
static_assert(std::is_same<T0, TN>::value, ""); // better than nothing
using R0 = typename kth_element_const_reference_type<ColorBase, 0>::type;
R0 r = dynamic_at_c(cb, 0);
boost::ignore_unused(r);
}
ColorBase cb;
};
/// \ingroup ColorBaseConcept
/// \brief Homogeneous color base that allows for modifying its elements
/// \code
/// concept MutableHomogeneousColorBaseConcept<ColorBaseConcept CB>
/// : HomogeneousColorBaseConcept<CB>
/// {
/// kth_element_reference_type<CB, 0>::type dynamic_at_c(CB&, std::size_t n);
/// };
/// \endcode
template <typename ColorBase>
struct MutableHomogeneousColorBaseConcept
{
void constraints()
{
gil_function_requires<ColorBaseConcept<ColorBase>>();
gil_function_requires<HomogeneousColorBaseConcept<ColorBase>>();
using R0 = typename kth_element_reference_type<ColorBase, 0>::type;
R0 r = dynamic_at_c(cb, 0);
boost::ignore_unused(r);
dynamic_at_c(cb, 0) = dynamic_at_c(cb, 0);
}
ColorBase cb;
};
/// \ingroup ColorBaseConcept
/// \brief Homogeneous color base that also has a default constructor.
/// Refines Regular.
///
/// \code
/// concept HomogeneousColorBaseValueConcept<typename T>
/// : MutableHomogeneousColorBaseConcept<T>, Regular<T>
/// {
/// };
/// \endcode
template <typename ColorBase>
struct HomogeneousColorBaseValueConcept
{
void constraints()
{
gil_function_requires<MutableHomogeneousColorBaseConcept<ColorBase>>();
gil_function_requires<Regular<ColorBase>>();
}
};
/// \ingroup ColorBaseConcept
/// \brief Two color bases are compatible if they have the same color space and their elements are compatible, semantic-pairwise.
/// \code
/// concept ColorBasesCompatibleConcept<ColorBaseConcept C1, ColorBaseConcept C2>
/// {
/// where SameType<C1::layout_t::color_space_t, C2::layout_t::color_space_t>;
/// // also, for all K in [0 ... size<C1>::value):
/// // where Convertible<kth_semantic_element_type<C1,K>::type, kth_semantic_element_type<C2,K>::type>;
/// // where Convertible<kth_semantic_element_type<C2,K>::type, kth_semantic_element_type<C1,K>::type>;
/// };
/// \endcode
template <typename ColorBase1, typename ColorBase2>
struct ColorBasesCompatibleConcept
{
void constraints()
{
static_assert(std::is_same
<
typename ColorBase1::layout_t::color_space_t,
typename ColorBase2::layout_t::color_space_t
>::value, "");
// using e1 = typename kth_semantic_element_type<ColorBase1,0>::type;
// using e2 = typename kth_semantic_element_type<ColorBase2,0>::type;
// "e1 is convertible to e2"
}
};
}} // namespace boost::gil
#if defined(BOOST_CLANG)
#pragma clang diagnostic pop
#endif
#if defined(BOOST_GCC) && (BOOST_GCC >= 40900)
#pragma GCC diagnostic pop
#endif
#endif

View File

@@ -0,0 +1,60 @@
//
// 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_CONCEPTS_CONCEPTS_CHECK_HPP
#define BOOST_GIL_CONCEPTS_CONCEPTS_CHECK_HPP
#include <boost/config.hpp>
#if defined(BOOST_CLANG)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunknown-pragmas"
#pragma clang diagnostic ignored "-Wconversion"
#pragma clang diagnostic ignored "-Wfloat-equal"
#pragma clang diagnostic ignored "-Wuninitialized"
#endif
#if defined(BOOST_GCC) && (BOOST_GCC >= 40900)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wconversion"
#pragma GCC diagnostic ignored "-Wfloat-equal"
#pragma GCC diagnostic ignored "-Wuninitialized"
#endif
#include <boost/concept_check.hpp>
#if defined(BOOST_CLANG)
#pragma clang diagnostic pop
#endif
#if defined(BOOST_GCC) && (BOOST_GCC >= 40900)
#pragma GCC diagnostic pop
#endif
// TODO: Document BOOST_GIL_USE_CONCEPT_CHECK here
namespace boost { namespace gil {
// TODO: What is BOOST_GIL_CLASS_REQUIRE for; Why not use BOOST_CLASS_REQUIRE?
// TODO: What is gil_function_requires for; Why not function_requires?
#ifdef BOOST_GIL_USE_CONCEPT_CHECK
#define BOOST_GIL_CLASS_REQUIRE(type_var, ns, concept) \
BOOST_CLASS_REQUIRE(type_var, ns, concept);
template <typename Concept>
void gil_function_requires() { function_requires<Concept>(); }
#else
#define BOOST_GIL_CLASS_REQUIRE(type_var, ns, concept)
template <typename C>
void gil_function_requires() {}
#endif
}} // namespace boost::gil:
#endif

View File

@@ -0,0 +1,24 @@
//
// 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_CONCEPTS_DETAIL_TYPE_TRAITS_HPP
#define BOOST_GIL_CONCEPTS_DETAIL_TYPE_TRAITS_HPP
#include <type_traits>
namespace boost { namespace gil { namespace detail {
// TODO: C++20: deprecate and replace with std::std_remove_cvref
template <typename T>
struct remove_const_and_reference
: std::remove_const<typename std::remove_reference<T>::type>
{
};
}}} // namespace boost::gil::detail
#endif

View File

@@ -0,0 +1,19 @@
//
// 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_CONCEPTS_DETAIL_UTILITY_HPP
#define BOOST_GIL_CONCEPTS_DETAIL_UTILITY_HPP
namespace boost { namespace gil { namespace detail {
// TODO: Remove, replace with ignore_unised?
template <typename T>
void initialize_it(T&) {}
}}} // namespace boost::gil::detail
#endif

View File

@@ -0,0 +1,78 @@
//
// 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_CONCEPTS_DYNAMIC_STEP_HPP
#define BOOST_GIL_CONCEPTS_DYNAMIC_STEP_HPP
#include <boost/gil/concepts/fwd.hpp>
#include <boost/gil/concepts/concept_check.hpp>
#if defined(BOOST_CLANG)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunknown-pragmas"
#pragma clang diagnostic ignored "-Wunused-local-typedefs"
#endif
#if defined(BOOST_GCC) && (BOOST_GCC >= 40900)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#endif
namespace boost { namespace gil {
/// \ingroup PixelIteratorConcept
/// \brief Concept for iterators, locators and views that can define a type just like the given
/// iterator, locator or view, except it supports runtime specified step along the X navigation.
///
/// \code
/// concept HasDynamicXStepTypeConcept<typename T>
/// {
/// typename dynamic_x_step_type<T>;
/// where Metafunction<dynamic_x_step_type<T> >;
/// };
/// \endcode
template <typename T>
struct HasDynamicXStepTypeConcept
{
void constraints()
{
using type = typename dynamic_x_step_type<T>::type;
ignore_unused_variable_warning(type{});
}
};
/// \ingroup PixelLocatorConcept
/// \brief Concept for locators and views that can define a type just like the given locator or view,
/// except it supports runtime specified step along the Y navigation
/// \code
/// concept HasDynamicYStepTypeConcept<typename T>
/// {
/// typename dynamic_y_step_type<T>;
/// where Metafunction<dynamic_y_step_type<T> >;
/// };
/// \endcode
template <typename T>
struct HasDynamicYStepTypeConcept
{
void constraints()
{
using type = typename dynamic_y_step_type<T>::type;
ignore_unused_variable_warning(type{});
}
};
}} // namespace boost::gil
#if defined(BOOST_CLANG)
#pragma clang diagnostic pop
#endif
#if defined(BOOST_GCC) && (BOOST_GCC >= 40900)
#pragma GCC diagnostic pop
#endif
#endif

View File

@@ -0,0 +1,36 @@
//
// 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_CONCEPTS_FWD_HPP
#define BOOST_GIL_CONCEPTS_FWD_HPP
namespace boost { namespace gil {
// Forward declarations used by concepts
template <typename ColorBase, int K> struct kth_element_type;
template <typename ColorBase, int K> struct kth_element_reference_type;
template <typename ColorBase, int K> struct kth_element_const_reference_type;
template <typename ColorBase, int K> struct kth_semantic_element_reference_type;
template <typename ColorBase, int K> struct kth_semantic_element_const_reference_type;
template <typename ColorBase> struct size;
template <typename ColorBase> struct element_type;
template <typename T> struct is_pixel;
template <typename T> struct is_planar;
template <typename T> struct channel_type;
template <typename T> struct color_space_type;
template <typename T> struct channel_mapping_type;
template <typename T> struct num_channels;
template <typename T> struct dynamic_x_step_type;
template <typename T> struct dynamic_y_step_type;
template <typename T> struct transposed_type;
}} // namespace boost::gil
#endif

View File

@@ -0,0 +1,169 @@
//
// 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_CONCEPTS_IMAGE_HPP
#define BOOST_GIL_CONCEPTS_IMAGE_HPP
#include <boost/gil/concepts/basic.hpp>
#include <boost/gil/concepts/concept_check.hpp>
#include <boost/gil/concepts/fwd.hpp>
#include <boost/gil/concepts/image_view.hpp>
#include <boost/gil/concepts/point.hpp>
#include <boost/gil/detail/mp11.hpp>
#include <type_traits>
#if defined(BOOST_CLANG)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunknown-pragmas"
#pragma clang diagnostic ignored "-Wunused-local-typedefs"
#endif
#if defined(BOOST_GCC) && (BOOST_GCC >= 40900)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#endif
namespace boost { namespace gil {
/// \ingroup ImageConcept
/// \brief N-dimensional container of values
///
/// \code
/// concept RandomAccessNDImageConcept<typename Image> : Regular<Image>
/// {
/// typename view_t; where MutableRandomAccessNDImageViewConcept<view_t>;
/// typename const_view_t = view_t::const_t;
/// typename point_t = view_t::point_t;
/// typename value_type = view_t::value_type;
/// typename allocator_type;
///
/// Image::Image(point_t dims, std::size_t alignment=1);
/// Image::Image(point_t dims, value_type fill_value, std::size_t alignment);
///
/// void Image::recreate(point_t new_dims, std::size_t alignment=1);
/// void Image::recreate(point_t new_dims, value_type fill_value, std::size_t alignment);
///
/// const point_t& Image::dimensions() const;
/// const const_view_t& const_view(const Image&);
/// const view_t& view(Image&);
/// };
/// \endcode
template <typename Image>
struct RandomAccessNDImageConcept
{
void constraints()
{
gil_function_requires<Regular<Image>>();
using view_t = typename Image::view_t;
gil_function_requires<MutableRandomAccessNDImageViewConcept<view_t>>();
using const_view_t = typename Image::const_view_t;
using pixel_t = typename Image::value_type;
using point_t = typename Image::point_t;
gil_function_requires<PointNDConcept<point_t>>();
const_view_t cv = const_view(image);
ignore_unused_variable_warning(cv);
view_t v = view(image);
ignore_unused_variable_warning(v);
pixel_t fill_value;
point_t pt = image.dimensions();
Image image1(pt);
Image image2(pt, 1);
Image image3(pt, fill_value, 1);
image.recreate(pt);
image.recreate(pt, 1);
image.recreate(pt, fill_value, 1);
}
Image image;
};
/// \ingroup ImageConcept
/// \brief 2-dimensional container of values
///
/// \code
/// concept RandomAccess2DImageConcept<RandomAccessNDImageConcept Image>
/// {
/// typename x_coord_t = const_view_t::x_coord_t;
/// typename y_coord_t = const_view_t::y_coord_t;
///
/// Image::Image(x_coord_t width, y_coord_t height, std::size_t alignment=1);
/// Image::Image(x_coord_t width, y_coord_t height, value_type fill_value, std::size_t alignment);
///
/// x_coord_t Image::width() const;
/// y_coord_t Image::height() const;
///
/// void Image::recreate(x_coord_t width, y_coord_t height, std::size_t alignment=1);
/// void Image::recreate(x_coord_t width, y_coord_t height, value_type fill_value, std::size_t alignment);
/// };
/// \endcode
template <typename Image>
struct RandomAccess2DImageConcept
{
void constraints()
{
gil_function_requires<RandomAccessNDImageConcept<Image>>();
using x_coord_t = typename Image::x_coord_t;
using y_coord_t = typename Image::y_coord_t;
using value_t = typename Image::value_type;
gil_function_requires<MutableRandomAccess2DImageViewConcept<typename Image::view_t>>();
x_coord_t w=image.width();
y_coord_t h=image.height();
value_t fill_value;
Image im1(w,h);
Image im2(w,h,1);
Image im3(w,h,fill_value,1);
image.recreate(w,h);
image.recreate(w,h,1);
image.recreate(w,h,fill_value,1);
}
Image image;
};
/// \ingroup ImageConcept
/// \brief 2-dimensional image whose value type models PixelValueConcept
///
/// \code
/// concept ImageConcept<RandomAccess2DImageConcept Image>
/// {
/// where MutableImageViewConcept<view_t>;
/// typename coord_t = view_t::coord_t;
/// };
/// \endcode
template <typename Image>
struct ImageConcept
{
void constraints()
{
gil_function_requires<RandomAccess2DImageConcept<Image>>();
gil_function_requires<MutableImageViewConcept<typename Image::view_t>>();
using coord_t = typename Image::coord_t;
static_assert(num_channels<Image>::value == mp11::mp_size<typename color_space_type<Image>::type>::value, "");
static_assert(std::is_same<coord_t, typename Image::x_coord_t>::value, "");
static_assert(std::is_same<coord_t, typename Image::y_coord_t>::value, "");
}
Image image;
};
}} // namespace boost::gil
#if defined(BOOST_CLANG)
#pragma clang diagnostic pop
#endif
#if defined(BOOST_GCC) && (BOOST_GCC >= 40900)
#pragma GCC diagnostic pop
#endif
#endif

View File

@@ -0,0 +1,557 @@
//
// 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_CONCEPTS_IMAGE_VIEW_HPP
#define BOOST_GIL_CONCEPTS_IMAGE_VIEW_HPP
#include <boost/gil/concepts/basic.hpp>
#include <boost/gil/concepts/concept_check.hpp>
#include <boost/gil/concepts/fwd.hpp>
#include <boost/gil/concepts/pixel.hpp>
#include <boost/gil/concepts/pixel_dereference.hpp>
#include <boost/gil/concepts/pixel_iterator.hpp>
#include <boost/gil/concepts/pixel_locator.hpp>
#include <boost/gil/concepts/point.hpp>
#include <boost/gil/concepts/detail/utility.hpp>
#include <cstddef>
#include <iterator>
#include <type_traits>
#if defined(BOOST_CLANG)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunknown-pragmas"
#pragma clang diagnostic ignored "-Wunused-local-typedefs"
#endif
#if defined(BOOST_GCC) && (BOOST_GCC >= 40900)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
#endif
namespace boost { namespace gil {
/// \defgroup ImageViewNDConcept ImageViewNDLocatorConcept
/// \ingroup ImageViewConcept
/// \brief N-dimensional range
/// \defgroup ImageView2DConcept ImageView2DLocatorConcept
/// \ingroup ImageViewConcept
/// \brief 2-dimensional range
/// \defgroup PixelImageViewConcept ImageViewConcept
/// \ingroup ImageViewConcept
/// \brief 2-dimensional range over pixel data
/// \ingroup ImageViewNDConcept
/// \brief N-dimensional view over immutable values
///
/// \code
/// concept RandomAccessNDImageViewConcept<Regular View>
/// {
/// typename value_type;
/// typename reference; // result of dereferencing
/// typename difference_type; // result of operator-(iterator,iterator) (1-dimensional!)
/// typename const_t; where RandomAccessNDImageViewConcept<View>; // same as View, but over immutable values
/// typename point_t; where PointNDConcept<point_t>; // N-dimensional point
/// typename locator; where RandomAccessNDLocatorConcept<locator>; // N-dimensional locator.
/// typename iterator; where RandomAccessTraversalConcept<iterator>; // 1-dimensional iterator over all values
/// typename reverse_iterator; where RandomAccessTraversalConcept<reverse_iterator>;
/// typename size_type; // the return value of size()
///
/// // Equivalent to RandomAccessNDLocatorConcept::axis
/// template <size_t D> struct axis {
/// typename coord_t = point_t::axis<D>::coord_t;
/// typename iterator; where RandomAccessTraversalConcept<iterator>; // iterator along D-th axis.
/// where SameType<coord_t, iterator::difference_type>;
/// where SameType<iterator::value_type,value_type>;
/// };
///
/// // Defines the type of a view similar to this type, except it invokes Deref upon dereferencing
/// template <PixelDereferenceAdaptorConcept Deref> struct add_deref {
/// typename type; where RandomAccessNDImageViewConcept<type>;
/// static type make(const View& v, const Deref& deref);
/// };
///
/// static const size_t num_dimensions = point_t::num_dimensions;
///
/// // Create from a locator at the top-left corner and dimensions
/// View::View(const locator&, const point_type&);
///
/// size_type View::size() const; // total number of elements
/// reference operator[](View, const difference_type&) const; // 1-dimensional reference
/// iterator View::begin() const;
/// iterator View::end() const;
/// reverse_iterator View::rbegin() const;
/// reverse_iterator View::rend() const;
/// iterator View::at(const point_t&);
/// point_t View::dimensions() const; // number of elements along each dimension
/// bool View::is_1d_traversable() const; // can an iterator over the first dimension visit each value? I.e. are there gaps between values?
///
/// // iterator along a given dimension starting at a given point
/// template <size_t D> View::axis<D>::iterator View::axis_iterator(const point_t&) const;
///
/// reference operator()(View,const point_t&) const;
/// };
/// \endcode
template <typename View>
struct RandomAccessNDImageViewConcept
{
void constraints()
{
gil_function_requires<Regular<View>>();
using value_type = typename View::value_type;
using reference = typename View::reference; // result of dereferencing
using pointer = typename View::pointer;
using difference_type = typename View::difference_type; // result of operator-(1d_iterator,1d_iterator)
using const_t = typename View::const_t; // same as this type, but over const values
using point_t = typename View::point_t; // N-dimensional point
using locator = typename View::locator; // N-dimensional locator
using iterator = typename View::iterator;
using const_iterator = typename View::const_iterator;
using reverse_iterator = typename View::reverse_iterator;
using size_type = typename View::size_type;
static const std::size_t N=View::num_dimensions;
gil_function_requires<RandomAccessNDLocatorConcept<locator>>();
gil_function_requires<boost_concepts::RandomAccessTraversalConcept<iterator>>();
gil_function_requires<boost_concepts::RandomAccessTraversalConcept<reverse_iterator>>();
using first_it_type = typename View::template axis<0>::iterator;
using last_it_type = typename View::template axis<N-1>::iterator;
gil_function_requires<boost_concepts::RandomAccessTraversalConcept<first_it_type>>();
gil_function_requires<boost_concepts::RandomAccessTraversalConcept<last_it_type>>();
// static_assert(typename std::iterator_traits<first_it_type>::difference_type, typename point_t::template axis<0>::coord_t>::value, "");
// static_assert(typename std::iterator_traits<last_it_type>::difference_type, typename point_t::template axis<N-1>::coord_t>::value, "");
// point_t must be an N-dimensional point, each dimension of which must have the same type as difference_type of the corresponding iterator
gil_function_requires<PointNDConcept<point_t>>();
static_assert(point_t::num_dimensions == N, "");
static_assert(std::is_same
<
typename std::iterator_traits<first_it_type>::difference_type,
typename point_t::template axis<0>::coord_t
>::value, "");
static_assert(std::is_same
<
typename std::iterator_traits<last_it_type>::difference_type,
typename point_t::template axis<N-1>::coord_t
>::value, "");
point_t p;
locator lc;
iterator it;
reverse_iterator rit;
difference_type d; detail::initialize_it(d); ignore_unused_variable_warning(d);
View(p,lc); // view must be constructible from a locator and a point
p = view.dimensions();
lc = view.pixels();
size_type sz = view.size(); ignore_unused_variable_warning(sz);
bool is_contiguous = view.is_1d_traversable();
ignore_unused_variable_warning(is_contiguous);
it = view.begin();
it = view.end();
rit = view.rbegin();
rit = view.rend();
reference r1 = view[d]; ignore_unused_variable_warning(r1); // 1D access
reference r2 = view(p); ignore_unused_variable_warning(r2); // 2D access
// get 1-D iterator of any dimension at a given pixel location
first_it_type fi = view.template axis_iterator<0>(p);
ignore_unused_variable_warning(fi);
last_it_type li = view.template axis_iterator<N-1>(p);
ignore_unused_variable_warning(li);
using deref_t = PixelDereferenceAdaptorArchetype<typename View::value_type>;
using dtype = typename View::template add_deref<deref_t>::type;
}
View view;
};
/// \ingroup ImageView2DConcept
/// \brief 2-dimensional view over immutable values
///
/// \code
/// concept RandomAccess2DImageViewConcept<RandomAccessNDImageViewConcept View> {
/// where num_dimensions==2;
///
/// typename x_iterator = axis<0>::iterator;
/// typename y_iterator = axis<1>::iterator;
/// typename x_coord_t = axis<0>::coord_t;
/// typename y_coord_t = axis<1>::coord_t;
/// typename xy_locator = locator;
///
/// x_coord_t View::width() const;
/// y_coord_t View::height() const;
///
/// // X-navigation
/// x_iterator View::x_at(const point_t&) const;
/// x_iterator View::row_begin(y_coord_t) const;
/// x_iterator View::row_end (y_coord_t) const;
///
/// // Y-navigation
/// y_iterator View::y_at(const point_t&) const;
/// y_iterator View::col_begin(x_coord_t) const;
/// y_iterator View::col_end (x_coord_t) const;
///
/// // navigating in 2D
/// xy_locator View::xy_at(const point_t&) const;
///
/// // (x,y) versions of all methods taking point_t
/// View::View(x_coord_t,y_coord_t,const locator&);
/// iterator View::at(x_coord_t,y_coord_t) const;
/// reference operator()(View,x_coord_t,y_coord_t) const;
/// xy_locator View::xy_at(x_coord_t,y_coord_t) const;
/// x_iterator View::x_at(x_coord_t,y_coord_t) const;
/// y_iterator View::y_at(x_coord_t,y_coord_t) const;
/// };
/// \endcode
template <typename View>
struct RandomAccess2DImageViewConcept
{
void constraints()
{
gil_function_requires<RandomAccessNDImageViewConcept<View>>();
static_assert(View::num_dimensions == 2, "");
// TODO: This executes the requirements for RandomAccessNDLocatorConcept again. Fix it to improve compile time
gil_function_requires<RandomAccess2DLocatorConcept<typename View::locator>>();
using dynamic_x_step_t = typename dynamic_x_step_type<View>::type;
using dynamic_y_step_t = typename dynamic_y_step_type<View>::type;
using transposed_t = typename transposed_type<View>::type;
using x_iterator = typename View::x_iterator;
using y_iterator = typename View::y_iterator;
using x_coord_t = typename View::x_coord_t;
using y_coord_t = typename View::y_coord_t;
using xy_locator = typename View::xy_locator;
x_coord_t xd = 0; ignore_unused_variable_warning(xd);
y_coord_t yd = 0; ignore_unused_variable_warning(yd);
x_iterator xit;
y_iterator yit;
typename View::point_t d;
View(xd, yd, xy_locator()); // constructible with width, height, 2d_locator
xy_locator lc = view.xy_at(xd, yd);
lc = view.xy_at(d);
typename View::reference r = view(xd, yd);
ignore_unused_variable_warning(r);
xd = view.width();
yd = view.height();
xit = view.x_at(d);
xit = view.x_at(xd,yd);
xit = view.row_begin(xd);
xit = view.row_end(xd);
yit = view.y_at(d);
yit = view.y_at(xd,yd);
yit = view.col_begin(xd);
yit = view.col_end(xd);
}
View view;
};
/// \brief GIL view as Collection.
///
/// \see https://www.boost.org/libs/utility/Collection.html
///
template <typename View>
struct CollectionImageViewConcept
{
void constraints()
{
using value_type = typename View::value_type;
using iterator = typename View::iterator;
using const_iterator = typename View::const_iterator;
using reference = typename View::reference;
using const_reference = typename View::const_reference;
using pointer = typename View::pointer;
using difference_type = typename View::difference_type;
using size_type= typename View::size_type;
iterator i;
i = view1.begin();
i = view2.end();
const_iterator ci;
ci = view1.begin();
ci = view2.end();
size_type s;
s = view1.size();
s = view2.size();
ignore_unused_variable_warning(s);
view1.empty();
view1.swap(view2);
}
View view1;
View view2;
};
/// \brief GIL view as ForwardCollection.
///
/// \see https://www.boost.org/libs/utility/Collection.html
///
template <typename View>
struct ForwardCollectionImageViewConcept
{
void constraints()
{
gil_function_requires<CollectionImageViewConcept<View>>();
using reference = typename View::reference;
using const_reference = typename View::const_reference;
reference r = view.front();
ignore_unused_variable_warning(r);
const_reference cr = view.front();
ignore_unused_variable_warning(cr);
}
View view;
};
/// \brief GIL view as ReversibleCollection.
///
/// \see https://www.boost.org/libs/utility/Collection.html
///
template <typename View>
struct ReversibleCollectionImageViewConcept
{
void constraints()
{
gil_function_requires<CollectionImageViewConcept<View>>();
using reverse_iterator = typename View::reverse_iterator;
using reference = typename View::reference;
using const_reference = typename View::const_reference;
reverse_iterator i;
i = view.rbegin();
i = view.rend();
reference r = view.back();
ignore_unused_variable_warning(r);
const_reference cr = view.back();
ignore_unused_variable_warning(cr);
}
View view;
};
/// \ingroup PixelImageViewConcept
/// \brief GIL's 2-dimensional view over immutable GIL pixels
/// \code
/// concept ImageViewConcept<RandomAccess2DImageViewConcept View>
/// {
/// where PixelValueConcept<value_type>;
/// where PixelIteratorConcept<x_iterator>;
/// where PixelIteratorConcept<y_iterator>;
/// where x_coord_t == y_coord_t;
///
/// typename coord_t = x_coord_t;
///
/// std::size_t View::num_channels() const;
/// };
/// \endcode
template <typename View>
struct ImageViewConcept
{
void constraints()
{
gil_function_requires<RandomAccess2DImageViewConcept<View>>();
// TODO: This executes the requirements for RandomAccess2DLocatorConcept again. Fix it to improve compile time
gil_function_requires<PixelLocatorConcept<typename View::xy_locator>>();
static_assert(std::is_same<typename View::x_coord_t, typename View::y_coord_t>::value, "");
using coord_t = typename View::coord_t; // 1D difference type (same for all dimensions)
std::size_t num_chan = view.num_channels(); ignore_unused_variable_warning(num_chan);
}
View view;
};
namespace detail {
/// \tparam View Models RandomAccessNDImageViewConcept
template <typename View>
struct RandomAccessNDImageViewIsMutableConcept
{
void constraints()
{
gil_function_requires<detail::RandomAccessNDLocatorIsMutableConcept<typename View::locator>>();
gil_function_requires<detail::RandomAccessIteratorIsMutableConcept<typename View::iterator>>();
gil_function_requires<detail::RandomAccessIteratorIsMutableConcept
<
typename View::reverse_iterator
>>();
gil_function_requires<detail::RandomAccessIteratorIsMutableConcept
<
typename View::template axis<0>::iterator
>>();
gil_function_requires<detail::RandomAccessIteratorIsMutableConcept
<
typename View::template axis<View::num_dimensions - 1>::iterator
>>();
typename View::difference_type diff;
initialize_it(diff);
ignore_unused_variable_warning(diff);
typename View::point_t pt;
typename View::value_type v;
initialize_it(v);
view[diff] = v;
view(pt) = v;
}
View view;
};
/// \tparam View Models RandomAccessNDImageViewConcept
template <typename View>
struct RandomAccess2DImageViewIsMutableConcept
{
void constraints()
{
gil_function_requires<detail::RandomAccessNDImageViewIsMutableConcept<View>>();
typename View::x_coord_t xd = 0; ignore_unused_variable_warning(xd);
typename View::y_coord_t yd = 0; ignore_unused_variable_warning(yd);
typename View::value_type v; initialize_it(v);
view(xd, yd) = v;
}
View view;
};
/// \tparam View Models ImageViewConcept
template <typename View>
struct PixelImageViewIsMutableConcept
{
void constraints()
{
gil_function_requires<detail::RandomAccess2DImageViewIsMutableConcept<View>>();
}
};
} // namespace detail
/// \ingroup ImageViewNDConcept
/// \brief N-dimensional view over mutable values
///
/// \code
/// concept MutableRandomAccessNDImageViewConcept<RandomAccessNDImageViewConcept View>
/// {
/// where Mutable<reference>;
/// };
/// \endcode
template <typename View>
struct MutableRandomAccessNDImageViewConcept
{
void constraints()
{
gil_function_requires<RandomAccessNDImageViewConcept<View>>();
gil_function_requires<detail::RandomAccessNDImageViewIsMutableConcept<View>>();
}
};
/// \ingroup ImageView2DConcept
/// \brief 2-dimensional view over mutable values
///
/// \code
/// concept MutableRandomAccess2DImageViewConcept<RandomAccess2DImageViewConcept View>
/// : MutableRandomAccessNDImageViewConcept<View> {};
/// \endcode
template <typename View>
struct MutableRandomAccess2DImageViewConcept
{
void constraints()
{
gil_function_requires<RandomAccess2DImageViewConcept<View>>();
gil_function_requires<detail::RandomAccess2DImageViewIsMutableConcept<View>>();
}
};
/// \ingroup PixelImageViewConcept
/// \brief GIL's 2-dimensional view over mutable GIL pixels
///
/// \code
/// concept MutableImageViewConcept<ImageViewConcept View>
/// : MutableRandomAccess2DImageViewConcept<View> {};
/// \endcode
template <typename View>
struct MutableImageViewConcept
{
void constraints()
{
gil_function_requires<ImageViewConcept<View>>();
gil_function_requires<detail::PixelImageViewIsMutableConcept<View>>();
}
};
/// \brief Returns whether two views are compatible
///
/// Views are compatible if their pixels are compatible.
/// Compatible views can be assigned and copy constructed from one another.
///
/// \tparam V1 Models ImageViewConcept
/// \tparam V2 Models ImageViewConcept
///
template <typename V1, typename V2>
struct views_are_compatible
: pixels_are_compatible<typename V1::value_type, typename V2::value_type>
{
};
/// \ingroup ImageViewConcept
/// \brief Views are compatible if they have the same color spaces and compatible channel values.
///
/// Constness and layout are not important for compatibility.
///
/// \code
/// concept ViewsCompatibleConcept<ImageViewConcept V1, ImageViewConcept V2>
/// {
/// where PixelsCompatibleConcept<V1::value_type, P2::value_type>;
/// };
/// \endcode
template <typename V1, typename V2>
struct ViewsCompatibleConcept
{
void constraints()
{
static_assert(views_are_compatible<V1, V2>::value, "");
}
};
}} // namespace boost::gil
#if defined(BOOST_CLANG)
#pragma clang diagnostic pop
#endif
#if defined(BOOST_GCC) && (BOOST_GCC >= 40900)
#pragma GCC diagnostic pop
#endif
#endif

View File

@@ -0,0 +1,299 @@
//
// 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_CONCEPTS_PIXEL_HPP
#define BOOST_GIL_CONCEPTS_PIXEL_HPP
#include <boost/gil/concepts/basic.hpp>
#include <boost/gil/concepts/channel.hpp>
#include <boost/gil/concepts/color.hpp>
#include <boost/gil/concepts/color_base.hpp>
#include <boost/gil/concepts/concept_check.hpp>
#include <boost/gil/concepts/fwd.hpp>
#include <boost/gil/concepts/pixel_based.hpp>
#include <boost/gil/concepts/detail/type_traits.hpp>
#include <boost/gil/detail/mp11.hpp>
#include <cstddef>
#include <type_traits>
#if defined(BOOST_CLANG)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunknown-pragmas"
#pragma clang diagnostic ignored "-Wunused-local-typedefs"
#endif
#if defined(BOOST_GCC) && (BOOST_GCC >= 40900)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#endif
namespace boost { namespace gil {
/// \brief Pixel concept - A color base whose elements are channels
/// \ingroup PixelConcept
/// \code
/// concept PixelConcept<typename P> : ColorBaseConcept<P>, PixelBasedConcept<P>
/// {
/// where is_pixel<P>::value == true;
/// // where for each K [0..size<P>::value - 1]:
/// // ChannelConcept<kth_element_type<P, K>>;
///
/// typename P::value_type;
/// where PixelValueConcept<value_type>;
/// typename P::reference;
/// where PixelConcept<reference>;
/// typename P::const_reference;
/// where PixelConcept<const_reference>;
/// static const bool P::is_mutable;
///
/// template <PixelConcept P2> where { PixelConcept<P, P2> }
/// P::P(P2);
/// template <PixelConcept P2> where { PixelConcept<P, P2> }
/// bool operator==(const P&, const P2&);
/// template <PixelConcept P2> where { PixelConcept<P, P2> }
/// bool operator!=(const P&, const P2&);
/// };
/// \endcode
template <typename P>
struct PixelConcept
{
void constraints()
{
gil_function_requires<ColorBaseConcept<P>>();
gil_function_requires<PixelBasedConcept<P>>();
static_assert(is_pixel<P>::value, "");
static const bool is_mutable = P::is_mutable;
ignore_unused_variable_warning(is_mutable);
using value_type = typename P::value_type;
// TODO: Is the cyclic dependency intentional? --mloskot
// gil_function_requires<PixelValueConcept<value_type>>();
using reference = typename P::reference;
gil_function_requires<PixelConcept
<
typename detail::remove_const_and_reference<reference>::type
>>();
using const_reference = typename P::const_reference;
gil_function_requires<PixelConcept
<
typename detail::remove_const_and_reference<const_reference>::type
>>();
}
};
/// \brief Pixel concept that allows for changing its channels
/// \ingroup PixelConcept
/// \code
/// concept MutablePixelConcept<PixelConcept P> : MutableColorBaseConcept<P>
/// {
/// where is_mutable==true;
/// };
/// \endcode
template <typename P>
struct MutablePixelConcept
{
void constraints()
{
gil_function_requires<PixelConcept<P>>();
static_assert(P::is_mutable, "");
}
};
/// \brief Homogeneous pixel concept
/// \ingroup PixelConcept
/// \code
/// concept HomogeneousPixelConcept<PixelConcept P>
/// : HomogeneousColorBaseConcept<P>, HomogeneousPixelBasedConcept<P>
/// {
/// P::template element_const_reference_type<P>::type operator[](P p, std::size_t i) const
/// {
/// return dynamic_at_c(p,i);
/// }
/// };
/// \endcode
template <typename P>
struct HomogeneousPixelConcept
{
void constraints()
{
gil_function_requires<PixelConcept<P>>();
gil_function_requires<HomogeneousColorBaseConcept<P>>();
gil_function_requires<HomogeneousPixelBasedConcept<P>>();
p[0];
}
P p;
};
/// \brief Homogeneous pixel concept that allows for changing its channels
/// \ingroup PixelConcept
/// \code
/// concept MutableHomogeneousPixelConcept<HomogeneousPixelConcept P>
/// : MutableHomogeneousColorBaseConcept<P>
/// {
/// P::template element_reference_type<P>::type operator[](P p, std::size_t i)
/// {
/// return dynamic_at_c(p, i);
/// }
/// };
/// \endcode
template <typename P>
struct MutableHomogeneousPixelConcept
{
void constraints()
{
gil_function_requires<HomogeneousPixelConcept<P>>();
gil_function_requires<MutableHomogeneousColorBaseConcept<P>>();
p[0] = v;
v = p[0];
}
typename P::template element_type<P>::type v;
P p;
};
/// \brief Pixel concept that is a Regular type
/// \ingroup PixelConcept
/// \code
/// concept PixelValueConcept<PixelConcept P> : Regular<P>
/// {
/// where SameType<value_type,P>;
/// };
/// \endcode
template <typename P>
struct PixelValueConcept
{
void constraints()
{
gil_function_requires<PixelConcept<P>>();
gil_function_requires<Regular<P>>();
}
};
/// \brief Homogeneous pixel concept that is a Regular type
/// \ingroup PixelConcept
/// \code
/// concept HomogeneousPixelValueConcept<HomogeneousPixelConcept P> : Regular<P>
/// {
/// where SameType<value_type,P>;
/// };
/// \endcode
template <typename P>
struct HomogeneousPixelValueConcept
{
void constraints()
{
gil_function_requires<HomogeneousPixelConcept<P>>();
gil_function_requires<Regular<P>>();
static_assert(std::is_same<P, typename P::value_type>::value, "");
}
};
namespace detail {
template <typename P1, typename P2, int K>
struct channels_are_pairwise_compatible
: mp11::mp_and
<
channels_are_pairwise_compatible<P1, P2, K - 1>,
channels_are_compatible
<
typename kth_semantic_element_reference_type<P1, K>::type,
typename kth_semantic_element_reference_type<P2, K>::type
>
>
{
};
template <typename P1, typename P2>
struct channels_are_pairwise_compatible<P1, P2, -1> : std::true_type {};
} // namespace detail
/// \ingroup PixelAlgorithm
/// \brief Returns whether two pixels are compatible
/// Pixels are compatible if their channels and color space types are compatible.
/// Compatible pixels can be assigned and copy constructed from one another.
/// \tparam P1 Models PixelConcept
/// \tparam P2 Models PixelConcept
template <typename P1, typename P2>
struct pixels_are_compatible
: mp11::mp_and
<
typename color_spaces_are_compatible
<
typename color_space_type<P1>::type,
typename color_space_type<P2>::type
>::type,
detail::channels_are_pairwise_compatible
<
P1, P2, num_channels<P1>::value - 1
>
>
{
};
/// \ingroup PixelConcept
/// \brief Concept for pixel compatibility
/// Pixels are compatible if their channels and color space types are compatible.
/// Compatible pixels can be assigned and copy constructed from one another.
/// \tparam P1 Models PixelConcept
/// \tparam P2 Models PixelConcept
/// \code
/// concept PixelsCompatibleConcept<PixelConcept P1, PixelConcept P2>
/// : ColorBasesCompatibleConcept<P1,P2> {
/// // where for each K [0..size<P1>::value):
/// // ChannelsCompatibleConcept<kth_semantic_element_type<P1,K>::type, kth_semantic_element_type<P2,K>::type>;
/// };
/// \endcode
template <typename P1, typename P2>
struct PixelsCompatibleConcept
{
void constraints()
{
static_assert(pixels_are_compatible<P1, P2>::value, "");
}
};
/// \ingroup PixelConcept
/// \brief Pixel convertible concept
/// Convertibility is non-symmetric and implies that one pixel
/// can be converted to another, approximating the color.
/// Conversion is explicit and sometimes lossy.
/// \code
/// template <PixelConcept SrcPixel, MutablePixelConcept DstPixel>
/// concept PixelConvertibleConcept
/// {
/// void color_convert(const SrcPixel&, DstPixel&);
/// };
/// \endcode
template <typename SrcP, typename DstP>
struct PixelConvertibleConcept
{
void constraints()
{
gil_function_requires<PixelConcept<SrcP>>();
gil_function_requires<MutablePixelConcept<DstP>>();
color_convert(src, dst);
}
SrcP src;
DstP dst;
};
}} // namespace boost::gil
#if defined(BOOST_CLANG)
#pragma clang diagnostic pop
#endif
#if defined(BOOST_GCC) && (BOOST_GCC >= 40900)
#pragma GCC diagnostic pop
#endif
#endif

View File

@@ -0,0 +1,104 @@
//
// 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_CONCEPTS_PIXEL_BASED_HPP
#define BOOST_GIL_CONCEPTS_PIXEL_BASED_HPP
#include <boost/gil/concepts/basic.hpp>
#include <boost/gil/concepts/channel.hpp>
#include <boost/gil/concepts/color.hpp>
#include <boost/gil/concepts/concept_check.hpp>
#include <boost/gil/concepts/fwd.hpp>
#include <cstddef>
#if defined(BOOST_CLANG)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunknown-pragmas"
#pragma clang diagnostic ignored "-Wunused-local-typedefs"
#endif
#if defined(BOOST_GCC) && (BOOST_GCC >= 40900)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#endif
namespace boost { namespace gil {
/// \ingroup PixelBasedConcept
/// \brief Concept for all pixel-based GIL constructs.
///
/// Pixel-based constructs include pixels, iterators, locators, views and
/// images whose value type is a pixel.
///
/// \code
/// concept PixelBasedConcept<typename T>
/// {
/// typename color_space_type<T>;
/// where Metafunction<color_space_type<T> >;
/// where ColorSpaceConcept<color_space_type<T>::type>;
/// typename channel_mapping_type<T>;
/// where Metafunction<channel_mapping_type<T> >;
/// where ChannelMappingConcept<channel_mapping_type<T>::type>;
/// typename is_planar<T>;
/// where Metafunction<is_planar<T> >;
/// where SameType<is_planar<T>::type, bool>;
/// };
/// \endcode
template <typename P>
struct PixelBasedConcept
{
void constraints()
{
using color_space_t = typename color_space_type<P>::type;
gil_function_requires<ColorSpaceConcept<color_space_t>>();
using channel_mapping_t = typename channel_mapping_type<P>::type ;
gil_function_requires<ChannelMappingConcept<channel_mapping_t>>();
static const bool planar = is_planar<P>::value;
ignore_unused_variable_warning(planar);
// This is not part of the concept, but should still work
static const std::size_t nc = num_channels<P>::value;
ignore_unused_variable_warning(nc);
}
};
/// \brief Concept for homogeneous pixel-based GIL constructs
/// \ingroup PixelBasedConcept
/// \code
/// concept HomogeneousPixelBasedConcept<PixelBasedConcept T>
/// {
/// typename channel_type<T>;
/// where Metafunction<channel_type<T>>;
/// where ChannelConcept<channel_type<T>::type>;
/// };
/// \endcode
template <typename P>
struct HomogeneousPixelBasedConcept
{
void constraints()
{
gil_function_requires<PixelBasedConcept<P>>();
using channel_t = typename channel_type<P>::type;
gil_function_requires<ChannelConcept<channel_t>>();
}
};
}} // namespace boost::gil
#if defined(BOOST_CLANG)
#pragma clang diagnostic pop
#endif
#if defined(BOOST_GCC) && (BOOST_GCC >= 40900)
#pragma GCC diagnostic pop
#endif
#endif

View File

@@ -0,0 +1,115 @@
//
// 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_CONCEPTS_PIXEL_DEREFERENCE_HPP
#define BOOST_GIL_CONCEPTS_PIXEL_DEREFERENCE_HPP
#include <boost/gil/concepts/basic.hpp>
#include <boost/gil/concepts/concept_check.hpp>
#include <boost/gil/concepts/fwd.hpp>
#include <boost/gil/concepts/pixel.hpp>
#include <boost/gil/concepts/detail/type_traits.hpp>
#include <boost/concept_check.hpp>
#include <cstddef>
#include <type_traits>
#if defined(BOOST_CLANG)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunknown-pragmas"
#pragma clang diagnostic ignored "-Wunused-local-typedefs"
#endif
#if defined(BOOST_GCC) && (BOOST_GCC >= 40900)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#endif
namespace boost { namespace gil {
/// \ingroup PixelDereferenceAdaptorConcept
/// \brief Represents a unary function object that can be invoked upon dereferencing a pixel iterator.
///
/// This can perform an arbitrary computation, such as color conversion or table lookup.
/// \code
/// concept PixelDereferenceAdaptorConcept<boost::UnaryFunctionConcept D>
/// : DefaultConstructibleConcept<D>, CopyConstructibleConcept<D>, AssignableConcept<D>
/// {
/// typename const_t; where PixelDereferenceAdaptorConcept<const_t>;
/// typename value_type; where PixelValueConcept<value_type>;
/// typename reference; // may be mutable
/// typename const_reference; // must not be mutable
/// static const bool D::is_mutable;
///
/// where Convertible<value_type,result_type>;
/// };
/// \endcode
template <typename D>
struct PixelDereferenceAdaptorConcept
{
void constraints()
{
gil_function_requires
<
boost::UnaryFunctionConcept
<
D,
typename detail::remove_const_and_reference<typename D::result_type>::type,
typename D::argument_type
>
>();
gil_function_requires<boost::DefaultConstructibleConcept<D>>();
gil_function_requires<boost::CopyConstructibleConcept<D>>();
gil_function_requires<boost::AssignableConcept<D>>();
gil_function_requires<PixelConcept
<
typename detail::remove_const_and_reference<typename D::result_type>::type
>>();
using const_t = typename D::const_t;
gil_function_requires<PixelDereferenceAdaptorConcept<const_t>>();
using value_type = typename D::value_type;
gil_function_requires<PixelValueConcept<value_type>>();
// TODO: Should this be concept-checked after "if you remove const and reference"? --mloskot
using reference = typename D::reference; // == PixelConcept (if you remove const and reference)
using const_reference = typename D::const_reference; // == PixelConcept (if you remove const and reference)
bool const is_mutable = D::is_mutable;
ignore_unused_variable_warning(is_mutable);
}
D d;
};
template <typename P>
struct PixelDereferenceAdaptorArchetype
{
using argument_type = P;
using result_type = P;
using const_t = PixelDereferenceAdaptorArchetype;
using value_type = typename std::remove_reference<P>::type;
using reference = typename std::add_lvalue_reference<P>::type;
using const_reference = reference;
static const bool is_mutable = false;
P operator()(P) const { throw; }
};
}} // namespace boost::gil
#if defined(BOOST_CLANG)
#pragma clang diagnostic pop
#endif
#if defined(BOOST_GCC) && (BOOST_GCC >= 40900)
#pragma GCC diagnostic pop
#endif
#endif

View File

@@ -0,0 +1,361 @@
//
// 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_CONCEPTS_PIXEL_ITERATOR_HPP
#define BOOST_GIL_CONCEPTS_PIXEL_ITERATOR_HPP
#include <boost/gil/concepts/channel.hpp>
#include <boost/gil/concepts/color.hpp>
#include <boost/gil/concepts/concept_check.hpp>
#include <boost/gil/concepts/fwd.hpp>
#include <boost/gil/concepts/pixel.hpp>
#include <boost/gil/concepts/pixel_based.hpp>
#include <boost/iterator/iterator_concepts.hpp>
#include <cstddef>
#include <iterator>
#include <type_traits>
#if defined(BOOST_CLANG)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunknown-pragmas"
#pragma clang diagnostic ignored "-Wunused-local-typedefs"
#endif
#if defined(BOOST_GCC) && (BOOST_GCC >= 40900)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#endif
namespace boost { namespace gil {
// Forward declarations
template <typename It> struct const_iterator_type;
template <typename It> struct iterator_is_mutable;
template <typename It> struct is_iterator_adaptor;
template <typename It, typename NewBaseIt> struct iterator_adaptor_rebind;
template <typename It> struct iterator_adaptor_get_base;
// These iterator mutability concepts are taken from Boost concept_check.hpp.
// Isolating mutability to result in faster compile time
namespace detail {
// Preconditions: TT Models boost_concepts::ForwardTraversalConcept
template <class TT>
struct ForwardIteratorIsMutableConcept
{
void constraints()
{
auto const tmp = *i;
*i++ = tmp; // require postincrement and assignment
}
TT i;
};
// Preconditions: TT Models boost::BidirectionalIteratorConcept
template <class TT>
struct BidirectionalIteratorIsMutableConcept
{
void constraints()
{
gil_function_requires< ForwardIteratorIsMutableConcept<TT>>();
auto const tmp = *i;
*i-- = tmp; // require postdecrement and assignment
}
TT i;
};
// Preconditions: TT Models boost_concepts::RandomAccessTraversalConcept
template <class TT>
struct RandomAccessIteratorIsMutableConcept
{
void constraints()
{
gil_function_requires<BidirectionalIteratorIsMutableConcept<TT>>();
typename std::iterator_traits<TT>::difference_type n = 0;
ignore_unused_variable_warning(n);
i[n] = *i; // require element access and assignment
}
TT i;
};
// Iterators that can be used as the base of memory_based_step_iterator require some additional functions
// \tparam Iterator Models boost_concepts::RandomAccessTraversalConcept
template <typename Iterator>
struct RandomAccessIteratorIsMemoryBasedConcept
{
void constraints()
{
std::ptrdiff_t bs = memunit_step(it);
ignore_unused_variable_warning(bs);
it = memunit_advanced(it, 3);
std::ptrdiff_t bd = memunit_distance(it, it);
ignore_unused_variable_warning(bd);
memunit_advance(it,3);
// for performace you may also provide a customized implementation of memunit_advanced_ref
}
Iterator it;
};
/// \tparam Iterator Models PixelIteratorConcept
template <typename Iterator>
struct PixelIteratorIsMutableConcept
{
void constraints()
{
gil_function_requires<detail::RandomAccessIteratorIsMutableConcept<Iterator>>();
using ref_t = typename std::remove_reference
<
typename std::iterator_traits<Iterator>::reference
>::type;
using channel_t = typename element_type<ref_t>::type;
gil_function_requires<detail::ChannelIsMutableConcept<channel_t>>();
}
};
} // namespace detail
/// \ingroup PixelLocatorConcept
/// \brief Concept for locators and views that can define a type just like the given locator or view, except X and Y is swapped
/// \code
/// concept HasTransposedTypeConcept<typename T>
/// {
/// typename transposed_type<T>;
/// where Metafunction<transposed_type<T> >;
/// };
/// \endcode
template <typename T>
struct HasTransposedTypeConcept
{
void constraints()
{
using type = typename transposed_type<T>::type;
ignore_unused_variable_warning(type{});
}
};
/// \defgroup PixelIteratorConceptPixelIterator PixelIteratorConcept
/// \ingroup PixelIteratorConcept
/// \brief STL iterator over pixels
/// \ingroup PixelIteratorConceptPixelIterator
/// \brief An STL random access traversal iterator over a model of PixelConcept.
///
/// GIL's iterators must also provide the following metafunctions:
/// - \p const_iterator_type<Iterator>: Returns a read-only equivalent of \p Iterator
/// - \p iterator_is_mutable<Iterator>: Returns whether the given iterator is read-only or mutable
/// - \p is_iterator_adaptor<Iterator>: Returns whether the given iterator is an adaptor over another iterator. See IteratorAdaptorConcept for additional requirements of adaptors.
///
/// \code
/// concept PixelIteratorConcept<typename Iterator>
/// : boost_concepts::RandomAccessTraversalConcept<Iterator>, PixelBasedConcept<Iterator>
/// {
/// where PixelValueConcept<value_type>;
/// typename const_iterator_type<It>::type;
/// where PixelIteratorConcept<const_iterator_type<It>::type>;
/// static const bool iterator_is_mutable<It>::value;
/// static const bool is_iterator_adaptor<It>::value; // is it an iterator adaptor
/// };
/// \endcode
template <typename Iterator>
struct PixelIteratorConcept
{
void constraints()
{
gil_function_requires<boost_concepts::RandomAccessTraversalConcept<Iterator>>();
gil_function_requires<PixelBasedConcept<Iterator>>();
using value_type = typename std::iterator_traits<Iterator>::value_type;
gil_function_requires<PixelValueConcept<value_type>>();
using const_t = typename const_iterator_type<Iterator>::type;
static bool const is_mutable = iterator_is_mutable<Iterator>::value;
ignore_unused_variable_warning(is_mutable);
// immutable iterator must be constructible from (possibly mutable) iterator
const_t const_it(it);
ignore_unused_variable_warning(const_it);
check_base(typename is_iterator_adaptor<Iterator>::type());
}
void check_base(std::false_type) {}
void check_base(std::true_type)
{
using base_t = typename iterator_adaptor_get_base<Iterator>::type;
gil_function_requires<PixelIteratorConcept<base_t>>();
}
Iterator it;
};
/// \brief Pixel iterator that allows for changing its pixel
/// \ingroup PixelIteratorConceptPixelIterator
/// \code
/// concept MutablePixelIteratorConcept<PixelIteratorConcept Iterator>
/// : MutableRandomAccessIteratorConcept<Iterator> {};
/// \endcode
template <typename Iterator>
struct MutablePixelIteratorConcept
{
void constraints()
{
gil_function_requires<PixelIteratorConcept<Iterator>>();
gil_function_requires<detail::PixelIteratorIsMutableConcept<Iterator>>();
}
};
/// \defgroup PixelIteratorConceptStepIterator StepIteratorConcept
/// \ingroup PixelIteratorConcept
/// \brief Iterator that advances by a specified step
/// \ingroup PixelIteratorConceptStepIterator
/// \brief Concept of a random-access iterator that can be advanced in memory units (bytes or bits)
/// \code
/// concept MemoryBasedIteratorConcept<boost_concepts::RandomAccessTraversalConcept Iterator>
/// {
/// typename byte_to_memunit<Iterator>; where metafunction<byte_to_memunit<Iterator> >;
/// std::ptrdiff_t memunit_step(const Iterator&);
/// std::ptrdiff_t memunit_distance(const Iterator& , const Iterator&);
/// void memunit_advance(Iterator&, std::ptrdiff_t diff);
/// Iterator memunit_advanced(const Iterator& p, std::ptrdiff_t diff) { Iterator tmp; memunit_advance(tmp,diff); return tmp; }
/// Iterator::reference memunit_advanced_ref(const Iterator& p, std::ptrdiff_t diff) { return *memunit_advanced(p,diff); }
/// };
/// \endcode
template <typename Iterator>
struct MemoryBasedIteratorConcept
{
void constraints()
{
gil_function_requires<boost_concepts::RandomAccessTraversalConcept<Iterator>>();
gil_function_requires<detail::RandomAccessIteratorIsMemoryBasedConcept<Iterator>>();
}
};
/// \ingroup PixelIteratorConceptStepIterator
/// \brief Step iterator concept
///
/// Step iterators are iterators that have a set_step method
/// \code
/// concept StepIteratorConcept<boost_concepts::ForwardTraversalConcept Iterator>
/// {
/// template <Integral D>
/// void Iterator::set_step(D step);
/// };
/// \endcode
template <typename Iterator>
struct StepIteratorConcept
{
void constraints()
{
gil_function_requires<boost_concepts::ForwardTraversalConcept<Iterator>>();
it.set_step(0);
}
Iterator it;
};
/// \ingroup PixelIteratorConceptStepIterator
/// \brief Step iterator that allows for modifying its current value
/// \code
/// concept MutableStepIteratorConcept<Mutable_ForwardIteratorConcept Iterator>
/// : StepIteratorConcept<Iterator> {};
/// \endcode
template <typename Iterator>
struct MutableStepIteratorConcept
{
void constraints()
{
gil_function_requires<StepIteratorConcept<Iterator>>();
gil_function_requires<detail::ForwardIteratorIsMutableConcept<Iterator>>();
}
};
/// \defgroup PixelIteratorConceptIteratorAdaptor IteratorAdaptorConcept
/// \ingroup PixelIteratorConcept
/// \brief Adaptor over another iterator
/// \ingroup PixelIteratorConceptIteratorAdaptor
/// \brief Iterator adaptor is a forward iterator adapting another forward iterator.
///
/// In addition to GIL iterator requirements,
/// GIL iterator adaptors must provide the following metafunctions:
/// - \p is_iterator_adaptor<Iterator>: Returns \p std::true_type
/// - \p iterator_adaptor_get_base<Iterator>: Returns the base iterator type
/// - \p iterator_adaptor_rebind<Iterator,NewBase>: Replaces the base iterator with the new one
///
/// The adaptee can be obtained from the iterator via the "base()" method.
///
/// \code
/// concept IteratorAdaptorConcept<boost_concepts::ForwardTraversalConcept Iterator>
/// {
/// where SameType<is_iterator_adaptor<Iterator>::type, std::true_type>;
///
/// typename iterator_adaptor_get_base<Iterator>;
/// where Metafunction<iterator_adaptor_get_base<Iterator> >;
/// where boost_concepts::ForwardTraversalConcept<iterator_adaptor_get_base<Iterator>::type>;
///
/// typename another_iterator;
/// typename iterator_adaptor_rebind<Iterator,another_iterator>::type;
/// where boost_concepts::ForwardTraversalConcept<another_iterator>;
/// where IteratorAdaptorConcept<iterator_adaptor_rebind<Iterator,another_iterator>::type>;
///
/// const iterator_adaptor_get_base<Iterator>::type& Iterator::base() const;
/// };
/// \endcode
template <typename Iterator>
struct IteratorAdaptorConcept
{
void constraints()
{
gil_function_requires<boost_concepts::ForwardTraversalConcept<Iterator>>();
using base_t = typename iterator_adaptor_get_base<Iterator>::type;
gil_function_requires<boost_concepts::ForwardTraversalConcept<base_t>>();
static_assert(is_iterator_adaptor<Iterator>::value, "");
using rebind_t = typename iterator_adaptor_rebind<Iterator, void*>::type;
base_t base = it.base();
ignore_unused_variable_warning(base);
}
Iterator it;
};
/// \brief Iterator adaptor that is mutable
/// \ingroup PixelIteratorConceptIteratorAdaptor
/// \code
/// concept MutableIteratorAdaptorConcept<Mutable_ForwardIteratorConcept Iterator>
/// : IteratorAdaptorConcept<Iterator> {};
/// \endcode
template <typename Iterator>
struct MutableIteratorAdaptorConcept
{
void constraints()
{
gil_function_requires<IteratorAdaptorConcept<Iterator>>();
gil_function_requires<detail::ForwardIteratorIsMutableConcept<Iterator>>();
}
};
}} // namespace boost::gil
#if defined(BOOST_CLANG)
#pragma clang diagnostic pop
#endif
#if defined(BOOST_GCC) && (BOOST_GCC >= 40900)
#pragma GCC diagnostic pop
#endif
#endif

View File

@@ -0,0 +1,411 @@
//
// 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_CONCEPTS_PIXEL_LOCATOR_HPP
#define BOOST_GIL_CONCEPTS_PIXEL_LOCATOR_HPP
#include <boost/gil/concepts/basic.hpp>
#include <boost/gil/concepts/concept_check.hpp>
#include <boost/gil/concepts/fwd.hpp>
#include <boost/gil/concepts/pixel.hpp>
#include <boost/gil/concepts/pixel_dereference.hpp>
#include <boost/gil/concepts/pixel_iterator.hpp>
#include <boost/gil/concepts/point.hpp>
#include <boost/gil/concepts/detail/utility.hpp>
#include <cstddef>
#include <iterator>
#include <type_traits>
#if defined(BOOST_CLANG)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunknown-pragmas"
#pragma clang diagnostic ignored "-Wunused-local-typedefs"
#endif
#if defined(BOOST_GCC) && (BOOST_GCC >= 40900)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
#endif
namespace boost { namespace gil {
/// \defgroup LocatorNDConcept RandomAccessNDLocatorConcept
/// \ingroup PixelLocatorConcept
/// \brief N-dimensional locator
/// \defgroup Locator2DConcept RandomAccess2DLocatorConcept
/// \ingroup PixelLocatorConcept
/// \brief 2-dimensional locator
/// \defgroup PixelLocator2DConcept PixelLocatorConcept
/// \ingroup PixelLocatorConcept
/// \brief 2-dimensional locator over pixel data
/// \ingroup LocatorNDConcept
/// \brief N-dimensional locator over immutable values
///
/// \code
/// concept RandomAccessNDLocatorConcept<Regular Loc>
/// {
/// typename value_type; // value over which the locator navigates
/// typename reference; // result of dereferencing
/// typename difference_type; where PointNDConcept<difference_type>; // return value of operator-.
/// typename const_t; // same as Loc, but operating over immutable values
/// typename cached_location_t; // type to store relative location (for efficient repeated access)
/// typename point_t = difference_type;
///
/// static const size_t num_dimensions; // dimensionality of the locator
/// where num_dimensions = point_t::num_dimensions;
///
/// // The difference_type and iterator type along each dimension. The iterators may only differ in
/// // difference_type. Their value_type must be the same as Loc::value_type
/// template <size_t D>
/// struct axis
/// {
/// typename coord_t = point_t::axis<D>::coord_t;
/// typename iterator; where RandomAccessTraversalConcept<iterator>; // iterator along D-th axis.
/// where iterator::value_type == value_type;
/// };
///
/// // Defines the type of a locator similar to this type, except it invokes Deref upon dereferencing
/// template <PixelDereferenceAdaptorConcept Deref>
/// struct add_deref
/// {
/// typename type;
/// where RandomAccessNDLocatorConcept<type>;
/// static type make(const Loc& loc, const Deref& deref);
/// };
///
/// Loc& operator+=(Loc&, const difference_type&);
/// Loc& operator-=(Loc&, const difference_type&);
/// Loc operator+(const Loc&, const difference_type&);
/// Loc operator-(const Loc&, const difference_type&);
///
/// reference operator*(const Loc&);
/// reference operator[](const Loc&, const difference_type&);
///
/// // Storing relative location for faster repeated access and accessing it
/// cached_location_t Loc::cache_location(const difference_type&) const;
/// reference operator[](const Loc&,const cached_location_t&);
///
/// // Accessing iterators along a given dimension at the current location or at a given offset
/// template <size_t D> axis<D>::iterator& Loc::axis_iterator();
/// template <size_t D> axis<D>::iterator const& Loc::axis_iterator() const;
/// template <size_t D> axis<D>::iterator Loc::axis_iterator(const difference_type&) const;
/// };
/// \endcode
template <typename Loc>
struct RandomAccessNDLocatorConcept
{
void constraints()
{
gil_function_requires<Regular<Loc>>();
// TODO: Should these be concept-checked instead of ignored? --mloskot
using value_type = typename Loc::value_type;
ignore_unused_variable_warning(value_type{});
// result of dereferencing
using reference = typename Loc::reference;
//ignore_unused_variable_warning(reference{});
// result of operator-(pixel_locator, pixel_locator)
using difference_type = typename Loc::difference_type;
ignore_unused_variable_warning(difference_type{});
// type used to store relative location (to allow for more efficient repeated access)
using cached_location_t = typename Loc::cached_location_t;
ignore_unused_variable_warning(cached_location_t{});
// same as this type, but over const values
using const_t = typename Loc::const_t;
ignore_unused_variable_warning(const_t{});
// same as difference_type
using point_t = typename Loc::point_t;
ignore_unused_variable_warning(point_t{});
static std::size_t const N = Loc::num_dimensions; ignore_unused_variable_warning(N);
using first_it_type = typename Loc::template axis<0>::iterator;
using last_it_type = typename Loc::template axis<N-1>::iterator;
gil_function_requires<boost_concepts::RandomAccessTraversalConcept<first_it_type>>();
gil_function_requires<boost_concepts::RandomAccessTraversalConcept<last_it_type>>();
// point_t must be an N-dimensional point, each dimension of which must
// have the same type as difference_type of the corresponding iterator
gil_function_requires<PointNDConcept<point_t>>();
static_assert(point_t::num_dimensions == N, "");
static_assert(std::is_same
<
typename std::iterator_traits<first_it_type>::difference_type,
typename point_t::template axis<0>::coord_t
>::value, "");
static_assert(std::is_same
<
typename std::iterator_traits<last_it_type>::difference_type,
typename point_t::template axis<N-1>::coord_t
>::value, "");
difference_type d;
loc += d;
loc -= d;
loc = loc + d;
loc = loc - d;
reference r1 = loc[d]; ignore_unused_variable_warning(r1);
reference r2 = *loc; ignore_unused_variable_warning(r2);
cached_location_t cl = loc.cache_location(d); ignore_unused_variable_warning(cl);
reference r3 = loc[d]; ignore_unused_variable_warning(r3);
first_it_type fi = loc.template axis_iterator<0>();
fi = loc.template axis_iterator<0>(d);
last_it_type li = loc.template axis_iterator<N-1>();
li = loc.template axis_iterator<N-1>(d);
using deref_t = PixelDereferenceAdaptorArchetype<typename Loc::value_type>;
using dtype = typename Loc::template add_deref<deref_t>::type;
// TODO: infinite recursion - FIXME?
//gil_function_requires<RandomAccessNDLocatorConcept<dtype>>();
}
Loc loc;
};
/// \ingroup Locator2DConcept
/// \brief 2-dimensional locator over immutable values
///
/// \code
/// concept RandomAccess2DLocatorConcept<RandomAccessNDLocatorConcept Loc>
/// {
/// where num_dimensions==2;
/// where Point2DConcept<point_t>;
///
/// typename x_iterator = axis<0>::iterator;
/// typename y_iterator = axis<1>::iterator;
/// typename x_coord_t = axis<0>::coord_t;
/// typename y_coord_t = axis<1>::coord_t;
///
/// // Only available to locators that have dynamic step in Y
/// //Loc::Loc(const Loc& loc, y_coord_t);
///
/// // Only available to locators that have dynamic step in X and Y
/// //Loc::Loc(const Loc& loc, x_coord_t, y_coord_t, bool transposed=false);
///
/// x_iterator& Loc::x();
/// x_iterator const& Loc::x() const;
/// y_iterator& Loc::y();
/// y_iterator const& Loc::y() const;
///
/// x_iterator Loc::x_at(const difference_type&) const;
/// y_iterator Loc::y_at(const difference_type&) const;
/// Loc Loc::xy_at(const difference_type&) const;
///
/// // x/y versions of all methods that can take difference type
/// x_iterator Loc::x_at(x_coord_t, y_coord_t) const;
/// y_iterator Loc::y_at(x_coord_t, y_coord_t) const;
/// Loc Loc::xy_at(x_coord_t, y_coord_t) const;
/// reference operator()(const Loc&, x_coord_t, y_coord_t);
/// cached_location_t Loc::cache_location(x_coord_t, y_coord_t) const;
///
/// bool Loc::is_1d_traversable(x_coord_t width) const;
/// y_coord_t Loc::y_distance_to(const Loc& loc2, x_coord_t x_diff) const;
/// };
/// \endcode
template <typename Loc>
struct RandomAccess2DLocatorConcept
{
void constraints()
{
gil_function_requires<RandomAccessNDLocatorConcept<Loc>>();
static_assert(Loc::num_dimensions == 2, "");
using dynamic_x_step_t = typename dynamic_x_step_type<Loc>::type;
using dynamic_y_step_t = typename dynamic_y_step_type<Loc>::type;
using transposed_t = typename transposed_type<Loc>::type;
using cached_location_t = typename Loc::cached_location_t;
gil_function_requires<Point2DConcept<typename Loc::point_t>>();
using x_iterator = typename Loc::x_iterator;
using y_iterator = typename Loc::y_iterator;
using x_coord_t = typename Loc::x_coord_t;
using y_coord_t = typename Loc::y_coord_t;
x_coord_t xd = 0; ignore_unused_variable_warning(xd);
y_coord_t yd = 0; ignore_unused_variable_warning(yd);
typename Loc::difference_type d;
typename Loc::reference r=loc(xd,yd); ignore_unused_variable_warning(r);
dynamic_x_step_t loc2(dynamic_x_step_t(), yd);
dynamic_x_step_t loc3(dynamic_x_step_t(), xd, yd);
using dynamic_xy_step_transposed_t = typename dynamic_y_step_type
<
typename dynamic_x_step_type<transposed_t>::type
>::type;
dynamic_xy_step_transposed_t loc4(loc, xd,yd,true);
bool is_contiguous = loc.is_1d_traversable(xd);
ignore_unused_variable_warning(is_contiguous);
loc.y_distance_to(loc, xd);
loc = loc.xy_at(d);
loc = loc.xy_at(xd, yd);
x_iterator xit = loc.x_at(d);
xit = loc.x_at(xd, yd);
xit = loc.x();
y_iterator yit = loc.y_at(d);
yit = loc.y_at(xd, yd);
yit = loc.y();
cached_location_t cl = loc.cache_location(xd, yd);
ignore_unused_variable_warning(cl);
}
Loc loc;
};
/// \ingroup PixelLocator2DConcept
/// \brief GIL's 2-dimensional locator over immutable GIL pixels
/// \code
/// concept PixelLocatorConcept<RandomAccess2DLocatorConcept Loc>
/// {
/// where PixelValueConcept<value_type>;
/// where PixelIteratorConcept<x_iterator>;
/// where PixelIteratorConcept<y_iterator>;
/// where x_coord_t == y_coord_t;
///
/// typename coord_t = x_coord_t;
/// };
/// \endcode
template <typename Loc>
struct PixelLocatorConcept
{
void constraints()
{
gil_function_requires<RandomAccess2DLocatorConcept<Loc>>();
gil_function_requires<PixelIteratorConcept<typename Loc::x_iterator>>();
gil_function_requires<PixelIteratorConcept<typename Loc::y_iterator>>();
using coord_t = typename Loc::coord_t;
static_assert(std::is_same<typename Loc::x_coord_t, typename Loc::y_coord_t>::value, "");
}
Loc loc;
};
namespace detail {
/// \tparam Loc Models RandomAccessNDLocatorConcept
template <typename Loc>
struct RandomAccessNDLocatorIsMutableConcept
{
void constraints()
{
gil_function_requires<detail::RandomAccessIteratorIsMutableConcept
<
typename Loc::template axis<0>::iterator
>>();
gil_function_requires<detail::RandomAccessIteratorIsMutableConcept
<
typename Loc::template axis<Loc::num_dimensions-1>::iterator
>>();
typename Loc::difference_type d; initialize_it(d);
typename Loc::value_type v; initialize_it(v);
typename Loc::cached_location_t cl = loc.cache_location(d);
*loc = v;
loc[d] = v;
loc[cl] = v;
}
Loc loc;
};
// \tparam Loc Models RandomAccess2DLocatorConcept
template <typename Loc>
struct RandomAccess2DLocatorIsMutableConcept
{
void constraints()
{
gil_function_requires<detail::RandomAccessNDLocatorIsMutableConcept<Loc>>();
typename Loc::x_coord_t xd = 0; ignore_unused_variable_warning(xd);
typename Loc::y_coord_t yd = 0; ignore_unused_variable_warning(yd);
typename Loc::value_type v; initialize_it(v);
loc(xd, yd) = v;
}
Loc loc;
};
} // namespace detail
/// \ingroup LocatorNDConcept
/// \brief N-dimensional locator over mutable pixels
///
/// \code
/// concept MutableRandomAccessNDLocatorConcept<RandomAccessNDLocatorConcept Loc>
/// {
/// where Mutable<reference>;
/// };
/// \endcode
template <typename Loc>
struct MutableRandomAccessNDLocatorConcept
{
void constraints()
{
gil_function_requires<RandomAccessNDLocatorConcept<Loc>>();
gil_function_requires<detail::RandomAccessNDLocatorIsMutableConcept<Loc>>();
}
};
/// \ingroup Locator2DConcept
/// \brief 2-dimensional locator over mutable pixels
///
/// \code
/// concept MutableRandomAccess2DLocatorConcept<RandomAccess2DLocatorConcept Loc>
/// : MutableRandomAccessNDLocatorConcept<Loc> {};
/// \endcode
template <typename Loc>
struct MutableRandomAccess2DLocatorConcept
{
void constraints()
{
gil_function_requires<RandomAccess2DLocatorConcept<Loc>>();
gil_function_requires<detail::RandomAccess2DLocatorIsMutableConcept<Loc>>();
}
};
/// \ingroup PixelLocator2DConcept
/// \brief GIL's 2-dimensional locator over mutable GIL pixels
///
/// \code
/// concept MutablePixelLocatorConcept<PixelLocatorConcept Loc>
/// : MutableRandomAccess2DLocatorConcept<Loc> {};
/// \endcode
template <typename Loc>
struct MutablePixelLocatorConcept
{
void constraints()
{
gil_function_requires<PixelLocatorConcept<Loc>>();
gil_function_requires<detail::RandomAccess2DLocatorIsMutableConcept<Loc>>();
}
};
}} // namespace boost::gil
#if defined(BOOST_CLANG)
#pragma clang diagnostic pop
#endif
#if defined(BOOST_GCC) && (BOOST_GCC >= 40900)
#pragma GCC diagnostic pop
#endif
#endif

View File

@@ -0,0 +1,125 @@
//
// 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_CONCEPTS_POINT_HPP
#define BOOST_GIL_CONCEPTS_POINT_HPP
#include <boost/gil/concepts/basic.hpp>
#include <boost/gil/concepts/concept_check.hpp>
#include <cstddef>
#if defined(BOOST_CLANG)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunknown-pragmas"
#pragma clang diagnostic ignored "-Wunused-local-typedefs"
#endif
#if defined(BOOST_GCC) && (BOOST_GCC >= 40900)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#endif
namespace boost { namespace gil {
// Forward declarations
template <typename T>
class point;
template <std::size_t K, typename T>
T const& axis_value(point<T> const& p);
template <std::size_t K, typename T>
T& axis_value(point<T>& p);
/// \brief N-dimensional point concept
/// \code
/// concept PointNDConcept<typename T> : Regular<T>
/// {
/// // the type of a coordinate along each axis
/// template <size_t K>
/// struct axis; where Metafunction<axis>;
///
/// const size_t num_dimensions;
///
/// // accessor/modifier of the value of each axis.
///
/// template <size_t K>
/// typename axis<K>::type const& T::axis_value() const;
///
/// template <size_t K>
/// typename axis<K>::type& T::axis_value();
/// };
/// \endcode
/// \ingroup PointConcept
///
template <typename P>
struct PointNDConcept
{
void constraints()
{
gil_function_requires<Regular<P>>();
using value_type = typename P::value_type;
ignore_unused_variable_warning(value_type{});
static const std::size_t N = P::num_dimensions;
ignore_unused_variable_warning(N);
using FT = typename P::template axis<0>::coord_t;
using LT = typename P::template axis<N - 1>::coord_t;
FT ft = gil::axis_value<0>(point);
axis_value<0>(point) = ft;
LT lt = axis_value<N - 1>(point);
axis_value<N - 1>(point) = lt;
//value_type v=point[0];
//ignore_unused_variable_warning(v);
}
P point;
};
/// \brief 2-dimensional point concept
/// \code
/// concept Point2DConcept<typename T> : PointNDConcept<T>
/// {
/// where num_dimensions == 2;
/// where SameType<axis<0>::type, axis<1>::type>;
///
/// typename value_type = axis<0>::type;
///
/// value_type const& operator[](T const&, size_t i);
/// value_type& operator[](T&, size_t i);
///
/// value_type x,y;
/// };
/// \endcode
/// \ingroup PointConcept
///
template <typename P>
struct Point2DConcept
{
void constraints()
{
gil_function_requires<PointNDConcept<P>>();
static_assert(P::num_dimensions == 2, "");
point.x = point.y;
point[0] = point[1];
}
P point;
};
}} // namespace boost::gil
#if defined(BOOST_CLANG)
#pragma clang diagnostic pop
#endif
#if defined(BOOST_GCC) && (BOOST_GCC >= 40900)
#pragma GCC diagnostic pop
#endif
#endif

View File

@@ -0,0 +1,65 @@
//
// 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_DEPRECATED_HPP
#define BOOST_GIL_DEPRECATED_HPP
#include <cstddef>
/// This file is provided as a courtesy to ease upgrading GIL client code.
/// Please make sure your code compiles when this file is not included.
#define planar_ptr planar_pixel_iterator
#define planar_ref planar_pixel_reference
#define membased_2d_locator memory_based_2d_locator
#define pixel_step_iterator memory_based_step_iterator
#define pixel_image_iterator iterator_from_2d
#define equal_channels static_equal
#define copy_channels static_copy
#define fill_channels static_fill
#define generate_channels static_generate
#define for_each_channel static_for_each
#define transform_channels static_transform
#define max_channel static_max
#define min_channel static_min
#define semantic_channel semantic_at_c
template <typename Img>
void resize_clobber_image(Img& img, const typename Img::point_t& new_dims) {
img.recreate(new_dims);
}
template <typename Img>
void resize_clobber_image(Img& img, const typename Img::x_coord_t& width, const typename Img::y_coord_t& height) {
img.recreate(width,height);
}
template <typename T> typename T::x_coord_t get_width(const T& a) { return a.width(); }
template <typename T> typename T::y_coord_t get_height(const T& a) { return a.height(); }
template <typename T> typename T::point_t get_dimensions(const T& a) { return a.dimensions(); }
template <typename T> std::size_t get_num_channels(const T& a) { return a.num_channels(); }
#define GIL boost::gil
#define ADOBE_GIL_NAMESPACE_BEGIN namespace boost { namespace gil {
#define ADOBE_GIL_NAMESPACE_END } }
#define ByteAdvancableIteratorConcept MemoryBasedIteratorConcept
#define byte_advance memunit_advance
#define byte_advanced memunit_advanced
#define byte_step memunit_step
#define byte_distance memunit_distance
#define byte_addressable_step_iterator memory_based_step_iterator
#define byte_addressable_2d_locator memory_based_2d_locator
// These are members of memory-based locators
//#define row_bytes row_size // commented out because row_bytes is commonly used
#define pix_bytestep pixel_size
#endif

View File

@@ -0,0 +1,47 @@
//
// Copyright 2019 Mateusz Loskot <mateusz at loskot dot net>
// 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_DETAIL_IS_CHANNEL_INTEGRAL_HPP
#define BOOST_GIL_DETAIL_IS_CHANNEL_INTEGRAL_HPP
#include <boost/gil/channel.hpp>
#include <type_traits>
namespace boost { namespace gil { namespace detail {
template <typename ChannelValue>
struct is_channel_integral : std::is_integral<ChannelValue> {};
template <int NumBits>
struct is_channel_integral<boost::gil::packed_channel_value<NumBits>> : std::true_type {};
template <typename BitField, int FirstBit, int NumBits, bool IsMutable>
struct is_channel_integral
<
boost::gil::packed_channel_reference<BitField, FirstBit, NumBits, IsMutable>
> : std::true_type
{};
template <typename BitField, int NumBits, bool IsMutable>
struct is_channel_integral
<
boost::gil::packed_dynamic_channel_reference<BitField, NumBits, IsMutable>
> : std::true_type
{};
template <typename BaseChannelValue, typename MinVal, typename MaxVal>
struct is_channel_integral
<
boost::gil::scoped_channel_value<BaseChannelValue, MinVal, MaxVal>
> : std::is_integral<BaseChannelValue>
{};
}}} //namespace boost::gil::detail
#endif

View File

@@ -0,0 +1,33 @@
//
// Copyright 2019 Olzhas Zhumabek <anonymous.from.applecity@gmail.com>
//
// Use, modification and distribution are subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef BOOST_GIL_IMAGE_PROCESSING_DETAIL_MATH_HPP
#define BOOST_GIL_IMAGE_PROCESSING_DETAIL_MATH_HPP
#include <array>
#include <boost/gil/extension/numeric/kernel.hpp>
namespace boost { namespace gil { namespace detail {
static constexpr double pi = 3.14159265358979323846;
static constexpr std::array<float, 9> dx_sobel = {{-1, 0, 1, -2, 0, 2, -1, 0, 1}};
static constexpr std::array<float, 9> dx_scharr = {{-1, 0, 1, -1, 0, 1, -1, 0, 1}};
static constexpr std::array<float, 9> dy_sobel = {{1, 2, 1, 0, 0, 0, -1, -2, -1}};
static constexpr std::array<float, 9> dy_scharr = {{1, 1, 1, 0, 0, 0, -1, -1, -1}};
template <typename T, typename Allocator>
inline detail::kernel_2d<T, Allocator> get_identity_kernel()
{
detail::kernel_2d<T, Allocator> kernel(1, 0, 0);
kernel[0] = 1;
return kernel;
}
}}} // namespace boost::gil::detail
#endif

View File

@@ -0,0 +1,26 @@
//
// Copyright 2017 Peter Dimov.
// Copyright 2019 Mateusz Loskot <mateusz at loskot dot net>
//
// 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_DETAIL_MP11_HPP
#define BOOST_GIL_DETAIL_MP11_HPP
#include <boost/mp11.hpp>
#include <boost/mp11/mpl.hpp> // required by dynamic_image and boost::variant (?)
namespace boost { namespace gil { namespace detail {
template<typename L>
using mp_back = ::boost::mp11::mp_at_c<L, ::boost::mp11::mp_size<L>::value - 1>;
template<typename L>
using mp_pop_back = ::boost::mp11::mp_take_c<L, ::boost::mp11::mp_size<L>::value - 1>;
}}} // namespace boost::gil::detail
#endif

View File

@@ -0,0 +1,39 @@
//
// Copyright Louis Dionne 2013-2017
//
// Distributed under the Boost Software License, Version 1.0.
//(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
//
#ifndef BOOST_GIL_DETAIL_STD_COMMON_TYPE_HPP
#define BOOST_GIL_DETAIL_STD_COMMON_TYPE_HPP
#include <type_traits>
#include <utility>
namespace boost { namespace gil { namespace detail {
// Defines a SFINAE-friendly version of `std::common_type`.
//
// Based on boost/hana/detail/std_common_type.hpp
// Equivalent to `std::common_type`, except it is SFINAE-friendly and
// does not support custom specializations.
template <typename T, typename U, typename = void>
struct std_common_type {};
template <typename T, typename U>
struct std_common_type
<
T, U,
decltype((void)(true ? std::declval<T>() : std::declval<U>()))
>
{
using type = typename std::decay
<
decltype(true ? std::declval<T>() : std::declval<U>())
>::type;
};
}}} // namespace boost::gil::detail
#endif

View File

@@ -0,0 +1,39 @@
//
// Copyright 2017-2019 Peter Dimov.
//
// 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_DETAIL_TYPE_TRAITS_HPP
#define BOOST_GIL_DETAIL_TYPE_TRAITS_HPP
#include <boost/config.hpp>
#include <type_traits>
namespace boost { namespace gil { namespace detail {
#if defined(BOOST_LIBSTDCXX_VERSION) && BOOST_LIBSTDCXX_VERSION < 50100
template<class T>
struct is_trivially_default_constructible
: std::integral_constant
<
bool,
std::is_default_constructible<T>::value &&
std::has_trivial_default_constructor<T>::value
>
{};
#else
using std::is_trivially_default_constructible;
#endif
using std::is_trivially_destructible;
}}} //namespace boost::gil::detail
#endif

View File

@@ -0,0 +1,103 @@
//
// 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_DEVICE_N_HPP
#define BOOST_GIL_DEVICE_N_HPP
#include <boost/gil/metafunctions.hpp>
#include <boost/gil/utilities.hpp>
#include <boost/gil/detail/mp11.hpp>
#include <boost/config.hpp>
#include <cstddef>
#include <type_traits>
namespace boost { namespace gil {
// TODO: Document the DeviceN Color Space and Color Model
// with reference to the Adobe documentation
// https://www.adobe.com/content/dam/acom/en/devnet/postscript/pdfs/TN5604.DeviceN_Color.pdf
/// \brief unnamed color
/// \ingroup ColorNameModel
template <int N>
struct devicen_color_t {};
template <int N>
struct devicen_t;
/// \brief Unnamed color space of 1, 3, 4, or 5 channels
/// \tparam N Number of color components (1, 3, 4 or 5).
/// \ingroup ColorSpaceModel
template <int N>
struct devicen_t
{
private:
template <typename T>
using color_t = devicen_color_t<T::value>;
static_assert(
N == 1 || (3 <= N && N <= 5),
"invalid number of DeviceN color components");
public:
using type = mp11::mp_transform<color_t, mp11::mp_iota_c<N>>;
};
/// \brief unnamed color layout of up to five channels
/// \ingroup LayoutModel
template <int N>
struct devicen_layout_t : layout<typename devicen_t<N>::type> {};
/// \ingroup ImageViewConstructors
/// \brief from 2-channel planar data
template <typename IC>
inline typename type_from_x_iterator<planar_pixel_iterator<IC,devicen_t<2>>>::view_t
planar_devicen_view(std::size_t width, std::size_t height, IC c0, IC c1, std::ptrdiff_t rowsize_in_bytes)
{
using view_t = typename type_from_x_iterator<planar_pixel_iterator<IC,devicen_t<2>>>::view_t;
return view_t(width, height, typename view_t::locator(typename view_t::x_iterator(c0,c1), rowsize_in_bytes));
}
/// \ingroup ImageViewConstructors
/// \brief from 3-channel planar data
template <typename IC>
inline
auto planar_devicen_view(std::size_t width, std::size_t height, IC c0, IC c1, IC c2, std::ptrdiff_t rowsize_in_bytes)
-> typename type_from_x_iterator<planar_pixel_iterator<IC,devicen_t<3>>>::view_t
{
using view_t = typename type_from_x_iterator<planar_pixel_iterator<IC,devicen_t<3>>>::view_t;
return view_t(width, height, typename view_t::locator(typename view_t::x_iterator(c0,c1,c2), rowsize_in_bytes));
}
/// \ingroup ImageViewConstructors
/// \brief from 4-channel planar data
template <typename IC>
inline
auto planar_devicen_view(std::size_t width, std::size_t height, IC c0, IC c1, IC c2, IC c3, std::ptrdiff_t rowsize_in_bytes)
-> typename type_from_x_iterator<planar_pixel_iterator<IC,devicen_t<4>>>::view_t
{
using view_t = typename type_from_x_iterator<planar_pixel_iterator<IC,devicen_t<4>>>::view_t;
return view_t(width, height, typename view_t::locator(typename view_t::x_iterator(c0,c1,c2,c3), rowsize_in_bytes));
}
/// \ingroup ImageViewConstructors
/// \brief from 5-channel planar data
template <typename IC>
inline
auto planar_devicen_view(std::size_t width, std::size_t height, IC c0, IC c1, IC c2, IC c3, IC c4, std::ptrdiff_t rowsize_in_bytes)
-> typename type_from_x_iterator<planar_pixel_iterator<IC,devicen_t<5>>>::view_t
{
using view_t = typename type_from_x_iterator<planar_pixel_iterator<IC,devicen_t<5>>>::view_t;
return view_t(width, height, typename view_t::locator(typename view_t::x_iterator(c0,c1,c2,c3,c4), rowsize_in_bytes));
}
}} // namespace boost::gil
#endif

View File

@@ -0,0 +1,31 @@
//
// 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_DYNAMIC_STEP_HPP
#define BOOST_GIL_DYNAMIC_STEP_HPP
#include <boost/gil/concepts/dynamic_step.hpp>
namespace boost { namespace gil {
/// Base template for types that model HasDynamicXStepTypeConcept.
template <typename IteratorOrLocatorOrView>
struct dynamic_x_step_type;
/// Base template for types that model HasDynamicYStepTypeConcept.
template <typename LocatorOrView>
struct dynamic_y_step_type;
/// Base template for types that model both, HasDynamicXStepTypeConcept and HasDynamicYStepTypeConcept.
///
/// \todo TODO: Is Locator allowed or practical to occur?
template <typename View>
struct dynamic_xy_step_type;
}} // namespace boost::gil
#endif

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View 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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View 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

View File

@@ -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

View 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

View File

@@ -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

View 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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View 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

View File

@@ -0,0 +1,30 @@
//
// Copyright 2007-2008 Christian Henning
//
// Distributed under the Boost Software License, Version 1.0
// See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt
//
#ifndef BOOST_GIL_EXTENSION_IO_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

View File

@@ -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

View File

@@ -0,0 +1,19 @@
//
// Copyright 2007-2008 Christian Henning
//
// Distributed under the Boost Software License, Version 1.0
// See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt
//
#ifndef BOOST_GIL_EXTENSION_IO_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

View 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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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
, &params
);
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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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 >( &params.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

View 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

View File

@@ -0,0 +1,30 @@
//
// Copyright 2007-2008 Christian Henning
//
// Distributed under the Boost Software License, Version 1.0
// See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt
//
#ifndef BOOST_GIL_EXTENSION_IO_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

View 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

View File

@@ -0,0 +1,19 @@
//
// Copyright 2007-2008 Christian Henning
//
// Distributed under the Boost Software License, Version 1.0
// See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt
//
#ifndef BOOST_GIL_EXTENSION_IO_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

View 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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View 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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View 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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View 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

Some files were not shown because too many files have changed in this diff Show More