WIP. Scale cover art option. Seems to work

This commit is contained in:
emeric
2014-06-14 20:44:03 +02:00
parent 1d67a548c9
commit 9bada5ee2a
92 changed files with 15866 additions and 1890 deletions
@@ -0,0 +1,39 @@
/*
Copyright 2010 Christian Henning
Use, modification and distribution are subject to the Boost Software License,
Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
http://www.boost.org/LICENSE_1_0.txt).
*/
/*************************************************************************************************/
#ifndef BOOST_GIL_EXTENSION_IO_DETAIL_JPEG_IO_BASE_HPP
#define BOOST_GIL_EXTENSION_IO_DETAIL_JPEG_IO_BASE_HPP
////////////////////////////////////////////////////////////////////////////////////////
/// \file
/// \brief
/// \author Christian Henning \n
///
/// \date 2010 \n
///
////////////////////////////////////////////////////////////////////////////////////////
#include <boost/gil/extension/io_new/jpeg_tags.hpp>
namespace boost { namespace gil { namespace detail {
class jpeg_io_base
{
protected:
jpeg_error_mgr _jerr;
jmp_buf _mark;
};
} // namespace detail
} // namespace gil
} // namespace boost
#endif // BOOST_GIL_EXTENSION_IO_DETAIL_JPEG_IO_BASE_HPP
@@ -0,0 +1,54 @@
/*
Copyright 2009 Christian Henning
Use, modification and distribution are subject to the Boost Software License,
Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
http://www.boost.org/LICENSE_1_0.txt).
*/
/*************************************************************************************************/
#ifndef BOOST_GIL_EXTENSION_IO_JPEG_IO_IS_ALLOWED_HPP
#define BOOST_GIL_EXTENSION_IO_JPEG_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< jpeg_tag >& info
, mpl::true_ // is read_and_no_convert
)
{
if( info._color_space == JCS_YCbCr )
{
// We read JCS_YCbCr files as rgb.
return ( is_read_supported< typename View::value_type
, jpeg_tag
>::_color_space == JCS_RGB );
}
return ( is_read_supported< typename View::value_type
, jpeg_tag
>::_color_space == info._color_space );
}
template< typename View >
bool is_allowed( const image_read_info< jpeg_tag >& /* info */
, mpl::false_ // is read_and_convert
)
{
return true;
}
} // namespace detail
} // namespace gil
} // namespace boost
#endif // BOOST_GIL_EXTENSION_IO_JPEG_IO_IS_ALLOWED_HPP
@@ -0,0 +1,418 @@
/*
Copyright 2007-2008 Christian Henning, Andreas Pokorny, Lubomir Bourdev
Use, modification and distribution are subject to the Boost Software License,
Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
http://www.boost.org/LICENSE_1_0.txt).
*/
/*************************************************************************************************/
#ifndef BOOST_GIL_EXTENSION_IO_JPEG_IO_READ_HPP
#define BOOST_GIL_EXTENSION_IO_JPEG_IO_READ_HPP
////////////////////////////////////////////////////////////////////////////////////////
/// \file
/// \brief
/// \author Christian Henning, Andreas Pokorny, Lubomir Bourdev \n
///
/// \date 2007-2008 \n
///
////////////////////////////////////////////////////////////////////////////////////////
#include <csetjmp>
#include <vector>
#include <boost/gil/extension/io_new/jpeg_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/reader_base.hpp>
#include <boost/gil/extension/io_new/detail/io_device.hpp>
#include <boost/gil/extension/io_new/detail/typedefs.hpp>
#include "base.hpp"
#include "is_allowed.hpp"
namespace boost { namespace gil { namespace detail {
template<typename Device>
struct jpeg_decompress_mgr : public jpeg_io_base
{
jpeg_decompress_mgr( Device& file )
: in(file)
{
_cinfo.err = jpeg_std_error( &_jerr );
_cinfo.client_data = this;
// Error exit handler: does not return to caller.
_jerr.error_exit = &jpeg_decompress_mgr::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 )>( &jpeg_decompress_mgr< Device >::init_device );
_src._jsrc.fill_input_buffer = reinterpret_cast< boolean(*)( j_decompress_ptr )>( &jpeg_decompress_mgr< Device >::fill_buffer );
_src._jsrc.skip_input_data = reinterpret_cast< void(*) ( j_decompress_ptr
, long num_bytes
) >( &jpeg_decompress_mgr< Device >::skip_input_data );
_src._jsrc.term_source = reinterpret_cast< void(*) ( j_decompress_ptr ) >( &jpeg_decompress_mgr< Device >::close_device );
_src._jsrc.resync_to_restart = jpeg_resync_to_restart;
_src._this = this;
jpeg_create_decompress( &_cinfo );
_cinfo.src = &_src._jsrc;
jpeg_read_header( &_cinfo
, TRUE );
io_error_if( _cinfo.data_precision != 8
, "Image file is not supported."
);
}
~jpeg_decompress_mgr()
{
jpeg_destroy_decompress( &_cinfo );
}
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 )
{
jpeg_decompress_mgr< Device >* mgr = reinterpret_cast< jpeg_decompress_mgr< Device >* >( 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->in.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* ) {}
protected:
jpeg_decompress_struct _cinfo;
private:
Device &in;
struct gil_jpeg_source_mgr
{
jpeg_source_mgr _jsrc;
jpeg_decompress_mgr* _this;
};
gil_jpeg_source_mgr _src;
// libjpeg default is 4096 - see jdatasrc.c
JOCTET buffer[4096];
};
template< typename Device
, typename ConversionPolicy
>
class reader< Device
, jpeg_tag
, ConversionPolicy
>
: public jpeg_decompress_mgr< Device >
, public reader_base< jpeg_tag
, ConversionPolicy >
{
public:
reader( Device& device
, const image_read_settings< jpeg_tag >& settings
)
: jpeg_decompress_mgr<Device>( device )
, reader_base< jpeg_tag
, ConversionPolicy >( settings )
{}
reader( Device& device
, const typename ConversionPolicy::color_converter_type& cc
, const image_read_settings< jpeg_tag >& settings
)
: jpeg_decompress_mgr< Device >( device )
, reader_base< jpeg_tag
, ConversionPolicy >( cc
, settings
)
{}
image_read_info< jpeg_tag > get_info()
{
image_read_info<jpeg_tag> ret;
ret._width = this->_cinfo.image_width;
ret._height = this->_cinfo.image_height;
ret._num_components = this->_cinfo.num_components;
ret._color_space = this->_cinfo.jpeg_color_space;
ret._data_precision = this->_cinfo.data_precision;
return ret;
}
template<typename View>
void apply( const View& view )
{
// Fire exception in case of error.
if( setjmp( this->_mark )) { this->raise_error(); }
jpeg_decompress_struct& cinfo = this->_cinfo;
cinfo.dct_method = this->_settings._dct_method;
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."
);
if( jpeg_start_decompress( &this->_cinfo ) == false )
{
io_error( "Cannot start decompression." );
}
switch( this->_info._color_space )
{
case JCS_GRAYSCALE: { read_rows< gray8_pixel_t >( view ); break; }
case JCS_RGB: { read_rows< rgb8_pixel_t >( view ); break; }
//!\todo add Y'CbCr? We loose image quality when reading JCS_YCbCr as JCS_RGB
case JCS_YCbCr: { read_rows< rgb8_pixel_t >( view ); break; }
case JCS_CMYK: { read_rows< cmyk8_pixel_t >( view ); break; }
//!\todo add Y'CbCrK? We loose image quality when reading JCS_YCCK as JCS_CMYK
case JCS_YCCK:
{
this->_cinfo.out_color_space = JCS_CMYK;
read_rows< cmyk8_pixel_t >( view );
break;
}
default: { io_error( "Unsupported jpeg color space." ); }
}
jpeg_finish_decompress ( &this->_cinfo );
}
private:
template< typename ImagePixel
, typename View
>
void read_rows( const View& view )
{
typedef std::vector<ImagePixel> buffer_t;
buffer_t buffer( this->_info._width );
// In case of an error we'll jump back to here and fire an exception.
// @todo Is the buffer above cleaned up when the exception is thrown?
// The strategy right now is to allocate necessary memory before
// the setjmp.
if( setjmp( this->_mark )) { this->raise_error(); }
JSAMPLE *row_adr = reinterpret_cast< JSAMPLE* >( &buffer[0] );
//Skip scanlines if necessary.
for( int y = 0; y < this->_settings._top_left.y; ++y )
{
io_error_if( jpeg_read_scanlines( &this->_cinfo
, &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->_cinfo
, &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->_cinfo.output_scanline < this->_cinfo.image_height )
{
io_error_if( jpeg_read_scanlines( &this->_cinfo
, &row_adr
, 1
) !=1
, "jpeg_read_scanlines: fail to read JPEG file"
);
}
}
};
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
>
{};
};
template< typename Device
>
class dynamic_image_reader< Device
, jpeg_tag
>
: public reader< Device
, jpeg_tag
, detail::read_and_no_convert
>
{
typedef reader< Device
, jpeg_tag
, detail::read_and_no_convert
> parent_t;
public:
dynamic_image_reader( Device& device
, const image_read_settings< jpeg_tag >& settings
)
: parent_t( device
, settings
)
{}
template< typename Images >
void apply( any_image< Images >& images )
{
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
{
init_image( images
, this->_info
);
dynamic_io_fnobj< jpeg_read_is_supported
, parent_t
> op( this );
apply_operation( view( images )
, op
);
}
}
};
} // detail
} // gil
} // boost
#endif // BOOST_GIL_EXTENSION_IO_JPEG_IO_READ_HPP
@@ -0,0 +1,121 @@
/*
Copyright 2007-2008 Christian Henning, Andreas Pokorny, Lubomir Bourdev
Use, modification and distribution are subject to the Boost Software License,
Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
http://www.boost.org/LICENSE_1_0.txt).
*/
/*************************************************************************************************/
#ifndef BOOST_GIL_EXTENSION_IO_JPEG_SUPPORTED_TYPES_HPP
#define BOOST_GIL_EXTENSION_IO_JPEG_SUPPORTED_TYPES_HPP
////////////////////////////////////////////////////////////////////////////////////////
/// \file
/// \brief
/// \author Christian Henning, Andreas Pokorny, Lubomir Bourdev \n
///
/// \date 2007-2008 \n
///
////////////////////////////////////////////////////////////////////////////////////////
#include <boost/mpl/not.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/gil/channel.hpp>
#include <boost/gil/color_base.hpp>
namespace boost { namespace gil { namespace detail {
// Read support
template< jpeg_color_space::type ColorSpace >
struct jpeg_rw_support_base
{
static const jpeg_color_space::type _color_space = ColorSpace;
};
template< typename Channel
, typename ColorSpace
>
struct jpeg_read_support : read_support_false
, jpeg_rw_support_base< JCS_UNKNOWN > {};
template<>
struct jpeg_read_support< bits8
, rgb_t
> : read_support_true
, jpeg_rw_support_base< JCS_RGB > {};
template<>
struct jpeg_read_support< bits8
, cmyk_t
> : read_support_true
, jpeg_rw_support_base< JCS_CMYK > {};
template<>
struct jpeg_read_support< bits8
, 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< bits8
, gray_t
> : write_support_true
, jpeg_rw_support_base< JCS_GRAYSCALE > {};
template<>
struct jpeg_write_support< bits8
, rgb_t
> : write_support_true
, jpeg_rw_support_base< JCS_RGB > {};
template<>
struct jpeg_write_support< bits8
, cmyk_t
> : write_support_true
, jpeg_rw_support_base< JCS_CMYK > {};
} // namespace detail
template< typename Pixel >
struct is_read_supported< Pixel
, jpeg_tag
>
: mpl::bool_< detail::jpeg_read_support< typename channel_type< Pixel >::type
, typename color_space_type< Pixel >::type
>::is_supported
>
{
typedef detail::jpeg_read_support< typename channel_type< Pixel >::type
, typename color_space_type< Pixel >::type
> parent_t;
static const typename jpeg_color_space::type _color_space = parent_t::_color_space;
};
template< typename Pixel >
struct is_write_supported< Pixel
, jpeg_tag
>
: mpl::bool_< detail::jpeg_write_support< typename channel_type< Pixel >::type
, typename color_space_type< Pixel >::type
>::is_supported
>
{};
} // namespace gil
} // namespace boost
#endif // BOOST_GIL_EXTENSION_IO_JPEG_SUPPORTED_TYPES_HPP
@@ -0,0 +1,317 @@
/*
Copyright 2007-2008 Christian Henning, Andreas Pokorny, Lubomir Bourdev
Use, modification and distribution are subject to the Boost Software License,
Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
http://www.boost.org/LICENSE_1_0.txt).
*/
/*************************************************************************************************/
#ifndef BOOST_GIL_EXTENSION_IO_JPEG_IO_WRITE_HPP
#define BOOST_GIL_EXTENSION_IO_JPEG_IO_WRITE_HPP
////////////////////////////////////////////////////////////////////////////////////////
/// \file
/// \brief
/// \author Christian Henning, Andreas Pokorny, Lubomir Bourdev \n
///
/// \date 2007-2008 \n
///
////////////////////////////////////////////////////////////////////////////////////////
#include <vector>
#include <boost/gil/extension/io_new/detail/base.hpp>
#include <boost/gil/extension/io_new/detail/io_device.hpp>
#include <boost/gil/extension/io_new/jpeg_tags.hpp>
#include "base.hpp"
#include "supported_types.hpp"
namespace boost { namespace gil { namespace detail {
template< typename Device >
class writer< Device
, jpeg_tag
> : public jpeg_io_base
{
public:
writer( Device& file )
: out( file )
{
_cinfo.err = jpeg_std_error( &_jerr );
_cinfo.client_data = this;
// Error exit handler: does not return to caller.
_jerr.error_exit = &writer< Device, jpeg_tag >::error_exit;
// Fire exception in case of error.
if( setjmp( _mark )) { raise_error(); }
_dest._jdest.free_in_buffer = sizeof( buffer );
_dest._jdest.next_output_byte = buffer;
_dest._jdest.init_destination = reinterpret_cast< void(*) ( j_compress_ptr ) >( &writer< Device, jpeg_tag >::init_device );
_dest._jdest.empty_output_buffer = reinterpret_cast< boolean(*)( j_compress_ptr ) >( &writer< Device, jpeg_tag >::empty_buffer );
_dest._jdest.term_destination = reinterpret_cast< void(*) ( j_compress_ptr ) >( &writer< Device, jpeg_tag >::close_device );
_dest._this = this;
jpeg_create_compress( &_cinfo );
_cinfo.dest = &_dest._jdest;
}
~writer()
{
jpeg_finish_compress ( &_cinfo );
jpeg_destroy_compress( &_cinfo );
}
template<typename View>
void apply( const View& view )
{
write_rows( view
, jpeg_quality::default_value
, jpeg_dct_method::default_value
);
}
template< typename View >
void apply( const View& view
, const image_write_info< jpeg_tag >& info )
{
write_rows( view
, info._quality
, info._dct_method
);
}
private:
template<typename View>
void write_rows( const View& view
, const jpeg_quality::type quality
, const jpeg_dct_method::type dct_method
)
{
std::vector< typename View::value_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( _mark )) { raise_error(); }
typedef typename channel_type< typename View::value_type >::type channel_t;
_cinfo.image_width = JDIMENSION( view.width() );
_cinfo.image_height = JDIMENSION( view.height() );
_cinfo.input_components = num_channels<View>::value;
_cinfo.in_color_space = detail::jpeg_write_support< channel_t
, typename color_space_type< View >::type
>::_color_space;
jpeg_set_defaults( &_cinfo );
jpeg_set_quality ( &_cinfo
, quality
, TRUE
);
// Needs to be done after jpeg_set_defaults() since it's overridding this value back to slow.
_cinfo.dct_method = dct_method;
jpeg_start_compress( &_cinfo
, 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->_cinfo
, &row_addr
, 1
);
}
}
struct gil_jpeg_destination_mgr
{
jpeg_destination_mgr _jdest;
writer<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->out.write( dest->_this->buffer
, buffer_size
);
writer<Device,jpeg_tag>::init_device( cinfo );
return 1;
}
static void close_device( jpeg_compress_struct* cinfo )
{
writer<Device,jpeg_tag>::empty_buffer( cinfo );
gil_jpeg_destination_mgr* dest = reinterpret_cast< gil_jpeg_destination_mgr* >( cinfo->dest );
dest->_this->out.flush();
}
void raise_error()
{
io_error( "Cannot write jpeg file." );
}
static void error_exit( j_common_ptr cinfo )
{
writer< Device, jpeg_tag >* mgr = reinterpret_cast< writer< Device, jpeg_tag >* >( cinfo->client_data );
longjmp( mgr->_mark, 1 );
}
private:
Device &out;
jpeg_compress_struct _cinfo;
gil_jpeg_destination_mgr _dest;
static const unsigned int buffer_size = 1024;
JOCTET buffer[buffer_size];
};
struct jpeg_write_is_supported
{
template< typename View >
struct apply
: public is_write_supported< typename get_pixel_type< View >::type
, jpeg_tag
>
{};
};
// unary application
template <typename Types, typename Tag, typename Bits, typename Op>
typename Op::result_type GIL_FORCEINLINE apply_operation_basec( const Bits& bits
, std::size_t index
, const image_write_info< Tag >& info
, Op op
)
{
return detail::apply_operation_fwd_fn<mpl::size<Types>::value>().template applyc<Types>( bits
, index
, op
);
}
// unary application
template< typename Types
, typename Info
, typename Bits
, typename Op
>
typename Op::result_type GIL_FORCEINLINE apply_operation_base( Bits& bits
, std::size_t index
, const Info& info
, Op op
)
{
return detail::apply_operation_fwd_fn< mpl::size< Types >::value>().template apply< Types
>( bits
, index
, info
, op
);
}
/// \ingroup Variant
/// \brief Invokes a generic constant operation (represented as a binary function object) on two variants
template< typename Types1
, typename Info
, typename BinaryOp
>
GIL_FORCEINLINE
typename BinaryOp::result_type apply_operation( const variant< Types1 >& arg1
, const Info& info
, BinaryOp op
)
{
typename variant< Types1 >::base_t bits = arg1.bits();
return apply_operation_base< Types1
, image_write_info< jpeg_tag >
>( bits
, arg1.index()
, info
, op
);
}
template< typename Device >
class dynamic_image_writer< Device
, jpeg_tag
>
: public writer< Device
, jpeg_tag
>
{
typedef writer< Device
, jpeg_tag
> parent_t;
public:
dynamic_image_writer( Device& file )
: parent_t( file )
{}
template< typename Views >
void apply( const any_image_view< Views >& views )
{
dynamic_io_fnobj< jpeg_write_is_supported
, parent_t
> op( this );
apply_operation( views, op );
}
template< typename Views >
void apply( const any_image_view < Views >& views
, const image_write_info< jpeg_tag >& info
)
{
dynamic_io_fnobj< jpeg_write_is_supported
, parent_t
> op( this );
apply_operation( views, info, op );
}
};
} // detail
} // gil
} // boost
#endif // BOOST_GIL_EXTENSION_IO_JPEG_IO_WRITE_HPP