insert works fully

switched im_insert over, though nip2 make check still fails
This commit is contained in:
John Cupitt 2011-10-24 16:21:42 +01:00
parent 045c2b37aa
commit 0c74ac2ebf
7 changed files with 58 additions and 349 deletions

38
TODO
View File

@ -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,

View File

@ -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

View File

@ -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 );
}

View File

@ -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 );

View File

@ -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

View File

@ -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 ) );

View File

@ -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 );