WIP. Scale cover art option. Seems to work
This commit is contained in:
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
Copyright 2009 Christian Henning
|
||||
Use, modification and distribution are subject to the Boost Software License,
|
||||
Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
http://www.boost.org/LICENSE_1_0.txt).
|
||||
*/
|
||||
|
||||
/*************************************************************************************************/
|
||||
|
||||
#ifndef BOOST_GIL_EXTENSION_IO_PNM_IO_IS_ALLOWED_HPP
|
||||
#define BOOST_GIL_EXTENSION_IO_PNM_IO_IS_ALLOWED_HPP
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// \file
|
||||
/// \brief
|
||||
/// \author Christian Henning \n
|
||||
///
|
||||
/// \date 2008 \n
|
||||
///
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace boost { namespace gil { namespace detail {
|
||||
|
||||
template< typename View >
|
||||
bool is_allowed( const image_read_info< pnm_tag >& info
|
||||
, mpl::true_ // is read_and_no_convert
|
||||
)
|
||||
{
|
||||
pnm_image_type::type asc_type = is_read_supported< typename get_pixel_type< View >::type
|
||||
, pnm_tag
|
||||
>::_asc_type;
|
||||
|
||||
pnm_image_type::type bin_type = is_read_supported< typename get_pixel_type< View >::type
|
||||
, pnm_tag
|
||||
>::_bin_type;
|
||||
if( info._type == pnm_image_type::mono_asc_t::value )
|
||||
{
|
||||
// ascii mono images are read gray8_image_t
|
||||
return ( asc_type == pnm_image_type::gray_asc_t::value );
|
||||
}
|
||||
|
||||
|
||||
return ( asc_type == info._type
|
||||
|| bin_type == info._type
|
||||
);
|
||||
}
|
||||
|
||||
template< typename View >
|
||||
bool is_allowed( const image_read_info< pnm_tag >& /* info */
|
||||
, mpl::false_ // is read_and_convert
|
||||
)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
} // namespace gil
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_GIL_EXTENSION_IO_PNM_IO_IS_ALLOWED_HPP
|
||||
@@ -0,0 +1,498 @@
|
||||
/*
|
||||
Copyright 2008 Christian Henning
|
||||
Use, modification and distribution are subject to the Boost Software License,
|
||||
Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
http://www.boost.org/LICENSE_1_0.txt).
|
||||
*/
|
||||
|
||||
/*************************************************************************************************/
|
||||
|
||||
#ifndef BOOST_GIL_EXTENSION_IO_PNM_IO_READ_HPP
|
||||
#define BOOST_GIL_EXTENSION_IO_PNM_IO_READ_HPP
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// \file
|
||||
/// \brief
|
||||
/// \author Christian Henning \n
|
||||
///
|
||||
/// \date 2008 \n
|
||||
///
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <vector>
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/gil/gil_all.hpp>
|
||||
#include <boost/gil/extension/io_new/pnm_tags.hpp>
|
||||
|
||||
#include <boost/gil/extension/io_new/detail/base.hpp>
|
||||
#include <boost/gil/extension/io_new/detail/conversion_policies.hpp>
|
||||
#include <boost/gil/extension/io_new/detail/row_buffer_helper.hpp>
|
||||
#include <boost/gil/extension/io_new/detail/bit_operations.hpp>
|
||||
#include <boost/gil/extension/io_new/detail/reader_base.hpp>
|
||||
#include <boost/gil/extension/io_new/detail/io_device.hpp>
|
||||
#include <boost/gil/extension/io_new/detail/typedefs.hpp>
|
||||
|
||||
#include "is_allowed.hpp"
|
||||
|
||||
namespace boost { namespace gil { namespace detail {
|
||||
|
||||
template< typename View, typename T >
|
||||
struct calc_pitch {};
|
||||
|
||||
template< typename View >
|
||||
struct calc_pitch< View, mpl::false_ >
|
||||
{
|
||||
static uint32_t do_it( uint32_t width ) { return width * num_channels< View >::value; }
|
||||
};
|
||||
|
||||
template< typename View >
|
||||
struct calc_pitch< View, mpl::true_ >
|
||||
{
|
||||
static uint32_t do_it( uint32_t width ) { return ( width + 7 ) >> 3; }
|
||||
};
|
||||
|
||||
|
||||
template< typename Device
|
||||
, typename ConversionPolicy
|
||||
>
|
||||
class reader< Device
|
||||
, pnm_tag
|
||||
, ConversionPolicy
|
||||
>
|
||||
: public reader_base< pnm_tag
|
||||
, ConversionPolicy
|
||||
>
|
||||
{
|
||||
private:
|
||||
|
||||
typedef typename ConversionPolicy::color_converter_type cc_t;
|
||||
|
||||
public:
|
||||
reader( Device& device
|
||||
, const image_read_settings< pnm_tag >& settings
|
||||
)
|
||||
: reader_base< pnm_tag
|
||||
, ConversionPolicy >( settings )
|
||||
, _io_dev( device )
|
||||
{}
|
||||
|
||||
reader( Device& device
|
||||
, const cc_t& cc
|
||||
, const image_read_settings< pnm_tag >& settings
|
||||
)
|
||||
: reader_base< pnm_tag
|
||||
, ConversionPolicy >( cc
|
||||
, settings
|
||||
)
|
||||
, _io_dev( device )
|
||||
{}
|
||||
|
||||
image_read_info<pnm_tag> get_info()
|
||||
{
|
||||
image_read_info<pnm_tag> ret;
|
||||
|
||||
// read signature
|
||||
io_error_if( read_char() != 'P', "Invalid PNM signature" );
|
||||
|
||||
ret._type = read_char() - '0';
|
||||
|
||||
io_error_if( ret._type < pnm_image_type::mono_asc_t::value || ret._type > pnm_image_type::color_bin_t::value
|
||||
, "Invalid PNM file (supports P1 to P6)"
|
||||
);
|
||||
|
||||
ret._width = read_int();
|
||||
ret._height = read_int();
|
||||
|
||||
if( ret._type == pnm_image_type::mono_asc_t::value || ret._type == pnm_image_type::mono_bin_t::value )
|
||||
{
|
||||
ret._max_value = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
ret._max_value = read_int();
|
||||
|
||||
io_error_if( ret._max_value > 255
|
||||
, "Unsupported PNM format (supports maximum value 255)"
|
||||
);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
template<typename View>
|
||||
void apply( const View& view )
|
||||
{
|
||||
|
||||
typedef typename is_same< ConversionPolicy
|
||||
, read_and_no_convert
|
||||
>::type is_read_and_convert_t;
|
||||
|
||||
io_error_if( !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: { read_text_data< gray8_view_t >( view ); break; }
|
||||
case pnm_image_type::gray_asc_t::value: { read_text_data< gray8_view_t >( view ); break; }
|
||||
case pnm_image_type::color_asc_t::value: { read_text_data< rgb8_view_t >( view ); break; }
|
||||
|
||||
case pnm_image_type::mono_bin_t::value: { read_bin_data< gray1_image_t::view_t >( view ); break; }
|
||||
case pnm_image_type::gray_bin_t::value: { read_bin_data< gray8_view_t >( view ); break; }
|
||||
case pnm_image_type::color_bin_t::value: { read_bin_data< rgb8_view_t >( view ); break; }
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
template< typename View_Src
|
||||
, typename View_Dst
|
||||
>
|
||||
void read_text_data( const View_Dst& dst )
|
||||
{
|
||||
typedef typename View_Dst::y_coord_t y_t;
|
||||
|
||||
uint32_t pitch = this->_info._width * num_channels< View_Src >::value;
|
||||
|
||||
byte_vector_t row( pitch );
|
||||
|
||||
//Skip scanlines if necessary.
|
||||
for( int y = 0; y < this->_settings._top_left.y; ++y )
|
||||
{
|
||||
read_text_row< View_Src >( dst, row, pitch, y, false );
|
||||
}
|
||||
|
||||
for( y_t y = 0; y < dst.height(); ++y )
|
||||
{
|
||||
read_text_row< View_Src >( dst, row, pitch, y, true );
|
||||
}
|
||||
}
|
||||
|
||||
template< typename View_Src
|
||||
, typename View_Dst
|
||||
>
|
||||
void read_text_row( const View_Dst& dst
|
||||
, byte_vector_t& row
|
||||
, uint32_t pitch
|
||||
, typename View_Dst::y_coord_t y
|
||||
, bool process
|
||||
)
|
||||
{
|
||||
static char buf[16];
|
||||
|
||||
View_Src src = interleaved_view( this->_info._width
|
||||
, 1
|
||||
, (typename View_Src::value_type*) &row.front()
|
||||
, pitch
|
||||
);
|
||||
|
||||
for( uint32_t x = 0; x < pitch; ++x )
|
||||
{
|
||||
for( uint32_t k = 0; ; )
|
||||
{
|
||||
int ch = _io_dev.getc_unchecked();
|
||||
|
||||
if( isdigit( ch ))
|
||||
{
|
||||
buf[ k++ ] = static_cast< char >( ch );
|
||||
}
|
||||
else if( k )
|
||||
{
|
||||
buf[ k ] = 0;
|
||||
break;
|
||||
}
|
||||
else if( ch == EOF || !isspace( ch ))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if( process )
|
||||
{
|
||||
int value = atoi( buf );
|
||||
|
||||
if( this->_info._max_value == 1 )
|
||||
{
|
||||
typedef typename channel_type< typename get_pixel_type< View_Dst >::type >::type channel_t;
|
||||
|
||||
// for pnm format 0 is white
|
||||
row[x] = ( value != 0 )
|
||||
? typename channel_traits< channel_t >::value_type( 0 )
|
||||
: channel_traits< channel_t >::max_value();
|
||||
}
|
||||
else
|
||||
{
|
||||
row[x] = static_cast< byte_t >( value );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( process )
|
||||
{
|
||||
// We are reading a gray1_image like a gray8_image but the two pixel_t
|
||||
// aren't compatible. Though, read_and_no_convert::read(...) wont work.
|
||||
copy_data< View_Dst
|
||||
, View_Src >( dst
|
||||
, src
|
||||
, y
|
||||
, typename is_same< View_Dst
|
||||
, gray1_image_t::view_t
|
||||
>::type()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
template< typename View_Dst
|
||||
, typename View_Src
|
||||
>
|
||||
void copy_data( const View_Dst& dst
|
||||
, const View_Src& src
|
||||
, typename View_Dst::y_coord_t y
|
||||
, mpl::true_ // is gray1_view
|
||||
)
|
||||
{
|
||||
if( this->_info._max_value == 1 )
|
||||
{
|
||||
typename View_Dst::x_iterator it = dst.row_begin( y );
|
||||
|
||||
for( typename View_Dst::x_coord_t x = 0
|
||||
; x < dst.width()
|
||||
; ++x
|
||||
)
|
||||
{
|
||||
it[x] = src[x];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
copy_data( dst
|
||||
, src
|
||||
, y
|
||||
, mpl::false_()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
template< typename View_Dst
|
||||
, typename View_Src
|
||||
>
|
||||
void copy_data( const View_Dst& view
|
||||
, const View_Src& src
|
||||
, typename View_Dst::y_coord_t y
|
||||
, mpl::false_ // is gray1_view
|
||||
)
|
||||
{
|
||||
typename View_Src::x_iterator beg = src.row_begin( 0 ) + this->_settings._top_left.x;
|
||||
typename View_Src::x_iterator end = beg + this->_settings._dim.x;
|
||||
|
||||
this->_cc_policy.read( beg
|
||||
, end
|
||||
, view.row_begin( y )
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
template< typename View_Src
|
||||
, typename View_Dst
|
||||
>
|
||||
void read_bin_data( const View_Dst& view )
|
||||
{
|
||||
typedef typename View_Dst::y_coord_t y_t;
|
||||
typedef typename is_bit_aligned<
|
||||
typename View_Src::value_type >::type is_bit_aligned_t;
|
||||
|
||||
uint32_t pitch = calc_pitch< View_Src, is_bit_aligned_t >::do_it( this->_info._width );
|
||||
|
||||
typedef row_buffer_helper_view< View_Src > rh_t;
|
||||
rh_t rh( pitch, 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.
|
||||
negate_bits< typename rh_t::buffer_t
|
||||
, is_bit_aligned_t
|
||||
> neg;
|
||||
|
||||
swap_half_bytes< typename rh_t::buffer_t
|
||||
, is_bit_aligned_t
|
||||
> swhb;
|
||||
|
||||
//Skip scanlines if necessary.
|
||||
for( y_t y = 0; y < this->_settings._top_left.y; ++y )
|
||||
{
|
||||
_io_dev.read( reinterpret_cast< byte_t* >( rh.data() )
|
||||
, pitch
|
||||
);
|
||||
}
|
||||
|
||||
for( y_t y = 0; y < view.height(); ++y )
|
||||
{
|
||||
_io_dev.read( reinterpret_cast< byte_t* >( rh.data() )
|
||||
, pitch
|
||||
);
|
||||
|
||||
neg( rh.buffer() );
|
||||
swhb( rh.buffer() );
|
||||
|
||||
this->_cc_policy.read( beg
|
||||
, end
|
||||
, view.row_begin( y )
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
Device& _io_dev;
|
||||
};
|
||||
|
||||
struct pnm_type_format_checker
|
||||
{
|
||||
pnm_type_format_checker( pnm_image_type::type type )
|
||||
: _type( type )
|
||||
{}
|
||||
|
||||
template< typename Image >
|
||||
bool apply()
|
||||
{
|
||||
typedef is_read_supported< typename get_pixel_type< typename Image::view_t >::type
|
||||
, pnm_tag
|
||||
> is_supported_t;
|
||||
|
||||
return is_supported_t::_asc_type == _type
|
||||
|| is_supported_t::_bin_type == _type;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
pnm_image_type::type _type;
|
||||
};
|
||||
|
||||
struct pnm_read_is_supported
|
||||
{
|
||||
template< typename View >
|
||||
struct apply : public is_read_supported< typename get_pixel_type< View >::type
|
||||
, pnm_tag
|
||||
>
|
||||
{};
|
||||
};
|
||||
|
||||
template< typename Device
|
||||
>
|
||||
class dynamic_image_reader< Device
|
||||
, pnm_tag
|
||||
>
|
||||
: public reader< Device
|
||||
, pnm_tag
|
||||
, detail::read_and_no_convert
|
||||
>
|
||||
{
|
||||
typedef reader< Device
|
||||
, pnm_tag
|
||||
, detail::read_and_no_convert
|
||||
> parent_t;
|
||||
|
||||
public:
|
||||
|
||||
dynamic_image_reader( Device& device
|
||||
, const image_read_settings< pnm_tag >& settings
|
||||
)
|
||||
: parent_t( device
|
||||
, settings
|
||||
)
|
||||
{}
|
||||
|
||||
template< typename Images >
|
||||
void apply( any_image< Images >& images )
|
||||
{
|
||||
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
|
||||
{
|
||||
init_image( images
|
||||
, this->_info
|
||||
);
|
||||
|
||||
dynamic_io_fnobj< pnm_read_is_supported
|
||||
, parent_t
|
||||
> op( this );
|
||||
|
||||
apply_operation( view( images )
|
||||
, op
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // detail
|
||||
} // gil
|
||||
} // boost
|
||||
|
||||
#endif // BOOST_GIL_EXTENSION_IO_PNM_IO_READ_HPP
|
||||
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
Copyright 2008 Christian Henning
|
||||
Use, modification and distribution are subject to the Boost Software License,
|
||||
Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
http://www.boost.org/LICENSE_1_0.txt).
|
||||
*/
|
||||
|
||||
/*************************************************************************************************/
|
||||
|
||||
#ifndef BOOST_GIL_EXTENSION_IO_PNM_SUPPORTED_TYPES_HPP
|
||||
#define BOOST_GIL_EXTENSION_IO_PNM_SUPPORTED_TYPES_HPP
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// \file
|
||||
/// \brief
|
||||
/// \author Christian Henning \n
|
||||
///
|
||||
/// \date 2008 \n
|
||||
///
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <boost/mpl/not.hpp>
|
||||
#include <boost/type_traits/is_same.hpp>
|
||||
|
||||
#include <boost/gil/channel.hpp>
|
||||
#include <boost/gil/color_base.hpp>
|
||||
|
||||
namespace boost { namespace gil { namespace detail {
|
||||
|
||||
// Read Support
|
||||
|
||||
template< pnm_image_type::type ASCII_Type
|
||||
, pnm_image_type::type Binary_Type
|
||||
>
|
||||
struct pnm_rw_support_base
|
||||
{
|
||||
static const pnm_image_type::type _asc_type = ASCII_Type;
|
||||
static const pnm_image_type::type _bin_type = Binary_Type;
|
||||
};
|
||||
|
||||
template< typename Channel
|
||||
, typename ColorSpace
|
||||
>
|
||||
struct pnm_read_support : read_support_false
|
||||
, pnm_rw_support_base< 0
|
||||
, 0
|
||||
> {};
|
||||
|
||||
template< typename BitField, bool Mutable >
|
||||
struct pnm_read_support< packed_dynamic_channel_reference< BitField
|
||||
, 1
|
||||
, Mutable
|
||||
>
|
||||
, gray_t
|
||||
> : read_support_true
|
||||
, pnm_rw_support_base< pnm_image_type::mono_asc_t::value
|
||||
, pnm_image_type::mono_bin_t::value
|
||||
> {};
|
||||
|
||||
template<>
|
||||
struct pnm_read_support< bits8
|
||||
, 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< bits8
|
||||
, 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< bits8
|
||||
, 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< bits8
|
||||
, rgb_t
|
||||
> : write_support_true
|
||||
, pnm_rw_support_base< pnm_image_type::color_asc_t::value
|
||||
, pnm_image_type::color_bin_t::value
|
||||
> {};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template< typename Pixel >
|
||||
struct is_read_supported< Pixel
|
||||
, pnm_tag
|
||||
>
|
||||
: mpl::bool_< detail::pnm_read_support< typename channel_type < Pixel >::type
|
||||
, typename color_space_type< Pixel >::type
|
||||
>::is_supported
|
||||
>
|
||||
{
|
||||
typedef detail::pnm_read_support< typename channel_type < Pixel >::type
|
||||
, typename color_space_type< Pixel >::type
|
||||
> parent_t;
|
||||
|
||||
static const pnm_image_type::type _asc_type = parent_t::_asc_type;
|
||||
static const pnm_image_type::type _bin_type = parent_t::_bin_type;
|
||||
};
|
||||
|
||||
template< typename Pixel >
|
||||
struct is_write_supported< Pixel
|
||||
, pnm_tag
|
||||
>
|
||||
: mpl::bool_< detail::pnm_write_support< typename channel_type < Pixel >::type
|
||||
, typename color_space_type< Pixel >::type
|
||||
>::is_supported
|
||||
> {};
|
||||
|
||||
} // namespace gil
|
||||
} // namespace boost
|
||||
|
||||
|
||||
#endif // BOOST_GIL_EXTENSION_IO_PNM_SUPPORTED_TYPES_HPP
|
||||
@@ -0,0 +1,242 @@
|
||||
/*
|
||||
Copyright 2008 Christian Henning
|
||||
Use, modification and distribution are subject to the Boost Software License,
|
||||
Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
http://www.boost.org/LICENSE_1_0.txt).
|
||||
*/
|
||||
|
||||
/*************************************************************************************************/
|
||||
|
||||
#ifndef BOOST_GIL_EXTENSION_IO_PNM_IO_WRITE_HPP
|
||||
#define BOOST_GIL_EXTENSION_IO_PNM_IO_WRITE_HPP
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// \file
|
||||
/// \brief
|
||||
/// \author Christian Henning \n
|
||||
///
|
||||
/// \date 2008 \n
|
||||
///
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <boost/lexical_cast.hpp>
|
||||
|
||||
#include <boost/gil/extension/io_new/pnm_tags.hpp>
|
||||
|
||||
#include <boost/gil/extension/io_new/detail/base.hpp>
|
||||
#include <boost/gil/extension/io_new/detail/io_device.hpp>
|
||||
|
||||
namespace boost { namespace gil { namespace detail {
|
||||
|
||||
template< typename Device >
|
||||
class writer< Device
|
||||
, pnm_tag
|
||||
>
|
||||
{
|
||||
typedef image_write_info< pnm_tag > info_t;
|
||||
|
||||
public:
|
||||
|
||||
writer( Device & file )
|
||||
: _out( file )
|
||||
{
|
||||
}
|
||||
|
||||
~writer()
|
||||
{
|
||||
}
|
||||
|
||||
template<typename View>
|
||||
void apply( const View& view )
|
||||
{
|
||||
info_t info;
|
||||
|
||||
apply( view
|
||||
, info );
|
||||
}
|
||||
|
||||
template<typename View>
|
||||
void apply( const View& view
|
||||
, const info_t& /* info */
|
||||
)
|
||||
{
|
||||
typedef typename get_pixel_type< View >::type pixel_t;
|
||||
|
||||
std::size_t width = view.width();
|
||||
std::size_t height = view.height();
|
||||
|
||||
std::size_t chn = num_channels< View >::value;
|
||||
std::size_t pitch = chn * width;
|
||||
|
||||
unsigned int type;
|
||||
if( num_channels< View >::value == 1 )
|
||||
{
|
||||
if( is_bit_aligned< pixel_t >::value )
|
||||
{
|
||||
type = pnm_image_type::mono_bin_t::value;
|
||||
}
|
||||
else
|
||||
{
|
||||
type = pnm_image_type::gray_bin_t::value;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
type = pnm_image_type::color_bin_t::value;
|
||||
}
|
||||
|
||||
// write header
|
||||
|
||||
// Add a white space at each string so read_int() can decide when a numbers ends.
|
||||
|
||||
std::string str( "P" );
|
||||
str += lexical_cast< std::string >( type ) + std::string( " " );
|
||||
_out.print_line( str );
|
||||
|
||||
str.clear();
|
||||
str += lexical_cast< std::string >( width ) + std::string( " " );
|
||||
_out.print_line( str );
|
||||
|
||||
str.clear();
|
||||
str += lexical_cast< std::string >( height ) + std::string( " " );
|
||||
_out.print_line( str );
|
||||
|
||||
if( type != pnm_image_type::mono_bin_t::value )
|
||||
{
|
||||
_out.print_line( "255 ");
|
||||
}
|
||||
|
||||
// write data
|
||||
write_data( view
|
||||
, pitch
|
||||
, typename is_bit_aligned< pixel_t >::type()
|
||||
);
|
||||
}
|
||||
|
||||
template< typename View >
|
||||
void write_data( const View& src
|
||||
, std::size_t pitch
|
||||
, const mpl::true_& // bit_aligned
|
||||
)
|
||||
{
|
||||
BOOST_STATIC_ASSERT(( is_same< View
|
||||
, typename gray1_image_t::view_t
|
||||
>::value
|
||||
));
|
||||
|
||||
byte_vector_t row( pitch / 8 );
|
||||
|
||||
typedef typename View::x_iterator x_it_t;
|
||||
x_it_t row_it = x_it_t( &( *row.begin() ));
|
||||
|
||||
negate_bits< byte_vector_t
|
||||
, mpl::true_
|
||||
> neg;
|
||||
|
||||
mirror_bits< byte_vector_t
|
||||
, mpl::true_
|
||||
> mirror;
|
||||
|
||||
|
||||
for( typename View::y_coord_t y = 0; y < src.height(); ++y )
|
||||
{
|
||||
std::copy( src.row_begin( y )
|
||||
, src.row_end( y )
|
||||
, row_it
|
||||
);
|
||||
|
||||
mirror( row );
|
||||
neg ( row );
|
||||
|
||||
_out.write( &row.front()
|
||||
, pitch / 8
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
template< typename View >
|
||||
void write_data( const View& src
|
||||
, std::size_t pitch
|
||||
, const mpl::false_& // bit_aligned
|
||||
)
|
||||
{
|
||||
byte_vector_t buf( pitch );
|
||||
|
||||
typedef typename View::value_type pixel_t;
|
||||
typedef typename view_type_from_pixel< pixel_t >::type view_t;
|
||||
|
||||
view_t row = interleaved_view( src.width()
|
||||
, 1
|
||||
, reinterpret_cast< pixel_t* >( &buf.front() )
|
||||
, pitch
|
||||
);
|
||||
|
||||
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
|
||||
);
|
||||
|
||||
_out.write( &buf.front(), pitch );
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
Device& _out;
|
||||
};
|
||||
|
||||
struct pnm_write_is_supported
|
||||
{
|
||||
template< typename View >
|
||||
struct apply
|
||||
: public is_write_supported< typename get_pixel_type< View >::type
|
||||
, pnm_tag
|
||||
>
|
||||
{};
|
||||
};
|
||||
|
||||
template< typename Device >
|
||||
class dynamic_image_writer< Device
|
||||
, pnm_tag
|
||||
>
|
||||
: public writer< Device
|
||||
, pnm_tag
|
||||
>
|
||||
{
|
||||
typedef writer< Device
|
||||
, pnm_tag
|
||||
> parent_t;
|
||||
|
||||
public:
|
||||
|
||||
dynamic_image_writer( Device& file )
|
||||
: parent_t( file )
|
||||
{}
|
||||
|
||||
template< typename Views >
|
||||
void apply( const any_image_view< Views >& views )
|
||||
{
|
||||
dynamic_io_fnobj< pnm_write_is_supported
|
||||
, parent_t
|
||||
> op( this );
|
||||
|
||||
apply_operation( views, op );
|
||||
}
|
||||
};
|
||||
|
||||
} // detail
|
||||
} // gil
|
||||
} // boost
|
||||
|
||||
#endif // BOOST_GIL_EXTENSION_IO_JPEG_IO_WRITE_HPP
|
||||
Reference in New Issue
Block a user