From 7257c5426a027e993d1d7901fbeafc58043b49da Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Tue, 1 Mar 2011 14:49:16 +0000 Subject: [PATCH] split vips_new_*() modes up New modes and properties mean we can use _build() for all the vipsimage init stuff now. --- libvips/include/vips/image.h | 10 +- libvips/include/vips/internal.h | 2 +- libvips/include/vips/region.h | 6 +- libvips/iofuncs/Makefile.am | 2 - libvips/iofuncs/dispatch_types.c | 9 +- libvips/iofuncs/im_cp_desc.c | 2 +- libvips/iofuncs/im_demand_hint.c | 21 +- libvips/iofuncs/im_generate.c | 31 ++- libvips/iofuncs/im_image.c | 102 --------- libvips/iofuncs/im_mapfile.c | 40 ++-- libvips/iofuncs/im_partial.c | 65 ------ libvips/iofuncs/im_prepare.c | 124 ++--------- libvips/iofuncs/image.c | 360 +++++++++++++++++++++---------- libvips/iofuncs/vips.c | 2 +- 14 files changed, 342 insertions(+), 434 deletions(-) delete mode 100644 libvips/iofuncs/im_image.c delete mode 100644 libvips/iofuncs/im_partial.c diff --git a/libvips/include/vips/image.h b/libvips/include/vips/image.h index 990f7bb3..1fa91e3f 100644 --- a/libvips/include/vips/image.h +++ b/libvips/include/vips/image.h @@ -290,7 +290,7 @@ typedef struct _VipsImageClass { /* An image has been modified in some way and downstream caches all * need dropping. */ - int (*invalidate)( VipsImage *image ); + void (*invalidate)( VipsImage *image ); } VipsImageClass; @@ -348,11 +348,17 @@ int vips_image_get_yoffset( VipsImage *image ); size_t vips_image_size( VipsImage *image ); void vips_image_written( VipsImage *image ); +void vips_image_invalidate_all( VipsImage *image ); void vips_image_preeval( VipsImage *image ); void vips_image_eval( VipsImage *image, int w, int h ); void vips_image_posteval( VipsImage *image ); -VipsImage *vips_image_open( const char *filename, const char *mode ); +VipsImage *vips_image_new( const char *mode ); +VipsImage *vips_image_new_from_file( const char *filename, const char *mode ); +VipsImage *vips_image_new_from_file_raw( const char *filename, + int xsize, int ysize, int bands, int offset ); +VipsImage *vips_image_new_from_memory( void *buffer, + int xsize, int ysize, int bands, VipsBandFormat bandfmt ); gboolean vips_image_isMSBfirst( VipsImage *image ); gboolean vips_image_isfile( VipsImage *image ); diff --git a/libvips/include/vips/internal.h b/libvips/include/vips/internal.h index 35f1dae5..5d2af381 100644 --- a/libvips/include/vips/internal.h +++ b/libvips/include/vips/internal.h @@ -80,7 +80,7 @@ typedef int (*im__fftproc_fn)( VipsImage *, VipsImage *, VipsImage * ); /* iofuncs */ int vips_open_input( VipsImage *image ); -int vips_open_input_rw( VipsImage *image ); +int vips_image_open_input( VipsImage *image ); int im_mapfile( VipsImage * ); int im_mapfilerw( VipsImage * ); diff --git a/libvips/include/vips/region.h b/libvips/include/vips/region.h index 47efc58c..eeae59be 100644 --- a/libvips/include/vips/region.h +++ b/libvips/include/vips/region.h @@ -96,7 +96,7 @@ void im_region_copy( REGION *reg, REGION *dest, Rect *r, int x, int y ); #define IM_REGION_N_ELEMENTS(R) \ ((size_t)((R)->valid.width * (R)->im->Bands)) #define IM_REGION_SIZEOF_LINE(R) \ - ((size_t)((R)->valid.width * IM_IMAGE_SIZEOF_PEL((R)->im))) + ((size_t)((R)->valid.width * VIPS_IMAGE_SIZEOF_PEL((R)->im))) /* If DEBUG is defined, add bounds checking. */ @@ -104,7 +104,7 @@ void im_region_copy( REGION *reg, REGION *dest, Rect *r, int x, int y ); #define IM_REGION_ADDR(R,X,Y) \ ( (im_rect_includespoint( &(R)->valid, (X), (Y) ))? \ ((R)->data + ((Y) - (R)->valid.top) * IM_REGION_LSKIP(R) + \ - ((X) - (R)->valid.left) * IM_IMAGE_SIZEOF_PEL((R)->im)): \ + ((X) - (R)->valid.left) * VIPS_IMAGE_SIZEOF_PEL((R)->im)): \ (fprintf( stderr, \ "IM_REGION_ADDR: point out of bounds, " \ "file \"%s\", line %d\n" \ @@ -122,7 +122,7 @@ void im_region_copy( REGION *reg, REGION *dest, Rect *r, int x, int y ); #define IM_REGION_ADDR(R,X,Y) \ ((R)->data + \ ((Y)-(R)->valid.top) * IM_REGION_LSKIP(R) + \ - ((X)-(R)->valid.left) * IM_IMAGE_SIZEOF_PEL((R)->im)) + ((X)-(R)->valid.left) * VIPS_IMAGE_SIZEOF_PEL((R)->im)) #endif /*DEBUG*/ #define IM_REGION_ADDR_TOPLEFT(R) ( (R)->data ) diff --git a/libvips/iofuncs/Makefile.am b/libvips/iofuncs/Makefile.am index f6110b2a..9b741b32 100644 --- a/libvips/iofuncs/Makefile.am +++ b/libvips/iofuncs/Makefile.am @@ -15,9 +15,7 @@ libiofuncs_la_SOURCES = \ im_demand_hint.c \ im_generate.c \ im_histlin.c \ - im_image.c \ im_mapfile.c \ - im_partial.c \ im_prepare.c \ im_setbuf.c \ im_setupout.c \ diff --git a/libvips/iofuncs/dispatch_types.c b/libvips/iofuncs/dispatch_types.c index e124aac1..3b0b6b13 100644 --- a/libvips/iofuncs/dispatch_types.c +++ b/libvips/iofuncs/dispatch_types.c @@ -113,7 +113,7 @@ input_image_init( im_object *obj, char *str ) { IMAGE **im = (IMAGE **) obj; - return( !(*im = vips_image_open( str, "rd" )) ); + return( !(*im = vips_image_new_from_file( str, "rd" )) ); } /* Input image type. @@ -133,7 +133,7 @@ output_image_init( im_object *obj, char *str ) { IMAGE **im = (IMAGE **) obj; - return( !(*im = vips_image_open( str, "w" )) ); + return( !(*im = vips_image_new_from_file( str, "w" )) ); } /* Output image type. @@ -153,7 +153,7 @@ rw_image_init( im_object *obj, char *str ) { IMAGE **im = (IMAGE **) obj; - return( !(*im = vips_image_open( str, "rw" )) ); + return( !(*im = vips_image_new_from_file( str, "rw" )) ); } /* RW image type. @@ -215,7 +215,8 @@ input_imagevec_init( im_object *obj, char *str ) iv->vec[i] = NULL; for( i = 0; i < nargs; i++ ) - if( !(iv->vec[i] = vips_image_open( strv[i], "rd" )) ) { + if( !(iv->vec[i] = + vips_image_new_from_file( strv[i], "rd" )) ) { g_strfreev( strv ); return( -1 ); } diff --git a/libvips/iofuncs/im_cp_desc.c b/libvips/iofuncs/im_cp_desc.c index a94dd4f5..bed1d0b0 100644 --- a/libvips/iofuncs/im_cp_desc.c +++ b/libvips/iofuncs/im_cp_desc.c @@ -170,7 +170,7 @@ im_cp_descv( IMAGE *out, IMAGE *in1, ... ) ; va_end( ap ); if( i == MAX_IMAGES ) { - im_error( "im_cp_descv", + vips_error( "im_cp_descv", "%s", _( "too many images" ) ); return( -1 ); } diff --git a/libvips/iofuncs/im_demand_hint.c b/libvips/iofuncs/im_demand_hint.c index 60fe52be..bb6ff76a 100644 --- a/libvips/iofuncs/im_demand_hint.c +++ b/libvips/iofuncs/im_demand_hint.c @@ -150,6 +150,19 @@ im__link_map( IMAGE *im, VSListMap2Fn fn, void *a, void *b ) { static int serial = 0; + /* Invalidate callbacks might do anything, including removing images + * or invalidating other images, so we can't trigger them from within + * the image loop. Instead we collect a list of image to invalidate + * and trigger them all in one go, checking that they are not + * invalidated. + */ + + /* im__link_mapp() needs to make the list, ref all the images, call + * the callbacks, then unref and free the list. + */ + + FIXME + serial += 1; return( im__link_mapp( im, fn, &serial, a, b ) ); } @@ -159,7 +172,7 @@ im__link_map( IMAGE *im, VSListMap2Fn fn, void *a, void *b ) static im_demand_type find_least( im_demand_type a, im_demand_type b ) { - return( (im_demand_type) IM_MIN( (int) a, (int) b ) ); + return( (im_demand_type) VIPS_MIN( (int) a, (int) b ) ); } /** @@ -191,7 +204,7 @@ im_demand_hint_array( IMAGE *im, VipsDemandStyle hint, IMAGE **in ) /* How many input images are there? And how many are IM_ANY? */ for( i = 0, len = 0, nany = 0; in[i]; i++, len++ ) - if( in[i]->dhint == IM_ANY ) + if( in[i]->dhint == VIPS_DEMAND_STYLE_ANY ) nany++; set_hint = hint; @@ -206,7 +219,7 @@ im_demand_hint_array( IMAGE *im, VipsDemandStyle hint, IMAGE **in ) /* Special case: if all the inputs are IM_ANY, then output can * be IM_ANY regardless of what this function wants. */ - set_hint = IM_ANY; + set_hint = VIPS_DEMAND_STYLE_ANY; else /* Find the most restrictive of all the hints available to us. */ @@ -263,7 +276,7 @@ im_demand_hint( IMAGE *im, VipsDemandStyle hint, ... ) ; va_end( ap ); if( i == MAX_IMAGES ) { - im_error( "im_demand_hint", "%s", _( "too many images" ) ); + vips_error( "im_demand_hint", "%s", _( "too many images" ) ); return( -1 ); } diff --git a/libvips/iofuncs/im_generate.c b/libvips/iofuncs/im_generate.c index 8ac8c485..fc055de0 100644 --- a/libvips/iofuncs/im_generate.c +++ b/libvips/iofuncs/im_generate.c @@ -207,7 +207,7 @@ im_start_many( IMAGE *out, void *a, void *b ) /* Alocate space for region array. */ - if( !(ar = IM_ARRAY( NULL, n + 1, REGION * )) ) + if( !(ar = VIPS_ARRAY( NULL, n + 1, REGION * )) ) return( NULL ); /* Create a set of regions. @@ -251,7 +251,7 @@ im_allocate_input_array( IMAGE *out, ... ) /* Allocate array. */ - if( !(ar = IM_ARRAY( out, n + 1, IMAGE * )) ) + if( !(ar = VIPS_ARRAY( out, n + 1, IMAGE * )) ) return( NULL ); /* Fill array. @@ -365,13 +365,13 @@ im_generate( IMAGE *im, g_assert( !im_image_sanity( im ) ); if( !im->hint_set ) { - im_error( "im_generate", + vips_error( "im_generate", "%s", _( "im_demand_hint() not set" ) ); return( -1 ); } if( im->Xsize <= 0 || im->Ysize <= 0 || im->Bands <= 0 ) { - im_error( "im_generate", + vips_error( "im_generate", "%s", _( "bad dimensions" ) ); return( -1 ); } @@ -384,11 +384,11 @@ im_generate( IMAGE *im, /* Look at output type to decide our action. */ switch( im->dtype ) { - case IM_PARTIAL: + case VIPS_IMAGE_PARTIAL: /* Output to partial image. Just attach functions and return. */ if( im->generate || im->start || im->stop ) { - im_error( "im_generate", + vips_error( "im_generate", "%s", _( "func already attached" ) ); return( -1 ); } @@ -405,14 +405,14 @@ im_generate( IMAGE *im, break; - case IM_SETBUF: - case IM_SETBUF_FOREIGN: - case IM_MMAPINRW: - case IM_OPENOUT: + case VIPS_IMAGE_SETBUF: + case VIPS_IMAGE_SETBUF_FOREIGN: + case VIPS_IMAGE_MMAPINRW: + case VIPS_IMAGE_OPENOUT: /* Eval now .. sanity check. */ if( im->generate || im->start || im->stop ) { - im_error( "im_generate", + vips_error( "im_generate", "%s", _( "func already attached" ) ); return( -1 ); } @@ -430,7 +430,7 @@ im_generate( IMAGE *im, im->client1 = a; im->client2 = b; - if( im->dtype == IM_OPENOUT ) + if( im->dtype == VIPS_IMAGE_OPENOUT ) res = vips_sink_disc( im, (VipsRegionWrite) write_vips, NULL ); else @@ -446,15 +446,12 @@ im_generate( IMAGE *im, default: /* Not a known output style. */ - im_error( "im_generate", _( "unable to output to a %s image" ), + vips_error( "im_generate", _( "unable to output to a %s image" ), im_dtype2char( im->dtype ) ); return( -1 ); } - /* Successful write: trigger "written". - */ - if( im__trigger_callbacks( im->writtenfns ) ) - return( -1 ); + vips_image_written( im ); return( 0 ); } diff --git a/libvips/iofuncs/im_image.c b/libvips/iofuncs/im_image.c deleted file mode 100644 index 4d888a66..00000000 --- a/libvips/iofuncs/im_image.c +++ /dev/null @@ -1,102 +0,0 @@ -/* im_image.c ... area of memory as an image - * - * Written on: 11/7/00 - * Modified on: - * 20/3/01 JC - * - oops, broken for IM_BANDFMT_UCHAR - */ - -/* - - This file is part of VIPS. - - VIPS 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 -#endif /*HAVE_CONFIG_H*/ -#include - -#include -#include - -#include -#include - -#ifdef WITH_DMALLOC -#include -#endif /*WITH_DMALLOC*/ - -/** - * im_image: - * @buffer: start of memory area - * @xsize: image width - * @ysize: image height - * @bands: image bands (or bytes per pixel) - * @bandfmt: image format - * - * This function wraps an #IMAGE around a memory buffer. VIPS does not take - * responsibility for the area of memory, it's up to you to make sure it's - * freed when the image is closed. See for example im_add_close_callback(). - * - * See also: im_binfile(), im_raw2vips(), im_open(). - * - * Returns: the new #IMAGE, or %NULL on error. - */ -IMAGE * -im_image( void *buffer, int xsize, int ysize, int bands, VipsBandFmt bandfmt ) -{ - IMAGE *im; - - if( xsize <= 0 || ysize <= 0 || bands <= 0 || - bandfmt < 0 || bandfmt > IM_BANDFMT_DPCOMPLEX ) { - im_error( "im_image", "%s", _( "bad parameters" ) ); - return( NULL ); - } - - /* Make new output image for us. - */ - if( !(im = im_init( "untitled" )) ) - return( NULL ); - - /* Set header fields. - */ - im->Xsize = xsize; - im->Ysize = ysize; - im->Bands = bands; - im->BandFmt = bandfmt; - im->Bbits = im_bits_of_fmt( bandfmt ); - im->Coding = IM_CODING_NONE; - - if( bands == 1 ) - im->Type = IM_TYPE_B_W; - else if( bands == 3 ) - im->Type = IM_TYPE_RGB; - else - im->Type = IM_TYPE_MULTIBAND; - - im->data = (char *) buffer; - im->dtype = IM_SETBUF_FOREIGN; - - return( im ); -} diff --git a/libvips/iofuncs/im_mapfile.c b/libvips/iofuncs/im_mapfile.c index a09e5bd8..d090a809 100644 --- a/libvips/iofuncs/im_mapfile.c +++ b/libvips/iofuncs/im_mapfile.c @@ -138,17 +138,17 @@ im__mmap( int fd, int writeable, size_t length, gint64 offset ) if( !(hMMFile = CreateFileMapping( hFile, NULL, flProtect, 0, 0, NULL )) ) { - im_error_system( GetLastError(), "im_mapfile", + vips_error_system( GetLastError(), "im_mapfile", "%s", _( "unable to CreateFileMapping" ) ); - printf( "CreateFileMapping failed: %s\n", im_error_buffer() ); + printf( "CreateFileMapping failed: %s\n", vips_error_buffer() ); return( NULL ); } if( !(baseaddr = (char *)MapViewOfFile( hMMFile, dwDesiredAccess, dwFileOffsetHigh, dwFileOffsetLow, length )) ) { - im_error_system( GetLastError(), "im_mapfile", + vips_error_system( GetLastError(), "im_mapfile", "%s", _( "unable to MapViewOfFile" ) ); - printf( "MapViewOfFile failed: %s\n", im_error_buffer() ); + printf( "MapViewOfFile failed: %s\n", vips_error_buffer() ); CloseHandle( hMMFile ); return( NULL ); } @@ -186,9 +186,9 @@ im__mmap( int fd, int writeable, size_t length, gint64 offset ) baseaddr = mmap( 0, length, prot, MAP_SHARED, fd, (off_t) offset ); if( baseaddr == MAP_FAILED ) { - im_error_system( errno, "im_mapfile", + vips_error_system( errno, "im_mapfile", "%s", _( "unable to mmap" ) ); - im_warn( "im_mapfile", _( "map failed (%s), " + vips_warn( "im_mapfile", _( "map failed (%s), " "running very low on system resources, " "expect a crash soon" ), strerror( errno ) ); return( NULL ); @@ -204,13 +204,13 @@ im__munmap( void *start, size_t length ) { #ifdef OS_WIN32 if( !UnmapViewOfFile( start ) ) { - im_error_system( GetLastError(), "im_mapfile", + vips_error_system( GetLastError(), "im_mapfile", "%s", _( "unable to UnmapViewOfFile" ) ); return( -1 ); } #else /*!OS_WIN32*/ if( munmap( start, length ) < 0 ) { - im_error_system( errno, "im_mapfile", + vips_error_system( errno, "im_mapfile", "%s", _( "unable to munmap file" ) ); return( -1 ); } @@ -232,18 +232,18 @@ im_mapfile( IMAGE *im ) */ g_assert( im->file_length > 0 ); if( im->file_length < 64 ) { - im_error( "im_mapfile", + vips_error( "im_mapfile", "%s", _( "file is less than 64 bytes" ) ); return( -1 ); } if( fstat( im->fd, &st ) == -1 ) { - im_error( "im_mapfile", + vips_error( "im_mapfile", "%s", _( "unable to get file status" ) ); return( -1 ); } m = (mode_t) st.st_mode; if( !S_ISREG( m ) ) { - im_error( "im_mapfile", + vips_error( "im_mapfile", "%s", _( "not a regular file" ) ); return( -1 ); } @@ -271,13 +271,13 @@ im_mapfilerw( IMAGE *im ) */ g_assert( im->file_length > 0 ); if( fstat( im->fd, &st ) == -1 ) { - im_error( "im_mapfilerw", + vips_error( "im_mapfilerw", "%s", _( "unable to get file status" ) ); return( -1 ); } m = (mode_t) st.st_mode; if( im->file_length < 64 || !S_ISREG( m ) ) { - im_error( "im_mapfile", + vips_error( "im_mapfile", "%s", _( "unable to read data" ) ); return( -1 ); } @@ -305,19 +305,19 @@ im_remapfilerw( IMAGE *image ) if( !(hMMFile = CreateFileMapping( hFile, NULL, PAGE_READWRITE, 0, 0, NULL )) ) { - im_error_system( GetLastError(), "im_mapfile", + vips_error_system( GetLastError(), "im_mapfile", "%s", _( "unable to CreateFileMapping" ) ); return( -1 ); } if( !UnmapViewOfFile( image->baseaddr ) ) { - im_error_system( GetLastError(), "im_mapfile", + vips_error_system( GetLastError(), "im_mapfile", "%s", _( "unable to UnmapViewOfFile" ) ); return( -1 ); } if( !(baseaddr = (char *)MapViewOfFileEx( hMMFile, FILE_MAP_WRITE, 0, 0, 0, image->baseaddr )) ) { - im_error_system( GetLastError(), "im_mapfile", + vips_error_system( GetLastError(), "im_mapfile", "%s", _( "unable to MapViewOfFile" ) ); CloseHandle( hMMFile ); return( -1 ); @@ -332,23 +332,23 @@ im_remapfilerw( IMAGE *image ) } #else /*!OS_WIN32*/ { - assert( image->dtype == IM_MMAPIN ); + assert( image->dtype == VIPS_IMAGE_MMAPIN ); baseaddr = mmap( image->baseaddr, image->length, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED, image->fd, 0 ); if( baseaddr == (void *)-1 ) { - im_error( "im_mapfile", _( "unable to mmap: \"%s\" - %s" ), + vips_error( "im_mapfile", _( "unable to mmap: \"%s\" - %s" ), image->filename, strerror( errno ) ); return( -1 ); } } #endif /*OS_WIN32*/ - image->dtype = IM_MMAPINRW; + image->dtype = VIPS_IMAGE_MMAPINRW; if( baseaddr != image->baseaddr ) { - im_error( "im_mapfile", _( "unable to mmap \"%s\" to same " + vips_error( "im_mapfile", _( "unable to mmap \"%s\" to same " "address" ), image->filename ); image->baseaddr = baseaddr; return( -1 ); diff --git a/libvips/iofuncs/im_partial.c b/libvips/iofuncs/im_partial.c deleted file mode 100644 index f569d4de..00000000 --- a/libvips/iofuncs/im_partial.c +++ /dev/null @@ -1,65 +0,0 @@ -/* @(#) im_partial: initialise a partial IMAGE. Just set im->dtype. - * @(#) - * @(#) IMAGE * - * @(#) im_partial( file_name ) - * @(#) char *file_name; - * @(#) - */ - -/* - - This file is part of VIPS. - - VIPS 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 -#endif /*HAVE_CONFIG_H*/ -#include - -#include -#include -#include - -#include -#include - -#ifdef WITH_DMALLOC -#include -#endif /*WITH_DMALLOC*/ - -IMAGE * -im_partial( const char *filename ) -{ - IMAGE *im = im_init( filename ); - - if( !im ) - return(NULL); - im->dtype = IM_PARTIAL; - - /* No need to set demand style - im_demand_hint() from application - * will do this. - */ - - return( im ); -} diff --git a/libvips/iofuncs/im_prepare.c b/libvips/iofuncs/im_prepare.c index ce43b5fb..a3d9d26d 100644 --- a/libvips/iofuncs/im_prepare.c +++ b/libvips/iofuncs/im_prepare.c @@ -99,7 +99,7 @@ im__test_kill( IMAGE *im ) /* Has kill been set for this image? If yes, abort evaluation. */ if( im->kill ) { - im_error( "im__test_kill", _( "killed for image \"%s\"" ), + vips_error( "im__test_kill", _( "killed for image \"%s\"" ), im->filename ); return( -1 ); } @@ -162,18 +162,18 @@ im_prepare( REGION *reg, Rect *r ) #endif /*DEBUG*/ switch( im->dtype ) { - case IM_PARTIAL: + case VIPS_IMAGE_PARTIAL: if( im_region_fill( reg, r, (im_region_fill_fn) fill_region, NULL ) ) return( -1 ); break; - case IM_SETBUF: - case IM_SETBUF_FOREIGN: - case IM_MMAPIN: - case IM_MMAPINRW: - case IM_OPENIN: + case VIPS_IMAGE_SETBUF: + case VIPS_IMAGE_SETBUF_FOREIGN: + case VIPS_IMAGE_MMAPIN: + case VIPS_IMAGE_MMAPINRW: + case VIPS_IMAGE_OPENIN: /* Attach to existing buffer. */ if( im_region_image( reg, r ) ) @@ -182,7 +182,7 @@ im_prepare( REGION *reg, Rect *r ) break; default: - im_error( "im_prepare", _( "unable to input from a %s image" ), + vips_error( "im_prepare", _( "unable to input from a %s image" ), im_dtype2char( im->dtype ) ); return( -1 ); } @@ -204,7 +204,7 @@ im_prepare_to_generate( REGION *reg, REGION *dest, Rect *r, int x, int y ) char *p; if( !im->generate ) { - im_error( "im_prepare_to", "%s", _( "incomplete header" ) ); + vips_error( "im_prepare_to", "%s", _( "incomplete header" ) ); return( -1 ); } @@ -271,7 +271,7 @@ im_prepare_to( REGION *reg, REGION *dest, Rect *r, int x, int y ) if( !dest->data || dest->im->BandFmt != reg->im->BandFmt || dest->im->Bands != reg->im->Bands ) { - im_error( "im_prepare_to", + vips_error( "im_prepare_to", "%s", _( "inappropriate region type" ) ); return( -1 ); } @@ -297,7 +297,7 @@ im_prepare_to( REGION *reg, REGION *dest, Rect *r, int x, int y ) /* Test that dest->valid is large enough. */ if( !im_rect_includesrect( &dest->valid, &wanted ) ) { - im_error( "im_prepare_to", "%s", _( "dest too small" ) ); + vips_error( "im_prepare_to", "%s", _( "dest too small" ) ); return( -1 ); } @@ -314,7 +314,7 @@ im_prepare_to( REGION *reg, REGION *dest, Rect *r, int x, int y ) y = clipped2.top; if( im_rect_isempty( &final ) ) { - im_error( "im_prepare_to", + vips_error( "im_prepare_to", "%s", _( "valid clipped to nothing" ) ); return( -1 ); } @@ -327,8 +327,8 @@ im_prepare_to( REGION *reg, REGION *dest, Rect *r, int x, int y ) /* Input or output image type? */ switch( im->dtype ) { - case IM_OPENOUT: - case IM_PARTIAL: + case VIPS_IMAGE_OPENOUT: + case VIPS_IMAGE_PARTIAL: /* We are generating with a sequence. */ if( im_prepare_to_generate( reg, dest, &final, x, y ) ) @@ -336,9 +336,9 @@ im_prepare_to( REGION *reg, REGION *dest, Rect *r, int x, int y ) break; - case IM_MMAPIN: - case IM_MMAPINRW: - case IM_OPENIN: + case VIPS_IMAGE_MMAPIN: + case VIPS_IMAGE_MMAPINRW: + case VIPS_IMAGE_OPENIN: /* Attach to existing buffer and copy to dest. */ if( im_region_image( reg, &final ) ) @@ -347,8 +347,8 @@ im_prepare_to( REGION *reg, REGION *dest, Rect *r, int x, int y ) break; - case IM_SETBUF: - case IM_SETBUF_FOREIGN: + case VIPS_IMAGE_SETBUF: + case VIPS_IMAGE_SETBUF_FOREIGN: /* Could be either input or output. If there is a generate * function, we are outputting. */ @@ -365,7 +365,7 @@ im_prepare_to( REGION *reg, REGION *dest, Rect *r, int x, int y ) break; default: - im_error( "im_prepare_to", _( "unable to input from a " + vips_error( "im_prepare_to", _( "unable to input from a " "%s image" ), im_dtype2char( im->dtype ) ); return( -1 ); } @@ -390,87 +390,3 @@ im_prepare_many( REGION **reg, Rect *r ) return( 0 ); } - -static void * -im_invalidate_region( REGION *reg ) -{ - reg->invalid = TRUE; - - return( NULL ); -} - -static void * -im_invalidate_image( IMAGE *im, GSList **to_be_invalidated ) -{ - g_mutex_lock( im->sslock ); - (void) im_slist_map2( im->regions, - (VSListMap2Fn) im_invalidate_region, NULL, NULL ); - g_mutex_unlock( im->sslock ); - - *to_be_invalidated = g_slist_prepend( *to_be_invalidated, im ); - - return( NULL ); -} - -/* Trigger a callbacks on a list of images, where the callbacks might create - * or destroy the images. - * - * We make a set of temp regions to hold the images open, but when we switch - * to VipsObject we should incr/decr ref count. - */ -static void -im_invalidate_trigger( GSList *images ) -{ - GSList *regions; - GSList *p; - - regions = NULL; - for( p = images; p; p = p->next ) { - IMAGE *im = (IMAGE *) p->data; - - regions = g_slist_prepend( regions, im_region_create( im ) ); - } - - for( p = images; p; p = p->next ) { - IMAGE *im = (IMAGE *) p->data; - - (void) im__trigger_callbacks( im->invalidatefns ); - } - - for( p = regions; p; p = p->next ) { - REGION *r = (REGION *) p->data; - - im_region_free( r ); - } - - g_slist_free( regions ); -} - -/** - * im_invalidate: - * @im: #IMAGE to invalidate - * - * Invalidate all pixel caches on an #IMAGE and any derived images. The - * "invalidate" callback is triggered for all invalidated images. - * - * See also: im_add_invalidate_callback(). - */ -void -im_invalidate( IMAGE *im ) -{ - GSList *to_be_invalidated; - - /* Invalidate callbacks might do anything, including removing images - * or invalidating other images, so we can't trigger them from within - * the image loop. Instead we collect a list of image to invalidate - * and trigger them all in one go, checking that they are not - * invalidated. - */ - to_be_invalidated = NULL; - (void) im__link_map( im, - (VSListMap2Fn) im_invalidate_image, &to_be_invalidated, NULL ); - - im_invalidate_trigger( to_be_invalidated ); - - g_slist_free( to_be_invalidated ); -} diff --git a/libvips/iofuncs/image.c b/libvips/iofuncs/image.c index 72bed7fb..700e5dea 100644 --- a/libvips/iofuncs/image.c +++ b/libvips/iofuncs/image.c @@ -296,6 +296,8 @@ enum { PROP_KILL, PROP_MODE, PROP_DEMAND, + PROP_SIZEOF_HEADER, + PROP_FOREIGN_BUFFER, PROP_LAST }; @@ -306,6 +308,7 @@ enum { SIG_EVAL, SIG_POSTEVAL, SIG_WRITTEN, + SIG_INVALIDATE, SIG_LAST }; @@ -597,7 +600,7 @@ lazy_real_image( Lazy *lazy ) /* Otherwise, fall back to a "p". */ if( !real && - !(real = vips_image_open( lazy->filename, "p" )) ) + !(real = vips_image_new( "p" )) ) return( NULL ); return( real ); @@ -831,7 +834,7 @@ vips_image_build( VipsObject *object ) else { VipsImage *x; - if( !(x = vips_image_open( filename, "p" )) ) + if( !(x = vips_image_new( "p" )) ) return( -1 ); vips_object_local( image, x ); if( vips_image_open_input( x ) ) @@ -871,6 +874,63 @@ vips_image_build( VipsObject *object ) image->dtype = VIPS_IMAGE_PARTIAL; break; + case 'a': + /* Check parameters. + */ + if( image->sizeof_header < 0 ) { + vips_error( "vips_image_open_raw", + "%s", _( "bad parameters" ) ); + return( -1 ); + } + + if( (image->fd = im__open_image_file( filename )) == -1 ) + return( -1 ); + image->dtype = VIPS_IMAGE_OPENIN; + image->dhint = VIPS_DEMAND_STYLE_THINSTRIP; + + if( image->Bands == 1 ) + image->Type = VIPS_INTERPRETATION_B_W; + else if( image->Bands == 3 ) + image->Type = VIPS_INTERPRETATION_RGB; + else + image->Type = VIPS_INTERPRETATION_MULTIBAND; + + /* Read the real file length and check against what we think + * the size should be. + */ + if( (image->file_length = im_file_length( image->fd )) == -1 ) + return( -1 ); + + /* Very common, so a special message. + */ + if( image->file_length < vips_image_size( image ) ) { + vips_error( "VipsImage", + _( "unable to open %s: file too short" ), + image->filename ); + return( -1 ); + } + + /* Just weird. Only print a warning for this, since we should + * still be able to process it without coredumps. + */ + if( image->file_length > vips_image_size( image ) ) + vips_warn( "VipsImage", + _( "%s is longer than expected" ), + image->filename ); + break; + + case 'm': + if( image->Bands == 1 ) + image->Type = VIPS_INTERPRETATION_B_W; + else if( image->Bands == 3 ) + image->Type = VIPS_INTERPRETATION_RGB; + else + image->Type = VIPS_INTERPRETATION_MULTIBAND; + + image->dtype = VIPS_IMAGE_SETBUF_FOREIGN; + + break; + default: vips_error( "VipsImage", _( "bad mode \"%s\"" ), mode ); @@ -887,6 +947,28 @@ vips_image_build( VipsObject *object ) return( 0 ); } +static void * +vips_region_invalidate( REGION *reg ) +{ + reg->invalid = TRUE; + + return( NULL ); +} + +static void +vips_image_real_invalidate( VipsImage *image ) +{ +#ifdef DEBUG_VIPS + printf( "vips_image_real_invalidate: " ); + vips_object_dump( VIPS_OBJECT( image ) ); +#endif /*DEBUG_VIPS*/ + + g_mutex_lock( image->sslock ); + (void) im_slist_map2( image->regions, + (VSListMap2Fn) vips_region_invalidate, NULL, NULL ); + g_mutex_unlock( image->sslock ); +} + static void vips_image_class_init( VipsImageClass *class ) { @@ -909,11 +991,13 @@ vips_image_class_init( VipsImageClass *class ) vobject_class->print = vips_image_print; vobject_class->build = vips_image_build; + class->invalidate = vips_image_real_invalidate; + /* Create properties. */ pspec = g_param_spec_int( "width", "Width", _( "Image width in pixels" ), - 0, 1000000, 0, + 1, 1000000, 0, G_PARAM_READWRITE ); g_object_class_install_property( gobject_class, PROP_WIDTH, pspec ); vips_object_class_install_argument( vobject_class, pspec, @@ -922,7 +1006,7 @@ vips_image_class_init( VipsImageClass *class ) pspec = g_param_spec_int( "height", "Height", _( "Image height in pixels" ), - 0, 1000000, 0, + 1, 1000000, 0, G_PARAM_READWRITE ); g_object_class_install_property( gobject_class, PROP_HEIGHT, pspec ); vips_object_class_install_argument( vobject_class, pspec, @@ -931,7 +1015,7 @@ vips_image_class_init( VipsImageClass *class ) pspec = g_param_spec_int( "bands", "Bands", _( "Number of bands in image" ), - 0, 1000000, 0, + 1, 1000000, 0, G_PARAM_READWRITE ); g_object_class_install_property( gobject_class, PROP_BANDS, pspec ); vips_object_class_install_argument( vobject_class, pspec, @@ -965,7 +1049,7 @@ vips_image_class_init( VipsImageClass *class ) VIPS_ARGUMENT_CONSTRUCT, G_STRUCT_OFFSET( VipsImage, mode ) ); - pspec = g_param_spec_boolean("kill", "Kill", + pspec = g_param_spec_boolean( "kill", "Kill", _( "Block evaluation on this image" ), FALSE, G_PARAM_READWRITE ); @@ -983,6 +1067,25 @@ vips_image_class_init( VipsImageClass *class ) VIPS_ARGUMENT_NONE, G_STRUCT_OFFSET( VipsImage, dhint ) ); + pspec = g_param_spec_int( "sizeof_header", "Size of header", + _( "Offset in bytes from start of file" ), + 0, 1000000, IM_SIZEOF_HEADER, + G_PARAM_READWRITE ); + g_object_class_install_property( gobject_class, + PROP_SIZEOF_HEADER, pspec ); + vips_object_class_install_argument( vobject_class, pspec, + VIPS_ARGUMENT_SET_ONCE | VIPS_ARGUMENT_CONSTRUCT, + G_STRUCT_OFFSET( VipsImage, sizeof_header ) ); + + pspec = g_param_spec_pointer( "foreign_buffer", "Foreign buffer", + "Pointer to foreign pixels", + G_PARAM_READWRITE ); + g_object_class_install_property( gobject_class, + PROP_FOREIGN_BUFFER, pspec ); + vips_object_class_install_argument( vobject_class, pspec, + VIPS_ARGUMENT_SET_ONCE | VIPS_ARGUMENT_CONSTRUCT, + G_STRUCT_OFFSET( VipsImage, data ) ); + /* Create signals. */ @@ -1015,6 +1118,14 @@ vips_image_class_init( VipsImageClass *class ) NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0 ); + + vips_image_signals[SIG_INVALIDATE] = g_signal_new( "invalidate", + G_TYPE_FROM_CLASS( class ), + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET( VipsImageClass, invalidate ), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0 ); } static void @@ -1029,7 +1140,6 @@ vips_image_init( VipsImage *image ) image->magic = im_amiMSBfirst() ? VIPS_MAGIC_SPARC : VIPS_MAGIC_INTEL; image->fd = -1; /* since 0 is stdout */ - image->sizeof_header = IM_SIZEOF_HEADER; image->sslock = g_mutex_new (); } @@ -1113,6 +1223,39 @@ vips_image_written( VipsImage *image ) g_signal_emit( image, vips_image_signals[SIG_WRITTEN], 0 ); } +void +vips_image_invalidate( VipsImage *image ) +{ +#ifdef DEBUG + printf( "vips_image_invalidate: " ); + vips_object_print( object ); +#endif /*DEBUG*/ + + g_signal_emit( image, vips_image_signals[SIG_INVALIDATE], 0 ); +} + +static void * +vips_image_invalidate_all_cb( VipsImage *image ) +{ + vips_image_invalidate( image ); + + return( NULL ); +} + +/** + * vips_image_invalidate_all: + * @image: #VipsImage to invalidate + * + * Invalidate all pixel caches on an @image and any derived images. The + * "invalidate" callback is triggered for all invalidated images. + */ +void +vips_image_invalidate_all( VipsImage *image ) +{ + (void) im__link_map( image, + (VSListMap2Fn) vips_image_invalidate_all_cb, NULL, NULL ); +} + /* Attach a new time struct, if necessary, and reset it. */ static int @@ -1202,20 +1345,62 @@ vips_image_posteval( VipsImage *image ) } /** - * vips_image_open: + * vips_image_new: + * @mode: mode to open with + * + * vips_image_new() examines the mode string and creates an + * appropriate #VipsImage. + * + * + * + * + * "t" + * creates a temporary memory buffer image. + * + * + * + * + * "p" + * creates a "glue" descriptor you can use to join two image + * processing operations together. + * + * + * + * + * Returns: the image descriptor on success and NULL on error. + */ +VipsImage * +vips_image_new( const char *mode ) +{ + VipsImage *image; + + image = VIPS_IMAGE( g_object_new( VIPS_TYPE_IMAGE, NULL ) ); + g_object_set( image, + "mode", mode, + NULL ); + if( vips_object_build( VIPS_OBJECT( image ) ) ) { + VIPS_UNREF( image ); + return( NULL ); + } + + return( image ); +} + +/** + * vips_image_new_from_file: * @filename: file to open * @mode: mode to open with * - * vips_image_open() examines the mode string, and creates an appropriate - * #VipsImage. + * vips_image_new_from_file() examines the mode string and creates an + * appropriate #VipsImage. * * * * * "r" * opens the named file for reading. If the file is not in the native - * VIPS format for your machine, vips_image_open() automatically converts the - * file for you in memory. + * VIPS format for your machine, vips_image_new_from_file() + * automatically converts the file for you in memory. * * For some large files (eg. TIFF) this may * not be what you want, it can fill memory very quickly. Instead, you @@ -1223,7 +1408,7 @@ vips_image_posteval( VipsImage *image ) * API and control the loading process yourself. See * #VipsBandFormat. * - * vips_image_open() can read files in most formats. + * vips_image_new_from_file() can read files in most formats. * * Note that "r" mode works in at least two stages. * It should return quickly and let you check header fields. It will @@ -1235,9 +1420,9 @@ vips_image_posteval( VipsImage *image ) * "rd" * opens the named file for reading. If the uncompressed image is larger * than a threshold and the file format does not support random access, - * rather than uncompressing to memory, vips_image_open() will uncompress to a - * temporary disc file. This file will be automatically deleted when the - * IMAGE is closed. + * rather than uncompressing to memory, vips_image_new_from_file() will + * uncompress to a temporary disc file. This file will be automatically + * deleted when the IMAGE is closed. * * See im_system_image() for an explanation of how VIPS selects a * location for the temporary file. @@ -1264,7 +1449,7 @@ vips_image_posteval( VipsImage *image ) * suffix to determine the type to write -- for example: * * |[ - * vips_image_open( "fred.tif", "w" ) + * vips_image_new_from_file( "fred.tif", "w" ) * ]| * * will write in TIFF format. @@ -1272,19 +1457,6 @@ vips_image_posteval( VipsImage *image ) * * * - * "t" - * creates a temporary memory buffer image. - * - * - * - * - * "p" - * creates a "glue" descriptor you can use to join two image - * processing operations together. - * - * - * - * * "rw" * opens the named file for reading and writing. This will only work for * VIPS files in a format native to your machine. It is only for @@ -1296,7 +1468,7 @@ vips_image_posteval( VipsImage *image ) * Returns: the image descriptor on success and NULL on error. */ VipsImage * -vips_image_open( const char *filename, const char *mode ) +vips_image_new_from_file( const char *filename, const char *mode ) { VipsImage *image; @@ -1314,7 +1486,7 @@ vips_image_open( const char *filename, const char *mode ) } /** - * vips_image_open_raw: + * vips_image_new_from_file_raw: * @filename: filename to open * @xsize: image width * @ysize: image height @@ -1327,98 +1499,70 @@ vips_image_open( const char *filename, const char *mode ) * It returns an 8-bit image with @bands bands. If the image is not 8-bit, use * im_copy_set() to transform the descriptor after loading it. * - * See also: im_copy_set(), im_raw2vips(), vips_image_open(). + * See also: im_copy_set(), im_raw2vips(), vips_image_new_from_file(). * * Returns: the new #VipsImage, or %NULL on error. */ VipsImage * -vips_image_open_raw( const char *filename, +vips_image_new_from_file_raw( const char *filename, int xsize, int ysize, int bands, int offset ) { VipsImage *image; - /* Check parameters. - */ - if( xsize <= 0 || ysize <= 0 || - bands <= 0 || offset <= 0 ) { - vips_error( "vips_image_open_raw", - "%s", _( "bad parameters" ) ); + image = VIPS_IMAGE( g_object_new( VIPS_TYPE_IMAGE, NULL ) ); + g_object_set( image, + "filename", filename, + "mode", "a", + "width", xsize, + "height", ysize, + "bands", bands, + "sizeof_header", offset, + NULL ); + if( vips_object_build( VIPS_OBJECT( image ) ) ) { + VIPS_UNREF( image ); return( NULL ); } - if( !(image = vips_image_open( filename, "p" )) ) - return( NULL ); + return( image ); +} - if( (im->fd = im__open_image_file( name )) == -1 ) { - im_close( im ); - return( NULL ); - } - im->dtype = IM_OPENIN; - im->sizeof_header = offset; +/** + * vips_image_new_from_memory: + * @buffer: start of memory area + * @xsize: image width + * @ysize: image height + * @bands: image bands (or bytes per pixel) + * @bandfmt: image format + * + * This function wraps an #IMAGE around a memory buffer. VIPS does not take + * responsibility for the area of memory, it's up to you to make sure it's + * freed when the image is closed. See for example im_add_close_callback(). + * + * See also: im_binfile(), im_raw2vips(), im_open(). + * + * Returns: the new #IMAGE, or %NULL on error. + */ +VipsImage * +vips_image_new_from_memory( void *buffer, + int xsize, int ysize, int bands, VipsBandFormat bandfmt ) +{ + VipsImage *image; - /* Predict file size. - */ - psize = (gint64) xsize * ysize * bands + offset; - - /* Read the real file length and check against what we think - * the size should be. - */ - if( (rsize = im_file_length( im->fd )) == -1 ) { - im_close( im ); - return( NULL ); - } - im->file_length = rsize; - - /* Very common, so a special message. - */ - if( psize > rsize ) { - vips_error( "im_binfile", _( "unable to open %s: " - "file has been truncated" ), im->filename ); - im_close( im ); + image = VIPS_IMAGE( g_object_new( VIPS_TYPE_IMAGE, NULL ) ); + g_object_set( image, + "foreign_buffer", buffer, + "mode", "m", + "width", xsize, + "height", ysize, + "bands", bands, + "format", bandfmt, + NULL ); + if( vips_object_build( VIPS_OBJECT( image ) ) ) { + VIPS_UNREF( image ); return( NULL ); } - /* Just wierd. Only print a warning for this, since we should - * still be able to process it without coredumps. - */ - if( psize < rsize ) - im_warn( "im_binfile", _( "%s is longer than expected" ), - im->filename ); - - /* Set header fields. - */ - im->Xsize = xsize; - im->Ysize = ysize; - im->Bands = bands; - - /* Set others to standard values. - */ - im->BandFmt = IM_BANDFMT_UCHAR; - im->Bbits = im_bits_of_fmt( im->BandFmt ); - im->Coding = IM_CODING_NONE; - - if( bands == 1 ) - im->Type = IM_TYPE_B_W; - else if( bands == 3 ) - im->Type = IM_TYPE_RGB; - else - im->Type = IM_TYPE_MULTIBAND; - - im->Xres = 1.0; - im->Yres = 1.0; - - im->Length = 0; - im->Compression = 0; - im->Level = 0; - - im->Xoffset = 0; - im->Yoffset = 0; - - /* Init others too. - */ - im->dhint = IM_THINSTRIP; - - return( im ); + return( image ); } /** diff --git a/libvips/iofuncs/vips.c b/libvips/iofuncs/vips.c index 59751dd6..4c318ea4 100644 --- a/libvips/iofuncs/vips.c +++ b/libvips/iofuncs/vips.c @@ -902,7 +902,7 @@ im__writehist( IMAGE *im ) /* Open the filename, read the header, some sanity checking. */ int -vips_open_input( VipsImage *image ) +vips_image_open_input( VipsImage *image ) { /* We don't use im->sizeof_header here, but we know we're reading a * VIPS image anyway.