remove stop-at-solid feature

We used to stop compositing when we reached the first solid image, but
that only works for modes like OVER.

Instead, composite all images, regardless of transparency.

See https://github.com/libvips/libvips/issues/928
This commit is contained in:
John Cupitt 2018-11-27 14:51:56 +00:00
parent 24abbb83ab
commit e6f271df10

View File

@ -9,6 +9,8 @@
* - allow one mode ... reused for all joins * - allow one mode ... reused for all joins
* 11/8/18 [medakk] * 11/8/18 [medakk]
* - x/y params let you position images * - x/y params let you position images
* 27/11/18
* - don't stop on first non-transparent image [felixbuenemann]
*/ */
/* /*
@ -105,11 +107,6 @@ typedef struct _VipsCompositeBase {
int *x_offset; int *x_offset;
int *y_offset; int *y_offset;
/* The number of inputs. This can be less than the number of images in
* @in.
*/
int n;
/* The number of non-alpha bands we are blending. /* The number of non-alpha bands we are blending.
*/ */
int bands; int bands;
@ -312,7 +309,7 @@ vips_composite_base_max_band( VipsCompositeBase *composite, double *max_band )
break; break;
case VIPS_INTERPRETATION_B_W: case VIPS_INTERPRETATION_B_W:
max_band[0] = 256; max_band[0] = 255;
break; break;
default: default:
@ -793,7 +790,7 @@ vips_combine_pixels( VipsCompositeBase *composite, VipsPel *q, VipsPel **p )
{ {
VipsBlendMode *mode = (VipsBlendMode *) composite->mode->area.data; VipsBlendMode *mode = (VipsBlendMode *) composite->mode->area.data;
int n_mode = composite->mode->area.n; int n_mode = composite->mode->area.n;
int n = composite->n; int n = composite->in->area.n;
int bands = composite->bands; int bands = composite->bands;
T * restrict tq = (T * restrict) q; T * restrict tq = (T * restrict) q;
T ** restrict tp = (T ** restrict) p; T ** restrict tp = (T ** restrict) p;
@ -856,7 +853,7 @@ vips_combine_pixels3( VipsCompositeBase *composite, VipsPel *q, VipsPel **p )
{ {
VipsBlendMode *mode = (VipsBlendMode *) composite->mode->area.data; VipsBlendMode *mode = (VipsBlendMode *) composite->mode->area.data;
int n_mode = composite->mode->area.n; int n_mode = composite->mode->area.n;
int n = composite->n; int n = composite->in->area.n;
T * restrict tq = (T * restrict) q; T * restrict tq = (T * restrict) q;
T ** restrict tp = (T ** restrict) p; T ** restrict tp = (T ** restrict) p;
@ -924,6 +921,7 @@ vips_composite_base_gen( VipsRegion *output_region,
VipsCompositeBase *composite = (VipsCompositeBase *) b; VipsCompositeBase *composite = (VipsCompositeBase *) b;
VipsRect *r = &output_region->valid; VipsRect *r = &output_region->valid;
int ps = VIPS_IMAGE_SIZEOF_PEL( output_region->im ); int ps = VIPS_IMAGE_SIZEOF_PEL( output_region->im );
int n = composite->in->area.n;
if( vips_reorder_prepare_many( output_region->im, seq->ir, r ) ) if( vips_reorder_prepare_many( output_region->im, seq->ir, r ) )
return( -1 ); return( -1 );
@ -933,10 +931,10 @@ vips_composite_base_gen( VipsRegion *output_region,
for( int y = 0; y < r->height; y++ ) { for( int y = 0; y < r->height; y++ ) {
VipsPel *q; VipsPel *q;
for( int i = 0; i < composite->n; i++ ) for( int i = 0; i < n; i++ )
seq->p[i] = VIPS_REGION_ADDR( seq->ir[i], seq->p[i] = VIPS_REGION_ADDR( seq->ir[i],
r->left, r->top + y ); r->left, r->top + y );
seq->p[composite->n] = NULL; seq->p[n] = NULL;
q = VIPS_REGION_ADDR( output_region, r->left, r->top + y ); q = VIPS_REGION_ADDR( output_region, r->left, r->top + y );
for( int x = 0; x < r->width; x++ ) { for( int x = 0; x < r->width; x++ ) {
@ -1015,7 +1013,7 @@ vips_composite_base_gen( VipsRegion *output_region,
return( -1 ); return( -1 );
} }
for( int i = 0; i < composite->n; i++ ) for( int i = 0; i < n; i++ )
seq->p[i] += ps; seq->p[i] += ps;
q += ps; q += ps;
} }
@ -1033,27 +1031,28 @@ vips_composite_base_build( VipsObject *object )
VipsConversion *conversion = VIPS_CONVERSION( object ); VipsConversion *conversion = VIPS_CONVERSION( object );
VipsCompositeBase *composite = (VipsCompositeBase *) object; VipsCompositeBase *composite = (VipsCompositeBase *) object;
int n;
VipsBlendMode *mode;
VipsImage **in; VipsImage **in;
VipsImage **decode; VipsImage **decode;
VipsImage **compositing; VipsImage **compositing;
VipsImage **format; VipsImage **format;
VipsImage **size; VipsImage **size;
VipsBlendMode *mode;
if( VIPS_OBJECT_CLASS( vips_composite_base_parent_class )-> if( VIPS_OBJECT_CLASS( vips_composite_base_parent_class )->
build( object ) ) build( object ) )
return( -1 ); return( -1 );
composite->n = composite->in->area.n; n = composite->in->area.n;
if( composite->n <= 0 ) { if( n <= 0 ) {
vips_error( klass->nickname, "%s", _( "no input images" ) ); vips_error( klass->nickname, "%s", _( "no input images" ) );
return( -1 ); return( -1 );
} }
if( composite->mode->area.n != composite->n - 1 && if( composite->mode->area.n != n - 1 &&
composite->mode->area.n != 1 ) { composite->mode->area.n != 1 ) {
vips_error( klass->nickname, _( "must be 1 or %d blend modes" ), vips_error( klass->nickname, _( "must be 1 or %d blend modes" ),
composite->n - 1 ); n - 1 );
return( -1 ); return( -1 );
} }
mode = (VipsBlendMode *) composite->mode->area.data; mode = (VipsBlendMode *) composite->mode->area.data;
@ -1069,16 +1068,15 @@ vips_composite_base_build( VipsObject *object )
in = (VipsImage **) composite->in->area.data; in = (VipsImage **) composite->in->area.data;
decode = (VipsImage **) vips_object_local_array( object, composite->n ); decode = (VipsImage **) vips_object_local_array( object, n );
for( int i = 0; i < composite->n; i++ ) for( int i = 0; i < n; i++ )
if( vips_image_decode( in[i], &decode[i] ) ) if( vips_image_decode( in[i], &decode[i] ) )
return( -1 ); return( -1 );
in = decode; in = decode;
/* Are any of the images missing an alpha? The first missing alpha is /* Add a solid alpha to any images missing one.
* given a solid 255 and becomes the background image, shortening n.
*/ */
for( int i = composite->n - 1; i >= 0; i-- ) for( int i = n - 1; i >= 0; i-- )
if( !vips_image_hasalpha( in[i] ) ) { if( !vips_image_hasalpha( in[i] ) ) {
VipsImage *x; VipsImage *x;
@ -1086,11 +1084,6 @@ vips_composite_base_build( VipsObject *object )
return( -1 ); return( -1 );
g_object_unref( in[i] ); g_object_unref( in[i] );
in[i] = x; in[i] = x;
composite->n -= i;
in += i;
break;
} }
/* Transform to compositing space. It defaults to sRGB or B_W, usually /* Transform to compositing space. It defaults to sRGB or B_W, usually
@ -1101,14 +1094,14 @@ vips_composite_base_build( VipsObject *object )
gboolean any_16; gboolean any_16;
all_grey = TRUE; all_grey = TRUE;
for( int i = 0; i < composite->n; i++ ) for( int i = 0; i < n; i++ )
if( in[i]->Bands > 2 ) { if( in[i]->Bands > 2 ) {
all_grey = FALSE; all_grey = FALSE;
break; break;
} }
any_16 = FALSE; any_16 = FALSE;
for( int i = 0; i < composite->n; i++ ) for( int i = 0; i < n; i++ )
if( in[i]->Type == VIPS_INTERPRETATION_GREY16 || if( in[i]->Type == VIPS_INTERPRETATION_GREY16 ||
in[i]->Type == VIPS_INTERPRETATION_RGB16 ) { in[i]->Type == VIPS_INTERPRETATION_RGB16 ) {
any_16 = TRUE; any_16 = TRUE;
@ -1125,8 +1118,8 @@ vips_composite_base_build( VipsObject *object )
} }
compositing = (VipsImage **) compositing = (VipsImage **)
vips_object_local_array( object, composite->n ); vips_object_local_array( object, n );
for( int i = 0; i < composite->n; i++ ) for( int i = 0; i < n; i++ )
if( vips_colourspace( in[i], &compositing[i], if( vips_colourspace( in[i], &compositing[i],
composite->compositing_space, (void *) NULL ) ) composite->compositing_space, (void *) NULL ) )
return( -1 ); return( -1 );
@ -1135,7 +1128,7 @@ vips_composite_base_build( VipsObject *object )
/* Check that they all now match in bands. This can fail for some /* Check that they all now match in bands. This can fail for some
* input combinations. * input combinations.
*/ */
for( int i = 1; i < composite->n; i++ ) for( int i = 1; i < n; i++ )
if( in[i]->Bands != in[0]->Bands ) { if( in[i]->Bands != in[0]->Bands ) {
vips_error( klass->nickname, vips_error( klass->nickname,
"%s", _( "images do not have same " "%s", _( "images do not have same "
@ -1170,8 +1163,8 @@ vips_composite_base_build( VipsObject *object )
/* Transform the input images to match format. We may have /* Transform the input images to match format. We may have
* mixed float and double, for example. * mixed float and double, for example.
*/ */
format = (VipsImage **) vips_object_local_array( object, composite->n ); format = (VipsImage **) vips_object_local_array( object, n );
if( vips__formatalike_vec( in, format, composite->n ) ) if( vips__formatalike_vec( in, format, n ) )
return( -1 ); return( -1 );
in = format; in = format;
@ -1182,14 +1175,14 @@ vips_composite_base_build( VipsObject *object )
int width = vips_image_get_width( in[0] ); int width = vips_image_get_width( in[0] );
int height = vips_image_get_height( in[0] ); int height = vips_image_get_height( in[0] );
VipsImage **position = (VipsImage **) VipsImage **position = (VipsImage **)
vips_object_local_array( object, composite->n ); vips_object_local_array( object, n );
/* The zero image does not move. /* The zero image does not move.
*/ */
g_object_ref( in[0] ); g_object_ref( in[0] );
position[0] = in[0]; position[0] = in[0];
for( int i = 1; i < composite->n; i++ ) for( int i = 1; i < n; i++ )
if( vips_embed( in[i], &position[i], if( vips_embed( in[i], &position[i],
composite->x_offset[i - 1], composite->x_offset[i - 1],
composite->y_offset[i - 1], composite->y_offset[i - 1],
@ -1202,8 +1195,8 @@ vips_composite_base_build( VipsObject *object )
/* Transform the input images to match in size. They can be mismatched /* Transform the input images to match in size. They can be mismatched
* if there was no supplied x/y. * if there was no supplied x/y.
*/ */
size = (VipsImage **) vips_object_local_array( object, composite->n ); size = (VipsImage **) vips_object_local_array( object, n );
if( vips__sizealike_vec( in, size, composite->n ) ) if( vips__sizealike_vec( in, size, n ) )
return( -1 ); return( -1 );
in = size; in = size;