From 6b1c5b8e56ce09ea5e99336b10b7bf2c7bf578f1 Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Tue, 28 Sep 2010 16:06:58 +0000 Subject: [PATCH] im_draw_mask() added --- ChangeLog | 1 + TODO | 4 + libvips/deprecated/rename.c | 25 +- libvips/include/vips/almostdeprecated.h | 2 + libvips/include/vips/check.h | 1 + libvips/include/vips/inplace.h | 29 ++- libvips/inplace/Makefile.am | 2 +- libvips/inplace/flood.c | 21 +- libvips/inplace/im_draw_image.c | 20 +- libvips/inplace/im_draw_line.c | 28 +- libvips/inplace/im_draw_mask.c | 327 ++++++++++++++++++++++++ libvips/inplace/im_plotmask.c | 241 ----------------- libvips/inplace/inplace_dispatch.c | 110 +++++++- libvips/iofuncs/check.c | 28 ++ 14 files changed, 536 insertions(+), 303 deletions(-) create mode 100644 libvips/inplace/im_draw_mask.c delete mode 100644 libvips/inplace/im_plotmask.c diff --git a/ChangeLog b/ChangeLog index 8f7e8ebd..962800b7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -26,6 +26,7 @@ - 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 +- added im_draw_mask(), now wrappable, moved im_plotmask() 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/TODO b/TODO index 69dc44c6..05ef0e3c 100644 --- a/TODO +++ b/TODO @@ -1,3 +1,7 @@ +- im_draw_mask() should not take mx/my args, we can just displace x / y + + + - im_plotmask() should take the mask as a mono uchar IMAGE perhaps still need a rect for x/y/w/h of mask, since we use it with userline and an diff --git a/libvips/deprecated/rename.c b/libvips/deprecated/rename.c index 5634b3ec..2cde1514 100644 --- a/libvips/deprecated/rename.c +++ b/libvips/deprecated/rename.c @@ -34,6 +34,8 @@ #endif /*HAVE_CONFIG_H*/ #include +#include + #include #include @@ -516,7 +518,7 @@ im_paintrect( IMAGE *im, Rect *r, PEL *ink ) int im_insertplace( IMAGE *main, IMAGE *sub, int x, int y ) { - return( im_draw_image( main, x, y, sub ) ); + return( im_draw_image( main, sub, x, y ) ); } int @@ -533,3 +535,24 @@ im_fastlineuser( IMAGE *im, return( im_draw_line_user( im, x1, y1, x2, y2, fn, client1, client2, client3 ) ); } + +int +im_plotmask( IMAGE *im, int ix, int iy, PEL *ink, PEL *mask, Rect *r ) +{ + IMAGE *mask_im; + + if( !(mask_im = im_open( "im_plotmask", "t" )) ) + return( -1 ); + if( im_black( mask_im, r->width, r->height, 1 ) ) { + im_close( mask_im ); + return( -1 ); + } + memcpy( mask_im->data, mask, r->width * r->height ); + if( im_draw_mask( im, mask_im, ix - r->left, iy - r->top, ink ) ) { + im_close( mask_im ); + return( -1 ); + } + im_close( mask_im ); + + return( 0 ); +} diff --git a/libvips/include/vips/almostdeprecated.h b/libvips/include/vips/almostdeprecated.h index ff0524e8..6fed3ac6 100644 --- a/libvips/include/vips/almostdeprecated.h +++ b/libvips/include/vips/almostdeprecated.h @@ -244,6 +244,8 @@ int im_fastlineuser( IMAGE *im, int x1, int y1, int x2, int y2, int (*fn)(), void *client1, void *client2, void *client3 ); +int im_plotmask( IMAGE *im, int ix, int iy, PEL *ink, PEL *mask, Rect *r ); + #ifdef __cplusplus } #endif /*__cplusplus*/ diff --git a/libvips/include/vips/check.h b/libvips/include/vips/check.h index 3485f3ab..49779ba1 100644 --- a/libvips/include/vips/check.h +++ b/libvips/include/vips/check.h @@ -48,6 +48,7 @@ int im_check_uncoded( const char *domain, IMAGE *im ); int im_check_coding_known( const char *domain, IMAGE *im ); int im_check_coding_labq( const char *domain, IMAGE *im ); int im_check_coding_rad( const char *domain, IMAGE *im ); +int im_check_coding_noneorlabq( const char *domain, IMAGE *im ); int im_check_coding_same( const char *domain, IMAGE *im1, IMAGE *im2 ); int im_check_mono( const char *domain, IMAGE *im ); int im_check_bands_1or3( const char *domain, IMAGE *in ); diff --git a/libvips/include/vips/inplace.h b/libvips/include/vips/inplace.h index 35415631..9a883840 100644 --- a/libvips/include/vips/inplace.h +++ b/libvips/include/vips/inplace.h @@ -37,32 +37,33 @@ extern "C" { #endif /*__cplusplus*/ -int im_draw_rect( IMAGE *image, +int im_draw_rect( VipsImage *image, int left, int top, int width, int height, int fill, PEL *ink ); -int im_draw_circle( IMAGE *im, +int im_draw_circle( VipsImage *image, 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_image( VipsImage *image, VipsImage *sub, int x, int y ); -typedef int (*VipsPlotFn)( VipsImage *im, int x, int y, +typedef int (*VipsPlotFn)( VipsImage *image, int x, int y, void *a, void *b, void *c ); -int im_draw_line_user( VipsImage *im, +int im_draw_line_user( VipsImage *image, int x1, int y1, int x2, int y2, 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 im_draw_line( VipsImage *image, int x1, int y1, int x2, int y2, PEL *ink ); +int im_lineset( VipsImage *in, VipsImage *out, VipsImage *mask, VipsImage *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 im_flood( VipsImage *image, int x, int y, PEL *ink, Rect *dout ); +int im_flood_blob( VipsImage *image, int x, int y, PEL *ink, Rect *dout ); +int im_flood_other( VipsImage *image, VipsImage *test, int x, int y, int serial, Rect *dout ); -int im_readpoint( IMAGE *im, int x, int y, PEL *pel ); +int im_draw_mask( VipsImage *image, + VipsImage *mask_im, int ix, int iy, PEL *ink ); -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_readpoint( VipsImage *im, int x, int y, PEL *pel ); +int im_smear( VipsImage *im, int ix, int iy, Rect *r ); +int im_smudge( VipsImage *im, int ix, int iy, Rect *r ); #ifdef __cplusplus } diff --git a/libvips/inplace/Makefile.am b/libvips/inplace/Makefile.am index afdeb48b..2256fa4c 100644 --- a/libvips/inplace/Makefile.am +++ b/libvips/inplace/Makefile.am @@ -7,8 +7,8 @@ libinplace_la_SOURCES = \ im_draw_line.c \ im_draw_image.c \ im_draw_rect.c \ + im_draw_mask.c \ flood.c \ - im_plotmask.c \ inplace_dispatch.c \ plot_point.c \ smudge_area.c diff --git a/libvips/inplace/flood.c b/libvips/inplace/flood.c index fc5437e5..061f17b5 100644 --- a/libvips/inplace/flood.c +++ b/libvips/inplace/flood.c @@ -370,13 +370,13 @@ flood_free( Flood *flood ) } static Flood * -flood_new( IMAGE *test, IMAGE *mark, int x, int y, PEL *ink, Rect *dout ) +flood_new( IMAGE *image, IMAGE *test, int x, int y, PEL *ink, Rect *dout ) { Flood *flood; if( !(flood = IM_NEW( NULL, Flood )) ) return( NULL ); - if( !im__draw_init( DRAW( flood ), mark, ink ) ) { + if( !im__draw_init( DRAW( flood ), image, ink ) ) { flood_free( flood ); return( NULL ); } @@ -505,8 +505,8 @@ im_flood_blob( IMAGE *im, int x, int y, PEL *ink, Rect *dout ) /** * im_flood_other: + * @image: image to mark * @test: image to test - * @mark: image to mark * @x: position to start fill * @y: position to start fill * @serial: mark pixels with this number @@ -529,26 +529,27 @@ im_flood_blob( IMAGE *im, int x, int y, PEL *ink, Rect *dout ) * Returns: 0 on success, or -1 on error. */ int -im_flood_other( IMAGE *test, IMAGE *mark, int x, int y, int serial, Rect *dout ) +im_flood_other( IMAGE *image, + IMAGE *test, int x, int y, int serial, Rect *dout ) { int *m; Flood *flood; if( im_incheck( test ) || im_check_coding_known( "im_flood_other", test ) || - im_check_uncoded( "im_flood_other", mark ) || - im_check_mono( "im_flood_other", mark ) || - im_check_format( "im_flood_other", mark, IM_BANDFMT_INT ) || - im_check_size_same( "im_flood_other", test, mark ) ) + im_check_uncoded( "im_flood_other", image ) || + im_check_mono( "im_flood_other", image ) || + im_check_format( "im_flood_other", image, IM_BANDFMT_INT ) || + im_check_size_same( "im_flood_other", test, image ) ) return( -1 ); /* Have we done this point already? */ - m = (int *) IM_IMAGE_ADDR( mark, x, y ); + m = (int *) IM_IMAGE_ADDR( image, x, y ); if( *m == serial ) return( 0 ); - if( !(flood = flood_new( test, mark, x, y, (PEL *) &serial, dout )) ) + if( !(flood = flood_new( image, test, x, y, (PEL *) &serial, dout )) ) return( -1 ); /* Edge is set by colour of start pixel. diff --git a/libvips/inplace/im_draw_image.c b/libvips/inplace/im_draw_image.c index 90fe7282..aedeaa8d 100644 --- a/libvips/inplace/im_draw_image.c +++ b/libvips/inplace/im_draw_image.c @@ -72,11 +72,11 @@ * Unlike im__formatalike() and friends, we can only change one of the images, * since the other is being updated. */ -IMAGE * +VipsImage * im__inplace_base( const char *domain, - IMAGE *main, IMAGE *sub, IMAGE *out ) + VipsImage *main, VipsImage *sub, VipsImage *out ) { - IMAGE *t[2]; + VipsImage *t[2]; if( im_rwcheck( main ) || im_pincheck( sub ) || @@ -116,7 +116,7 @@ im__inplace_base( const char *domain, * Returns: 0 on success, or -1 on error. */ int -im_draw_image( IMAGE *main, int x, int y, IMAGE *sub ) +im_draw_image( VipsImage *image, VipsImage *sub, int x, int y ) { Rect br, sr, clip; PEL *p, *q; @@ -126,8 +126,8 @@ im_draw_image( IMAGE *main, int x, int y, IMAGE *sub ) */ br.left = 0; br.top = 0; - br.width = main->Xsize; - br.height = main->Ysize; + br.width = image->Xsize; + br.height = image->Ysize; sr.left = x; sr.top = y; sr.width = sub->Xsize; @@ -136,20 +136,20 @@ im_draw_image( IMAGE *main, int x, int y, IMAGE *sub ) if( im_rect_isempty( &clip ) ) return( 0 ); - if( !(sub = im__inplace_base( "im_draw_image", main, sub, main )) || - im_rwcheck( main ) || + if( !(sub = im__inplace_base( "im_draw_image", image, sub, image )) || + im_rwcheck( image ) || im_incheck( sub ) ) return( -1 ); /* Loop, memcpying sub to main. */ p = (PEL *) IM_IMAGE_ADDR( sub, clip.left - x, clip.top - y ); - q = (PEL *) IM_IMAGE_ADDR( main, clip.left, clip.top ); + q = (PEL *) IM_IMAGE_ADDR( image, clip.left, clip.top ); for( z = 0; z < clip.height; z++ ) { memcpy( (char *) q, (char *) p, clip.width * IM_IMAGE_SIZEOF_PEL( sub ) ); p += IM_IMAGE_SIZEOF_LINE( sub ); - q += IM_IMAGE_SIZEOF_LINE( main ); + q += IM_IMAGE_SIZEOF_LINE( image ); } return( 0 ); diff --git a/libvips/inplace/im_draw_line.c b/libvips/inplace/im_draw_line.c index 1295abff..1b2376f5 100644 --- a/libvips/inplace/im_draw_line.c +++ b/libvips/inplace/im_draw_line.c @@ -267,6 +267,12 @@ line_draw( Line *line ) return( 0 ); } +/** + * VipsPlotFn: + * + * A plot function, as used by im_draw_line_user() to draw on an image. + */ + /** * im_draw_line_user: * @im: image to draw on @@ -274,23 +280,19 @@ line_draw( Line *line ) * @y1: start point * @x2: end point * @y2: end point - * @ink: value to draw + * @plot: draw operation + * @a: draw operation parameter + * @b: draw operation parameter + * @c: draw operation parameter * - * Draws a 1-pixel-wide line on an image. @x1, @y1 and @x2, @y2 must be - * within the image. + * Calls @plot for every point on the line connecting @x1, @y1 and @x2, @y2. + * If you pass im_draw_mask() as the plot operation, you can draw wide lines + * or lines with various brushes. * - * @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(). + * See also: im_draw_mask(), im_draw_line(), 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, @@ -298,7 +300,7 @@ im_draw_line_user( VipsImage *im, { Line *line; - if( im_check_coding_known( "im_draw_line", im ) || + if( im_check_coding_known( "im_draw_line_user", im ) || !(line = line_new( im, x1, y1, x2, y2, NULL )) ) return( -1 ); diff --git a/libvips/inplace/im_draw_mask.c b/libvips/inplace/im_draw_mask.c new file mode 100644 index 00000000..e90ef2a6 --- /dev/null +++ b/libvips/inplace/im_draw_mask.c @@ -0,0 +1,327 @@ +/* Draw a mask on an image. + * + * Copyright: J. Cupitt + * Written: 15/06/1992 + * 22/7/93 JC + * - im_incheck() added + * 16/8/94 JC + * - im_incheck() changed to im_makerw() + * 24/10/03 JC + * - now blends with 0-255 mask + * 5/12/06 + * - im_invalidate() after paint + * 6/3/10 + * - don't im_invalidate() after paint, this now needs to be at a higher + * level + * 28/9/10 + * - gtk-doc + * - renamed as im_draw_mask() + * - use Draw base class + */ + +/* + + This file is part of VIPS. + + VIPS is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + */ + +/* + + These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk + + */ + +#ifdef HAVE_CONFIG_H +#include +#endif /*HAVE_CONFIG_H*/ +#include + +#include +#include + +#include +#include + +#include "draw.h" + +#ifdef WITH_DMALLOC +#include +#endif /*WITH_DMALLOC*/ + +typedef struct _Mask { + Draw draw; + + /* Parameters. + */ + int ix; + int iy; + VipsImage *mask_im; + + /* Derived. + */ + Rect image_clip; + Rect mask_clip; +} Mask; + +static void +mask_free( Mask *mask ) +{ + im__draw_free( DRAW( mask ) ); + im_free( mask ); +} + +static Mask * +mask_new( VipsImage *im, int ix, int iy, PEL *ink, VipsImage *mask_im ) +{ + Mask *mask; + Rect area, image; + + if( im_check_coding_noneorlabq( "im_draw_mask", im ) || + im_incheck( mask_im ) || + im_check_mono( "im_draw_mask", mask_im ) || + im_check_uncoded( "im_draw_mask", mask_im ) || + im_check_format( "im_draw_mask", mask_im, IM_BANDFMT_UCHAR ) || + !(mask = IM_NEW( NULL, Mask )) ) + return( NULL ); + if( !im__draw_init( DRAW( mask ), im, ink ) ) { + mask_free( mask ); + return( NULL ); + } + + mask->ix = ix; + mask->iy = iy; + mask->mask_im = mask_im; + + /* Find the area we draw on the image. + */ + area.left = ix; + area.top = iy; + area.width = mask_im->Xsize; + area.height = mask_im->Ysize; + image.left = 0; + image.top = 0; + image.width = im->Xsize; + image.height = im->Ysize; + im_rect_intersectrect( &area, &image, &mask->image_clip ); + + /* And the area of the mask image we use. + */ + mask->mask_clip = mask->image_clip; + mask->mask_clip.left -= ix; + mask->mask_clip.top -= iy; + + return( mask ); +} + +/* Paint ink into an 8 or 16 bit integer image. + */ +#define IBLEND( TYPE, TO, INK ) { \ + TYPE *tto = (TYPE *) (TO); \ + TYPE *tink = (TYPE *) (INK); \ + \ + int x, i, j; \ + \ + for( j = 0, x = 0; x < mask->image_clip.width; x++ ) \ + for( i = 0; i < DRAW( mask )->im->Bands; i++, j++ ) \ + tto[j] = (tink[i] * mask_line[x] + \ + tto[j] * (255 - mask_line[x])) / 255; \ +} + +/* Do the blend with doubles. + */ +#define DBLEND( TYPE, TO, INK ) { \ + TYPE *tto = (TYPE *) (TO); \ + TYPE *tink = (TYPE *) (INK); \ + \ + int x, i, j; \ + \ + for( j = 0, x = 0; x < mask->image_clip.width; x++ ) \ + for( i = 0; i < DRAW( mask )->im->Bands; i++, j++ ) \ + tto[j] = ((double) tink[i] * mask_line[x] + \ + (double) tto[j] * (255 - mask_line[x])) / 255;\ +} + +/* Blend of complex. + */ +#define CBLEND( TYPE, TO, INK ) { \ + TYPE *tto = (TYPE *) (TO); \ + TYPE *tink = (TYPE *) (INK); \ + \ + int x, i, j; \ + \ + for( j = 0, x = 0; x < mask->image_clip.width; x++ ) \ + for( i = 0; i < DRAW( mask )->im->Bands * 2; i += 2, j += 2 ) { \ + tto[j] = ((double) tink[i] * mask_line[x] + \ + (double) tto[j] * (255 - mask_line[x])) / 255;\ + tto[j + 1] = ((double) tink[i + 1] * mask_line[x] + \ + (double) tto[j + 1] * (255 - mask_line[x])) / \ + 255;\ + } \ +} + +static int +mask_draw_labq( Mask *mask ) +{ + float *lab_buffer; + float ink_buffer[3]; + int y; + + if( !(lab_buffer = IM_ARRAY( NULL, + mask->image_clip.width * 3, float )) ) + return( -1 ); + + imb_LabQ2Lab( DRAW( mask )->ink, ink_buffer, 1 ); + + for( y = 0; y < mask->image_clip.height; y++ ) { + PEL *to = (PEL *) IM_IMAGE_ADDR( DRAW( mask )->im, + mask->image_clip.left, y + mask->image_clip.top ); + PEL *mask_line = (PEL *) IM_IMAGE_ADDR( mask->mask_im, + mask->mask_clip.left, y + mask->mask_clip.top ); + + imb_LabQ2Lab( to, lab_buffer, mask->image_clip.width ); + DBLEND( float, lab_buffer, ink_buffer ); + imb_Lab2LabQ( lab_buffer, to, mask->image_clip.width ); + } + + im_free( lab_buffer ); + + return( 0 ); +} + +static int +mask_draw( Mask *mask ) +{ + int y; + + for( y = 0; y < mask->image_clip.height; y++ ) { + PEL *to = (PEL *) IM_IMAGE_ADDR( DRAW( mask )->im, + mask->image_clip.left, + y + mask->image_clip.top ); + PEL *mask_line = (PEL *) IM_IMAGE_ADDR( mask->mask_im, + mask->mask_clip.left, + y + mask->mask_clip.top ); + + switch( DRAW( mask )->im->BandFmt ) { + case IM_BANDFMT_UCHAR: + IBLEND( unsigned char, to, DRAW( mask )->ink ); + break; + + case IM_BANDFMT_CHAR: + IBLEND( signed char, to, DRAW( mask )->ink ); + break; + + case IM_BANDFMT_USHORT: + IBLEND( unsigned short, to, DRAW( mask )->ink ); + break; + + case IM_BANDFMT_SHORT: + IBLEND( signed short, to, DRAW( mask )->ink ); + break; + + case IM_BANDFMT_UINT: + DBLEND( unsigned int, to, DRAW( mask )->ink ); + break; + + case IM_BANDFMT_INT: + DBLEND( signed int, to, DRAW( mask )->ink ); + break; + + case IM_BANDFMT_FLOAT: + DBLEND( float, to, DRAW( mask )->ink ); + break; + + case IM_BANDFMT_DOUBLE: + DBLEND( double, to, DRAW( mask )->ink ); + break; + + case IM_BANDFMT_COMPLEX: + CBLEND( float, to, DRAW( mask )->ink ); + break; + + case IM_BANDFMT_DPCOMPLEX: + CBLEND( double, to, DRAW( mask )->ink ); + break; + + default: + g_assert( 0 ); + } + } + + return( 0 ); +} + +/** + * im_draw_mask: + * @im: image to draw on + * @x: draw mask here + * @y: draw mask here + * @ink: value to draw + * @mask_im: mask of 0/255 values showing where to plot + * + * Draw a mask on the image. @mask_im is a monochrome 8-bit image with 0/255 + * for transparent or @ink coloured points. Intermediate values blend the ink + * with the pixel. Use with im_text() to draw text 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(), im_text(). + * + * Returns: 0 on success, or -1 on error. + */ +int +im_draw_mask( VipsImage *im, VipsImage *mask_im, int ix, int iy, PEL *ink ) +{ + Mask *mask; + + if( !(mask = mask_new( im, ix, iy, ink, mask_im )) ) + return( -1 ); + + /* Any points to plot? + */ + if( im_rect_isempty( &mask->image_clip ) ) { + mask_free( mask ); + return( 0 ); + } + + /* Loop through image plotting where required. + */ + switch( im->Coding ) { + case IM_CODING_LABQ: + if( mask_draw_labq( mask ) ) { + mask_free( mask ); + return( 0 ); + } + break; + + case IM_CODING_NONE: + if( mask_draw( mask ) ) { + mask_free( mask ); + return( 0 ); + } + break; + + default: + g_assert( 0 ); + } + + mask_free( mask ); + + return( 0 ); +} + diff --git a/libvips/inplace/im_plotmask.c b/libvips/inplace/im_plotmask.c deleted file mode 100644 index 0ad76fcd..00000000 --- a/libvips/inplace/im_plotmask.c +++ /dev/null @@ -1,241 +0,0 @@ -/* @(#) Plot many points in a single call. Pass ink, array containing - * @(#) 0/255 showing where to plot and Rect showing size of array and - * @(#) offset to get to centre of array. ix and iy are where to plot. Rect - * @(#) can be any size, any position - we clip against the edges of the - * @(#) image. - * @(#) - * @(#) int - * @(#) im_plotmask( IMAGE *im, int ix, int iy, PEL *ink, PEL *mask, Rect *r ) - * @(#) - * - * Copyright: J. Cupitt - * Written: 15/06/1992 - * 22/7/93 JC - * - im_incheck() added - * 16/8/94 JC - * - im_incheck() changed to im_makerw() - * 24/10/03 JC - * - now blends with 0-255 mask - * 5/12/06 - * - im_invalidate() after paint - * 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 -#include - -#ifdef WITH_DMALLOC -#include -#endif /*WITH_DMALLOC*/ - -/* Paint ink into an 8 or 16 bit integer image. - */ -#define IBLEND( TYPE, TO, INK, B, W ) { \ - TYPE *tto = (TYPE *) (TO); \ - TYPE *tink = (TYPE *) (INK); \ - \ - int x, i, j; \ - \ - for( j = 0, x = 0; x < (W); x++ ) \ - for( i = 0; i < (B); i++, j++ ) \ - tto[j] = (tink[i] * mask_line[x] + \ - tto[j] * (255 - mask_line[x])) / 255; \ -} - -/* Do the blend with doubles. - */ -#define DBLEND( TYPE, TO, INK, B, W ) { \ - TYPE *tto = (TYPE *) (TO); \ - TYPE *tink = (TYPE *) (INK); \ - \ - int x, i, j; \ - \ - for( j = 0, x = 0; x < (W); x++ ) \ - for( i = 0; i < (B); i++, j++ ) \ - tto[j] = ((double) tink[i] * mask_line[x] + \ - (double) tto[j] * (255 - mask_line[x])) / 255;\ -} - -/* Blend of complex. - */ -#define CBLEND( TYPE, TO, INK, B, W ) { \ - TYPE *tto = (TYPE *) (TO); \ - TYPE *tink = (TYPE *) (INK); \ - \ - int x, i, j; \ - \ - for( j = 0, x = 0; x < (W); x++ ) \ - for( i = 0; i < (B) * 2; i += 2, j += 2 ) { \ - tto[j] = ((double) tink[i] * mask_line[x] + \ - (double) tto[j] * (255 - mask_line[x])) / 255;\ - tto[j + 1] = ((double) tink[i + 1] * mask_line[x] + \ - (double) tto[j + 1] * (255 - mask_line[x])) / \ - 255;\ - } \ -} - -/* Plot lots of points! Pass ink, array of 0/255 showing where to plot, rect - * showing size and offset for array. Used for fat lines and text. - */ -int -im_plotmask( IMAGE *im, int ix, int iy, PEL *ink, PEL *mask, Rect *r ) -{ - Rect area, image, clipped; - int y; - int mx, my; - - if( im_rwcheck( im ) ) - return( -1 ); - - /* Find area we plot. - */ - area = *r; - area.left += ix; - area.top += iy; - image.left = 0; - image.top = 0; - image.width = im->Xsize; - image.height = im->Ysize; - im_rect_intersectrect( &area, &image, &clipped ); - - /* Any points left to plot? - */ - if( im_rect_isempty( &clipped ) ) - return( 0 ); - - /* Find area of mask we use. - */ - mx = IM_MAX( 0, clipped.left - area.left ); - my = IM_MAX( 0, clipped.top - area.top ); - - /* Loop through image plotting where required. - */ - if( im->Coding == IM_CODING_LABQ ) { - float *lab_buffer; - float ink_buffer[3]; - - if( !(lab_buffer = - IM_ARRAY( NULL, clipped.width * 3, float )) ) - return( -1 ); - - imb_LabQ2Lab( ink, ink_buffer, 1 ); - - for( y = 0; y < clipped.height; y++ ) { - PEL *to = (PEL *) IM_IMAGE_ADDR( im, - clipped.left, y + clipped.top ); - PEL *mask_line = mask + - mx + (y + my) * area.width; - - imb_LabQ2Lab( to, lab_buffer, clipped.width ); - DBLEND( float, - lab_buffer, ink_buffer, 3, clipped.width ); - imb_Lab2LabQ( lab_buffer, to, clipped.width ); - } - - im_free( lab_buffer ); - } - else { - for( y = 0; y < clipped.height; y++ ) { - PEL *to = (PEL *) IM_IMAGE_ADDR( im, - clipped.left, y + clipped.top ); - PEL *mask_line = mask + - mx + (y + my) * area.width; - - switch( im->BandFmt ) { - case IM_BANDFMT_UCHAR: - IBLEND( unsigned char, - to, ink, im->Bands, clipped.width ); - break; - - case IM_BANDFMT_CHAR: - IBLEND( signed char, - to, ink, im->Bands, clipped.width ); - break; - - case IM_BANDFMT_USHORT: - IBLEND( unsigned short, - to, ink, im->Bands, clipped.width ); - break; - - case IM_BANDFMT_SHORT: - IBLEND( signed short, - to, ink, im->Bands, clipped.width ); - break; - - case IM_BANDFMT_UINT: - DBLEND( unsigned int, - to, ink, im->Bands, clipped.width ); - break; - - case IM_BANDFMT_INT: - DBLEND( signed int, - to, ink, im->Bands, clipped.width ); - break; - - case IM_BANDFMT_FLOAT: - DBLEND( float, - to, ink, im->Bands, clipped.width ); - break; - - case IM_BANDFMT_DOUBLE: - DBLEND( double, - to, ink, im->Bands, clipped.width ); - break; - - case IM_BANDFMT_COMPLEX: - CBLEND( float, - to, ink, im->Bands, clipped.width ); - break; - - case IM_BANDFMT_DPCOMPLEX: - CBLEND( double, - to, ink, im->Bands, clipped.width ); - break; - - default: - im_error( "im_plotmask", - "%s", _( "internal error" ) ); - return( -1 ); - } - } - } - - return( 0 ); -} - diff --git a/libvips/inplace/inplace_dispatch.c b/libvips/inplace/inplace_dispatch.c index 5fcf0866..03eadd3f 100644 --- a/libvips/inplace/inplace_dispatch.c +++ b/libvips/inplace/inplace_dispatch.c @@ -61,10 +61,10 @@ /* Args for im_draw_image. */ static im_arg_desc draw_image_args[] = { - IM_RW_IMAGE( "main" ), + IM_RW_IMAGE( "image" ), + IM_INPUT_IMAGE( "sub" ), IM_INPUT_INT( "x" ), - IM_INPUT_INT( "y" ), - IM_INPUT_IMAGE( "sub" ) + IM_INPUT_INT( "y" ) }; /* Call im_draw_image via arg vector. @@ -72,10 +72,10 @@ static im_arg_desc draw_image_args[] = { static int draw_image_vec( im_object *argv ) { - int x = *((int *) argv[1]); - int y = *((int *) argv[2]); + int x = *((int *) argv[2]); + int y = *((int *) argv[3]); - return( im_draw_image( argv[0], x, y, argv[3] ) ); + return( im_draw_image( argv[0], argv[1], x, y ) ); } /* Description of im_draw_image. @@ -158,6 +158,47 @@ im__vector_to_ink( const char *domain, IMAGE *im, int n, double *vec ) return( (PEL *) t[2]->data ); } +/* Args for im_draw_mask. + */ +static im_arg_desc draw_mask_args[] = { + IM_RW_IMAGE( "image" ), + IM_INPUT_IMAGE( "mask" ), + IM_INPUT_INT( "x" ), + IM_INPUT_INT( "y" ), + IM_INPUT_DOUBLEVEC( "ink" ) +}; + +/* Call im_draw_mask via arg vector. + */ +static int +draw_mask_vec( im_object *argv ) +{ + IMAGE *image = argv[0]; + IMAGE *mask = argv[1]; + int x = *((int *) argv[2]); + int y = *((int *) argv[3]); + im_doublevec_object *dv = (im_doublevec_object *) argv[4]; + + PEL *ink; + + if( !(ink = im__vector_to_ink( "im_draw_mask", + image, dv->n, dv->vec )) ) + return( -1 ); + + return( im_draw_mask( image, mask, x, y, ink ) ); +} + +/* Description of im_draw_mask. + */ +static im_function draw_mask_desc = { + "im_draw_mask", /* Name */ + "draw mask sub inside image main at position (x,y)", + 0, /* Flags */ + draw_mask_vec, /* Dispatch function */ + IM_NUMBER( draw_mask_args ), /* Size of arg list */ + draw_mask_args /* Arg list */ +}; + /* Args for im_flood_blob(). */ static im_arg_desc flood_blob_args[] = { @@ -238,8 +279,8 @@ static im_function flood_desc = { /* Args for im_flood_other(). */ static im_arg_desc flood_other_args[] = { + IM_RW_IMAGE( "image" ), IM_INPUT_IMAGE( "test" ), - IM_RW_IMAGE( "mark" ), IM_INPUT_INT( "start_x" ), IM_INPUT_INT( "start_y" ), IM_INPUT_INT( "serial" ) @@ -250,13 +291,13 @@ static im_arg_desc flood_other_args[] = { static int flood_other_vec( im_object *argv ) { - IMAGE *test = argv[0]; - IMAGE *mark = argv[1]; + IMAGE *image = argv[0]; + IMAGE *test = argv[1]; int start_x = *((int *) argv[2]); int start_y = *((int *) argv[3]); int serial = *((int *) argv[4]); - return( im_flood_other( test, mark, start_x, start_y, serial, NULL ) ); + return( im_flood_other( image, test, start_x, start_y, serial, NULL ) ); } /* Description of im_flood_other(). @@ -270,6 +311,49 @@ static im_function flood_other_desc = { flood_other_args /* Arg list */ }; +/* Args for im_draw_line. + */ +static im_arg_desc draw_line_args[] = { + IM_RW_IMAGE( "image" ), + IM_INPUT_INT( "x1" ), + IM_INPUT_INT( "y1" ), + IM_INPUT_INT( "x2" ), + IM_INPUT_INT( "y2" ), + IM_INPUT_DOUBLEVEC( "ink" ) +}; + +/* Call im_draw_line via arg vector. + */ +static int +draw_line_vec( im_object *argv ) +{ + IMAGE *image = argv[0]; + int x1 = *((int *) argv[1]); + int y1 = *((int *) argv[2]); + int x2 = *((int *) argv[3]); + int y2 = *((int *) argv[4]); + im_doublevec_object *dv = (im_doublevec_object *) argv[5]; + + PEL *ink; + + if( !(ink = im__vector_to_ink( "im_draw_line", + image, dv->n, dv->vec )) ) + return( -1 ); + + return( im_draw_line( image, x1, y1, x2, y2, ink ) ); +} + +/* Description of im_draw_line. + */ +static im_function draw_line_desc = { + "im_draw_line", /* Name */ + "draw line on image", + 0, /* Flags */ + draw_line_vec, /* Dispatch function */ + IM_NUMBER( draw_line_args ), /* Size of arg list */ + draw_line_args /* Arg list */ +}; + /* Args for im_draw_rect. */ static im_arg_desc draw_rect_args[] = { @@ -282,7 +366,7 @@ static im_arg_desc draw_rect_args[] = { IM_INPUT_DOUBLEVEC( "ink" ) }; -/* Call im_draw_circle via arg vector. +/* Call im_draw_rect via arg vector. */ static int draw_rect_vec( im_object *argv ) @@ -361,8 +445,6 @@ static im_function draw_circle_desc = { /* To do: * these all need some kind of pel type * - im_plotmask.c - line_draw.c plot_point.c smudge_area.c * @@ -373,10 +455,12 @@ static im_function draw_circle_desc = { static im_function *inplace_list[] = { &draw_circle_desc, &draw_rect_desc, + &draw_line_desc, &flood_desc, &flood_blob_desc, &flood_other_desc, &draw_image_desc, + &draw_mask_desc, &lineset_desc }; diff --git a/libvips/iofuncs/check.c b/libvips/iofuncs/check.c index 5368aa49..f85e6a3d 100644 --- a/libvips/iofuncs/check.c +++ b/libvips/iofuncs/check.c @@ -561,6 +561,34 @@ im_check_uncoded( const char *domain, IMAGE *im ) return( 0 ); } +/** + * im_check_coding_noneorlabq: + * @domain: the originating domain for the error message + * @im: image to check + * + * Check that the image is uncoded or LABQ coded. + * If not, set an error message + * and return non-zero. + * + * See also: im_error(). + * + * Returns: 0 on OK, or -1 on error. + */ +int +im_check_coding_noneorlabq( const char *domain, IMAGE *im ) +{ + /* These all have codings that extract/ifthenelse/etc can ignore. + */ + if( im->Coding != IM_CODING_NONE && + im->Coding != IM_CODING_LABQ ) { + im_error( domain, + "%s", _( "image coding must be NONE or LABQ" ) ); + return( -1 ); + } + + return( 0 ); +} + /** * im_check_coding_known: * @domain: the originating domain for the error message