im_draw_smudge() done

This commit is contained in:
John Cupitt 2014-02-11 13:28:13 +00:00
parent 25fbe71c74
commit f4e970fb72
12 changed files with 185 additions and 256 deletions

View File

@ -4,7 +4,8 @@
- colourspace has a source_space option
- operations can be tagged as "deprecated"
- redo im_draw_circle(), im_draw_flood(), im_draw_line(), im_draw_mask(),
im_draw_image(), im_draw_rect(), im_draw_point(), im_read_point() as classes
im_draw_image(), im_draw_rect(), im_draw_point(), im_read_point(),
im_draw_smudge() as classes
- better rounding in vips_flatten()
- VipsStatistic operations are sequential

76
TODO
View File

@ -1,3 +1,50 @@
- need to do im_label_regions in morph
- swap VipsArea ink for VipsArrayDouble?
- ink to vec etc. should work for complex .. output or accept a double-length
vector
needs to work for eg. vips_linear() as well
if vector.len is == bands, expand to complex by setting imaginary == 0
if vector.len == bands * 2, set imaginary from constant
if vector.len == 1, bandup with imaginary == 0
if vector.len == 2, bandup setting imaginary from vector
what about bands == 2? ambigious
we must insist vector.length == 2 or bands * 2 for complex, or have the
current behaviour of imaginary == 0 always
- try:
$ vips draw_smudge
usage:
draw_smudge image ink left top width height
blur a rectangle on an image
where:
image - Image to draw on, input VipsImage
ink - Colour for pixels, input VipsArrayDouble
left - Rect to fill, input gint
top - Rect to fill, input gint
width - Rect to fill, input gint
height - Rect to fill, input gint
nice if we could hide the "ink" param
also for
draw_image
draw_line_user
we could either move ink to the other operations or make a new subclass of
draw containing the ink arg
- try
$ vips getpoint
@ -38,11 +85,6 @@
- swap VipsArea ink for VipsArrayDouble?
- try:
@ -52,29 +94,7 @@
with wtc.jpg, segv if libvips is compiled with -O, OK without
- ink to vec etc. should work for complex .. output or accept a double-length
vector
needs to work for eg. vips_linear() as well
if vector.len is == bands, expand to complex by setting imaginary == 0
if vector.len == bands * 2, set imaginary from constant
if vector.len == 1, bandup with imaginary == 0
if vector.len == 2, bandup setting imaginary from vector
what about bands == 2? ambigious
we must insist vector.length == 2 or bands * 2 for complex, or have the
current behaviour of imaginary == 0 always
- inplace
can we set a region for the pixels we will modify?
is there any point doing this? only useful on 32-bit machines, which
don't really exist any more
- need to do mosaicing and inplace, plus im_label_regions in morph
- need to do mosaicing
- now vips_linear() has uchar output, can we do something with orc?

View File

@ -1,6 +1,7 @@
noinst_LTLIBRARIES = libdeprecated.la
libdeprecated_la_SOURCES = \
inplace_dispatch.c \
tone.c \
freq_dispatch.c \
im_linreg.c \

View File

