From aad2eb8703204f9820f723a0d17a1b4cd236f909 Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Mon, 27 Sep 2010 17:14:22 +0000 Subject: [PATCH] line drawing --- ChangeLog | 2 + libvips/deprecated/rename.c | 9 + libvips/include/vips/almostdeprecated.h | 3 + libvips/include/vips/inplace.h | 22 +- libvips/inplace/Makefile.am | 6 +- libvips/inplace/draw.c | 103 +++++ libvips/inplace/draw.h | 91 +++++ libvips/inplace/flood.c | 87 ++--- libvips/inplace/im_draw_circle.c | 144 ++----- libvips/inplace/im_draw_line.c | 423 +++++++++++++++++++++ libvips/inplace/im_draw_rect.c | 23 +- libvips/inplace/inplace_dispatch.c | 8 +- libvips/inplace/line_draw.c | 478 ------------------------ 13 files changed, 736 insertions(+), 663 deletions(-) create mode 100644 libvips/inplace/draw.c create mode 100644 libvips/inplace/draw.h create mode 100644 libvips/inplace/im_draw_line.c delete mode 100644 libvips/inplace/line_draw.c diff --git a/ChangeLog b/ChangeLog index cd052d76..8f7e8ebd 100644 --- a/ChangeLog +++ b/ChangeLog @@ -24,6 +24,8 @@ nip2 can call inplace ops directly now - added im_draw_rect(), moved im_paintrect() to deprecated - added im_draw_image(), moved im_insertplace() to deprecated +- added im_draw_line(), now clips, moved im_fastline() to deprecated +- added im_draw_line_user(), now clips, moved im_fastlineuser() to deprecated 12/5/10 started 7.22.2 - the conditional image of ifthenelse can be any format, a (!=0) is added if diff --git a/libvips/deprecated/rename.c b/libvips/deprecated/rename.c index 2c8ec669..5634b3ec 100644 --- a/libvips/deprecated/rename.c +++ b/libvips/deprecated/rename.c @@ -524,3 +524,12 @@ im_fastline( IMAGE *im, int x1, int y1, int x2, int y2, PEL *pel ) { return( im_draw_line( im, x1, y1, x2, y2, pel ) ); } + +int +im_fastlineuser( IMAGE *im, + int x1, int y1, int x2, int y2, + int (*fn)(), void *client1, void *client2, void *client3 ) +{ + return( im_draw_line_user( im, x1, y1, x2, y2, + fn, client1, client2, client3 ) ); +} diff --git a/libvips/include/vips/almostdeprecated.h b/libvips/include/vips/almostdeprecated.h index 19f7ea1b..ff0524e8 100644 --- a/libvips/include/vips/almostdeprecated.h +++ b/libvips/include/vips/almostdeprecated.h @@ -240,6 +240,9 @@ int im_flood_other_copy( IMAGE *test, IMAGE *mark, IMAGE *out, int x, int y, int serial ); int im_fastline( IMAGE *im, int x1, int y1, int x2, int y2, PEL *pel ); +int im_fastlineuser( IMAGE *im, + int x1, int y1, int x2, int y2, + int (*fn)(), void *client1, void *client2, void *client3 ); #ifdef __cplusplus } diff --git a/libvips/include/vips/inplace.h b/libvips/include/vips/inplace.h index f9987d2b..35415631 100644 --- a/libvips/include/vips/inplace.h +++ b/libvips/include/vips/inplace.h @@ -37,30 +37,32 @@ extern "C" { #endif /*__cplusplus*/ -int im_plotmask( IMAGE *im, int ix, int iy, PEL *ink, PEL *mask, Rect *r ); -int im_smear( IMAGE *im, int ix, int iy, Rect *r ); -int im_smudge( IMAGE *im, int ix, int iy, Rect *r ); - int im_draw_rect( IMAGE *image, int left, int top, int width, int height, int fill, PEL *ink ); int im_draw_circle( IMAGE *im, int cx, int cy, int radius, gboolean fill, PEL *ink ); int im_draw_image( IMAGE *main, int x, int y, IMAGE *sub ); -int im_draw_line( IMAGE *im, int x1, int y1, int x2, int y2, PEL *pel ); -int im_fastlineuser( IMAGE *im, +typedef int (*VipsPlotFn)( VipsImage *im, int x, int y, + void *a, void *b, void *c ); +int im_draw_line_user( VipsImage *im, int x1, int y1, int x2, int y2, - int (*fn)(), void *client1, void *client2, void *client3 ); -int im_readpoint( IMAGE *im, int x, int y, PEL *pel ); + VipsPlotFn plot, void *a, void *b, void *c ); +int im_draw_line( VipsImage *im, int x1, int y1, int x2, int y2, PEL *ink ); +int im_lineset( IMAGE *in, IMAGE *out, IMAGE *mask, IMAGE *ink, + int n, int *x1v, int *y1v, int *x2v, int *y2v ); int im_flood( IMAGE *im, int x, int y, PEL *ink, Rect *dout ); int im_flood_blob( IMAGE *im, int x, int y, PEL *ink, Rect *dout ); int im_flood_other( IMAGE *test, IMAGE *mark, int x, int y, int serial, Rect *dout ); -int im_lineset( IMAGE *in, IMAGE *out, IMAGE *mask, IMAGE *ink, - int n, int *x1v, int *y1v, int *x2v, int *y2v ); +int im_readpoint( IMAGE *im, int x, int y, PEL *pel ); + +int im_plotmask( IMAGE *im, int ix, int iy, PEL *ink, PEL *mask, Rect *r ); +int im_smear( IMAGE *im, int ix, int iy, Rect *r ); +int im_smudge( IMAGE *im, int ix, int iy, Rect *r ); #ifdef __cplusplus } diff --git a/libvips/inplace/Makefile.am b/libvips/inplace/Makefile.am index b6c38168..afdeb48b 100644 --- a/libvips/inplace/Makefile.am +++ b/libvips/inplace/Makefile.am @@ -1,13 +1,15 @@ noinst_LTLIBRARIES = libinplace.la libinplace_la_SOURCES = \ + draw.c \ + draw.h \ im_draw_circle.c \ - flood.c \ + im_draw_line.c \ im_draw_image.c \ im_draw_rect.c \ + flood.c \ im_plotmask.c \ inplace_dispatch.c \ - line_draw.c \ plot_point.c \ smudge_area.c diff --git a/libvips/inplace/draw.c b/libvips/inplace/draw.c new file mode 100644 index 00000000..c92403b6 --- /dev/null +++ b/libvips/inplace/draw.c @@ -0,0 +1,103 @@ +/* base class for drawing operations + * + * 27/9/10 + * - from im_draw_circle() + */ + +/* + + 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 +#endif /*HAVE_CONFIG_H*/ +#include + +#include + +#include + +#include "draw.h" + +#ifdef WITH_DMALLOC +#include +#endif /*WITH_DMALLOC*/ + +/* Fill a scanline between points x1 and x2 inclusive. x1 < x2. + */ +void +im__draw_scanline( Draw *draw, int y, int x1, int x2 ) +{ + PEL *mp; + int i; + int len; + + g_assert( x1 <= x2 ); + + if( y < 0 || y > draw->im->Ysize ) + return; + if( x1 < 0 && x2 < 0 ) + return; + if( x1 > draw->im->Xsize && x2 > draw->im->Xsize ) + return; + x1 = IM_CLIP( 0, x1, draw->im->Xsize - 1 ); + x2 = IM_CLIP( 0, x2, draw->im->Xsize - 1 ); + + mp = (PEL *) IM_IMAGE_ADDR( draw->im, x1, y ); + len = x2 - x1 + 1; + + for( i = 0; i < len; i++ ) { + im__draw_pel( draw, mp ); + mp += draw->psize; + } +} + +void +im__draw_free( Draw *draw ) +{ + IM_FREE( draw->ink ); +} + +Draw * +im__draw_init( Draw *draw, IMAGE *im, PEL *ink ) +{ + if( im_rwcheck( im ) ) + return( NULL ); + + draw->im = im; + draw->ink = NULL; + + draw->lsize = IM_IMAGE_SIZEOF_LINE( im ); + draw->psize = IM_IMAGE_SIZEOF_PEL( im ); + draw->noclip = FALSE; + + if( ink ) { + if( !(draw->ink = (PEL *) im_malloc( NULL, draw->psize )) ) + return( NULL ); + memcpy( draw->ink, ink, draw->psize ); + } + + return( draw ); +} diff --git a/libvips/inplace/draw.h b/libvips/inplace/draw.h new file mode 100644 index 00000000..34f508d9 --- /dev/null +++ b/libvips/inplace/draw.h @@ -0,0 +1,91 @@ +/* base class for drawing operations + */ + +/* + + 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 + + */ + +/* Our state. + */ +typedef struct _Draw { + /* Parameters. + */ + IMAGE *im; /* Draw here */ + PEL *ink; /* Copy of ink param */ + + /* Derived stuff. + */ + size_t lsize; + size_t psize; + + /* If the object to draw is entirely within the image, we have a + * faster noclip path. + */ + gboolean noclip; +} Draw; + +#define DRAW(X) ((Draw *)(X)) + +static inline void +im__draw_pel( Draw *draw, PEL *q ) +{ + int j; + + /* Faster than memcopy() for n < about 20. + */ + for( j = 0; j < draw->psize; j++ ) + q[j] = draw->ink[j]; +} + +/* Paint, with clip. + */ +static inline void +im__draw_pel_clip( Draw *draw, int x, int y ) +{ + if( x < 0 || x >= draw->im->Xsize ) + return; + if( y < 0 || y >= draw->im->Ysize ) + return; + + im__draw_pel( draw, (PEL *) IM_IMAGE_ADDR( draw->im, x, y ) ); +} + +/* Is p painted? + */ +static inline gboolean +im__draw_painted( Draw *draw, PEL *p ) +{ + int j; + + for( j = 0; j < draw->psize; j++ ) + if( p[j] != draw->ink[j] ) + break; + + return( j == draw->psize ); +} + +void im__draw_scanline( Draw *draw, int y, int x1, int x2 ); +void im__draw_free( Draw *draw ); +Draw *im__draw_init( Draw *draw, IMAGE *im, PEL *ink ); diff --git a/libvips/inplace/flood.c b/libvips/inplace/flood.c index 9ac6ca71..fc5437e5 100644 --- a/libvips/inplace/flood.c +++ b/libvips/inplace/flood.c @@ -26,6 +26,8 @@ * 6/3/10 * - don't im_invalidate() after paint, this now needs to be at a higher * level + * 27/9/10 + * - use Draw base class */ /* @@ -65,6 +67,8 @@ #include +#include "draw.h" + #ifdef WITH_DMALLOC #include #endif /*WITH_DMALLOC*/ @@ -105,12 +109,12 @@ typedef struct _Buffer { /* Our state. */ typedef struct { + Draw draw; + /* Parameters. */ IMAGE *test; /* Test this image */ - IMAGE *mark; /* Mark this image */ int x, y; - PEL *ink; /* Copy of ink param */ Rect *dout; /* Write dirty here at end */ /* Derived stuff. @@ -118,7 +122,6 @@ typedef struct { PEL *edge; /* Boundary colour */ int equal; /* Fill to == edge, or != edge */ int tsize; /* sizeof( one pel in test ) */ - int msize; /* sizeof( one pel in mark ) */ int left, right; /* Record bounding box of modified pixels */ int top, bottom; @@ -208,48 +211,22 @@ flood_connected( Flood *flood, PEL *tp ) return( flood->equal ^ (j < flood->tsize) ); } -/* Is p painted? - */ -static inline gboolean -flood_painted( Flood *flood, PEL *mp ) -{ - int j; - - for( j = 0; j < flood->msize; j++ ) - if( mp[j] != flood->ink[j] ) - break; - - return( j == flood->msize ); -} - -/* Faster than memcpy for n < about 20. - */ -static inline void -flood_paint( Flood *flood, PEL *q ) -{ - int j; - - for( j = 0; j < flood->msize; j++ ) - q[j] = flood->ink[j]; -} - /* Fill left and right, return the endpoints. The start point (x, y) must be * connected and unpainted. */ static void flood_scanline( Flood *flood, int x, int y, int *x1, int *x2 ) { - const int width = flood->mark->Xsize; + Draw *draw = DRAW( flood ); + const int width = flood->test->Xsize; PEL *tp; - PEL *mp; int i; - int len; g_assert( flood_connected( flood, (PEL *) IM_IMAGE_ADDR( flood->test, x, y ) ) ); - g_assert( !flood_painted( flood, - (PEL *) IM_IMAGE_ADDR( flood->mark, x, y ) ) ); + g_assert( !im__draw_painted( draw, + (PEL *) IM_IMAGE_ADDR( draw->im, x, y ) ) ); /* Search to the right for the first non-connected pixel. If the start * pixel is unpainted, we know all the intervening pixels must be @@ -275,12 +252,7 @@ flood_scanline( Flood *flood, int x, int y, int *x1, int *x2 ) /* Paint the range we discovered. */ - mp = (PEL *) IM_IMAGE_ADDR( flood->mark, *x1, y ); - len = *x2 - *x1 + 1; - for( i = 0; i < len; i++ ) { - flood_paint( flood, mp ); - mp += flood->msize; - } + im__draw_scanline( DRAW( flood ), y, *x1, *x2 ); if( flood->dout ) { flood->left = IM_MIN( flood->left, *x1 ); @@ -296,6 +268,8 @@ flood_scanline( Flood *flood, int x, int y, int *x1, int *x2 ) static void flood_around( Flood *flood, Scan *scan ) { + Draw *draw = DRAW( flood ); + PEL *tp; int x; @@ -313,11 +287,11 @@ flood_around( Flood *flood, Scan *scan ) * to check for painted. Otherwise we can get stuck in * connected loops. */ - if( flood->mark != flood->test ) { + if( draw->im != flood->test ) { PEL *mp = (PEL *) IM_IMAGE_ADDR( - flood->mark, x, scan->y ); + draw->im, x, scan->y ); - if( flood_painted( flood, mp ) ) + if( im__draw_painted( draw, mp ) ) continue; } @@ -388,7 +362,7 @@ flood_free( Flood *flood ) flood->dout->height = flood->bottom - flood->top + 1; } - IM_FREE( flood->ink ); + im__draw_free( DRAW( flood ) ); IM_FREE( flood->edge ); IM_FREEF( buffer_free, flood->in ); IM_FREEF( buffer_free, flood->out ); @@ -402,15 +376,17 @@ flood_new( IMAGE *test, IMAGE *mark, int x, int y, PEL *ink, Rect *dout ) if( !(flood = IM_NEW( NULL, Flood )) ) return( NULL ); + if( !im__draw_init( DRAW( flood ), mark, ink ) ) { + flood_free( flood ); + return( NULL ); + } + flood->test = test; - flood->mark = mark; flood->x = x; flood->y = y; - flood->ink = NULL; flood->dout = dout; flood->edge = NULL; flood->tsize = IM_IMAGE_SIZEOF_PEL( test ); - flood->msize = IM_IMAGE_SIZEOF_PEL( mark ); flood->left = x; flood->top = y; flood->right = x; @@ -419,14 +395,12 @@ flood_new( IMAGE *test, IMAGE *mark, int x, int y, PEL *ink, Rect *dout ) flood->in = NULL; flood->out = NULL; - if( !(flood->ink = (PEL *) im_malloc( NULL, flood->msize )) || - !(flood->edge = (PEL *) im_malloc( NULL, flood->tsize )) || + if( !(flood->edge = (PEL *) im_malloc( NULL, flood->tsize )) || !(flood->in = buffer_build()) || !(flood->out = buffer_build()) ) { flood_free( flood ); return( NULL ); } - memcpy( flood->ink, ink, flood->msize ); return( flood ); } @@ -459,10 +433,8 @@ im_flood( IMAGE *im, int x, int y, PEL *ink, Rect *dout ) { Flood *flood; - if( im_rwcheck( im ) || - im_check_coding_known( "im_flood", im ) ) - return( -1 ); - if( !(flood = flood_new( im, im, x, y, ink, dout )) ) + if( im_check_coding_known( "im_flood", im ) || + !(flood = flood_new( im, im, x, y, ink, dout )) ) return( -1 ); /* Flood to != ink. @@ -506,10 +478,8 @@ im_flood_blob( IMAGE *im, int x, int y, PEL *ink, Rect *dout ) Flood *flood; int j; - if( im_rwcheck( im ) || - im_check_coding_known( "im_flood", im ) ) - return( -1 ); - if( !(flood = flood_new( im, im, x, y, ink, dout )) ) + if( im_check_coding_known( "im_flood", im ) || + !(flood = flood_new( im, im, x, y, ink, dout )) ) return( -1 ); /* Edge is set by colour of start pixel. @@ -521,7 +491,7 @@ im_flood_blob( IMAGE *im, int x, int y, PEL *ink, Rect *dout ) * do. */ for( j = 0; j < flood->tsize; j++ ) - if( flood->edge[j] != flood->ink[j] ) + if( flood->edge[j] != DRAW( flood )->ink[j] ) break; if( j == flood->tsize ) return( 0 ); @@ -565,7 +535,6 @@ im_flood_other( IMAGE *test, IMAGE *mark, int x, int y, int serial, Rect *dout ) Flood *flood; if( im_incheck( test ) || - im_rwcheck( mark ) || im_check_coding_known( "im_flood_other", test ) || im_check_uncoded( "im_flood_other", mark ) || im_check_mono( "im_flood_other", mark ) || diff --git a/libvips/inplace/im_draw_circle.c b/libvips/inplace/im_draw_circle.c index 0132dd1f..768e0964 100644 --- a/libvips/inplace/im_draw_circle.c +++ b/libvips/inplace/im_draw_circle.c @@ -15,6 +15,8 @@ * 18/8/10 * - gtkdoc * - rewritten: clips, fills, any bands, any format + * 27/9/10 + * - break base out to Draw */ /* @@ -52,6 +54,8 @@ #include +#include "draw.h" + #ifdef WITH_DMALLOC #include #endif /*WITH_DMALLOC*/ @@ -59,124 +63,66 @@ /* Our state. */ typedef struct { + Draw draw; + /* Parameters. */ - IMAGE *im; /* Test this image */ int cx, cy; int radius; gboolean fill; - PEL *ink; /* Copy of ink param */ /* Derived stuff. */ - size_t lsize; - size_t psize; PEL *centre; - - /* If the circle is entirely within the image, we have a faster - * noclip path. - */ - gboolean noclip; } Circle; -/* Faster than memcpy for n < about 20. - */ -static inline void -circle_paint_pel( Circle *circle, PEL *q ) -{ - int j; - - for( j = 0; j < circle->psize; j++ ) - q[j] = circle->ink[j]; -} - -/* Paint, with clip. - */ -static void -circle_paint_pel_clip( Circle *circle, int x, int y ) -{ - if( x < 0 || x >= circle->im->Xsize ) - return; - if( y < 0 || y >= circle->im->Ysize ) - return; - - circle_paint_pel( circle, (PEL *) IM_IMAGE_ADDR( circle->im, x, y ) ); -} - -/* Fill a scanline between points x1 and x2 inclusive. x1 < x2. - */ -static void -circle_paint_scanline( Circle *circle, int y, int x1, int x2 ) -{ - PEL *mp; - int i; - int len; - - g_assert( x1 <= x2 ); - - if( y < 0 || y > circle->im->Ysize ) - return; - if( x1 < 0 && x2 < 0 ) - return; - if( x1 > circle->im->Xsize && x2 > circle->im->Xsize ) - return; - x1 = IM_CLIP( 0, x1, circle->im->Xsize - 1 ); - x2 = IM_CLIP( 0, x2, circle->im->Xsize - 1 ); - - mp = (PEL *) IM_IMAGE_ADDR( circle->im, x1, y ); - len = x2 - x1 + 1; - - for( i = 0; i < len; i++ ) { - circle_paint_pel( circle, mp ); - mp += circle->psize; - } -} - static void circle_octants( Circle *circle, int x, int y ) { + Draw *draw = DRAW( circle ); + if( circle->fill ) { const int cx = circle->cx; const int cy = circle->cy; - circle_paint_scanline( circle, cy + y, cx - x, cx + x ); - circle_paint_scanline( circle, cy - y, cx - x, cx + x ); - circle_paint_scanline( circle, cy + x, cx - y, cx + y ); - circle_paint_scanline( circle, cy - x, cx - y, cx + y ); + im__draw_scanline( draw, cy + y, cx - x, cx + x ); + im__draw_scanline( draw, cy - y, cx - x, cx + x ); + im__draw_scanline( draw, cy + x, cx - y, cx + y ); + im__draw_scanline( draw, cy - x, cx - y, cx + y ); } - else if( circle->noclip ) { - const size_t lsize = circle->lsize; - const size_t psize = circle->psize; + else if( DRAW( circle )->noclip ) { + const size_t lsize = draw->lsize; + const size_t psize = draw->psize; PEL *centre = circle->centre; - circle_paint_pel( circle, centre + lsize * y - psize * x ); - circle_paint_pel( circle, centre + lsize * y + psize * x ); - circle_paint_pel( circle, centre - lsize * y - psize * x ); - circle_paint_pel( circle, centre - lsize * y + psize * x ); - circle_paint_pel( circle, centre + lsize * x - psize * y ); - circle_paint_pel( circle, centre + lsize * x + psize * y ); - circle_paint_pel( circle, centre - lsize * x - psize * y ); - circle_paint_pel( circle, centre - lsize * x + psize * y ); + im__draw_pel( draw, centre + lsize * y - psize * x ); + im__draw_pel( draw, centre + lsize * y + psize * x ); + im__draw_pel( draw, centre - lsize * y - psize * x ); + im__draw_pel( draw, centre - lsize * y + psize * x ); + im__draw_pel( draw, centre + lsize * x - psize * y ); + im__draw_pel( draw, centre + lsize * x + psize * y ); + im__draw_pel( draw, centre - lsize * x - psize * y ); + im__draw_pel( draw, centre - lsize * x + psize * y ); } else { const int cx = circle->cx; const int cy = circle->cy; - circle_paint_pel_clip( circle, cx + y, cy - x ); - circle_paint_pel_clip( circle, cx + y, cy + x ); - circle_paint_pel_clip( circle, cx - y, cy - x ); - circle_paint_pel_clip( circle, cx - y, cy + x ); - circle_paint_pel_clip( circle, cx + x, cy - y ); - circle_paint_pel_clip( circle, cx + x, cy + y ); - circle_paint_pel_clip( circle, cx - x, cy - y ); - circle_paint_pel_clip( circle, cx - x, cy + y ); + im__draw_pel_clip( draw, cx + y, cy - x ); + im__draw_pel_clip( draw, cx + y, cy + x ); + im__draw_pel_clip( draw, cx - y, cy - x ); + im__draw_pel_clip( draw, cx - y, cy + x ); + im__draw_pel_clip( draw, cx + x, cy - y ); + im__draw_pel_clip( draw, cx + x, cy + y ); + im__draw_pel_clip( draw, cx - x, cy - y ); + im__draw_pel_clip( draw, cx - x, cy + y ); } } static void circle_free( Circle *circle ) { - IM_FREE( circle->ink ); + im__draw_free( DRAW( circle ) ); im_free( circle ); } @@ -187,33 +133,26 @@ circle_new( IMAGE *im, int cx, int cy, int radius, gboolean fill, PEL *ink ) if( !(circle = IM_NEW( NULL, Circle )) ) return( NULL ); - circle->im = im; + if( !im__draw_init( DRAW( circle ), im, ink ) ) { + circle_free( circle ); + return( NULL ); + } + circle->cx = cx; circle->cy = cy; circle->radius = radius; circle->fill = fill; - circle->ink = NULL; - - circle->lsize = IM_IMAGE_SIZEOF_LINE( im ); - circle->psize = IM_IMAGE_SIZEOF_PEL( im ); circle->centre = (PEL *) IM_IMAGE_ADDR( im, cx, cy ); - circle->noclip = FALSE; - - if( !(circle->ink = (PEL *) im_malloc( NULL, circle->psize )) ) { - circle_free( circle ); - return( NULL ); - } - memcpy( circle->ink, ink, circle->psize ); if( cx - radius >= 0 && cx + radius < im->Xsize && cy - radius >= 0 && cy + radius < im->Ysize ) - circle->noclip = TRUE; + DRAW( circle )->noclip = TRUE; return( circle ); } static void -circle_paint( Circle *circle ) +circle_draw( Circle *circle ) { int x, y, d; @@ -267,11 +206,10 @@ im_draw_circle( IMAGE *im, int cx, int cy, int radius, gboolean fill, PEL *ink ) cy + radius < 0 || cy - radius >= im->Ysize ) return( 0 ); - if( im_rwcheck( im ) || - im_check_coding_known( "im_draw_circle", im ) || + if( im_check_coding_known( "im_draw_circle", im ) || !(circle = circle_new( im, cx, cy, radius, fill, ink )) ) return( -1 ); - circle_paint( circle ); + circle_draw( circle ); circle_free( circle ); return( 0 ); diff --git a/libvips/inplace/im_draw_line.c b/libvips/inplace/im_draw_line.c new file mode 100644 index 00000000..1295abff --- /dev/null +++ b/libvips/inplace/im_draw_line.c @@ -0,0 +1,423 @@ +/* draw straight lines + * + * Copyright: J. Cupitt + * Written: 15/06/1992 + * Modified : 22/10/92 - clipping constraints changed + * 22/7/93 JC + * - im_incheck() added + * 16/8/94 JC + * - im_incheck() changed to im_makerw() + * 5/12/06 + * - im_invalidate() after paint + * 1/3/10 + * - oops, lineset needs to ask for WIO of mask and ink + * 6/3/10 + * - don't im_invalidate() after paint, this now needs to be at a higher + * level + * 27/9/10 + * - gtk-doc + * - use draw.c base class + * - do pointwise clipping + * - rename as im_draw_line() for consistency + * - 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 +#endif /*HAVE_CONFIG_H*/ +#include + +#include +#include + +#include + +#include "draw.h" + +#ifdef WITH_DMALLOC +#include +#endif /*WITH_DMALLOC*/ + +#define SWAP(A,B) {int t; t = (A); (A) = (B); (B) = t;} + +typedef struct _Line { + Draw draw; + + int x1, y1; + int x2, y2; + + int dx; + int dy; + + VipsPlotFn plot; + void *a; + void *b; + void *c; +} Line; + +static void +line_free( Line *line ) +{ + im__draw_free( DRAW( line ) ); + im_free( line ); +} + +static Line * +line_new( VipsImage *im, int x1, int y1, int x2, int y2, PEL *ink ) +{ + Line *line; + + if( !(line = IM_NEW( NULL, Line )) ) + return( NULL ); + if( !im__draw_init( DRAW( line ), im, ink ) ) { + line_free( line ); + return( NULL ); + } + + /* Find offsets. + */ + line->dx = x2 - x1; + line->dy = y2 - y1; + + /* Swap endpoints to reduce number of cases. + */ + if( abs( line->dx ) >= abs( line->dy ) && line->dx < 0 ) { + /* Swap to get all x greater or equal cases going to the + * right. Do diagonals here .. just have up and right and down + * and right now. + */ + SWAP( x1, x2 ); + SWAP( y1, y2 ); + } + else if( abs( line->dx ) < abs( line->dy ) && line->dy < 0 ) { + /* Swap to get all y greater cases going down the screen. + */ + SWAP( x1, x2 ); + SWAP( y1, y2 ); + } + + /* Recalculate dx, dy. + */ + line->dx = x2 - x1; + line->dy = y2 - y1; + + line->x1 = x1; + line->y1 = y1; + line->x2 = x2; + line->y2 = y2; + + line->plot = NULL; + line->a = NULL; + line->b = NULL; + line->c = NULL; + + if( x1 < im->Xsize && x1 >= 0 && + x2 < im->Xsize && x2 >= 0 && + y1 < im->Ysize && y1 >= 0 && + y2 < im->Ysize && y2 >= 0 ) + DRAW( line )->noclip = TRUE; + + return( line ); +} + +static inline int +line_plot( Line *line, int x, int y ) +{ + return( line->plot( DRAW( line )->im, x, y, + line->a, line->b, line->c ) ); +} + +static int +line_draw( Line *line ) +{ + int x, y, err; + + /* Start point and offset. + */ + x = line->x1; + y = line->y1; + + /* Special case: zero width and height is single point. + */ + if( line->dx == 0 && line->dy == 0 ) { + if( line_plot( line, x, y ) ) + return( -1 ); + } + /* Special case vertical and horizontal lines for speed. + */ + else if( line->dx == 0 ) { + /* Vertical line going down. + */ + for( ; y <= line->y2; y++ ) { + if( line_plot( line, x, y ) ) + return( -1 ); + } + } + else if( line->dy == 0 ) { + /* Horizontal line to the right. + */ + for( ; x <= line->x2; x++ ) { + if( line_plot( line, x, y ) ) + return( -1 ); + } + } + /* Special case diagonal lines. + */ + else if( abs( line->dy ) == abs( line->dx ) && line->dy > 0 ) { + /* Diagonal line going down and right. + */ + for( ; x <= line->x2; x++, y++ ) { + if( line_plot( line, x, y ) ) + return( -1 ); + } + } + else if( abs( line->dy ) == abs( line->dx ) && line->dy < 0 ) { + /* Diagonal line going up and right. + */ + for( ; x <= line->x2; x++, y-- ) { + if( line_plot( line, x, y ) ) + return( -1 ); + } + } + else if( abs( line->dy ) < abs( line->dx ) && line->dy > 0 ) { + /* Between -45 and 0 degrees. + */ + for( err = 0; x <= line->x2; x++ ) { + if( line_plot( line, x, y ) ) + return( -1 ); + + err += line->dy; + if( err >= line->dx ) { + err -= line->dx; + y++; + } + } + } + else if( abs( line->dy ) < abs( line->dx ) && line->dy < 0 ) { + /* Between 0 and 45 degrees. + */ + for( err = 0; x <= line->x2; x++ ) { + if( line_plot( line, x, y ) ) + return( -1 ); + + err -= line->dy; + if( err >= line->dx ) { + err -= line->dx; + y--; + } + } + } + else if( abs( line->dy ) > abs( line->dx ) && line->dx > 0 ) { + /* Between -45 and -90 degrees. + */ + for( err = 0; y <= line->y2; y++ ) { + if( line_plot( line, x, y ) ) + return( -1 ); + + err += line->dx; + if( err >= line->dy ) { + err -= line->dy; + x++; + } + } + } + else if( abs( line->dy ) > abs( line->dx ) && line->dx < 0 ) { + /* Between -90 and -135 degrees. + */ + for( err = 0; y <= line->y2; y++ ) { + if( line_plot( line, x, y ) ) + return( -1 ); + + err -= line->dx; + if( err >= line->dy ) { + err -= line->dy; + x--; + } + } + } + else + g_assert( 0 ); + + return( 0 ); +} + +/** + * im_draw_line_user: + * @im: image to draw on + * @x1: start point + * @y1: start point + * @x2: end point + * @y2: end point + * @ink: value to draw + * + * Draws a 1-pixel-wide line on an image. @x1, @y1 and @x2, @y2 must be + * within the image. + * + * @ink is an array of bytes + * containing a valid pixel for the image's format. + * It must have at least IM_IMAGE_SIZEOF_PEL( @im ) bytes. + * + * See also: im_draw_circle(). + * + * Returns: 0 on success, or -1 on error. + */ + +/* Draw a line on a image with a user plot function. We do no clipping: the + * user function should check ranges for each pixel when it is called. + */ +int +im_draw_line_user( VipsImage *im, + int x1, int y1, int x2, int y2, + VipsPlotFn plot, void *a, void *b, void *c ) +{ + Line *line; + + if( im_check_coding_known( "im_draw_line", im ) || + !(line = line_new( im, x1, y1, x2, y2, NULL )) ) + return( -1 ); + + line->plot = plot; + line->a = a; + line->b = b; + line->c = c; + + if( line_draw( line ) ) { + line_free( line ); + return( -1 ); + } + line_free( line ); + + return( 0 ); +} + +static int +line_plot_point( VipsImage *im, int x, int y, + void *a, void *b, void *c ) +{ + Draw *draw = (Draw *) a; + + if( draw->noclip ) + im__draw_pel( draw, (PEL *) IM_IMAGE_ADDR( draw->im, x, y ) ); + else + im__draw_pel_clip( draw, x, y ); + + return( 0 ); +} + +/** + * im_draw_line: + * @im: image to draw on + * @x1: start point + * @y1: start point + * @x2: end point + * @y2: end point + * @ink: value to draw + * + * Draws a 1-pixel-wide line on an image. + * + * @ink is an array of bytes + * containing a valid pixel for the image's format. + * It must have at least IM_IMAGE_SIZEOF_PEL( @im ) bytes. + * + * See also: im_draw_circle(). + * + * Returns: 0 on success, or -1 on error. + */ +int +im_draw_line( VipsImage *im, int x1, int y1, int x2, int y2, PEL *ink ) +{ + Line *line; + + if( im_check_coding_known( "im_draw_line", im ) || + !(line = line_new( im, x1, y1, x2, y2, ink )) ) + return( -1 ); + + line->plot = line_plot_point; + line->a = line; + + if( line_draw( line ) ) { + line_free( line ); + return( 0 ); + } + + line_free( line ); + + return( 0 ); +} + +/* Draw a set of lines with an ink and a mask. A non-inplace operation, handy + * for nip2. + */ +int +im_lineset( IMAGE *in, IMAGE *out, IMAGE *mask, IMAGE *ink, + int n, int *x1v, int *y1v, int *x2v, int *y2v ) +{ + Rect mask_rect; + int i; + + if( mask->Bands != 1 || mask->BandFmt != IM_BANDFMT_UCHAR || + mask->Coding != IM_CODING_NONE ) { + im_error( "im_lineset", + "%s", _( "mask image not 1 band 8 bit uncoded" ) ); + return( -1 ); + } + if( ink->Bands != in->Bands || ink->BandFmt != in->BandFmt || + ink->Coding != in->Coding ) { + im_error( "im_lineset", + "%s", _( "ink image does not match in image" ) ); + return( -1 ); + } + if( ink->Xsize != 1 || ink->Ysize != 1 ) { + im_error( "im_lineset", "%s", _( "ink image not 1x1 pixels" ) ); + return( -1 ); + } + + /* Copy the image then fastline to it ... this will render to a "t" + * usually. + */ + if( im_copy( in, out ) ) + return( -1 ); + + mask_rect.left = mask->Xsize / 2; + mask_rect.top = mask->Ysize / 2; + mask_rect.width = mask->Xsize; + mask_rect.height = mask->Ysize; + + if( im_incheck( ink ) || + im_incheck( mask ) ) + return( -1 ); + + for( i = 0; i < n; i++ ) { + if( im_fastlineuser( out, x1v[i], y1v[i], x2v[i], y2v[i], + im_plotmask, ink->data, mask->data, &mask_rect ) ) + return( -1 ); + } + + return( 0 ); +} diff --git a/libvips/inplace/im_draw_rect.c b/libvips/inplace/im_draw_rect.c index 605dba3c..d355cfc7 100644 --- a/libvips/inplace/im_draw_rect.c +++ b/libvips/inplace/im_draw_rect.c @@ -15,6 +15,8 @@ * - gtk-doc * - added 'fill' * - renamed as im_draw_rect() for consistency + * 27/9/10 + * - memcpy() subsequent lines of the rect */ /* @@ -50,6 +52,7 @@ #include #include +#include #include @@ -118,20 +121,22 @@ im_draw_rect( IMAGE *im, if( im_rect_isempty( &clipped ) ) return( 0 ); - /* Loop through image plotting where required. + /* We plot the first line pointwise, then memcpy() it for the + * subsequent lines. */ to = (PEL *) IM_IMAGE_ADDR( im, clipped.left, clipped.top ); - for( y = 0; y < clipped.height; y++ ) { - q = to; - - for( x = 0; x < clipped.width; x++ ) { - for( b = 0; b < ps; b++ ) - q[b] = ink[b]; + q = to; + for( x = 0; x < clipped.width; x++ ) + for( b = 0; b < ps; b++ ) { + q[b] = ink[b]; q += ps; } - - to += ls; + + q = to + ls; + for( y = 1; y < clipped.height; y++ ) { + memcpy( q, to, clipped.width * ps ); + q += ls; } return( 0 ); diff --git a/libvips/inplace/inplace_dispatch.c b/libvips/inplace/inplace_dispatch.c index 7b7fd92d..5fcf0866 100644 --- a/libvips/inplace/inplace_dispatch.c +++ b/libvips/inplace/inplace_dispatch.c @@ -49,8 +49,12 @@ * @stability: Stable * @include: vips/vips.h * - * These operations modify the input image. You can't easily use them in - * pipelines, but they are useful for paintbox-style programs. + * These operations directly modify the image. They do not thread, on 32-bit + * machines they will be limited to 2GB images, and a little care needs to be + * taken if you use them as part of an image pipeline. + * + * They are mostly supposed to be useful + * for paintbox-style programs. * */ diff --git a/libvips/inplace/line_draw.c b/libvips/inplace/line_draw.c deleted file mode 100644 index 70c8f950..00000000 --- a/libvips/inplace/line_draw.c +++ /dev/null @@ -1,478 +0,0 @@ -/* @(#) Line drawer. Faster than the old im_line. Any number of bands, - * @(#) any type including complex. Instead of passing a PEL value, pass a - * @(#) pointer to the pel value you wish to plot. The correct number of - * @(#) bytes must be there! Both start and end points should be in the - * @(#) image. - * @(#) - * @(#) int - * @(#) im_fastline( im, x1, y1, x2, y2, pel ) - * @(#) IMAGE *im; - * @(#) int x1, x2, y1, y2; - * @(#) PEL *pel; - * @(#) - * @(#) As above, but rather than plotting a point, call a passed function - * @(#) for every point on the line. Up to three extra args passed down too. - * @(#) If the passed function returns non-zero, im_fastlineuser stops and - * @(#) returns non-zero. Start and end points may be outside the image - - * @(#) clipping is the responsibility of the user function. - * @(#) - * @(#) int - * @(#) im_fastlineuser( im, x1, y1, x2, y2, plot_fn, - * @(#) client1, client2, client3 ) - * @(#) IMAGE *im; - * @(#) int x1, x2, y1, y2; - * @(#) int (*plot_fn)(); - * @(#) void *client1, *client2, *client3; - * @(#) - * @(#) int - * @(#) plot_fn( im, x, y, client1, client2, client3 ) - * @(#) IMAGE *im; - * @(#) int x, y; - * @(#) void *client1, *client2, *client3; - * @(#) - * - * Copyright: J. Cupitt - * Written: 15/06/1992 - * Modified : 22/10/92 - clipping constraints changed - * 22/7/93 JC - * - im_incheck() added - * 16/8/94 JC - * - im_incheck() changed to im_makerw() - * 5/12/06 - * - im_invalidate() after paint - * 1/3/10 - * - oops, lineset needs to ask for WIO of mask and ink - * 6/3/10 - * - don't im_invalidate() after paint, this now needs to be at a higher - * level - */ - -/* - - 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 -#endif /*HAVE_CONFIG_H*/ -#include - -#include -#include - -#include - -#ifdef WITH_DMALLOC -#include -#endif /*WITH_DMALLOC*/ - -#define SWAP(A,B) {int t; t = (A); (A) = (B); (B) = t;} - -/* Draw a line on a image. - */ - -/** - * im_draw_line: - * @im: image to draw on - * @x1: start point - * @y1: start point - * @x2: end point - * @y2: end point - * @ink: value to draw - * - * Draws a 1-pixel-wide line on an image. @x1, @y1 and @x2, @y2 must be - * within the image. - * - * @ink is an array of bytes - * containing a valid pixel for the image's format. - * It must have at least IM_IMAGE_SIZEOF_PEL( @im ) bytes. - * - * This an inplace operation, so @im is changed. It does not thread and will - * not work well as part of a pipeline. On 32-bit machines it will be limited - * to 2GB images. - * - * See also: im_draw_circle(). - * - * Returns: 0 on success, or -1 on error. - */ -int -im_draw_line( IMAGE *im, int x1, int y1, int x2, int y2, PEL *pel ) -{ - int es = IM_IMAGE_SIZEOF_ELEMENT( im ); - int ps = es * im->Bands; - int ls = ps * im->Xsize; - PEL *p; - - int x, y, dx, dy; - int err; - int b; - - if( im_rwcheck( im ) ) - return( -1 ); - - /* Check coordinates in range. - */ - if( x1 > im->Xsize || x1 < 0 || - y1 > im->Ysize || y1 < 0 || - x2 > im->Xsize || x2 < 0 || - y2 > im->Ysize || y2 < 0 ) { - im_error( "im_fastline", "%s", - _( "invalid line cooordinates" ) ); - return( -1 ); - } - - /* Find offsets. - */ - dx = x2 - x1; - dy = y2 - y1; - - /* Swap endpoints to reduce number of cases. - */ - if( abs( dx ) >= abs( dy ) && dx < 0 ) { - /* Swap to get all x greater or equal cases going to the - * right. Do diagonals here .. just have up and right and down - * and right now. - */ - SWAP( x1, x2 ); - SWAP( y1, y2 ); - } - else if( abs( dx ) < abs( dy ) && dy < 0 ) { - /* Swap to get all y greater cases going down the screen. - */ - SWAP( x1, x2 ); - SWAP( y1, y2 ); - } - - /* Recalculate dx, dy. - */ - dx = x2 - x1; - dy = y2 - y1; - - /* Start point and offset. - */ - x = x1; - y = y1; - p = (PEL *) im->data + x * ps + y * ls; - - /* Plot point macro. - */ -#define PLOT \ - for( b = 0; b < ps; b++ ) \ - p[b] = pel[b]; - - /* Special case: zero width and height is single point. - */ - if( dx == 0 && dy == 0 ) { - PLOT; - } - /* Special case vertical and horizontal lines for speed. - */ - else if( dx == 0 ) { - /* Vertical line going down. - */ - for( ; y <= y2; y++ ) { - PLOT; - p += ls; - } - } - else if( dy == 0 ) { - /* Horizontal line to the right. - */ - for( ; x <= x2; x++ ) { - PLOT; - p += ps; - } - } - /* Special case diagonal lines. - */ - else if( abs( dy ) == abs( dx ) && dy > 0 ) { - /* Diagonal line going down and right. - */ - for( ; x <= x2; x++ ) { - PLOT; - p += ps + ls; - } - } - else if( abs( dy ) == abs( dx ) && dy < 0 ) { - /* Diagonal line going up and right. - */ - for( ; x <= x2; x++ ) { - PLOT; - p += ps - ls; - } - } - else if( abs( dy ) < abs( dx ) && dy > 0 ) { - /* Between -45 and 0 degrees. - */ - for( err = 0; x <= x2; x++ ) { - PLOT; - p += ps; - err += dy; - if( err >= dx ) { - err -= dx; - p += ls; - } - } - } - else if( abs( dy ) < abs( dx ) && dy < 0 ) { - /* Between 0 and 45 degrees. - */ - for( err = 0; x <= x2; x++ ) { - PLOT; - p += ps; - err -= dy; - if( err >= dx ) { - err -= dx; - p -= ls; - } - } - } - else if( abs( dy ) > abs( dx ) && dx > 0 ) { - /* Between -45 and -90 degrees. - */ - for( err = 0; y <= y2; y++ ) { - PLOT; - p += ls; - err += dx; - if( err >= dy ) { - err -= dy; - p += ps; - } - } - } - else if( abs( dy ) > abs( dx ) && dx < 0 ) { - /* Between -90 and -135 degrees. - */ - for( err = 0; y <= y2; y++ ) { - PLOT; - p += ls; - err -= dx; - if( err >= dy ) { - err -= dy; - p -= ps; - } - } - } - else - error_exit( "internal error #9872659823475982375" ); - - return( 0 ); -} - -/* Draw a line on a image with a user plot function. We do no clipping: the - * user function should check ranges for each pixel when it is called. - */ -int -im_fastlineuser( IMAGE *im, - int x1, int y1, int x2, int y2, - int (*fn)(), void *client1, void *client2, void *client3 ) -{ - int x, y, dx, dy; - int err; - - if( im_rwcheck( im ) ) - return( -1 ); - - /* Find offsets. - */ - dx = x2 - x1; - dy = y2 - y1; - - /* Swap endpoints to reduce number of cases. - */ - if( abs( dx ) >= abs( dy ) && dx < 0 ) { - /* Swap to get all x greater or equal cases going to the - * right. Do diagonals here .. just have up and right and down - * and right now. - */ - SWAP( x1, x2 ); - SWAP( y1, y2 ); - } - else if( abs( dx ) < abs( dy ) && dy < 0 ) { - /* Swap to get all y greater cases going down the screen. - */ - SWAP( x1, x2 ); - SWAP( y1, y2 ); - } - - /* Recalculate dx, dy. - */ - dx = x2 - x1; - dy = y2 - y1; - - /* Start point and offset. - */ - x = x1; - y = y1; - - /* Special case: zero width and height is single point. - */ - if( dx == 0 && dy == 0 ) { - if( fn( im, x, y, client1, client2, client3 ) ) - return( 1 ); - } - /* Special case vertical and horizontal lines for speed. - */ - else if( dx == 0 ) { - /* Vertical line going down. - */ - for( ; y <= y2; y++ ) { - if( fn( im, x, y, client1, client2, client3 ) ) - return( 1 ); - } - } - else if( dy == 0 ) { - /* Horizontal line to the right. - */ - for( ; x <= x2; x++ ) { - if( fn( im, x, y, client1, client2, client3 ) ) - return( 1 ); - } - } - /* Special case diagonal lines. - */ - else if( abs( dy ) == abs( dx ) && dy > 0 ) { - /* Diagonal line going down and right. - */ - for( ; x <= x2; x++, y++ ) { - if( fn( im, x, y, client1, client2, client3 ) ) - return( 1 ); - } - } - else if( abs( dy ) == abs( dx ) && dy < 0 ) { - /* Diagonal line going up and right. - */ - for( ; x <= x2; x++, y-- ) { - if( fn( im, x, y, client1, client2, client3 ) ) - return( 1 ); - } - } - else if( abs( dy ) < abs( dx ) && dy > 0 ) { - /* Between -45 and 0 degrees. - */ - for( err = 0; x <= x2; x++ ) { - if( fn( im, x, y, client1, client2, client3 ) ) - return( 1 ); - err += dy; - if( err >= dx ) { - err -= dx; - y++; - } - } - } - else if( abs( dy ) < abs( dx ) && dy < 0 ) { - /* Between 0 and 45 degrees. - */ - for( err = 0; x <= x2; x++ ) { - if( fn( im, x, y, client1, client2, client3 ) ) - return( 1 ); - err -= dy; - if( err >= dx ) { - err -= dx; - y--; - } - } - } - else if( abs( dy ) > abs( dx ) && dx > 0 ) { - /* Between -45 and -90 degrees. - */ - for( err = 0; y <= y2; y++ ) { - if( fn( im, x, y, client1, client2, client3 ) ) - return( 1 ); - err += dx; - if( err >= dy ) { - err -= dy; - x++; - } - } - } - else if( abs( dy ) > abs( dx ) && dx < 0 ) { - /* Between -90 and -135 degrees. - */ - for( err = 0; y <= y2; y++ ) { - if( fn( im, x, y, client1, client2, client3 ) ) - return( 1 ); - err -= dx; - if( err >= dy ) { - err -= dy; - x--; - } - } - } - else - error_exit( "internal error #9872659823475982375" ); - - return( 0 ); -} - -/* Draw a set of lines with an ink and a mask. A non-inplace operation, handy - * for nip2. - */ -int -im_lineset( IMAGE *in, IMAGE *out, IMAGE *mask, IMAGE *ink, - int n, int *x1v, int *y1v, int *x2v, int *y2v ) -{ - Rect mask_rect; - int i; - - if( mask->Bands != 1 || mask->BandFmt != IM_BANDFMT_UCHAR || - mask->Coding != IM_CODING_NONE ) { - im_error( "im_lineset", - "%s", _( "mask image not 1 band 8 bit uncoded" ) ); - return( -1 ); - } - if( ink->Bands != in->Bands || ink->BandFmt != in->BandFmt || - ink->Coding != in->Coding ) { - im_error( "im_lineset", - "%s", _( "ink image does not match in image" ) ); - return( -1 ); - } - if( ink->Xsize != 1 || ink->Ysize != 1 ) { - im_error( "im_lineset", "%s", _( "ink image not 1x1 pixels" ) ); - return( -1 ); - } - - /* Copy the image then fastline to it ... this will render to a "t" - * usually. - */ - if( im_copy( in, out ) ) - return( -1 ); - - mask_rect.left = mask->Xsize / 2; - mask_rect.top = mask->Ysize / 2; - mask_rect.width = mask->Xsize; - mask_rect.height = mask->Ysize; - - if( im_incheck( ink ) || - im_incheck( mask ) ) - return( -1 ); - - for( i = 0; i < n; i++ ) { - if( im_fastlineuser( out, x1v[i], y1v[i], x2v[i], y2v[i], - im_plotmask, ink->data, mask->data, &mask_rect ) ) - return( -1 ); - } - - return( 0 ); -}