remove old im_embed()
switched to the new class-based one
This commit is contained in:
parent
26792ed4e1
commit
62baa5dfbc
@ -1,6 +1,7 @@
|
||||
20/8/11 started 7.27.0
|
||||
- version bump for new dev cycle
|
||||
- im_subtract(), im_avg(), im_min(), im_minpos(), im_copy() redone as classes
|
||||
- im_subtract(), im_avg(), im_min(), im_minpos(), im_copy(), im_embed()
|
||||
redone as classes
|
||||
- added VIPS_ARGUMENT_APPEND to help control arg ordering
|
||||
- generate has a 'stop' param to signal successful early termination
|
||||
- added optional output args, eg. x/y for min
|
||||
|
@ -18,7 +18,6 @@ libconversion_la_SOURCES = \
|
||||
im_fliphor.c \
|
||||
im_flipver.c \
|
||||
im_gbandjoin.c \
|
||||
im_embed.c \
|
||||
im_insert.c \
|
||||
im_lrjoin.c \
|
||||
im_mask2vips.c \
|
||||
|
@ -1,555 +0,0 @@
|
||||
/* im_embed
|
||||
*
|
||||
* Author: J. Cupitt
|
||||
* Written on: 21/2/95
|
||||
* Modified on:
|
||||
* 6/4/04
|
||||
* - added extend pixels from edge mode
|
||||
* - sets Xoffset / Yoffset to x / y
|
||||
* 15/4/04
|
||||
* - added replicate and mirror modes
|
||||
* 4/3/05
|
||||
* - added solid white mode
|
||||
* 4/1/07
|
||||
* - degenerate to im_copy() for 0/0/w/h
|
||||
* 1/8/07
|
||||
* - more general ... x and y can be negative
|
||||
* 24/3/09
|
||||
* - added IM_CODING_RAD support
|
||||
* 5/11/09
|
||||
* - gtkdoc
|
||||
* 27/1/10
|
||||
* - use im_region_paint()
|
||||
* - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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>
|
||||
|
||||
/* Per-call struct.
|
||||
*/
|
||||
typedef struct _Embed {
|
||||
IMAGE *in;
|
||||
IMAGE *out;
|
||||
int type;
|
||||
int x;
|
||||
int y;
|
||||
int width;
|
||||
int height;
|
||||
|
||||
/* Geometry calculations.
|
||||
*/
|
||||
Rect rout; /* Whole output area */
|
||||
Rect rsub; /* Rect occupied by image */
|
||||
|
||||
/* The 8 border pieces. The 4 borders strictly up/down/left/right of
|
||||
* the main image, and the 4 corner pieces.
|
||||
*/
|
||||
Rect border[8];
|
||||
} Embed;
|
||||
|
||||
/* r is the bit we are trying to paint, guaranteed to be entirely within
|
||||
* border area i. Set out to be the edge of the image we need to paint the
|
||||
* pixels in r.
|
||||
*/
|
||||
static void
|
||||
embed_find_edge( Embed *embed, Rect *r, int i, Rect *out )
|
||||
{
|
||||
/* Expand the border by 1 pixel, intersect with the image area, and we
|
||||
* get the edge. Usually too much though: eg. we could make the entire
|
||||
* right edge.
|
||||
*/
|
||||
*out = embed->border[i];
|
||||
im_rect_marginadjust( out, 1 );
|
||||
im_rect_intersectrect( out, &embed->rsub, out );
|
||||
|
||||
/* Usually too much though: eg. we could make the entire
|
||||
* right edge. If we're strictly up/down/left/right of the image, we
|
||||
* can trim.
|
||||
*/
|
||||
if( i == 0 || i == 2 ) {
|
||||
Rect extend;
|
||||
|
||||
/* Above or below.
|
||||
*/
|
||||
extend = *r;
|
||||
extend.top = 0;
|
||||
extend.height = embed->height;
|
||||
im_rect_intersectrect( out, &extend, out );
|
||||
}
|
||||
if( i == 1 || i == 3 ) {
|
||||
Rect extend;
|
||||
|
||||
/* Left or right.
|
||||
*/
|
||||
extend = *r;
|
||||
extend.left = 0;
|
||||
extend.width = embed->width;
|
||||
im_rect_intersectrect( out, &extend, out );
|
||||
}
|
||||
}
|
||||
|
||||
/* Copy a single pixel sideways into a line of pixels.
|
||||
*/
|
||||
static void
|
||||
embed_copy_pixel( Embed *embed, PEL *q, PEL *p, int n )
|
||||
{
|
||||
const int bs = IM_IMAGE_SIZEOF_PEL( embed->in );
|
||||
|
||||
int x, b;
|
||||
|
||||
for( x = 0; x < n; x++ )
|
||||
for( b = 0; b < bs; b++ )
|
||||
*q++ = p[b];
|
||||
}
|
||||
|
||||
/* Paint r of region or. It's a border area, lying entirely within
|
||||
* embed->border[i]. p points to the top-left source pixel to fill with.
|
||||
* plsk is the line stride.
|
||||
*/
|
||||
static void
|
||||
embed_paint_edge( Embed *embed, REGION *or, int i, Rect *r, PEL *p, int plsk )
|
||||
{
|
||||
const int bs = IM_IMAGE_SIZEOF_PEL( embed->in );
|
||||
|
||||
Rect todo;
|
||||
PEL *q;
|
||||
int y;
|
||||
|
||||
/* Pixels left to paint.
|
||||
*/
|
||||
todo = *r;
|
||||
|
||||
/* Corner pieces ... copy the single pixel to paint the top line of
|
||||
* todo, then use the line copier below to paint the rest of it.
|
||||
*/
|
||||
if( i > 3 ) {
|
||||
q = (PEL *) IM_REGION_ADDR( or, todo.left, todo.top );
|
||||
embed_copy_pixel( embed, q, p, todo.width );
|
||||
|
||||
p = q;
|
||||
todo.top += 1;
|
||||
todo.height -= 1;
|
||||
}
|
||||
|
||||
if( i == 1 || i == 3 ) {
|
||||
/* Vertical line of pixels to copy.
|
||||
*/
|
||||
for( y = 0; y < todo.height; y++ ) {
|
||||
q = (PEL *) IM_REGION_ADDR( or,
|
||||
todo.left, todo.top + y );
|
||||
embed_copy_pixel( embed, q, p, todo.width );
|
||||
p += plsk;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Horizontal line of pixels to copy.
|
||||
*/
|
||||
for( y = 0; y < todo.height; y++ ) {
|
||||
q = (PEL *) IM_REGION_ADDR( or,
|
||||
todo.left, todo.top + y );
|
||||
memcpy( q, p, bs * todo.width );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
embed_gen( REGION *or, void *seq, void *a, void *b )
|
||||
{
|
||||
REGION *ir = (REGION *) seq;
|
||||
Embed *embed = (Embed *) b;
|
||||
Rect *r = &or->valid;
|
||||
|
||||
Rect ovl;
|
||||
int i;
|
||||
PEL *p;
|
||||
int plsk;
|
||||
|
||||
/* Entirely within the input image? Generate the subimage and copy
|
||||
* pointers.
|
||||
*/
|
||||
if( im_rect_includesrect( &embed->rsub, r ) ) {
|
||||
Rect need;
|
||||
|
||||
need = *r;
|
||||
need.left -= embed->x;
|
||||
need.top -= embed->y;
|
||||
if( im_prepare( ir, &need ) ||
|
||||
im_region_region( or, ir, r, need.left, need.top ) )
|
||||
return( -1 );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
/* Does any of the input image appear in the area we have been asked
|
||||
* to make? Paste it in.
|
||||
*/
|
||||
im_rect_intersectrect( r, &embed->rsub, &ovl );
|
||||
if( !im_rect_isempty( &ovl ) ) {
|
||||
/* Paint the bits coming from the input image.
|
||||
*/
|
||||
ovl.left -= embed->x;
|
||||
ovl.top -= embed->y;
|
||||
if( im_prepare_to( ir, or, &ovl,
|
||||
ovl.left + embed->x, ovl.top + embed->y ) )
|
||||
return( -1 );
|
||||
ovl.left += embed->x;
|
||||
ovl.top += embed->y;
|
||||
}
|
||||
|
||||
switch( embed->type ) {
|
||||
case 0:
|
||||
case 4:
|
||||
/* Paint the borders a solid value.
|
||||
*/
|
||||
for( i = 0; i < 8; i++ )
|
||||
im_region_paint( or, &embed->border[i],
|
||||
embed->type == 0 ? 0 : 255 );
|
||||
break;
|
||||
|
||||
case 1:
|
||||
/* Extend the borders.
|
||||
*/
|
||||
for( i = 0; i < 8; i++ ) {
|
||||
Rect todo;
|
||||
Rect edge;
|
||||
|
||||
im_rect_intersectrect( r, &embed->border[i], &todo );
|
||||
if( !im_rect_isempty( &todo ) ) {
|
||||
embed_find_edge( embed, &todo, i, &edge );
|
||||
|
||||
/* Did we paint any of the input image? If we
|
||||
* did, we can fetch the edge pixels from
|
||||
* that.
|
||||
*/
|
||||
if( !im_rect_isempty( &ovl ) ) {
|
||||
p = (PEL *) IM_REGION_ADDR( or,
|
||||
edge.left, edge.top );
|
||||
plsk = IM_REGION_LSKIP( or );
|
||||
}
|
||||
else {
|
||||
/* No pixels painted ... fetch
|
||||
* directly from the input image.
|
||||
*/
|
||||
edge.left -= embed->x;
|
||||
edge.top -= embed->y;
|
||||
if( im_prepare( ir, &edge ) )
|
||||
return( -1 );
|
||||
p = (PEL *) IM_REGION_ADDR( ir,
|
||||
edge.left, edge.top );
|
||||
plsk = IM_REGION_LSKIP( ir );
|
||||
}
|
||||
|
||||
embed_paint_edge( embed,
|
||||
or, i, &todo, p, plsk );
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
g_assert( 0 );
|
||||
}
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
static Embed *
|
||||
embed_new( IMAGE *in, IMAGE *out,
|
||||
int type, int x, int y, int width, int height )
|
||||
{
|
||||
Embed *embed = IM_NEW( out, Embed );
|
||||
Rect want;
|
||||
|
||||
/* Take a copy of args.
|
||||
*/
|
||||
embed->in = in;
|
||||
embed->out = out;
|
||||
embed->type = type;
|
||||
embed->x = x;
|
||||
embed->y = y;
|
||||
embed->width = width;
|
||||
embed->height = height;
|
||||
|
||||
/* Whole output area.
|
||||
*/
|
||||
embed->rout.left = 0;
|
||||
embed->rout.top = 0;
|
||||
embed->rout.width = out->Xsize;
|
||||
embed->rout.height = out->Ysize;
|
||||
|
||||
/* Rect occupied by image (can be clipped to nothing).
|
||||
*/
|
||||
want.left = x;
|
||||
want.top = y;
|
||||
want.width = in->Xsize;
|
||||
want.height = in->Ysize;
|
||||
im_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 and remove this
|
||||
* test.
|
||||
*/
|
||||
if( im_rect_isempty( &embed->rsub ) ) {
|
||||
im_error( "im_embed", "%s", _( "bad dimensions" ) );
|
||||
return( NULL );
|
||||
}
|
||||
|
||||
/* Edge rects of new pixels ... top, right, bottom, left. Order
|
||||
* important. Can be empty.
|
||||
*/
|
||||
embed->border[0].left = embed->rsub.left;
|
||||
embed->border[0].top = 0;
|
||||
embed->border[0].width = embed->rsub.width;
|
||||
embed->border[0].height = embed->rsub.top;
|
||||
|
||||
embed->border[1].left = IM_RECT_RIGHT( &embed->rsub );
|
||||
embed->border[1].top = embed->rsub.top;
|
||||
embed->border[1].width = out->Xsize - IM_RECT_RIGHT( &embed->rsub );
|
||||
embed->border[1].height = embed->rsub.height;
|
||||
|
||||
embed->border[2].left = embed->rsub.left;
|
||||
embed->border[2].top = IM_RECT_BOTTOM( &embed->rsub );
|
||||
embed->border[2].width = embed->rsub.width;
|
||||
embed->border[2].height = out->Ysize - IM_RECT_BOTTOM( &embed->rsub );
|
||||
|
||||
embed->border[3].left = 0;
|
||||
embed->border[3].top = embed->rsub.top;
|
||||
embed->border[3].width = embed->rsub.left;
|
||||
embed->border[3].height = embed->rsub.height;
|
||||
|
||||
/* Corner rects. Top-left, top-right, bottom-right, bottom-left. Order
|
||||
* important.
|
||||
*/
|
||||
embed->border[4].left = 0;
|
||||
embed->border[4].top = 0;
|
||||
embed->border[4].width = embed->rsub.left;
|
||||
embed->border[4].height = embed->rsub.top;
|
||||
|
||||
embed->border[5].left = IM_RECT_RIGHT( &embed->rsub );
|
||||
embed->border[5].top = 0;
|
||||
embed->border[5].width = out->Xsize - IM_RECT_RIGHT( &embed->rsub );
|
||||
embed->border[5].height = embed->rsub.top;
|
||||
|
||||
embed->border[6].left = IM_RECT_RIGHT( &embed->rsub );
|
||||
embed->border[6].top = IM_RECT_BOTTOM( &embed->rsub );
|
||||
embed->border[6].width = out->Xsize - IM_RECT_RIGHT( &embed->rsub );
|
||||
embed->border[6].height = out->Ysize - IM_RECT_BOTTOM( &embed->rsub );
|
||||
|
||||
embed->border[7].left = 0;
|
||||
embed->border[7].top = IM_RECT_BOTTOM( &embed->rsub );
|
||||
embed->border[7].width = embed->rsub.left;
|
||||
embed->border[7].height = out->Ysize - IM_RECT_BOTTOM( &embed->rsub );
|
||||
|
||||
return( embed );
|
||||
}
|
||||
|
||||
/* Do type 0/4 (black/white) and 1 (extend).
|
||||
*/
|
||||
static int
|
||||
embed( IMAGE *in, IMAGE *out, int type, int x, int y, int width, int height )
|
||||
{
|
||||
Embed *embed;
|
||||
|
||||
if( im_cp_desc( out, in ) )
|
||||
return( -1 );
|
||||
out->Xsize = width;
|
||||
out->Ysize = height;
|
||||
|
||||
if( !(embed = embed_new( in, out, type, x, y, width, height )) ||
|
||||
im_demand_hint( out, IM_SMALLTILE, in, NULL ) ||
|
||||
im_generate( out,
|
||||
im_start_one, embed_gen, im_stop_one,
|
||||
in, embed ) )
|
||||
return( -1 );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
/**
|
||||
* im_embed:
|
||||
* @in: input image
|
||||
* @out: output image
|
||||
* @type: how to generate the edge pixels
|
||||
* @x: place @in at this x position in @out
|
||||
* @y: place @in at this y position in @out
|
||||
* @width: @out should be this many pixels across
|
||||
* @height: @out should be this many pixels down
|
||||
*
|
||||
* The opposite of im_extract(): embed an image within a larger image. @type
|
||||
* controls what appears in the new pels:
|
||||
*
|
||||
* <tgroup cols='2' align='left' colsep='1' rowsep='1'>
|
||||
* <tbody>
|
||||
* <row>
|
||||
* <entry>0</entry>
|
||||
* <entry>black pels (all bytes == 0)</entry>
|
||||
* </row>
|
||||
* <row>
|
||||
* <entry>1</entry>
|
||||
* <entry>extend pels from image edge</entry>
|
||||
* </row>
|
||||
* <row>
|
||||
* <entry>2</entry>
|
||||
* <entry>repeat image</entry>
|
||||
* </row>
|
||||
* <row>
|
||||
* <entry>3</entry>
|
||||
* <entry>mirror image</entry>
|
||||
* </row>
|
||||
* <row>
|
||||
* <entry>4</entry>
|
||||
* <entry>white pels (all bytes == 255)</entry>
|
||||
* </row>
|
||||
* </tbody>
|
||||
* </tgroup>
|
||||
*
|
||||
* See also: im_extract_area(), im_insert().
|
||||
*
|
||||
* Returns: 0 on success, -1 on error.
|
||||
*/
|
||||
int
|
||||
im_embed( IMAGE *in, IMAGE *out, int type, int x, int y, int width, int height )
|
||||
{
|
||||
if( im_piocheck( in, out ) ||
|
||||
im_check_coding_known( "im_embed", in ) )
|
||||
return( -1 );
|
||||
if( type < 0 || type > 4 ) {
|
||||
im_error( "im_embed", "%s", _( "unknown type" ) );
|
||||
return( -1 );
|
||||
}
|
||||
if( width <= 0 || height <= 0 ) {
|
||||
im_error( "im_embed", "%s", _( "bad dimensions" ) );
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
/* nip can generate this quite often ... just copy.
|
||||
*/
|
||||
if( x == 0 && y == 0 && width == in->Xsize && height == in->Ysize )
|
||||
return( im_copy( in, out ) );
|
||||
|
||||
switch( type ) {
|
||||
case 0:
|
||||
case 1:
|
||||
case 4:
|
||||
if( embed( in, out, type, x, y, width, height ) )
|
||||
return( -1 );
|
||||
break;
|
||||
|
||||
case 2:
|
||||
{
|
||||
/* Clock arithmetic: we want negative x/y to wrap around
|
||||
* nicely.
|
||||
*/
|
||||
const int nx = x < 0 ?
|
||||
-x % in->Xsize : in->Xsize - x % in->Xsize;
|
||||
const int ny = y < 0 ?
|
||||
-y % in->Ysize : in->Ysize - y % in->Ysize;
|
||||
|
||||
IMAGE *t[1];
|
||||
|
||||
if( im_open_local_array( out, t, 1, "embed-type2", "p" ) ||
|
||||
im_replicate( in, t[0],
|
||||
width / in->Xsize + 2,
|
||||
height / in->Ysize + 2 ) ||
|
||||
im_extract_area( t[0], out, nx, ny, width, height ) )
|
||||
return( -1 );
|
||||
}
|
||||
break;
|
||||
|
||||
case 3:
|
||||
{
|
||||
/* As case 2, but the tiles are twice the size because of
|
||||
* mirroring.
|
||||
*/
|
||||
const int w2 = in->Xsize * 2;
|
||||
const int h2 = in->Ysize * 2;
|
||||
|
||||
const int nx = x < 0 ? -x % w2 : w2 - x % w2;
|
||||
const int ny = y < 0 ? -y % h2 : h2 - y % h2;
|
||||
|
||||
IMAGE *t[7];
|
||||
|
||||
if( im_open_local_array( out, 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( in, 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],
|
||||
width / t[4]->Xsize + 2,
|
||||
height / t[4]->Ysize + 2 ) ||
|
||||
im_extract_area( t[5], t[6], nx, ny, width, height ) ||
|
||||
|
||||
/* Overwrite the centre with the input, much faster
|
||||
* for centre pixels.
|
||||
*/
|
||||
im_insert_noexpand( t[6], in, out, x, y ) )
|
||||
return( -1 );
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
g_assert( 0 );
|
||||
}
|
||||
|
||||
out->Xoffset = x;
|
||||
out->Yoffset = y;
|
||||
|
||||
return( 0 );
|
||||
}
|
@ -1061,3 +1061,21 @@ im_copy_native( IMAGE *in, IMAGE *out, gboolean is_msb_first )
|
||||
else
|
||||
return( im_copy( in, out ) );
|
||||
}
|
||||
|
||||
int
|
||||
im_embed( IMAGE *in, IMAGE *out, int type, int x, int y, int width, int height )
|
||||
{
|
||||
VipsImage *t;
|
||||
|
||||
if( vips_embed( in, &t, x, y, width, height,
|
||||
"extend", type,
|
||||
NULL ) )
|
||||
return( -1 );
|
||||
if( vips_image_write( t, out ) ) {
|
||||
g_object_unref( t );
|
||||
return( -1 );
|
||||
}
|
||||
g_object_unref( t );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
@ -115,8 +115,6 @@ int im_extract_area( VipsImage *in, VipsImage *out,
|
||||
int left, int top, int width, int height );
|
||||
int im_extract_areabands( VipsImage *in, VipsImage *out,
|
||||
int left, int top, int width, int height, int band, int nbands );
|
||||
int im_embed( VipsImage *in, VipsImage *out,
|
||||
int type, int x, int y, int width, int height );
|
||||
int im_bandjoin( VipsImage *in1, VipsImage *in2, VipsImage *out );
|
||||
int im_gbandjoin( VipsImage **in, VipsImage *out, int n );
|
||||
int im_insert( VipsImage *main, VipsImage *sub, VipsImage *out, int x, int y );
|
||||
|
@ -537,6 +537,9 @@ int im_copy_morph( VipsImage *in, VipsImage *out,
|
||||
int im_copy_swap( VipsImage *in, VipsImage *out );
|
||||
int im_copy_native( VipsImage *in, VipsImage *out, gboolean is_msb_first );
|
||||
|
||||
int im_embed( VipsImage *in, VipsImage *out,
|
||||
int type, int x, int y, int width, int height );
|
||||
|
||||
/* ruby-vips uses this
|
||||
*/
|
||||
#define vips_class_map_concrete_all vips_class_map_all
|
||||
|
Loading…
Reference in New Issue
Block a user