line drawing
This commit is contained in:
parent
9330273f51
commit
aad2eb8703
@ -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
|
||||
|
@ -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 ) );
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
103
libvips/inplace/draw.c
Normal file
103
libvips/inplace/draw.c
Normal file
@ -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 <config.h>
|
||||
#endif /*HAVE_CONFIG_H*/
|
||||
#include <vips/intl.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <vips/vips.h>
|
||||
|
||||
#include "draw.h"
|
||||
|
||||
#ifdef WITH_DMALLOC
|
||||
#include <dmalloc.h>
|
||||
#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 );
|
||||
}
|
91
libvips/inplace/draw.h
Normal file
91
libvips/inplace/draw.h
Normal file
@ -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 );
|
@ -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 <vips/vips.h>
|
||||
|
||||
#include "draw.h"
|
||||
|
||||
#ifdef WITH_DMALLOC
|
||||
#include <dmalloc.h>
|
||||
#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 ) ||
|
||||
|
@ -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 <vips/vips.h>
|
||||
|
||||
#include "draw.h"
|
||||
|
||||
#ifdef WITH_DMALLOC
|
||||
#include <dmalloc.h>
|
||||
#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 );
|
||||
|
423
libvips/inplace/im_draw_line.c
Normal file
423
libvips/inplace/im_draw_line.c
Normal file
@ -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 <config.h>
|
||||
#endif /*HAVE_CONFIG_H*/
|
||||
#include <vips/intl.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <vips/vips.h>
|
||||
|
||||
#include "draw.h"
|
||||
|
||||
#ifdef WITH_DMALLOC
|
||||
#include <dmalloc.h>
|
||||
#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 );
|
||||
}
|
@ -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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <vips/vips.h>
|
||||
|
||||
@ -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 );
|
||||
|
@ -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.
|
||||
*
|
||||
*/
|
||||
|
||||
|
@ -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 <config.h>
|
||||
#endif /*HAVE_CONFIG_H*/
|
||||
#include <vips/intl.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <vips/vips.h>
|
||||
|
||||
#ifdef WITH_DMALLOC
|
||||
#include <dmalloc.h>
|
||||
#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 );
|
||||
}
|
Loading…
Reference in New Issue
Block a user