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:
parent
8693179ef2
commit
cc29a13cc7
@ -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à]
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user