rewrite im_replicate() as a class
This commit is contained in:
parent
2bfe021088
commit
014763a845
@ -2,7 +2,8 @@
|
||||
- version bump for new dev cycle
|
||||
- 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_tbjoin(), im_extract_area(), im_extract_bands(), im_extract_areabands(),
|
||||
im_replicate()
|
||||
redone as classes
|
||||
- added VIPS_ARGUMENT_APPEND to help control arg ordering
|
||||
- generate has a 'stop' param to signal successful early termination
|
||||
|
18
TODO
18
TODO
@ -1,3 +1,12 @@
|
||||
|
||||
- do clip etc. in new style, good to get everything that VipsAdd uses in
|
||||
the new stack
|
||||
|
||||
insert* needs clip, lintra_vec
|
||||
|
||||
|
||||
|
||||
|
||||
- bandalike: consider RGB + RGBA ... we should bandup by adding a black band
|
||||
|
||||
(or white?? unclear)
|
||||
@ -76,15 +85,6 @@
|
||||
|
||||
|
||||
|
||||
- do clip etc. in new style, good to get everything that VipsAdd uses in
|
||||
the new stack
|
||||
|
||||
embed needs flip* *join extract_area replicate insert
|
||||
|
||||
*join needs insert too
|
||||
|
||||
insert* needs clip, lintra_vec
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -9,6 +9,7 @@ libconversion_la_SOURCES = \
|
||||
insert.c \
|
||||
join.c \
|
||||
extract.c \
|
||||
replicate.c \
|
||||
conver_dispatch.c \
|
||||
im_black.c \
|
||||
im_c2amph.c \
|
||||
@ -21,7 +22,6 @@ libconversion_la_SOURCES = \
|
||||
im_gbandjoin.c \
|
||||
im_mask2vips.c \
|
||||
im_msb.c \
|
||||
im_replicate.c \
|
||||
im_grid.c \
|
||||
im_ri2c.c \
|
||||
im_rot180.c \
|
||||
|
@ -109,6 +109,7 @@ vips_conversion_operation_init( void )
|
||||
extern GType vips_join_get_type( void );
|
||||
extern GType vips_extract_area_get_type( void );
|
||||
extern GType vips_extract_band_get_type( void );
|
||||
extern GType vips_replicate_get_type( void );
|
||||
|
||||
vips_copy_get_type();
|
||||
vips_embed_get_type();
|
||||
@ -117,5 +118,6 @@ vips_conversion_operation_init( void )
|
||||
vips_join_get_type();
|
||||
vips_extract_area_get_type();
|
||||
vips_extract_band_get_type();
|
||||
vips_replicate_get_type();
|
||||
}
|
||||
|
||||
|
@ -81,11 +81,11 @@
|
||||
* @x: place @in at this x position in @out
|
||||
* @y: place @in at this y position in @out
|
||||
*
|
||||
* The opposite of im_extract(): embed @in within an image of size @width by
|
||||
* @height at position @x, @y. @extend
|
||||
* The opposite of #VipsExtractArea: embed @in within an image of size @width
|
||||
* by @height at position @x, @y. @extend
|
||||
* controls what appears in the new pels, see #VipsExtend.
|
||||
*
|
||||
* See also: im_extract_area(), im_insert().
|
||||
* See also: #VipsExtractArea, #VipsInsert.
|
||||
*
|
||||
* Returns: 0 on success, -1 on error.
|
||||
*/
|
||||
@ -325,6 +325,76 @@ vips_embed_gen( VipsRegion *or, void *seq, void *a, void *b, gboolean *stop )
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
static int
|
||||
vips_embed_repeat( VipsPool *pool, VipsImage *input, VipsImage **output,
|
||||
int x, int y, int width, int height )
|
||||
{
|
||||
VipsPoolContext *context = vips_pool_context_new( pool );
|
||||
|
||||
/* Clock arithmetic: we want negative x/y to wrap around
|
||||
* nicely.
|
||||
*/
|
||||
const int nx = x < 0 ?
|
||||
-x % input->Xsize : input->Xsize - x % input->Xsize;
|
||||
const int ny = y < 0 ?
|
||||
-y % input->Ysize : input->Ysize - y % input->Ysize;
|
||||
|
||||
if(
|
||||
vips_replicate( input, &VIPS_VI( 1 ),
|
||||
width / input->Xsize + 2,
|
||||
height / input->Ysize + 2, NULL ) ||
|
||||
vips_extract_area( VIPS_VI( 1 ), output,
|
||||
nx, ny, width, height, NULL ) )
|
||||
return( -1 );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
static int
|
||||
vips_embed_mirror( VipsPool *pool, VipsImage *input, VipsImage **output,
|
||||
int x, int y, int width, int height )
|
||||
{
|
||||
VipsPoolContext *context = vips_pool_context_new( pool );
|
||||
|
||||
/* As repeat, but the tiles are twice the size because of
|
||||
* mirroring.
|
||||
*/
|
||||
const int w2 = input->Xsize * 2;
|
||||
const int h2 = input->Ysize * 2;
|
||||
|
||||
const int nx = x < 0 ? -x % w2 : w2 - x % w2;
|
||||
const int ny = y < 0 ? -y % h2 : h2 - y % h2;
|
||||
|
||||
if(
|
||||
/* Make a 2x2 mirror tile.
|
||||
*/
|
||||
vips_flip( input, &VIPS_VI( 1 ),
|
||||
VIPS_DIRECTION_HORIZONTAL, NULL ) ||
|
||||
vips_join( input, VIPS_VI( 1 ), &VIPS_VI( 2 ),
|
||||
VIPS_DIRECTION_HORIZONTAL, NULL ) ||
|
||||
vips_flip( VIPS_VI( 2 ), &VIPS_VI( 3 ),
|
||||
VIPS_DIRECTION_VERTICAL, NULL ) ||
|
||||
vips_join( VIPS_VI( 2 ), VIPS_VI( 3 ), &VIPS_VI( 4 ),
|
||||
VIPS_DIRECTION_VERTICAL, NULL ) ||
|
||||
|
||||
/* Repeat, then cut out the centre.
|
||||
*/
|
||||
vips_replicate( VIPS_VI( 4 ), &VIPS_VI( 5 ),
|
||||
width / VIPS_VI( 4 )->Xsize + 2,
|
||||
height / VIPS_VI( 4 )->Ysize + 2, NULL ) ||
|
||||
vips_extract_area( VIPS_VI( 5 ), &VIPS_VI( 6 ),
|
||||
nx, ny, width, height, NULL ) ||
|
||||
|
||||
/* Overwrite the centre with the input, much faster
|
||||
* for centre pixels.
|
||||
*/
|
||||
vips_insert( VIPS_VI( 6 ), input, output,
|
||||
x, y, NULL ) )
|
||||
return( -1 );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
static int
|
||||
vips_embed_build( VipsObject *object )
|
||||
{
|
||||
@ -332,6 +402,7 @@ vips_embed_build( VipsObject *object )
|
||||
VipsEmbed *embed = (VipsEmbed *) object;
|
||||
|
||||
VipsRect want;
|
||||
VipsPool *pool;
|
||||
|
||||
if( VIPS_OBJECT_CLASS( vips_embed_parent_class )->build( object ) )
|
||||
return( -1 );
|
||||
@ -352,87 +423,30 @@ vips_embed_build( VipsObject *object )
|
||||
embed->height == embed->input->Ysize )
|
||||
return( vips_image_write( embed->input, conversion->output ) );
|
||||
|
||||
pool = vips_pool_new( "VipsEmbed" );
|
||||
vips_object_local( object, pool );
|
||||
|
||||
switch( embed->extend ) {
|
||||
case VIPS_EXTEND_REPEAT:
|
||||
{
|
||||
/* Clock arithmetic: we want negative x/y to wrap around
|
||||
* nicely.
|
||||
*/
|
||||
const int nx = embed->x < 0 ?
|
||||
-embed->x % embed->input->Xsize :
|
||||
embed->input->Xsize - embed->x % embed->input->Xsize;
|
||||
const int ny = embed->y < 0 ?
|
||||
-embed->y % embed->input->Ysize :
|
||||
embed->input->Ysize - embed->y % embed->input->Ysize;
|
||||
VipsPoolContext *context = vips_pool_context_new( pool );
|
||||
|
||||
VipsImage *t[1];
|
||||
|
||||
if( im_open_local_array( conversion->output,
|
||||
t, 1, "embed-type2", "p" ) ||
|
||||
im_replicate( embed->input, t[0],
|
||||
embed->width / embed->input->Xsize + 2,
|
||||
embed->height / embed->input->Ysize + 2 ) ||
|
||||
im_extract_area( t[0], conversion->output,
|
||||
nx, ny, embed->width, embed->height ) )
|
||||
if( vips_embed_repeat( pool, embed->input, &VIPS_VI( 1 ),
|
||||
embed->x, embed->y, embed->width, embed->height ) ||
|
||||
vips_image_write( VIPS_VI( 1 ), conversion->output ) )
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case VIPS_EXTEND_MIRROR:
|
||||
{
|
||||
/* As case 2, but the tiles are twice the size because of
|
||||
* mirroring.
|
||||
*/
|
||||
const int w2 = embed->input->Xsize * 2;
|
||||
const int h2 = embed->input->Ysize * 2;
|
||||
VipsPoolContext *context = vips_pool_context_new( pool );
|
||||
|
||||
const int nx = embed->x < 0 ?
|
||||
-embed->x % w2 : w2 - embed->x % w2;
|
||||
const int ny = embed->y < 0 ?
|
||||
-embed->y % h2 : h2 - embed->y % h2;
|
||||
|
||||
VipsImage *t[7];
|
||||
|
||||
if( im_open_local_array( conversion->output,
|
||||
t, 7, "embed-type3", "p" ) ||
|
||||
/* Cache the edges of in, since we may well be reusing
|
||||
* them repeatedly. Will only help for tiny borders
|
||||
* (up to 20 pixels?), but that's our typical case
|
||||
* with im_conv() etc.
|
||||
im_cache( in, t[0], IM__TILE_WIDTH, IM__TILE_HEIGHT,
|
||||
3 * (in->Xsize / IM__TILE_WIDTH + 1) +
|
||||
3 * (in->Ysize / IM__TILE_HEIGHT + 1) ) ||
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
FIXME ... alternatively, don't cache, hmm,
|
||||
need to time this for typical cases
|
||||
|
||||
*/
|
||||
im_copy( embed->input, t[0] ) ||
|
||||
|
||||
/* Make a 2x2 mirror tile.
|
||||
*/
|
||||
im_fliphor( t[0], t[1] ) ||
|
||||
im_lrjoin( t[0], t[1], t[2] ) ||
|
||||
im_flipver( t[2], t[3] ) ||
|
||||
im_tbjoin( t[2], t[3], t[4] ) ||
|
||||
|
||||
/* Repeat, then cut out the centre.
|
||||
*/
|
||||
im_replicate( t[4], t[5],
|
||||
embed->width / t[4]->Xsize + 2,
|
||||
embed->height / t[4]->Ysize + 2 ) ||
|
||||
im_extract_area( t[5], t[6], nx, ny,
|
||||
embed->width, embed->height ) ||
|
||||
|
||||
/* Overwrite the centre with the input, much faster
|
||||
* for centre pixels.
|
||||
*/
|
||||
im_insert_noexpand( t[6], embed->input,
|
||||
conversion->output, embed->x, embed->y ) )
|
||||
return( -1 );
|
||||
if( vips_embed_mirror( pool, embed->input, &VIPS_VI( 1 ),
|
||||
embed->x, embed->y, embed->width, embed->height ) ||
|
||||
vips_image_write( VIPS_VI( 1 ), conversion->output ) )
|
||||
return( -1 );
|
||||
}
|
||||
break;
|
||||
|
||||
@ -461,7 +475,7 @@ vips_embed_build( VipsObject *object )
|
||||
want.top = embed->y;
|
||||
want.width = embed->input->Xsize;
|
||||
want.height = embed->input->Ysize;
|
||||
im_rect_intersectrect( &want, &embed->rout, &embed->rsub );
|
||||
vips_rect_intersectrect( &want, &embed->rout, &embed->rsub );
|
||||
|
||||
/* FIXME ... actually, it can't. embed_find_edge() will fail
|
||||
* if rsub is empty. Make this more general at some point
|
||||
|
@ -66,7 +66,7 @@
|
||||
|
||||
/**
|
||||
* VipsFlip:
|
||||
* @in: input image
|
||||
* @input: input image
|
||||
* @output: output image
|
||||
* @direction: flip horizontally or vertically
|
||||
*
|
||||
@ -250,7 +250,7 @@ vips_flip_class_init( VipsFlipClass *class )
|
||||
vobject_class->description = _( "flip an image" );
|
||||
vobject_class->build = vips_flip_build;
|
||||
|
||||
VIPS_ARG_IMAGE( class, "in", 1,
|
||||
VIPS_ARG_IMAGE( class, "input", 1,
|
||||
_( "Input" ),
|
||||
_( "Input image" ),
|
||||
VIPS_ARGUMENT_REQUIRED_INPUT,
|
||||
|
@ -1,167 +0,0 @@
|
||||
/* replicate an image x times horizontally and vertically
|
||||
*
|
||||
* JC, 30 sep 03
|
||||
*
|
||||
* 15/4/04
|
||||
* - some optimisations for some cases
|
||||
* 1/2/10
|
||||
* - gtkdoc
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
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
|
||||
|
||||
*/
|
||||
|
||||
/* Turn on debugging output.
|
||||
#define DEBUG
|
||||
#define DEBUG_PAINT
|
||||
#define DEBUG_MAKE
|
||||
*/
|
||||
|
||||
#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>
|
||||
|
||||
static int
|
||||
replicate_gen( REGION *or, void *seq, void *a, void *b )
|
||||
{
|
||||
REGION *ir = (REGION *) seq;
|
||||
IMAGE *in = (IMAGE *) a;
|
||||
Rect *r = &or->valid;
|
||||
int twidth = in->Xsize;
|
||||
int theight = in->Ysize;
|
||||
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;
|
||||
if( im_prepare( ir, &irect ) )
|
||||
return( -1 );
|
||||
|
||||
if( 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;
|
||||
|
||||
/* 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 );
|
||||
|
||||
/* Translate back to ir coordinates.
|
||||
*/
|
||||
paint.left -= x;
|
||||
paint.top -= y;
|
||||
|
||||
g_assert( !im_rect_isempty( &paint ) );
|
||||
|
||||
/* Render into or.
|
||||
*/
|
||||
if( im_prepare_to( ir, or, &paint,
|
||||
paint.left + x,
|
||||
paint.top + y ) )
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
/**
|
||||
* im_replicate:
|
||||
* @in: input image
|
||||
* @out: output image
|
||||
* @across: repeat @in this many times across
|
||||
* @down: repeat @in this many times down
|
||||
*
|
||||
* Replicate an image x times horizontally and vertically.
|
||||
*
|
||||
* See also: im_embed(), im_copy().
|
||||
*
|
||||
* Returns: 0 on success, -1 on error.
|
||||
*/
|
||||
int
|
||||
im_replicate( IMAGE *in, IMAGE *out, int across, int down )
|
||||
{
|
||||
if( across <= 0 || down <= 0 ) {
|
||||
im_error( "im_replicate", "%s", _( "bad parameters" ) );
|
||||
return( -1 );
|
||||
}
|
||||
if( im_piocheck( in, out ) ||
|
||||
im_cp_desc( out, in ) )
|
||||
return( -1 );
|
||||
out->Xsize *= across;
|
||||
out->Ysize *= 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, replicate_gen, im_stop_one, in, NULL ) )
|
||||
return( -1 );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
246
libvips/conversion/replicate.c
Normal file
246
libvips/conversion/replicate.c
Normal file
@ -0,0 +1,246 @@
|
||||
/* replicate an image x times horizontally and vertically
|
||||
*
|
||||
* JC, 30 sep 03
|
||||
*
|
||||
* 15/4/04
|
||||
* - some optimisations for some cases
|
||||
* 1/2/10
|
||||
* - gtkdoc
|
||||
* 26/10/11
|
||||
* - redone as a class
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
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
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
#define VIPS_DEBUG
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif /*HAVE_CONFIG_H*/
|
||||
#include <vips/intl.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <vips/vips.h>
|
||||
#include <vips/internal.h>
|
||||
#include <vips/debug.h>
|
||||
|
||||
#include "conversion.h"
|
||||
|
||||
/**
|
||||
* VipsReplicate:
|
||||
* @in: input image
|
||||
* @output: output image
|
||||
* @across: repeat input this many times across
|
||||
* @down: repeat input this many times down
|
||||
*
|
||||
* Repeats an image many times.
|
||||
*
|
||||
* See also: #VipsExtract.
|
||||
*/
|
||||
|
||||
typedef struct _VipsReplicate {
|
||||
VipsConversion parent_instance;
|
||||
|
||||
/* The input image.
|
||||
*/
|
||||
VipsImage *input;
|
||||
|
||||
int across;
|
||||
int down;
|
||||
|
||||
} VipsReplicate;
|
||||
|
||||
typedef VipsConversionClass VipsReplicateClass;
|
||||
|
||||
G_DEFINE_TYPE( VipsReplicate, vips_replicate, VIPS_TYPE_CONVERSION );
|
||||
|
||||
static int
|
||||
vips_replicate_gen( VipsRegion *or, void *seq, void *a, void *b,
|
||||
gboolean *stop )
|
||||
{
|
||||
VipsRegion *ir = (VipsRegion *) seq;
|
||||
VipsImage *in = (VipsImage *) a;
|
||||
VipsRect *r = &or->valid;
|
||||
int twidth = in->Xsize;
|
||||
int theight = in->Ysize;
|
||||
|
||||
int x, y;
|
||||
VipsRect 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( vips_rect_includesrect( &tile, r ) ) {
|
||||
VipsRect irect;
|
||||
|
||||
/* Translate request to input space.
|
||||
*/
|
||||
irect = *r;
|
||||
irect.left -= xs;
|
||||
irect.top -= ys;
|
||||
if( vips_region_prepare( ir, &irect ) )
|
||||
return( -1 );
|
||||
|
||||
if( vips_region_region( or, ir, r, irect.left, irect.top ) )
|
||||
return( -1 );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
for( y = ys; y < VIPS_RECT_BOTTOM( r ); y += theight )
|
||||
for( x = xs; x < VIPS_RECT_RIGHT( r ); x += twidth ) {
|
||||
VipsRect paint;
|
||||
|
||||
/* 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.
|
||||
*/
|
||||
vips_rect_intersectrect( &tile, r, &paint );
|
||||
|
||||
/* Translate back to ir coordinates.
|
||||
*/
|
||||
paint.left -= x;
|
||||
paint.top -= y;
|
||||
|
||||
g_assert( !im_rect_isempty( &paint ) );
|
||||
|
||||
/* Render into or.
|
||||
*/
|
||||
if( vips_region_prepare_to( ir, or, &paint,
|
||||
paint.left + x,
|
||||
paint.top + y ) )
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
static int
|
||||
vips_replicate_build( VipsObject *object )
|
||||
{
|
||||
VipsConversion *conversion = VIPS_CONVERSION( object );
|
||||
VipsReplicate *replicate = (VipsReplicate *) object;
|
||||
|
||||
if( VIPS_OBJECT_CLASS( vips_replicate_parent_class )->build( object ) )
|
||||
return( -1 );
|
||||
|
||||
if( vips_image_pio_input( replicate->input ) ||
|
||||
vips_image_pio_output( conversion->output ) )
|
||||
return( -1 );
|
||||
|
||||
if( vips_image_copy_fields( conversion->output, replicate->input ) )
|
||||
return( -1 );
|
||||
vips_demand_hint( conversion->output,
|
||||
VIPS_DEMAND_STYLE_SMALLTILE, replicate->input, NULL );
|
||||
|
||||
conversion->output->Xsize *= replicate->across;
|
||||
conversion->output->Ysize *= replicate->down;
|
||||
|
||||
if( vips_image_generate( conversion->output,
|
||||
vips_start_one, vips_replicate_gen, vips_stop_one,
|
||||
replicate->input, replicate ) )
|
||||
return( -1 );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
static void
|
||||
vips_replicate_class_init( VipsReplicateClass *class )
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
|
||||
VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS( class );
|
||||
|
||||
VIPS_DEBUG_MSG( "vips_replicate_class_init\n" );
|
||||
|
||||
gobject_class->set_property = vips_object_set_property;
|
||||
gobject_class->get_property = vips_object_get_property;
|
||||
|
||||
vobject_class->nickname = "replicate";
|
||||
vobject_class->description = _( "replicate an image" );
|
||||
vobject_class->build = vips_replicate_build;
|
||||
|
||||
VIPS_ARG_IMAGE( class, "input", 0,
|
||||
_( "Input" ),
|
||||
_( "Input image" ),
|
||||
VIPS_ARGUMENT_REQUIRED_INPUT,
|
||||
G_STRUCT_OFFSET( VipsReplicate, input ) );
|
||||
|
||||
VIPS_ARG_INT( class, "across", 4,
|
||||
_( "Across" ),
|
||||
_( "Repeat this many times horizontally" ),
|
||||
VIPS_ARGUMENT_REQUIRED_INPUT,
|
||||
G_STRUCT_OFFSET( VipsReplicate, across ),
|
||||
1, 1000000, 1 );
|
||||
|
||||
VIPS_ARG_INT( class, "down", 5,
|
||||
_( "Down" ),
|
||||
_( "Repeat this many times vertically" ),
|
||||
VIPS_ARGUMENT_REQUIRED_INPUT,
|
||||
G_STRUCT_OFFSET( VipsReplicate, down ),
|
||||
1, 1000000, 1 );
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
vips_replicate_init( VipsReplicate *replicate )
|
||||
{
|
||||
}
|
||||
|
||||
int
|
||||
vips_replicate( VipsImage *in, VipsImage **out, int across, int down, ... )
|
||||
{
|
||||
va_list ap;
|
||||
int result;
|
||||
|
||||
va_start( ap, down );
|
||||
result = vips_call_split( "replicate", ap, in, out, across, down );
|
||||
va_end( ap );
|
||||
|
||||
return( result );
|
||||
}
|
@ -1249,3 +1249,20 @@ im_extract_areabands( IMAGE *in, IMAGE *out,
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
int
|
||||
im_replicate( IMAGE *in, IMAGE *out, int across, int down )
|
||||
{
|
||||
VipsImage *t;
|
||||
|
||||
if( vips_replicate( in, &t, across, down,
|
||||
NULL ) )
|
||||
return( -1 );
|
||||
if( vips_image_write( t, out ) ) {
|
||||
g_object_unref( t );
|
||||
return( -1 );
|
||||
}
|
||||
g_object_unref( t );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
|
@ -132,6 +132,8 @@ int vips_extract_area( VipsImage *input, VipsImage **output,
|
||||
__attribute__((sentinel));
|
||||
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));
|
||||
|
||||
|
||||
|
||||
@ -163,7 +165,6 @@ int im_text( VipsImage *out, const char *text, const char *font,
|
||||
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_replicate( VipsImage *in, VipsImage *out, int across, int down );
|
||||
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 );
|
||||
|
||||
|
@ -556,6 +556,8 @@ int im_extract_bands( VipsImage *in, VipsImage *out, int band, int nbands );
|
||||
int im_extract_areabands( VipsImage *in, VipsImage *out,
|
||||
int left, int top, int width, int height, int band, int nbands );
|
||||
|
||||
int im_replicate( VipsImage *in, VipsImage *out, int across, int down );
|
||||
|
||||
/* ruby-vips uses this
|
||||
*/
|
||||
#define vips_class_map_concrete_all vips_class_map_all
|
||||
|
Loading…
Reference in New Issue
Block a user