libvips/cplusplus/VImage.cc

510 lines
11 KiB
C++
Raw Normal View History

2014-10-20 12:50:34 +02:00
// Object part of VImage class
/*
Copyright (C) 1991-2001 The National Gallery
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
/*
These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif /*HAVE_CONFIG_H*/
#include <vips/intl.h>
2014-10-27 14:41:44 +01:00
#include <vips/vips8>
2014-10-20 12:50:34 +02:00
#include <vips/debug.h>
/*
*/
2014-10-27 15:17:33 +01:00
#define VIPS_DEBUG
#define DEBUG
2014-10-20 12:50:34 +02:00
VIPS_NAMESPACE_START
2014-10-27 14:41:44 +01:00
VOption::~VOption()
2014-10-20 12:50:34 +02:00
{
2014-10-27 14:41:44 +01:00
std::list<Pair *>::iterator i;
2014-10-20 12:50:34 +02:00
2014-10-27 14:41:44 +01:00
for( i = options.begin(); i != options.end(); i++ )
delete *i;
2014-10-20 12:50:34 +02:00
}
2014-10-28 11:12:06 +01:00
// input bool
VOption *VOption::set( const char *name, bool value )
2014-10-20 12:50:34 +02:00
{
2014-10-27 14:41:44 +01:00
Pair *pair = new Pair( name );
2014-10-20 12:50:34 +02:00
2014-10-27 14:41:44 +01:00
pair->input = true;
2014-10-28 11:12:06 +01:00
g_value_init( &pair->value, G_TYPE_BOOLEAN );
g_value_set_boolean( &pair->value, value );
2014-10-27 14:41:44 +01:00
options.push_back( pair );
2014-10-27 14:41:44 +01:00
return( this );
2014-10-21 15:55:38 +02:00
}
2014-10-27 15:17:33 +01:00
// input int ... this path is used for enums as well
2014-10-27 14:41:44 +01:00
VOption *VOption::set( const char *name, int value )
2014-10-21 15:55:38 +02:00
{
2014-10-27 14:41:44 +01:00
Pair *pair = new Pair( name );
2014-10-27 14:41:44 +01:00
pair->input = true;
g_value_init( &pair->value, G_TYPE_INT );
g_value_set_int( &pair->value, value );
options.push_back( pair );
2014-10-27 14:41:44 +01:00
return( this );
}
2014-10-21 15:55:38 +02:00
2014-10-28 11:12:06 +01:00
// input double
VOption *VOption::set( const char *name, double value )
{
Pair *pair = new Pair( name );
pair->input = true;
g_value_init( &pair->value, G_TYPE_DOUBLE );
g_value_set_double( &pair->value, value );
options.push_back( pair );
return( this );
}
VOption *VOption::set( const char *name, const char *value )
{
Pair *pair = new Pair( name );
pair->input = true;
g_value_init( &pair->value, G_TYPE_STRING );
g_value_set_string( &pair->value, value );
options.push_back( pair );
return( this );
}
2014-10-27 15:17:33 +01:00
// input image
2014-10-27 14:41:44 +01:00
VOption *VOption::set( const char *name, VImage value )
{
Pair *pair = new Pair( name );
2014-10-21 15:55:38 +02:00
2014-10-27 14:41:44 +01:00
pair->input = true;
g_value_init( &pair->value, VIPS_TYPE_IMAGE );
// we need to unbox
g_value_set_object( &pair->value, value.get_image() );
options.push_back( pair );
2014-10-21 15:55:38 +02:00
2014-10-27 14:41:44 +01:00
return( this );
}
2014-10-21 15:55:38 +02:00
2014-10-27 19:17:49 +01:00
// input double array
VOption *VOption::set( const char *name, std::vector<double> value )
{
Pair *pair = new Pair( name );
double *array;
unsigned int i;
pair->input = true;
vips_value_set_array_double( &pair->value, NULL, value.size() );
array = vips_value_get_array_double( &pair->value, NULL );
for( i = 0; i < value.size(); i++ )
array[i] = value[i];
options.push_back( pair );
return( this );
}
// input image array
VOption *VOption::set( const char *name, std::vector<VImage> value )
{
Pair *pair = new Pair( name );
VipsImage **array;
unsigned int i;
pair->input = true;
vips_value_set_array_image( &pair->value, value.size() );
array = vips_value_get_array_image( &pair->value, NULL );
for( i = 0; i < value.size(); i++ ) {
VipsImage *vips_image = value[i].get_image();
array[i] = vips_image;
g_object_ref( vips_image );
}
options.push_back( pair );
return( this );
}
2014-10-28 11:12:06 +01:00
// input blob
VOption *VOption::set( const char *name, VipsBlob *value )
{
Pair *pair = new Pair( name );
pair->input = true;
g_value_init( &pair->value, VIPS_TYPE_BLOB );
g_value_set_boxed( &pair->value, value );
options.push_back( pair );
return( this );
}
// output bool
VOption *VOption::set( const char *name, bool *value )
2014-10-27 14:41:44 +01:00
{
Pair *pair = new Pair( name );
2014-10-21 15:55:38 +02:00
2014-10-27 14:41:44 +01:00
// note where we will write the VImage on success
pair->input = false;
2014-10-28 11:12:06 +01:00
pair->vbool = value;
g_value_init( &pair->value, G_TYPE_BOOLEAN );
options.push_back( pair );
return( this );
}
// output int
VOption *VOption::set( const char *name, int *value )
{
Pair *pair = new Pair( name );
// note where we will write the VImage on success
pair->input = false;
pair->vint = value;
g_value_init( &pair->value, G_TYPE_INT );
2014-10-21 15:55:38 +02:00
2014-10-27 14:41:44 +01:00
options.push_back( pair );
2014-10-21 15:55:38 +02:00
2014-10-27 14:41:44 +01:00
return( this );
}
2014-10-21 15:55:38 +02:00
2014-10-27 19:17:49 +01:00
// output double
VOption *VOption::set( const char *name, double *value )
{
Pair *pair = new Pair( name );
// note where we will write the VImage on success
pair->input = false;
pair->vdouble = value;
g_value_init( &pair->value, G_TYPE_DOUBLE );
options.push_back( pair );
return( this );
}
2014-10-28 11:12:06 +01:00
// output image
VOption *VOption::set( const char *name, VImage *value )
2014-10-27 19:17:49 +01:00
{
Pair *pair = new Pair( name );
// note where we will write the VImage on success
pair->input = false;
2014-10-28 11:12:06 +01:00
pair->vimage = value;
g_value_init( &pair->value, VIPS_TYPE_IMAGE );
2014-10-27 19:17:49 +01:00
options.push_back( pair );
return( this );
}
// output doublearray
2014-10-28 11:12:06 +01:00
VOption *VOption::set( const char *name, std::vector<double> *value )
2014-10-27 19:17:49 +01:00
{
Pair *pair = new Pair( name );
// note where we will write the VImage on success
pair->input = false;
2014-10-28 11:12:06 +01:00
pair->vvector = value;
options.push_back( pair );
return( this );
}
// output blob
VOption *VOption::set( const char *name, VipsBlob **value )
{
Pair *pair = new Pair( name );
pair->input = false;
pair->vblob = value;
2014-10-27 19:17:49 +01:00
options.push_back( pair );
return( this );
}
2014-10-27 14:41:44 +01:00
// walk the options and set props on the operation
void VOption::set_operation( VipsOperation *operation )
{
std::list<Pair *>::iterator i;
for( i = options.begin(); i != options.end(); i++ )
if( (*i)->input ) {
2014-10-27 15:17:33 +01:00
#ifdef DEBUG
2014-10-27 14:41:44 +01:00
printf( "set_operation: " );
vips_object_print_name( VIPS_OBJECT( operation ) );
char *str_value =
g_strdup_value_contents( &(*i)->value );
printf( ".%s = %s\n", (*i)->name, str_value );
g_free( str_value );
2014-10-27 15:17:33 +01:00
#endif /*DEBUG*/
2014-10-27 14:41:44 +01:00
g_object_set_property( G_OBJECT( operation ),
(*i)->name, &(*i)->value );
2014-10-21 15:55:38 +02:00
}
2014-10-27 14:41:44 +01:00
}
2014-10-21 15:55:38 +02:00
2014-10-27 14:41:44 +01:00
// walk the options and do any processing needed for output objects
void VOption::get_operation( VipsOperation *operation )
{
std::list<Pair *>::iterator i;
for( i = options.begin(); i != options.end(); i++ )
if( not (*i)->input ) {
2014-10-27 19:17:49 +01:00
const char *name = (*i)->name;
GValue *value = &(*i)->value;
2014-10-27 14:41:44 +01:00
g_object_get_property( G_OBJECT( operation ),
2014-10-27 19:17:49 +01:00
name, value );
2014-10-27 14:41:44 +01:00
2014-10-27 15:17:33 +01:00
#ifdef DEBUG
2014-10-27 14:41:44 +01:00
printf( "get_operation: " );
vips_object_print_name( VIPS_OBJECT( operation ) );
2014-10-27 19:17:49 +01:00
char *str_value = g_strdup_value_contents( value );
printf( ".%s = %s\n", name, str_value );
2014-10-27 14:41:44 +01:00
g_free( str_value );
2014-10-27 15:17:33 +01:00
#endif /*DEBUG*/
2014-10-27 14:41:44 +01:00
2014-10-27 19:17:49 +01:00
GType type = G_VALUE_TYPE( value );
if( type == VIPS_TYPE_IMAGE ) {
// rebox object
VipsImage *image = VIPS_IMAGE(
g_value_get_object( value ) );
2014-10-27 14:41:44 +01:00
*((*i)->vimage) = VImage( image );
2014-10-27 19:17:49 +01:00
}
else if( type == G_TYPE_INT )
*((*i)->vint) = g_value_get_int( value );
2014-10-28 11:12:06 +01:00
else if( type == G_TYPE_BOOLEAN )
*((*i)->vbool) = g_value_get_boolean( value );
2014-10-27 19:17:49 +01:00
else if( type == G_TYPE_DOUBLE )
*((*i)->vdouble) = g_value_get_double( value );
2014-10-27 19:17:49 +01:00
else if( type == VIPS_TYPE_ARRAY_DOUBLE ) {
int length;
double *array =
vips_value_get_array_double( value,
&length );
int j;
2014-10-28 11:12:06 +01:00
((*i)->vvector)->resize( length );
2014-10-27 19:17:49 +01:00
for( j = 0; j < length; j++ )
2014-10-28 11:12:06 +01:00
(*((*i)->vvector))[j] = array[j];
}
else if( type == VIPS_TYPE_BLOB ) {
*((*i)->vblob) =
(VipsBlob *) g_value_get_boxed( value );
2014-10-27 19:17:49 +01:00
}
2014-10-27 14:41:44 +01:00
}
2014-10-21 15:55:38 +02:00
}
2014-10-27 14:41:44 +01:00
void VImage::call_option_string( const char *operation_name,
const char *option_string, VOption *options )
throw( VError )
2014-10-21 15:55:38 +02:00
{
VipsOperation *operation;
2014-10-27 14:41:44 +01:00
VIPS_DEBUG_MSG( "vips_call_by_name: starting for %s ...\n",
operation_name );
2014-10-21 15:55:38 +02:00
2014-10-27 14:41:44 +01:00
if( !(operation = vips_operation_new( operation_name )) ) {
if( options )
delete options;
throw( VError() );
}
2014-10-21 15:55:38 +02:00
2014-10-27 14:41:44 +01:00
/* 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() );
}
2014-10-21 15:55:38 +02:00
2014-10-27 14:41:44 +01:00
if( options )
options->set_operation( operation );
2014-10-21 15:55:38 +02:00
2014-10-27 14:41:44 +01:00
/* Build from cache.
2014-10-21 15:55:38 +02:00
*/
2014-10-27 14:41:44 +01:00
if( vips_cache_operation_buildp( &operation ) ) {
2014-10-21 15:55:38 +02:00
vips_object_unref_outputs( VIPS_OBJECT( operation ) );
2014-10-27 14:41:44 +01:00
delete options;
throw( VError() );
}
2014-10-21 15:55:38 +02:00
2014-10-27 14:41:44 +01:00
/* Walk args again, writing output.
2014-10-21 15:55:38 +02:00
*/
2014-10-27 14:41:44 +01:00
if( options )
options->get_operation( operation );
2014-10-20 12:50:34 +02:00
2014-10-27 14:41:44 +01:00
/* We're done with options!
*/
delete options;
2014-10-20 12:50:34 +02:00
2014-10-27 14:41:44 +01:00
/* 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 );
2014-10-20 12:50:34 +02:00
}
2014-10-27 14:41:44 +01:00
void VImage::call( const char *operation_name, VOption *options )
2014-10-21 15:55:38 +02:00
throw( VError )
2014-10-20 12:50:34 +02:00
{
2014-10-27 14:41:44 +01:00
call_option_string( operation_name, NULL, options );
2014-10-20 12:50:34 +02:00
}
2014-10-27 14:41:44 +01:00
VImage VImage::new_from_file( const char *name, VOption *options )
2014-10-20 12:50:34 +02:00
throw( VError )
{
2014-10-20 15:54:03 +02:00
char filename[VIPS_PATH_MAX];
char option_string[VIPS_PATH_MAX];
const char *operation_name;
2014-10-27 14:41:44 +01:00
VImage out;
2014-10-20 12:50:34 +02:00
2014-10-20 15:54:03 +02:00
vips__filename_split8( name, filename, option_string );
2014-10-27 14:41:44 +01:00
if( !(operation_name = vips_foreign_find_load( filename )) ) {
delete options;
2014-10-20 15:54:03 +02:00
throw VError();
2014-10-27 14:41:44 +01:00
}
2014-10-20 12:50:34 +02:00
2014-10-27 14:41:44 +01:00
call_option_string( operation_name, option_string,
(options ? options : VImage::option())->
set( "filename", filename )->
set( "out", &out ) );
2014-10-20 12:50:34 +02:00
2014-10-27 14:41:44 +01:00
return( out );
2014-10-20 12:50:34 +02:00
}
2014-10-27 14:41:44 +01:00
void VImage::write_to_file( const char *name, VOption *options )
2014-10-20 12:50:34 +02:00
throw( VError )
{
2014-10-20 15:54:03 +02:00
char filename[VIPS_PATH_MAX];
char option_string[VIPS_PATH_MAX];
const char *operation_name;
2014-10-20 12:50:34 +02:00
2014-10-27 14:41:44 +01:00
vips__filename_split8( name, filename, option_string );
if( !(operation_name = vips_foreign_find_save( filename )) ) {
delete options;
2014-10-20 15:54:03 +02:00
throw VError();
2014-10-27 14:41:44 +01:00
}
2014-10-20 12:50:34 +02:00
2014-10-27 14:41:44 +01:00
call_option_string( operation_name, option_string,
(options ? options : VImage::option())->
set( "in", *this )->
set( "filename", filename ) );
2014-10-20 12:50:34 +02:00
}
2014-10-20 15:54:03 +02:00
#include "vips-operators.cc"
2014-10-20 12:50:34 +02:00
VImage VImage::linear( double a, double b, VOption *options )
throw( VError )
{
double av[1] = { a };
std::vector<double> avec( av, av + VIPS_NUMBER( av ) );
double bv[1] = { b };
std::vector<double> bvec( bv, bv + VIPS_NUMBER( bv ) );
VImage out;
call( "linear",
(options ? options : VImage::option()) ->
set( "out", &out ) ->
set( "in", *this ) ->
set( "a", avec ) ->
set( "b", bvec ) );
return( out );
}
std::vector<VImage> VImage::bandsplit( VOption *options )
throw( VError )
{
std::vector<VImage> bands;
for( int i = 0; i < this->bands(); i++ )
bands.push_back( this->extract_band( i ) );
return( bands );
}
VImage VImage::bandjoin( VImage other, VOption *options )
throw( VError )
{
VImage v[2] = { *this, other };
std::vector<VImage> vec( v, v + VIPS_NUMBER( v ) );
return( bandjoin( vec, options ) );
}
std::complex<double> VImage::minpos( VOption *options )
throw( VError )
{
double x, y;
(void) this->min(
(options ? options : VImage::option()) ->
set( "x", &x ) ->
set( "y", &y ) );
return( std::complex<double>( x, y ) );
}
std::complex<double> VImage::maxpos( VOption *options )
throw( VError )
{
double x, y;
(void) this->max(
(options ? options : VImage::option()) ->
set( "x", &x ) ->
set( "y", &y ) );
return( std::complex<double>( x, y ) );
}
2014-10-20 12:50:34 +02:00
VIPS_NAMESPACE_END