redo im_grid() as a class

This commit is contained in:
John Cupitt 2013-05-30 15:52:36 +01:00
parent 130aaf1fd0
commit e0951c223b
8 changed files with 62 additions and 244 deletions

View File

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

View File

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

View File

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

View File

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

View File

@ -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 <config.h>
#endif /*HAVE_CONFIG_H*/
#include <vips/intl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <vips/vips.h>
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 );
}

View File

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

View File

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

View File

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