From 9b13188fc14d883901b36ad6dc9c09148e1800a9 Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Fri, 28 Mar 2014 13:55:56 +0000 Subject: [PATCH] add "mode" to vips_draw_image() --- ChangeLog | 2 +- TODO | 2 +- bootstrap.sh | 2 +- libvips/draw/Makefile.am | 1 - libvips/draw/draw.c | 2 - libvips/draw/draw_add.c | 238 ------------------------------- libvips/draw/draw_image.c | 54 +++++-- libvips/include/vips/Makefile.am | 1 + libvips/include/vips/draw.h | 2 - libvips/include/vips/enumtypes.h | 3 + libvips/iofuncs/Makefile.am | 1 + libvips/iofuncs/enumtypes.c | 19 +++ 12 files changed, 68 insertions(+), 259 deletions(-) delete mode 100644 libvips/draw/draw_add.c diff --git a/ChangeLog b/ChangeLog index 21053e8d..26b8ced6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -15,7 +15,7 @@ - fix to vipsthumbnail --crop, thanks Alessandro - add vips_sum() - add vips_hough base class and vips_hough_line() -- add vips_draw_add() +- add "mode" param to vips_draw_image() 6/3/14 started 7.38.6 - grey ramp minimum was wrong diff --git a/TODO b/TODO index 09b4715a..f9f17dbc 100644 --- a/TODO +++ b/TODO @@ -1,4 +1,4 @@ -- add a "mode" param to draw_image.c, get rid of draw_add.c +- vips_draw_image() might need a direct mode? see vips_flood_direct() - hough_line.c should have a main accumulator and use vips_draw_add() to add threads to that diff --git a/bootstrap.sh b/bootstrap.sh index 2488f60c..d07e6996 100755 --- a/bootstrap.sh +++ b/bootstrap.sh @@ -1,6 +1,6 @@ #!/bin/sh -set -x +# set -x # a bunch of cleaning up ... make certain everything will be regenerated rm -f Makefile Makefile.in aclocal.m4 diff --git a/libvips/draw/Makefile.am b/libvips/draw/Makefile.am index fe68356f..20f8ece2 100644 --- a/libvips/draw/Makefile.am +++ b/libvips/draw/Makefile.am @@ -9,7 +9,6 @@ libdraw_la_SOURCES = \ draw_flood.c \ draw_mask.c \ draw_image.c \ - draw_add.c \ draw_rect.c \ draw_line.h \ draw_line.c \ diff --git a/libvips/draw/draw.c b/libvips/draw/draw.c index 71ae2ef1..74d8d249 100644 --- a/libvips/draw/draw.c +++ b/libvips/draw/draw.c @@ -130,7 +130,6 @@ vips_draw_operation_init( void ) { extern GType vips_draw_rect_get_type( void ); extern GType vips_draw_image_get_type( void ); - extern GType vips_draw_add_get_type( void ); extern GType vips_draw_mask_get_type( void ); extern GType vips_draw_line_get_type( void ); extern GType vips_draw_line_mask_get_type( void ); @@ -141,7 +140,6 @@ vips_draw_operation_init( void ) vips_draw_rect_get_type(); vips_draw_image_get_type(); - vips_draw_add_get_type(); vips_draw_mask_get_type(); vips_draw_line_get_type(); vips_draw_line_mask_get_type(); diff --git a/libvips/draw/draw_add.c b/libvips/draw/draw_add.c deleted file mode 100644 index 2d5f85b7..00000000 --- a/libvips/draw/draw_add.c +++ /dev/null @@ -1,238 +0,0 @@ -/* in-place add, ie. a = a + b - * - * 26/3/14 - * - from draw_image.c - */ - -/* - - 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., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 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 - -#include "pdraw.h" - -typedef struct _VipsDrawAdd { - VipsDraw parent_object; - - /* Parameters. - */ - VipsImage *sub; - int x; - int y; - -} VipsDrawAdd; - -typedef struct _VipsDrawAddClass { - VipsDrawClass parent_class; - -} VipsDrawAddClass; - -G_DEFINE_TYPE( VipsDrawAdd, vips_draw_add, VIPS_TYPE_DRAW ); - -#define LOOP( TYPE ) { \ - TYPE * restrict pt = (TYPE *) p; \ - TYPE * restrict qt = (TYPE *) q; \ - \ - for( x = 0; x < sz; x++ ) \ - qt[x] += pt[x]; \ -} - -static int -vips_draw_add_build( VipsObject *object ) -{ - VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object ); - VipsDraw *draw = VIPS_DRAW( object ); - VipsDrawAdd *image = (VipsDrawAdd *) object; - VipsImage **t = (VipsImage **) vips_object_local_array( object, 3 ); - - VipsImage *im; - VipsRect image_rect; - VipsRect sub_rect; - VipsRect clip_rect; - - if( VIPS_OBJECT_CLASS( vips_draw_add_parent_class )->build( object ) ) - return( -1 ); - - if( vips_check_uncoded( class->nickname, draw->image ) || - vips_check_coding_same( class->nickname, - draw->image, image->sub ) || - vips_check_bands_1orn_unary( class->nickname, - image->sub, draw->image->Bands ) ) - return( -1 ); - - /* Cast sub to match main in bands and format. - */ - im = image->sub; - if( vips__bandup( class->nickname, - im, &t[0], draw->image->Bands ) || - vips_cast( t[0], &t[1], draw->image->BandFmt, NULL ) ) - return( -1 ); - im = t[1]; - - /* Make rects for main and sub and clip. - */ - image_rect.left = 0; - image_rect.top = 0; - image_rect.width = draw->image->Xsize; - image_rect.height = draw->image->Ysize; - sub_rect.left = image->x; - sub_rect.top = image->y; - sub_rect.width = im->Xsize; - sub_rect.height = im->Ysize; - vips_rect_intersectrect( &image_rect, &sub_rect, &clip_rect ); - - if( !vips_rect_isempty( &clip_rect ) ) { - /* Complex just doubles the size. - */ - const int sz = clip_rect.width * im->Bands * - (vips_band_format_iscomplex( im->BandFmt ) ? - 2 : 1); - - VipsPel *p, *q; - int x, y; - - if( vips_image_wio_input( im ) ) - return( -1 ); - - p = VIPS_IMAGE_ADDR( im, - clip_rect.left - image->x, clip_rect.top - image->y ); - q = VIPS_IMAGE_ADDR( draw->image, - clip_rect.left, clip_rect.top ); - - for( y = 0; y < clip_rect.height; y++ ) { - switch( im->BandFmt ) { - case VIPS_FORMAT_UCHAR: - LOOP( unsigned char ); break; - case VIPS_FORMAT_CHAR: - LOOP( signed char ); break; - case VIPS_FORMAT_USHORT: - LOOP( unsigned short ); break; - case VIPS_FORMAT_SHORT: - LOOP( signed short ); break; - case VIPS_FORMAT_UINT: - LOOP( unsigned int ); break; - case VIPS_FORMAT_INT: - LOOP( signed int ); break; - - case VIPS_FORMAT_FLOAT: - case VIPS_FORMAT_COMPLEX: - LOOP( float ); break; - - case VIPS_FORMAT_DOUBLE: - case VIPS_FORMAT_DPCOMPLEX: - LOOP( double ); break; - - default: - g_assert( 0 ); - } - - p += VIPS_IMAGE_SIZEOF_LINE( im ); - q += VIPS_IMAGE_SIZEOF_LINE( draw->image ); - } - } - - return( 0 ); -} - -static void -vips_draw_add_class_init( VipsDrawAddClass *class ) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS( class ); - VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS( class ); - - gobject_class->set_property = vips_object_set_property; - gobject_class->get_property = vips_object_get_property; - - vobject_class->nickname = "draw_add"; - vobject_class->description = _( "add an image into another image" ); - vobject_class->build = vips_draw_add_build; - - VIPS_ARG_IMAGE( class, "sub", 5, - _( "Sub-image" ), - _( "Sub-image to add to main image" ), - VIPS_ARGUMENT_REQUIRED_INPUT, - G_STRUCT_OFFSET( VipsDrawAdd, sub ) ); - - VIPS_ARG_INT( class, "x", 6, - _( "x" ), - _( "Add image here" ), - VIPS_ARGUMENT_REQUIRED_INPUT, - G_STRUCT_OFFSET( VipsDrawAdd, x ), - -1000000000, 1000000000, 0 ); - - VIPS_ARG_INT( class, "y", 7, - _( "y" ), - _( "Add image here" ), - VIPS_ARGUMENT_REQUIRED_INPUT, - G_STRUCT_OFFSET( VipsDrawAdd, y ), - -1000000000, 1000000000, 0 ); - -} - -static void -vips_draw_add_init( VipsDrawAdd *draw_add ) -{ -} - -/** - * vips_draw_add: - * @image: image to add to - * @sub: image to add from - * @x: add @sub here - * @y: add @sub here - * - * Add @sub to @image at position @x, @y. The two images must be uncoded. - * If @sub has 1 band, the bands will be duplicated to match the - * number of bands in @image. @sub will be converted to @image's format, see - * vips_cast(). - * - * See also: vips_draw_mask(), vips_draw_image(), vips_insert(). - * - * Returns: 0 on success, or -1 on error. - */ -int -vips_draw_add( VipsImage *image, VipsImage *sub, int x, int y, ... ) -{ - va_list ap; - int result; - - va_start( ap, y ); - result = vips_call_split( "draw_add", ap, image, sub, x, y ); - va_end( ap ); - - return( result ); -} diff --git a/libvips/draw/draw_image.c b/libvips/draw/draw_image.c index c65bd939..4e5123cf 100644 --- a/libvips/draw/draw_image.c +++ b/libvips/draw/draw_image.c @@ -26,6 +26,8 @@ * - gtk-doc * 9/2/14 * - redo as a class, based on draw_image + * 28/3/14 + * - add "mode" param */ /* @@ -63,6 +65,7 @@ #include #include #include +#include #include #include @@ -88,7 +91,25 @@ typedef struct _VipsDrawImageClass { G_DEFINE_TYPE( VipsDrawImage, vips_draw_image, VIPS_TYPE_DRAW ); -#define LOOP( TYPE ) { \ +#define LOOP( TYPE, TEMP, MIN, MAX ) { \ + TYPE * restrict pt = (TYPE *) p; \ + TYPE * restrict qt = (TYPE *) q; \ + \ + for( x = 0; x < sz; x++ ) { \ + TEMP v; \ + \ + v = pt[x] + qt[x]; \ + \ + if( v > MAX ) \ + v = MAX; \ + else if( v < MIN ) \ + v = MIN; \ + \ + qt[x] = v; \ + } \ +} + +#define LOOPF( TYPE ) { \ TYPE * restrict pt = (TYPE *) p; \ TYPE * restrict qt = (TYPE *) q; \ \ @@ -97,37 +118,37 @@ G_DEFINE_TYPE( VipsDrawImage, vips_draw_image, VIPS_TYPE_DRAW ); } static void -vips_draw_image_mode_add( VipsDrawImage *draw_image, +vips_draw_image_mode_add( VipsDrawImage *draw_image, VipsImage *im, VipsPel *q, VipsPel *p, int n ) { /* Complex just doubles the size. */ - const int sz = clip_rect.width * im->Bands * + const int sz = n * im->Bands * (vips_band_format_iscomplex( im->BandFmt ) ? 2 : 1); int x; switch( im->BandFmt ) { case VIPS_FORMAT_UCHAR: - LOOP( unsigned char ); break; + LOOP( unsigned char, int, 0, UCHAR_MAX ); break; case VIPS_FORMAT_CHAR: - LOOP( signed char ); break; + LOOP( signed char, int, SCHAR_MIN, SCHAR_MAX ); break; case VIPS_FORMAT_USHORT: - LOOP( unsigned short ); break; + LOOP( unsigned short, int, 0, USHRT_MAX ); break; case VIPS_FORMAT_SHORT: - LOOP( signed short ); break; + LOOP( signed short, int, SCHAR_MIN, SCHAR_MAX ); break; case VIPS_FORMAT_UINT: - LOOP( unsigned int ); break; + LOOP( unsigned int, gint64, 0, UINT_MAX ); break; case VIPS_FORMAT_INT: - LOOP( signed int ); break; + LOOP( signed int, gint64, INT_MIN, INT_MAX ); break; case VIPS_FORMAT_FLOAT: case VIPS_FORMAT_COMPLEX: - LOOP( float ); break; + LOOPF( float ); break; case VIPS_FORMAT_DOUBLE: case VIPS_FORMAT_DPCOMPLEX: - LOOP( double ); break; + LOOPF( double ); break; default: g_assert( 0 ); @@ -210,8 +231,8 @@ vips_draw_image_build( VipsObject *object ) break; case VIPS_COMBINE_MODE_ADD: - vips_draw_image_add( draw_image, - q, p, clip_rect.width ); + vips_draw_image_mode_add( draw_image, + im, q, p, clip_rect.width ); break; default: @@ -283,11 +304,18 @@ vips_draw_image_init( VipsDrawImage *draw_image ) * @x: draw @sub here * @y: draw @sub here * + * Optional arguments: + * + * @mode: how to combine pixels + * * Draw @sub on top of @image at position @x, @y. The two images must have the * same Coding. If @sub has 1 band, the bands will be duplicated to match the * number of bands in @image. @sub will be converted to @image's format, see * vips_cast(). * + * Use @mode to set how pixels are combined. If you use + * #VIPS_COMBINE_MODE_ADD, both images muct be uncoded. + * * See also: vips_draw_mask(), vips_insert(). * * Returns: 0 on success, or -1 on error. diff --git a/libvips/include/vips/Makefile.am b/libvips/include/vips/Makefile.am index 9f7b796e..270110a9 100644 --- a/libvips/include/vips/Makefile.am +++ b/libvips/include/vips/Makefile.am @@ -67,6 +67,7 @@ vips_scan_headers = \ ${top_srcdir}/libvips/include/vips/operation.h \ ${top_srcdir}/libvips/include/vips/convolution.h \ ${top_srcdir}/libvips/include/vips/morphology.h \ + ${top_srcdir}/libvips/include/vips/draw.h \ ${top_srcdir}/libvips/include/vips/object.h enumtypes.h: $(vips_scan_headers) Makefile diff --git a/libvips/include/vips/draw.h b/libvips/include/vips/draw.h index 3b9ce377..cafbe339 100644 --- a/libvips/include/vips/draw.h +++ b/libvips/include/vips/draw.h @@ -57,8 +57,6 @@ int vips_draw_point1( VipsImage *image, double ink, int x, int y, ... ) int vips_draw_image( VipsImage *image, VipsImage *sub, int x, int y, ... ) __attribute__((sentinel)); -int vips_draw_add( VipsImage *image, VipsImage *sub, int x, int y, ... ) - __attribute__((sentinel)); int vips_draw_mask( VipsImage *image, double *ink, int n, VipsImage *mask, int x, int y, ... ) diff --git a/libvips/include/vips/enumtypes.h b/libvips/include/vips/enumtypes.h index 6fff1c4d..9e4978f7 100644 --- a/libvips/include/vips/enumtypes.h +++ b/libvips/include/vips/enumtypes.h @@ -81,6 +81,9 @@ GType vips_combine_get_type (void) G_GNUC_CONST; /* enumerations from "../../../libvips/include/vips/morphology.h" */ GType vips_operation_morphology_get_type (void) G_GNUC_CONST; #define VIPS_TYPE_OPERATION_MORPHOLOGY (vips_operation_morphology_get_type()) +/* enumerations from "../../../libvips/include/vips/draw.h" */ +GType vips_combine_mode_get_type (void) G_GNUC_CONST; +#define VIPS_TYPE_COMBINE_MODE (vips_combine_mode_get_type()) /* enumerations from "../../../libvips/include/vips/object.h" */ GType vips_argument_flags_get_type (void) G_GNUC_CONST; #define VIPS_TYPE_ARGUMENT_FLAGS (vips_argument_flags_get_type()) diff --git a/libvips/iofuncs/Makefile.am b/libvips/iofuncs/Makefile.am index 1342bd62..af1af54b 100644 --- a/libvips/iofuncs/Makefile.am +++ b/libvips/iofuncs/Makefile.am @@ -52,6 +52,7 @@ vips_scan_headers = \ ${top_srcdir}/libvips/include/vips/operation.h \ ${top_srcdir}/libvips/include/vips/convolution.h \ ${top_srcdir}/libvips/include/vips/morphology.h \ + ${top_srcdir}/libvips/include/vips/draw.h \ ${top_srcdir}/libvips/include/vips/object.h enumtypes.c: $(vips_scan_headers) Makefile diff --git a/libvips/iofuncs/enumtypes.c b/libvips/iofuncs/enumtypes.c index fec6fe77..d0a7c547 100644 --- a/libvips/iofuncs/enumtypes.c +++ b/libvips/iofuncs/enumtypes.c @@ -690,6 +690,25 @@ vips_operation_morphology_get_type( void ) return( etype ); } +/* enumerations from "../../libvips/include/vips/draw.h" */ +GType +vips_combine_mode_get_type( void ) +{ + static GType etype = 0; + + if( etype == 0 ) { + static const GEnumValue values[] = { + {VIPS_COMBINE_MODE_SET, "VIPS_COMBINE_MODE_SET", "set"}, + {VIPS_COMBINE_MODE_ADD, "VIPS_COMBINE_MODE_ADD", "add"}, + {VIPS_COMBINE_MODE_LAST, "VIPS_COMBINE_MODE_LAST", "last"}, + {0, NULL, NULL} + }; + + etype = g_enum_register_static( "VipsCombineMode", values ); + } + + return( etype ); +} /* enumerations from "../../libvips/include/vips/object.h" */ GType vips_argument_flags_get_type( void )