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
|
- version bump for new dev cycle
|
||||||
- im_subtract(), im_avg(), im_min(), im_minpos(), im_copy(), im_embed(),
|
- im_subtract(), im_avg(), im_min(), im_minpos(), im_copy(), im_embed(),
|
||||||
im_flophor(), im_flipver(), im_insert(), im_insert_noexpand(), im_lrjoin(),
|
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
|
redone as classes
|
||||||
- added VIPS_ARGUMENT_APPEND to help control arg ordering
|
- added VIPS_ARGUMENT_APPEND to help control arg ordering
|
||||||
- generate has a 'stop' param to signal successful early termination
|
- 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
|
- bandalike: consider RGB + RGBA ... we should bandup by adding a black band
|
||||||
|
|
||||||
(or white?? unclear)
|
(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 \
|
insert.c \
|
||||||
join.c \
|
join.c \
|
||||||
extract.c \
|
extract.c \
|
||||||
|
replicate.c \
|
||||||
conver_dispatch.c \
|
conver_dispatch.c \
|
||||||
im_black.c \
|
im_black.c \
|
||||||
im_c2amph.c \
|
im_c2amph.c \
|
||||||
@ -21,7 +22,6 @@ libconversion_la_SOURCES = \
|
|||||||
im_gbandjoin.c \
|
im_gbandjoin.c \
|
||||||
im_mask2vips.c \
|
im_mask2vips.c \
|
||||||
im_msb.c \
|
im_msb.c \
|
||||||
im_replicate.c \
|
|
||||||
im_grid.c \
|
im_grid.c \
|
||||||
im_ri2c.c \
|
im_ri2c.c \
|
||||||
im_rot180.c \
|
im_rot180.c \
|
||||||
|
@ -109,6 +109,7 @@ vips_conversion_operation_init( void )
|
|||||||
extern GType vips_join_get_type( void );
|
extern GType vips_join_get_type( void );
|
||||||
extern GType vips_extract_area_get_type( void );
|
extern GType vips_extract_area_get_type( void );
|
||||||
extern GType vips_extract_band_get_type( void );
|
extern GType vips_extract_band_get_type( void );
|
||||||
|
extern GType vips_replicate_get_type( void );
|
||||||
|
|
||||||
vips_copy_get_type();
|
vips_copy_get_type();
|
||||||
vips_embed_get_type();
|
vips_embed_get_type();
|
||||||
@ -117,5 +118,6 @@ vips_conversion_operation_init( void )
|
|||||||
vips_join_get_type();
|
vips_join_get_type();
|
||||||
vips_extract_area_get_type();
|
vips_extract_area_get_type();
|
||||||
vips_extract_band_get_type();
|
vips_extract_band_get_type();
|
||||||
|
vips_replicate_get_type();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,11 +81,11 @@
|
|||||||
* @x: place @in at this x position in @out
|
* @x: place @in at this x position in @out
|
||||||
* @y: place @in at this y 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
|
* The opposite of #VipsExtractArea: embed @in within an image of size @width
|
||||||
* @height at position @x, @y. @extend
|
* by @height at position @x, @y. @extend
|
||||||
* controls what appears in the new pels, see #VipsExtend.
|
* 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.
|
* 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 );
|
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
|
static int
|
||||||
vips_embed_build( VipsObject *object )
|
vips_embed_build( VipsObject *object )
|
||||||
{
|
{
|
||||||
@ -332,6 +402,7 @@ vips_embed_build( VipsObject *object )
|
|||||||
VipsEmbed *embed = (VipsEmbed *) object;
|
VipsEmbed *embed = (VipsEmbed *) object;
|
||||||
|
|
||||||
VipsRect want;
|
VipsRect want;
|
||||||
|
VipsPool *pool;
|
||||||
|
|
||||||
if( VIPS_OBJECT_CLASS( vips_embed_parent_class )->build( object ) )
|
if( VIPS_OBJECT_CLASS( vips_embed_parent_class )->build( object ) )
|
||||||
return( -1 );
|
return( -1 );
|
||||||
@ -352,87 +423,30 @@ vips_embed_build( VipsObject *object )
|
|||||||
embed->height == embed->input->Ysize )
|
embed->height == embed->input->Ysize )
|
||||||
return( vips_image_write( embed->input, conversion->output ) );
|
return( vips_image_write( embed->input, conversion->output ) );
|
||||||
|
|
||||||
|
pool = vips_pool_new( "VipsEmbed" );
|
||||||
|
vips_object_local( object, pool );
|
||||||
|
|
||||||
switch( embed->extend ) {
|
switch( embed->extend ) {
|
||||||
case VIPS_EXTEND_REPEAT:
|
case VIPS_EXTEND_REPEAT:
|
||||||
{
|
{
|
||||||
/* Clock arithmetic: we want negative x/y to wrap around
|
VipsPoolContext *context = vips_pool_context_new( pool );
|
||||||
* 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;
|
|
||||||
|
|
||||||
VipsImage *t[1];
|
if( vips_embed_repeat( pool, embed->input, &VIPS_VI( 1 ),
|
||||||
|
embed->x, embed->y, embed->width, embed->height ) ||
|
||||||
if( im_open_local_array( conversion->output,
|
vips_image_write( VIPS_VI( 1 ), 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 ) )
|
|
||||||
return( -1 );
|
return( -1 );
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case VIPS_EXTEND_MIRROR:
|
case VIPS_EXTEND_MIRROR:
|
||||||
{
|
{
|
||||||
/* As case 2, but the tiles are twice the size because of
|
VipsPoolContext *context = vips_pool_context_new( pool );
|
||||||
* mirroring.
|
|
||||||
*/
|
|
||||||
const int w2 = embed->input->Xsize * 2;
|
|
||||||
const int h2 = embed->input->Ysize * 2;
|
|
||||||
|
|
||||||
const int nx = embed->x < 0 ?
|
if( vips_embed_mirror( pool, embed->input, &VIPS_VI( 1 ),
|
||||||
-embed->x % w2 : w2 - embed->x % w2;
|
embed->x, embed->y, embed->width, embed->height ) ||
|
||||||
const int ny = embed->y < 0 ?
|
vips_image_write( VIPS_VI( 1 ), conversion->output ) )
|
||||||
-embed->y % h2 : h2 - embed->y % h2;
|
return( -1 );
|
||||||
|
|
||||||
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 );
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -461,7 +475,7 @@ vips_embed_build( VipsObject *object )
|
|||||||
want.top = embed->y;
|
want.top = embed->y;
|
||||||
want.width = embed->input->Xsize;
|
want.width = embed->input->Xsize;
|
||||||
want.height = embed->input->Ysize;
|
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
|
/* FIXME ... actually, it can't. embed_find_edge() will fail
|
||||||
* if rsub is empty. Make this more general at some point
|
* if rsub is empty. Make this more general at some point
|
||||||
|
@ -66,7 +66,7 @@
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* VipsFlip:
|
* VipsFlip:
|
||||||
* @in: input image
|
* @input: input image
|
||||||
* @output: output image
|
* @output: output image
|
||||||
* @direction: flip horizontally or vertically
|
* @direction: flip horizontally or vertically
|
||||||
*
|
*
|
||||||
@ -250,7 +250,7 @@ vips_flip_class_init( VipsFlipClass *class )
|
|||||||
vobject_class->description = _( "flip an image" );
|
vobject_class->description = _( "flip an image" );
|
||||||
vobject_class->build = vips_flip_build;
|
vobject_class->build = vips_flip_build;
|
||||||
|
|
||||||
VIPS_ARG_IMAGE( class, "in", 1,
|
VIPS_ARG_IMAGE( class, "input", 1,
|
||||||
_( "Input" ),
|
_( "Input" ),
|
||||||
_( "Input image" ),
|
_( "Input image" ),
|
||||||
VIPS_ARGUMENT_REQUIRED_INPUT,
|
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 );
|
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));
|
__attribute__((sentinel));
|
||||||
int vips_extract_band( VipsImage *input, VipsImage **output, int band, ... )
|
int vips_extract_band( VipsImage *input, VipsImage **output, int band, ... )
|
||||||
__attribute__((sentinel));
|
__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_bandjoin( VipsImage *in1, VipsImage *in2, VipsImage *out );
|
||||||
int im_gbandjoin( VipsImage **in, VipsImage *out, int n );
|
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_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_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_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 im_extract_areabands( VipsImage *in, VipsImage *out,
|
||||||
int left, int top, int width, int height, int band, int nbands );
|
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
|
/* ruby-vips uses this
|
||||||
*/
|
*/
|
||||||
#define vips_class_map_concrete_all vips_class_map_all
|
#define vips_class_map_concrete_all vips_class_map_all
|
||||||
|
Loading…
Reference in New Issue
Block a user