diff --git a/ChangeLog b/ChangeLog index a8dd2881..427767f0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -3,7 +3,7 @@ - im_subtract(), im_avg(), im_min(), im_minpos(), im_copy(), im_embed(), im_flophor(), im_flipver(), im_insert(), im_insert_noexpand(), im_lrjoin(), im_tbjoin(), im_extract_area(), im_extract_bands(), im_extract_areabands(), - im_replicate(), im_clip2fmt() + im_replicate(), im_clip2fmt(), im_gbandjoin(), im_bandjoin() redone as classes - added argument priorites to help control arg ordering - generate has a 'stop' param to signal successful early termination diff --git a/TODO b/TODO index 58fb9e63..db94f98d 100644 --- a/TODO +++ b/TODO @@ -1,11 +1,3 @@ -- started factoring VipsArea out into area.[hc] - - - -- bandjoin needs testing - - see vips_bandjoin() .. ugly! - - does transform_array_g_string() work? it seems to use diff --git a/libvips/conversion/Makefile.am b/libvips/conversion/Makefile.am index 6120f0cc..0af85fe6 100644 --- a/libvips/conversion/Makefile.am +++ b/libvips/conversion/Makefile.am @@ -20,7 +20,6 @@ libconversion_la_SOURCES = \ im_c2real.c \ im_copy_file.c \ im_falsecolour.c \ - im_gbandjoin.c \ im_mask2vips.c \ im_msb.c \ im_grid.c \ diff --git a/libvips/conversion/bandjoin.c b/libvips/conversion/bandjoin.c index f25f6b06..de6e565a 100644 --- a/libvips/conversion/bandjoin.c +++ b/libvips/conversion/bandjoin.c @@ -257,9 +257,9 @@ vips_bandjoin_build( VipsObject *object ) { VipsConversion *conversion = VIPS_CONVERSION( object ); VipsBandjoin *bandjoin = (VipsBandjoin *) object; - int n = bandjoin->in->n; VipsImage **in; + int n; int i; VipsImage **format; VipsImage **size; @@ -268,6 +268,7 @@ vips_bandjoin_build( VipsObject *object ) return( -1 ); in = bandjoin->in->data; + n = bandjoin->in->n; if( n == 1 ) return( vips_image_write( in[0], conversion->out ) ); @@ -286,9 +287,19 @@ vips_bandjoin_build( VipsObject *object ) return( -1 ); in = size; + bandjoin->is = VIPS_ARRAY( object, n, int ); for( i = 0; i < n; i++ ) bandjoin->is[i] = VIPS_IMAGE_SIZEOF_PEL( in[i] ); + if( vips_image_copy_fields_array( conversion->out, in ) ) + return( -1 ); + vips_demand_hint_array( conversion->out, + VIPS_DEMAND_STYLE_THINSTRIP, in ); + + conversion->out->Bands = 0; + for( i = 0; i < n; i++ ) + conversion->out->Bands += in[i]->Bands; + if( vips_image_generate( conversion->out, vips_start_many, vips_bandjoin_gen, vips_stop_many, in, bandjoin ) ) @@ -352,3 +363,27 @@ vips_bandjoin( VipsImage **in, VipsImage **out, int n, ... ) return( result ); } + +int +vips_bandjoin2( VipsImage *in1, VipsImage *in2, VipsImage **out, ... ) +{ + va_list ap; + VipsArea *area; + VipsImage **array; + int result; + + area = vips_area_new_array_object( 2 ); + array = (VipsImage **) area->data; + array[0] = in1; + array[1] = in2; + g_object_ref( array[0] ); + g_object_ref( array[1] ); + + va_start( ap, out ); + result = vips_call_split( "bandjoin", ap, area, out ); + va_end( ap ); + + vips_area_unref( area ); + + return( result ); +} diff --git a/libvips/conversion/embed.c b/libvips/conversion/embed.c index a60c85f5..e2bc08f1 100644 --- a/libvips/conversion/embed.c +++ b/libvips/conversion/embed.c @@ -451,13 +451,12 @@ vips_embed_build( VipsObject *object ) case VIPS_EXTEND_COPY: if( vips_image_copy_fields( conversion->out, embed->in ) ) return( -1 ); + vips_demand_hint( conversion->out, + VIPS_DEMAND_STYLE_SMALLTILE, embed->in, NULL ); conversion->out->Xsize = embed->width; conversion->out->Ysize = embed->height; - vips_demand_hint( conversion->out, - VIPS_DEMAND_STYLE_SMALLTILE, embed->in, NULL ); - /* Whole output area. */ embed->rout.left = 0; diff --git a/libvips/conversion/im_gbandjoin.c b/libvips/conversion/im_gbandjoin.c deleted file mode 100644 index 5badfa56..00000000 --- a/libvips/conversion/im_gbandjoin.c +++ /dev/null @@ -1,261 +0,0 @@ -/* im_gbandjoin -- bandwise join of a set of images - * - * Copyright: 1991, N. Dessipris, modification of im_bandjoin() - * - * Author: N. Dessipris - * Written on: 17/04/1991 - * Modified on : - * 16/3/94 JC - * - rewritten for partials - * - now in ANSI C - * - now works for any number of input images, except zero - * 7/10/94 JC - * - new IM_NEW() - * 16/4/07 - * - fall back to im_copy() for 1 input image - * 17/1/09 - * - cleanups - * - gtk-doc - * - im_bandjoin() just calls this - * - works for RAD coding too - * 27/1/10 - * - formatalike inputs - * 17/5/11 - * - sizealike inputs - */ - -/* - - This file is part of VIPS. - - VIPS is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - */ - -/* - - These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk - - */ - -#ifdef HAVE_CONFIG_H -#include -#endif /*HAVE_CONFIG_H*/ -#include - -#include -#include - -#include -#include - -/* Struct we carry stuff around in. - */ -typedef struct joins { - int n; /* Number of input images */ - IMAGE **t; /* Array of temp images */ - IMAGE **in; /* Array of input images, NULL-terminated */ - int *is; /* An int for SIZEOF_PEL() for each image */ -} Join; - -/* Make a Join struct. - */ -static Join * -join_new( IMAGE *out, IMAGE **in, int n ) -{ - Join *join; - int i; - - if( !(join = IM_NEW( out, Join )) ) - return( NULL ); - join->n = n; - if( !(join->t = IM_ARRAY( out, n, IMAGE * )) || - !(join->in = IM_ARRAY( out, n + 1, IMAGE * )) || - !(join->is = IM_ARRAY( out, n, int )) ) - return( NULL ); - - /* Cast inputs up to a common format. - */ - if( im_open_local_array( out, join->t, n, "im_gbandjoin", "p" ) || - im_open_local_array( out, join->in, n, "im_gbandjoin", "p" ) || - im__formatalike_vec( in, join->t, n ) || - im__sizealike_vec( join->t, join->in, n ) ) - return( NULL ); - - for( i = 0; i < n; i++ ) - join->is[i] = IM_IMAGE_SIZEOF_PEL( join->in[i] ); - - /* Remember to NULL-terminate. We pass ->in[] to - * im_demand_hint_array() and friends later. - */ - join->in[n] = NULL; - - return( join ); -} - -/* Perform join. - */ -static int -join_bands( REGION *or, void *seq, void *a, void *b ) -{ - REGION **ir = (REGION **) seq; - Join *join = (Join *) b; - Rect *r = &or->valid; - const int ps = IM_IMAGE_SIZEOF_PEL( or->im ); - - int x, y, z, i; - - for( i = 0; i < join->n; i++ ) - if( im_prepare( ir[i], r ) ) - return( -1 ); - - /* Loop over output! - */ - for( y = 0; y < r->height; y++ ) { - PEL *qb; - - qb = (PEL *) IM_REGION_ADDR( or, r->left, r->top + y ); - - /* Loop for each input image. Scattered write is faster than - * scattered read. - */ - for( i = 0; i < join->n; i++ ) { - int k = join->is[i]; - - PEL *p; - PEL *q; - - p = (PEL *) IM_REGION_ADDR( ir[i], - r->left, r->top + y ); - q = qb; - - for( x = 0; x < r->width; x++ ) { - for( z = 0; z < k; z++ ) - q[z] = p[z]; - - p += z; - q += ps; - } - - qb += k; - } - } - - return( 0 ); -} - -/** - * im_gbandjoin: - * @in: vector of input images - * @out: output image - * @n: number of input images - * - * Join a set of images together, bandwise. - * If the images - * have n and m bands, then the output image will have n + m - * bands, with the first n coming from the first image and the last m - * from the second. - * - * If the images differ in size, the smaller images are enlarged to match the - * larger by adding zero pixels along the bottom and right. - * - * The input images are cast up to the smallest common type (see table - * Smallest common format in - * arithmetic). - * - * See also: im_bandjoin(), im_insert(). - * - * Returns: 0 on success, -1 on error - */ -int -im_gbandjoin( IMAGE **in, IMAGE *out, int n ) -{ - int i; - Join *join; - - /* Check it out! - */ - if( n < 1 ) { - im_error( "im_gbandjoin", "%s", _( "zero input images!" ) ); - return( -1 ); - } - else if( n == 1 ) - return( im_copy( in[0], out ) ); - - /* Check our args. - */ - if( im_poutcheck( out ) || - im_check_coding_known( "im_gbandjoin", in[0] ) ) - return( -1 ); - for( i = 0; i < n; i++ ) - if( im_pincheck( in[i] ) || - im_check_coding_same( "im_gbandjoin", in[i], in[0] ) ) - return( -1 ); - - /* Build a data area. - */ - if( !(join = join_new( out, in, n )) ) - return( -1 ); - - /* Prepare the output header. - */ - if( im_cp_desc_array( out, join->in ) ) - return( -1 ); - out->Bands = 0; - for( i = 0; i < n; i++ ) - out->Bands += join->in[i]->Bands; - if( im_demand_hint_array( out, IM_THINSTRIP, join->in ) ) - return( -1 ); - - if( im_generate( out, - im_start_many, join_bands, im_stop_many, join->in, join ) ) - return( -1 ); - - return( 0 ); -} - -/** - * im_bandjoin: - * @in1: first input image - * @in2: second input image - * @out: output image - * - * Join two images bandwise. - * If the two images - * have n and m bands respectively, then the output image will have n + m - * bands, with the first n coming from the first image and the last m - * from the second. - * - * If the images differ in size, the smaller image is enlarged to match the - * larger by adding zero pixels along the bottom and right. - * - * The two input images are cast up to the smallest common type (see table - * Smallest common format in - * arithmetic). - * - * See also: im_gbandjoin(), im_insert(). - * - * Returns: 0 on success, -1 on error - */ -int -im_bandjoin( IMAGE *in1, IMAGE *in2, IMAGE *out ) -{ - IMAGE *t[2]; - - t[0] = in1; - t[1] = in2; - - return( im_gbandjoin( t, out, 2 ) ); -} diff --git a/libvips/deprecated/vips7compat.c b/libvips/deprecated/vips7compat.c index dabc6bbb..1314681a 100644 --- a/libvips/deprecated/vips7compat.c +++ b/libvips/deprecated/vips7compat.c @@ -1292,3 +1292,38 @@ im_ref_string_get_length( const GValue *value ) return( length ); } + +int +im_bandjoin( VipsImage *in1, VipsImage *in2, VipsImage *out ) +{ + VipsImage *t; + + if( vips_bandjoin2( in1, in2, &t, + NULL ) ) + return( -1 ); + if( vips_image_write( t, out ) ) { + g_object_unref( t ); + return( -1 ); + } + g_object_unref( t ); + + return( 0 ); +} + +int +im_gbandjoin( VipsImage **in, VipsImage *out, int n ) +{ + VipsImage *t; + + if( vips_bandjoin( in, &t, n, + NULL ) ) + return( -1 ); + if( vips_image_write( t, out ) ) { + g_object_unref( t ); + return( -1 ); + } + g_object_unref( t ); + + return( 0 ); +} + diff --git a/libvips/include/vips/conversion.h b/libvips/include/vips/conversion.h index 95eccf27..27ab66c6 100644 --- a/libvips/include/vips/conversion.h +++ b/libvips/include/vips/conversion.h @@ -136,6 +136,10 @@ int vips_replicate( VipsImage *in, VipsImage **out, int across, int down, ... ) __attribute__((sentinel)); int vips_cast( VipsImage *in, VipsImage **out, VipsBandFormat format, ... ) __attribute__((sentinel)); +int vips_bandjoin( VipsImage **in, VipsImage **out, int n, ... ) + __attribute__((sentinel)); +int vips_bandjoin2( VipsImage *in1, VipsImage *in2, VipsImage **out, ... ) + __attribute__((sentinel)); @@ -163,8 +167,6 @@ int im_black( VipsImage *out, int x, int y, int bands ); int im_text( VipsImage *out, const char *text, const char *font, int width, int alignment, int dpi ); -int im_bandjoin( VipsImage *in1, VipsImage *in2, VipsImage *out ); -int im_gbandjoin( VipsImage **in, VipsImage *out, int n ); int im_insertset( VipsImage *main, VipsImage *sub, VipsImage *out, int n, int *x, int *y ); int im_grid( VipsImage *in, VipsImage *out, int tile_height, int across, int down ); int im_wrap( VipsImage *in, VipsImage *out, int x, int y ); diff --git a/libvips/include/vips/vips7compat.h b/libvips/include/vips/vips7compat.h index 0fd2c70e..cfc5a8eb 100644 --- a/libvips/include/vips/vips7compat.h +++ b/libvips/include/vips/vips7compat.h @@ -560,6 +560,9 @@ int im_replicate( VipsImage *in, VipsImage *out, int across, int down ); int im_clip2fmt( VipsImage *in, VipsImage *out, VipsBandFormat fmt ); +int im_bandjoin( VipsImage *in1, VipsImage *in2, VipsImage *out ); +int im_gbandjoin( VipsImage **in, VipsImage *out, int n ); + /* ruby-vips uses this */ diff --git a/libvips/iofuncs/object.c b/libvips/iofuncs/object.c index 880d9f79..750991f7 100644 --- a/libvips/iofuncs/object.c +++ b/libvips/iofuncs/object.c @@ -1814,6 +1814,7 @@ vips_object_print_all_cb( VipsObject *object, int *n ) printf( "%d) ", *n ); vips_object_print_name( object ); printf( "\n" ); + vips_object_print( object ); *n += 1; diff --git a/libvips/iofuncs/type.c b/libvips/iofuncs/type.c index 6a763feb..8e232c9e 100644 --- a/libvips/iofuncs/type.c +++ b/libvips/iofuncs/type.c @@ -97,7 +97,7 @@ vips_area_unref( VipsArea *area ) if( area->count == 0 ) { if( area->free_fn && area->data ) { - area->free_fn( area->data, NULL ); + area->free_fn( area->data, area ); area->data = NULL; area->free_fn = NULL; } @@ -171,16 +171,14 @@ vips_area_new_array( GType type, size_t sizeof_type, int n ) } static void -vips_area_free_array_object( VipsArea *area ) +vips_area_free_array_object( GObject **array, VipsArea *area ) { - GObject **array = (GObject **) area->data; - int i; - for( i = 0; i < area->n; i++ ) + for( i = 0; i < area->n; i++ ) VIPS_FREEF( g_object_unref, array[i] ); - g_free( area ); + area->n = 0; } /* An area which holds an array of GObjects. @@ -251,7 +249,7 @@ vips_area_get_type( void ) static GType type = 0; if( !type ) { - type = g_boxed_type_register_static( "vips_area", + type = g_boxed_type_register_static( "VipsArea", (GBoxedCopyFunc) vips_area_copy, (GBoxedFreeFunc) vips_area_unref ); g_value_register_transform_func( type, G_TYPE_STRING, @@ -359,7 +357,7 @@ vips_save_string_get_type( void ) static GType type = 0; if( !type ) { - type = g_boxed_type_register_static( "vips_save_string", + type = g_boxed_type_register_static( "VipsSaveString", (GBoxedCopyFunc) g_strdup, (GBoxedFreeFunc) g_free ); } @@ -454,7 +452,7 @@ vips_ref_string_get_type( void ) static GType type = 0; if( !type ) { - type = g_boxed_type_register_static( "vips_ref_string", + type = g_boxed_type_register_static( "VipsRefString", (GBoxedCopyFunc) vips_area_copy, (GBoxedFreeFunc) vips_area_unref ); g_value_register_transform_func( type, G_TYPE_STRING, @@ -575,7 +573,7 @@ vips_blob_get_type( void ) static GType type = 0; if( !type ) { - type = g_boxed_type_register_static( "vips_blob", + type = g_boxed_type_register_static( "VipsBlob", (GBoxedCopyFunc) vips_area_copy, (GBoxedFreeFunc) vips_area_unref ); g_value_register_transform_func( type, G_TYPE_STRING, @@ -710,32 +708,33 @@ transform_array_g_string( const GValue *src_value, GValue *dest_value ) static void transform_g_string_array_double( const GValue *src_value, GValue *dest_value ) { - const char *str = g_value_get_string( src_value ); - + char *str; int n; - const char *p; + char *p, *q; int i; double *array; - /* Walk the string to get the number of elements. Empty string is zero - * elements. + /* Walk the string to get the number of elements. + * We need a copy of the string, since we insert \0 during + * scan. + * + * We can't allow ',' as a separator, since some locales use it as a + * decimal point. */ - for( n = 0, p = str; p && *p; n += 1 ) { - p = strchr( p, ',' ); - if( p ) - p += 1; - } + str = g_value_dup_string( src_value ); + n = 0; + for( p = str; (q = vips_break_token( p, "\t; " )); p = q ) + n += 1; + g_free( str ); vips_value_set_array( dest_value, G_TYPE_DOUBLE, sizeof( double ), n ); array = (double *) vips_value_get_array( dest_value, NULL, NULL, NULL ); - p = str; - for( i = 0; i < n; i++ ) { - array[i] = atof( p ); - p = strchr( p, ',' ); - if( p ) - p += 1; - } + str = g_value_dup_string( src_value ); + i = 0; + for( p = str; (q = vips_break_token( p, "\t; " )); p = q ) + array[i++] = atof( p ); + g_free( str ); } GType @@ -744,7 +743,7 @@ vips_array_double_get_type( void ) static GType type = 0; if( !type ) { - type = g_boxed_type_register_static( "vips_array_double", + type = g_boxed_type_register_static( "VipsArrayDouble", (GBoxedCopyFunc) vips_area_copy, (GBoxedFreeFunc) vips_area_unref ); g_value_register_transform_func( type, G_TYPE_STRING, @@ -810,16 +809,17 @@ transform_g_string_array_image( const GValue *src_value, GValue *dest_value ) /* We need a copy of the string, since we insert \0 during * scan. */ - str = g_strdup_value_contents( src_value ); - for( n = 0; (q = vips_break_token( p, " " )); n++, p = q ) - ; + str = g_value_dup_string( src_value ); + n = 0; + for( p = str; (q = vips_break_token( p, " " )); p = q ) + n += 1; g_free( str ); vips_value_set_array_object( dest_value, n ); array = vips_value_get_array_object( dest_value, NULL ); - str = g_strdup_value_contents( src_value ); - for( i = 0; (q = vips_break_token( p, " " )); i++, p = q ) + str = g_value_dup_string( src_value ); + for( i = 0, p = str; (q = vips_break_token( p, " " )); i++, p = q ) /* Sadly there's no error return possible here. */ array[i] = G_OBJECT( vips_image_new_from_file( p ) ); @@ -832,7 +832,7 @@ vips_array_image_get_type( void ) static GType type = 0; if( !type ) { - type = g_boxed_type_register_static( "vips_array_image", + type = g_boxed_type_register_static( "VipsArrayImage", (GBoxedCopyFunc) vips_area_copy, (GBoxedFreeFunc) vips_area_unref ); g_value_register_transform_func( G_TYPE_STRING, type,