bandjoin done and dusted

This commit is contained in:
John Cupitt 2011-10-28 14:12:39 +01:00
parent c1f1957e88
commit 2da5560992
11 changed files with 116 additions and 311 deletions

View File

@ -3,7 +3,7 @@
- im_subtract(), im_avg(), im_min(), im_minpos(), im_copy(), im_embed(),
im_flophor(), im_flipver(), im_insert(), im_insert_noexpand(), im_lrjoin(),
im_tbjoin(), im_extract_area(), im_extract_bands(), im_extract_areabands(),
im_replicate(), im_clip2fmt()
im_replicate(), im_clip2fmt(), im_gbandjoin(), im_bandjoin()
redone as classes
- added argument priorites to help control arg ordering
- generate has a 'stop' param to signal successful early termination

8
TODO
View File

@ -1,11 +1,3 @@
- started factoring VipsArea out into area.[hc]
- bandjoin needs testing
see vips_bandjoin() .. ugly!
- does transform_array_g_string() work? it seems to use

View File

@ -20,7 +20,6 @@ libconversion_la_SOURCES = \
im_c2real.c \
im_copy_file.c \
im_falsecolour.c \
im_gbandjoin.c \
im_mask2vips.c \
im_msb.c \
im_grid.c \

View File

@ -257,9 +257,9 @@ vips_bandjoin_build( VipsObject *object )
{
VipsConversion *conversion = VIPS_CONVERSION( object );
VipsBandjoin *bandjoin = (VipsBandjoin *) object;
int n = bandjoin->in->n;
VipsImage **in;
int n;
int i;
VipsImage **format;
VipsImage **size;
@ -268,6 +268,7 @@ vips_bandjoin_build( VipsObject *object )
return( -1 );
in = bandjoin->in->data;
n = bandjoin->in->n;
if( n == 1 )
return( vips_image_write( in[0], conversion->out ) );
@ -286,9 +287,19 @@ vips_bandjoin_build( VipsObject *object )
return( -1 );
in = size;
bandjoin->is = VIPS_ARRAY( object, n, int );
for( i = 0; i < n; i++ )
bandjoin->is[i] = VIPS_IMAGE_SIZEOF_PEL( in[i] );
if( vips_image_copy_fields_array( conversion->out, in ) )
return( -1 );
vips_demand_hint_array( conversion->out,
VIPS_DEMAND_STYLE_THINSTRIP, in );
conversion->out->Bands = 0;
for( i = 0; i < n; i++ )
conversion->out->Bands += in[i]->Bands;
if( vips_image_generate( conversion->out,
vips_start_many, vips_bandjoin_gen, vips_stop_many,
in, bandjoin ) )
@ -352,3 +363,27 @@ vips_bandjoin( VipsImage **in, VipsImage **out, int n, ... )
return( result );
}
int
vips_bandjoin2( VipsImage *in1, VipsImage *in2, VipsImage **out, ... )
{
va_list ap;
VipsArea *area;
VipsImage **array;
int result;
area = vips_area_new_array_object( 2 );
array = (VipsImage **) area->data;
array[0] = in1;
array[1] = in2;
g_object_ref( array[0] );
g_object_ref( array[1] );
va_start( ap, out );
result = vips_call_split( "bandjoin", ap, area, out );
va_end( ap );
vips_area_unref( area );
return( result );
}

View File

@ -451,13 +451,12 @@ vips_embed_build( VipsObject *object )
case VIPS_EXTEND_COPY:
if( vips_image_copy_fields( conversion->out, embed->in ) )
return( -1 );
vips_demand_hint( conversion->out,
VIPS_DEMAND_STYLE_SMALLTILE, embed->in, NULL );
conversion->out->Xsize = embed->width;
conversion->out->Ysize = embed->height;
vips_demand_hint( conversion->out,
VIPS_DEMAND_STYLE_SMALLTILE, embed->in, NULL );
/* Whole output area.
*/
embed->rout.left = 0;

View File

