diff --git a/ChangeLog b/ChangeLog index 4efea2b3..017f1a54 100644 --- a/ChangeLog +++ b/ChangeLog @@ -3,6 +3,7 @@ - fix a minor accidental ABI break in 8.6.0 -> 8.6.1 [remicollet] - fix read of plane-separate TIFFs with large strips [remicollet] - fix a C++ warning in composite.cpp [lovell] +- remove number of images limit in composite 10/12/17 started 8.6.1 - fix mmap window new/free cycling diff --git a/libvips/conversion/composite.cpp b/libvips/conversion/composite.cpp index 870aa95b..1c08193f 100644 --- a/libvips/conversion/composite.cpp +++ b/libvips/conversion/composite.cpp @@ -4,6 +4,8 @@ * - from bandjoin.c * 30/11/17 * - add composite2 class, to make a nice CLI interface + * 30/1/18 + * - remove number of images limit */ /* @@ -53,10 +55,6 @@ #include "pconversion.h" -/* Maximum number of input images -- why not? - */ -#define MAX_INPUT_IMAGES (64) - /* Maximum number of image bands. */ #define MAX_BANDS (64) @@ -141,6 +139,88 @@ vips_composite_base_dispose( GObject *gobject ) G_OBJECT_CLASS( vips_composite_base_parent_class )->dispose( gobject ); } +/* Our sequence value. + */ +typedef struct { + VipsCompositeBase *composite; + + /* Set of input regions. + */ + VipsRegion **ir; + + /* For each input, an input pointer. + */ + VipsPel **p; + +} VipsCompositeSequence; + +static int +vips_composite_stop( void *vseq, void *a, void *b ) +{ + VipsCompositeSequence *seq = (VipsCompositeSequence *) vseq; + + if( seq->ir ) { + int i; + + for( i = 0; seq->ir[i]; i++ ) + VIPS_UNREF( seq->ir[i] ); + VIPS_FREE( seq->ir ); + } + + VIPS_FREE( seq->p ); + + VIPS_FREE( seq ); + + return( 0 ); +} + +static void * +vips_composite_start( VipsImage *out, void *a, void *b ) +{ + VipsImage **in = (VipsImage **) a; + VipsCompositeBase *composite = (VipsCompositeBase *) b; + + VipsCompositeSequence *seq; + int i, n; + + if( !(seq = VIPS_NEW( NULL, VipsCompositeSequence )) ) + return( NULL ); + + seq->composite = composite; + seq->ir = NULL; + seq->p = NULL; + + /* How many images? + */ + for( n = 0; in[n]; n++ ) + ; + + /* Alocate space for region array. + */ + if( !(seq->ir = VIPS_ARRAY( NULL, n + 1, VipsRegion * )) ) { + vips_composite_stop( seq, NULL, NULL ); + return( NULL ); + } + + /* Create a set of regions. + */ + for( i = 0; i < n; i++ ) + if( !(seq->ir[i] = vips_region_new( in[i] )) ) { + vips_composite_stop( seq, NULL, NULL ); + return( NULL ); + } + seq->ir[n] = NULL; + + /* Input pointers. + */ + if( !(seq->p = VIPS_ARRAY( NULL, n + 1, VipsPel * )) ) { + vips_composite_stop( seq, NULL, NULL ); + return( NULL ); + } + + return( seq ); +} + /* For each of the supported interpretations, the maximum value of each band. */ static int @@ -815,47 +895,46 @@ vips_combine_pixels3( VipsCompositeBase *composite, VipsPel *q, VipsPel **p ) static int vips_composite_base_gen( VipsRegion *output_region, - void *seq, void *a, void *b, gboolean *stop ) + void *vseq, void *a, void *b, gboolean *stop ) { - VipsRegion **input_regions = (VipsRegion **) seq; + VipsCompositeSequence *seq = (VipsCompositeSequence *) vseq; VipsCompositeBase *composite = (VipsCompositeBase *) b; VipsRect *r = &output_region->valid; int ps = VIPS_IMAGE_SIZEOF_PEL( output_region->im ); - if( vips_reorder_prepare_many( output_region->im, input_regions, r ) ) + if( vips_reorder_prepare_many( output_region->im, seq->ir, r ) ) return( -1 ); VIPS_GATE_START( "vips_composite_base_gen: work" ); for( int y = 0; y < r->height; y++ ) { - VipsPel *p[MAX_INPUT_IMAGES]; VipsPel *q; for( int i = 0; i < composite->n; i++ ) - p[i] = VIPS_REGION_ADDR( input_regions[i], + seq->p[i] = VIPS_REGION_ADDR( seq->ir[i], r->left, r->top + y ); - p[composite->n] = NULL; + seq->p[composite->n] = NULL; q = VIPS_REGION_ADDR( output_region, r->left, r->top + y ); for( int x = 0; x < r->width; x++ ) { - switch( input_regions[0]->im->BandFmt ) { + switch( seq->ir[0]->im->BandFmt ) { case VIPS_FORMAT_UCHAR: #ifdef HAVE_VECTOR_ARITH if( composite->bands == 3 ) vips_combine_pixels3 - ( composite, q, p ); + ( composite, q, seq->p ); else #endif vips_combine_pixels - ( composite, q, p ); + ( composite, q, seq->p ); break; case VIPS_FORMAT_CHAR: vips_combine_pixels - ( composite, q, p ); + ( composite, q, seq->p ); break; case VIPS_FORMAT_USHORT: @@ -863,30 +942,30 @@ vips_composite_base_gen( VipsRegion *output_region, if( composite->bands == 3 ) vips_combine_pixels3 - ( composite, q, p ); + ( composite, q, seq->p ); else #endif vips_combine_pixels - ( composite, q, p ); + ( composite, q, seq->p ); break; case VIPS_FORMAT_SHORT: vips_combine_pixels - ( composite, q, p ); + ( composite, q, seq->p ); break; case VIPS_FORMAT_UINT: vips_combine_pixels - ( composite, q, p ); + ( composite, q, seq->p ); break; case VIPS_FORMAT_INT: vips_combine_pixels - ( composite, q, p ); + ( composite, q, seq->p ); break; case VIPS_FORMAT_FLOAT: @@ -894,18 +973,18 @@ vips_composite_base_gen( VipsRegion *output_region, if( composite->bands == 3 ) vips_combine_pixels3 - ( composite, q, p ); + ( composite, q, seq->p ); else #endif vips_combine_pixels - ( composite, q, p ); + ( composite, q, seq->p ); break; case VIPS_FORMAT_DOUBLE: vips_combine_pixels - ( composite, q, p ); + ( composite, q, seq->p ); break; default: @@ -914,7 +993,7 @@ vips_composite_base_gen( VipsRegion *output_region, } for( int i = 0; i < composite->n; i++ ) - p[i] += ps; + seq->p[i] += ps; q += ps; } } @@ -991,12 +1070,6 @@ vips_composite_base_build( VipsObject *object ) break; } - if( composite->n > MAX_INPUT_IMAGES ) { - vips_error( klass->nickname, - "%s", _( "too many input images" ) ); - return( -1 ); - } - /* Transform to compositing space. It defaults to sRGB or B_W, usually * 8 bit, but 16 bit if any inputs are 16 bit. */ @@ -1086,7 +1159,9 @@ vips_composite_base_build( VipsObject *object ) return( -1 ); if( vips_image_generate( conversion->out, - vips_start_many, vips_composite_base_gen, vips_stop_many, + vips_composite_start, + vips_composite_base_gen, + vips_composite_stop, in, composite ) ) return( -1 );