From 15e44f731f9205119cf25c16a88f855d0ac33f9a Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Tue, 30 Jun 2020 11:31:33 +0100 Subject: [PATCH 01/10] add spng in there twice --- ChangeLog | 1 - 1 file changed, 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 96bed143..c6c33b3b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -19,7 +19,6 @@ - add "all" mode to smartcrop - flood fill could stop half-way for some very complex shapes - better handling of unaligned reads in multipage tiffs [petoor] -- add experimental libspng reader - mark old --delete option to vipsthumbnail as deprecated [UweOhse] - png save with a bad ICC profile just gives a warning - add "premultipled" option to vips_affine(), clarified vips_resize() From 8dcf3bca57386dcf416fb3c621c79b639e11a9ba Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Tue, 30 Jun 2020 12:32:07 +0100 Subject: [PATCH 02/10] move vips_lrmerge() etc. out of the public API --- libvips/include/vips/internal.h | 24 ++++++++++++++++++++++++ libvips/include/vips/mosaicing.h | 30 ------------------------------ libvips/mosaicing/global_balance.c | 1 + libvips/mosaicing/im_lrmosaic.c | 1 + libvips/mosaicing/match.c | 1 + libvips/mosaicing/merge.c | 1 + libvips/mosaicing/mosaic1.c | 1 + 7 files changed, 29 insertions(+), 30 deletions(-) diff --git a/libvips/include/vips/internal.h b/libvips/include/vips/internal.h index e9a78640..524097d8 100644 --- a/libvips/include/vips/internal.h +++ b/libvips/include/vips/internal.h @@ -276,6 +276,30 @@ VipsWindow *vips_window_take( VipsWindow *window, int vips__profile_set( VipsImage *image, const char *name ); +int vips_correl( VipsImage *ref, VipsImage *sec, + int xref, int yref, int xsec, int ysec, + int hwindowsize, int hsearchsize, + double *correlation, int *x, int *y ); + +int vips_lrmerge( VipsImage *ref, VipsImage *sec, VipsImage *out, + int dx, int dy, int mwidth ); +int vips_tbmerge( VipsImage *ref, VipsImage *sec, VipsImage *out, + int dx, int dy, int mwidth ); + +int vips_lrmosaic( VipsImage *ref, VipsImage *sec, VipsImage *out, + int bandno, + int xref, int yref, int xsec, int ysec, + int hwindowsize, int hsearchsize, + int balancetype, + int mwidth ); + +int vips_tbmosaic( VipsImage *ref, VipsImage *sec, VipsImage *out, + int bandno, + int xref, int yref, int xsec, int ysec, + int hwindowsize, int hsearchsize, + int balancetype, + int mwidth ); + #ifdef __cplusplus } #endif /*__cplusplus*/ diff --git a/libvips/include/vips/mosaicing.h b/libvips/include/vips/mosaicing.h index 4a18068c..848675ea 100644 --- a/libvips/include/vips/mosaicing.h +++ b/libvips/include/vips/mosaicing.h @@ -51,36 +51,6 @@ int vips_mosaic1( VipsImage *ref, VipsImage *sec, VipsImage **out, int xr2, int yr2, int xs2, int ys2, ... ) __attribute__((sentinel)); -/* TODO(kleisauke): Convert these to pure vips8 classes? */ -int vips_correl( VipsImage *ref, VipsImage *sec, - int xref, int yref, int xsec, int ysec, - int hwindowsize, int hsearchsize, - double *correlation, int *x, int *y/*, ...*/ ) - /*__attribute__((sentinel))*/; - -int vips_lrmerge( VipsImage *ref, VipsImage *sec, VipsImage *out, - int dx, int dy, int mwidth/*, ...*/ ) - /*__attribute__((sentinel))*/; -int vips_tbmerge( VipsImage *ref, VipsImage *sec, VipsImage *out, - int dx, int dy, int mwidth/*, ...*/ ) - /*__attribute__((sentinel))*/; - -int vips_lrmosaic( VipsImage *ref, VipsImage *sec, VipsImage *out, - int bandno, - int xref, int yref, int xsec, int ysec, - int hwindowsize, int hsearchsize, - int balancetype, - int mwidth/*, ...*/ ) - /*__attribute__((sentinel))*/; - -int vips_tbmosaic( VipsImage *ref, VipsImage *sec, VipsImage *out, - int bandno, - int xref, int yref, int xsec, int ysec, - int hwindowsize, int hsearchsize, - int balancetype, - int mwidth/*, ...*/ ) - /*__attribute__((sentinel))*/; - int vips_match( VipsImage *ref, VipsImage *sec, VipsImage **out, int xr1, int yr1, int xs1, int ys1, int xr2, int yr2, int xs2, int ys2, ... ) diff --git a/libvips/mosaicing/global_balance.c b/libvips/mosaicing/global_balance.c index 190db7e2..ba45d395 100644 --- a/libvips/mosaicing/global_balance.c +++ b/libvips/mosaicing/global_balance.c @@ -111,6 +111,7 @@ #include #include +#include #include "pmosaicing.h" #include "global_balance.h" diff --git a/libvips/mosaicing/im_lrmosaic.c b/libvips/mosaicing/im_lrmosaic.c index 82cc9ef6..5832897a 100644 --- a/libvips/mosaicing/im_lrmosaic.c +++ b/libvips/mosaicing/im_lrmosaic.c @@ -69,6 +69,7 @@ #include #include +#include #include "pmosaicing.h" diff --git a/libvips/mosaicing/match.c b/libvips/mosaicing/match.c index dfad8866..38821ebc 100644 --- a/libvips/mosaicing/match.c +++ b/libvips/mosaicing/match.c @@ -37,6 +37,7 @@ #include #include +#include #include "pmosaicing.h" diff --git a/libvips/mosaicing/merge.c b/libvips/mosaicing/merge.c index 24d2cd47..e2f33118 100644 --- a/libvips/mosaicing/merge.c +++ b/libvips/mosaicing/merge.c @@ -41,6 +41,7 @@ #include #include +#include typedef struct { VipsOperation parent_instance; diff --git a/libvips/mosaicing/mosaic1.c b/libvips/mosaicing/mosaic1.c index 39aad6ce..8cebcb2b 100644 --- a/libvips/mosaicing/mosaic1.c +++ b/libvips/mosaicing/mosaic1.c @@ -57,6 +57,7 @@ #include #include #include +#include #include "pmosaicing.h" From 92460940337d14caf45c902ab47b8863ca41a9ae Mon Sep 17 00:00:00 2001 From: Kleis Auke Wolthuizen Date: Tue, 30 Jun 2020 12:10:30 +0200 Subject: [PATCH 03/10] Fix function pointer cast issues It is undefined behavior in C and C++ to cast a function pointer to another type and call it that way. This does work in most native platforms, however, despite it being UB, but in WASM it can fail. See: https://emscripten.org/docs/porting/guidelines/function_pointer_issues.html --- libvips/colour/profile_load.c | 2 +- libvips/conversion/extract.c | 24 +++++++++++++++++++++++ libvips/conversion/tilecache.c | 2 +- libvips/convolution/canny.c | 2 +- libvips/deprecated/package.c | 2 +- libvips/deprecated/rename.c | 10 ++++++++++ libvips/foreign/analyze2vips.c | 10 +++++----- libvips/foreign/dzsave.c | 4 ++-- libvips/foreign/exif.c | 4 ++-- libvips/foreign/foreign.c | 10 +++++----- libvips/foreign/jpeg2vips.c | 4 ++-- libvips/foreign/magicksave.c | 4 +--- libvips/foreign/matlab.c | 2 +- libvips/foreign/openexr2vips.c | 2 +- libvips/foreign/radiance.c | 6 +++--- libvips/foreign/tiff2vips.c | 4 ++-- libvips/foreign/tiffsave.c | 5 +---- libvips/foreign/vips2tiff.c | 8 ++++---- libvips/include/vips/almostdeprecated.h | 4 ++++ libvips/include/vips/image.h | 12 ++++++------ libvips/include/vips/memory.h | 1 - libvips/include/vips/object.h | 2 +- libvips/include/vips/type.h | 1 + libvips/iofuncs/buffer.c | 2 +- libvips/iofuncs/cache.c | 4 ++-- libvips/iofuncs/gate.c | 8 +++++--- libvips/iofuncs/generate.c | 19 +++++++++--------- libvips/iofuncs/header.c | 6 +++--- libvips/iofuncs/image.c | 22 ++++++++++----------- libvips/iofuncs/memory.c | 26 +++++-------------------- libvips/iofuncs/object.c | 14 ++++++------- libvips/iofuncs/rect.c | 2 +- libvips/iofuncs/region.c | 9 ++++----- libvips/iofuncs/sink.c | 2 +- libvips/iofuncs/sinkdisc.c | 2 +- libvips/iofuncs/sinkmemory.c | 2 +- libvips/iofuncs/sinkscreen.c | 14 ++++++------- libvips/iofuncs/source.c | 6 +++--- libvips/iofuncs/target.c | 2 +- libvips/iofuncs/type.c | 24 ++++++++++++++++------- libvips/iofuncs/util.c | 12 ++++++------ libvips/iofuncs/vips.c | 4 ++-- libvips/iofuncs/window.c | 4 ++-- 43 files changed, 167 insertions(+), 142 deletions(-) diff --git a/libvips/colour/profile_load.c b/libvips/colour/profile_load.c index c7fdb4a5..4966cb79 100644 --- a/libvips/colour/profile_load.c +++ b/libvips/colour/profile_load.c @@ -96,7 +96,7 @@ vips_profile_load_build( VipsObject *object ) else if( (data = vips__file_read_name( load->name, vips__icc_dir(), &length )) ) profile = vips_blob_new( - (VipsCallbackFn) g_free, data, length ); + (VipsCallbackFn) vips_area_free_cb, data, length ); else { vips_error( class->nickname, _( "unable to load profile \"%s\"" ), load->name ); diff --git a/libvips/conversion/extract.c b/libvips/conversion/extract.c index 7a60f877..e2c8ec72 100644 --- a/libvips/conversion/extract.c +++ b/libvips/conversion/extract.c @@ -172,6 +172,14 @@ vips_extract_area_build( VipsObject *object ) return( 0 ); } +#ifdef __EMSCRIPTEN__ +static void +vips_crop_class_init_adapter( VipsExtractAreaClass *class, void *dummy ) +{ + vips_extract_area_class_init( class ); +} +#endif + static void vips_extract_area_class_init( VipsExtractAreaClass *class ) { @@ -226,6 +234,14 @@ vips_extract_area_class_init( VipsExtractAreaClass *class ) } +#ifdef __EMSCRIPTEN__ +static void +vips_crop_init_adapter( VipsExtractArea *extract, void *dummy ) +{ + vips_extract_area_init( extract ); +} +#endif + static void vips_extract_area_init( VipsExtractArea *extract ) { @@ -275,12 +291,20 @@ vips_crop_get_type( void ) sizeof( VipsExtractAreaClass ), NULL, /* base_init */ NULL, /* base_finalize */ +#ifdef __EMSCRIPTEN__ + (GClassInitFunc) vips_crop_class_init_adapter, +#else (GClassInitFunc) vips_extract_area_class_init, +#endif NULL, /* class_finalize */ NULL, /* class_data */ sizeof( VipsExtractArea ), 32, /* n_preallocs */ +#ifdef __EMSCRIPTEN__ + (GInstanceInitFunc) vips_crop_init_adapter, +#else (GInstanceInitFunc) vips_extract_area_init, +#endif }; type = g_type_register_static( VIPS_TYPE_CONVERSION, diff --git a/libvips/conversion/tilecache.c b/libvips/conversion/tilecache.c index c458254f..e89853db 100644 --- a/libvips/conversion/tilecache.c +++ b/libvips/conversion/tilecache.c @@ -473,7 +473,7 @@ vips_tile_destroy( VipsTile *tile ) VIPS_UNREF( tile->region ); - vips_free( tile ); + g_free( tile ); } static void diff --git a/libvips/convolution/canny.c b/libvips/convolution/canny.c index ca96f6b1..bd732c37 100644 --- a/libvips/convolution/canny.c +++ b/libvips/convolution/canny.c @@ -225,7 +225,7 @@ vips_canny_polar( VipsImage **args, VipsImage **out ) { static GOnce once = G_ONCE_INIT; - g_once( &once, (GThreadFunc) vips_atan2_init, NULL ); + g_once( &once, vips_atan2_init, NULL ); *out = vips_image_new(); if( vips_image_pipeline_array( *out, diff --git a/libvips/deprecated/package.c b/libvips/deprecated/package.c index fb5b4dbc..2549b2d0 100644 --- a/libvips/deprecated/package.c +++ b/libvips/deprecated/package.c @@ -910,7 +910,7 @@ im_free_vargv( im_function *fn, im_object *vargv ) /* If there is local storage, free it. */ if( fn->argv[i].desc->size != 0 ) - vips_free( vargv[i] ); + g_free( vargv[i] ); /* NULL out pointer. */ diff --git a/libvips/deprecated/rename.c b/libvips/deprecated/rename.c index ad3eaa22..3c776190 100644 --- a/libvips/deprecated/rename.c +++ b/libvips/deprecated/rename.c @@ -813,3 +813,13 @@ vips_autorot_get_angle( VipsImage *im ) return( VIPS_ANGLE_D0 ); } +/* The old vips_free(), now replaced by g_free() and vips_area_free_cb(). + */ +int +vips_free( void *buf ) +{ + g_free( buf ); + + return( 0 ); +} + diff --git a/libvips/foreign/analyze2vips.c b/libvips/foreign/analyze2vips.c index c3802d8c..9f17f1ff 100644 --- a/libvips/foreign/analyze2vips.c +++ b/libvips/foreign/analyze2vips.c @@ -309,7 +309,7 @@ read_header( const char *header ) if( len != sizeof( struct dsr ) ) { vips_error( "analyze2vips", "%s", _( "header file size incorrect" ) ); - vips_free( d ); + g_free( d ); return( NULL ); } @@ -354,7 +354,7 @@ read_header( const char *header ) if( (int) len != d->hk.sizeof_hdr ) { vips_error( "analyze2vips", "%s", _( "header size incorrect" ) ); - vips_free( d ); + g_free( d ); return( NULL ); } @@ -444,7 +444,7 @@ attach_meta( VipsImage *out, struct dsr *d ) int i; vips_image_set_blob( out, "dsr", - (VipsCallbackFn) vips_free, d, d->hk.sizeof_hdr ); + (VipsCallbackFn) vips_area_free_cb, d, d->hk.sizeof_hdr ); for( i = 0; i < VIPS_NUMBER( dsr_header ); i++ ) { switch( dsr_header[i].type ) { @@ -514,7 +514,7 @@ vips__isanalyze( const char *filename ) result = get_vips_properties( d, &width, &height, &bands, &fmt ); vips_error_thaw(); - vips_free( d ); + g_free( d ); return( result == 0 ); } @@ -538,7 +538,7 @@ vips__analyze_read_header( const char *filename, VipsImage *out ) #endif /*DEBUG*/ if( get_vips_properties( d, &width, &height, &bands, &fmt ) ) { - vips_free( d ); + g_free( d ); return( -1 ); } diff --git a/libvips/foreign/dzsave.c b/libvips/foreign/dzsave.c index d0e2a98a..c793668e 100644 --- a/libvips/foreign/dzsave.c +++ b/libvips/foreign/dzsave.c @@ -275,7 +275,7 @@ vips_gsf_tree_new( GsfOutput *out, gint deflate_level ) } static void * -vips_gsf_child_by_name_sub( VipsGsfDirectory *dir, const char *name ) +vips_gsf_child_by_name_sub( VipsGsfDirectory *dir, const char *name, void *b ) { if( strcmp( dir->name, name ) == 0 ) return( dir ); @@ -2692,7 +2692,7 @@ vips_foreign_save_dz_buffer_build( VipsObject *object ) gsf_output_memory_get_bytes( GSF_OUTPUT_MEMORY( dz->out ) ), olen ); - blob = vips_blob_new( (VipsCallbackFn) g_free, obuf, olen ); + blob = vips_blob_new( (VipsCallbackFn) vips_area_free_cb, obuf, olen ); g_object_set( object, "buffer", blob, NULL ); vips_area_unref( VIPS_AREA( blob ) ); diff --git a/libvips/foreign/exif.c b/libvips/foreign/exif.c index 6e6c442d..3dc35ec5 100644 --- a/libvips/foreign/exif.c +++ b/libvips/foreign/exif.c @@ -1258,7 +1258,7 @@ vips_exif_exif_entry( ExifEntry *entry, VipsExifRemove *ve ) } static void * -vips_exif_exif_remove( ExifEntry *entry, VipsExifRemove *ve ) +vips_exif_exif_remove( ExifEntry *entry, VipsExifRemove *ve, void *b ) { #ifdef DEBUG { @@ -1405,7 +1405,7 @@ vips__exif_update( VipsImage *image ) #endif /*DEBUG*/ vips_image_set_blob( image, VIPS_META_EXIF_NAME, - (VipsCallbackFn) vips_free, data, length ); + (VipsCallbackFn) vips_area_free_cb, data, length ); exif_data_free( ed ); diff --git a/libvips/foreign/foreign.c b/libvips/foreign/foreign.c index f7fdd496..0459c47f 100644 --- a/libvips/foreign/foreign.c +++ b/libvips/foreign/foreign.c @@ -390,7 +390,7 @@ file_add_class( VipsForeignClass *class, GSList **files ) } static gint -file_compare( VipsForeignClass *a, VipsForeignClass *b ) +file_compare( VipsForeignClass *a, VipsForeignClass *b, void *user_data ) { return( b->priority - a->priority ); } @@ -479,7 +479,7 @@ vips_foreign_load_summary_class( VipsObjectClass *object_class, VipsBuf *buf ) */ static void * vips_foreign_find_load_sub( VipsForeignLoadClass *load_class, - const char *filename ) + const char *filename, void *b ) { VipsObjectClass *object_class = VIPS_OBJECT_CLASS( load_class ); VipsForeignClass *class = VIPS_FOREIGN_CLASS( load_class ); @@ -1763,7 +1763,7 @@ vips_foreign_save_init( VipsForeignSave *save ) */ static void * vips_foreign_find_save_sub( VipsForeignSaveClass *save_class, - const char *filename ) + const char *filename, void *b ) { VipsObjectClass *object_class = VIPS_OBJECT_CLASS( save_class ); VipsForeignClass *class = VIPS_FOREIGN_CLASS( save_class ); @@ -1919,7 +1919,7 @@ vips_foreign_save( VipsImage *in, const char *name, ... ) */ static void * vips_foreign_find_save_target_sub( VipsForeignSaveClass *save_class, - const char *suffix ) + const char *suffix, void *b ) { VipsObjectClass *object_class = VIPS_OBJECT_CLASS( save_class ); VipsForeignClass *class = VIPS_FOREIGN_CLASS( save_class ); @@ -1977,7 +1977,7 @@ vips_foreign_find_save_target( const char *name ) */ static void * vips_foreign_find_save_buffer_sub( VipsForeignSaveClass *save_class, - const char *suffix ) + const char *suffix, void *b ) { VipsObjectClass *object_class = VIPS_OBJECT_CLASS( save_class ); VipsForeignClass *class = VIPS_FOREIGN_CLASS( save_class ); diff --git a/libvips/foreign/jpeg2vips.c b/libvips/foreign/jpeg2vips.c index 26accc40..c1e87fd5 100644 --- a/libvips/foreign/jpeg2vips.c +++ b/libvips/foreign/jpeg2vips.c @@ -334,7 +334,7 @@ readjpeg_free( ReadJpeg *jpeg ) } static void -readjpeg_close_cb( VipsObject *object, ReadJpeg *jpeg ) +readjpeg_close_cb( VipsImage *image, ReadJpeg *jpeg ) { (void) readjpeg_free( jpeg ); } @@ -728,7 +728,7 @@ read_jpeg_header( ReadJpeg *jpeg, VipsImage *out ) } vips_image_set_blob( out, VIPS_META_ICC_NAME, - (VipsCallbackFn) vips_free, data, data_length ); + (VipsCallbackFn) vips_area_free_cb, data, data_length ); } return( 0 ); diff --git a/libvips/foreign/magicksave.c b/libvips/foreign/magicksave.c index 102252d9..bc1d3987 100644 --- a/libvips/foreign/magicksave.c +++ b/libvips/foreign/magicksave.c @@ -593,9 +593,7 @@ vips_foreign_save_magick_buffer_build( VipsObject *object ) return( -1 ); } - /* obuf is a g_free() buffer, not vips_free(). - */ - blob = vips_blob_new( (VipsCallbackFn) g_free, obuf, olen ); + blob = vips_blob_new( (VipsCallbackFn) vips_area_free_cb, obuf, olen ); g_object_set( buffer, "buffer", blob, NULL ); vips_area_unref( VIPS_AREA( blob ) ); diff --git a/libvips/foreign/matlab.c b/libvips/foreign/matlab.c index 5335647b..dde57f2e 100644 --- a/libvips/foreign/matlab.c +++ b/libvips/foreign/matlab.c @@ -92,7 +92,7 @@ read_destroy( Read *read ) VIPS_FREEF( Mat_VarFree, read->var ); VIPS_FREEF( Mat_Close, read->mat ); - vips_free( read ); + g_free( read ); } static Read * diff --git a/libvips/foreign/openexr2vips.c b/libvips/foreign/openexr2vips.c index e36b477e..523b72b5 100644 --- a/libvips/foreign/openexr2vips.c +++ b/libvips/foreign/openexr2vips.c @@ -139,7 +139,7 @@ read_destroy( VipsImage *out, Read *read ) read_close( read ); - vips_free( read ); + g_free( read ); } static Read * diff --git a/libvips/foreign/radiance.c b/libvips/foreign/radiance.c index d5ba070b..c9889b14 100644 --- a/libvips/foreign/radiance.c +++ b/libvips/foreign/radiance.c @@ -739,13 +739,13 @@ vips__rad_israd( VipsSource *source ) } static void -read_destroy( VipsObject *object, Read *read ) +read_destroy( VipsImage *image, Read *read ) { VIPS_UNREF( read->sbuf ); } static void -read_minimise_cb( VipsObject *object, Read *read ) +read_minimise_cb( VipsImage *image, Read *read ) { if( read->sbuf ) vips_source_minimise( read->sbuf->source ); @@ -994,7 +994,7 @@ write_destroy( Write *write ) VIPS_FREE( write->line ); VIPS_UNREF( write->target ); - vips_free( write ); + g_free( write ); } static Write * diff --git a/libvips/foreign/tiff2vips.c b/libvips/foreign/tiff2vips.c index 6bde6f31..cac71396 100644 --- a/libvips/foreign/tiff2vips.c +++ b/libvips/foreign/tiff2vips.c @@ -522,7 +522,7 @@ rtiff_free( Rtiff *rtiff ) } static void -rtiff_close_cb( VipsObject *object, Rtiff *rtiff ) +rtiff_close_cb( VipsImage *image, Rtiff *rtiff ) { rtiff_free( rtiff ); } @@ -1926,7 +1926,7 @@ rtiff_fill_region( VipsRegion *out, static int rtiff_seq_stop( void *seq, void *a, void *b ) { - vips_free( seq ); + g_free( seq ); return( 0 ); } diff --git a/libvips/foreign/tiffsave.c b/libvips/foreign/tiffsave.c index 83d9fd94..33bc65ea 100644 --- a/libvips/foreign/tiffsave.c +++ b/libvips/foreign/tiffsave.c @@ -503,10 +503,7 @@ vips_foreign_save_tiff_buffer_build( VipsObject *object ) tiff->subifd ) ) return( -1 ); - /* vips__tiff_write_buf() makes a buffer that needs g_free(), not - * vips_free(). - */ - blob = vips_blob_new( (VipsCallbackFn) g_free, obuf, olen ); + blob = vips_blob_new( (VipsCallbackFn) vips_area_free_cb, obuf, olen ); g_object_set( object, "buffer", blob, NULL ); vips_area_unref( VIPS_AREA( blob ) ); diff --git a/libvips/foreign/vips2tiff.c b/libvips/foreign/vips2tiff.c index 5ff5834d..9a6244a9 100644 --- a/libvips/foreign/vips2tiff.c +++ b/libvips/foreign/vips2tiff.c @@ -979,9 +979,9 @@ wtiff_free( Wtiff *wtiff ) wtiff_delete_temps( wtiff ); VIPS_UNREF( wtiff->ready ); - VIPS_FREEF( vips_free, wtiff->tbuf ); + VIPS_FREE( wtiff->tbuf ); VIPS_FREEF( layer_free_all, wtiff->layer ); - VIPS_FREEF( vips_free, wtiff->icc_profile ); + VIPS_FREE( wtiff->icc_profile ); VIPS_FREE( wtiff->filename ); VIPS_FREE( wtiff ); } @@ -1888,11 +1888,11 @@ wtiff_copy_tiff( Wtiff *wtiff, TIFF *out, TIFF *in ) len = TIFFReadEncodedTile( in, tile, buf, -1 ); if( len < 0 || TIFFWriteEncodedTile( out, tile, buf, len ) < 0 ) { - vips_free( buf ); + g_free( buf ); return( -1 ); } } - vips_free( buf ); + g_free( buf ); return( 0 ); } diff --git a/libvips/include/vips/almostdeprecated.h b/libvips/include/vips/almostdeprecated.h index 1bde7c84..e397c27f 100644 --- a/libvips/include/vips/almostdeprecated.h +++ b/libvips/include/vips/almostdeprecated.h @@ -294,6 +294,10 @@ void vips_vinfo( const char *domain, const char *fmt, va_list ap ); VipsAngle vips_autorot_get_angle( VipsImage *image ); +/* iofuncs + */ +int vips_free( void *buf ); + #ifdef __cplusplus } #endif /*__cplusplus*/ diff --git a/libvips/include/vips/image.h b/libvips/include/vips/image.h index d400ffc4..01b59968 100644 --- a/libvips/include/vips/image.h +++ b/libvips/include/vips/image.h @@ -319,27 +319,27 @@ typedef struct _VipsImageClass { /* Evaluation is starting. */ - void (*preeval)( VipsImage *image, VipsProgress *progress ); + void (*preeval)( VipsImage *image, VipsProgress *progress, void *data ); /* Evaluation progress. */ - void (*eval)( VipsImage *image, VipsProgress *progress ); + void (*eval)( VipsImage *image, VipsProgress *progress, void *data ); /* Evaluation is ending. */ - void (*posteval)( VipsImage *image, VipsProgress *progress ); + void (*posteval)( VipsImage *image, VipsProgress *progress, void *data ); /* An image has been written to. * Used by eg. vips_image_new_mode("x.jpg", "w") to do the * final write to jpeg. * Set *result to non-zero to indicate an error on write. */ - void (*written)( VipsImage *image, int *result ); + void (*written)( VipsImage *image, int *result, void *data ); /* An image has been modified in some way and all caches * need dropping. */ - void (*invalidate)( VipsImage *image ); + void (*invalidate)( VipsImage *image, void *data ); /* Minimise this pipeline. * @@ -349,7 +349,7 @@ typedef struct _VipsImageClass { * * See vips_tilecache(). */ - void (*minimise)( VipsImage *image ); + void (*minimise)( VipsImage *image, void *data ); } VipsImageClass; diff --git a/libvips/include/vips/memory.h b/libvips/include/vips/memory.h index 99b26e8f..6469db9f 100644 --- a/libvips/include/vips/memory.h +++ b/libvips/include/vips/memory.h @@ -66,7 +66,6 @@ G_STMT_START { \ void *vips_malloc( VipsObject *object, size_t size ); char *vips_strdup( VipsObject *object, const char *str ); -int vips_free( void *buf ); void vips_tracked_free( void *s ); void *vips_tracked_malloc( size_t size ); diff --git a/libvips/include/vips/object.h b/libvips/include/vips/object.h index ff500a61..f83ee461 100644 --- a/libvips/include/vips/object.h +++ b/libvips/include/vips/object.h @@ -455,7 +455,7 @@ struct _VipsObjectClass { /* Just after build ... the object is fully ready for work. */ - int (*postbuild)( VipsObject *object ); + int (*postbuild)( VipsObject *object, void *data ); /* Try to print something about the class, handy for help displays. * Keep to one line. diff --git a/libvips/include/vips/type.h b/libvips/include/vips/type.h index ba7512ea..4f73d43e 100644 --- a/libvips/include/vips/type.h +++ b/libvips/include/vips/type.h @@ -92,6 +92,7 @@ typedef struct _VipsArea { } VipsArea; VipsArea *vips_area_copy( VipsArea *area ); +int vips_area_free_cb( void *mem, VipsArea *area ); void vips_area_unref( VipsArea *area ); VipsArea *vips_area_new( VipsCallbackFn free_fn, void *data ); diff --git a/libvips/iofuncs/buffer.c b/libvips/iofuncs/buffer.c index 87efa49f..4462087b 100644 --- a/libvips/iofuncs/buffer.c +++ b/libvips/iofuncs/buffer.c @@ -153,7 +153,7 @@ vips_buffer_dump( VipsBuffer *buffer, size_t *reserve, size_t *alive ) #ifdef DEBUG_CREATE static void * -vips_buffer_cache_dump( VipsBufferCache *cache ) +vips_buffer_cache_dump( VipsBufferCache *cache, void *a, void *b ) { printf( "VipsBufferCache: %p\n", cache ); printf( "\t%d buffers\n", g_slist_length( cache->buffers ) ); diff --git a/libvips/iofuncs/cache.c b/libvips/iofuncs/cache.c index 3ec40966..339bbb92 100644 --- a/libvips/iofuncs/cache.c +++ b/libvips/iofuncs/cache.c @@ -453,7 +453,7 @@ vips_operation_equal( VipsOperation *a, VipsOperation *b ) } void * -vips__cache_once_init( void ) +vips__cache_once_init( void *data ) { vips_cache_lock = vips_g_mutex_new(); @@ -469,7 +469,7 @@ vips__cache_init( void ) { static GOnce once = G_ONCE_INIT; - VIPS_ONCE( &once, (GThreadFunc) vips__cache_once_init, NULL ); + VIPS_ONCE( &once, vips__cache_once_init, NULL ); } static void * diff --git a/libvips/iofuncs/gate.c b/libvips/iofuncs/gate.c index 0b45ec3e..5e38d315 100644 --- a/libvips/iofuncs/gate.c +++ b/libvips/iofuncs/gate.c @@ -210,8 +210,8 @@ vips__thread_profile_init_cb( VipsThreadProfile *profile ) vips_thread_profile_free( profile ); } -static void -vips__thread_profile_init( void ) +static void * +vips__thread_profile_init( void *data ) { #ifdef HAVE_PRIVATE_INIT static GPrivate private = @@ -223,6 +223,8 @@ vips__thread_profile_init( void ) vips_thread_profile_key = g_private_new( (GDestroyNotify) vips__thread_profile_init_cb ); #endif + + return( NULL ); } static VipsThreadGate * @@ -245,7 +247,7 @@ vips__thread_profile_attach( const char *thread_name ) VipsThreadProfile *profile; - VIPS_ONCE( &once, (GThreadFunc) vips__thread_profile_init, NULL ); + VIPS_ONCE( &once, vips__thread_profile_init, NULL ); VIPS_DEBUG_MSG( "vips__thread_profile_attach: %s\n", thread_name ); diff --git a/libvips/iofuncs/generate.c b/libvips/iofuncs/generate.c index 65be8d9c..8e8e53a4 100644 --- a/libvips/iofuncs/generate.c +++ b/libvips/iofuncs/generate.c @@ -148,7 +148,7 @@ vips__link_make( VipsImage *image_up, VipsImage *image_down ) } static void * -vips__link_break( VipsImage *image_up, VipsImage *image_down ) +vips__link_break( VipsImage *image_up, VipsImage *image_down, void *b ) { g_assert( image_up ); g_assert( image_down ); @@ -171,9 +171,9 @@ vips__link_break( VipsImage *image_up, VipsImage *image_down ) } static void * -vips__link_break_rev( VipsImage *image_down, VipsImage *image_up ) +vips__link_break_rev( VipsImage *image_down, VipsImage *image_up, void *b ) { - return( vips__link_break( image_up, image_down ) ); + return( vips__link_break( image_up, image_down, b ) ); } /* A VipsImage is going ... break all links. @@ -203,7 +203,7 @@ typedef struct _LinkMap { } LinkMap; static void * -vips__link_mapp( VipsImage *image, LinkMap *map ) +vips__link_mapp( VipsImage *image, LinkMap *map, void *b ) { void *res; @@ -222,7 +222,7 @@ vips__link_mapp( VipsImage *image, LinkMap *map ) } static void * -vips__link_map_cb( VipsImage *image, GSList **images ) +vips__link_map_cb( VipsImage *image, GSList **images, void *b ) { *images = g_slist_prepend( *images, image ); @@ -265,7 +265,7 @@ vips__link_map( VipsImage *image, gboolean upstream, serial += 1; map.serial = serial; - vips__link_mapp( image, &map ); + vips__link_mapp( image, &map, NULL ); for( p = images; p; p = p->next ) g_object_ref( p->data ); @@ -494,7 +494,7 @@ vips_stop_many( void *seq, void *a, void *b ) for( i = 0; ar[i]; i++ ) g_object_unref( ar[i] ); - vips_free( (char *) ar ); + g_free( (char *) ar ); } return( 0 ); @@ -630,7 +630,7 @@ vips_allocate_input_array( VipsImage *out, ... ) /* A write function for VIPS images. Just write() the pixel data. */ static int -write_vips( VipsRegion *region, VipsRect *area, void *a, void *b ) +write_vips( VipsRegion *region, VipsRect *area, void *a ) { size_t nwritten, count; void *buf; @@ -753,8 +753,7 @@ vips_image_generate( VipsImage *image, return( -1 ); if( image->dtype == VIPS_IMAGE_OPENOUT ) - res = vips_sink_disc( image, - (VipsRegionWrite) write_vips, NULL ); + res = vips_sink_disc( image, write_vips, NULL ); else res = vips_sink_memory( image ); diff --git a/libvips/iofuncs/header.c b/libvips/iofuncs/header.c index 4109b5d4..b10235b3 100644 --- a/libvips/iofuncs/header.c +++ b/libvips/iofuncs/header.c @@ -235,7 +235,7 @@ vips_format_sizeof_unsafe( VipsBandFormat format ) /* Check that this meta is on the hash table. */ static void * -meta_sanity_on_hash( VipsMeta *meta, VipsImage *im ) +meta_sanity_on_hash( VipsMeta *meta, VipsImage *im, void *b ) { VipsMeta *found; @@ -970,7 +970,7 @@ vips_image_init_fields( VipsImage *image, } static void * -meta_cp_field( VipsMeta *meta, VipsImage *dst ) +meta_cp_field( VipsMeta *meta, VipsImage *dst, void *b ) { #ifdef DEBUG { @@ -1569,7 +1569,7 @@ vips_image_set_blob_copy( VipsImage *image, ((unsigned char *) data_copy)[length] = '\0'; vips_image_set_blob( image, - name, (VipsCallbackFn) vips_free, data_copy, length ); + name, (VipsCallbackFn) vips_area_free_cb, data_copy, length ); } /** diff --git a/libvips/iofuncs/image.c b/libvips/iofuncs/image.c index c5d51b23..f2acf931 100644 --- a/libvips/iofuncs/image.c +++ b/libvips/iofuncs/image.c @@ -651,7 +651,7 @@ vips_image_summary( VipsObject *object, VipsBuf *buf ) } static void * -vips_image_sanity_upstream( VipsImage *up, VipsImage *down ) +vips_image_sanity_upstream( VipsImage *up, VipsImage *down, void *b ) { if( !g_slist_find( up->downstream, down ) || !g_slist_find( down->upstream, up ) ) @@ -661,9 +661,9 @@ vips_image_sanity_upstream( VipsImage *up, VipsImage *down ) } static void * -vips_image_sanity_downstream( VipsImage *down, VipsImage *up ) +vips_image_sanity_downstream( VipsImage *down, VipsImage *up, void *b ) { - return( vips_image_sanity_upstream( up, down ) ); + return( vips_image_sanity_upstream( up, down, b ) ); } static void @@ -738,7 +738,7 @@ vips_image_rewind( VipsObject *object ) /* From "written" callback: save to image->filename using VipsForeign. */ static void -vips_image_save_cb( VipsImage *image, int *result ) +vips_image_save_cb( VipsImage *image, int *result, void *data ) { if( vips_foreign_save( image, image->filename, NULL ) ) *result = -1; @@ -786,7 +786,7 @@ vips_image_eval_cb( VipsImage *image, VipsProgress *progress, int *last ) } static void -vips_image_posteval_cb( VipsImage *image, VipsProgress *progress ) +vips_image_posteval_cb( VipsImage *image, VipsProgress *progress, void *data ) { /* Spaces at end help to erase the %complete message we overwrite. */ @@ -1016,7 +1016,7 @@ vips_image_build( VipsObject *object ) } static void * -vips_image_real_invalidate_cb( VipsRegion *reg ) +vips_image_real_invalidate_cb( VipsRegion *reg, void *a, void *b ) { vips_region_invalidate( reg ); @@ -1024,7 +1024,7 @@ vips_image_real_invalidate_cb( VipsRegion *reg ) } static void -vips_image_real_invalidate( VipsImage *image ) +vips_image_real_invalidate( VipsImage *image, void *data ) { VIPS_DEBUG_MSG( "vips_image_real_invalidate: %p\n", image ); @@ -1041,13 +1041,13 @@ vips_image_real_invalidate( VipsImage *image ) } static void -vips_image_real_minimise( VipsImage *image ) +vips_image_real_minimise( VipsImage *image, void *data ) { VIPS_DEBUG_MSG( "vips_image_real_minimise: %p\n", image ); } static void -vips_image_real_written( VipsImage *image, int *result ) +vips_image_real_written( VipsImage *image, int *result, void *data ) { VIPS_DEBUG_MSG( "vips_image_real_written: %p\n", image ); @@ -1390,7 +1390,7 @@ vips_image_invalidate( VipsImage *image ) } static void * -vips_image_invalidate_all_cb( VipsImage *image ) +vips_image_invalidate_all_cb( VipsImage *image, void *a, void *b ) { vips_image_invalidate( image ); @@ -1430,7 +1430,7 @@ vips_image_minimise( VipsImage *image ) } static void * -vips_image_minimise_all_cb( VipsImage *image ) +vips_image_minimise_all_cb( VipsImage *image, void *a, void *b ) { vips_image_minimise( image ); diff --git a/libvips/iofuncs/memory.c b/libvips/iofuncs/memory.c index 2233b17b..b2fa30aa 100644 --- a/libvips/iofuncs/memory.c +++ b/libvips/iofuncs/memory.c @@ -215,24 +215,6 @@ vips_strdup( VipsObject *object, const char *str ) return( str_dup ); } -/** - * vips_free: - * @buf: memory to free - * - * Frees memory with g_free() and returns 0. Handy for callbacks. - * - * See also: vips_malloc(). - * - * Returns: 0 - */ -int -vips_free( void *buf ) -{ - g_free( buf ); - - return( 0 ); -} - /** * vips_tracked_free: * @s: (transfer full): memory to free @@ -273,10 +255,12 @@ vips_tracked_free( void *s ) VIPS_GATE_FREE( size ); } -static void -vips_tracked_init_mutex( void ) +static void * +vips_tracked_init_mutex( void *data ) { vips_tracked_mutex = vips_g_mutex_new(); + + return( NULL ); } static void @@ -285,7 +269,7 @@ vips_tracked_init( void ) static GOnce vips_tracked_once = G_ONCE_INIT; VIPS_ONCE( &vips_tracked_once, - (GThreadFunc) vips_tracked_init_mutex, NULL ); + vips_tracked_init_mutex, NULL ); } /** diff --git a/libvips/iofuncs/object.c b/libvips/iofuncs/object.c index bbb6ac3c..36cccdf3 100644 --- a/libvips/iofuncs/object.c +++ b/libvips/iofuncs/object.c @@ -1460,7 +1460,7 @@ vips_object_real_build( VipsObject *object ) } static int -vips_object_real_postbuild( VipsObject *object ) +vips_object_real_postbuild( VipsObject *object, void *data ) { #ifdef DEBUG printf( "vips_object_real_postbuild: " ); @@ -1701,7 +1701,7 @@ traverse_find_required_priority( void *data, void *a, void *b ) } static gint -traverse_sort( gconstpointer a, gconstpointer b ) +traverse_sort( gconstpointer a, gconstpointer b, void *user_data ) { VipsArgumentClass *class1 = (VipsArgumentClass *) a; VipsArgumentClass *class2 = (VipsArgumentClass *) b; @@ -1803,7 +1803,7 @@ vips_object_class_install_argument( VipsObjectClass *object_class, argument_table_traverse = g_slist_prepend( argument_table_traverse, argument_class ); argument_table_traverse = g_slist_sort( - argument_table_traverse, traverse_sort ); + argument_table_traverse, (GCompareFunc) traverse_sort ); VIPS_SWAP( GSList *, argument_table_traverse, object_class->argument_table_traverse ); @@ -3045,7 +3045,7 @@ typedef struct { } VipsObjectLocal; static void -vips_object_local_array_cb( GObject *parent, VipsObjectLocal *local ) +vips_object_local_array_cb( VipsObject *parent, VipsObjectLocal *local ) { int i; @@ -3111,7 +3111,7 @@ vips_object_set_static( VipsObject *object, gboolean static_object ) } static void * -vips_object_n_static_cb( VipsObject *object, int *n ) +vips_object_n_static_cb( VipsObject *object, int *n, void *b ) { if( object->static_object ) *n += 1; @@ -3132,7 +3132,7 @@ vips_object_n_static( void ) } static void * -vips_object_print_all_cb( VipsObject *object, int *n ) +vips_object_print_all_cb( VipsObject *object, int *n, void *b ) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object ); @@ -3176,7 +3176,7 @@ vips_object_print_all( void ) } static void * -vips_object_sanity_all_cb( VipsObject *object ) +vips_object_sanity_all_cb( VipsObject *object, void *a, void *b ) { (void) vips_object_sanity( object ); diff --git a/libvips/iofuncs/rect.c b/libvips/iofuncs/rect.c index 8e5dd5ac..79ae69f7 100644 --- a/libvips/iofuncs/rect.c +++ b/libvips/iofuncs/rect.c @@ -225,7 +225,7 @@ vips_rect_unionrect( const VipsRect *r1, const VipsRect *r2, VipsRect *out ) * vips_rect_dup: (skip) * @r: rectangle to duplicate * - * Duplicate a rect to the heap. You need to free the result with vips_free(). + * Duplicate a rect to the heap. You need to free the result with g_free(). * * Returns: (transfer full): a pointer to copy of @r allocated on the heap. */ diff --git a/libvips/iofuncs/region.c b/libvips/iofuncs/region.c index 50b4dc83..89d215ab 100644 --- a/libvips/iofuncs/region.c +++ b/libvips/iofuncs/region.c @@ -1576,7 +1576,7 @@ vips_region_shrink( VipsRegion *from, VipsRegion *to, const VipsRect *target ) /* Generate into a region. */ static int -vips_region_generate( VipsRegion *reg ) +vips_region_generate( VipsRegion *reg, void *a ) { VipsImage *im = reg->im; @@ -1659,8 +1659,7 @@ vips_region_prepare( VipsRegion *reg, const VipsRect *r ) switch( im->dtype ) { case VIPS_IMAGE_PARTIAL: - if( vips_region_fill( reg, r, - (VipsRegionFillFn) vips_region_generate, NULL ) ) + if( vips_region_fill( reg, r, vips_region_generate, NULL ) ) return( -1 ); break; @@ -1716,7 +1715,7 @@ vips_region_prepare_to_generate( VipsRegion *reg, /* Run sequence into reg. */ - if( vips_region_generate( reg ) ) + if( vips_region_generate( reg, NULL ) ) return( -1 ); /* The generate function may not have actually made any pixels ... it @@ -2007,7 +2006,7 @@ vips_region_invalidate( VipsRegion *reg ) #ifdef VIPS_DEBUG static void * -vips_region_dump_all_cb( VipsRegion *region, size_t *alive ) +vips_region_dump_all_cb( VipsRegion *region, size_t *alive, void *b ) { char str[2048]; VipsBuf buf = VIPS_BUF_STATIC( str ); diff --git a/libvips/iofuncs/sink.c b/libvips/iofuncs/sink.c index d8cad9b3..17454eda 100644 --- a/libvips/iofuncs/sink.c +++ b/libvips/iofuncs/sink.c @@ -120,7 +120,7 @@ static void sink_area_free( SinkArea *area ) { vips_semaphore_destroy( &area->n_thread ); - vips_free( area ); + g_free( area ); } static SinkArea * diff --git a/libvips/iofuncs/sinkdisc.c b/libvips/iofuncs/sinkdisc.c index 33647b63..8cd62be6 100644 --- a/libvips/iofuncs/sinkdisc.c +++ b/libvips/iofuncs/sinkdisc.c @@ -157,7 +157,7 @@ wbuffer_free( WriteBuffer *wbuffer ) vips_semaphore_destroy( &wbuffer->go ); vips_semaphore_destroy( &wbuffer->nwrite ); vips_semaphore_destroy( &wbuffer->done ); - vips_free( wbuffer ); + g_free( wbuffer ); } static void diff --git a/libvips/iofuncs/sinkmemory.c b/libvips/iofuncs/sinkmemory.c index bde9ac09..0441312f 100644 --- a/libvips/iofuncs/sinkmemory.c +++ b/libvips/iofuncs/sinkmemory.c @@ -126,7 +126,7 @@ static void sink_memory_area_free( SinkMemoryArea *area ) { vips_semaphore_destroy( &area->nwrite ); - vips_free( area ); + g_free( area ); } static SinkMemoryArea * diff --git a/libvips/iofuncs/sinkscreen.c b/libvips/iofuncs/sinkscreen.c index e36644a3..9c216e59 100644 --- a/libvips/iofuncs/sinkscreen.c +++ b/libvips/iofuncs/sinkscreen.c @@ -206,12 +206,12 @@ render_thread_state_new( VipsImage *im, void *a ) } static void * -tile_free( Tile *tile ) +tile_free( Tile *tile, void *a, void *b ) { VIPS_DEBUG_MSG_AMBER( "tile_free\n" ); VIPS_UNREF( tile->region ); - vips_free( tile ); + g_free( tile ); return( NULL ); } @@ -245,7 +245,7 @@ render_free( Render *render ) VIPS_UNREF( render->in ); - vips_free( render ); + g_free( render ); #ifdef VIPS_DEBUG_AMBER render_num_renders -= 1; @@ -454,7 +454,7 @@ vips__render_shutdown( void ) } static int -render_dirty_sort( Render *a, Render *b ) +render_dirty_sort( Render *a, Render *b, void *user_data ) { return( b->priority - a->priority ); } @@ -504,7 +504,7 @@ tile_equal( gconstpointer a, gconstpointer b ) rect1->top == rect2->top ); } -static int +static void render_close_cb( VipsImage *image, Render *render ) { VIPS_DEBUG_MSG_AMBER( "render_close_cb\n" ); @@ -523,8 +523,6 @@ render_close_cb( VipsImage *image, Render *render ) */ VIPS_DEBUG_MSG_GREEN( "render_close_cb: reschedule\n" ); render_reschedule = TRUE; - - return( 0 ); } static Render * @@ -617,7 +615,7 @@ tile_new( Render *render ) tile->ticks = render->ticks; if( !(tile->region = vips_region_new( render->in )) ) { - (void) tile_free( tile ); + (void) tile_free( tile, NULL, NULL ); return( NULL ); } diff --git a/libvips/iofuncs/source.c b/libvips/iofuncs/source.c index b20c5b58..a8d59261 100644 --- a/libvips/iofuncs/source.c +++ b/libvips/iofuncs/source.c @@ -1000,9 +1000,8 @@ vips_source_map( VipsSource *source, size_t *length_out ) } static int -vips_source_map_cb( void *a, void *b ) +vips_source_map_cb( void *a, VipsArea *area ) { - VipsArea *area = VIPS_AREA( b ); GObject *gobject = G_OBJECT( area->client ); VIPS_UNREF( gobject ); @@ -1027,7 +1026,8 @@ vips_source_map_blob( VipsSource *source ) VipsBlob *blob; if( !(buf = vips_source_map( source, &len )) || - !(blob = vips_blob_new( vips_source_map_cb, buf, len )) ) + !(blob = vips_blob_new( (VipsCallbackFn) vips_source_map_cb, + buf, len )) ) return( NULL ); /* The source must stay alive until the blob is done. diff --git a/libvips/iofuncs/target.c b/libvips/iofuncs/target.c index 11ca2fc6..1ca37835 100644 --- a/libvips/iofuncs/target.c +++ b/libvips/iofuncs/target.c @@ -413,7 +413,7 @@ vips_target_finish( VipsTarget *target ) data = g_byte_array_free( target->memory_buffer, FALSE ); target->memory_buffer = NULL; vips_blob_set( target->blob, - (VipsCallbackFn) g_free, data, length ); + (VipsCallbackFn) vips_area_free_cb, data, length ); } else class->finish( target ); diff --git a/libvips/iofuncs/type.c b/libvips/iofuncs/type.c index 120a71da..f706655c 100644 --- a/libvips/iofuncs/type.c +++ b/libvips/iofuncs/type.c @@ -171,6 +171,14 @@ vips_area_copy( VipsArea *area ) return( area ); } +int +vips_area_free_cb( void *mem, VipsArea *area ) +{ + g_free( mem ); + + return( 0 ); +} + void vips_area_free( VipsArea *area ) { @@ -314,7 +322,7 @@ vips_area_new_array( GType type, size_t sizeof_type, int n ) void *array; array = g_malloc( n * sizeof_type ); - area = vips_area_new( (VipsCallbackFn) g_free, array ); + area = vips_area_new( (VipsCallbackFn) vips_area_free_cb, array ); area->n = n; area->length = n * sizeof_type; area->type = type; @@ -323,7 +331,7 @@ vips_area_new_array( GType type, size_t sizeof_type, int n ) return( area ); } -static void +static int vips_area_free_array_object( GObject **array, VipsArea *area ) { int i; @@ -333,6 +341,8 @@ vips_area_free_array_object( GObject **array, VipsArea *area ) VIPS_FREE( array ); area->n = 0; + + return( 0 ); } /** @@ -556,7 +566,7 @@ vips_ref_string_new( const char *str ) if( !g_utf8_validate( str, -1, NULL ) ) str = ""; - area = vips_area_new( (VipsCallbackFn) g_free, g_strdup( str ) ); + area = vips_area_new( (VipsCallbackFn) vips_area_free_cb, g_strdup( str ) ); /* Handy place to cache this. */ @@ -655,7 +665,7 @@ vips_blob_copy( const void *data, size_t length ) data_copy = vips_malloc( NULL, length ); memcpy( data_copy, data, length ); - area = vips_area_new( (VipsCallbackFn) g_free, data_copy ); + area = vips_area_new( (VipsCallbackFn) vips_area_free_cb, data_copy ); area->length = length; return( (VipsBlob *) area ); @@ -737,7 +747,7 @@ transform_blob_save_string( const GValue *src_value, GValue *dest_value ) blob = vips_value_get_blob( src_value, &length ); if( (b64 = g_base64_encode( blob, length )) ) { vips_value_set_save_string( dest_value, b64 ); - vips_free( b64 ); + g_free( b64 ); } else /* No error return from transform, but we should set it to @@ -756,7 +766,7 @@ transform_save_string_blob( const GValue *src_value, GValue *dest_value ) b64 = vips_value_get_save_string( src_value ); if( (blob = g_base64_decode( b64, &length )) ) vips_value_set_blob( dest_value, - (VipsCallbackFn) vips_free, blob, length ); + (VipsCallbackFn) vips_area_free_cb, blob, length ); else /* No error return from transform, but we should set it to * something. @@ -1641,7 +1651,7 @@ vips_value_set_blob_free( GValue *value, void *data, size_t length ) g_assert( G_VALUE_TYPE( value ) == VIPS_TYPE_BLOB ); - blob = vips_blob_new( (VipsCallbackFn) g_free, data, length ); + blob = vips_blob_new( (VipsCallbackFn) vips_area_free_cb, data, length ); g_value_set_boxed( value, blob ); vips_area_unref( VIPS_AREA( blob ) ); } diff --git a/libvips/iofuncs/util.c b/libvips/iofuncs/util.c index f99deb81..0629adab 100644 --- a/libvips/iofuncs/util.c +++ b/libvips/iofuncs/util.c @@ -222,10 +222,10 @@ vips_slist_filter( GSList *list, VipsSListMap2Fn fn, void *a, void *b ) static void vips_slist_free_all_cb( void * thing, void * dummy ) { - vips_free( thing ); + g_free( thing ); } -/* Free a g_slist of things which need vips_free()ing. +/* Free a g_slist of things which need g_free()ing. */ void vips_slist_free_all( GSList *list ) @@ -815,7 +815,7 @@ vips__file_read( FILE *fp, const char *filename, size_t *length_out ) rewind( fp ); read = fread( str, sizeof( char ), (size_t) len, fp ); if( read != (size_t) len ) { - vips_free( str ); + g_free( str ); vips_error( "vips__file_read", _( "error reading from file \"%s\"" ), filename ); @@ -944,7 +944,7 @@ vips__gvalue_copy( GValue *value ) } static void -vips__gvalue_free( GValue *value ) +vips__gvalue_free( GValue *value, void *user_data ) { g_value_unset( value ); g_free( value ); @@ -2031,7 +2031,7 @@ vips__icc_dir( void ) static GOnce once = G_ONCE_INIT; return( (const char *) g_once( &once, - (GThreadFunc) vips_icc_dir_once, NULL ) ); + vips_icc_dir_once, NULL ) ); } #ifdef OS_WIN32 @@ -2069,7 +2069,7 @@ vips__windows_prefix( void ) static GOnce once = G_ONCE_INIT; return( (const char *) g_once( &once, - (GThreadFunc) vips__windows_prefix_once, NULL ) ); + vips__windows_prefix_once, NULL ) ); } char * diff --git a/libvips/iofuncs/vips.c b/libvips/iofuncs/vips.c index 16e74759..a1b61ab8 100644 --- a/libvips/iofuncs/vips.c +++ b/libvips/iofuncs/vips.c @@ -490,7 +490,7 @@ read_chunk( int fd, gint64 offset, size_t length ) if( !(buf = vips_malloc( NULL, length + 1 )) ) return( NULL ); if( read( fd, buf, length ) != (ssize_t) length ) { - vips_free( buf ); + g_free( buf ); vips_error( "VipsImage", "%s", _( "unable to read history" ) ); return( NULL ); } @@ -828,7 +828,7 @@ target_write_quotes( VipsTarget *target, const char *str ) } static void * -build_xml_meta( VipsMeta *meta, VipsTarget *target ) +build_xml_meta( VipsMeta *meta, VipsTarget *target, void *b ) { GType type = G_VALUE_TYPE( &meta->value ); diff --git a/libvips/iofuncs/window.c b/libvips/iofuncs/window.c index 8b98683d..875c895e 100644 --- a/libvips/iofuncs/window.c +++ b/libvips/iofuncs/window.c @@ -129,7 +129,7 @@ vips_window_free( VipsWindow *window ) window->im = NULL; - vips_free( window ); + g_free( window ); return( 0 ); } @@ -307,7 +307,7 @@ typedef struct { } request_t; static void * -vips_window_fits( VipsWindow *window, request_t *req ) +vips_window_fits( VipsWindow *window, request_t *req, void *b ) { if( window->top <= req->top && window->top + window->height >= req->top + req->height ) From 41961f138a5ea906164a843921ba739479bdf374 Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Tue, 30 Jun 2020 20:00:42 +0100 Subject: [PATCH 04/10] webpsave: when minimising the size of an animated WebP image, allow the encoder to evaluate and mix lossy+lossless frames, which minimises the size of the file by a further ~5%. See https://github.com/webmproject/libwebp/commit/f29bf582df2349b29264e188670750b54850651e --- libvips/foreign/vips2webp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/libvips/foreign/vips2webp.c b/libvips/foreign/vips2webp.c index c63f2a8d..f480e67d 100644 --- a/libvips/foreign/vips2webp.c +++ b/libvips/foreign/vips2webp.c @@ -310,6 +310,7 @@ write_webp_anim( VipsWebPWrite *write, VipsImage *image, int page_height ) } anim_config.minimize_size = write->min_size; + anim_config.allow_mixed = write->min_size; anim_config.kmin = write->kmin; anim_config.kmax = write->kmax; From 0803de07e7586ea3127f9f2b71710ab065f43f53 Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Wed, 1 Jul 2020 17:31:25 +0100 Subject: [PATCH 05/10] move vips__lr|tbmerge to private API --- libvips/deprecated/mosaicing_dispatch.c | 4 +- libvips/deprecated/vips7compat.c | 38 ++++++ libvips/include/vips/vips7compat.h | 4 + libvips/mosaicing/Makefile.am | 4 +- libvips/mosaicing/global_balance.c | 43 ++++--- libvips/mosaicing/im_lrmosaic.c | 10 +- libvips/mosaicing/im_tbmosaic.c | 10 +- libvips/mosaicing/{im_lrmerge.c => lrmerge.c} | 115 +++++++++--------- libvips/mosaicing/merge.c | 17 ++- libvips/mosaicing/mosaic1.c | 2 +- libvips/mosaicing/{im_tbmerge.c => tbmerge.c} | 33 +++-- test/test-suite/test_mosaicing.py | 17 +-- 12 files changed, 182 insertions(+), 115 deletions(-) rename libvips/mosaicing/{im_lrmerge.c => lrmerge.c} (90%) rename libvips/mosaicing/{im_tbmerge.c => tbmerge.c} (96%) diff --git a/libvips/deprecated/mosaicing_dispatch.c b/libvips/deprecated/mosaicing_dispatch.c index ab70f938..b8f7b121 100644 --- a/libvips/deprecated/mosaicing_dispatch.c +++ b/libvips/deprecated/mosaicing_dispatch.c @@ -367,7 +367,7 @@ lrmerge_vec( im_object *argv ) int dy = *((int *) argv[4]); int mwidth = *((int *) argv[5]); - return( vips_lrmerge( argv[0], argv[1], argv[2], dx, dy, mwidth ) ); + return( im_lrmerge( argv[0], argv[1], argv[2], dx, dy, mwidth ) ); } /* Call im_lrmerge1 via arg vector. @@ -421,7 +421,7 @@ tbmerge_vec( im_object *argv ) int dy = *((int *) argv[4]); int mwidth = *((int *) argv[5]); - return( vips_tbmerge( argv[0], argv[1], argv[2], dx, dy, mwidth ) ); + return( im_tbmerge( argv[0], argv[1], argv[2], dx, dy, mwidth ) ); } /* Call im_tbmerge1 via arg vector. diff --git a/libvips/deprecated/vips7compat.c b/libvips/deprecated/vips7compat.c index dd01f70c..f0a8f2fc 100644 --- a/libvips/deprecated/vips7compat.c +++ b/libvips/deprecated/vips7compat.c @@ -5367,6 +5367,25 @@ im_tbmosaic1( IMAGE *ref, IMAGE *sec, IMAGE *out, return( 0 ); } +int +im_lrmerge( IMAGE *ref, IMAGE *sec, IMAGE *out, + int dx, int dy, int mwidth ) +{ + VipsImage *x; + + if( vips_merge( ref, sec, &x, VIPS_DIRECTION_HORIZONTAL, dx, dy, + "mblend", mwidth, + NULL ) ) + return( -1 ); + if( vips_image_write( x, out ) ) { + g_object_unref( x ); + return( -1 ); + } + g_object_unref( x ); + + return( 0 ); +} + int im_lrmerge1( IMAGE *ref, IMAGE *sec, IMAGE *out, int xr1, int yr1, int xs1, int ys1, @@ -5389,6 +5408,25 @@ im_lrmerge1( IMAGE *ref, IMAGE *sec, IMAGE *out, return( 0 ); } +int +im_tbmerge( IMAGE *ref, IMAGE *sec, IMAGE *out, + int dx, int dy, int mwidth ) +{ + VipsImage *x; + + if( vips_merge( ref, sec, &x, VIPS_DIRECTION_VERTICAL, dx, dy, + "mblend", mwidth, + NULL ) ) + return( -1 ); + if( vips_image_write( x, out ) ) { + g_object_unref( x ); + return( -1 ); + } + g_object_unref( x ); + + return( 0 ); +} + int im_tbmerge1( IMAGE *ref, IMAGE *sec, IMAGE *out, int xr1, int yr1, int xs1, int ys1, diff --git a/libvips/include/vips/vips7compat.h b/libvips/include/vips/vips7compat.h index 7c1f01d0..460eab0c 100644 --- a/libvips/include/vips/vips7compat.h +++ b/libvips/include/vips/vips7compat.h @@ -1065,10 +1065,14 @@ int im_global_balancef( VipsImage *in, VipsImage *out, double gamma ); int im_remosaic( VipsImage *in, VipsImage *out, const char *old_str, const char *new_str ); +int im_lrmerge( VipsImage *ref, VipsImage *sec, VipsImage *out, + int dx, int dy, int mwidth ); int im_lrmerge1( VipsImage *ref, VipsImage *sec, VipsImage *out, int xr1, int yr1, int xs1, int ys1, int xr2, int yr2, int xs2, int ys2, int mwidth ); +int im_tbmerge( VipsImage *ref, VipsImage *sec, VipsImage *out, + int dx, int dy, int mwidth ); int im_tbmerge1( VipsImage *ref, VipsImage *sec, VipsImage *out, int xr1, int yr1, int xs1, int ys1, int xr2, int yr2, int xs2, int ys2, diff --git a/libvips/mosaicing/Makefile.am b/libvips/mosaicing/Makefile.am index d7da3b87..9d7b4035 100644 --- a/libvips/mosaicing/Makefile.am +++ b/libvips/mosaicing/Makefile.am @@ -8,16 +8,16 @@ libmosaicing_la_SOURCES = \ mosaic1.c \ matrixinvert.c \ global_balance.c \ + lrmerge.c \ + tbmerge.c \ im_avgdxdy.c \ im_chkpair.c \ im_clinear.c \ im_improve.c \ im_initialize.c \ im_lrcalcon.c \ - im_lrmerge.c \ im_lrmosaic.c \ im_tbcalcon.c \ - im_tbmerge.c \ im_remosaic.c \ im_tbmosaic.c \ global_balance.h \ diff --git a/libvips/mosaicing/global_balance.c b/libvips/mosaicing/global_balance.c index ba45d395..3089cebf 100644 --- a/libvips/mosaicing/global_balance.c +++ b/libvips/mosaicing/global_balance.c @@ -1340,22 +1340,17 @@ make_mos_image( SymbolTable *st, JoinNode *node, transform_fn tfn, void *a ) !(im2 = make_mos_image( st, node->arg2, tfn, a )) ) return( NULL ); - out = vips_image_new(); + if( vips_merge( im1, im2, &out, + node->type == JOIN_LR ? + VIPS_DIRECTION_HORIZONTAL : + VIPS_DIRECTION_VERTICAL, + -node->dx, -node->dy, + "mblend", node->mwidth, + NULL ) ) + return( NULL ); vips_object_local( st->im, out ); - vips_image_set_string( out, "mosaic-name", node->name ); - if( node->type == JOIN_LR ) { - if( vips_lrmerge( im1, im2, out, - -node->dx, -node->dy, node->mwidth ) ) - return( NULL ); - } - else { - if( vips_tbmerge( im1, im2, out, - -node->dx, -node->dy, node->mwidth ) ) - return( NULL ); - } - break; case JOIN_LRROTSCALE: @@ -1415,6 +1410,7 @@ vips__build_mosaic( SymbolTable *st, VipsImage *out, transform_fn tfn, void *a ) { JoinNode *root = st->root; VipsImage *im1, *im2; + VipsImage *x; switch( root->type ) { case JOIN_LR: @@ -1423,16 +1419,19 @@ vips__build_mosaic( SymbolTable *st, VipsImage *out, transform_fn tfn, void *a ) !(im2 = make_mos_image( st, root->arg2, tfn, a )) ) return( -1 ); - if( root->type == JOIN_LR ) { - if( vips_lrmerge( im1, im2, out, - -root->dx, -root->dy, root->mwidth ) ) - return( -1 ); - } - else { - if( vips_tbmerge( im1, im2, out, - -root->dx, -root->dy, root->mwidth ) ) - return( -1 ); + if( vips_merge( im1, im2, &x, + root->type == JOIN_LR ? + VIPS_DIRECTION_HORIZONTAL : + VIPS_DIRECTION_VERTICAL, + -root->dx, -root->dy, + "mblend", root->mwidth, + NULL ) ) + return( -1 ); + if( vips_image_write( x, out ) ) { + g_object_unref( x ); + return( -1 ); } + g_object_unref( x ); break; diff --git a/libvips/mosaicing/im_lrmosaic.c b/libvips/mosaicing/im_lrmosaic.c index 5832897a..975a062e 100644 --- a/libvips/mosaicing/im_lrmosaic.c +++ b/libvips/mosaicing/im_lrmosaic.c @@ -252,6 +252,7 @@ vips_lrmosaic( VipsImage *ref, VipsImage *sec, VipsImage *out, int dx0, dy0; double scale1, angle1, dx1, dy1; VipsImage *dummy; + VipsImage *x; /* Correct overlap. dummy is just a placeholder used to ensure that * memory used by the analysis phase is freed as soon as possible. @@ -270,8 +271,15 @@ vips_lrmosaic( VipsImage *ref, VipsImage *sec, VipsImage *out, /* Merge left right. */ - if( vips_lrmerge( ref, sec, out, dx0, dy0, mwidth ) ) + if( vips_merge( ref, sec, &x, VIPS_DIRECTION_HORIZONTAL, dx0, dy0, + "mblend", mwidth, + NULL ) ) return( -1 ); + if( vips_image_write( x, out ) ) { + g_object_unref( x ); + return( -1 ); + } + g_object_unref( x ); return( 0 ); } diff --git a/libvips/mosaicing/im_tbmosaic.c b/libvips/mosaicing/im_tbmosaic.c index 61d8364b..2d3a85ee 100644 --- a/libvips/mosaicing/im_tbmosaic.c +++ b/libvips/mosaicing/im_tbmosaic.c @@ -223,6 +223,7 @@ vips_tbmosaic( VipsImage *ref, VipsImage *sec, VipsImage *out, int dx0, dy0; double scale1, angle1, dx1, dy1; VipsImage *dummy; + VipsImage *x; /* Correct overlap. dummy is just a placeholder used to ensure that * memory used by the analysis phase is freed as soon as possible. @@ -241,8 +242,15 @@ vips_tbmosaic( VipsImage *ref, VipsImage *sec, VipsImage *out, /* Merge top-bottom. */ - if( vips_tbmerge( ref, sec, out, dx0, dy0, mwidth ) ) + if( vips_merge( ref, sec, &x, VIPS_DIRECTION_VERTICAL, dx0, dy0, + "mblend", mwidth, + NULL ) ) return( -1 ); + if( vips_image_write( x, out ) ) { + g_object_unref( x ); + return( -1 ); + } + g_object_unref( x ); return( 0 ); } diff --git a/libvips/mosaicing/im_lrmerge.c b/libvips/mosaicing/lrmerge.c similarity index 90% rename from libvips/mosaicing/im_lrmerge.c rename to libvips/mosaicing/lrmerge.c index 4bbe31f2..8bb6f9dc 100644 --- a/libvips/mosaicing/im_lrmerge.c +++ b/libvips/mosaicing/lrmerge.c @@ -203,19 +203,19 @@ find_first( VipsRegion *ir, int *pos, int x, int y, int w ) } switch( im->BandFmt ) { - case VIPS_FORMAT_UCHAR: lsearch( unsigned char ); break; - case VIPS_FORMAT_CHAR: lsearch( signed char ); break; + case VIPS_FORMAT_UCHAR: lsearch( unsigned char ); break; + case VIPS_FORMAT_CHAR: lsearch( signed char ); break; case VIPS_FORMAT_USHORT: lsearch( unsigned short ); break; - case VIPS_FORMAT_SHORT: lsearch( signed short ); break; - case VIPS_FORMAT_UINT: lsearch( unsigned int ); break; - case VIPS_FORMAT_INT: lsearch( signed int ); break; - case VIPS_FORMAT_FLOAT: lsearch( float ); break; + case VIPS_FORMAT_SHORT: lsearch( signed short ); break; + case VIPS_FORMAT_UINT: lsearch( unsigned int ); break; + case VIPS_FORMAT_INT: lsearch( signed int ); break; + case VIPS_FORMAT_FLOAT: lsearch( float ); break; case VIPS_FORMAT_DOUBLE: lsearch( double ); break; case VIPS_FORMAT_COMPLEX: lsearch( float ); break; case VIPS_FORMAT_DPCOMPLEX: lsearch( double ); break; default: - vips_error( "vips_lrmerge", "%s", _( "internal error" ) ); + g_assert_not_reached(); return( -1 ); } @@ -252,19 +252,19 @@ find_last( VipsRegion *ir, int *pos, int x, int y, int w ) } switch( im->BandFmt ) { - case VIPS_FORMAT_UCHAR: rsearch( unsigned char ); break; - case VIPS_FORMAT_CHAR: rsearch( signed char ); break; + case VIPS_FORMAT_UCHAR: rsearch( unsigned char ); break; + case VIPS_FORMAT_CHAR: rsearch( signed char ); break; case VIPS_FORMAT_USHORT: rsearch( unsigned short ); break; - case VIPS_FORMAT_SHORT: rsearch( signed short ); break; - case VIPS_FORMAT_UINT: rsearch( unsigned int ); break; - case VIPS_FORMAT_INT: rsearch( signed int ); break; - case VIPS_FORMAT_FLOAT: rsearch( float ); break; + case VIPS_FORMAT_SHORT: rsearch( signed short ); break; + case VIPS_FORMAT_UINT: rsearch( unsigned int ); break; + case VIPS_FORMAT_INT: rsearch( signed int ); break; + case VIPS_FORMAT_FLOAT: rsearch( float ); break; case VIPS_FORMAT_DOUBLE: rsearch( double ); break; case VIPS_FORMAT_COMPLEX: rsearch( float ); break; case VIPS_FORMAT_DPCOMPLEX: rsearch( double ); break; default: - vips_error( "vipslrmerge", "%s", _( "internal error" ) ); + vips_error( "lrmerge", "%s", _( "internal error" ) ); return( -1 ); } @@ -330,7 +330,7 @@ make_firstlast( MergeInfo *inf, Overlapping *ovlap, VipsRect *oreg ) sr.top -= ovlap->sarea.top; #ifdef DEBUG - printf( "vips__lrmerge: making first/last for areas:\n" ); + printf( "lrmerge: making first/last for areas:\n" ); printf( "ref: left = %d, top = %d, width = %d, height = %d\n", rr.left, rr.top, rr.width, rr.height ); printf( "sec: left = %d, top = %d, width = %d, height = %d\n", @@ -605,7 +605,7 @@ lr_blend( VipsRegion *or, MergeInfo *inf, Overlapping *ovlap, VipsRect *oreg ) fblend( double, im->Bands * 2, pr, ps, q ); break; default: - vips_error( "vips_lrmerge", "%s", _( "internal error" ) ); + g_assert_not_reached(); return( -1 ); } } @@ -616,7 +616,8 @@ lr_blend( VipsRegion *or, MergeInfo *inf, Overlapping *ovlap, VipsRect *oreg ) /* Left-right blend function for VIPS_CODING_LABQ images. */ static int -lr_blend_labpack( VipsRegion *or, MergeInfo *inf, Overlapping *ovlap, VipsRect *oreg ) +lr_blend_labpack( VipsRegion *or, MergeInfo *inf, Overlapping *ovlap, + VipsRect *oreg ) { VipsRegion *rir = inf->rir; VipsRegion *sir = inf->sir; @@ -688,11 +689,12 @@ lock_free( VipsImage *image, GMutex *lock ) } /* Build basic per-call state and do some geometry calculations. Shared with - * vips_tbmerge, so not static. + * tbmerge, so not static. */ Overlapping * vips__build_mergestate( const char *domain, - VipsImage *ref, VipsImage *sec, VipsImage *out, int dx, int dy, int mwidth ) + VipsImage *ref, VipsImage *sec, VipsImage *out, + int dx, int dy, int mwidth ) { VipsImage **t = (VipsImage **) vips_object_local_array( VIPS_OBJECT( out ), 4 ); @@ -703,14 +705,13 @@ vips__build_mergestate( const char *domain, /* TODO(kleisauke): Copied from vips_insert, perhaps we * need a separate function for this? - * (just like im__insert_base) */ + * (just like im__insert_base) + */ if( vips_image_pio_input( ref ) || vips_image_pio_input( sec ) || - vips_check_bands_1orn( domain, - ref, sec ) || + vips_check_bands_1orn( domain, ref, sec ) || vips_check_coding_known( domain, ref ) || - vips_check_coding_same( domain, - ref, sec ) ) + vips_check_coding_same( domain, ref, sec ) ) return( NULL ); /* Cast our input images up to a common format and bands. @@ -809,11 +810,12 @@ vips__build_mergestate( const char *domain, /* Build per-call state. */ static Overlapping * -build_lrstate( VipsImage *ref, VipsImage *sec, VipsImage *out, int dx, int dy, int mwidth ) +build_lrstate( VipsImage *ref, VipsImage *sec, VipsImage *out, + int dx, int dy, int mwidth ) { Overlapping *ovlap; - if( !(ovlap = vips__build_mergestate( "vips_lrmerge", + if( !(ovlap = vips__build_mergestate( "lrmerge", ref, sec, out, dx, dy, mwidth )) ) return( NULL ); @@ -829,7 +831,7 @@ build_lrstate( VipsImage *ref, VipsImage *sec, VipsImage *out, int dx, int dy, i break; default: - vips_error( "vips_lrmerge", "%s", _( "unknown coding type" ) ); + vips_error( "lrmerge", "%s", _( "unknown coding type" ) ); return( NULL ); } @@ -844,9 +846,10 @@ build_lrstate( VipsImage *ref, VipsImage *sec, VipsImage *out, int dx, int dy, i /* Is there too much overlap? ie. right edge of ref image is greater * than right edge of sec image, or left > left. */ - if( VIPS_RECT_RIGHT( &ovlap->rarea ) > VIPS_RECT_RIGHT( &ovlap->sarea ) || + if( VIPS_RECT_RIGHT( &ovlap->rarea ) > + VIPS_RECT_RIGHT( &ovlap->sarea ) || ovlap->rarea.left > ovlap->sarea.left ) { - vips_error( "vips_lrmerge", "%s", _( "too much overlap" ) ); + vips_error( "lrmerge", "%s", _( "too much overlap" ) ); return( NULL ); } @@ -861,7 +864,7 @@ build_lrstate( VipsImage *ref, VipsImage *sec, VipsImage *out, int dx, int dy, i * or the sec images. Attach output to the appropriate part of the input image. * area is the position that ir->im occupies in the output image. * - * Shared with vips_tbmerge(), so not static. + * Shared with tbmerge, so not static. */ int vips__attach_input( VipsRegion *or, VipsRegion *ir, VipsRect *area ) @@ -890,10 +893,11 @@ vips__attach_input( VipsRegion *or, VipsRegion *ir, VipsRect *area ) * above, but just do a sub-area of the output, and make sure we copy rather * than just pointer-fiddling. reg is the sub-area of or->valid we should do. * - * Shared with vips_tbmerge(), so not static. + * Shared with tbmerge, so not static. */ int -vips__copy_input( VipsRegion *or, VipsRegion *ir, VipsRect *area, VipsRect *reg ) +vips__copy_input( VipsRegion *or, VipsRegion *ir, + VipsRect *area, VipsRect *reg ) { VipsRect r = *reg; @@ -910,8 +914,8 @@ vips__copy_input( VipsRegion *or, VipsRegion *ir, VipsRect *area, VipsRect *reg return( 0 ); } -/* Generate function for merge. This is shared between vips_lrmerge() and - * vips_tbmerge(). +/* Generate function for merge. This is shared between lrmerge and + * tbmerge. */ int vips__merge_gen( VipsRegion *or, void *seq, void *a, void *b, @@ -981,7 +985,7 @@ vips__merge_gen( VipsRegion *or, void *seq, void *a, void *b, return( 0 ); } -/* Stop function. Shared with vips_tbmerge(). Free explicitly to reduce mem +/* Stop function. Shared with tbmerge. Free explicitly to reduce mem * requirements quickly for large mosaics. */ int @@ -999,7 +1003,7 @@ vips__stop_merge( void *seq, void *a, void *b ) return( 0 ); } -/* Start function. Shared with vips_tbmerge(). +/* Start function. Shared with tbmerge. */ void * vips__start_merge( VipsImage *out, void *a, void *b ) @@ -1041,12 +1045,13 @@ vips__start_merge( VipsImage *out, void *a, void *b ) } int -vips__lrmerge( VipsImage *ref, VipsImage *sec, VipsImage *out, int dx, int dy, int mwidth ) +vips__lrmerge( VipsImage *ref, VipsImage *sec, VipsImage *out, + int dx, int dy, int mwidth ) { Overlapping *ovlap; #ifdef DEBUG - printf( "vips__lrmerge %s %s %s %d %d %d\n", + printf( "lrmerge %s %s %s %d %d %d\n", ref->filename, sec->filename, out->filename, dx, dy, mwidth ); printf( "ref is %d x %d pixels\n", ref->Xsize, ref->Ysize ); @@ -1054,16 +1059,24 @@ vips__lrmerge( VipsImage *ref, VipsImage *sec, VipsImage *out, int dx, int dy, i #endif if( dx > 0 || dx < 1 - ref->Xsize ) { + VipsImage *x; + #ifdef DEBUG - printf( "vips__lrmerge: no overlap, using insert\n" ); + printf( "lrmerge: no overlap, using insert\n" ); #endif /* No overlap, use insert instead. */ - if( vips_insert( ref, sec, &out, -dx, -dy, + if( vips_insert( ref, sec, &x, -dx, -dy, "expand", TRUE, NULL ) ) return( -1 ); + if( vips_image_write( x, out ) ) { + g_object_unref( x ); + return( -1 ); + } + g_object_unref( x ); + out->Xoffset = -dx; out->Yoffset = -dy; @@ -1083,7 +1096,8 @@ vips__lrmerge( VipsImage *ref, VipsImage *sec, VipsImage *out, int dx, int dy, i out->Yoffset = -dy; if( vips_image_generate( out, - vips__start_merge, vips__merge_gen, vips__stop_merge, ovlap, NULL ) ) + vips__start_merge, vips__merge_gen, vips__stop_merge, + ovlap, NULL ) ) return( -1 ); return ( 0 ); @@ -1109,8 +1123,9 @@ vips__add_mosaic_name( VipsImage *image ) { static int global_serial = 0; - /* TODO(kleisauke): Could we call vips_image_temp_name instead? */ /* Old glibs named this differently. + * + * TODO(kleisauke): Could we call vips_image_temp_name instead? */ int serial = #if GLIB_CHECK_VERSION( 2, 30, 0 ) @@ -1128,19 +1143,3 @@ vips__add_mosaic_name( VipsImage *image ) vips_image_set_string( image, "mosaic-name", name ); } -int -vips_lrmerge( VipsImage *ref, VipsImage *sec, VipsImage *out, int dx, int dy, int mwidth ) -{ - if( vips__lrmerge( ref, sec, out, dx, dy, mwidth ) ) - return( -1 ); - - vips__add_mosaic_name( out ); - if( vips_image_history_printf( out, "#LRJOIN <%s> <%s> <%s> <%d> <%d> <%d>", - vips__get_mosaic_name( ref ), - vips__get_mosaic_name( sec ), - vips__get_mosaic_name( out ), - -dx, -dy, mwidth ) ) - return( -1 ); - - return( 0 ); -} diff --git a/libvips/mosaicing/merge.c b/libvips/mosaicing/merge.c index e2f33118..3f0b419d 100644 --- a/libvips/mosaicing/merge.c +++ b/libvips/mosaicing/merge.c @@ -41,7 +41,7 @@ #include #include -#include +#include "pmosaicing.h" typedef struct { VipsOperation parent_instance; @@ -72,13 +72,13 @@ vips_merge_build( VipsObject *object ) switch( merge->direction ) { case VIPS_DIRECTION_HORIZONTAL: - if( vips_lrmerge( merge->ref, merge->sec, merge->out, + if( vips__lrmerge( merge->ref, merge->sec, merge->out, merge->dx, merge->dy, merge->mblend ) ) return( -1 ); break; case VIPS_DIRECTION_VERTICAL: - if( vips_tbmerge( merge->ref, merge->sec, merge->out, + if( vips__tbmerge( merge->ref, merge->sec, merge->out, merge->dx, merge->dy, merge->mblend ) ) return( -1 ); break; @@ -87,6 +87,17 @@ vips_merge_build( VipsObject *object ) g_assert_not_reached(); } + vips__add_mosaic_name( merge->out ); + if( vips_image_history_printf( merge->out, + "#%s <%s> <%s> <%s> <%d> <%d> <%d>", + merge->direction == VIPS_DIRECTION_HORIZONTAL ? + "LRJOIN" : "TBJOIN", + vips__get_mosaic_name( merge->ref ), + vips__get_mosaic_name( merge->sec ), + vips__get_mosaic_name( merge->out ), + -merge->dx, -merge->dy, merge->mblend ) ) + return( -1 ); + return( 0 ); } diff --git a/libvips/mosaicing/mosaic1.c b/libvips/mosaicing/mosaic1.c index 8cebcb2b..379ed5ec 100644 --- a/libvips/mosaicing/mosaic1.c +++ b/libvips/mosaicing/mosaic1.c @@ -394,7 +394,7 @@ old_lrmosaic1( VipsImage *ref, VipsImage *sec, VipsImage *out, /* And join to ref. */ - if( vips_lrmerge( ref, t[1], out, + if( vips_merge( ref, t[1], out, VIPS_DIRECtION_HORIZONTAL, -trn2.area.left, -trn2.area.top, mwidth ) ) return( -1 ); diff --git a/libvips/mosaicing/im_tbmerge.c b/libvips/mosaicing/tbmerge.c similarity index 96% rename from libvips/mosaicing/im_tbmerge.c rename to libvips/mosaicing/tbmerge.c index 8600f25e..6959878f 100644 --- a/libvips/mosaicing/im_tbmerge.c +++ b/libvips/mosaicing/tbmerge.c @@ -663,17 +663,30 @@ build_tbstate( VipsImage *ref, VipsImage *sec, VipsImage *out, int dx, int dy, i } int -vips__tbmerge( VipsImage *ref, VipsImage *sec, VipsImage *out, int dx, int dy, int mwidth ) +vips__tbmerge( VipsImage *ref, VipsImage *sec, VipsImage *out, + int dx, int dy, int mwidth ) { Overlapping *ovlap; if( dy > 0 || dy < 1 - ref->Ysize ) { + VipsImage *x; + +#ifdef DEBUG + printf( "vips__tbmerge: no overlap, using insert\n" ); +#endif + /* No overlap, use insert instead. */ - if( vips_insert( ref, sec, &out, -dx, -dy, + if( vips_insert( ref, sec, &x, -dx, -dy, "expand", TRUE, NULL ) ) return( -1 ); + if( vips_image_write( x, out ) ) { + g_object_unref( x ); + return( -1 ); + } + g_object_unref( x ); + out->Xoffset = -dx; out->Yoffset = -dy; @@ -699,19 +712,3 @@ vips__tbmerge( VipsImage *ref, VipsImage *sec, VipsImage *out, int dx, int dy, i return ( 0 ); } -int -vips_tbmerge( VipsImage *ref, VipsImage *sec, VipsImage *out, int dx, int dy, int mwidth ) -{ - if( vips__tbmerge( ref, sec, out, dx, dy, mwidth ) ) - return( -1 ); - - vips__add_mosaic_name( out ); - if( vips_image_history_printf( out, "#TBJOIN <%s> <%s> <%s> <%d> <%d> <%d>", - vips__get_mosaic_name( ref ), - vips__get_mosaic_name( sec ), - vips__get_mosaic_name( out ), - -dx, -dy, mwidth ) ) - return( -1 ); - - return( 0 ); -} diff --git a/test/test-suite/test_mosaicing.py b/test/test-suite/test_mosaicing.py index f9e85be5..7d79fcb1 100644 --- a/test/test-suite/test_mosaicing.py +++ b/test/test-suite/test_mosaicing.py @@ -16,21 +16,24 @@ class TestMosaicing: im = pyvips.Image.new_from_file(files[0]) sec_im = pyvips.Image.new_from_file(files[1]) - horizontal_part = im.mosaic(sec_im, pyvips.Direction.HORIZONTAL, - marks[0][0], marks[0][1], marks[1][0], marks[1][1]) + horizontal_part = im.mosaic(sec_im, + pyvips.Direction.HORIZONTAL, + marks[0][0], marks[0][1], + marks[1][0], marks[1][1]) if mosaiced_image is None: mosaiced_image = horizontal_part else: vertical_marks = MOSAIC_VERTICAL_MARKS[i - 2:i] - mosaiced_image = mosaiced_image.mosaic(horizontal_part, pyvips.Direction.VERTICAL, - vertical_marks[1][0], vertical_marks[1][1], - vertical_marks[0][0], vertical_marks[0][1]) + mosaiced_image = mosaiced_image.mosaic(horizontal_part, + pyvips.Direction.VERTICAL, + vertical_marks[1][0], vertical_marks[1][1], + vertical_marks[0][0], vertical_marks[0][1]) - mosaiced_image = mosaiced_image.globalbalance() + mosaiced_image = mosaiced_image.globalbalance() # Uncomment to see output file - # mosaiced_image.write_to_file('1-pt-mosaic.jpg') + #mosaiced_image.write_to_file('after.jpg') # hard to test much more than this assert mosaiced_image.width == 1005 From 3c071a8ebb18e321026b84d173ea0cc47caa0790 Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Thu, 2 Jul 2020 12:35:37 +0100 Subject: [PATCH 06/10] more the rest of mosaicing into private API chkpair, lr|tbmosaic, etc. --- libvips/deprecated/mosaicing_dispatch.c | 6 ++-- libvips/include/vips/internal.h | 35 ++++++++----------- libvips/mosaicing/Makefile.am | 8 ++--- libvips/mosaicing/{im_chkpair.c => chkpair.c} | 17 ++++----- .../mosaicing/{im_lrmosaic.c => lrmosaic.c} | 2 +- libvips/mosaicing/match.c | 4 +-- libvips/mosaicing/mosaic1.c | 4 +-- libvips/mosaicing/mosaicing.c | 16 ++++----- libvips/mosaicing/pmosaicing.h | 6 ++++ .../mosaicing/{im_remosaic.c => remosaic.c} | 0 .../mosaicing/{im_tbmosaic.c => tbmosaic.c} | 2 +- po/POTFILES.in | 12 +++---- 12 files changed, 55 insertions(+), 57 deletions(-) rename libvips/mosaicing/{im_chkpair.c => chkpair.c} (94%) rename libvips/mosaicing/{im_lrmosaic.c => lrmosaic.c} (99%) rename libvips/mosaicing/{im_remosaic.c => remosaic.c} (100%) rename libvips/mosaicing/{im_tbmosaic.c => tbmosaic.c} (99%) diff --git a/libvips/deprecated/mosaicing_dispatch.c b/libvips/deprecated/mosaicing_dispatch.c index b8f7b121..bf7a6ed6 100644 --- a/libvips/deprecated/mosaicing_dispatch.c +++ b/libvips/deprecated/mosaicing_dispatch.c @@ -123,7 +123,7 @@ lrmosaic_vec( im_object *argv ) int balancetype = *((int *) argv[10]); int mwidth = *((int *) argv[11]); - return( vips_lrmosaic( argv[0], argv[1], argv[2], + return( vips__lrmosaic( argv[0], argv[1], argv[2], bandno, xr, yr, xs, ys, halfcorrelation, halfarea, @@ -257,7 +257,7 @@ tbmosaic_vec( im_object *argv ) int balancetype = *((int *) argv[10]); int mwidth = *((int *) argv[11]); - return( vips_tbmosaic( argv[0], argv[1], argv[2], + return( vips__tbmosaic( argv[0], argv[1], argv[2], bandno, x1, y1, x2, y2, halfcorrelation, halfarea, @@ -594,7 +594,7 @@ correl_vec( im_object *argv ) int *y = (int *) argv[9]; double *correlation = (double *) argv[10]; - return( vips_correl( argv[0], argv[1], + return( vips__correl( argv[0], argv[1], xref, yref, xsec, ysec, cor, area, correlation, x, y ) ); } diff --git a/libvips/include/vips/internal.h b/libvips/include/vips/internal.h index 524097d8..84030580 100644 --- a/libvips/include/vips/internal.h +++ b/libvips/include/vips/internal.h @@ -276,30 +276,25 @@ VipsWindow *vips_window_take( VipsWindow *window, int vips__profile_set( VipsImage *image, const char *name ); -int vips_correl( VipsImage *ref, VipsImage *sec, +int vips__lrmosaic( VipsImage *ref, VipsImage *sec, VipsImage *out, + int bandno, + int xref, int yref, int xsec, int ysec, + int hwindowsize, int hsearchsize, + int balancetype, + int mwidth ); + +int vips__tbmosaic( VipsImage *ref, VipsImage *sec, VipsImage *out, + int bandno, + int xref, int yref, int xsec, int ysec, + int hwindowsize, int hsearchsize, + int balancetype, + int mwidth ); + +int vips__correl( VipsImage *ref, VipsImage *sec, int xref, int yref, int xsec, int ysec, int hwindowsize, int hsearchsize, double *correlation, int *x, int *y ); -int vips_lrmerge( VipsImage *ref, VipsImage *sec, VipsImage *out, - int dx, int dy, int mwidth ); -int vips_tbmerge( VipsImage *ref, VipsImage *sec, VipsImage *out, - int dx, int dy, int mwidth ); - -int vips_lrmosaic( VipsImage *ref, VipsImage *sec, VipsImage *out, - int bandno, - int xref, int yref, int xsec, int ysec, - int hwindowsize, int hsearchsize, - int balancetype, - int mwidth ); - -int vips_tbmosaic( VipsImage *ref, VipsImage *sec, VipsImage *out, - int bandno, - int xref, int yref, int xsec, int ysec, - int hwindowsize, int hsearchsize, - int balancetype, - int mwidth ); - #ifdef __cplusplus } #endif /*__cplusplus*/ diff --git a/libvips/mosaicing/Makefile.am b/libvips/mosaicing/Makefile.am index 9d7b4035..6e6420bf 100644 --- a/libvips/mosaicing/Makefile.am +++ b/libvips/mosaicing/Makefile.am @@ -6,20 +6,20 @@ libmosaicing_la_SOURCES = \ mosaic.c \ match.c \ mosaic1.c \ + chkpair.c \ matrixinvert.c \ global_balance.c \ lrmerge.c \ tbmerge.c \ + lrmosaic.c \ + tbmosaic.c \ + remosaic.c \ im_avgdxdy.c \ - im_chkpair.c \ im_clinear.c \ im_improve.c \ im_initialize.c \ im_lrcalcon.c \ - im_lrmosaic.c \ im_tbcalcon.c \ - im_remosaic.c \ - im_tbmosaic.c \ global_balance.h \ pmosaicing.h diff --git a/libvips/mosaicing/im_chkpair.c b/libvips/mosaicing/chkpair.c similarity index 94% rename from libvips/mosaicing/im_chkpair.c rename to libvips/mosaicing/chkpair.c index 5472f5d1..a7de1e8c 100644 --- a/libvips/mosaicing/im_chkpair.c +++ b/libvips/mosaicing/chkpair.c @@ -59,8 +59,7 @@ #include "pmosaicing.h" -/** - * vips_correl: +/* vips__correl: * @ref: reference image * @sec: secondary image * @xref: position in reference image @@ -86,19 +85,19 @@ * parts needed. Correlation is done with vips_spcor(); the position of * the maximum is found with vips_max(). * - * See also: vips_match(), vips_lrmosaic(). + * See also: vips_match(), vips__lrmosaic(). * * Returns: 0 on success, -1 on error */ int -vips_correl( VipsImage *ref, VipsImage *sec, +vips__correl( VipsImage *ref, VipsImage *sec, int xref, int yref, int xsec, int ysec, int hwindowsize, int hsearchsize, double *correlation, int *x, int *y ) { VipsImage *surface = vips_image_new(); VipsImage **t = (VipsImage **) - vips_object_local_array( VIPS_OBJECT( surface ), 4 ); + vips_object_local_array( VIPS_OBJECT( surface ), 4 ); VipsRect refr, secr; VipsRect winr, srhr; @@ -130,9 +129,11 @@ vips_correl( VipsImage *ref, VipsImage *sec, /* Extract window and search area. */ if( vips_extract_area( ref, &t[0], - wincr.left, wincr.top, wincr.width, wincr.height, NULL ) || + wincr.left, wincr.top, wincr.width, wincr.height, + NULL ) || vips_extract_area( sec, &t[1], - srhcr.left, srhcr.top, srhcr.width, srhcr.height, NULL ) ) { + srhcr.left, srhcr.top, srhcr.width, srhcr.height, + NULL ) ) { g_object_unref( surface ); return( -1 ); } @@ -205,7 +206,7 @@ vips__chkpair( VipsImage *ref, VipsImage *sec, TiePoints *points ) for( i = 0; i < points->nopoints; i++ ) { /* Find correlation point. */ - if( vips_correl( ref, sec, + if( vips__correl( ref, sec, points->x_reference[i], points->y_reference[i], points->x_reference[i], points->y_reference[i], hcor, harea, diff --git a/libvips/mosaicing/im_lrmosaic.c b/libvips/mosaicing/lrmosaic.c similarity index 99% rename from libvips/mosaicing/im_lrmosaic.c rename to libvips/mosaicing/lrmosaic.c index 975a062e..8d736c2d 100644 --- a/libvips/mosaicing/im_lrmosaic.c +++ b/libvips/mosaicing/lrmosaic.c @@ -242,7 +242,7 @@ vips__find_lroverlap( VipsImage *ref_in, VipsImage *sec_in, VipsImage *out, } int -vips_lrmosaic( VipsImage *ref, VipsImage *sec, VipsImage *out, +vips__lrmosaic( VipsImage *ref, VipsImage *sec, VipsImage *out, int bandno, int xref, int yref, int xsec, int ysec, int hwindowsize, int hsearchsize, diff --git a/libvips/mosaicing/match.c b/libvips/mosaicing/match.c index 38821ebc..c56fa07e 100644 --- a/libvips/mosaicing/match.c +++ b/libvips/mosaicing/match.c @@ -128,7 +128,7 @@ vips_match_build( VipsObject *object ) int xs, ys; double cor; - if( vips_correl( match->ref, match->sec, + if( vips__correl( match->ref, match->sec, match->xr1, match->yr1, match->xs1, match->ys1, match->hwindow, match->harea, &cor, &xs, &ys ) ) @@ -136,7 +136,7 @@ vips_match_build( VipsObject *object ) match->xs1 = xs; match->ys1 = ys; - if( vips_correl( match->ref, match->sec, + if( vips__correl( match->ref, match->sec, match->xr2, match->yr2, match->xs2, match->ys2, match->hwindow, match->harea, &cor, &xs, &ys ) ) diff --git a/libvips/mosaicing/mosaic1.c b/libvips/mosaicing/mosaic1.c index 379ed5ec..ddf9160e 100644 --- a/libvips/mosaicing/mosaic1.c +++ b/libvips/mosaicing/mosaic1.c @@ -275,11 +275,11 @@ rotjoin_search( VipsImage *ref, VipsImage *sec, VipsImage *out, joinfn jfn, * vips__transform_set_area() has set, and move the sec tie-points * accordingly. */ - if( vips_correl( t[0], t[2], xr1, yr1, + if( vips__correl( t[0], t[2], xr1, yr1, xs3 - trn.oarea.left, ys3 - trn.oarea.top, halfcorrelation, halfarea, &cor1, &xs5, &ys5 ) ) return( -1 ); - if( vips_correl( t[0], t[2], xr2, yr2, + if( vips__correl( t[0], t[2], xr2, yr2, xs4 - trn.oarea.left, ys4 - trn.oarea.top, halfcorrelation, halfarea, &cor2, &xs6, &ys6 ) ) return( -1 ); diff --git a/libvips/mosaicing/mosaicing.c b/libvips/mosaicing/mosaicing.c index 5689cb7e..6b1660b8 100644 --- a/libvips/mosaicing/mosaicing.c +++ b/libvips/mosaicing/mosaicing.c @@ -58,21 +58,17 @@ * * The mosaicing functions can be grouped into layers: * - * The lowest level functions are vips_correl() and vips_merge(). - * vips_correl() - * searches a large image for a small sub-image, returning - * the position of the best sub-image match. vips_merge() + * The lowest level operation is vips_merge() which * joins two images together * left-right or up-down with a smooth seam. * - * Next, vips_mosaic() use the - * search function plus the two low-level merge operations to join two images + * Next, vips_mosaic() uses + * search functions plus the two low-level merge operations to join two images * given just an approximate overlap as a start point. * - * The functions vips_lrmosaic1() and vips_tbmosaic1() are - * first-order - * analogues of the basic mosaic functions: they take two approximate - * tie-points and use + * vips_mosaic1() is a first-order + * analogue of the basic mosaic functions: it takes two approximate + * tie-points and uses * them to rotate and scale the right-hand or bottom image before starting to * join. * diff --git a/libvips/mosaicing/pmosaicing.h b/libvips/mosaicing/pmosaicing.h index adaf8457..2acbdeb5 100644 --- a/libvips/mosaicing/pmosaicing.h +++ b/libvips/mosaicing/pmosaicing.h @@ -122,10 +122,12 @@ void *vips__start_merge( VipsImage *out, void *, void * ); int vips__merge_gen( VipsRegion *or, void *seq, void *a, void *, gboolean *stop ); int vips__stop_merge( void *seq, void *, void * ); + int vips__lrmerge( VipsImage *ref, VipsImage *sec, VipsImage *out, int dx, int dy, int mwidth ); int vips__tbmerge( VipsImage *ref, VipsImage *sec, VipsImage *out, int dx, int dy, int mwidth ); + int vips__lrmerge1( VipsImage *ref, VipsImage *sec, VipsImage *out, double a, double b, double dx, double dy, int mwidth ); @@ -133,6 +135,10 @@ int vips__tbmerge1( VipsImage *ref, VipsImage *sec, VipsImage *out, double a, double b, double dx, double dy, int mwidth ); +int vips_correl( VipsImage *ref, VipsImage *sec, + int xref, int yref, int xsec, int ysec, + int hwindowsize, int hsearchsize, + double *correlation, int *x, int *y ); #define VIPS_MAXPOINTS (60) /* VIPS_MAXPOINTS % AREAS must be zero */ #define AREAS (3) diff --git a/libvips/mosaicing/im_remosaic.c b/libvips/mosaicing/remosaic.c similarity index 100% rename from libvips/mosaicing/im_remosaic.c rename to libvips/mosaicing/remosaic.c diff --git a/libvips/mosaicing/im_tbmosaic.c b/libvips/mosaicing/tbmosaic.c similarity index 99% rename from libvips/mosaicing/im_tbmosaic.c rename to libvips/mosaicing/tbmosaic.c index 2d3a85ee..dac7b7a8 100644 --- a/libvips/mosaicing/im_tbmosaic.c +++ b/libvips/mosaicing/tbmosaic.c @@ -213,7 +213,7 @@ vips__find_tboverlap( VipsImage *ref_in, VipsImage *sec_in, VipsImage *out, } int -vips_tbmosaic( VipsImage *ref, VipsImage *sec, VipsImage *out, +vips__tbmosaic( VipsImage *ref, VipsImage *sec, VipsImage *out, int bandno, int xref, int yref, int xsec, int ysec, int hwindowsize, int hsearchsize, diff --git a/po/POTFILES.in b/po/POTFILES.in index 2b1843eb..c3dc94dc 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -349,25 +349,25 @@ libvips/morphology/morph.c libvips/morphology/morphology.c libvips/morphology/nearest.c libvips/morphology/rank.c +libvips/mosaicing/chkpair.c libvips/mosaicing/global_balance.c libvips/mosaicing/im_avgdxdy.c -libvips/mosaicing/im_chkpair.c libvips/mosaicing/im_clinear.c libvips/mosaicing/im_improve.c libvips/mosaicing/im_initialize.c libvips/mosaicing/im_lrcalcon.c -libvips/mosaicing/im_lrmerge.c -libvips/mosaicing/im_lrmosaic.c -libvips/mosaicing/im_remosaic.c libvips/mosaicing/im_tbcalcon.c -libvips/mosaicing/im_tbmerge.c -libvips/mosaicing/im_tbmosaic.c +libvips/mosaicing/lrmerge.c +libvips/mosaicing/lrmosaic.c libvips/mosaicing/match.c libvips/mosaicing/matrixinvert.c libvips/mosaicing/merge.c libvips/mosaicing/mosaic1.c libvips/mosaicing/mosaic.c libvips/mosaicing/mosaicing.c +libvips/mosaicing/remosaic.c +libvips/mosaicing/tbmerge.c +libvips/mosaicing/tbmosaic.c libvips/resample/affine.c libvips/resample/bicubic.cpp libvips/resample/interpolate.c From 207d40f6409d471903d67e4f42430b5bb36cd336 Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Thu, 2 Jul 2020 14:15:58 +0100 Subject: [PATCH 07/10] better leak test output --- libvips/iofuncs/init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libvips/iofuncs/init.c b/libvips/iofuncs/init.c index 1ea409f6..1ee28194 100644 --- a/libvips/iofuncs/init.c +++ b/libvips/iofuncs/init.c @@ -639,7 +639,7 @@ vips_leak( void ) vips_buf_appendf( &buf, "error buffer: %s", vips_error_buffer() ); - if( vips__n_active_threads != 0 ) + if( vips__n_active_threads > 0 ) vips_buf_appendf( &buf, "threads: %d not joined\n", vips__n_active_threads ); From e4d38d1d3e0cf43b2f7b6596f0aa70ebb8410577 Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Thu, 2 Jul 2020 16:41:37 +0100 Subject: [PATCH 08/10] clip out of bounds GIF images against the canvas Some malformed GIFs have images which lie outside or partly outside the canvas. With this patch, these frames are clipped and rendered. Previously, these GIFs were rejected. See https://github.com/libvips/libvips/issues/1701 --- ChangeLog | 1 + README.md | 45 ----------- libvips/foreign/gifload.c | 152 ++++++++++++++++++++++---------------- 3 files changed, 90 insertions(+), 108 deletions(-) diff --git a/ChangeLog b/ChangeLog index c6c33b3b..1f136816 100644 --- a/ChangeLog +++ b/ChangeLog @@ -39,6 +39,7 @@ - rework the final bits of vips7 for vips8 [kleisauke] - --disable-deprecated now works [kleisauke] - vipsheader allows "stdin" as a filename +- gifload clips out of bounds images against the canvas 24/4/20 started 8.9.3 - better iiif tile naming [IllyaMoskvin] diff --git a/README.md b/README.md index 89ae80a5..2e48c31f 100644 --- a/README.md +++ b/README.md @@ -4,51 +4,6 @@ [![Fuzzing Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/libvips.svg)](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=2&q=proj:libvips) [![Coverity Status](https://scan.coverity.com/projects/6503/badge.svg)](https://scan.coverity.com/projects/jcupitt-libvips) -# This branch - -Is for experiemtning with [libspng](https://github.com/randy408/libspng). - -## Notes - -Build libspng: - -``` -cd libspng -meson build --prefix=/home/john/vips --libdir=/home/john/vips/lib \ - --buildtype=release -cd build -ninja -ninja install -``` - -Installs `spng.pc`. - -Sample code: - -https://github.com/randy408/libspng/blob/master/examples/example.c - -libspng benchmark: - -``` -$ time vips avg wtc.png -117.065766 - -real 0m2.972s -user 0m3.376s -sys 0m0.197s -``` - -And for libpng: - -``` -$ time vips avg wtc.png -117.065766 - -real 0m3.816s -user 0m4.177s -sys 0m0.221s -``` - # Introduction libvips is a [demand-driven, horizontally diff --git a/libvips/foreign/gifload.c b/libvips/foreign/gifload.c index 412b2f31..724ade75 100644 --- a/libvips/foreign/gifload.c +++ b/libvips/foreign/gifload.c @@ -39,6 +39,8 @@ * - add gifload_source * 5/2/20 alon-ne * - fix DISPOSE_BACKGROUND and DISPOSE_PREVIOUS + * 2/7/20 + * - clip out of bounds images against canvas */ /* @@ -177,7 +179,8 @@ typedef struct _VipsForeignLoadGif { */ VipsImage *frame; - /* A scratch buffer the size of frame, used for rendering. + /* A scratch buffer the size of the largest Image inside the GIF. We + * decompress lines from the GIF to this. */ VipsImage *scratch; @@ -189,8 +192,10 @@ typedef struct _VipsForeignLoadGif { */ int current_page; - /* Decompress lines of the gif file to here. + /* Decompress lines of the gif file to here. This is large enough to + * hold one line of the widest sub-image in the GIF. */ + int max_image_width; GifPixelType *line; /* The current dispose method. @@ -400,6 +405,7 @@ vips_foreign_load_gif_open_giflib( VipsForeignLoadGif *gif ) gif->eof = FALSE; gif->current_page = 0; + gif->max_image_width = 0; return( 0 ); } @@ -478,8 +484,10 @@ vips_foreign_load_gif_ext_next( VipsForeignLoadGif *gif, return( -1 ); } +#ifdef DEBUG_VERBOSE if( *extension ) - VIPS_DEBUG_MSG( "gifload: EXTENSION_NEXT\n" ); + printf( "gifload: EXTENSION_NEXT\n" ); +#endif /*DEBUG_VERBOSE*/ return( 0 ); } @@ -493,8 +501,10 @@ vips_foreign_load_gif_code_next( VipsForeignLoadGif *gif, return( -1 ); } +#ifdef DEBUG_VERBOSE if( *extension ) - VIPS_DEBUG_MSG( "gifload: CODE_NEXT\n" ); + printf( "gifload: CODE_NEXT\n" ); +#endif /*DEBUG_VERBOSE*/ return( 0 ); } @@ -510,26 +520,33 @@ vips_foreign_load_gif_scan_image( VipsForeignLoadGif *gif ) ColorMapObject *map; GifByteType *extension; - if( DGifGetImageDesc( gif->file ) == GIF_ERROR ) { + if( DGifGetImageDesc( file ) == GIF_ERROR ) { vips_foreign_load_gif_error( gif ); return( -1 ); } - /* Check that the frame looks sane. Perhaps giflib checks - * this for us. + VIPS_DEBUG_MSG( "vips_foreign_load_gif_scan_image: " + "frame of %dx%d pixels at %dx%d\n", + file->Image.Width, file->Image.Height, + file->Image.Left, file->Image.Top ); + + /* giflib does no checking of image dimensions, not even for 0. */ - if( file->Image.Left < 0 || - file->Image.Width < 1 || - file->Image.Width > 10000 || - file->Image.Left + file->Image.Width > file->SWidth || - file->Image.Top < 0 || - file->Image.Height < 1 || - file->Image.Height > 10000 || - file->Image.Top + file->Image.Height > file->SHeight ) { - vips_error( class->nickname, "%s", _( "bad frame size" ) ); + if( file->Image.Width <= 0 || + file->Image.Width > VIPS_MAX_COORD || + file->Image.Height <= 0 || + file->Image.Height > VIPS_MAX_COORD ) { + vips_error( class->nickname, + "%s", _( "image size out of bounds" ) ); return( -1 ); } + /* We need to find the max scanline size inside the GIF + * so we can allocate the decompress buffer. + */ + gif->max_image_width = VIPS_MAX( gif->max_image_width, + file->Image.Width ); + /* Test for a non-greyscale colourmap for this frame. */ map = file->Image.ColorMap ? file->Image.ColorMap : file->SColorMap; @@ -713,7 +730,7 @@ vips_foreign_load_gif_set_header( VipsForeignLoadGif *gif, VipsImage *image ) } /* Attempt to quickly scan a GIF and discover what we need for our header. We - * need to scan the whole file to get n_pages, transparency and colour. + * need to scan the whole file to get n_pages, transparency, colour etc. * * Don't flag errors during header scan. Many GIFs do not follow spec. */ @@ -769,6 +786,12 @@ vips_foreign_load_gif_scan( VipsForeignLoadGif *gif ) return( -1 ); } + if( gif->max_image_width <= 0 || + gif->max_image_width > VIPS_MAX_COORD ) { + vips_error( class->nickname, "%s", _( "bad image size" ) ); + return( -1 ); + } + return( 0 ); } @@ -801,9 +824,9 @@ vips_foreign_load_gif_header( VipsForeignLoad *load ) /* Allocate a line buffer now that we have the GIF width. */ - if( !(gif->line = - VIPS_ARRAY( NULL, gif->file->SWidth, GifPixelType )) || - vips_foreign_load_gif_scan( gif ) || + if( vips_foreign_load_gif_scan( gif ) || + !(gif->line = VIPS_ARRAY( NULL, + gif->max_image_width, GifPixelType )) || vips_foreign_load_gif_set_header( gif, load->out ) ) { (void) vips_foreign_load_gif_close_giflib( gif ); @@ -844,19 +867,46 @@ vips_foreign_load_gif_build_cmap( VipsForeignLoadGif *gif ) } } +/* Paint line y from the image left/top/width/height into scratch, clipping as + * we go. + */ static void vips_foreign_load_gif_render_line( VipsForeignLoadGif *gif, - int width, VipsPel * restrict dst, VipsPel * restrict src ) + int y, + int left, int top, int width, int height, + VipsPel *line ) { - guint32 * restrict idst = (guint32 *) dst; + VipsRect canvas; + VipsRect row; + VipsRect overlap; - int x; + /* Many GIFs have frames which lie outside the canvas. We have to + * clip. + */ + canvas.left = 0; + canvas.top = 0; + canvas.width = gif->file->SWidth; + canvas.height = gif->file->SHeight; + row.left = left; + row.top = top + y; + row.width = width; + row.height = height; + vips_rect_intersectrect( &canvas, &row, &overlap ); - for( x = 0; x < width; x++ ) { - VipsPel v = src[x]; + if( !vips_rect_isempty( &overlap ) ) { + VipsPel *dst = VIPS_IMAGE_ADDR( gif->scratch, + overlap.left, overlap.top ); + guint32 * restrict idst = (guint32 *) dst; + VipsPel * restrict src = line + overlap.left - row.left; - if( v != gif->transparent_index ) - idst[x] = gif->cmap[v]; + int x; + + for( x = 0; x < overlap.width; x++ ) { + VipsPel v = src[x]; + + if( v != gif->transparent_index ) + idst[x] = gif->cmap[v]; + } } } @@ -873,32 +923,6 @@ vips_foreign_load_gif_render( VipsForeignLoadGif *gif ) return( -1 ); } - /* giflib does not check that the Left / Top / Width / Height for this - * Image is inside the canvas. - * - * We could clip against the canvas, but for now, just ignore out of - * bounds frames. Watch for int overflow too. - */ - if( file->Image.Left < 0 || - file->Image.Left > VIPS_MAX_COORD || - file->Image.Width <= 0 || - file->Image.Width > VIPS_MAX_COORD || - file->Image.Left + file->Image.Width > file->SWidth || - file->Image.Top < 0 || - file->Image.Top > VIPS_MAX_COORD || - file->Image.Height <= 0 || - file->Image.Height > VIPS_MAX_COORD || - file->Image.Top + file->Image.Height > file->SHeight ) { - VIPS_DEBUG_MSG( "vips_foreign_load_gif_render: " - "out of bounds frame of %d x %d pixels at %d x %d\n", - file->Image.Width, file->Image.Height, - file->Image.Left, file->Image.Top ); - - /* Don't flag an error -- many GIFs have this problem. - */ - return( 0 ); - } - /* Update the colour map for this frame. */ vips_foreign_load_gif_build_cmap( gif ); @@ -925,9 +949,6 @@ vips_foreign_load_gif_render( VipsForeignLoadGif *gif ) for( y = InterlacedOffset[i]; y < file->Image.Height; y += InterlacedJumps[i] ) { - VipsPel *dst = VIPS_IMAGE_ADDR( gif->scratch, - file->Image.Left, file->Image.Top + y ); - if( DGifGetLine( gif->file, gif->line, file->Image.Width ) == GIF_ERROR ) { @@ -935,8 +956,12 @@ vips_foreign_load_gif_render( VipsForeignLoadGif *gif ) return( -1 ); } - vips_foreign_load_gif_render_line( gif, - file->Image.Width, dst, gif->line ); + vips_foreign_load_gif_render_line( gif, y, + file->Image.Left, + file->Image.Top, + file->Image.Width, + file->Image.Height, + gif->line ); } } } @@ -949,17 +974,18 @@ vips_foreign_load_gif_render( VipsForeignLoadGif *gif ) file->Image.Left, file->Image.Top ); for( y = 0; y < file->Image.Height; y++ ) { - VipsPel *dst = VIPS_IMAGE_ADDR( gif->scratch, - file->Image.Left, file->Image.Top + y ); - if( DGifGetLine( gif->file, gif->line, file->Image.Width ) == GIF_ERROR ) { vips_foreign_load_gif_error( gif ); return( -1 ); } - vips_foreign_load_gif_render_line( gif, - file->Image.Width, dst, gif->line ); + vips_foreign_load_gif_render_line( gif, y, + file->Image.Left, + file->Image.Top, + file->Image.Width, + file->Image.Height, + gif->line ); } } From 5789ac905d2c4e3f9b1ba8e491505bd0868d3810 Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Thu, 2 Jul 2020 17:41:40 +0100 Subject: [PATCH 09/10] revise DISPOSE_PREVIOUS, again Perhaps it now works :( See https://github.com/libvips/libvips/issues/1649 --- libvips/foreign/gifload.c | 83 ++++++++++++++++++++++----------------- 1 file changed, 46 insertions(+), 37 deletions(-) diff --git a/libvips/foreign/gifload.c b/libvips/foreign/gifload.c index 724ade75..3a1bfa27 100644 --- a/libvips/foreign/gifload.c +++ b/libvips/foreign/gifload.c @@ -41,6 +41,7 @@ * - fix DISPOSE_BACKGROUND and DISPOSE_PREVIOUS * 2/7/20 * - clip out of bounds images against canvas + * - fix PREVIOUS handling, again */ /* @@ -216,11 +217,6 @@ typedef struct _VipsForeignLoadGif { */ int transparent_index; - /* Params for DGifOpen(). Set by subclasses, called by base class in - * _open(). - */ - InputFunc read_func; - } VipsForeignLoadGif; typedef VipsForeignLoadClass VipsForeignLoadGifClass; @@ -927,14 +923,14 @@ vips_foreign_load_gif_render( VipsForeignLoadGif *gif ) */ vips_foreign_load_gif_build_cmap( gif ); - /* PREVIOUS means we init the frame with the last un-disposed frame. - * So the last un-disposed frame is used as a backdrop for the new - * frame. + /* If this is PREVIOUS, then after we're done, we'll need to restore + * the frame to what it was previously. Make a note of the current + * state. */ if( gif->dispose == DISPOSE_PREVIOUS ) - memcpy( VIPS_IMAGE_ADDR( gif->scratch, 0, 0 ), - VIPS_IMAGE_ADDR( gif->previous, 0, 0 ), - VIPS_IMAGE_SIZEOF_IMAGE( gif->scratch ) ); + memcpy( VIPS_IMAGE_ADDR( gif->previous, 0, 0 ), + VIPS_IMAGE_ADDR( gif->frame, 0, 0 ), + VIPS_IMAGE_SIZEOF_IMAGE( gif->previous ) ); if( file->Image.Interlace ) { int i; @@ -996,39 +992,52 @@ vips_foreign_load_gif_render( VipsForeignLoadGif *gif ) VIPS_IMAGE_SIZEOF_IMAGE( gif->frame ) ); if( gif->dispose == DISPOSE_BACKGROUND ) { - /* BACKGROUND means we reset the frame to transparent before we - * render the next set of pixels. + /* BACKGROUND means we reset the area we just painted to + * transparent. We have to clip against the canvas. */ - guint32 *q = (guint32 *) VIPS_IMAGE_ADDR( gif->scratch, - file->Image.Left, file->Image.Top ); + VipsRect canvas; + VipsRect image; + VipsRect overlap; - /* What we write for transparent pixels. We want RGB to be - * 255, and A to be 0. - */ - guint32 ink = GUINT32_TO_BE( 0xffffff00 ); + canvas.left = 0; + canvas.top = 0; + canvas.width = gif->file->SWidth; + canvas.height = gif->file->SHeight; + image.left = file->Image.Left, + image.top = file->Image.Top, + image.width = file->Image.Width, + image.height = file->Image.Height, + vips_rect_intersectrect( &canvas, &image, &overlap ); - int x, y; + if( !vips_rect_isempty( &overlap ) ) { + guint32 *q = (guint32 *) VIPS_IMAGE_ADDR( gif->scratch, + overlap.left, overlap.top ); - /* Generate the first line a pixel at a time, memcpy() for - * subsequent lines. - */ - if( file->Image.Height > 0 ) - for( x = 0; x < file->Image.Width; x++ ) - q[x] = ink; + /* What we write for transparent pixels. We want RGB + * to be 255, and A to be 0. + */ + guint32 transparent = GUINT32_TO_BE( 0xffffff00 ); - for( y = 1; y < file->Image.Height; y++ ) - memcpy( q + gif->scratch->Xsize * y, - q, - file->Image.Width * sizeof( guint32 ) ); + int x, y; + + /* Generate the first line a pixel at a time, + * memcpy() for subsequent lines. + */ + for( x = 0; x < overlap.width; x++ ) + q[x] = transparent; + + for( y = 1; y < overlap.height; y++ ) + memcpy( q + gif->scratch->Xsize * y, + q, + overlap.width * sizeof( guint32 ) ); + } } - else if( gif->dispose == DISPOSAL_UNSPECIFIED || - gif->dispose == DISPOSE_DO_NOT ) - /* Copy the frame to previous, so it can be restored if - * DISPOSE_PREVIOUS is specified in a later frame. + else if( gif->dispose == DISPOSE_PREVIOUS ) + /* If this is PREVIOUS, put everything back. */ - memcpy( VIPS_IMAGE_ADDR( gif->previous, 0, 0 ), - VIPS_IMAGE_ADDR( gif->frame, 0, 0 ), - VIPS_IMAGE_SIZEOF_IMAGE( gif->previous ) ); + memcpy( VIPS_IMAGE_ADDR( gif->scratch, 0, 0 ), + VIPS_IMAGE_ADDR( gif->previous, 0, 0 ), + VIPS_IMAGE_SIZEOF_IMAGE( gif->scratch ) ); /* Reset values, as Graphic Control Extension is optional */ From 7c2c152a740a0b1545d15919a5a9fa14c272e229 Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Fri, 3 Jul 2020 02:21:16 +0100 Subject: [PATCH 10/10] note wasm patch in changelog --- ChangeLog | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 1f136816..240d555c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -39,7 +39,8 @@ - rework the final bits of vips7 for vips8 [kleisauke] - --disable-deprecated now works [kleisauke] - vipsheader allows "stdin" as a filename -- gifload clips out of bounds images against the canvas +- gifload allows gifs with images outside the canvas +- wasm compatibility patches [kleisauke] 24/4/20 started 8.9.3 - better iiif tile naming [IllyaMoskvin]