remove old flood-fill
This commit is contained in:
parent
d5a4ecb767
commit
b84b08a883
@ -28,6 +28,8 @@
|
||||
deprecated
|
||||
- im_bandjoin()/im_gbandjoin() work with images of varying formats
|
||||
- added im_copy_native(), deprecated im_copy_from() and friends
|
||||
- im_check*() name rationalisation
|
||||
- finally removed old flood stuff
|
||||
|
||||
26/11/09 started 7.20.3
|
||||
- updated en_GB.po translation
|
||||
|
6
TODO
6
TODO
@ -24,12 +24,6 @@
|
||||
|
||||
rather awkward to do atm with the way check.c is structured
|
||||
|
||||
- we sill have the old flood-fill code there, move to deprecated
|
||||
|
||||
should we have new API? we could have a single "im_floodfill" that allows
|
||||
two inputs and has an "equals" param and junk im_flood(), im_flood_blob()
|
||||
and im_flood_other()
|
||||
|
||||
- what does G_UNLIKELY() do? can we use it?
|
||||
|
||||
- rename vipsCC in SWIG as pyvips?
|
||||
|
@ -62,14 +62,6 @@ int im_flood_other_copy( IMAGE *test, IMAGE *mark, IMAGE *out,
|
||||
int im_lineset( IMAGE *in, IMAGE *out, IMAGE *mask, IMAGE *ink,
|
||||
int n, int *x1v, int *y1v, int *x2v, int *y2v );
|
||||
|
||||
int im_flood_old( IMAGE *im, int x, int y, PEL *ink, Rect *dout );
|
||||
int im_flood_blob_old( IMAGE *im, int x, int y, PEL *ink, Rect *dout );
|
||||
int im_flood_other_old( IMAGE *mask, IMAGE *test, int x, int y, int serial );
|
||||
int im_flood_copy_old( IMAGE *in, IMAGE *out, int x, int y, PEL *ink );
|
||||
int im_flood_blob_copy_old( IMAGE *in, IMAGE *out, int x, int y, PEL *ink );
|
||||
int im_flood_other_copy_old( IMAGE *mask, IMAGE *test, IMAGE *out,
|
||||
int x, int y, int serial );
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /*__cplusplus*/
|
||||
|
@ -2,8 +2,6 @@ noinst_LTLIBRARIES = libinplace.la
|
||||
|
||||
libinplace_la_SOURCES = \
|
||||
im_circle.c \
|
||||
im_flood.c \
|
||||
im_flood_other.c \
|
||||
flood.c \
|
||||
im_insertplace.c \
|
||||
im_paintrect.c \
|
||||
|
@ -1,452 +0,0 @@
|
||||
/* int im_flood( IMAGE *im, int x, int y, PEL *ink, Rect *dout )
|
||||
*
|
||||
* Flood fill from point (x,y) with colour ink. Flood up to boundary == ink.
|
||||
* Any type, any number of bands, IM_CODING_LABQ too. Returns the bounding box
|
||||
* of the modified pixels in dout, whether it succeeds or not.
|
||||
*
|
||||
* Currently a rather inefficient pixel-based algorithm, should put something
|
||||
* better in, really. Speed isn't likely to be a problem, except for very
|
||||
* large images.
|
||||
*
|
||||
* JC 30/8/97
|
||||
* - VIPSified, cleaned up, from "John Robinson's prog to fill
|
||||
* enclosed areas"
|
||||
* - something Kirk gave me, so thanks John
|
||||
* JC 1/10/97
|
||||
* - swapped inner memcmp/cpy for a loop ... faster for small pixels
|
||||
* 13/7/02 JC
|
||||
* - im_flood_blob() added
|
||||
* 5/12/06
|
||||
* - im_invalidate() after paint
|
||||
* 24/3/09
|
||||
* - added IM_CODING_RAD support
|
||||
* 28/9/09
|
||||
* - ooops, tiny memleak
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
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>
|
||||
|
||||
#ifdef WITH_DMALLOC
|
||||
#include <dmalloc.h>
|
||||
#endif /*WITH_DMALLOC*/
|
||||
|
||||
/* Size of a point buffer. We allocate a list of these to hold points we need
|
||||
* to visit.
|
||||
*/
|
||||
#define PBUFSIZE (1000)
|
||||
|
||||
/* An xy position.
|
||||
*/
|
||||
typedef struct {
|
||||
int x, y;
|
||||
} Point;
|
||||
|
||||
/* A buffer of points, and how many of them have been used. When full, alloc a
|
||||
* new buffer, and link it on.
|
||||
*/
|
||||
typedef struct _Buffer {
|
||||
struct _Buffer *next;
|
||||
int n;
|
||||
Point points[PBUFSIZE];
|
||||
} Buffer;
|
||||
|
||||
/* Our state.
|
||||
*/
|
||||
typedef struct {
|
||||
/* Parameters.
|
||||
*/
|
||||
IMAGE *im;
|
||||
int x, y;
|
||||
PEL *ink; /* Copy of ink param */
|
||||
Rect *dout; /* Write dirty here at end */
|
||||
|
||||
/* Derived stuff.
|
||||
*/
|
||||
PEL *edge; /* Boundary colour */
|
||||
int equal; /* Fill to == edge, or != edge */
|
||||
int ps; /* sizeof( one pel ) */
|
||||
int ls; /* sizeof( one line ) */
|
||||
int left, right; /* Area will fill within */
|
||||
int top, bottom;
|
||||
Rect dirty; /* Bounding box of pixels we have changed */
|
||||
|
||||
/* Two buffers of points which we know need checking.
|
||||
*/
|
||||
Buffer *buf1;
|
||||
Buffer *buf2;
|
||||
} State;
|
||||
|
||||
/* Alloc a new buffer.
|
||||
*/
|
||||
static Buffer *
|
||||
build_buffer( void )
|
||||
{
|
||||
Buffer *buf = IM_NEW( NULL, Buffer );
|
||||
|
||||
if( !buf )
|
||||
return( NULL );
|
||||
buf->next = NULL;
|
||||
buf->n = 0;
|
||||
|
||||
return( buf );
|
||||
}
|
||||
|
||||
/* Free a chain of buffers.
|
||||
*/
|
||||
static void
|
||||
free_buffer( Buffer *buf )
|
||||
{
|
||||
IM_FREE( buf->next );
|
||||
im_free( buf );
|
||||
}
|
||||
|
||||
/* Free a state.
|
||||
*/
|
||||
static void
|
||||
free_state( State *st )
|
||||
{
|
||||
/* Write dirty back to caller.
|
||||
*/
|
||||
if( st->dout )
|
||||
*st->dout = st->dirty;
|
||||
|
||||
/* Free our stuff.
|
||||
*/
|
||||
IM_FREE( st->ink );
|
||||
IM_FREE( st->edge );
|
||||
IM_FREEF( free_buffer, st->buf1 );
|
||||
IM_FREEF( free_buffer, st->buf2 );
|
||||
im_free( st );
|
||||
}
|
||||
|
||||
/* Build a state.
|
||||
*/
|
||||
static State *
|
||||
build_state( IMAGE *im, int x, int y, PEL *ink, Rect *dout )
|
||||
{
|
||||
State *st = IM_NEW( NULL, State );
|
||||
|
||||
if( !st )
|
||||
return( NULL );
|
||||
st->im = im;
|
||||
st->x = x;
|
||||
st->y = y;
|
||||
st->ink = NULL;
|
||||
st->dout = dout;
|
||||
st->edge = NULL;
|
||||
st->ps = IM_IMAGE_SIZEOF_PEL( im );
|
||||
st->ls = IM_IMAGE_SIZEOF_LINE( im );
|
||||
st->buf1 = NULL;
|
||||
st->buf2 = NULL;
|
||||
st->left = 0;
|
||||
st->top = 0;
|
||||
st->right = im->Xsize;
|
||||
st->bottom = im->Ysize;
|
||||
st->dirty.left = x;
|
||||
st->dirty.top = y;
|
||||
st->dirty.width = 0;
|
||||
st->dirty.height = 0;
|
||||
|
||||
if( !(st->ink = (PEL *) im_malloc( NULL, st->ps )) ||
|
||||
!(st->edge = (PEL *) im_malloc( NULL, st->ps )) ||
|
||||
!(st->buf1 = build_buffer()) ||
|
||||
!(st->buf2 = build_buffer()) ) {
|
||||
free_state( st );
|
||||
return( NULL );
|
||||
}
|
||||
memcpy( st->ink, ink, st->ps );
|
||||
|
||||
return( st );
|
||||
}
|
||||
|
||||
/* Add xy to buffer, move buffer on on overflow.
|
||||
*/
|
||||
#define ADD( BUF, X, Y ) { \
|
||||
BUF->points[BUF->n].x = X; \
|
||||
BUF->points[BUF->n].y = Y; \
|
||||
BUF->n++; \
|
||||
if( BUF->n == PBUFSIZE ) { \
|
||||
if( !BUF->next ) { \
|
||||
if( !(BUF->next = build_buffer()) ) \
|
||||
return( -1 ); \
|
||||
} \
|
||||
BUF = BUF->next; \
|
||||
BUF->n = 0; \
|
||||
} \
|
||||
}
|
||||
|
||||
/* If point != edge, add it to out.
|
||||
*/
|
||||
#define ADDIFNOTEDGE( P, X, Y ) { \
|
||||
PEL *p1 = (P); \
|
||||
\
|
||||
for( j = 0; j < st->ps; j++ ) \
|
||||
if( p1[j] != st->edge[j] ) { \
|
||||
ADD( out, X, Y ); \
|
||||
break; \
|
||||
} \
|
||||
}
|
||||
|
||||
/* If point == edge, add it to out.
|
||||
*/
|
||||
#define ADDIFEDGE( P, X, Y ) { \
|
||||
PEL *p1 = (P); \
|
||||
\
|
||||
for( j = 0; j < st->ps; j++ ) \
|
||||
if( p1[j] != st->edge[j] ) \
|
||||
break; \
|
||||
if( j == st->ps ) \
|
||||
ADD( out, X, Y ); \
|
||||
}
|
||||
|
||||
/* Read points to fill from in, write new points to out.
|
||||
*/
|
||||
static int
|
||||
dofill( State *st, Buffer *in, Buffer *out )
|
||||
{
|
||||
int i, j;
|
||||
|
||||
/* Clear output buffer.
|
||||
*/
|
||||
out->n = 0;
|
||||
|
||||
/* Loop over chain of input buffers.
|
||||
*/
|
||||
for(;;) {
|
||||
/* Loop for this buffer.
|
||||
*/
|
||||
for( i = 0; i < in->n; i++ ) {
|
||||
/* Find this pixel.
|
||||
*/
|
||||
int x = in->points[i].x;
|
||||
int y = in->points[i].y;
|
||||
PEL *p = (PEL *) st->im->data + x*st->ps + y*st->ls;
|
||||
|
||||
/* Is it still not fore? May have been set by us
|
||||
* earlier.
|
||||
*/
|
||||
for( j = 0; j < st->ps; j++ )
|
||||
if( p[j] != st->ink[j] )
|
||||
break;
|
||||
if( j == st->ps )
|
||||
continue;
|
||||
|
||||
/* Set this pixel.
|
||||
*/
|
||||
for( j = 0; j < st->ps; j++ )
|
||||
p[j] = st->ink[j];
|
||||
|
||||
/* Changes bb of dirty area?
|
||||
*/
|
||||
if( x < st->dirty.left ) {
|
||||
st->dirty.left -= x;
|
||||
st->dirty.width += x;
|
||||
}
|
||||
else if( x > st->dirty.left + st->dirty.width )
|
||||
st->dirty.width += x;
|
||||
|
||||
if( y < st->dirty.top ) {
|
||||
st->dirty.top -= y;
|
||||
st->dirty.height += y;
|
||||
}
|
||||
else if( y > st->dirty.top + st->dirty.height )
|
||||
st->dirty.height += y;
|
||||
|
||||
/* Propogate to neighbours.
|
||||
*/
|
||||
if( st->equal ) {
|
||||
if( x < st->right - 1 )
|
||||
ADDIFEDGE( p + st->ps, x + 1, y );
|
||||
if( x > st->left )
|
||||
ADDIFEDGE( p - st->ps, x - 1, y );
|
||||
if( y < st->bottom - 1 )
|
||||
ADDIFEDGE( p + st->ls, x, y + 1 );
|
||||
if( y > st->top )
|
||||
ADDIFEDGE( p - st->ls, x, y - 1 );
|
||||
}
|
||||
else {
|
||||
if( x < st->right - 1 )
|
||||
ADDIFNOTEDGE( p + st->ps, x + 1, y );
|
||||
if( x > st->left )
|
||||
ADDIFNOTEDGE( p - st->ps, x - 1, y );
|
||||
if( y < st->bottom - 1 )
|
||||
ADDIFNOTEDGE( p + st->ls, x, y + 1 );
|
||||
if( y > st->top )
|
||||
ADDIFNOTEDGE( p - st->ls, x, y - 1 );
|
||||
}
|
||||
}
|
||||
|
||||
if( in->n == PBUFSIZE )
|
||||
/* Buffer full ... must be another one.
|
||||
*/
|
||||
in = in->next;
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
int
|
||||
im_flood_old( IMAGE *im, int x, int y, PEL *ink, Rect *dout )
|
||||
{
|
||||
State *st;
|
||||
Buffer *in, *out, *t;
|
||||
PEL *p;
|
||||
|
||||
if( im_rwcheck( im ) )
|
||||
return( -1 );
|
||||
if( im->Coding != IM_CODING_NONE &&
|
||||
im->Coding != IM_CODING_LABQ &&
|
||||
im->Coding != IM_CODING_RAD ) {
|
||||
im_error( "im_flood", "%s",
|
||||
_( "Coding should be NONE, LABQ or RAD" ) );
|
||||
return( -1 );
|
||||
}
|
||||
if( !(st = build_state( im, x, y, ink, dout )) )
|
||||
return( -1 );
|
||||
|
||||
/* Test start pixel ... nothing to do?
|
||||
*/
|
||||
p = (PEL *) im->data + x*st->ps + y*st->ls;
|
||||
if( memcmp( p, ink, st->ps ) == 0 ) {
|
||||
free_state( st );
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
/* Flood to != ink.
|
||||
*/
|
||||
memcpy( st->edge, ink, st->ps );
|
||||
st->equal = 0;
|
||||
|
||||
/* Add start pixel to the work buffer, and loop.
|
||||
*/
|
||||
ADD( st->buf1, x, y )
|
||||
for( in = st->buf1, out = st->buf2;
|
||||
in->n > 0; t = in, in = out, out = t )
|
||||
if( dofill( st, in, out ) ) {
|
||||
free_state( st );
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
free_state( st );
|
||||
|
||||
im_invalidate( im );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
int
|
||||
im_flood_blob_old( IMAGE *im, int x, int y, PEL *ink, Rect *dout )
|
||||
{
|
||||
State *st;
|
||||
Buffer *in, *out, *t;
|
||||
PEL *p;
|
||||
|
||||
if( im_rwcheck( im ) )
|
||||
return( -1 );
|
||||
if( im->Coding != IM_CODING_NONE &&
|
||||
im->Coding != IM_CODING_LABQ &&
|
||||
im->Coding != IM_CODING_RAD ) {
|
||||
im_error( "im_flood", "%s",
|
||||
_( "Coding should be NONE, LABQ or RAD" ) );
|
||||
return( -1 );
|
||||
}
|
||||
if( !(st = build_state( im, x, y, ink, dout )) )
|
||||
return( -1 );
|
||||
|
||||
/* Edge is set by colour of start pixel.
|
||||
*/
|
||||
p = (PEL *) im->data + x*st->ps + y*st->ls;
|
||||
memcpy( st->edge, p, st->ps );
|
||||
st->equal = 1;
|
||||
|
||||
/* Add start pixel to the work buffer, and loop.
|
||||
*/
|
||||
ADD( st->buf1, x, y )
|
||||
for( in = st->buf1, out = st->buf2;
|
||||
in->n > 0; t = in, in = out, out = t )
|
||||
if( dofill( st, in, out ) ) {
|
||||
free_state( st );
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
free_state( st );
|
||||
|
||||
im_invalidate( im );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
/* A Flood blob we can call from nip. Grr! Should be a way to wrap these
|
||||
* automatically. Maybe nip could do it if it sees a RW image argument?
|
||||
*/
|
||||
int
|
||||
im_flood_blob_copy_old( IMAGE *in, IMAGE *out, int x, int y, PEL *ink )
|
||||
{
|
||||
IMAGE *t;
|
||||
|
||||
if( !(t = im_open_local( out, "im_flood_blob_copy", "t" )) ||
|
||||
im_copy( in, t ) ||
|
||||
im_flood_blob_old( t, x, y, ink, NULL ) ||
|
||||
im_copy( t, out ) )
|
||||
return( -1 );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
/* A Flood blob we can call from nip. Grr! Should be a way to wrap these
|
||||
* automatically. Maybe nip could do it if it sees a RW image argument?
|
||||
*/
|
||||
int
|
||||
im_flood_copy_old( IMAGE *in, IMAGE *out, int x, int y, PEL *ink )
|
||||
{
|
||||
IMAGE *t;
|
||||
|
||||
if( !(t = im_open_local( out, "im_flood_copy", "t" )) ||
|
||||
im_copy( in, t ) ||
|
||||
im_flood_old( t, x, y, ink, NULL ) ||
|
||||
im_copy( t, out ) )
|
||||
return( -1 );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -1,330 +0,0 @@
|
||||
/* int im_flood( IMAGE *im, int x, int y, PEL *ink, Rect *dout )
|
||||
*
|
||||
* Flood fill from point (x,y) with colour ink. Flood up to boundary == ink.
|
||||
* Any type, any number of bands, IM_CODING_LABQ too. Returns the bounding box
|
||||
* of the modified pixels in dout, whether it succeeds or not.
|
||||
*
|
||||
* Currently a rather inefficient pixel-based algorithm, should put something
|
||||
* better in, really. Speed isn't likely to be a problem, except for very
|
||||
* large images.
|
||||
*
|
||||
* JC 30/8/97
|
||||
* - VIPSified, cleaned up, from "John Robinson's prog to fill
|
||||
* enclosed areas"
|
||||
* - something Kirk gave me, so thanks John
|
||||
* JC 1/10/97
|
||||
* - swapped inner memcmp/cpy for a loop ... faster for small pixels
|
||||
* 13/7/02 JC
|
||||
* - im_flood_blob() added
|
||||
* 5/12/06
|
||||
* - im_invalidate() after paint
|
||||
* 24/3/09
|
||||
* - added IM_CODING_RAD support
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
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>
|
||||
|
||||
#ifdef WITH_DMALLOC
|
||||
#include <dmalloc.h>
|
||||
#endif /*WITH_DMALLOC*/
|
||||
|
||||
/* Size of a point buffer. We allocate a list of these to hold points we need
|
||||
* to visit.
|
||||
*/
|
||||
#define PBUFSIZE (1000)
|
||||
|
||||
/* An xy position.
|
||||
*/
|
||||
typedef struct {
|
||||
int x, y;
|
||||
} Point;
|
||||
|
||||
/* A buffer of points, and how many of them have been used. When full, alloc a
|
||||
* new buffer, and link it on.
|
||||
*/
|
||||
typedef struct _Buffer {
|
||||
struct _Buffer *next;
|
||||
int n;
|
||||
Point points[PBUFSIZE];
|
||||
} Buffer;
|
||||
|
||||
/* Our state.
|
||||
*/
|
||||
typedef struct {
|
||||
/* Parameters.
|
||||
*/
|
||||
IMAGE *mask;
|
||||
IMAGE *test;
|
||||
int x, y;
|
||||
unsigned int serial;
|
||||
|
||||
/* Derived stuff.
|
||||
*/
|
||||
PEL *edge; /* Searching for these pixels */
|
||||
int ps; /* sizeof( one pel ) */
|
||||
int ls; /* sizeof( one line ) */
|
||||
int left, right; /* Area will fill within */
|
||||
int top, bottom;
|
||||
|
||||
/* Two buffers of points which we know need checking.
|
||||
*/
|
||||
Buffer *buf1;
|
||||
Buffer *buf2;
|
||||
} State;
|
||||
|
||||
/* Alloc a new buffer.
|
||||
*/
|
||||
static Buffer *
|
||||
build_buffer( void )
|
||||
{
|
||||
Buffer *buf = IM_NEW( NULL, Buffer );
|
||||
|
||||
if( !buf )
|
||||
return( NULL );
|
||||
buf->next = NULL;
|
||||
buf->n = 0;
|
||||
|
||||
return( buf );
|
||||
}
|
||||
|
||||
/* Free a chain of buffers.
|
||||
*/
|
||||
static void
|
||||
free_buffer( Buffer *buf )
|
||||
{
|
||||
IM_FREE( buf->next );
|
||||
im_free( buf );
|
||||
}
|
||||
|
||||
/* Free a state.
|
||||
*/
|
||||
static void
|
||||
free_state( State *st )
|
||||
{
|
||||
IM_FREE( st->edge );
|
||||
IM_FREEF( free_buffer, st->buf1 );
|
||||
IM_FREEF( free_buffer, st->buf2 );
|
||||
im_free( st );
|
||||
}
|
||||
|
||||
/* Build a state.
|
||||
*/
|
||||
static State *
|
||||
build_state( IMAGE *mask, IMAGE *test, int x, int y, int serial )
|
||||
{
|
||||
State *st = IM_NEW( NULL, State );
|
||||
|
||||
if( !st )
|
||||
return( NULL );
|
||||
st->mask = mask;
|
||||
st->test = test;
|
||||
st->x = x;
|
||||
st->y = y;
|
||||
st->serial = serial;
|
||||
st->edge = NULL;
|
||||
st->ps = IM_IMAGE_SIZEOF_PEL( test );
|
||||
st->ls = IM_IMAGE_SIZEOF_LINE( test );
|
||||
st->buf1 = NULL;
|
||||
st->buf2 = NULL;
|
||||
st->left = 0;
|
||||
st->top = 0;
|
||||
st->right = test->Xsize;
|
||||
st->bottom = test->Ysize;
|
||||
|
||||
if( !(st->edge = (PEL *) im_malloc( NULL, st->ps )) ||
|
||||
!(st->buf1 = build_buffer()) ||
|
||||
!(st->buf2 = build_buffer()) ) {
|
||||
free_state( st );
|
||||
return( NULL );
|
||||
}
|
||||
|
||||
return( st );
|
||||
}
|
||||
|
||||
/* Add xy to buffer, move buffer on on overflow.
|
||||
*/
|
||||
#define ADD( BUF, X, Y ) { \
|
||||
BUF->points[BUF->n].x = X; \
|
||||
BUF->points[BUF->n].y = Y; \
|
||||
BUF->n++; \
|
||||
if( BUF->n == PBUFSIZE ) { \
|
||||
if( !BUF->next ) { \
|
||||
if( !(BUF->next = build_buffer()) ) \
|
||||
return( -1 ); \
|
||||
} \
|
||||
BUF = BUF->next; \
|
||||
BUF->n = 0; \
|
||||
} \
|
||||
}
|
||||
|
||||
/* If point == blob colour, add it to out.
|
||||
*/
|
||||
#define ADDIFEDGE( P, X, Y ) { \
|
||||
const PEL *p1 = (P); \
|
||||
\
|
||||
for( j = 0; j < st->ps; j++ ) \
|
||||
if( p1[j] != st->edge[j] ) \
|
||||
break; \
|
||||
if( j == st->ps ) \
|
||||
ADD( out, X, Y ); \
|
||||
}
|
||||
|
||||
/* Read points to fill from in, write new points to out.
|
||||
*/
|
||||
static int
|
||||
dofill( State *st, Buffer *in, Buffer *out )
|
||||
{
|
||||
const int width = st->mask->Xsize;
|
||||
|
||||
int i, j;
|
||||
|
||||
/* Clear output buffer.
|
||||
*/
|
||||
out->n = 0;
|
||||
|
||||
/* Loop over chain of input buffers.
|
||||
*/
|
||||
for(;;) {
|
||||
/* Loop for this buffer.
|
||||
*/
|
||||
for( i = 0; i < in->n; i++ ) {
|
||||
/* Find this pixel.
|
||||
*/
|
||||
const int x = in->points[i].x;
|
||||
const int y = in->points[i].y;
|
||||
const PEL *p = (PEL *) st->test->data +
|
||||
x * st->ps + y * st->ls;
|
||||
int *m = (int *) st->mask->data + x + y * width;
|
||||
|
||||
/* Has it been marked already? Done.
|
||||
*/
|
||||
if( *m == st->serial )
|
||||
continue;
|
||||
*m = st->serial;
|
||||
|
||||
/* Propogate to neighbours.
|
||||
*/
|
||||
if( x < st->right - 1 && !m[1] )
|
||||
ADDIFEDGE( p + st->ps, x + 1, y );
|
||||
if( x > st->left && !m[-1] )
|
||||
ADDIFEDGE( p - st->ps, x - 1, y );
|
||||
if( y < st->bottom - 1 && !m[width] )
|
||||
ADDIFEDGE( p + st->ls, x, y + 1 );
|
||||
if( y > st->top && !m[-width] )
|
||||
ADDIFEDGE( p - st->ls, x, y - 1 );
|
||||
}
|
||||
|
||||
if( in->n == PBUFSIZE )
|
||||
/* Buffer full ... must be another one.
|
||||
*/
|
||||
in = in->next;
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
int
|
||||
im_flood_other_old( IMAGE *mask, IMAGE *test, int x, int y, int serial )
|
||||
{
|
||||
State *st;
|
||||
Buffer *in, *out, *t;
|
||||
PEL *p;
|
||||
int *m;
|
||||
|
||||
if( im_rwcheck( mask ) ||
|
||||
im_incheck( test ) )
|
||||
return( -1 );
|
||||
|
||||
if( im_check_coding_known( "im_flood_other", test ) ||
|
||||
im_check_uncoded( "im_flood_other", mask ) ||
|
||||
im_check_mono( "im_flood_other", mask ) ||
|
||||
im_check_format( "im_flood_other", mask, IM_BANDFMT_INT ) ||
|
||||
im_check_size_same( "im_flood_other", test, mask ) )
|
||||
return( -1 );
|
||||
|
||||
/* Make sure the mask has zero at the start position. If it does, we
|
||||
* must have filled with this serial already, so ... job done.
|
||||
*/
|
||||
m = (int *) mask->data + x + y * mask->Xsize;
|
||||
if( *m == serial )
|
||||
return( 0 );
|
||||
|
||||
if( !(st = build_state( mask, test, x, y, serial )) )
|
||||
return( -1 );
|
||||
|
||||
/* Edge is set by colour of start pixel.
|
||||
*/
|
||||
p = (PEL *) test->data + x * st->ps + y * st->ls;
|
||||
memcpy( st->edge, p, st->ps );
|
||||
|
||||
/* Add start pixel to the work buffer, and loop.
|
||||
*/
|
||||
ADD( st->buf1, x, y )
|
||||
for( in = st->buf1, out = st->buf2;
|
||||
in->n > 0; t = in, in = out, out = t )
|
||||
if( dofill( st, in, out ) ) {
|
||||
free_state( st );
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
free_state( st );
|
||||
|
||||
im_invalidate( mask );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
/* A Flood blob we can call from nip. Grr! Should be a way to wrap these
|
||||
* automatically. Maybe nip could do it if it sees a RW image argument?
|
||||
*/
|
||||
int
|
||||
im_flood_other_copy_old( IMAGE *mask, IMAGE *test, IMAGE *out,
|
||||
int x, int y, int serial )
|
||||
{
|
||||
IMAGE *t;
|
||||
|
||||
if( !(t = im_open_local( out, "im_flood_other_copy", "t" )) ||
|
||||
im_copy( mask, t ) ||
|
||||
im_flood_other_old( t, test, x, y, serial ) ||
|
||||
im_copy( t, out ) )
|
||||
return( -1 );
|
||||
|
||||
return( 0 );
|
||||
}
|
@ -188,51 +188,6 @@ vector_to_ink( IMAGE *im, double *vec )
|
||||
return( (PEL *) t[2]->data );
|
||||
}
|
||||
|
||||
/* Args for im_flood_copy_old().
|
||||
*/
|
||||
static im_arg_desc flood_copy_old_args[] = {
|
||||
IM_INPUT_IMAGE( "in" ),
|
||||
IM_OUTPUT_IMAGE( "out" ),
|
||||
IM_INPUT_INT( "start_x" ),
|
||||
IM_INPUT_INT( "start_y" ),
|
||||
IM_INPUT_DOUBLEVEC( "ink" )
|
||||
};
|
||||
|
||||
/* Call im_flood_copy_old() via arg vector.
|
||||
*/
|
||||
static int
|
||||
flood_copy_old_vec( im_object *argv )
|
||||
{
|
||||
IMAGE *in = argv[0];
|
||||
IMAGE *out = argv[1];
|
||||
int start_x = *((int *) argv[2]);
|
||||
int start_y = *((int *) argv[3]);
|
||||
im_doublevec_object *dv = (im_doublevec_object *) argv[4];
|
||||
|
||||
PEL *ink;
|
||||
|
||||
if( dv->n != in->Bands ) {
|
||||
im_error( "im_flood_copy_old",
|
||||
"%s", _( "bad vector length" ) );
|
||||
return( -1 );
|
||||
}
|
||||
if( !(ink = vector_to_ink( in, dv->vec )) )
|
||||
return( -1 );
|
||||
|
||||
return( im_flood_copy_old( in, out, start_x, start_y, ink ) );
|
||||
}
|
||||
|
||||
/* Description of im_flood_old().
|
||||
*/
|
||||
static im_function flood_copy_old_desc = {
|
||||
"im_flood_copy_old", /* Name */
|
||||
"flood with ink from start_x, start_y while pixel == start pixel",
|
||||
0, /* Flags */
|
||||
flood_copy_old_vec, /* Dispatch function */
|
||||
IM_NUMBER( flood_copy_old_args ),/* Size of arg list */
|
||||
flood_copy_old_args /* Arg list */
|
||||
};
|
||||
|
||||
/* Args for im_flood_blob_copy().
|
||||
*/
|
||||
static im_arg_desc flood_blob_copy_args[] = {
|
||||
@ -278,51 +233,6 @@ static im_function flood_blob_copy_desc = {
|
||||
flood_blob_copy_args /* Arg list */
|
||||
};
|
||||
|
||||
/* Args for im_flood_blob_copy_old().
|
||||
*/
|
||||
static im_arg_desc flood_blob_copy_old_args[] = {
|
||||
IM_INPUT_IMAGE( "in" ),
|
||||
IM_OUTPUT_IMAGE( "out" ),
|
||||
IM_INPUT_INT( "start_x" ),
|
||||
IM_INPUT_INT( "start_y" ),
|
||||
IM_INPUT_DOUBLEVEC( "ink" )
|
||||
};
|
||||
|
||||
/* Call im_flood_blob_copy_old() via arg vector.
|
||||
*/
|
||||
static int
|
||||
flood_blob_copy_old_vec( im_object *argv )
|
||||
{
|
||||
IMAGE *in = argv[0];
|
||||
IMAGE *out = argv[1];
|
||||
int start_x = *((int *) argv[2]);
|
||||
int start_y = *((int *) argv[3]);
|
||||
im_doublevec_object *dv = (im_doublevec_object *) argv[4];
|
||||
|
||||
PEL *ink;
|
||||
|
||||
if( dv->n != in->Bands ) {
|
||||
im_error( "im_flood_blob_copy_old",
|
||||
"%s", _( "bad vector length" ) );
|
||||
return( -1 );
|
||||
}
|
||||
if( !(ink = vector_to_ink( in, dv->vec )) )
|
||||
return( -1 );
|
||||
|
||||
return( im_flood_blob_copy_old( in, out, start_x, start_y, ink ) );
|
||||
}
|
||||
|
||||
/* Description of im_flood_blob_copy_old().
|
||||
*/
|
||||
static im_function flood_blob_copy_old_desc = {
|
||||
"im_flood_blob_copy_old", /* Name */
|
||||
"flood with ink from start_x, start_y while pixel == start pixel",
|
||||
0, /* Flags */
|
||||
flood_blob_copy_old_vec, /* Dispatch function */
|
||||
IM_NUMBER( flood_blob_copy_old_args ),/* Size of arg list */
|
||||
flood_blob_copy_old_args /* Arg list */
|
||||
};
|
||||
|
||||
/* Args for im_flood_copy().
|
||||
*/
|
||||
static im_arg_desc flood_copy_args[] = {
|
||||
@ -406,44 +316,6 @@ static im_function flood_other_copy_desc = {
|
||||
flood_other_copy_args /* Arg list */
|
||||
};
|
||||
|
||||
/* Args for im_flood_other_copy_old().
|
||||
*/
|
||||
static im_arg_desc flood_other_copy_old_args[] = {
|
||||
IM_INPUT_IMAGE( "mask" ),
|
||||
IM_INPUT_IMAGE( "test" ),
|
||||
IM_OUTPUT_IMAGE( "out" ),
|
||||
IM_INPUT_INT( "start_x" ),
|
||||
IM_INPUT_INT( "start_y" ),
|
||||
IM_INPUT_INT( "serial" )
|
||||
};
|
||||
|
||||
/* Call im_flood_other_copy_old() via arg vector.
|
||||
*/
|
||||
static int
|
||||
flood_other_copy_old_vec( im_object *argv )
|
||||
{
|
||||
IMAGE *mask = argv[0];
|
||||
IMAGE *test = argv[1];
|
||||
IMAGE *out = argv[2];
|
||||
int start_x = *((int *) argv[3]);
|
||||
int start_y = *((int *) argv[4]);
|
||||
int serial = *((int *) argv[5]);
|
||||
|
||||
return( im_flood_other_copy_old( mask, test, out,
|
||||
start_x, start_y, serial ) );
|
||||
}
|
||||
|
||||
/* Description of im_flood_other_copy_old().
|
||||
*/
|
||||
static im_function flood_other_copy_old_desc = {
|
||||
"im_flood_other_copy_old", /* Name */
|
||||
"flood mask with serial number from start_x, start_y while pixel == start pixel",
|
||||
0, /* Flags */
|
||||
flood_other_copy_old_vec, /* Dispatch function */
|
||||
IM_NUMBER( flood_other_copy_old_args ),/* Size of arg list */
|
||||
flood_other_copy_old_args /* Arg list */
|
||||
};
|
||||
|
||||
/* To do:
|
||||
* these all need some kind of pel type
|
||||
*
|
||||
@ -463,9 +335,6 @@ static im_function *inplace_list[] = {
|
||||
&flood_copy_desc,
|
||||
&flood_blob_copy_desc,
|
||||
&flood_other_copy_desc,
|
||||
&flood_copy_old_desc,
|
||||
&flood_blob_copy_old_desc,
|
||||
&flood_other_copy_old_desc,
|
||||
&insertplace_desc,
|
||||
&lineset_desc
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user