@ -1,261 +0,0 @@
/* im_gbandjoin -- bandwise join of a set of images
*
* Copyright: 1991, N. Dessipris, modification of im_bandjoin()
*
* Author: N. Dessipris
* Written on: 17/04/1991
* Modified on :
* 16/3/94 JC
* - rewritten for partials
* - now in ANSI C
* - now works for any number of input images, except zero
* 7/10/94 JC
* - new IM_NEW()
* 16/4/07
* - fall back to im_copy() for 1 input image
* 17/1/09
* - cleanups
* - gtk-doc
* - im_bandjoin() just calls this
* - works for RAD coding too
* 27/1/10
* - formatalike inputs
* 17/5/11
* - sizealike inputs
*/
/*
This file is part of VIPS.
VIPS is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif /*HAVE_CONFIG_H*/
#include <vips/intl.h>
#include <stdio.h>
#include <stdlib.h>
#include <vips/vips.h>
#include <vips/internal.h>
/* Struct we carry stuff around in.
*/
typedef struct joins {
int n; /* Number of input images */
IMAGE **t; /* Array of temp images */
IMAGE **in; /* Array of input images, NULL-terminated */
int *is; /* An int for SIZEOF_PEL() for each image */
} Join;
/* Make a Join struct.
*/
static Join *
join_new( IMAGE *out, IMAGE **in, int n )
{
Join *join;
int i;
if( !(join = IM_NEW( out, Join )) )
return( NULL );
join->n = n;
if( !(join->t = IM_ARRAY( out, n, IMAGE * )) ||
!(join->in = IM_ARRAY( out, n + 1, IMAGE * )) ||
!(join->is = IM_ARRAY( out, n, int )) )
return( NULL );
/* Cast inputs up to a common format.
*/
if( im_open_local_array( out, join->t, n, "im_gbandjoin", "p" ) ||
im_open_local_array( out, join->in, n, "im_gbandjoin", "p" ) ||
im__formatalike_vec( in, join->t, n ) ||
im__sizealike_vec( join->t, join->in, n ) )
return( NULL );
for( i = 0; i < n; i++ )
join->is[i] = IM_IMAGE_SIZEOF_PEL( join->in[i] );
/* Remember to NULL-terminate. We pass ->in[] to
* im_demand_hint_array() and friends later.
*/
join->in[n] = NULL;
return( join );
}
/* Perform join.
*/
static int
join_bands( REGION *or, void *seq, void *a, void *b )
{
REGION **ir = (REGION **) seq;
Join *join = (Join *) b;
Rect *r = &or->valid;
const int ps = IM_IMAGE_SIZEOF_PEL( or->im );
int x, y, z, i;
for( i = 0; i < join->n; i++ )
if( im_prepare( ir[i], r ) )
return( -1 );
/* Loop over output!
*/
for( y = 0; y < r->height; y++ ) {
PEL *qb;
qb = (PEL *) IM_REGION_ADDR( or, r->left, r->top + y );
/* Loop for each input image. Scattered write is faster than
* scattered read.
*/
for( i = 0; i < join->n; i++ ) {
int k = join->is[i];
PEL *p;
PEL *q;
p = (PEL *) IM_REGION_ADDR( ir[i],
r->left, r->top + y );
q = qb;
for( x = 0; x < r->width; x++ ) {
for( z = 0; z < k; z++ )
q[z] = p[z];
p += z;
q += ps;
}
qb += k;
}
}
return( 0 );
}
/**
* im_gbandjoin:
* @in: vector of input images
* @out: output image
* @n: number of input images
*
* Join a set of images together, bandwise.
* If the images
* have n and m bands, then the output image will have n + m
* bands, with the first n coming from the first image and the last m
* from the second.
*
* If the images differ in size, the smaller images are enlarged to match the
* larger by adding zero pixels along the bottom and right.
*
* The 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_bandjoin(), im_insert().
*
* Returns: 0 on success, -1 on error
*/
int
im_gbandjoin( IMAGE **in, IMAGE *out, int n )
{
int i;
Join *join;
/* Check it out!
*/
if( n < 1 ) {
im_error( "im_gbandjoin", "%s", _( "zero input images!" ) );
return( -1 );
}
else if( n == 1 )
return( im_copy( in[0], out ) );
/* Check our args.
*/
if( im_poutcheck( out ) ||
im_check_coding_known( "im_gbandjoin", in[0] ) )
return( -1 );
for( i = 0; i < n; i++ )
if( im_pincheck( in[i] ) ||
im_check_coding_same( "im_gbandjoin", in[i], in[0] ) )
return( -1 );
/* Build a data area.
*/
if( !(join = join_new( out, in, n )) )
return( -1 );
/* Prepare the output header.
*/
if( im_cp_desc_array( out, join->in ) )
return( -1 );
out->Bands = 0;
for( i = 0; i < n; i++ )
out->Bands += join->in[i]->Bands;
if( im_demand_hint_array( out, IM_THINSTRIP, join->in ) )
return( -1 );
if( im_generate( out,
im_start_many, join_bands, im_stop_many, join->in, join ) )
return( -1 );
return( 0 );
}
/**
* im_bandjoin:
* @in1: first input image
* @in2: second input image
* @out: output image
*
* Join two images bandwise.
* If the two images
* have n and m bands respectively, then the output image will have n + m
* bands, with the first n coming from the first image and the last m
* from the second.
*
* If the images differ in size, the smaller image is enlarged to match the
* larger by adding zero pixels along the bottom and right.
*
* 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_gbandjoin(), im_insert().
*
* Returns: 0 on success, -1 on error
*/
int
im_bandjoin( IMAGE *in1, IMAGE *in2, IMAGE *out )
{
IMAGE *t[2];
t[0] = in1;
t[1] = in2;
return( im_gbandjoin( t, out, 2 ) );
}

