revise composite position code slightly

- move x/y into composite and out of composite base, have separate x/y int
params for composite2
- upsize later for a small speed improvement
- doc comment
- note in changelog

see https://github.com/jcupitt/libvips/pull/934
This commit is contained in:
John Cupitt 2018-06-11 17:04:29 +01:00
parent 8693179ef2
commit cc29a13cc7
3 changed files with 133 additions and 71 deletions

View File

@ -27,6 +27,7 @@
- pdfload has a option for background
- vips7 C++ interface defaults off
- make members, getters and operators "const" in cpp API
- composite has params for x/y position of sub-images [medakk]
12/3/18 started 8.6.4
- better fitting of fonts with overhanging edges [Adrià]

View File

@ -7,6 +7,8 @@
* 30/1/18
* - remove number of images limit
* - allow one mode ... reused for all joins
* 11/8/18 [medakk]
* - x/y params let you position images
*/
/*
@ -87,14 +89,6 @@ typedef struct _VipsCompositeBase {
*/
VipsArrayInt *mode;
/* For N input images, N - 1 x coordinates.
*/
VipsArrayInt *x;
/* For N input images, N - 1 y coordinates.
*/
VipsArrayInt *y;
/* Compositing space. This defaults to RGB, or B_W if we only have
* G and GA inputs.
*/
@ -118,6 +112,12 @@ typedef struct _VipsCompositeBase {
*/
double max_band[MAX_BANDS + 1];
/* The x and y positions for each image in the stack. There are n - 1
* of these, since image 0 is always positioned at (0, 0).
*/
int *x_offset;
int *y_offset;
#ifdef HAVE_VECTOR_ARITH
/* max_band as a vector, for the RGBA case.
*/
@ -148,14 +148,6 @@ vips_composite_base_dispose( GObject *gobject )
vips_area_unref( (VipsArea *) composite->mode );
composite->mode = NULL;
}
if( composite->x ) {
vips_area_unref( (VipsArea *) composite->x );
composite->x = NULL;
}
if( composite->y ) {
vips_area_unref( (VipsArea *) composite->y );
composite->y = NULL;
}
G_OBJECT_CLASS( vips_composite_base_parent_class )->dispose( gobject );
}
@ -1074,44 +1066,8 @@ vips_composite_base_build( VipsObject *object )
}
}
if( vips_object_argument_isset( object, "x" ) ) {
if( composite->x->area.n != composite->n - 1 ) {
vips_error( klass->nickname, _( "must be %d x coordinates" ),
composite->n - 1 );
return( -1 );
}
}
if( vips_object_argument_isset( object, "y" ) ) {
if( composite->y->area.n != composite->n - 1 ) {
vips_error( klass->nickname, _( "must be %d y coordinates" ),
composite->n - 1 );
return( -1 );
}
}
in = (VipsImage **) composite->in->area.data;
if( vips_object_argument_isset( object, "x" ) && vips_object_argument_isset( object, "y" ) ) {
int width, height;
width = vips_image_get_width( in[0] );
height = vips_image_get_height( in[0] );
int *x_offsets = (int *) composite->x->area.data;
int *y_offsets = (int *) composite->y->area.data;
for( int i = 1; i < composite->n; i++ ) {
VipsImage *e;
if( vips_embed( in[i], &e, x_offsets[i - 1], y_offsets[i - 1], width, height, NULL ) )
return( -1 );
g_object_unref( in[i] );
in[i] = e;
}
}
decode = (VipsImage **) vips_object_local_array( object, composite->n );
for( int i = 0; i < composite->n; i++ )
if( vips_image_decode( in[i], &decode[i] ) )
@ -1210,13 +1166,43 @@ vips_composite_base_build( VipsObject *object )
composite->max_band_vec[b] = composite->max_band[b];
#endif /*HAVE_VECTOR_ARITH*/
/* Transform the input images to match in size and format. We may have
/* Transform the input images to match format. We may have
* mixed float and double, for example.
*/
format = (VipsImage **) vips_object_local_array( object, composite->n );
if( vips__formatalike_vec( in, format, composite->n ) )
return( -1 );
in = format;
/* Position all images, if x/y is set.
*/
if( composite->x_offset &&
composite->y_offset ) {
int width = vips_image_get_width( in[0] );
int height = vips_image_get_height( in[0] );
VipsImage **position = (VipsImage **)
vips_object_local_array( object, composite->n );
/* The zero image does not move.
*/
g_object_ref( in[0] );
position[0] = in[0];
for( int i = 1; i < composite->n; i++ )
if( vips_embed( in[i], &position[i],
composite->x_offset[i - 1],
composite->y_offset[i - 1],
width, height, NULL ) )
return( -1 );
in = position;
}
/* Transform the input images to match in size. They can be mismatched
* if there was no supplied x/y.
*/
size = (VipsImage **) vips_object_local_array( object, composite->n );
if( vips__formatalike_vec( in, format, composite->n ) ||
vips__sizealike_vec( format, size, composite->n ) )
if( vips__sizealike_vec( in, size, composite->n ) )
return( -1 );
in = size;
@ -1267,20 +1253,6 @@ vips_composite_base_class_init( VipsCompositeBaseClass *klass )
G_STRUCT_OFFSET( VipsCompositeBase, premultiplied ),
FALSE );
VIPS_ARG_BOXED( klass, "x", 12,
_( "x coordinates" ),
_( "Array of x coordinates to join at" ),
VIPS_ARGUMENT_OPTIONAL_INPUT,
G_STRUCT_OFFSET( VipsCompositeBase, x ),
VIPS_TYPE_ARRAY_INT );
VIPS_ARG_BOXED( klass, "y", 13,
_( "y coordinates" ),
_( "Array of y coordinates to join at" ),
VIPS_ARGUMENT_OPTIONAL_INPUT,
G_STRUCT_OFFSET( VipsCompositeBase, y ),
VIPS_TYPE_ARRAY_INT );
}
static void
@ -1292,6 +1264,14 @@ vips_composite_base_init( VipsCompositeBase *composite )
typedef struct _VipsComposite {
VipsCompositeBase parent_instance;
/* For N input images, N - 1 x coordinates.
*/
VipsArrayInt *x;
/* For N input images, N - 1 y coordinates.
*/
VipsArrayInt *y;
} VipsComposite;
typedef VipsCompositeBaseClass VipsCompositeClass;
@ -1302,6 +1282,44 @@ extern "C" {
G_DEFINE_TYPE( VipsComposite, vips_composite, vips_composite_base_get_type() );
}
static int
vips_composite_build( VipsObject *object )
{
VipsObjectClass *klass = VIPS_OBJECT_GET_CLASS( object );
VipsCompositeBase *base = (VipsCompositeBase *) object;
VipsComposite *composite = (VipsComposite *) object;
int n;
n = 0;
if( vips_object_argument_isset( object, "in" ) )
n = base->in->area.n;
if( vips_object_argument_isset( object, "x" ) ) {
if( composite->x->area.n != n - 1 ) {
vips_error( klass->nickname,
_( "must be %d x coordinates" ), n - 1 );
return( -1 );
}
base->x_offset = (int *) composite->x->area.data;
}
if( vips_object_argument_isset( object, "y" ) ) {
if( composite->y->area.n != n - 1 ) {
vips_error( klass->nickname,
_( "must be %d y coordinates" ), n - 1 );
return( -1 );
}
base->y_offset = (int *) composite->y->area.data;
}
if( VIPS_OBJECT_CLASS( vips_composite_parent_class )->
build( object ) )
return( -1 );
return( 0 );
}
static void
vips_composite_class_init( VipsCompositeClass *klass )
{
@ -1317,7 +1335,7 @@ vips_composite_class_init( VipsCompositeClass *klass )
vobject_class->nickname = "composite";
vobject_class->description =
_( "blend an array of images with an array of blend modes" );
vobject_class->build = vips_composite_base_build;
vobject_class->build = vips_composite_build;
operation_class->flags = VIPS_OPERATION_SEQUENTIAL;
@ -1335,6 +1353,20 @@ vips_composite_class_init( VipsCompositeClass *klass )
G_STRUCT_OFFSET( VipsCompositeBase, mode ),
VIPS_TYPE_ARRAY_INT );
VIPS_ARG_BOXED( klass, "x", 4,
_( "x coordinates" ),
_( "Array of x coordinates to join at" ),
VIPS_ARGUMENT_OPTIONAL_INPUT,
G_STRUCT_OFFSET( VipsComposite, x ),
VIPS_TYPE_ARRAY_INT );
VIPS_ARG_BOXED( klass, "y", 5,
_( "y coordinates" ),
_( "Array of y coordinates to join at" ),
VIPS_ARGUMENT_OPTIONAL_INPUT,
G_STRUCT_OFFSET( VipsComposite, y ),
VIPS_TYPE_ARRAY_INT );
}
static void
@ -1381,6 +1413,8 @@ typedef struct _VipsComposite2 {
VipsImage *base;
VipsImage *overlay;
VipsBlendMode mode;
int x;
int y;
} VipsComposite2;
@ -1412,6 +1446,9 @@ vips_composite2_build( VipsObject *object )
base->mode = vips_array_int_new( mode, 1 );
}
base->x_offset = &composite2->x;
base->y_offset = &composite2->y;
if( VIPS_OBJECT_CLASS( vips_composite2_parent_class )->build( object ) )
return( -1 );
@ -1456,6 +1493,20 @@ vips_composite2_class_init( VipsCompositeClass *klass )
G_STRUCT_OFFSET( VipsComposite2, mode ),
VIPS_TYPE_BLEND_MODE, VIPS_BLEND_MODE_OVER );
VIPS_ARG_INT( klass, "x", 4,
_( "x" ),
_( "x position of overlay" ),
VIPS_ARGUMENT_OPTIONAL_INPUT,
G_STRUCT_OFFSET( VipsComposite2, x ),
-VIPS_MAX_COORD, VIPS_MAX_COORD, 0 );
VIPS_ARG_INT( klass, "y", 5,
_( "y" ),
_( "y position of overlay" ),
VIPS_ARGUMENT_OPTIONAL_INPUT,
G_STRUCT_OFFSET( VipsComposite2, y ),
-VIPS_MAX_COORD, VIPS_MAX_COORD, 0 );
}
static void

View File

@ -81,6 +81,8 @@
*
* * @compositing_space: #VipsInterpretation to composite in
* * @premultiplied: %gboolean, images are already premultiplied
* * @x: #VipsArrayInt, position of subimages
* * @y: #VipsArrayInt, position of subimages
*
* Composite an array of images together.
*
@ -106,7 +108,8 @@
* added to any input missing an alpha.
*
* The images do not need to match in size or format. They will be expanded to
* the smallest common size and format in the usual way.
* the smallest common size and format in the usual way. Images are positioned
* using the @x and @y parameters, if set.
*
* Image are normally treated as unpremultiplied, so this operation can be used
* directly on PNG images. If your images have been through vips_premultiply(),
@ -125,6 +128,13 @@
* @mode: composite with this blend mode
* @...: %NULL-terminated list of optional named arguments
*
* Optional arguments:
*
* * @compositing_space: #VipsInterpretation to composite in
* * @premultiplied: %gboolean, images are already premultiplied
* * @x: %gint, position of overlay
* * @y: %gint, position of overlay
*
* Composite @overlay on top of @base with @mode. See vips_composite().
*
* Returns: 0 on success, -1 on error