more cpp tinkering
This commit is contained in:
parent
ceb143a22a
commit
66445c359d
@ -6,8 +6,36 @@
|
||||
*/
|
||||
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include <iosfwd>
|
||||
#include <exception>
|
||||
|
||||
#include <vips/vips.h>
|
||||
#include <vips/debug.h>
|
||||
|
||||
class VError : public std::exception {
|
||||
std::string _what;
|
||||
|
||||
public:
|
||||
VError( std::string what ) : _what( what ) {}
|
||||
VError() : _what( vips_error_buffer() ) {}
|
||||
virtual ~VError() throw() {}
|
||||
|
||||
// Extract string
|
||||
virtual const char *what() const throw() { return _what.c_str(); }
|
||||
void ostream_print( std::ostream & ) const;
|
||||
};
|
||||
|
||||
inline std::ostream &operator<<( std::ostream &file, const VError &err )
|
||||
{
|
||||
err.ostream_print( file );
|
||||
return( file );
|
||||
}
|
||||
|
||||
void VError::ostream_print( std::ostream &file ) const
|
||||
{
|
||||
file << _what;
|
||||
}
|
||||
|
||||
enum VSteal {
|
||||
NOSTEAL = 0,
|
||||
@ -17,80 +45,120 @@ enum VSteal {
|
||||
class VObject
|
||||
{
|
||||
private:
|
||||
GObject *gobject;
|
||||
// can be NULL, see eg. VObject()
|
||||
VipsObject *vobject;
|
||||
|
||||
public:
|
||||
VObject( GObject *new_gobject, VSteal steal = STEAL ) :
|
||||
gobject( new_gobject )
|
||||
VObject( VipsObject *new_vobject, VSteal steal = STEAL ) :
|
||||
vobject( new_vobject )
|
||||
{
|
||||
g_assert( new_vobject &&
|
||||
VIPS_IS_OBJECT( new_vobject ) );
|
||||
|
||||
printf( "VObject constructor, obj = %p, steal = %d\n",
|
||||
new_gobject, steal );
|
||||
new_vobject, steal );
|
||||
if( !steal ) {
|
||||
printf( " reffing object\n" );
|
||||
g_object_ref( gobject );
|
||||
g_object_ref( vobject );
|
||||
}
|
||||
}
|
||||
|
||||
// copy constructor
|
||||
VObject( const VObject &vobject ) :
|
||||
gobject( vobject.gobject )
|
||||
VObject() :
|
||||
vobject( 0 )
|
||||
{
|
||||
}
|
||||
|
||||
// copy constructor
|
||||
VObject( const VObject &a ) :
|
||||
vobject( a.vobject )
|
||||
{
|
||||
g_assert( VIPS_IS_OBJECT( a.vobject ) );
|
||||
|
||||
printf( "VObject copy constructor, obj = %p\n",
|
||||
gobject );
|
||||
g_object_ref( gobject );
|
||||
vobject );
|
||||
g_object_ref( vobject );
|
||||
printf( " reffing object\n" );
|
||||
}
|
||||
|
||||
// assignment ... we must delete the old ref
|
||||
// old can be NULL, new must not be NULL
|
||||
VObject &operator=( const VObject &a )
|
||||
{
|
||||
GObject *old_gobject;
|
||||
VipsObject *old_vobject;
|
||||
|
||||
printf( "VObject assignment\n" );
|
||||
printf( " reffing %p\n", a.gobject );
|
||||
printf( " unreffing %p\n", gobject );
|
||||
printf( " reffing %p\n", a.vobject );
|
||||
printf( " unreffing %p\n", vobject );
|
||||
|
||||
g_assert( !vobject ||
|
||||
VIPS_IS_OBJECT( vobject ) );
|
||||
g_assert( a.vobject &&
|
||||
VIPS_IS_OBJECT( a.vobject ) );
|
||||
|
||||
// delete the old ref at the end ... otherwise "a = a;" could
|
||||
// unref before reffing again
|
||||
old_gobject = gobject;
|
||||
gobject = a.gobject;
|
||||
g_object_ref( gobject );
|
||||
g_object_unref( old_gobject );
|
||||
old_vobject = vobject;
|
||||
vobject = a.vobject;
|
||||
g_object_ref( vobject );
|
||||
if( old_vobject )
|
||||
g_object_unref( old_vobject );
|
||||
|
||||
return( *this );
|
||||
}
|
||||
|
||||
// this mustn't be virtual: we want this class to only be a pointer
|
||||
~VObject()
|
||||
{
|
||||
printf( "VObject destructor\n" );
|
||||
printf( " unreffing %p\n", gobject );
|
||||
printf( " unreffing %p\n", vobject );
|
||||
|
||||
g_assert( !vobject ||
|
||||
VIPS_IS_OBJECT( vobject ) );
|
||||
|
||||
g_object_unref( gobject );
|
||||
if( vobject )
|
||||
g_object_unref( vobject );
|
||||
}
|
||||
|
||||
GObject *get_object()
|
||||
VipsObject *get_object()
|
||||
{
|
||||
return( gobject );
|
||||
g_assert( !vobject ||
|
||||
VIPS_IS_OBJECT( vobject ) );
|
||||
|
||||
return( vobject );
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class VImage;
|
||||
class VOption;
|
||||
|
||||
class VOption
|
||||
{
|
||||
private:
|
||||
struct Pair {
|
||||
const char *name;
|
||||
GValue value = {0, };
|
||||
|
||||
Pair( const char *name ) : name( name )
|
||||
// the thing we pass to VipsOperation
|
||||
GValue value;
|
||||
|
||||
// we need to box and unbox VImage ... keep a pointer to the
|
||||
// VImage from C++ here
|
||||
VImage *vimage;
|
||||
|
||||
// keep a VipsImage pointer from VipsOperation here
|
||||
VipsImage *vips_image;
|
||||
|
||||
Pair( const char *name ) :
|
||||
name( name ), vimage( 0 ), vips_image( 0 )
|
||||
{
|
||||
G_VALUE_TYPE( &value ) = 0;
|
||||
}
|
||||
|
||||
~Pair()
|
||||
{
|
||||
g_value_unset( &value )
|
||||
g_value_unset( &value );
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
std::list<Pair *> options;
|
||||
|
||||
@ -99,65 +167,29 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
~VOption()
|
||||
{
|
||||
std::list<Pair *>::iterator i;
|
||||
virtual ~VOption();
|
||||
|
||||
for( i = options.begin(); i != options.end(); i++ )
|
||||
delete *i;
|
||||
}
|
||||
VOption set( const char *name, const char *value );
|
||||
VOption set( const char *name, int value );
|
||||
VOption set( const char *name, VImage value );
|
||||
VOption set( const char *name, VImage *value );
|
||||
|
||||
VOption set( const char *name, const char *value )
|
||||
{
|
||||
Pair *pair = new Pair( name );
|
||||
int set_operation( VipsOperation *operation );
|
||||
int get_operation( VipsOperation *operation );
|
||||
|
||||
g_value_init( &pair->value, G_TYPE_STRING );
|
||||
g_value_set_string( &pair->value, value );
|
||||
options.push_back( pair );
|
||||
|
||||
return( this );
|
||||
}
|
||||
|
||||
VOption set( const char *name, int value )
|
||||
{
|
||||
Pair *pair = new Pair( name );
|
||||
|
||||
g_value_init( &pair->value, G_TYPE_INT );
|
||||
g_value_set_int( &pair->value, value );
|
||||
options.push_back( pair );
|
||||
|
||||
return( this );
|
||||
}
|
||||
|
||||
VOption set( const char *name, VImage value )
|
||||
{
|
||||
Pair *pair = new Pair( name );
|
||||
|
||||
g_value_init( &pair->value, G_TYPE_OBJECT );
|
||||
g_value_set_object( &pair->value, value );
|
||||
options.push_back( pair );
|
||||
|
||||
return( this );
|
||||
}
|
||||
|
||||
VOption set( const char *name, VImage *value )
|
||||
{
|
||||
Pair *pair = new Pair( name );
|
||||
|
||||
g_value_init( &pair->value, G_TYPE_POINTER );
|
||||
g_value_set_pointer( &pair->value, value );
|
||||
options.push_back( pair );
|
||||
|
||||
return( this );
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
class VImage : VObject
|
||||
{
|
||||
public:
|
||||
VImage( VipsImage *image, VSteal steal = STEAL ) :
|
||||
VObject( (GObject *) image, steal )
|
||||
VObject( (VipsObject *) image, steal )
|
||||
{
|
||||
}
|
||||
|
||||
// an empty (NULL) VImage, eg. "VImage a;"
|
||||
VImage() :
|
||||
VObject( 0 )
|
||||
{
|
||||
}
|
||||
|
||||
@ -166,74 +198,228 @@ public:
|
||||
return( (VipsImage *) VObject::get_object() );
|
||||
}
|
||||
|
||||
VImage::VOption *option()
|
||||
static VOption *option()
|
||||
{
|
||||
return( new VOption() );
|
||||
}
|
||||
|
||||
void call_option_string( const char *operation_name,
|
||||
const char *option_string, VOption *options = 0 )
|
||||
throw( VError );
|
||||
void call( const char *operation_name, VOption *options = 0 )
|
||||
throw( VError );
|
||||
|
||||
VImage new_from_file( const char *name, VOption *options = 0 )
|
||||
{
|
||||
char filename[VIPS_PATH_MAX];
|
||||
char option_string[VIPS_PATH_MAX];
|
||||
const char *operation_name;
|
||||
|
||||
VImage out;
|
||||
|
||||
vips__filename_split8( name, filename, option_string );
|
||||
if( !(operation_name = vips_foreign_find_load( filename )) ) {
|
||||
delete options;
|
||||
throw VError();
|
||||
}
|
||||
|
||||
if( call_option_string( operation_name, option_string,
|
||||
options.set( "filename", filename ).
|
||||
set( "out", &out ) ) ) {
|
||||
delete options;
|
||||
throw VError();
|
||||
}
|
||||
|
||||
delete options;
|
||||
}
|
||||
throw( VError );
|
||||
|
||||
void write_to_file( const char *name, VOption *options = 0 )
|
||||
{
|
||||
char filename[VIPS_PATH_MAX];
|
||||
char option_string[VIPS_PATH_MAX];
|
||||
const char *operation_name;
|
||||
|
||||
vips__filename_split8( name, filename, option_string );
|
||||
if( !(operation_name = vips_foreign_find_save( filename )) ) {
|
||||
delete options;
|
||||
throw VError();
|
||||
}
|
||||
|
||||
if( call_option_string( operation_name, option_string,
|
||||
options.set( "in", this ).
|
||||
set( "filename", filename ) ) ) {
|
||||
delete options;
|
||||
throw VError();
|
||||
}
|
||||
|
||||
delete options;
|
||||
}
|
||||
throw( VError );
|
||||
|
||||
VImage invert( VOption *options = 0 )
|
||||
{
|
||||
VImage out;
|
||||
|
||||
if( call( "invert",
|
||||
options.set( "in", this ).
|
||||
set( "out", &out ) ) ) {
|
||||
delete options;
|
||||
throw VError();
|
||||
}
|
||||
delete options;
|
||||
|
||||
return( out );
|
||||
}
|
||||
throw( VError );
|
||||
|
||||
};
|
||||
|
||||
VOption::~VOption()
|
||||
{
|
||||
std::list<Pair *>::iterator i;
|
||||
|
||||
for( i = options.begin(); i != options.end(); i++ )
|
||||
delete *i;
|
||||
}
|
||||
|
||||
VOption VOption::set( const char *name, const char *value )
|
||||
{
|
||||
Pair *pair = new Pair( name );
|
||||
|
||||
g_value_init( &pair->value, G_TYPE_STRING );
|
||||
g_value_set_string( &pair->value, value );
|
||||
options.push_back( pair );
|
||||
|
||||
return( *this );
|
||||
}
|
||||
|
||||
VOption VOption::set( const char *name, int value )
|
||||
{
|
||||
Pair *pair = new Pair( name );
|
||||
|
||||
g_value_init( &pair->value, G_TYPE_INT );
|
||||
g_value_set_int( &pair->value, value );
|
||||
options.push_back( pair );
|
||||
|
||||
return( *this );
|
||||
}
|
||||
|
||||
VOption VOption::set( const char *name, VImage value )
|
||||
{
|
||||
Pair *pair = new Pair( name );
|
||||
|
||||
// we need to unbox
|
||||
g_value_init( &pair->value, G_TYPE_OBJECT );
|
||||
g_value_set_pointer( &pair->value, value.get_image() );
|
||||
options.push_back( pair );
|
||||
|
||||
return( *this );
|
||||
}
|
||||
|
||||
VOption VOption::set( const char *name, VImage *value )
|
||||
{
|
||||
Pair *pair = new Pair( name );
|
||||
|
||||
// where we will write the VImage on success
|
||||
pair->vimage = value;
|
||||
|
||||
// get VipsOperation to write the VipsImage * here
|
||||
g_value_init( &pair->value, G_TYPE_POINTER );
|
||||
g_value_set_pointer( &pair->value, &pair->vips_image );
|
||||
options.push_back( pair );
|
||||
|
||||
return( *this );
|
||||
}
|
||||
|
||||
// walk the options and set props on the operation
|
||||
int VOption::set_operation( VipsOperation *operation )
|
||||
{
|
||||
std::list<Pair *>::iterator i;
|
||||
|
||||
for( i = options.begin(); i != options.end(); i++ )
|
||||
if( vips_object_set( VIPS_OBJECT( operation ),
|
||||
(*i)->name, &(*i)->value,
|
||||
NULL ) )
|
||||
return( -1 );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
// walk the options and do any processing needed for output objects
|
||||
int VOption::get_operation( VipsOperation *operation )
|
||||
{
|
||||
std::list<Pair *>::iterator i;
|
||||
|
||||
for( i = options.begin(); i != options.end(); i++ )
|
||||
if( (*i)->vimage )
|
||||
*((*i)->vimage) = VImage( (*i)->vips_image );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
void VImage::call_option_string( const char *operation_name,
|
||||
const char *option_string, VOption *options )
|
||||
throw( VError )
|
||||
{
|
||||
VipsOperation *operation;
|
||||
|
||||
VIPS_DEBUG_MSG( "vips_call_by_name: starting for %s ...\n",
|
||||
operation_name );
|
||||
|
||||
if( !(operation = vips_operation_new( operation_name )) ) {
|
||||
if( options )
|
||||
delete options;
|
||||
throw( VError() );
|
||||
}
|
||||
|
||||
/* Set str options before vargs options, so the user can't
|
||||
* override things we set deliberately.
|
||||
*/
|
||||
if( option_string &&
|
||||
vips_object_set_from_string( VIPS_OBJECT( operation ),
|
||||
option_string ) ) {
|
||||
vips_object_unref_outputs( VIPS_OBJECT( operation ) );
|
||||
g_object_unref( operation );
|
||||
delete options;
|
||||
throw( VError() );
|
||||
}
|
||||
|
||||
if( options &&
|
||||
options->set_operation( operation ) ) {
|
||||
g_object_unref( operation );
|
||||
delete options;
|
||||
throw( VError() );
|
||||
}
|
||||
|
||||
/* Build from cache.
|
||||
*/
|
||||
if( vips_cache_operation_buildp( &operation ) ) {
|
||||
vips_object_unref_outputs( VIPS_OBJECT( operation ) );
|
||||
delete options;
|
||||
throw( VError() );
|
||||
}
|
||||
|
||||
/* Walk args again, writing output.
|
||||
*/
|
||||
if( options &&
|
||||
options->get_operation( operation ) ) {
|
||||
vips_object_unref_outputs( VIPS_OBJECT( operation ) );
|
||||
delete options;
|
||||
throw( VError() );
|
||||
}
|
||||
|
||||
/* The operation we have built should now have been reffed by
|
||||
* one of its arguments or have finished its work. Either
|
||||
* way, we can unref.
|
||||
*/
|
||||
g_object_unref( operation );
|
||||
}
|
||||
|
||||
void VImage::call( const char *operation_name, VOption *options )
|
||||
throw( VError )
|
||||
{
|
||||
call_option_string( operation_name, NULL, options );
|
||||
}
|
||||
|
||||
VImage VImage::new_from_file( const char *name, VOption *options )
|
||||
throw( VError )
|
||||
{
|
||||
char filename[VIPS_PATH_MAX];
|
||||
char option_string[VIPS_PATH_MAX];
|
||||
const char *operation_name;
|
||||
|
||||
VImage out;
|
||||
|
||||
vips__filename_split8( name, filename, option_string );
|
||||
if( !(operation_name = vips_foreign_find_load( filename )) ) {
|
||||
delete options;
|
||||
throw VError();
|
||||
}
|
||||
|
||||
call_option_string( operation_name, option_string,
|
||||
(options ? options : VImage::option())->
|
||||
set( "filename", filename )->
|
||||
set( "out", &out ) );
|
||||
}
|
||||
|
||||
void VImage::write_to_file( const char *name, VOption *options )
|
||||
throw( VError )
|
||||
{
|
||||
char filename[VIPS_PATH_MAX];
|
||||
char option_string[VIPS_PATH_MAX];
|
||||
const char *operation_name;
|
||||
|
||||
vips__filename_split8( name, filename, option_string );
|
||||
if( !(operation_name = vips_foreign_find_save( filename )) ) {
|
||||
delete options;
|
||||
throw VError();
|
||||
}
|
||||
|
||||
call_option_string( operation_name, option_string,
|
||||
(options ? options : VImage::option())->
|
||||
set( "in", this )->
|
||||
set( "filename", filename ) );
|
||||
}
|
||||
|
||||
VImage VImage::invert( VOption *options )
|
||||
throw( VError )
|
||||
{
|
||||
VImage out;
|
||||
|
||||
call( "invert",
|
||||
(options ? options : VImage::option())->
|
||||
set( "in", this )->
|
||||
set( "out", &out ) );
|
||||
|
||||
return( out );
|
||||
}
|
||||
|
||||
int
|
||||
main( int argc, char **argv )
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user