View File

@ -1292,3 +1292,38 @@ im_ref_string_get_length( const GValue *value )
return( length );
}
int
im_bandjoin( VipsImage *in1, VipsImage *in2, VipsImage *out )
{
VipsImage *t;
if( vips_bandjoin2( in1, in2, &t,
NULL ) )
return( -1 );
if( vips_image_write( t, out ) ) {
g_object_unref( t );
return( -1 );
}
g_object_unref( t );
return( 0 );
}
int
im_gbandjoin( VipsImage **in, VipsImage *out, int n )
{
VipsImage *t;
if( vips_bandjoin( in, &t, n,
NULL ) )
return( -1 );
if( vips_image_write( t, out ) ) {
g_object_unref( t );
return( -1 );
}
g_object_unref( t );
return( 0 );
}

View File

@ -136,6 +136,10 @@ int vips_replicate( VipsImage *in, VipsImage **out, int across, int down, ... )
__attribute__((sentinel));
int vips_cast( VipsImage *in, VipsImage **out, VipsBandFormat format, ... )
__attribute__((sentinel));
int vips_bandjoin( VipsImage **in, VipsImage **out, int n, ... )
__attribute__((sentinel));
int vips_bandjoin2( VipsImage *in1, VipsImage *in2, VipsImage **out, ... )
__attribute__((sentinel));
@ -163,8 +167,6 @@ int im_black( VipsImage *out, int x, int y, int bands );
int im_text( VipsImage *out, const char *text, const char *font,
int width, int alignment, int dpi );
int im_bandjoin( VipsImage *in1, VipsImage *in2, VipsImage *out );
int im_gbandjoin( VipsImage **in, VipsImage *out, int n );
int im_insertset( VipsImage *main, VipsImage *sub, VipsImage *out, int n, int *x, int *y );
int im_grid( VipsImage *in, VipsImage *out, int tile_height, int across, int down );
int im_wrap( VipsImage *in, VipsImage *out, int x, int y );

View File

@ -560,6 +560,9 @@ int im_replicate( VipsImage *in, VipsImage *out, int across, int down );
int im_clip2fmt( VipsImage *in, VipsImage *out, VipsBandFormat fmt );
int im_bandjoin( VipsImage *in1, VipsImage *in2, VipsImage *out );
int im_gbandjoin( VipsImage **in, VipsImage *out, int n );
/* ruby-vips uses this
*/

View File

@ -1814,6 +1814,7 @@ vips_object_print_all_cb( VipsObject *object, int *n )
printf( "%d) ", *n );
vips_object_print_name( object );
printf( "\n" );
vips_object_print( object );
*n += 1;

View File

