insert works fully
switched im_insert over, though nip2 make check still fails
This commit is contained in:
parent
045c2b37aa
commit
0c74ac2ebf
38
TODO
38
TODO
@ -1,41 +1,3 @@
|
||||
- at the moment background is VIPS_TYPE_ARRAY_DOUBLE (a type created with
|
||||
g_boxed_type_register_static()) stored in a paramspec created with
|
||||
g_param_spec_boxed()
|
||||
|
||||
this means we will need a lot of
|
||||
|
||||
if( G_IS_PARAM_SPEC_BOXED( pspec ) &&
|
||||
(G_PARAM_SPEC_VALUE_TYPE( pspec ) == VIPS_TYPE_ARRAY_DOUBLE ||
|
||||
G_PARAM_SPEC_VALUE_TYPE( pspec ) == VIPS_TYPE_ARRAY_INT ||
|
||||
...
|
||||
|
||||
to spot vector args, since we don't have the idea of generic vector in the
|
||||
type system
|
||||
|
||||
we can't make a generic VIPS_TYPE_ARRAY boxed, since
|
||||
g_boxed_type_register_static() does not let us specify a parent class, the
|
||||
code has G_TYPE_BOXED hardwired as the parent class
|
||||
|
||||
instead, perhaps derive from G_TYPE_PARAM_BOXED to create
|
||||
VIPS_TYPE_PARAM_ARRAY, a boxed param that can only be a VipsArea array ...
|
||||
would this work?
|
||||
|
||||
nope, g_param_type_register_static() is also hardwired to have G_TYPE_PARAM
|
||||
as its parent class argh
|
||||
|
||||
best we can do is register a char->value transform in each array type, and
|
||||
have the generic transformer as a utility function
|
||||
|
||||
|
||||
|
||||
break in transform_g_string_array() and try running with --background
|
||||
|
||||
do we have anything in dest_value we can use to decide what type to write?
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
- we have this is many places:
|
||||
|
||||
if( vips_image_copy_fieldsv( conversion->output,
|
||||
|
@ -105,296 +105,6 @@ im__insert_base( const char *domain,
|
||||
return( vec );
|
||||
}
|
||||
|
||||
/* Hold our state in this.
|
||||
*/
|
||||
typedef struct {
|
||||
/* Args.
|
||||
*/
|
||||
IMAGE *main; /* Main image */
|
||||
IMAGE *sub; /* Sub image */
|
||||
IMAGE *out; /* Output image */
|
||||
int x, y; /* Position of sub wrt. main */
|
||||
|
||||
/* Geometry.
|
||||
*/
|
||||
Rect rout; /* Output space */
|
||||
Rect rmain; /* Position of main in output */
|
||||
Rect rsub; /* Position of sub in output */
|
||||
} InsertState;
|
||||
|
||||
/* Trivial case: we just need pels from one of the inputs.
|
||||
*/
|
||||
static int
|
||||
just_one( REGION *or, REGION *ir, int x, int y )
|
||||
{
|
||||
Rect need;
|
||||
|
||||
/* Find the part of pos we need.
|
||||
*/
|
||||
need = or->valid;
|
||||
need.left -= x;
|
||||
need.top -= y;
|
||||
if( im_prepare( ir, &need ) )
|
||||
return( -1 );
|
||||
|
||||
/* Attach our output to it.
|
||||
*/
|
||||
if( im_region_region( or, ir, &or->valid, need.left, need.top ) )
|
||||
return( -1 );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
/* Paste in parts of ir that fall within or --- ir is an input REGION for an
|
||||
* image positioned at pos within or.
|
||||
*/
|
||||
static int
|
||||
paste_region( REGION *or, REGION *ir, Rect *pos )
|
||||
{
|
||||
Rect ovl;
|
||||
|
||||
/* Does any of the sub-image appear in the area we have been asked
|
||||
* to make?
|
||||
*/
|
||||
im_rect_intersectrect( &or->valid, pos, &ovl );
|
||||
if( !im_rect_isempty( &ovl ) ) {
|
||||
/* Find the part of in we need.
|
||||
*/
|
||||
ovl.left -= pos->left;
|
||||
ovl.top -= pos->top;
|
||||
|
||||
/* Paint this area of pixels into or.
|
||||
*/
|
||||
if( im_prepare_to( ir, or, &ovl,
|
||||
ovl.left + pos->left, ovl.top + pos->top ) )
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
/* Insert generate function.
|
||||
*/
|
||||
static int
|
||||
insert_gen( REGION *or, void *seq, void *a, void *b )
|
||||
{
|
||||
REGION **ir = (REGION **) seq;
|
||||
InsertState *ins = (InsertState *) b;
|
||||
Rect ovl;
|
||||
|
||||
/* Does the rect we have been asked for fall entirely inside the
|
||||
* sub-image?
|
||||
*/
|
||||
if( im_rect_includesrect( &ins->rsub, &or->valid ) )
|
||||
return( just_one( or, ir[1],
|
||||
ins->rsub.left, ins->rsub.top ) );
|
||||
|
||||
/* Does it fall entirely inside the main, and not at all inside the
|
||||
* sub?
|
||||
*/
|
||||
im_rect_intersectrect( &or->valid, &ins->rsub, &ovl );
|
||||
if( im_rect_includesrect( &ins->rmain, &or->valid ) &&
|
||||
im_rect_isempty( &ovl ) )
|
||||
return( just_one( or, ir[0],
|
||||
ins->rmain.left, ins->rmain.top ) );
|
||||
|
||||
/* Output requires both (or neither) input. If it is not entirely
|
||||
* inside both the main and the sub, then there is going to be some
|
||||
* black.
|
||||
*/
|
||||
if( !(im_rect_includesrect( &ins->rsub, &or->valid ) &&
|
||||
im_rect_includesrect( &ins->rmain, &or->valid )) )
|
||||
/* Could be clever --- but just black the whole thing for
|
||||
* simplicity.
|
||||
*/
|
||||
im_region_black( or );
|
||||
|
||||
/* Paste from main.
|
||||
*/
|
||||
if( paste_region( or, ir[0], &ins->rmain ) )
|
||||
return( -1 );
|
||||
|
||||
/* Paste from sub.
|
||||
*/
|
||||
if( paste_region( or, ir[1], &ins->rsub ) )
|
||||
return( -1 );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
/* xy range we sanity check on ... just to stop crazy numbers from 1/0 etc.
|
||||
* causing assert() failures later.
|
||||
*/
|
||||
#define RANGE (10000000)
|
||||
|
||||
/**
|
||||
* im_insert:
|
||||
* @main: big image
|
||||
* @sub: small image
|
||||
* @out: output image
|
||||
* @x: left position of @sub
|
||||
* @y: top position of @sub
|
||||
*
|
||||
* Insert one image into another. @sub is inserted into image @main at
|
||||
* position @x, @y relative to the top LH corner of @main. @out is made large
|
||||
* enough to hold both @main and @sub. Any areas of @out not coming from
|
||||
* either @main or @sub are set to black (binary 0). If @sub overlaps @main,
|
||||
* @sub will appear on top of @main.
|
||||
*
|
||||
* If the number of bands differs, one of the images
|
||||
* must have one band. In this case, an n-band image is formed from the
|
||||
* one-band image by joining n copies of the one-band image together, and then
|
||||
* the two n-band images are operated upon.
|
||||
*
|
||||
* The two input images are cast up to the smallest common type (see table
|
||||
* Smallest common format in
|
||||
* <link linkend="VIPS-arithmetic">arithmetic</link>).
|
||||
*
|
||||
* See also: im_insert_noexpand(), im_lrjoin().
|
||||
*
|
||||
* Returns: 0 on success, -1 on error
|
||||
*/
|
||||
int
|
||||
im_insert( IMAGE *main, IMAGE *sub, IMAGE *out, int x, int y )
|
||||
{
|
||||
InsertState *ins;
|
||||
IMAGE **vec;
|
||||
|
||||
/* Check args.
|
||||
*/
|
||||
if( x > RANGE || x < -RANGE || y > RANGE || y < -RANGE ) {
|
||||
im_error( "im_insert", "%s", _( "xy out of range" ) );
|
||||
return( -1 );
|
||||
}
|
||||
if( !(ins = IM_NEW( out, InsertState )) ||
|
||||
!(vec = im__insert_base( "im_insert", main, sub, out )) )
|
||||
return( -1 );
|
||||
|
||||
/* Save args.
|
||||
*/
|
||||
ins->main = vec[0];
|
||||
ins->sub = vec[1];
|
||||
ins->out = out;
|
||||
ins->x = x;
|
||||
ins->y = y;
|
||||
|
||||
/* Calculate geometry. First, position rmain and rsub with (0,0) at
|
||||
* top LH corner of main.
|
||||
*/
|
||||
ins->rmain.left = 0;
|
||||
ins->rmain.top = 0;
|
||||
ins->rmain.width = vec[0]->Xsize;
|
||||
ins->rmain.height = vec[0]->Ysize;
|
||||
ins->rsub.left = x;
|
||||
ins->rsub.top = y;
|
||||
ins->rsub.width = vec[1]->Xsize;
|
||||
ins->rsub.height = vec[1]->Ysize;
|
||||
|
||||
/* Now: output is bounding box of these two.
|
||||
*/
|
||||
im_rect_unionrect( &ins->rmain, &ins->rsub, &ins->rout );
|
||||
|
||||
/* Translate origin to top LH corner of rout.
|
||||
*/
|
||||
ins->rmain.left -= ins->rout.left;
|
||||
ins->rmain.top -= ins->rout.top;
|
||||
ins->rsub.left -= ins->rout.left;
|
||||
ins->rsub.top -= ins->rout.top;
|
||||
ins->rout.left = 0;
|
||||
ins->rout.top = 0;
|
||||
|
||||
/* Set up the output header.
|
||||
*/
|
||||
out->Xsize = ins->rout.width;
|
||||
out->Ysize = ins->rout.height;
|
||||
|
||||
/* Make output image.
|
||||
*/
|
||||
if( im_generate( out,
|
||||
im_start_many, insert_gen, im_stop_many, vec, ins ) )
|
||||
return( -1 );
|
||||
|
||||
out->Xoffset = ins->rmain.left;
|
||||
out->Yoffset = ins->rmain.top;
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
/**
|
||||
* im_insert_noexpand:
|
||||
* @main: big image
|
||||
* @sub: small image
|
||||
* @out: output image
|
||||
* @x: left position of @sub
|
||||
* @y: top position of @sub
|
||||
*
|
||||
* Insert one image into another. @sub is inserted into image @main at
|
||||
* position @x, @y relative to the top LH corner of @main. @out is the same
|
||||
* size as @main. @sub is clipped against the edges of @main.
|
||||
*
|
||||
* If the number of bands differs, one of the images
|
||||
* must have one band. In this case, an n-band image is formed from the
|
||||
* one-band image by joining n copies of the one-band image together, and then
|
||||
* the two n-band images are operated upon.
|
||||
*
|
||||
* The two input images are cast up to the smallest common type (see table
|
||||
* Smallest common format in
|
||||
* <link linkend="VIPS-arithmetic">arithmetic</link>).
|
||||
*
|
||||
* See also: im_insert_noexpand(), im_lrjoin(), im_draw_image().
|
||||
*
|
||||
* Returns: 0 on success, -1 on error
|
||||
*/
|
||||
int
|
||||
im_insert_noexpand( IMAGE *main, IMAGE *sub, IMAGE *out, int x, int y )
|
||||
{
|
||||
InsertState *ins;
|
||||
IMAGE **vec;
|
||||
|
||||
/* Check args.
|
||||
*/
|
||||
if( x > RANGE || x < -RANGE || y > RANGE || y < -RANGE ) {
|
||||
im_error( "im_insert", "%s", _( "xy out of range" ) );
|
||||
return( -1 );
|
||||
}
|
||||
if( !(ins = IM_NEW( out, InsertState )) ||
|
||||
!(vec = im__insert_base( "im_insert", main, sub, out )) )
|
||||
return( -1 );
|
||||
|
||||
/* Save args.
|
||||
*/
|
||||
ins->main = vec[0];
|
||||
ins->sub = vec[1];
|
||||
ins->out = out;
|
||||
ins->x = x;
|
||||
ins->y = y;
|
||||
|
||||
/* Calculate geometry.
|
||||
*/
|
||||
ins->rmain.left = 0;
|
||||
ins->rmain.top = 0;
|
||||
ins->rmain.width = vec[0]->Xsize;
|
||||
ins->rmain.height = vec[0]->Ysize;
|
||||
ins->rsub.left = x;
|
||||
ins->rsub.top = y;
|
||||
ins->rsub.width = vec[1]->Xsize;
|
||||
ins->rsub.height = vec[1]->Ysize;
|
||||
ins->rout = ins->rmain;
|
||||
|
||||
/* Set up the output header.
|
||||
*/
|
||||
out->Xsize = ins->rout.width;
|
||||
out->Ysize = ins->rout.height;
|
||||
|
||||
/* Make output image.
|
||||
*/
|
||||
if( im_generate( out,
|
||||
im_start_many, insert_gen, im_stop_many, vec, ins ) )
|
||||
return( -1 );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
/**
|
||||
* im_insertset:
|
||||
* @main: big image
|
||||
|
@ -1111,3 +1111,39 @@ im_flipver( IMAGE *in, IMAGE *out )
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
int
|
||||
im_insert( IMAGE *main, IMAGE *sub, IMAGE *out, int x, int y )
|
||||
{
|
||||
VipsImage *t;
|
||||
|
||||
if( vips_insert( main, sub, &t, x, y,
|
||||
"expand", TRUE,
|
||||
NULL ) )
|
||||
return( -1 );
|
||||
if( vips_image_write( t, out ) ) {
|
||||
g_object_unref( t );
|
||||
return( -1 );
|
||||
}
|
||||
g_object_unref( t );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
int
|
||||
im_insert_noexpand( IMAGE *main, IMAGE *sub, IMAGE *out, int x, int y )
|
||||
{
|
||||
VipsImage *t;
|
||||
|
||||
if( vips_insert( main, sub, &t, x, y, NULL ) )
|
||||
return( -1 );
|
||||
if( vips_image_write( t, out ) ) {
|
||||
g_object_unref( t );
|
||||
return( -1 );
|
||||
}
|
||||
g_object_unref( t );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
|
||||
|
@ -101,6 +101,9 @@ int vips_embed( VipsImage *in, VipsImage **out,
|
||||
__attribute__((sentinel));
|
||||
int vips_flip( VipsImage *in, VipsImage **out, VipsDirection direction, ... )
|
||||
__attribute__((sentinel));
|
||||
int vips_insert( VipsImage *main, VipsImage *sub, VipsImage **out,
|
||||
int x, int y, ... )
|
||||
__attribute__((sentinel));
|
||||
|
||||
|
||||
|
||||
@ -137,8 +140,6 @@ int im_extract_areabands( VipsImage *in, VipsImage *out,
|
||||
int left, int top, int width, int height, int band, int nbands );
|
||||
int im_bandjoin( VipsImage *in1, VipsImage *in2, VipsImage *out );
|
||||
int im_gbandjoin( VipsImage **in, VipsImage *out, int n );
|
||||
int im_insert( VipsImage *main, VipsImage *sub, VipsImage *out, int x, int y );
|
||||
int im_insert_noexpand( VipsImage *main, VipsImage *sub, VipsImage *out, int x, int y );
|
||||
int im_insertset( VipsImage *main, VipsImage *sub, VipsImage *out, int n, int *x, int *y );
|
||||
int im_lrjoin( VipsImage *left, VipsImage *right, VipsImage *out );
|
||||
int im_tbjoin( VipsImage *top, VipsImage *bottom, VipsImage *out );
|
||||
|
@ -543,6 +543,9 @@ int im_embed( VipsImage *in, VipsImage *out,
|
||||
int im_fliphor( VipsImage *in, VipsImage *out );
|
||||
int im_flipver( VipsImage *in, VipsImage *out );
|
||||
|
||||
int im_insert( VipsImage *main, VipsImage *sub, VipsImage *out, int x, int y );
|
||||
int im_insert_noexpand( VipsImage *main, VipsImage *sub, VipsImage *out, int x, int y );
|
||||
|
||||
/* ruby-vips uses this
|
||||
*/
|
||||
#define vips_class_map_concrete_all vips_class_map_all
|
||||
|
@ -49,9 +49,9 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
*/
|
||||
#define VIPS_DEBUG
|
||||
#define DEBUG
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
@ -1575,15 +1575,18 @@ transform_array_g_string( const GValue *src_value, GValue *dest_value )
|
||||
g_value_set_string( dest_value, vips_buf_all( &buf ) );
|
||||
}
|
||||
|
||||
/* It'd be great to be able to write a generic string->array function, but
|
||||
* it doesn't seem possible.
|
||||
*/
|
||||
static void
|
||||
transform_g_string_array( const GValue *src_value, GValue *dest_value )
|
||||
transform_g_string_array_double( const GValue *src_value, GValue *dest_value )
|
||||
{
|
||||
const char *str = g_value_get_string( src_value );
|
||||
|
||||
int n;
|
||||
const char *p;
|
||||
int i;
|
||||
GType type;
|
||||
double *array;
|
||||
|
||||
/* Walk the string to get the number of elements. Empty string is zero
|
||||
* elements.
|
||||
@ -1594,19 +1597,16 @@ transform_g_string_array( const GValue *src_value, GValue *dest_value )
|
||||
p += 1;
|
||||
}
|
||||
|
||||
vips_array_set( dest_value, G_TYPE_DOUBLE, sizeof( double ), n );
|
||||
array = (double *) vips_array_get( dest_value, NULL, NULL, NULL );
|
||||
|
||||
p = str;
|
||||
for( i = 0; i < n; i++ ) {
|
||||
GValue value = { 0, };
|
||||
char *str;
|
||||
|
||||
g_value_init( &value, type );
|
||||
//g_value_set_instance( &value, array );
|
||||
|
||||
g_value_unset( &value );
|
||||
|
||||
// array += sizeof_type;
|
||||
array[i] = atof( p );
|
||||
p = strchr( p, ',' );
|
||||
if( p )
|
||||
p += 1;
|
||||
}
|
||||
|
||||
// g_value_set_string( dest_value, vips_buf_all( &buf ) );
|
||||
}
|
||||
|
||||
GType
|
||||
@ -1621,7 +1621,7 @@ vips_array_double_get_type( void )
|
||||
g_value_register_transform_func( type, G_TYPE_STRING,
|
||||
transform_array_g_string );
|
||||
g_value_register_transform_func( G_TYPE_STRING, type,
|
||||
transform_g_string_array );
|
||||
transform_g_string_array_double );
|
||||
}
|
||||
|
||||
return( type );
|
||||
@ -1662,6 +1662,7 @@ vips_array_double_set( GValue *value, const double *array, int n )
|
||||
{
|
||||
double *array_copy;
|
||||
|
||||
g_value_init( value, VIPS_TYPE_ARRAY_DOUBLE );
|
||||
vips_array_set( value, G_TYPE_DOUBLE, sizeof( double ), n );
|
||||
array_copy = vips_array_double_get( value, NULL );
|
||||
memcpy( array_copy, array, n * sizeof( double ) );
|
||||
|
@ -1261,10 +1261,6 @@ vips_object_set_argument_from_string( VipsObject *object,
|
||||
g_value_init( &gvalue, otype );
|
||||
g_value_set_enum( &gvalue, enum_value->value );
|
||||
}
|
||||
else if( G_IS_PARAM_SPEC_BOXED( pspec ) &&
|
||||
G_PARAM_SPEC_VALUE_TYPE( pspec ) == VIPS_TYPE_ARRAY_DOUBLE ) {
|
||||
printf( "init double array from %s\n", value );
|
||||
}
|
||||
else {
|
||||
g_value_init( &gvalue, G_TYPE_STRING );
|
||||
g_value_set_string( &gvalue, value );
|
||||
|
Loading…
Reference in New Issue
Block a user