From b11de1ce2258fe9289b433b7210d3c208eb8c040 Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Sat, 21 Sep 2013 15:21:15 +0100 Subject: [PATCH] redo im_profile() as a class also fix an oops in the new project.c code --- ChangeLog | 2 +- libvips/arithmetic/Makefile.am | 1 + libvips/arithmetic/arithmetic.c | 2 + libvips/arithmetic/profile.c | 344 +++++++++++++++++++++++++++++ libvips/arithmetic/project.c | 44 +--- libvips/deprecated/vips7compat.c | 33 +++ libvips/include/vips/arithmetic.h | 4 +- libvips/include/vips/morphology.h | 1 - libvips/include/vips/vips7compat.h | 1 + libvips/morphology/Makefile.am | 3 +- libvips/morphology/im_profile.c | 173 --------------- 11 files changed, 398 insertions(+), 210 deletions(-) create mode 100644 libvips/arithmetic/profile.c delete mode 100644 libvips/morphology/im_profile.c diff --git a/ChangeLog b/ChangeLog index d2471435..400be193 100644 --- a/ChangeLog +++ b/ChangeLog @@ -5,7 +5,7 @@ - rewrite im_buildlut(), im_identity*(), im_maplut(), im_falsecolour(), im_gammacorrect(), im_histgr(), im_histcum(), im_histnorm(), im_heq(), im_histnD(), im_histindexed(), im_histspec(), im_invertlut(), im_lhisteq(), - im_stdif(), im_project(), im_tone_build*() as classes + im_stdif(), im_project(), im_profile(), im_tone_build*() as classes - vips_hist_local(), vips_stdif() do any number of bands - thin vips8 wrapper for im_histplot() - added vips_error_freeze() / vips_error_thaw() diff --git a/libvips/arithmetic/Makefile.am b/libvips/arithmetic/Makefile.am index 2b7d64c4..52222136 100644 --- a/libvips/arithmetic/Makefile.am +++ b/libvips/arithmetic/Makefile.am @@ -19,6 +19,7 @@ libarithmetic_la_SOURCES = \ hist_find_ndim.c \ hist_find_indexed.c \ project.c \ + profile.c \ subtract.c \ math.c \ arithmetic.c \ diff --git a/libvips/arithmetic/arithmetic.c b/libvips/arithmetic/arithmetic.c index 5b387e99..8dbdce7d 100644 --- a/libvips/arithmetic/arithmetic.c +++ b/libvips/arithmetic/arithmetic.c @@ -696,6 +696,7 @@ vips_arithmetic_operation_init( void ) extern GType vips_hist_find_ndim_get_type( void ); extern GType vips_hist_find_indexed_get_type( void ); extern GType vips_project_get_type( void ); + extern GType vips_profile_get_type( void ); extern GType vips_measure_get_type( void ); extern GType vips_round_get_type( void ); extern GType vips_relational_get_type( void ); @@ -729,6 +730,7 @@ vips_arithmetic_operation_init( void ) vips_hist_find_ndim_get_type(); vips_hist_find_indexed_get_type(); vips_project_get_type(); + vips_profile_get_type(); vips_measure_get_type(); vips_round_get_type(); vips_relational_get_type(); diff --git a/libvips/arithmetic/profile.c b/libvips/arithmetic/profile.c new file mode 100644 index 00000000..11cc7f53 --- /dev/null +++ b/libvips/arithmetic/profile.c @@ -0,0 +1,344 @@ +/* find image profiles + * + * 11/8/99 JC + * - from im_cntlines() + * 22/4/04 + * - now outputs horizontal/vertical image + * 9/11/10 + * - any image format, any number of bands + * - gtk-doc + * 21/9/13 + * - rewrite as a class + * - output h and v profile in one pass + * - partial + * - output is int rather than ushort + */ + +/* + + 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., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA + + */ + +/* + + These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk + + */ + +#ifdef HAVE_CONFIG_H +#include +#endif /*HAVE_CONFIG_H*/ +#include + +#include +#include +#include + +#include + +#include "statistic.h" + +struct _Edges; + +typedef struct { + /* Horizontal array: Ys of top-most non-zero pixel. + */ + int *column_edges; + + /* Vertical array: Xs of left-most non-zero pixel. + */ + int *row_edges; + +} Edges; + +typedef struct _VipsProfile { + VipsStatistic parent_instance; + + /* Main edge set. Threads accumulate to this. + */ + Edges *edges; + + /* Write profiles here. + */ + VipsImage *columns; + VipsImage *rows; + +} VipsProfile; + +typedef VipsStatisticClass VipsProfileClass; + +G_DEFINE_TYPE( VipsProfile, vips_profile, VIPS_TYPE_STATISTIC ); + +static Edges * +edges_new( VipsProfile *profile ) +{ + VipsStatistic *statistic = VIPS_STATISTIC( profile ); + VipsImage *in = statistic->ready; + + Edges *edges; + int i; + + if( !(edges = VIPS_NEW( profile, Edges )) ) + return( NULL ); + edges->column_edges = VIPS_ARRAY( profile, in->Xsize * in->Bands, int ); + edges->row_edges = VIPS_ARRAY( profile, in->Ysize * in->Bands, int ); + if( !edges->column_edges || + !edges->row_edges ) + return( NULL ); + + for( i = 0; i < in->Xsize * in->Bands; i++ ) + edges->column_edges[i] = in->Ysize; + for( i = 0; i < in->Ysize * in->Bands; i++ ) + edges->row_edges[i] = in->Xsize; + + return( edges ); +} + +static int +vips_profile_build( VipsObject *object ) +{ + VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object ); + VipsStatistic *statistic = VIPS_STATISTIC( object ); + VipsProfile *profile = (VipsProfile *) object; + + int y; + + if( statistic->in && + vips_check_noncomplex( class->nickname, statistic->in ) ) + return( -1 ); + + g_object_set( object, + "columns", vips_image_new(), + "rows", vips_image_new(), + NULL ); + + /* main edge set made on first thread start. + */ + + if( VIPS_OBJECT_CLASS( vips_profile_parent_class )->build( object ) ) + return( -1 ); + + /* Make the output image. + */ + if( vips_image_copy_fields( profile->columns, statistic->ready ) || + vips_image_copy_fields( profile->rows, statistic->ready ) ) + return( -1 ); + profile->columns->Ysize = 1; + profile->columns->BandFmt = VIPS_FORMAT_INT; + profile->columns->Type = VIPS_INTERPRETATION_HISTOGRAM; + profile->rows->Xsize = 1; + profile->rows->BandFmt = VIPS_FORMAT_INT; + profile->rows->Type = VIPS_INTERPRETATION_HISTOGRAM; + + if( vips_image_write_line( profile->columns, 0, + (VipsPel *) profile->edges->column_edges ) ) + return( -1 ); + for( y = 0; y < profile->rows->Ysize; y++ ) + if( vips_image_write_line( profile->rows, y, + (VipsPel *) profile->edges->row_edges + + y * VIPS_IMAGE_SIZEOF_PEL( profile->rows ) ) ) + return( -1 ); + + return( 0 ); +} + +/* New edge accumulator. + */ +static void * +vips_profile_start( VipsStatistic *statistic ) +{ + VipsProfile *profile = (VipsProfile *) statistic; + + /* Make the main hist, if necessary. + */ + if( !profile->edges ) + profile->edges = edges_new( profile ); + + return( (void *) edges_new( profile ) ); +} + +/* We do this a lot. + */ +#define MINBANG( V, C ) ((V) = VIPS_MIN( V, C )) + +/* Add a line of pixels. + */ +#define ADD_PIXELS( TYPE ) { \ + TYPE *p; \ + int *column_edges; \ + int *row_edges; \ + \ + p = (TYPE *) in; \ + column_edges = edges->column_edges + x * nb; \ + row_edges = edges->row_edges + y * nb; \ + for( i = 0; i < n; i++ ) { \ + for( j = 0; j < nb; j++ ) { \ + if( p[j] ) { \ + MINBANG( column_edges[j], y ); \ + MINBANG( row_edges[j], x + i ); \ + } \ + } \ + \ + p += nb; \ + column_edges += nb; \ + } \ +} + +/* Add a region to a profile. + */ +static int +vips_profile_scan( VipsStatistic *statistic, void *seq, + int x, int y, void *in, int n ) +{ + int nb = statistic->ready->Bands; + Edges *edges = (Edges *) seq; + int i, j; + + switch( statistic->ready->BandFmt ) { + case VIPS_FORMAT_UCHAR: + ADD_PIXELS( guchar ); + break; + + case VIPS_FORMAT_CHAR: + ADD_PIXELS( char ); + break; + + case VIPS_FORMAT_USHORT: + ADD_PIXELS( gushort ); + break; + + case VIPS_FORMAT_SHORT: + ADD_PIXELS( short ); + break; + + case VIPS_FORMAT_UINT: + ADD_PIXELS( guint ); + break; + + case VIPS_FORMAT_INT: + ADD_PIXELS( int ); + break; + + case VIPS_FORMAT_FLOAT: + ADD_PIXELS( float ); + break; + + case VIPS_FORMAT_DOUBLE: + ADD_PIXELS( double ); + break; + + default: + g_assert( 0 ); + } + + return( 0 ); +} + +/* Join a sub-profile onto the main profile. + */ +static int +vips_profile_stop( VipsStatistic *statistic, void *seq ) +{ + VipsProfile *profile = (VipsProfile *) statistic; + Edges *edges = profile->edges; + Edges *sub_edges = (Edges *) seq; + VipsImage *in = statistic->ready; + + int i; + + for( i = 0; i < in->Xsize * in->Bands; i++ ) + MINBANG( edges->column_edges[i], sub_edges->column_edges[i] ); + + for( i = 0; i < in->Ysize * in->Bands; i++ ) + MINBANG( edges->row_edges[i], sub_edges->row_edges[i] ); + + /* Blank out sub-profile to make sure we can't add it again. + */ + sub_edges->row_edges = NULL; + sub_edges->column_edges = NULL; + + return( 0 ); +} + +static void +vips_profile_class_init( VipsProfileClass *class ) +{ + GObjectClass *gobject_class = (GObjectClass *) class; + VipsObjectClass *object_class = (VipsObjectClass *) class; + VipsStatisticClass *sclass = VIPS_STATISTIC_CLASS( class ); + + gobject_class->set_property = vips_object_set_property; + gobject_class->get_property = vips_object_get_property; + + object_class->nickname = "profile"; + object_class->description = _( "find image profiles" ); + object_class->build = vips_profile_build; + + sclass->start = vips_profile_start; + sclass->scan = vips_profile_scan; + sclass->stop = vips_profile_stop; + + VIPS_ARG_IMAGE( class, "columns", 100, + _( "Columns" ), + _( "First non-zero pixel in column" ), + VIPS_ARGUMENT_REQUIRED_OUTPUT, + G_STRUCT_OFFSET( VipsProfile, columns ) ); + + VIPS_ARG_IMAGE( class, "rows", 101, + _( "Rows" ), + _( "First non-zero pixel in row" ), + VIPS_ARGUMENT_REQUIRED_OUTPUT, + G_STRUCT_OFFSET( VipsProfile, rows ) ); + +} + +static void +vips_profile_init( VipsProfile *profile ) +{ +} + +/** + * vips_profile: + * @in: input image + * @columns: distances from top edge + * @rows: distances from left edge + * @...: %NULL-terminated list of optional named arguments + * + * vips_profile() searches inward from the edge of @in and finds the + * first non-zero pixel. Pixels in @columns have the distance from the top edge + * to the first non-zero pixel in that column, @rows has the distance from the + * left edge to the first non-zero pixel in that row. + * + * See also: vips_project(), vips_hist_find(). + * + * Returns: 0 on success, -1 on error + */ +int +vips_profile( VipsImage *in, VipsImage **columns, VipsImage **rows, ... ) +{ + va_list ap; + int result; + + va_start( ap, rows ); + result = vips_call_split( "profile", ap, in, columns, rows ); + va_end( ap ); + + return( result ); +} + diff --git a/libvips/arithmetic/project.c b/libvips/arithmetic/project.c index ad98199a..c2159179 100644 --- a/libvips/arithmetic/project.c +++ b/libvips/arithmetic/project.c @@ -183,11 +183,11 @@ vips_project_start( VipsStatistic *statistic ) /* Add a line of pixels. */ #define ADD_PIXELS( OUT, IN ) { \ - OUT *row_sums = ((OUT *) project->hist->row_sums) + y * nb; \ + OUT *row_sums = ((OUT *) hist->row_sums) + y * nb; \ OUT *column_sums; \ IN *p; \ \ - column_sums = ((OUT *) project->hist->column_sums) + x * nb; \ + column_sums = ((OUT *) hist->column_sums) + x * nb; \ p = (IN *) in; \ for( i = 0; i < n; i++ ) { \ for( j = 0; j < nb; j++ ) { \ @@ -206,32 +206,13 @@ static int vips_project_scan( VipsStatistic *statistic, void *seq, int x, int y, void *in, int n ) { - VipsProject *project = (VipsProject *) statistic; int nb = statistic->ready->Bands; + Histogram *hist = (Histogram *) seq; int i, j; switch( statistic->ready->BandFmt ) { case VIPS_FORMAT_UCHAR: - //ADD_PIXELS( guint, guchar ); - - { - guint *row_sums = ((guint *) project->hist->row_sums) + y * nb; - guint *column_sums; - guchar *p; - - column_sums = ((guint *) project->hist->column_sums) + x * nb; - p = (guchar *) in; - for( i = 0; i < n; i++ ) { - for( j = 0; j < nb; j++ ) { - column_sums[j] += p[j]; - row_sums[j] += p[j]; - } - - p += nb; - column_sums += nb; - } -} - + ADD_PIXELS( guint, guchar ); break; case VIPS_FORMAT_CHAR: @@ -289,7 +270,6 @@ vips_project_stop( VipsStatistic *statistic, void *seq ) Histogram *sub_hist = (Histogram *) seq; VipsImage *in = statistic->ready; VipsBandFormat outfmt = vips_project_format_table[in->BandFmt]; - int psize = vips__image_sizeof_bandformat[outfmt] * in->Bands; int hsz = in->Xsize * in->Bands; int vsz = in->Ysize * in->Bands; @@ -320,8 +300,8 @@ vips_project_stop( VipsStatistic *statistic, void *seq ) /* Blank out sub-project to make sure we can't add it again. */ - memset( sub_hist->column_sums, 0, psize * in->Xsize ); - memset( sub_hist->row_sums, 0, psize * in->Ysize ); + sub_hist->column_sums = NULL; + sub_hist->row_sums = NULL; return( 0 ); } @@ -346,7 +326,7 @@ vips_project_class_init( VipsProjectClass *class ) VIPS_ARG_IMAGE( class, "columns", 100, _( "Columns" ), - _( "Sums of colums" ), + _( "Sums of columns" ), VIPS_ARGUMENT_REQUIRED_OUTPUT, G_STRUCT_OFFSET( VipsProject, columns ) ); @@ -366,8 +346,8 @@ vips_project_init( VipsProject *project ) /** * vips_project: * @in: input image - * @hout: sums of rows - * @vout: sums of columns + * @columns: sums of columns + * @rows: sums of rows * @...: %NULL-terminated list of optional named arguments * * Find the horizontal and vertical projections of an image, ie. the sum @@ -381,13 +361,13 @@ vips_project_init( VipsProject *project ) * Returns: 0 on success, -1 on error */ int -vips_project( VipsImage *in, VipsImage **hout, VipsImage **vout, ... ) +vips_project( VipsImage *in, VipsImage **columns, VipsImage **rows, ... ) { va_list ap; int result; - va_start( ap, vout ); - result = vips_call_split( "project", ap, in, hout, vout ); + va_start( ap, rows ); + result = vips_call_split( "project", ap, in, columns, rows ); va_end( ap ); return( result ); diff --git a/libvips/deprecated/vips7compat.c b/libvips/deprecated/vips7compat.c index 3fc527f9..41ee1a1e 100644 --- a/libvips/deprecated/vips7compat.c +++ b/libvips/deprecated/vips7compat.c @@ -3593,6 +3593,39 @@ im_project( IMAGE *in, IMAGE *hout, IMAGE *vout ) return( 0 ); } + +int +im_profile( IMAGE *in, IMAGE *out, int dir ) +{ + VipsImage *columns, *rows; + VipsImage *t1, *t2; + + if( vips_profile( in, &columns, &rows, NULL ) ) + return( -1 ); + if( dir == 0 ) { + t1 = columns; + g_object_unref( rows ); + } + else { + t1 = rows; + g_object_unref( columns ); + } + + if( vips_cast( t1, &t2, VIPS_FORMAT_USHORT, NULL ) ) { + g_object_unref( t1 ); + return( -1 ); + } + g_object_unref( t1 ); + + if( im_copy( t2, out ) ) { + g_object_unref( t2 ); + return( -1 ); + } + g_object_unref( t2 ); + + return( 0 ); +} + int im_hsp( IMAGE *in, IMAGE *ref, IMAGE *out ) { diff --git a/libvips/include/vips/arithmetic.h b/libvips/include/vips/arithmetic.h index 808c6c4f..9ff2d153 100644 --- a/libvips/include/vips/arithmetic.h +++ b/libvips/include/vips/arithmetic.h @@ -384,7 +384,9 @@ int vips_hist_find_ndim( VipsImage *in, VipsImage **out, ... ) int vips_hist_find_indexed( VipsImage *in, VipsImage *index, VipsImage **out, ... ) __attribute__((sentinel)); -int vips_project( VipsImage *in, VipsImage **hout, VipsImage **vout, ... ) +int vips_project( VipsImage *in, VipsImage **columns, VipsImage **rows, ... ) + __attribute__((sentinel)); +int vips_profile( VipsImage *in, VipsImage **columns, VipsImage **rows, ... ) __attribute__((sentinel)); #ifdef __cplusplus diff --git a/libvips/include/vips/morphology.h b/libvips/include/vips/morphology.h index 5306e56b..1e383097 100644 --- a/libvips/include/vips/morphology.h +++ b/libvips/include/vips/morphology.h @@ -47,7 +47,6 @@ int im_maxvalue( VipsImage **in, VipsImage *out, int n ); int im_cntlines( VipsImage *im, double *nolines, int flag ); int im_zerox( VipsImage *in, VipsImage *out, int sign ); -int im_profile( VipsImage *in, VipsImage *out, int dir ); int im_label_regions( VipsImage *test, VipsImage *mask, int *segments ); #ifdef __cplusplus diff --git a/libvips/include/vips/vips7compat.h b/libvips/include/vips/vips7compat.h index 04774bfe..38d94e85 100644 --- a/libvips/include/vips/vips7compat.h +++ b/libvips/include/vips/vips7compat.h @@ -870,6 +870,7 @@ int im_histnD( VipsImage *in, VipsImage *out, int bins ); int im_hist_indexed( VipsImage *index, VipsImage *value, VipsImage *out ); int im_histplot( VipsImage *in, VipsImage *out ); int im_project( VipsImage *in, VipsImage *hout, VipsImage *vout ); +int im_profile( IMAGE *in, IMAGE *out, int dir ); int im_hsp( VipsImage *in, VipsImage *ref, VipsImage *out ); int im_histspec( VipsImage *in, VipsImage *ref, VipsImage *out ); int im_lhisteq( VipsImage *in, VipsImage *out, int xwin, int ywin ); diff --git a/libvips/morphology/Makefile.am b/libvips/morphology/Makefile.am index 477c3bd5..e4b7e75b 100644 --- a/libvips/morphology/Makefile.am +++ b/libvips/morphology/Makefile.am @@ -7,7 +7,6 @@ libmorphology_la_SOURCES = \ im_rank_image.c \ im_zerox.c \ morph_dispatch.c \ - im_label_regions.c \ - im_profile.c + im_label_regions.c AM_CPPFLAGS = -I${top_srcdir}/libvips/include @VIPS_CFLAGS@ @VIPS_INCLUDES@ diff --git a/libvips/morphology/im_profile.c b/libvips/morphology/im_profile.c deleted file mode 100644 index 3f5913b4..00000000 --- a/libvips/morphology/im_profile.c +++ /dev/null @@ -1,173 +0,0 @@ -/* find image profiles - * - * 11/8/99 JC - * - from im_cntlines() - * 22/4/04 - * - now outputs horizontal/vertical image - * 9/11/10 - * - any image format, any number of bands - * - gtk-doc - */ - -/* - - TODO - - - walk a region over the image and avoid wio - - */ - -/* - - 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., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - - */ - -/* - - These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk - - */ - -#ifdef HAVE_CONFIG_H -#include -#endif /*HAVE_CONFIG_H*/ -#include - -#include - -/** - * im_profile: - * @in: input image - * @out: output image - * @dir: search direction - * - * im_profile() searches inward from the edge of @in and finds the - * first non-zero pixel. It outputs an image containing a list of the offsets - * for each row or column. - * - * If @dir == 0, then im_profile() searches down from the top edge, writing an - * image as wide as the input image, but only 1 pixel high, containing the - * number of pixels down to the first non-zero pixel for each column of input - * pixels. - * - * If @dir == 1, then im_profile() searches across from the left edge, - * writing an image as high as the input image, but only 1 pixel wide, - * containing the number of pixels across to the - * first non-zero pixel for each row of input pixels. - * - * See also: im_cntlines(). - * - * Returns: 0 on success, -1 on error - */ -int -im_profile( IMAGE *in, IMAGE *out, int dir ) -{ - int sz; - unsigned short *buf; - int x, y; - - /* If in is not uchar, do (!=0) to make a uchar image. - */ - if( in->BandFmt != IM_BANDFMT_UCHAR ) { - IMAGE *t; - - if( !(t = im_open_local( out, "im_profile", "p" )) || - im_notequalconst( in, t, 0 ) ) - return( -1 ); - - in = t; - } - - /* Check im. - */ - if( im_iocheck( in, out ) || - im_check_uncoded( "im_profile", in ) || - im_check_format( "im_profile", in, IM_BANDFMT_UCHAR ) ) - return( -1 ); - if( dir != 0 && - dir != 1 ) { - im_error( "im_profile", "%s", _( "dir not 0 or 1" ) ); - return( -1 ); - } - - if( im_cp_desc( out, in ) ) - return( -1 ); - out->Type = IM_TYPE_HISTOGRAM; - if( dir == 0 ) { - out->Xsize = in->Xsize; - out->Ysize = 1; - } - else { - out->Xsize = 1; - out->Ysize = in->Ysize; - } - out->BandFmt = IM_BANDFMT_USHORT; - if( im_setupout( out ) ) - return( -1 ); - sz = IM_IMAGE_N_ELEMENTS( out ); - if( !(buf = IM_ARRAY( out, sz, unsigned short )) ) - return( -1 ); - - if( dir == 0 ) { - /* Find vertical lines. - */ - for( x = 0; x < sz; x++ ) { - VipsPel *p = IM_IMAGE_ADDR( in, 0, 0 ) + x; - int lsk = IM_IMAGE_SIZEOF_LINE( in ); - - for( y = 0; y < in->Ysize; y++ ) { - if( *p ) - break; - p += lsk; - } - - buf[x] = y; - } - - if( im_writeline( 0, out, (VipsPel *) buf ) ) - return( -1 ); - } - else { - /* Search horizontal lines. - */ - for( y = 0; y < in->Ysize; y++ ) { - VipsPel *p = IM_IMAGE_ADDR( in, 0, y ); - - int b; - - for( b = 0; b < in->Bands; b++ ) { - VipsPel *p1; - - p1 = p + b; - for( x = 0; x < in->Xsize; x++ ) { - if( *p1 ) - break; - p1 += in->Bands; - } - - buf[b] = x; - } - - if( im_writeline( y, out, (VipsPel *) buf ) ) - return( -1 ); - } - } - - return( 0 ); -}