| // 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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> |
| |
| #include <cstdlib> |
| #include <cstring> |
| #include <cstdio> |
| |
| #include <vips/vips.h> |
| #include <vips/internal.h> |
| #include <vips/debug.h> |
| |
| #include <vips/vipscpp.h> |
| |
| #ifdef WITH_DMALLOC |
| #include <dmalloc.h> |
| #endif /*WITH_DMALLOC*/ |
| |
| /* |
| #define DEBUG |
| */ |
| |
| VIPS_NAMESPACE_START |
| |
| void VImage::refblock::debug_print() |
| { |
| std::list<refblock *>::iterator i; |
| |
| printf( "refblock %p:\n", this ); |
| printf( " im = %p", im ); |
| if( im && im->filename ) |
| printf( " (im->filename = \"%s\")", im->filename ); |
| printf( "\n" ); |
| printf( " close_on_delete = %d\n", close_on_delete ); |
| printf( " nrefs (refs to us) = %d\n", nrefs ); |
| printf( " orefs (refs we make) = refblocks " ); |
| for( i = orefs.begin(); i != orefs.end(); i++ ) |
| printf( "%p ", *i ); |
| printf( "\n" ); |
| } |
| |
| // dump all refblocks for debugging |
| void VImage::print_all() |
| { |
| #ifdef DEBUG |
| std::list<VImage::refblock *>::iterator i; |
| |
| printf( "*** VImage::refblock::print_all() start\n" ); |
| for( i = all_refblock.begin(); i != all_refblock.end(); i++ ) |
| (*i)->debug_print(); |
| printf( "*** VImage::refblock::print_all() end\n" ); |
| #endif /*DEBUG*/ |
| } |
| |
| // easy call from C version |
| void im__ccp_print_all() |
| { |
| VImage::print_all(); |
| } |
| |
| // constructor |
| VImage::refblock::refblock() |
| { |
| im = 0; |
| close_on_delete = 1; |
| nrefs = 1; |
| |
| #ifdef DEBUG |
| all_refblock.push_front( this ); |
| #endif /*DEBUG*/ |
| } |
| |
| // Add a ref - this (output image) depends upon VipsImage in |
| void VImage::refblock::addref( refblock *in ) throw( VError ) |
| { |
| if( this == in ) |
| verror( "sanity failure" ); |
| |
| in->nrefs++; |
| orefs.push_front( in ); |
| } |
| |
| VImage::refblock::~refblock() throw( VError ) |
| { |
| #ifdef DEBUG |
| printf( "VImage::refblock::removeref(): death!\n" ); |
| debug_print(); |
| #endif /*DEBUG*/ |
| |
| std::list<refblock *>::iterator i; |
| |
| if( close_on_delete && im ) { |
| if( im_close( im ) ) |
| verror(); |
| im = 0; |
| } |
| |
| // remove any refs we have ... may trigger other destructs in turn |
| for( i = orefs.begin(); i != orefs.end(); i++ ) |
| (*i)->removeref(); |
| |
| #ifdef DEBUG |
| all_refblock.remove( this ); |
| #endif /*DEBUG*/ |
| } |
| |
| // Remove a ref |
| void VImage::refblock::removeref() throw( VError ) |
| { |
| nrefs--; |
| if( nrefs < 0 ) |
| verror( "too many closes!" ); |
| if( nrefs == 0 ) |
| delete this; |
| } |
| |
| // Init with name ... mode defaults to "r" |
| VImage::VImage( const char *name, const char *mode ) throw( VError ) |
| { |
| _ref = new refblock; |
| |
| if( !(_ref->im = im_open( name, mode )) ) |
| verror(); |
| _ref->close_on_delete = 1; |
| |
| #ifdef DEBUG |
| printf( "VImage::VImage( \"%s\", \"%s\" )\n", name, mode ); |
| _ref->debug_print(); |
| #endif /*DEBUG*/ |
| } |
| |
| // Build a VImage from an VipsImage structure |
| VImage::VImage( _VipsImage *in ) |
| { |
| _ref = new refblock; |
| |
| _ref->im = in; |
| _ref->close_on_delete = 0; |
| |
| #ifdef DEBUG |
| printf( "VImage::VImage( VipsImage* %p )\n", in ); |
| _ref->debug_print(); |
| #endif /*DEBUG*/ |
| } |
| |
| // Build from memory buffer |
| VImage::VImage( void *buffer, int width, int height, |
| int bands, TBandFmt format ) throw( VError ) |
| { |
| _ref = new refblock; |
| |
| if( !(_ref->im = im_image( buffer, width, height, |
| bands, VipsBandFmt( format ) )) ) |
| verror(); |
| _ref->close_on_delete = 1; |
| |
| #ifdef DEBUG |
| printf( "VImage::VImage( void* %p, %d, %d )\n", |
| buffer, width, height ); |
| _ref->debug_print(); |
| #endif /*DEBUG*/ |
| } |
| |
| // Empty init ... means open intermediate |
| VImage::VImage() throw( VError ) |
| { |
| static int id = 0; |
| char filename[256]; |
| |
| _ref = new refblock; |
| |
| /* This is not 100% safe if VIPS threading is not implemented on this |
| * platform ... but it doesn't really matter. |
| */ |
| g_mutex_lock( im__global_lock ); |
| im_snprintf( filename, 256, "intermediate image #%d", id++ ); |
| g_mutex_unlock( im__global_lock ); |
| |
| if( !(_ref->im = im_open( filename, "p" )) ) |
| verror(); |
| _ref->close_on_delete = 1; |
| |
| #ifdef DEBUG |
| printf( "VImage::VImage()\n" ); |
| _ref->debug_print(); |
| #endif /*DEBUG*/ |
| } |
| |
| // Copy constructor |
| VImage::VImage( const VImage &a ) |
| { |
| _ref = a._ref; |
| _ref->nrefs++; |
| } |
| |
| // Assignment |
| VImage &VImage::operator=( const VImage &a ) throw( VError ) |
| { |
| _ref->removeref(); |
| _ref = a._ref; |
| _ref->nrefs++; |
| |
| return( *this ); |
| } |
| |
| // Extract underlying data pointer |
| void *VImage::data() const throw( VError ) |
| { |
| if( im_incheck( _ref->im ) ) |
| verror(); |
| |
| return( (void *) _ref->im->data ); |
| } |
| |
| void VImage::debug_print() |
| { |
| im_printdesc( image() ); |
| } |
| |
| // Like jpeg2vips, but convert to a disc file rather than to memory |
| // We can handle huge files without running out of RAM |
| VImage VImage::convert2disc( const char* convert, |
| const char* in, const char* disc ) throw( VError ) |
| { |
| VImage out( disc, "w" ); |
| |
| Vargv _vec( convert ); |
| |
| _vec.data(0) = (im_object) in; |
| _vec.data(1) = out.image(); |
| _vec.call(); |
| |
| return( out ); |
| } |
| |
| // Write this to a VImage |
| VImage VImage::write( VImage out ) throw( VError ) |
| { |
| if( im_copy( _ref->im, out._ref->im ) ) |
| verror(); |
| out._ref->addref( _ref ); |
| |
| return( out ); |
| } |
| |
| VImage VImage::write( const char *name ) throw( VError ) |
| { |
| VImage out( name, "w" ); |
| |
| if( im_copy( _ref->im, out._ref->im ) ) |
| verror(); |
| out._ref->addref( _ref ); |
| |
| return( out ); |
| } |
| |
| VImage VImage::write() throw( VError ) |
| { |
| VImage out( "VImage:w1", "t" ); |
| |
| if( im_copy( _ref->im, out._ref->im ) ) |
| verror(); |
| out._ref->addref( _ref ); |
| |
| return( out ); |
| } |
| |
| // Projection functions to get header fields |
| int VImage::Xsize() { return( _ref->im->Xsize ); } |
| int VImage::Ysize() { return( _ref->im->Ysize ); } |
| int VImage::Bands() { return( _ref->im->Bands ); } |
| VImage::TBandFmt VImage::BandFmt() |
| { return( (TBandFmt) _ref->im->BandFmt ); } |
| VImage::TCoding VImage::Coding() |
| { return( (TCoding) _ref->im->Coding ); } |
| VImage::TType VImage::Type() { return( (TType) _ref->im->Type ); } |
| float VImage::Xres() { return( _ref->im->Xres ); } |
| float VImage::Yres() { return( _ref->im->Yres ); } |
| int VImage::Length() { return( _ref->im->Length ); } |
| VImage::TCompression VImage::Compression() |
| { return( (TCompression) _ref->im->Compression ); } |
| short VImage::Level() { return( _ref->im->Level ); } |
| int VImage::Xoffset() { return( _ref->im->Xoffset ); } |
| int VImage::Yoffset() { return( _ref->im->Yoffset ); } |
| |
| // Derived fields |
| const char *VImage::filename() { return( _ref->im->filename ); } |
| const char *VImage::Hist() { return( im_history_get( _ref->im ) ); } |
| |
| // metadata |
| |
| // base functionality |
| void VImage::meta_set( const char *field, GValue *value ) throw( VError ) |
| { |
| if( im_meta_set( _ref->im, field, value ) ) |
| verror(); |
| } |
| |
| gboolean VImage::meta_remove( const char *field ) |
| { |
| return( im_meta_remove( _ref->im, field ) ); |
| } |
| |
| void VImage::meta_get( const char *field, GValue *value_copy ) throw( VError ) |
| { |
| if( im_meta_get( _ref->im, field, value_copy ) ) |
| verror(); |
| } |
| |
| GType VImage::meta_get_typeof( const char *field ) |
| { |
| return( im_meta_get_typeof( _ref->im, field ) ); |
| } |
| |
| // convenience functions |
| int VImage::meta_get_int( const char *field ) |
| throw( VError ) |
| { |
| int result; |
| |
| if( im_meta_get_int( _ref->im, field, &result ) ) |
| verror(); |
| |
| return( result ); |
| } |
| |
| double VImage::meta_get_double( const char *field ) |
| throw( VError ) |
| { |
| double result; |
| |
| if( im_meta_get_double( _ref->im, field, &result ) ) |
| verror(); |
| |
| return( result ); |
| } |
| |
| const char *VImage::meta_get_string( const char *field ) |
| throw( VError ) |
| { |
| char *result; |
| |
| if( im_meta_get_string( _ref->im, field, &result ) ) |
| verror(); |
| |
| return( result ); |
| } |
| |
| void *VImage::meta_get_area( const char *field ) throw( VError ) |
| { |
| void *result; |
| |
| if( im_meta_get_area( _ref->im, field, &result ) ) |
| verror(); |
| |
| return( result ); |
| } |
| |
| void *VImage::meta_get_blob( const char *field, size_t *length ) throw( VError ) |
| { |
| void *result; |
| |
| if( im_meta_get_blob( _ref->im, field, &result, length ) ) |
| verror(); |
| |
| return( result ); |
| } |
| |
| void VImage::meta_set( const char *field, int value ) |
| throw( VError ) |
| { |
| if( im_meta_set_int( _ref->im, field, value ) ) |
| verror(); |
| } |
| |
| void VImage::meta_set( const char *field, double value ) |
| throw( VError ) |
| { |
| if( im_meta_set_double( _ref->im, field, value ) ) |
| verror(); |
| } |
| |
| void VImage::meta_set( const char *field, const char *value ) |
| throw( VError ) |
| { |
| if( im_meta_set_string( _ref->im, field, value ) ) |
| verror(); |
| } |
| |
| void VImage::meta_set( const char *field, |
| VCallback free_fn, void *value ) |
| throw( VError ) |
| { |
| if( im_meta_set_area( _ref->im, field, free_fn, value ) ) |
| verror(); |
| } |
| |
| void VImage::meta_set( const char *field, |
| VCallback free_fn, void *value, size_t length ) |
| throw( VError ) |
| { |
| if( im_meta_set_blob( _ref->im, field, free_fn, value, length ) ) |
| verror(); |
| } |
| |
| // Set header fields and setbuf() in one go. |
| void VImage::initdesc( int x, int y, int b, |
| TBandFmt f, TCoding c, TType t, float xr, float yr, int xo, int yo ) |
| throw( VError ) |
| { |
| im_initdesc( _ref->im, x, y, b, 0, |
| VipsBandFmt( f ), VipsCoding( c ), VipsType( t ), |
| xr, yr, xo, yo ); |
| if( im_setupout( _ref->im ) ) |
| verror(); |
| } |
| |
| // Create a Vargv from a name |
| Vargv::Vargv( const char *name ) |
| { |
| im_function *f = im_find_function( (char *) name ); |
| |
| if( !f ) |
| verror(); |
| |
| fn = (im__function *) f; |
| base = new im_object[f->argc]; |
| if( im_allocate_vargv( f, base ) ) { |
| delete[] base; |
| verror(); |
| } |
| } |
| |
| // Destroy a Vargv |
| Vargv::~Vargv() |
| { |
| im_function *f = (im_function *) fn; |
| |
| // free any memory allocated for input vectors |
| // this is the stuff allocated in each function during _object* build, |
| // see vipsc++.cc |
| for( int i = 0; i < f->argc; i++ ) { |
| im_type_desc *ty = f->argv[i].desc; |
| |
| if( !(ty->flags & IM_TYPE_OUTPUT) ) { |
| if( strcmp( ty->type, IM_TYPE_IMAGEVEC ) == 0 || |
| strcmp( ty->type, IM_TYPE_DOUBLEVEC ) == 0 || |
| strcmp( ty->type, IM_TYPE_INTVEC ) == 0 ) { |
| // will work for doublevec and intvec too |
| im_imagevec_object *io = |
| (im_imagevec_object *) base[i]; |
| |
| if( io->vec ) { |
| delete[] io->vec; |
| io->vec = NULL; |
| } |
| } |
| } |
| } |
| |
| im_free_vargv( f, base ); |
| delete[] base; |
| } |
| |
| // Call the function |
| void |
| Vargv::call() |
| { |
| im_function *f = (im_function *) fn; |
| |
| if( f->disp( base ) ) |
| verror(); |
| } |
| |
| /* Insert automatically generated wrappers for VIPS image processing |
| * functions. |
| */ |
| #include "vipsc++.cc" |
| |
| VIPS_NAMESPACE_END |