@ -4603,6 +4603,12 @@ im_draw_point( VipsImage *image, int x, int y, VipsPel *ink )
return( vips_draw_point( image, vec, n, x, y, NULL ) );
}
int
im_draw_smudge( VipsImage *im, int left, int top, int width, int height )
{
return( vips_draw_smudge( im, left, top, width, height, NULL ) );
}
int
im_read_point( VipsImage *image, int x, int y, VipsPel *ink )
{

View File

@ -12,9 +12,6 @@ libdraw_la_SOURCES = \
draw_line.c \
draw_line_mask.c \
draw_line_user.c \
im_draw_smudge.c \
inplace_dispatch.c \
old_draw.c \
old_draw.h
draw_smudge.c
AM_CPPFLAGS = -I${top_srcdir}/libvips/include @VIPS_CFLAGS@ @VIPS_INCLUDES@

View File

@ -138,6 +138,7 @@ vips_draw_operation_init( void )
extern GType vips_draw_line_user_get_type( void );
extern GType vips_draw_circle_get_type( void );
extern GType vips_draw_flood_get_type( void );
extern GType vips_draw_smudge_get_type( void );
vips_draw_rect_get_type();
vips_draw_image_get_type();
@ -147,6 +148,7 @@ vips_draw_operation_init( void )
vips_draw_line_user_get_type();
vips_draw_circle_get_type();
vips_draw_flood_get_type();
vips_draw_smudge_get_type();
}
/* Fill a scanline between points x1 and x2 inclusive. x1 < x2.

View File

@ -18,6 +18,8 @@
* - deprecate im_smear()
* 30/1/12
* - back to the custom smear, the conv one was too slow
* 11/2/14
* - redo as a class
*/
/*
@ -56,32 +58,43 @@
#include <stdlib.h>
#include <vips/vips.h>
#include <vips/internal.h>
/**
* im_draw_smudge:
* @image: image to smudge
* @left: area to smudge
* @top: area to smudge
* @width: area to smudge
* @height: area to smudge
*
* Smudge a section of @image. Each pixel in the area @left, @top, @width,
* @height is replaced by the average of the surrounding 3x3 pixels.
*
* This an inplace operation, so @image 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_line().
*
* Returns: 0 on success, or -1 on error.
#include "pdraw.h"
typedef struct _VipsDrawSmudge {
VipsDraw parent_object;
/* Parameters.
*/
int
im_draw_smudge( VipsImage *im, int left, int top, int width, int height )
int left;
int top;
int width;
int height;
} VipsDrawSmudge;
typedef struct _VipsDrawSmudgeClass {
VipsDrawClass parent_class;
} VipsDrawSmudgeClass;
G_DEFINE_TYPE( VipsDrawSmudge, vips_draw_smudge, VIPS_TYPE_DRAW );
static int
vips_draw_smudge_build( VipsObject *object )
{
VipsDraw *draw = VIPS_DRAW( object );
VipsImage *im = draw->image;
VipsDrawSmudge *smudge = (VipsDrawSmudge *) object;
int left = smudge->left;
int top = smudge->top;
int width = smudge->width;
int height = smudge->height;
/* Double bands for complex images.
*/
int bands = vips_image_get_bands( im ) *
int bands = vips_image_get_bands( draw->image ) *
(vips_band_format_iscomplex( vips_image_get_format( im ) ) ?
2 : 1);
int elements = bands * vips_image_get_width( im );
@ -90,6 +103,10 @@ im_draw_smudge( VipsImage *im, int left, int top, int width, int height )
double *total;
int x, y, i, j, b;
if( VIPS_OBJECT_CLASS( vips_draw_smudge_parent_class )->
build( object ) )
return( -1 );
area.left = left;
area.top = top;
area.width = width;
@ -107,13 +124,12 @@ im_draw_smudge( VipsImage *im, int left, int top, int width, int height )
if( vips_rect_isempty( &clipped ) )
return( 0 );
if( !(total = VIPS_ARRAY( im, bands, double )) ||
im_rwcheck( im ) )
if( !(total = VIPS_ARRAY( im, bands, double )) )
return( -1 );
/* What we do for each type.
*/
#define SMUDGE(TYPE) \
#define SMUDGE( TYPE ) \
for( y = 0; y < clipped.height; y++ ) { \
TYPE *q; \
TYPE *p; \
@ -163,3 +179,81 @@ im_draw_smudge( VipsImage *im, int left, int top, int width, int height )
return( 0 );
}
static void
vips_draw_smudge_class_init( VipsDrawSmudgeClass *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_smudge";
vobject_class->description = _( "blur a rectangle on an image" );
vobject_class->build = vips_draw_smudge_build;
VIPS_ARG_INT( class, "left", 6,
_( "Left" ),
_( "Rect to fill" ),
VIPS_ARGUMENT_REQUIRED_INPUT,
G_STRUCT_OFFSET( VipsDrawSmudge, left ),
-1000000000, 1000000000, 0 );
VIPS_ARG_INT( class, "top", 7,
_( "top" ),
_( "Rect to fill" ),
VIPS_ARGUMENT_REQUIRED_INPUT,
G_STRUCT_OFFSET( VipsDrawSmudge, top ),
-1000000000, 1000000000, 0 );
VIPS_ARG_INT( class, "width", 8,
_( "width" ),
_( "Rect to fill" ),
VIPS_ARGUMENT_REQUIRED_INPUT,
G_STRUCT_OFFSET( VipsDrawSmudge, width ),
-1000000000, 1000000000, 0 );
VIPS_ARG_INT( class, "height", 9,
_( "height" ),
_( "Rect to fill" ),
VIPS_ARGUMENT_REQUIRED_INPUT,
G_STRUCT_OFFSET( VipsDrawSmudge, height ),
-1000000000, 1000000000, 0 );
}
static void
vips_draw_smudge_init( VipsDrawSmudge *draw_smudge )
{
}
/**
* vips_draw_smudge:
* @image: image to draw on
* @left: point to paint
* @top: point to paint
* @width: area to paint
* @height: area to paint
*
* Smudge a section of @image. Each pixel in the area @left, @top, @width,
* @height is replaced by the average of the surrounding 3x3 pixels.
*
* See also: vips_draw_line().
*
* Returns: 0 on success, or -1 on error.
*/
int
vips_draw_smudge( VipsImage *image,
int left, int top, int width, int height, ... )
{
va_list ap;
int result;
va_start( ap, height );
result = vips_call_split( "draw_smudge", ap,
image, NULL, left, top, width, height );
va_end( ap );
return( result );
}

View File

@ -1,102 +0,0 @@
/* base class for drawing operations
*
* 27/9/10
* - from im_draw_circle()
* 17/11/10
* - oops, scanline clipping was off by 1
*/
/*
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 <config.h>
#endif /*HAVE_CONFIG_H*/
#include <vips/intl.h>
#include <string.h>
#include <vips/vips.h>
#include "old_draw.h"
/* Fill a scanline between points x1 and x2 inclusive. x1 < x2.
*/
void
im__draw_scanline( Draw *draw, int y, int x1, int x2 )
{
VipsPel *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 = 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, VipsPel *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 = (VipsPel *) im_malloc( NULL, draw->psize )) )
return( NULL );
memcpy( draw->ink, ink, draw->psize );
}
return( draw );
}

