libvips/libvips/draw/draw_smudge.c

261 lines
6.2 KiB
C

/* Smudge a piece of 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()
* ? JC
* - im_makerw() changed to im_rwcheck()
* 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
* 30/9/10
* - gtk-doc
* - deprecate im_smear()
* 30/1/12
* - back to the custom smear, the conv one was too slow
* 11/2/14
* - redo as a 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., 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 <glib/gi18n-lib.h>
#include <stdio.h>
#include <stdlib.h>
#include <vips/vips.h>
#include <vips/internal.h>
#include "pdraw.h"
typedef struct _VipsDrawSmudge {
VipsDraw parent_object;
/* Parameters.
*/
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( draw->image ) *
(vips_band_format_iscomplex( vips_image_get_format( im ) ) ?
2 : 1);
int elements = bands * vips_image_get_width( im );
VipsRect area, image, clipped;
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;
area.height = height;
/* Don't do the margins.
*/
image.left = 0;
image.top = 0;
image.width = im->Xsize;
image.height = im->Ysize;
vips_rect_marginadjust( &image, -1 );
vips_rect_intersectrect( &area, &image, &clipped );
if( vips_rect_isempty( &clipped ) )
return( 0 );
if( !(total = VIPS_ARRAY( im, bands, double )) )
return( -1 );
/* What we do for each type.
*/
#define SMUDGE( TYPE ) \
for( y = 0; y < clipped.height; y++ ) { \
TYPE *q; \
TYPE *p; \
\
q = (TYPE *) VIPS_IMAGE_ADDR( im, \
clipped.left, clipped.top + y ); \
p = q - elements - bands; \
for( x = 0; x < clipped.width; x++ ) { \
TYPE *p1, *p2; \
\
for( b = 0; b < bands; b++ ) \
total[b] = 0.0; \
\
p1 = p; \
for( i = 0; i < 3; i++ ) { \
p2 = p1; \
for( j = 0; j < 3; j++ ) \
for( b = 0; b < bands; b++ ) \
total[b] += *p2++; \
\
p1 += elements; \
} \
\
for( b = 0; b < bands; b++ ) \
q[b] = (16 * (double) q[b] + total[b]) / 25.0; \
\
p += bands; \
q += bands; \
} \
}
switch( vips_image_get_format( im ) ) {
case VIPS_FORMAT_UCHAR: SMUDGE( unsigned char ); break;
case VIPS_FORMAT_CHAR: SMUDGE( char ); break;
case VIPS_FORMAT_USHORT: SMUDGE( unsigned short ); break;
case VIPS_FORMAT_SHORT: SMUDGE( short ); break;
case VIPS_FORMAT_UINT: SMUDGE( unsigned int ); break;
case VIPS_FORMAT_INT: SMUDGE( int ); break;
case VIPS_FORMAT_FLOAT: SMUDGE( float ); break;
case VIPS_FORMAT_DOUBLE: SMUDGE( double ); break;
case VIPS_FORMAT_COMPLEX: SMUDGE( float ); break;
case VIPS_FORMAT_DPCOMPLEX: SMUDGE( double ); break;
default:
g_assert_not_reached();
}
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: (method)
* @image: image to draw on
* @left: point to paint
* @top: point to paint
* @width: area to paint
* @height: area to paint
* @...: %NULL-terminated list of optional named arguments
*
* 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, left, top, width, height );
va_end( ap );
return( result );
}