@ -97,7 +97,7 @@ vips_area_unref( VipsArea *area )
if( area->count == 0 ) {
if( area->free_fn && area->data ) {
area->free_fn( area->data, NULL );
area->free_fn( area->data, area );
area->data = NULL;
area->free_fn = NULL;
}
@ -171,16 +171,14 @@ vips_area_new_array( GType type, size_t sizeof_type, int n )
}
static void
vips_area_free_array_object( VipsArea *area )
vips_area_free_array_object( GObject **array, VipsArea *area )
{
GObject **array = (GObject **) area->data;
int i;
for( i = 0; i < area->n; i++ )
for( i = 0; i < area->n; i++ )
VIPS_FREEF( g_object_unref, array[i] );
g_free( area );
area->n = 0;
}
/* An area which holds an array of GObjects.
@ -251,7 +249,7 @@ vips_area_get_type( void )
static GType type = 0;
if( !type ) {
type = g_boxed_type_register_static( "vips_area",
type = g_boxed_type_register_static( "VipsArea",
(GBoxedCopyFunc) vips_area_copy,
(GBoxedFreeFunc) vips_area_unref );
g_value_register_transform_func( type, G_TYPE_STRING,
@ -359,7 +357,7 @@ vips_save_string_get_type( void )
static GType type = 0;
if( !type ) {
type = g_boxed_type_register_static( "vips_save_string",
type = g_boxed_type_register_static( "VipsSaveString",
(GBoxedCopyFunc) g_strdup,
(GBoxedFreeFunc) g_free );
}
@ -454,7 +452,7 @@ vips_ref_string_get_type( void )
static GType type = 0;
if( !type ) {
type = g_boxed_type_register_static( "vips_ref_string",
type = g_boxed_type_register_static( "VipsRefString",
(GBoxedCopyFunc) vips_area_copy,
(GBoxedFreeFunc) vips_area_unref );
g_value_register_transform_func( type, G_TYPE_STRING,
@ -575,7 +573,7 @@ vips_blob_get_type( void )
static GType type = 0;
if( !type ) {
type = g_boxed_type_register_static( "vips_blob",
type = g_boxed_type_register_static( "VipsBlob",
(GBoxedCopyFunc) vips_area_copy,
(GBoxedFreeFunc) vips_area_unref );
g_value_register_transform_func( type, G_TYPE_STRING,
@ -710,32 +708,33 @@ transform_array_g_string( const GValue *src_value, GValue *dest_value )
static void
transform_g_string_array_double( const GValue *src_value, GValue *dest_value )
{
const char *str = g_value_get_string( src_value );
char *str;
int n;
const char *p;
char *p, *q;
int i;
double *array;
/* Walk the string to get the number of elements. Empty string is zero
* elements.
/* Walk the string to get the number of elements.
* We need a copy of the string, since we insert \0 during
* scan.
*
* We can't allow ',' as a separator, since some locales use it as a
* decimal point.
*/
for( n = 0, p = str; p && *p; n += 1 ) {
p = strchr( p, ',' );
if( p )
p += 1;
}
str = g_value_dup_string( src_value );
n = 0;
for( p = str; (q = vips_break_token( p, "\t; " )); p = q )
n += 1;
g_free( str );
vips_value_set_array( dest_value, G_TYPE_DOUBLE, sizeof( double ), n );
array = (double *) vips_value_get_array( dest_value, NULL, NULL, NULL );
p = str;
for( i = 0; i < n; i++ ) {
array[i] = atof( p );
p = strchr( p, ',' );
if( p )
p += 1;
}
str = g_value_dup_string( src_value );
i = 0;
for( p = str; (q = vips_break_token( p, "\t; " )); p = q )
array[i++] = atof( p );
g_free( str );
}
GType
@ -744,7 +743,7 @@ vips_array_double_get_type( void )
static GType type = 0;
if( !type ) {
type = g_boxed_type_register_static( "vips_array_double",
type = g_boxed_type_register_static( "VipsArrayDouble",
(GBoxedCopyFunc) vips_area_copy,
(GBoxedFreeFunc) vips_area_unref );
g_value_register_transform_func( type, G_TYPE_STRING,
@ -810,16 +809,17 @@ transform_g_string_array_image( const GValue *src_value, GValue *dest_value )
/* We need a copy of the string, since we insert \0 during
* scan.
*/
str = g_strdup_value_contents( src_value );
for( n = 0; (q = vips_break_token( p, " " )); n++, p = q )
;
str = g_value_dup_string( src_value );
n = 0;
for( p = str; (q = vips_break_token( p, " " )); p = q )
n += 1;
g_free( str );
vips_value_set_array_object( dest_value, n );
array = vips_value_get_array_object( dest_value, NULL );
str = g_strdup_value_contents( src_value );
for( i = 0; (q = vips_break_token( p, " " )); i++, p = q )
str = g_value_dup_string( src_value );
for( i = 0, p = str; (q = vips_break_token( p, " " )); i++, p = q )
/* Sadly there's no error return possible here.
*/
array[i] = G_OBJECT( vips_image_new_from_file( p ) );
@ -832,7 +832,7 @@ vips_array_image_get_type( void )
static GType type = 0;
if( !type ) {
type = g_boxed_type_register_static( "vips_array_image",
type = g_boxed_type_register_static( "VipsArrayImage",
(GBoxedCopyFunc) vips_area_copy,
(GBoxedFreeFunc) vips_area_unref );
g_value_register_transform_func( G_TYPE_STRING, type,