View File

@ -1,92 +0,0 @@
/* 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., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
/*
These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
*/
/* Our state.
*/
typedef struct _Draw {
/* Parameters.
*/
IMAGE *im; /* Draw here */
VipsPel *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, VipsPel *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, IM_IMAGE_ADDR( draw->im, x, y ) );
}
/* Is p painted?
*/
static inline gboolean
im__draw_painted( Draw *draw, VipsPel *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, VipsPel *ink );

View File

@ -90,10 +90,9 @@ int vips_draw_flood( VipsImage *image, double *ink, int n, int x, int y, ... )
int vips_draw_flood1( VipsImage *image, double ink, int x, int y, ... )
__attribute__((sentinel));
int im_draw_smudge( VipsImage *image,
int left, int top, int width, int height );
int vips_draw_smudge( VipsImage *image,
int left, int top, int width, int height, ... )
__attribute__((sentinel));
#ifdef __cplusplus
}

View File

@ -1029,6 +1029,9 @@ int im_draw_flood_other( VipsImage *image, VipsImage *test,
int im_draw_point( VipsImage *image, int x, int y, VipsPel *ink );
int im_read_point( VipsImage *image, int x, int y, VipsPel *ink );
int im_draw_smudge( VipsImage *image,
int left, int top, int width, int height );
#ifdef __cplusplus
}
#endif /*__cplusplus*/