From e0951c223b7c232fccf08b85545b51d19562a8a0 Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Thu, 30 May 2013 15:52:36 +0100 Subject: [PATCH] redo im_grid() as a class --- ChangeLog | 2 +- libvips/conversion/Makefile.am | 2 +- libvips/conversion/conversion.c | 3 +- libvips/conversion/grid.c | 82 ++++++------ libvips/conversion/im_grid.c | 196 ----------------------------- libvips/deprecated/vips7compat.c | 16 +++ libvips/include/vips/conversion.h | 4 +- libvips/include/vips/vips7compat.h | 1 + 8 files changed, 62 insertions(+), 244 deletions(-) delete mode 100644 libvips/conversion/im_grid.c diff --git a/ChangeLog b/ChangeLog index 8cee8982..6bf62058 100644 --- a/ChangeLog +++ b/ChangeLog @@ -3,7 +3,7 @@ - turn off caching for im_copy()/vips_copy(), we use copy to stop sharing, and it's cheap so caching doesn't help anyway - auto rshift down to 8 bits on save, if necessary -- im_gaussnoise(), im_copy_file() redone as a class +- im_gaussnoise(), im_copy_file(), im_grid() redone as classes - add --angle option to dzsave 14/5/13 started 7.32.4 diff --git a/libvips/conversion/Makefile.am b/libvips/conversion/Makefile.am index 4f801a41..de5e1de3 100644 --- a/libvips/conversion/Makefile.am +++ b/libvips/conversion/Makefile.am @@ -28,7 +28,7 @@ libconversion_la_SOURCES = \ conver_dispatch.c \ im_falsecolour.c \ im_msb.c \ - im_grid.c \ + grid.c \ im_scale.c \ im_scaleps.c \ im_subsample.c \ diff --git a/libvips/conversion/conversion.c b/libvips/conversion/conversion.c index b5653fb6..670947d3 100644 --- a/libvips/conversion/conversion.c +++ b/libvips/conversion/conversion.c @@ -126,6 +126,7 @@ vips_conversion_operation_init( void ) extern GType vips_flatten_get_type( void ); extern GType vips_bandbool_get_type( void ); extern GType vips_gaussnoise_get_type( void ); + extern GType vips_grid_get_type( void ); vips_copy_get_type(); vips_tile_cache_get_type(); @@ -149,6 +150,7 @@ vips_conversion_operation_init( void ) vips_flatten_get_type(); vips_bandbool_get_type(); vips_gaussnoise_get_type(); + vips_grid_get_type(); } /* The common part of most binary conversion @@ -160,7 +162,6 @@ vips_conversion_operation_init( void ) * - make an input array * - return the matched images in vec[0] and vec[1] * - * * A left-over, remove soon. */ IMAGE ** diff --git a/libvips/conversion/grid.c b/libvips/conversion/grid.c index c89c4a91..46cd17ad 100644 --- a/libvips/conversion/grid.c +++ b/libvips/conversion/grid.c @@ -67,13 +67,14 @@ static int vips_grid_gen( VipsRegion *or, void *vseq, void *a, void *b, gboolean *stop ) { - REGION *ir = (REGION *) seq; - Grid *grid = (Grid *) b; - Rect *r = &or->valid; + VipsRegion *ir = (VipsRegion *) vseq; + VipsGrid *grid = (VipsGrid *) b; + VipsRect *r = &or->valid; int twidth = grid->in->Xsize; int theight = grid->tile_height; + int x, y; - Rect tile; + VipsRect tile; /* Find top left of tiles we need. */ @@ -89,7 +90,7 @@ vips_grid_gen( VipsRegion *or, void *vseq, void *a, void *b, /* If the request fits inside a single tile, we can just pointer-copy. */ - if( im_rect_includesrect( &tile, r ) ) { + if( vips_rect_includesrect( &tile, r ) ) { Rect irect; /* Translate request to input space. @@ -99,17 +100,17 @@ vips_grid_gen( VipsRegion *or, void *vseq, void *a, void *b, irect.top -= ys; irect.top += grid->across * ys + theight * (xs / twidth); - if( im_prepare( ir, &irect ) || - im_region_region( or, ir, r, irect.left, irect.top ) ) + if( vips_region_prepare( ir, &irect ) || + vips_region_region( or, ir, r, irect.left, irect.top ) ) return( -1 ); return( 0 ); } - for( y = ys; y < IM_RECT_BOTTOM( r ); y += theight ) - for( x = xs; x < IM_RECT_RIGHT( r ); x += twidth ) { - Rect paint; - Rect input; + for( y = ys; y < VIPS_RECT_BOTTOM( r ); y += theight ) + for( x = xs; x < VIPS_RECT_RIGHT( r ); x += twidth ) { + VipsRect paint; + VipsRect input; /* Whole tile at x, y */ @@ -121,9 +122,9 @@ vips_grid_gen( VipsRegion *or, void *vseq, void *a, void *b, /* Which parts touch the area of the output we are * building. */ - im_rect_intersectrect( &tile, r, &paint ); + vips_rect_intersectrect( &tile, r, &paint ); - g_assert( !im_rect_isempty( &paint ) ); + g_assert( !vips_rect_isempty( &paint ) ); /* Translate back to ir coordinates. */ @@ -134,7 +135,7 @@ vips_grid_gen( VipsRegion *or, void *vseq, void *a, void *b, /* Render into or. */ - if( im_prepare_to( ir, or, &input, + if( vips_region_prepare_to( ir, or, &input, paint.left, paint.top ) ) return( -1 ); } @@ -149,8 +150,6 @@ vips_grid_build( VipsObject *object ) VipsConversion *conversion = VIPS_CONVERSION( object ); VipsGrid *grid = (VipsGrid *) object; - int n_tiles; - if( VIPS_OBJECT_CLASS( vips_grid_parent_class )->build( object ) ) return( -1 ); @@ -158,21 +157,9 @@ vips_grid_build( VipsObject *object ) vips_image_pio_input( grid->in ) ) return( -1 ); - !vips_object_argument_isset( object, "background" ) ) { - - if( grid->in->Ysize % grid->tile_height != 0 ) { - vips_error( class->nickname, "%s", _( "geometry" ) ); - return( -1 ); - } - n_tiles = grid->in->Ysize / grid->tile_height; - - if( grid->across <= 0 || - grid->down <= 0 ) { - vips_error( class->nickname, "%s", _( "bad parameters" ) ); - return( -1 ); - } if( grid->in->Ysize % grid->tile_height != 0 || - grid->in->Ysize / grid->tile_height != grid->across * grid->down ) { + grid->in->Ysize / grid->tile_height != + grid->across * grid->down ) { vips_error( class->nickname, "%s", _( "bad grid geometry" ) ); return( -1 ); } @@ -183,8 +170,8 @@ vips_grid_build( VipsObject *object ) */ vips_demand_hint( conversion->out, VIPS_DEMAND_STYLE_SMALLTILE, grid->in, NULL ); - out->Xsize = grid->in->Xsize * grid->across; - out->Ysize = grid->tile_height * grid->down; + conversion->out->Xsize = grid->in->Xsize * grid->across; + conversion->out->Ysize = grid->tile_height * grid->down; if( vips_image_generate( conversion->out, vips_start_one, vips_grid_gen, vips_stop_one, @@ -199,9 +186,6 @@ vips_grid_class_init( VipsGridClass *class ) { GObjectClass *gobject_class = G_OBJECT_CLASS( class ); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS( class ); - VipsOperationClass *operation_class = VIPS_OPERATION_CLASS( class ); - - VIPS_DEBUG_MSG( "vips_grid_class_init\n" ); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; @@ -223,13 +207,20 @@ vips_grid_class_init( VipsGridClass *class ) G_STRUCT_OFFSET( VipsGrid, tile_height ), 1, 10000000, 128 ); - VIPS_ARG_INT( class, "across", 3, + VIPS_ARG_INT( class, "across", 4, _( "Across" ), _( "number of tiles across" ), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET( VipsGrid, across ), 1, 10000000, 1 ); + VIPS_ARG_INT( class, "down", 5, + _( "Down" ), + _( "number of tiles down" ), + VIPS_ARGUMENT_REQUIRED_INPUT, + G_STRUCT_OFFSET( VipsGrid, down ), + 1, 10000000, 1 ); + } static void @@ -244,13 +235,10 @@ vips_grid_init( VipsGrid *grid ) * vips_grid: * @in: input image * @out: output image - * @...: %NULL-terminated list of optional named arguments - * - * Optional args: - * * @tile_height: chop into tiles this high * @across: tiles across * @down: tiles down + * @...: %NULL-terminated list of optional named arguments * * Chop a tall thin image up into a set of tiles, lay the tiles out in a grid. * @@ -260,18 +248,24 @@ vips_grid_init( VipsGrid *grid ) * pixels high and the width of @in. The tiles are then rearranged into a grid * @across tiles across and @down tiles down in row-major order. * - * See also: im_embed(), im_insert(), im_lrjoin(). + * Supplying @tile_height, @across and @down is not strictly necessary, we + * only really need two of these. Requiring three is a double-check that the + * image has the expected geometry. + * + * See also: vips_embed(), vips_insert(), vips_join(). * * Returns: 0 on success, -1 on error */ int -vips_grid( VipsImage *in, VipsImage **out, ... ) +vips_grid( VipsImage *in, VipsImage **out, + int tile_height, int across, int down, ... ) { va_list ap; int result; - va_start( ap, format ); - result = vips_call( "grid", in, out, ap ); + va_start( ap, down ); + result = vips_call_split( "grid", ap, + in, out, tile_height, across, down ); va_end( ap ); return( result ); diff --git a/libvips/conversion/im_grid.c b/libvips/conversion/im_grid.c deleted file mode 100644 index d4186506..00000000 --- a/libvips/conversion/im_grid.c +++ /dev/null @@ -1,196 +0,0 @@ -/* im_grid - * - * 4/8/05 - * 7/9/05 - * - oops, clipping was wrong - * 30/1/10 - * - gtkdoc - * - small cleanups - */ - -/* - - 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 - -typedef struct _Grid { - IMAGE *in; - IMAGE *out; - int tile_height; - int across; - int down; -} Grid; - -static int -grid_gen( REGION *or, void *seq, void *a, void *b ) -{ - REGION *ir = (REGION *) seq; - Grid *grid = (Grid *) b; - Rect *r = &or->valid; - int twidth = grid->in->Xsize; - int theight = grid->tile_height; - int x, y; - Rect tile; - - /* Find top left of tiles we need. - */ - int xs = (r->left / twidth) * twidth; - int ys = (r->top / theight) * theight; - - /* The tile enclosing the top-left corner of the requested area. - */ - tile.left = xs; - tile.top = ys; - tile.width = twidth; - tile.height = theight; - - /* If the request fits inside a single tile, we can just pointer-copy. - */ - if( im_rect_includesrect( &tile, r ) ) { - Rect irect; - - /* Translate request to input space. - */ - irect = *r; - irect.left -= xs; - irect.top -= ys; - irect.top += grid->across * ys + theight * (xs / twidth); - - if( im_prepare( ir, &irect ) || - im_region_region( or, ir, r, irect.left, irect.top ) ) - return( -1 ); - - return( 0 ); - } - - for( y = ys; y < IM_RECT_BOTTOM( r ); y += theight ) - for( x = xs; x < IM_RECT_RIGHT( r ); x += twidth ) { - Rect paint; - Rect input; - - /* Whole tile at x, y - */ - tile.left = x; - tile.top = y; - tile.width = twidth; - tile.height = theight; - - /* Which parts touch the area of the output we are - * building. - */ - im_rect_intersectrect( &tile, r, &paint ); - - g_assert( !im_rect_isempty( &paint ) ); - - /* Translate back to ir coordinates. - */ - input = paint; - input.left -= x; - input.top -= y; - input.top += grid->across * y + theight * (x / twidth); - - /* Render into or. - */ - if( im_prepare_to( ir, or, &input, - paint.left, paint.top ) ) - return( -1 ); - } - - return( 0 ); -} - -/** - * im_grid: - * @in: input image - * @out: output image - * @tile_height: chop into tiles this high - * @across: tiles across - * @down: tiles down - * - * Chop a tall thin image up into a set of tiles, lay the tiles out in a grid. - * - * The input image should be a very tall, thin image containing a list of - * smaller images. Volumetric or time-sequence images are often laid out like - * this. This image is chopped into a series of tiles, each @tile_height - * pixels high and the width of @in. The tiles are then rearranged into a grid - * @across tiles across and @down tiles down in row-major order. - * - * See also: im_embed(), im_insert(), im_lrjoin(). - * - * Returns: 0 on success, -1 on error - */ -int -im_grid( IMAGE *in, IMAGE *out, int tile_height, int across, int down ) -{ - Grid *grid = IM_NEW( out, Grid ); - - if( !grid || - im_piocheck( in, out ) || - im_check_coding_known( "im_grid", in ) ) - return( -1 ); - if( across <= 0 || down <= 0 ) { - im_error( "im_grid", "%s", _( "bad parameters" ) ); - return( -1 ); - } - if( in->Ysize % tile_height != 0 || - in->Ysize / tile_height != across * down ) { - im_error( "im_grid", "%s", _( "bad grid geometry" ) ); - return( -1 ); - } - - grid->in = in; - grid->out = out; - grid->tile_height = tile_height; - grid->across = across; - grid->down = down; - - if( im_cp_desc( out, in ) ) - return( -1 ); - out->Xsize = in->Xsize * across; - out->Ysize = tile_height * down; - - /* We can render small tiles with pointer copies. - */ - if( im_demand_hint( out, IM_SMALLTILE, in, NULL ) ) - return( -1 ); - - if( im_generate( out, - im_start_one, grid_gen, im_stop_one, in, grid ) ) - return( -1 ); - - return( 0 ); -} - diff --git a/libvips/deprecated/vips7compat.c b/libvips/deprecated/vips7compat.c index 1e7569e4..59874100 100644 --- a/libvips/deprecated/vips7compat.c +++ b/libvips/deprecated/vips7compat.c @@ -1495,6 +1495,22 @@ im_gaussnoise( IMAGE *out, int x, int y, double mean, double sigma ) return( 0 ); } +int +im_grid( VipsImage *in, VipsImage *out, int tile_height, int across, int down ) +{ + VipsImage *t; + + if( vips_grid( in, &t, tile_height, across, down, NULL ) ) + return( -1 ); + if( vips_image_write( t, out ) ) { + g_object_unref( t ); + return( -1 ); + } + g_object_unref( t ); + + return( 0 ); +} + static int vips__math( VipsImage *in, VipsImage *out, VipsOperationMath math ) { diff --git a/libvips/include/vips/conversion.h b/libvips/include/vips/conversion.h index cb8b6419..d5105e3b 100644 --- a/libvips/include/vips/conversion.h +++ b/libvips/include/vips/conversion.h @@ -188,6 +188,9 @@ int vips_extract_band( VipsImage *input, VipsImage **output, int band, ... ) __attribute__((sentinel)); int vips_replicate( VipsImage *in, VipsImage **out, int across, int down, ... ) __attribute__((sentinel)); +int vips_grid( VipsImage *in, VipsImage **out, + int tile_height, int across, int down, ... ) + __attribute__((sentinel)); int vips_cast( VipsImage *in, VipsImage **out, VipsBandFormat format, ... ) __attribute__((sentinel)); @@ -261,7 +264,6 @@ int im_text( VipsImage *out, const char *text, const char *font, int width, int alignment, int dpi ); 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 ); int im_subsample( VipsImage *in, VipsImage *out, int xshrink, int yshrink ); diff --git a/libvips/include/vips/vips7compat.h b/libvips/include/vips/vips7compat.h index 4235d263..293a1b5b 100644 --- a/libvips/include/vips/vips7compat.h +++ b/libvips/include/vips/vips7compat.h @@ -710,6 +710,7 @@ int im_bandjoin( VipsImage *in1, VipsImage *in2, VipsImage *out ); int im_gbandjoin( VipsImage **in, VipsImage *out, int n ); int im_black( VipsImage *out, int x, int y, int bands ); int im_gaussnoise( VipsImage *out, int x, int y, double mean, double sigma ); +int im_grid( VipsImage *in, VipsImage *out, int tile_height, int across, int down ); int im_c2amph( VipsImage *in, VipsImage *out ); int im_c2rect( VipsImage *in, VipsImage *out );