removed all traces of yafrsmooth (obsolete prototype)

This commit is contained in:
Nicolas Robidoux 2010-05-15 22:24:27 +00:00
parent 16d6518965
commit 7de848e644
6 changed files with 174 additions and 978 deletions

2
TODO
View File

@ -133,7 +133,7 @@ g++ -shared -nostdlib /usr/lib/gcc/x86_64-linux-gnu/4.4.3/../../../../lib/crti.o
not really stable yet :( don't document not really stable yet :( don't document
- how to expose things like yafrsmooth's "sharpening" parameter to - how to expose things like snohalo1's "blur" parameter to
C++/Python? C++/Python?
can we write a find-by-nickname function? eg. can we write a find-by-nickname function? eg.

View File

@ -132,14 +132,14 @@ vips_argument_table_destroy( VipsArgumentTable *table )
/* Loop over the vips_arguments to an object. /* Loop over the vips_arguments to an object.
*/ */
void * void *
vips_argument_map( VipsObject *object, vips_argument_map( VipsObject *object,
VipsArgumentMapFn fn, void *a, void *b ) VipsArgumentMapFn fn, void *a, void *b )
{ {
VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object ); VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object );
GSList *p; GSList *p;
for( p = class->argument_table_traverse; p; p = p->next ) { for( p = class->argument_table_traverse; p; p = p->next ) {
VipsArgumentClass *argument_class = VipsArgumentClass *argument_class =
(VipsArgumentClass *) p->data; (VipsArgumentClass *) p->data;
VipsArgument *argument = (VipsArgument *) argument_class; VipsArgument *argument = (VipsArgument *) argument_class;
GParamSpec *pspec = argument->pspec; GParamSpec *pspec = argument->pspec;
@ -149,11 +149,11 @@ vips_argument_map( VipsObject *object,
/* We have many props on the arg table ... filter out the ones /* We have many props on the arg table ... filter out the ones
* for this class. * for this class.
*/ */
if( g_object_class_find_property( G_OBJECT_CLASS( class ), if( g_object_class_find_property( G_OBJECT_CLASS( class ),
pspec->name ) == pspec ) { pspec->name ) == pspec ) {
void *result; void *result;
if( (result = fn( object, pspec, if( (result = fn( object, pspec,
argument_class, argument_instance, a, b )) ) argument_class, argument_instance, a, b )) )
return( result ); return( result );
} }
@ -164,7 +164,7 @@ vips_argument_map( VipsObject *object,
static void * static void *
vips_argument_init2( VipsObject *object, GParamSpec *pspec, vips_argument_init2( VipsObject *object, GParamSpec *pspec,
VipsArgumentClass *argument_class, VipsArgumentClass *argument_class,
VipsArgumentInstance *argument_instance, VipsArgumentInstance *argument_instance,
void *a, void *b ) void *a, void *b )
{ {
@ -201,11 +201,11 @@ static void
vips_argument_init( VipsObject *object ) vips_argument_init( VipsObject *object )
{ {
if( !object->argument_table ) { if( !object->argument_table ) {
object->argument_table = g_hash_table_new_full( g_direct_hash, object->argument_table = g_hash_table_new_full( g_direct_hash,
g_direct_equal, NULL, g_direct_equal, NULL,
(GDestroyNotify) vips_argument_instance_free ); (GDestroyNotify) vips_argument_instance_free );
/* Make a VipsArgumentInstance for each installed argument /* Make a VipsArgumentInstance for each installed argument
* property. * property.
*/ */
vips_argument_map( object, vips_argument_init2, NULL, NULL ); vips_argument_map( object, vips_argument_init2, NULL, NULL );
@ -215,14 +215,14 @@ vips_argument_init( VipsObject *object )
/* Convenience ... given the VipsArgumentClass, get the VipsArgumentInstance. /* Convenience ... given the VipsArgumentClass, get the VipsArgumentInstance.
*/ */
VipsArgumentInstance * VipsArgumentInstance *
vips__argument_get_instance( VipsArgumentClass *argument_class, vips__argument_get_instance( VipsArgumentClass *argument_class,
VipsObject *object ) VipsObject *object )
{ {
/* Make sure the instance args are built. /* Make sure the instance args are built.
*/ */
vips_argument_init( object ); vips_argument_init( object );
return( (VipsArgumentInstance *) return( (VipsArgumentInstance *)
vips__argument_table_lookup( object->argument_table, vips__argument_table_lookup( object->argument_table,
((VipsArgument *) argument_class)->pspec ) ); ((VipsArgument *) argument_class)->pspec ) );
} }
@ -235,7 +235,7 @@ vips_object_clear_object( VipsObject *object, GParamSpec *pspec )
vips__argument_table_lookup( class->argument_table, pspec ); vips__argument_table_lookup( class->argument_table, pspec );
VipsArgumentInstance *argument_instance = VipsArgumentInstance *argument_instance =
vips__argument_get_instance( argument_class, object ); vips__argument_get_instance( argument_class, object );
GObject **member = &G_STRUCT_MEMBER( GObject *, object, GObject **member = &G_STRUCT_MEMBER( GObject *, object,
argument_class->offset ); argument_class->offset );
if( *member ) { if( *member ) {
@ -243,9 +243,9 @@ vips_object_clear_object( VipsObject *object, GParamSpec *pspec )
#ifdef DEBUG_REF #ifdef DEBUG_REF
printf( "vips_object_clear_object: vips object: " ); printf( "vips_object_clear_object: vips object: " );
vips_object_print( object ); vips_object_print( object );
printf( " no longer refers to gobject %s (%p)\n", printf( " no longer refers to gobject %s (%p)\n",
G_OBJECT_TYPE_NAME( *member ), *member ); G_OBJECT_TYPE_NAME( *member ), *member );
printf( " count down to %d\n", printf( " count down to %d\n",
G_OBJECT( *member )->ref_count - 1 ); G_OBJECT( *member )->ref_count - 1 );
#endif /*DEBUG_REF*/ #endif /*DEBUG_REF*/
@ -257,16 +257,16 @@ vips_object_clear_object( VipsObject *object, GParamSpec *pspec )
#ifdef DEBUG_REF #ifdef DEBUG_REF
printf( "vips_object_clear_object: gobject %s (%p)\n", printf( "vips_object_clear_object: gobject %s (%p)\n",
G_OBJECT_TYPE_NAME( *member ), *member ); G_OBJECT_TYPE_NAME( *member ), *member );
printf( " no longer refers to vips object: " ); printf( " no longer refers to vips object: " );
vips_object_print( object ); vips_object_print( object );
printf( " count down to %d\n", printf( " count down to %d\n",
G_OBJECT( object )->ref_count - 1 ); G_OBJECT( object )->ref_count - 1 );
#endif /*DEBUG_REF*/ #endif /*DEBUG_REF*/
/* The object reffed us. Stop listening link to the /* The object reffed us. Stop listening link to the
* object's "destroy" signal. We can come here from * object's "destroy" signal. We can come here from
* object being destroyed, in which case the handler * object being destroyed, in which case the handler
* will already have been disconnected for us. * will already have been disconnected for us.
*/ */
if( g_signal_handler_is_connected( object, if( g_signal_handler_is_connected( object,
argument_instance->destroy_id ) ) argument_instance->destroy_id ) )
@ -285,8 +285,8 @@ vips_object_clear_object( VipsObject *object, GParamSpec *pspec )
/* Free any args which are holding resources. /* Free any args which are holding resources.
*/ */
static void * static void *
vips_object_dispose_argument( VipsObject *object, GParamSpec *pspec, vips_object_dispose_argument( VipsObject *object, GParamSpec *pspec,
VipsArgumentClass *argument_class, VipsArgumentClass *argument_class,
VipsArgumentInstance *argument_instance, VipsArgumentInstance *argument_instance,
void *a, void *b ) void *a, void *b )
{ {
@ -300,19 +300,19 @@ vips_object_dispose_argument( VipsObject *object, GParamSpec *pspec,
g_assert( ((VipsArgument *) argument_instance)->pspec == pspec ); g_assert( ((VipsArgument *) argument_instance)->pspec == pspec );
if( G_IS_PARAM_SPEC_STRING( pspec ) ) { if( G_IS_PARAM_SPEC_STRING( pspec ) ) {
char **member = &G_STRUCT_MEMBER( char *, object, char **member = &G_STRUCT_MEMBER( char *, object,
argument_class->offset ); argument_class->offset );
IM_FREE( *member ); IM_FREE( *member );
} }
else if( G_IS_PARAM_SPEC_OBJECT( pspec ) ) else if( G_IS_PARAM_SPEC_OBJECT( pspec ) )
vips_object_clear_object( object, pspec ); vips_object_clear_object( object, pspec );
else if( G_IS_PARAM_SPEC_BOXED( pspec ) ) { else if( G_IS_PARAM_SPEC_BOXED( pspec ) ) {
gpointer *member = &G_STRUCT_MEMBER( gpointer, object, gpointer *member = &G_STRUCT_MEMBER( gpointer, object,
argument_class->offset ); argument_class->offset );
if( *member ) { if( *member ) {
g_boxed_free( G_PARAM_SPEC_VALUE_TYPE( pspec ), g_boxed_free( G_PARAM_SPEC_VALUE_TYPE( pspec ),
*member ); *member );
*member = NULL; *member = NULL;
} }
@ -354,7 +354,7 @@ vips_object_finalize( GObject *gobject )
} }
static void static void
vips_object_arg_destroy( GObject *argument, vips_object_arg_destroy( GObject *argument,
VipsArgumentInstance *argument_instance ) VipsArgumentInstance *argument_instance )
{ {
VipsObject *object = argument_instance->object; VipsObject *object = argument_instance->object;
@ -363,10 +363,10 @@ vips_object_arg_destroy( GObject *argument,
/* Argument had reffed us ... now it's being destroyed, so we unref. /* Argument had reffed us ... now it's being destroyed, so we unref.
*/ */
vips_object_clear_object( object, pspec ); vips_object_clear_object( object, pspec );
} }
static void static void
vips_object_set_object( VipsObject *object, GParamSpec *pspec, vips_object_set_object( VipsObject *object, GParamSpec *pspec,
GObject *argument ) GObject *argument )
{ {
VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object ); VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object );
@ -374,7 +374,7 @@ vips_object_set_object( VipsObject *object, GParamSpec *pspec,
vips__argument_table_lookup( class->argument_table, pspec ); vips__argument_table_lookup( class->argument_table, pspec );
VipsArgumentInstance *argument_instance = VipsArgumentInstance *argument_instance =
vips__argument_get_instance( argument_class, object ); vips__argument_get_instance( argument_class, object );
GObject **member = &G_STRUCT_MEMBER( GObject *, object, GObject **member = &G_STRUCT_MEMBER( GObject *, object,
argument_class->offset ); argument_class->offset );
g_assert( !*member ); g_assert( !*member );
@ -386,9 +386,9 @@ vips_object_set_object( VipsObject *object, GParamSpec *pspec,
#ifdef DEBUG_REF #ifdef DEBUG_REF
printf( "vips_object_set_object: vips object: " ); printf( "vips_object_set_object: vips object: " );
vips_object_print( object ); vips_object_print( object );
printf( " refers to gobject %s (%p)\n", printf( " refers to gobject %s (%p)\n",
G_OBJECT_TYPE_NAME( *member ), *member ); G_OBJECT_TYPE_NAME( *member ), *member );
printf( " count up to %d\n", printf( " count up to %d\n",
G_OBJECT( *member )->ref_count ); G_OBJECT( *member )->ref_count );
#endif /*DEBUG_REF*/ #endif /*DEBUG_REF*/
@ -400,9 +400,9 @@ vips_object_set_object( VipsObject *object, GParamSpec *pspec,
#ifdef DEBUG_REF #ifdef DEBUG_REF
printf( "vips_object_set_object: gobject %s (%p)\n", printf( "vips_object_set_object: gobject %s (%p)\n",
G_OBJECT_TYPE_NAME( *member ), *member ); G_OBJECT_TYPE_NAME( *member ), *member );
printf( " refers to vips object: " ); printf( " refers to vips object: " );
vips_object_print( object ); vips_object_print( object );
printf( " count up to %d\n", printf( " count up to %d\n",
G_OBJECT (object)->ref_count ); G_OBJECT (object)->ref_count );
#endif /*DEBUG_REF*/ #endif /*DEBUG_REF*/
@ -420,7 +420,7 @@ vips_object_set_object( VipsObject *object, GParamSpec *pspec,
/* Also used by subclasses, so not static. /* Also used by subclasses, so not static.
*/ */
void void
vips_object_set_property( GObject *gobject, vips_object_set_property( GObject *gobject,
guint property_id, const GValue *value, GParamSpec *pspec ) guint property_id, const GValue *value, GParamSpec *pspec )
{ {
VipsObject *object = VIPS_OBJECT( gobject ); VipsObject *object = VIPS_OBJECT( gobject );
@ -431,7 +431,7 @@ vips_object_set_property( GObject *gobject,
vips__argument_get_instance( argument_class, object ); vips__argument_get_instance( argument_class, object );
if( !argument_class ) { if( !argument_class ) {
G_OBJECT_WARN_INVALID_PROPERTY_ID( gobject, G_OBJECT_WARN_INVALID_PROPERTY_ID( gobject,
property_id, pspec ); property_id, pspec );
return; return;
} }
@ -454,9 +454,9 @@ vips_object_set_property( GObject *gobject,
/* If this is a construct-only argument, we can only set before we've /* If this is a construct-only argument, we can only set before we've
* built. * built.
*/ */
if( argument_class->flags & VIPS_ARGUMENT_CONSTRUCT && if( argument_class->flags & VIPS_ARGUMENT_CONSTRUCT &&
object->constructed ) { object->constructed ) {
g_warning( "%s: %s can't assign '%s' after construct", g_warning( "%s: %s can't assign '%s' after construct",
G_STRLOC, G_STRLOC,
G_OBJECT_TYPE_NAME( gobject ), G_OBJECT_TYPE_NAME( gobject ),
g_param_spec_get_name( pspec ) ); g_param_spec_get_name( pspec ) );
@ -467,7 +467,7 @@ vips_object_set_property( GObject *gobject,
*/ */
if( argument_class->flags & VIPS_ARGUMENT_SET_ONCE && if( argument_class->flags & VIPS_ARGUMENT_SET_ONCE &&
argument_instance->assigned ) { argument_instance->assigned ) {
g_warning( "%s: %s can only assign '%s' once", g_warning( "%s: %s can only assign '%s' once",
G_STRLOC, G_STRLOC,
G_OBJECT_TYPE_NAME( gobject ), G_OBJECT_TYPE_NAME( gobject ),
g_param_spec_get_name( pspec ) ); g_param_spec_get_name( pspec ) );
@ -475,7 +475,7 @@ vips_object_set_property( GObject *gobject,
} }
if( G_IS_PARAM_SPEC_STRING( pspec ) ) { if( G_IS_PARAM_SPEC_STRING( pspec ) ) {
char **member = &G_STRUCT_MEMBER( char *, object, char **member = &G_STRUCT_MEMBER( char *, object,
argument_class->offset ); argument_class->offset );
IM_SETSTR( *member, g_value_get_string( value ) ); IM_SETSTR( *member, g_value_get_string( value ) );
@ -487,45 +487,45 @@ vips_object_set_property( GObject *gobject,
/* Install the new object. /* Install the new object.
*/ */
vips_object_set_object( object, pspec, vips_object_set_object( object, pspec,
g_value_get_object( value ) ); g_value_get_object( value ) );
} }
else if( G_IS_PARAM_SPEC_INT( pspec ) ) { else if( G_IS_PARAM_SPEC_INT( pspec ) ) {
int *member = &G_STRUCT_MEMBER( int, object, int *member = &G_STRUCT_MEMBER( int, object,
argument_class->offset ); argument_class->offset );
*member = g_value_get_int( value ); *member = g_value_get_int( value );
} }
else if( G_IS_PARAM_SPEC_BOOLEAN( pspec ) ) { else if( G_IS_PARAM_SPEC_BOOLEAN( pspec ) ) {
gboolean *member = &G_STRUCT_MEMBER( gboolean, object, gboolean *member = &G_STRUCT_MEMBER( gboolean, object,
argument_class->offset ); argument_class->offset );
*member = g_value_get_boolean( value ); *member = g_value_get_boolean( value );
} }
else if( G_IS_PARAM_SPEC_ENUM( pspec ) ) { else if( G_IS_PARAM_SPEC_ENUM( pspec ) ) {
int *member = &G_STRUCT_MEMBER( int, object, int *member = &G_STRUCT_MEMBER( int, object,
argument_class->offset ); argument_class->offset );
*member = g_value_get_enum( value ); *member = g_value_get_enum( value );
} }
else if( G_IS_PARAM_SPEC_POINTER( pspec ) ) { else if( G_IS_PARAM_SPEC_POINTER( pspec ) ) {
gpointer *member = &G_STRUCT_MEMBER( gpointer, object, gpointer *member = &G_STRUCT_MEMBER( gpointer, object,
argument_class->offset ); argument_class->offset );
*member = g_value_get_pointer( value ); *member = g_value_get_pointer( value );
} }
else if( G_IS_PARAM_SPEC_DOUBLE( pspec ) ) { else if( G_IS_PARAM_SPEC_DOUBLE( pspec ) ) {
double *member = &G_STRUCT_MEMBER( double, object, double *member = &G_STRUCT_MEMBER( double, object,
argument_class->offset ); argument_class->offset );
*member = g_value_get_double( value ); *member = g_value_get_double( value );
} }
else if( G_IS_PARAM_SPEC_BOXED( pspec ) ) { else if( G_IS_PARAM_SPEC_BOXED( pspec ) ) {
gpointer *member = &G_STRUCT_MEMBER( gpointer, object, gpointer *member = &G_STRUCT_MEMBER( gpointer, object,
argument_class->offset ); argument_class->offset );
if( *member ) { if( *member ) {
g_boxed_free( G_PARAM_SPEC_VALUE_TYPE( pspec ), g_boxed_free( G_PARAM_SPEC_VALUE_TYPE( pspec ),
*member ); *member );
*member = NULL; *member = NULL;
} }
@ -536,13 +536,13 @@ vips_object_set_property( GObject *gobject,
*member = g_value_dup_boxed( value ); *member = g_value_dup_boxed( value );
} }
else { else {
g_warning( "%s: %s unimplemented property type %s", g_warning( "%s: %s unimplemented property type %s",
G_STRLOC, G_STRLOC,
G_OBJECT_TYPE_NAME( gobject ), G_OBJECT_TYPE_NAME( gobject ),
g_type_name( G_PARAM_SPEC_VALUE_TYPE( pspec ) ) ); g_type_name( G_PARAM_SPEC_VALUE_TYPE( pspec ) ) );
} }
/* Note that it's now been set. /* Note that it's now been set.
*/ */
argument_instance->assigned = TRUE; argument_instance->assigned = TRUE;
} }
@ -550,7 +550,7 @@ vips_object_set_property( GObject *gobject,
/* Also used by subclasses, so not static. /* Also used by subclasses, so not static.
*/ */
void void
vips_object_get_property( GObject *gobject, vips_object_get_property( GObject *gobject,
guint property_id, GValue *value, GParamSpec *pspec ) guint property_id, GValue *value, GParamSpec *pspec )
{ {
VipsObject *object = VIPS_OBJECT( gobject ); VipsObject *object = VIPS_OBJECT( gobject );
@ -559,7 +559,7 @@ vips_object_get_property( GObject *gobject,
vips__argument_table_lookup( class->argument_table, pspec ); vips__argument_table_lookup( class->argument_table, pspec );
if( !argument_class ) { if( !argument_class ) {
G_OBJECT_WARN_INVALID_PROPERTY_ID( gobject, G_OBJECT_WARN_INVALID_PROPERTY_ID( gobject,
property_id, pspec ); property_id, pspec );
return; return;
} }
@ -567,49 +567,49 @@ vips_object_get_property( GObject *gobject,
g_assert( ((VipsArgument *) argument_class)->pspec == pspec ); g_assert( ((VipsArgument *) argument_class)->pspec == pspec );
if( G_IS_PARAM_SPEC_STRING( pspec ) ) { if( G_IS_PARAM_SPEC_STRING( pspec ) ) {
char *member = G_STRUCT_MEMBER( char *, object, char *member = G_STRUCT_MEMBER( char *, object,
argument_class->offset ); argument_class->offset );
g_value_set_string( value, member ); g_value_set_string( value, member );
} }
else if( G_IS_PARAM_SPEC_OBJECT( pspec ) ) { else if( G_IS_PARAM_SPEC_OBJECT( pspec ) ) {
GObject **member = &G_STRUCT_MEMBER( GObject *, object, GObject **member = &G_STRUCT_MEMBER( GObject *, object,
argument_class->offset ); argument_class->offset );
g_value_set_object( value, *member ); g_value_set_object( value, *member );
} }
else if( G_IS_PARAM_SPEC_INT( pspec ) ) { else if( G_IS_PARAM_SPEC_INT( pspec ) ) {
int *member = &G_STRUCT_MEMBER( int, object, int *member = &G_STRUCT_MEMBER( int, object,
argument_class->offset ); argument_class->offset );
g_value_set_int( value, *member ); g_value_set_int( value, *member );
} }
else if( G_IS_PARAM_SPEC_BOOLEAN( pspec ) ) { else if( G_IS_PARAM_SPEC_BOOLEAN( pspec ) ) {
gboolean *member = &G_STRUCT_MEMBER( gboolean, object, gboolean *member = &G_STRUCT_MEMBER( gboolean, object,
argument_class->offset ); argument_class->offset );
g_value_set_boolean( value, *member ); g_value_set_boolean( value, *member );
} }
else if( G_IS_PARAM_SPEC_ENUM( pspec ) ) { else if( G_IS_PARAM_SPEC_ENUM( pspec ) ) {
int *member = &G_STRUCT_MEMBER( int, object, int *member = &G_STRUCT_MEMBER( int, object,
argument_class->offset ); argument_class->offset );
g_value_set_enum( value, *member ); g_value_set_enum( value, *member );
} }
else if( G_IS_PARAM_SPEC_POINTER( pspec ) ) { else if( G_IS_PARAM_SPEC_POINTER( pspec ) ) {
gpointer *member = &G_STRUCT_MEMBER( gpointer, object, gpointer *member = &G_STRUCT_MEMBER( gpointer, object,
argument_class->offset ); argument_class->offset );
g_value_set_pointer( value, *member ); g_value_set_pointer( value, *member );
} }
else if( G_IS_PARAM_SPEC_DOUBLE( pspec ) ) { else if( G_IS_PARAM_SPEC_DOUBLE( pspec ) ) {
double *member = &G_STRUCT_MEMBER( double, object, double *member = &G_STRUCT_MEMBER( double, object,
argument_class->offset ); argument_class->offset );
g_value_set_double( value, *member ); g_value_set_double( value, *member );
} }
else if( G_IS_PARAM_SPEC_BOXED( pspec ) ) { else if( G_IS_PARAM_SPEC_BOXED( pspec ) ) {
gpointer *member = &G_STRUCT_MEMBER( gpointer, object, gpointer *member = &G_STRUCT_MEMBER( gpointer, object,
argument_class->offset ); argument_class->offset );
/* Copy the boxed into our pointer (will use eg. /* Copy the boxed into our pointer (will use eg.
@ -618,16 +618,16 @@ vips_object_get_property( GObject *gobject,
g_value_set_boxed( value, *member ); g_value_set_boxed( value, *member );
} }
else { else {
g_warning( "%s: %s unimplemented property type %s", g_warning( "%s: %s unimplemented property type %s",
G_STRLOC, G_STRLOC,
G_OBJECT_TYPE_NAME( gobject ), G_OBJECT_TYPE_NAME( gobject ),
g_type_name( G_PARAM_SPEC_VALUE_TYPE( pspec ) ) ); g_type_name( G_PARAM_SPEC_VALUE_TYPE( pspec ) ) );
} }
} }
static void * static void *
vips_object_check_required( VipsObject *object, GParamSpec *pspec, vips_object_check_required( VipsObject *object, GParamSpec *pspec,
VipsArgumentClass *argument_class, VipsArgumentClass *argument_class,
VipsArgumentInstance *argument_instance, VipsArgumentInstance *argument_instance,
void *a, void *b ) void *a, void *b )
{ {
@ -636,7 +636,7 @@ vips_object_check_required( VipsObject *object, GParamSpec *pspec,
if( (argument_class->flags & VIPS_ARGUMENT_REQUIRED) && if( (argument_class->flags & VIPS_ARGUMENT_REQUIRED) &&
(argument_class->flags & VIPS_ARGUMENT_CONSTRUCT) && (argument_class->flags & VIPS_ARGUMENT_CONSTRUCT) &&
!argument_instance->assigned ) { !argument_instance->assigned ) {
im_error( "check_required", im_error( "check_required",
_( "required construct param %s to %s not set" ), _( "required construct param %s to %s not set" ),
g_param_spec_get_name( pspec ), g_param_spec_get_name( pspec ),
G_OBJECT_TYPE_NAME( object ) ); G_OBJECT_TYPE_NAME( object ) );
@ -670,7 +670,7 @@ vips_object_real_build( VipsObject *object )
* strdup(). Set these here rather than in object_init, so that the * strdup(). Set these here rather than in object_init, so that the
* class gets a chance to set them. * class gets a chance to set them.
*/ */
g_object_set( object, g_object_set( object,
"nickname", object_class->nickname, "nickname", object_class->nickname,
"description", object_class->description, NULL ); "description", object_class->description, NULL );
@ -696,7 +696,7 @@ vips_object_real_print( VipsObject *object, VipsBuf *buf )
static void static void
transform_string_double( const GValue *src_value, GValue *dest_value ) transform_string_double( const GValue *src_value, GValue *dest_value )
{ {
g_value_set_double( dest_value, g_value_set_double( dest_value,
g_ascii_strtod( g_value_get_string( src_value ), NULL ) ); g_ascii_strtod( g_value_get_string( src_value ), NULL ) );
} }
@ -720,7 +720,7 @@ vips_object_class_init( VipsObjectClass *object_class )
/* Table of VipsArgumentClass ... we can just g_free() them. /* Table of VipsArgumentClass ... we can just g_free() them.
*/ */
object_class->argument_table = g_hash_table_new_full( object_class->argument_table = g_hash_table_new_full(
g_direct_hash, g_direct_equal, NULL, (GDestroyNotify) g_free ); g_direct_hash, g_direct_equal, NULL, (GDestroyNotify) g_free );
object_class->argument_table_traverse = NULL; object_class->argument_table_traverse = NULL;
@ -731,23 +731,23 @@ vips_object_class_init( VipsObjectClass *object_class )
/* Create properties. /* Create properties.
*/ */
pspec = g_param_spec_string( "nickname", pspec = g_param_spec_string( "nickname",
_( "Nickname" ), _( "Nickname" ),
_( "Class nickname" ), _( "Class nickname" ),
"", "",
(GParamFlags) G_PARAM_READWRITE ); (GParamFlags) G_PARAM_READWRITE );
g_object_class_install_property( gobject_class, g_object_class_install_property( gobject_class,
PROP_NICKNAME, pspec ); PROP_NICKNAME, pspec );
vips_object_class_install_argument( object_class, pspec, vips_object_class_install_argument( object_class, pspec,
VIPS_ARGUMENT_SET_ONCE, VIPS_ARGUMENT_SET_ONCE,
G_STRUCT_OFFSET( VipsObject, nickname ) ); G_STRUCT_OFFSET( VipsObject, nickname ) );
pspec = g_param_spec_string( "description", pspec = g_param_spec_string( "description",
_( "Description" ), _( "Description" ),
_( "Class description" ), _( "Class description" ),
"", "",
(GParamFlags) G_PARAM_READWRITE ); (GParamFlags) G_PARAM_READWRITE );
g_object_class_install_property( gobject_class, g_object_class_install_property( gobject_class,
PROP_DESCRIPTION, pspec ); PROP_DESCRIPTION, pspec );
vips_object_class_install_argument( object_class, pspec, vips_object_class_install_argument( object_class, pspec,
VIPS_ARGUMENT_SET_ONCE, VIPS_ARGUMENT_SET_ONCE,
@ -767,7 +767,7 @@ vips_object_init( VipsObject *object )
/* Add a vipsargument ... automate some stuff with this. /* Add a vipsargument ... automate some stuff with this.
*/ */
void void
vips_object_class_install_argument( VipsObjectClass *object_class, vips_object_class_install_argument( VipsObjectClass *object_class,
GParamSpec *pspec, VipsArgumentFlags flags, guint offset ) GParamSpec *pspec, VipsArgumentFlags flags, guint offset )
{ {
VipsArgumentClass *argument_class = g_new( VipsArgumentClass, 1 ); VipsArgumentClass *argument_class = g_new( VipsArgumentClass, 1 );
@ -784,7 +784,7 @@ vips_object_class_install_argument( VipsObjectClass *object_class,
/* Mustn't have INPUT and OUTPUT both set. /* Mustn't have INPUT and OUTPUT both set.
*/ */
g_assert( !( g_assert( !(
(flags & VIPS_ARGUMENT_INPUT) && (flags & VIPS_ARGUMENT_INPUT) &&
(flags & VIPS_ARGUMENT_OUTPUT)) ); (flags & VIPS_ARGUMENT_OUTPUT)) );
((VipsArgument *) argument_class)->pspec = pspec; ((VipsArgument *) argument_class)->pspec = pspec;
@ -794,7 +794,7 @@ vips_object_class_install_argument( VipsObjectClass *object_class,
vips_argument_table_replace( object_class->argument_table, vips_argument_table_replace( object_class->argument_table,
(VipsArgument *) argument_class ); (VipsArgument *) argument_class );
object_class->argument_table_traverse = g_slist_append( object_class->argument_table_traverse = g_slist_append(
object_class->argument_table_traverse, argument_class ); object_class->argument_table_traverse, argument_class );
} }
@ -816,7 +816,7 @@ vips_object_set_arg( VipsObject *object, const char *name, const char *value )
static void * static void *
vips_object_set_required_test( VipsObject *object, vips_object_set_required_test( VipsObject *object,
GParamSpec *pspec, GParamSpec *pspec,
VipsArgumentClass *argument_class, VipsArgumentClass *argument_class,
VipsArgumentInstance *argument_instance, VipsArgumentInstance *argument_instance,
void *a, void *b ) void *a, void *b )
{ {
@ -835,9 +835,9 @@ vips_object_set_required( VipsObject *object, const char *value )
{ {
GParamSpec *pspec; GParamSpec *pspec;
if( !(pspec = vips_argument_map( object, if( !(pspec = vips_argument_map( object,
vips_object_set_required_test, NULL, NULL )) ) { vips_object_set_required_test, NULL, NULL )) ) {
im_error( "vips_object_set_required", im_error( "vips_object_set_required",
_( "no unset required arguments for %s" ), value ); _( "no unset required arguments for %s" ), value );
return( -1 ); return( -1 );
} }
@ -859,23 +859,23 @@ vips_object_set_args( VipsObject *object, const char *p )
char string2[PATH_MAX]; char string2[PATH_MAX];
do { do {
if( !(p = vips__token_need( p, VIPS_TOKEN_STRING, if( !(p = vips__token_need( p, VIPS_TOKEN_STRING,
string, PATH_MAX )) ) string, PATH_MAX )) )
return( -1 ); return( -1 );
/* We have to look for a '=', ')' or a ',' to see if string is /* We have to look for a '=', ')' or a ',' to see if string is
* a param name or a value. * a param name or a value.
*/ */
if( !(p = vips__token_must( p, &token, string2, PATH_MAX )) ) if( !(p = vips__token_must( p, &token, string2, PATH_MAX )) )
return( -1 ); return( -1 );
if( token == VIPS_TOKEN_EQUALS ) { if( token == VIPS_TOKEN_EQUALS ) {
if( !(p = vips__token_need( p, VIPS_TOKEN_STRING, if( !(p = vips__token_need( p, VIPS_TOKEN_STRING,
string2, PATH_MAX )) ) string2, PATH_MAX )) )
return( -1 ); return( -1 );
if( vips_object_set_arg( object, string, string2 ) ) if( vips_object_set_arg( object, string, string2 ) )
return( -1 ); return( -1 );
if( !(p = vips__token_must( p, &token, if( !(p = vips__token_must( p, &token,
string2, PATH_MAX )) ) string2, PATH_MAX )) )
return( -1 ); return( -1 );
} }
else { else {
@ -886,7 +886,7 @@ vips_object_set_args( VipsObject *object, const char *p )
/* Now must be a , or a ). /* Now must be a , or a ).
*/ */
if( token != VIPS_TOKEN_RIGHT && token != VIPS_TOKEN_COMMA ) { if( token != VIPS_TOKEN_RIGHT && token != VIPS_TOKEN_COMMA ) {
im_error( "set_args", "%s", im_error( "set_args", "%s",
_( "not , or ) after parameter" ) ); _( "not , or ) after parameter" ) );
return( -1 ); return( -1 );
} }
@ -947,11 +947,11 @@ vips_object_new_from_string( const char *basename, const char *p )
GType type; GType type;
if( !(p = vips__token_need( p, VIPS_TOKEN_STRING, string, PATH_MAX )) || if( !(p = vips__token_need( p, VIPS_TOKEN_STRING, string, PATH_MAX )) ||
!(type = vips_type_find( basename, string )) ) !(type = vips_type_find( basename, string )) )
return( NULL ); return( NULL );
return( vips_object_new( type, return( vips_object_new( type,
vips_object_new_from_string_set, (void *) p, NULL ) ); vips_object_new_from_string_set, (void *) p, NULL ) );
} }
static void static void
@ -974,7 +974,7 @@ vips_object_print_arg( VipsObject *object, GParamSpec *pspec, VipsBuf *buf )
static void * static void *
vips_object_to_string_required( VipsObject *object, vips_object_to_string_required( VipsObject *object,
GParamSpec *pspec, GParamSpec *pspec,
VipsArgumentClass *argument_class, VipsArgumentClass *argument_class,
VipsArgumentInstance *argument_instance, VipsArgumentInstance *argument_instance,
void *a, void *b ) void *a, void *b )
{ {
@ -990,7 +990,7 @@ vips_object_to_string_required( VipsObject *object,
vips_buf_appends( buf, "," ); vips_buf_appends( buf, "," );
} }
vips_object_print_arg( object, pspec, buf ); vips_object_print_arg( object, pspec, buf );
} }
return( NULL ); return( NULL );
@ -999,7 +999,7 @@ vips_object_to_string_required( VipsObject *object,
static void * static void *
vips_object_to_string_optional( VipsObject *object, vips_object_to_string_optional( VipsObject *object,
GParamSpec *pspec, GParamSpec *pspec,
VipsArgumentClass *argument_class, VipsArgumentClass *argument_class,
VipsArgumentInstance *argument_instance, VipsArgumentInstance *argument_instance,
void *a, void *b ) void *a, void *b )
{ {
@ -1018,14 +1018,14 @@ vips_object_to_string_optional( VipsObject *object,
vips_buf_appends( buf, g_param_spec_get_name( pspec ) ); vips_buf_appends( buf, g_param_spec_get_name( pspec ) );
vips_buf_appends( buf, "=" ); vips_buf_appends( buf, "=" );
vips_object_print_arg( object, pspec, buf ); vips_object_print_arg( object, pspec, buf );
} }
return( NULL ); return( NULL );
} }
/* The inverse of vips_object_new_from_string(): turn an object into eg. /* The inverse of vips_object_new_from_string(): turn an object into eg.
* "VipsInterpolateYafrsmooth(sharpening=12)". * "VipsInterpolateSnohalo1(blur=.333333)".
*/ */
void void
vips_object_to_string( VipsObject *object, VipsBuf *buf ) vips_object_to_string( VipsObject *object, VipsBuf *buf )
@ -1037,10 +1037,10 @@ vips_object_to_string( VipsObject *object, VipsBuf *buf )
*/ */
vips_buf_appends( buf, G_OBJECT_TYPE_NAME( object ) ); vips_buf_appends( buf, G_OBJECT_TYPE_NAME( object ) );
first = TRUE; first = TRUE;
(void) vips_argument_map( object, (void) vips_argument_map( object,
vips_object_to_string_required, buf, &first ); vips_object_to_string_required, buf, &first );
(void) vips_argument_map( object, (void) vips_argument_map( object,
vips_object_to_string_optional, buf, &first ); vips_object_to_string_optional, buf, &first );
if( !first ) if( !first )
vips_buf_appends( buf, ")" ); vips_buf_appends( buf, ")" );
} }

View File

@ -3,7 +3,6 @@ if ENABLE_CXX
C_SOURCES = \ C_SOURCES = \
bicubic.cpp \ bicubic.cpp \
lbb.cpp \ lbb.cpp \
yafrsmooth.cpp \
nohalo1.cpp \ nohalo1.cpp \
snohalo1.cpp \ snohalo1.cpp \
nohalo2.cpp \ nohalo2.cpp \
@ -14,7 +13,6 @@ C_SOURCES =
C_DIST = \ C_DIST = \
bicubic.cpp \ bicubic.cpp \
lbb.cpp \ lbb.cpp \
yafrsmooth.cpp \
nohalo1.cpp \ nohalo1.cpp \
snohalo1.cpp \ snohalo1.cpp \
nohalo2.cpp \ nohalo2.cpp \

View File

@ -4,7 +4,7 @@
/* /*
This file is part of VIPS. This file is part of VIPS.
VIPS is free software; you can redistribute it and/or modify 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 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 the Free Software Foundation; either version 2 of the License, or
@ -27,8 +27,11 @@
*/ */
/* Bicubic (catmull-rom) interpolator derived from Nicolas Robidoux's YAFR /* Bicubic (catmull-rom) interpolator derived from Nicolas Robidoux's
* resampler with permission and thanks. * original YAFR resampler with permission and thanks.
*
* Note: This may actually be an implementation of a Keys bicubic
* convolution method. To be checked.
*/ */
/* /*
@ -76,7 +79,7 @@ typedef struct _VipsInterpolateBicubic {
typedef struct _VipsInterpolateBicubicClass { typedef struct _VipsInterpolateBicubicClass {
VipsInterpolateClass parent_class; VipsInterpolateClass parent_class;
/* Precalculated interpolation matricies. int (used for pel sizes up /* Precalculated interpolation matricies. int (used for pel sizes up
* to short), and double (for all others). We go to scale + 1, so * to short), and double (for all others). We go to scale + 1, so
* we can round-to-nearest safely. * we can round-to-nearest safely.
*/ */
@ -92,7 +95,7 @@ typedef struct _VipsInterpolateBicubicClass {
/* We need C linkage for this. /* We need C linkage for this.
*/ */
extern "C" { extern "C" {
G_DEFINE_TYPE( VipsInterpolateBicubic, vips_interpolate_bicubic, G_DEFINE_TYPE( VipsInterpolateBicubic, vips_interpolate_bicubic,
VIPS_TYPE_INTERPOLATE ); VIPS_TYPE_INTERPOLATE );
} }
@ -105,14 +108,14 @@ G_DEFINE_TYPE( VipsInterpolateBicubic, vips_interpolate_bicubic,
/* Fixed-point version, for 8 and 16-bit types. /* Fixed-point version, for 8 and 16-bit types.
*/ */
template <typename T, int min_value, int max_value> template <typename T, int min_value, int max_value>
static void inline static void inline
bicubic_int_tab( PEL *pout, const PEL *pin, bicubic_int_tab( PEL *pout, const PEL *pin,
const int bands, const int lskip, const int bands, const int lskip,
const int *cx, const int *cy ) const int *cx, const int *cy )
{ {
T* restrict out = (T *) pout; T* restrict out = (T *) pout;
const T* restrict in = (T *) pin; const T* restrict in = (T *) pin;
const int b1 = bands; const int b1 = bands;
const int b2 = b1 + b1; const int b2 = b1 + b1;
@ -173,14 +176,14 @@ bicubic_int_tab( PEL *pout, const PEL *pin,
/* Floating-point version, for int/float types. /* Floating-point version, for int/float types.
*/ */
template <typename T> template <typename T>
static void inline static void inline
bicubic_float_tab( PEL *pout, const PEL *pin, bicubic_float_tab( PEL *pout, const PEL *pin,
const int bands, const int lskip, const int bands, const int lskip,
const double *cx, const double *cy ) const double *cx, const double *cy )
{ {
T* restrict out = (T *) pout; T* restrict out = (T *) pout;
const T* restrict in = (T *) pin; const T* restrict in = (T *) pin;
const int b1 = bands; const int b1 = bands;
const int b2 = b1 + b1; const int b2 = b1 + b1;
@ -236,14 +239,14 @@ bicubic_float_tab( PEL *pout, const PEL *pin,
/* Ultra-high-quality version for double images. /* Ultra-high-quality version for double images.
*/ */
template <typename T> template <typename T>
static void inline static void inline
bicubic_notab( PEL *pout, const PEL *pin, bicubic_notab( PEL *pout, const PEL *pin,
const int bands, const int lskip, const int bands, const int lskip,
double x, double y ) double x, double y )
{ {
T* restrict out = (T *) pout; T* restrict out = (T *) pout;
const T* restrict in = (T *) pin; const T* restrict in = (T *) pin;
const int b1 = bands; const int b1 = bands;
const int b2 = b1 + b1; const int b2 = b1 + b1;
@ -304,20 +307,20 @@ bicubic_notab( PEL *pout, const PEL *pin,
} }
static void static void
vips_interpolate_bicubic_interpolate( VipsInterpolate *interpolate, vips_interpolate_bicubic_interpolate( VipsInterpolate *interpolate,
PEL *out, REGION *in, double x, double y ) PEL *out, REGION *in, double x, double y )
{ {
VipsInterpolateBicubicClass *bicubic_class = VipsInterpolateBicubicClass *bicubic_class =
VIPS_INTERPOLATE_BICUBIC_GET_CLASS( interpolate ); VIPS_INTERPOLATE_BICUBIC_GET_CLASS( interpolate );
/* Scaled int. /* Scaled int.
*/ */
const double sx = x * VIPS_TRANSFORM_SCALE; const double sx = x * VIPS_TRANSFORM_SCALE;
const double sy = y * VIPS_TRANSFORM_SCALE; const double sy = y * VIPS_TRANSFORM_SCALE;
const int sxi = FAST_PSEUDO_FLOOR( sx ); const int sxi = FAST_PSEUDO_FLOOR( sx );
const int syi = FAST_PSEUDO_FLOOR( sy ); const int syi = FAST_PSEUDO_FLOOR( sy );
/* Get index into interpolation table and unscaled integer /* Get index into interpolation table and unscaled integer
* position. * position.
*/ */
const int tx = sxi & (VIPS_TRANSFORM_SCALE - 1); const int tx = sxi & (VIPS_TRANSFORM_SCALE - 1);
@ -334,83 +337,83 @@ vips_interpolate_bicubic_interpolate( VipsInterpolate *interpolate,
/* Back and up one to get the top-left of the 4x4. /* Back and up one to get the top-left of the 4x4.
*/ */
const PEL *p = (PEL *) IM_REGION_ADDR( in, ix - 1, iy - 1 ); const PEL *p = (PEL *) IM_REGION_ADDR( in, ix - 1, iy - 1 );
/* Pel size and line size. /* Pel size and line size.
*/ */
const int bands = in->im->Bands; const int bands = in->im->Bands;
const int lskip = IM_REGION_LSKIP( in ); const int lskip = IM_REGION_LSKIP( in );
#ifdef DEBUG #ifdef DEBUG
printf( "vips_interpolate_bicubic_interpolate: %g %g\n", x, y ); printf( "vips_interpolate_bicubic_interpolate: %g %g\n", x, y );
printf( "\tleft=%d, top=%d, width=%d, height=%d\n", printf( "\tleft=%d, top=%d, width=%d, height=%d\n",
ix - 1, iy - 1, 4, 4 ); ix - 1, iy - 1, 4, 4 );
#endif /*DEBUG*/ #endif /*DEBUG*/
switch( in->im->BandFmt ) { switch( in->im->BandFmt ) {
case IM_BANDFMT_UCHAR: case IM_BANDFMT_UCHAR:
bicubic_int_tab<unsigned char, 0, UCHAR_MAX>( bicubic_int_tab<unsigned char, 0, UCHAR_MAX>(
out, p, bands, lskip, out, p, bands, lskip,
cxi, cyi ); cxi, cyi );
/* /*
Handy for benchmarking Handy for benchmarking
bicubic_float_tab<unsigned char>( bicubic_float_tab<unsigned char>(
out, p, bands, lskip, out, p, bands, lskip,
cxf, cyf ); cxf, cyf );
bicubic_notab<unsigned char>( bicubic_notab<unsigned char>(
out, p, bands, lskip, out, p, bands, lskip,
x - ix, y - iy ); x - ix, y - iy );
*/ */
break; break;
case IM_BANDFMT_CHAR: case IM_BANDFMT_CHAR:
bicubic_int_tab<signed char, SCHAR_MIN, SCHAR_MAX>( bicubic_int_tab<signed char, SCHAR_MIN, SCHAR_MAX>(
out, p, bands, lskip, out, p, bands, lskip,
cxi, cyi ); cxi, cyi );
break; break;
case IM_BANDFMT_USHORT: case IM_BANDFMT_USHORT:
bicubic_int_tab<unsigned short, 0, USHRT_MAX>( bicubic_int_tab<unsigned short, 0, USHRT_MAX>(
out, p, bands, lskip, out, p, bands, lskip,
cxi, cyi ); cxi, cyi );
break; break;
case IM_BANDFMT_SHORT: case IM_BANDFMT_SHORT:
bicubic_int_tab<signed short, SHRT_MIN, SHRT_MAX>( bicubic_int_tab<signed short, SHRT_MIN, SHRT_MAX>(
out, p, bands, lskip, out, p, bands, lskip,
cxi, cyi ); cxi, cyi );
break; break;
case IM_BANDFMT_UINT: case IM_BANDFMT_UINT:
bicubic_float_tab<unsigned int>( out, p, bands, lskip, bicubic_float_tab<unsigned int>( out, p, bands, lskip,
cxf, cyf ); cxf, cyf );
break; break;
case IM_BANDFMT_INT: case IM_BANDFMT_INT:
bicubic_float_tab<signed int>( out, p, bands, lskip, bicubic_float_tab<signed int>( out, p, bands, lskip,
cxf, cyf ); cxf, cyf );
break; break;
case IM_BANDFMT_FLOAT: case IM_BANDFMT_FLOAT:
bicubic_float_tab<float>( out, p, bands, lskip, bicubic_float_tab<float>( out, p, bands, lskip,
cxf, cyf ); cxf, cyf );
break; break;
case IM_BANDFMT_DOUBLE: case IM_BANDFMT_DOUBLE:
bicubic_notab<double>( out, p, bands, lskip, bicubic_notab<double>( out, p, bands, lskip,
x - ix, y - iy ); x - ix, y - iy );
break; break;
case IM_BANDFMT_COMPLEX: case IM_BANDFMT_COMPLEX:
bicubic_float_tab<float>( out, p, bands * 2, lskip, bicubic_float_tab<float>( out, p, bands * 2, lskip,
cxf, cyf ); cxf, cyf );
break; break;
case IM_BANDFMT_DPCOMPLEX: case IM_BANDFMT_DPCOMPLEX:
bicubic_notab<double>( out, p, bands * 2, lskip, bicubic_notab<double>( out, p, bands * 2, lskip,
x - ix, y - iy ); x - ix, y - iy );
break; break;
@ -423,7 +426,7 @@ static void
vips_interpolate_bicubic_class_init( VipsInterpolateBicubicClass *iclass ) vips_interpolate_bicubic_class_init( VipsInterpolateBicubicClass *iclass )
{ {
VipsObjectClass *object_class = VIPS_OBJECT_CLASS( iclass ); VipsObjectClass *object_class = VIPS_OBJECT_CLASS( iclass );
VipsInterpolateClass *interpolate_class = VipsInterpolateClass *interpolate_class =
VIPS_INTERPOLATE_CLASS( iclass ); VIPS_INTERPOLATE_CLASS( iclass );
object_class->nickname = "bicubic"; object_class->nickname = "bicubic";
@ -435,12 +438,12 @@ vips_interpolate_bicubic_class_init( VipsInterpolateBicubicClass *iclass )
/* Build the tables of pre-computed coefficients. /* Build the tables of pre-computed coefficients.
*/ */
for( int x = 0; x < VIPS_TRANSFORM_SCALE + 1; x++ ) { for( int x = 0; x < VIPS_TRANSFORM_SCALE + 1; x++ ) {
calculate_coefficients_catmull( calculate_coefficients_catmull(
(float) x / VIPS_TRANSFORM_SCALE, (float) x / VIPS_TRANSFORM_SCALE,
iclass->matrixf[x] ); iclass->matrixf[x] );
for( int i = 0; i < 4; i++ ) for( int i = 0; i < 4; i++ )
iclass->matrixi[x][i] = iclass->matrixi[x][i] =
iclass->matrixf[x][i] * VIPS_INTERPOLATE_SCALE; iclass->matrixf[x][i] * VIPS_INTERPOLATE_SCALE;
} }
} }

View File

@ -6,7 +6,7 @@
/* /*
This file is part of VIPS. This file is part of VIPS.
VIPS is free software; you can redistribute it and/or modify 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 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 the Free Software Foundation; either version 2 of the License, or
@ -48,7 +48,7 @@
#include <dmalloc.h> #include <dmalloc.h>
#endif /*WITH_DMALLOC*/ #endif /*WITH_DMALLOC*/
/** /**
* SECTION: interpolate * SECTION: interpolate
* @short_description: various interpolators: nearest, bilinear, bicubic, and * @short_description: various interpolators: nearest, bilinear, bicubic, and
* some non-linear * some non-linear
@ -141,7 +141,7 @@ vips_interpolate_init( VipsInterpolate *interpolate )
* in_x, in_y in REGION in. Don't do this as a signal for speed. * in_x, in_y in REGION in. Don't do this as a signal for speed.
*/ */
void void
vips_interpolate( VipsInterpolate *interpolate, vips_interpolate( VipsInterpolate *interpolate,
PEL *out, REGION *in, double x, double y ) PEL *out, REGION *in, double x, double y )
{ {
VipsInterpolateClass *class = VIPS_INTERPOLATE_GET_CLASS( interpolate ); VipsInterpolateClass *class = VIPS_INTERPOLATE_GET_CLASS( interpolate );
@ -154,7 +154,7 @@ vips_interpolate( VipsInterpolate *interpolate,
/* As above, but return the function pointer. Use this to cache method /* As above, but return the function pointer. Use this to cache method
* dispatch. * dispatch.
*/ */
VipsInterpolateMethod VipsInterpolateMethod
vips_interpolate_get_method( VipsInterpolate *interpolate ) vips_interpolate_get_method( VipsInterpolate *interpolate )
{ {
VipsInterpolateClass *class = VIPS_INTERPOLATE_GET_CLASS( interpolate ); VipsInterpolateClass *class = VIPS_INTERPOLATE_GET_CLASS( interpolate );
@ -211,11 +211,11 @@ vips_interpolate_get_window_offset( VipsInterpolate *interpolate )
typedef VipsInterpolate VipsInterpolateNearest; typedef VipsInterpolate VipsInterpolateNearest;
typedef VipsInterpolateClass VipsInterpolateNearestClass; typedef VipsInterpolateClass VipsInterpolateNearestClass;
G_DEFINE_TYPE( VipsInterpolateNearest, vips_interpolate_nearest, G_DEFINE_TYPE( VipsInterpolateNearest, vips_interpolate_nearest,
VIPS_TYPE_INTERPOLATE ); VIPS_TYPE_INTERPOLATE );
static void static void
vips_interpolate_nearest_interpolate( VipsInterpolate *interpolate, vips_interpolate_nearest_interpolate( VipsInterpolate *interpolate,
PEL *out, REGION *in, double x, double y ) PEL *out, REGION *in, double x, double y )
{ {
/* Pel size and line size. /* Pel size and line size.
@ -228,7 +228,7 @@ vips_interpolate_nearest_interpolate( VipsInterpolate *interpolate,
const int xi = FAST_PSEUDO_FLOOR( x ); const int xi = FAST_PSEUDO_FLOOR( x );
const int yi = FAST_PSEUDO_FLOOR( y ); const int yi = FAST_PSEUDO_FLOOR( y );
const PEL *p = (PEL *) IM_REGION_ADDR( in, xi, yi ); const PEL *p = (PEL *) IM_REGION_ADDR( in, xi, yi );
for( z = 0; z < ps; z++ ) for( z = 0; z < ps; z++ )
out[z] = p[z]; out[z] = p[z];
@ -238,7 +238,7 @@ static void
vips_interpolate_nearest_class_init( VipsInterpolateNearestClass *class ) vips_interpolate_nearest_class_init( VipsInterpolateNearestClass *class )
{ {
VipsObjectClass *object_class = VIPS_OBJECT_CLASS( class ); VipsObjectClass *object_class = VIPS_OBJECT_CLASS( class );
VipsInterpolateClass *interpolate_class = VipsInterpolateClass *interpolate_class =
VIPS_INTERPOLATE_CLASS( class ); VIPS_INTERPOLATE_CLASS( class );
object_class->nickname = "nearest"; object_class->nickname = "nearest";
@ -261,7 +261,7 @@ VipsInterpolate *
vips_interpolate_nearest_new( void ) vips_interpolate_nearest_new( void )
{ {
return( VIPS_INTERPOLATE( vips_object_new( return( VIPS_INTERPOLATE( vips_object_new(
VIPS_TYPE_INTERPOLATE_NEAREST, NULL, NULL, NULL ) ) ); VIPS_TYPE_INTERPOLATE_NEAREST, NULL, NULL, NULL ) ) );
} }
@ -301,7 +301,7 @@ typedef VipsInterpolate VipsInterpolateBilinear;
typedef struct _VipsInterpolateBilinearClass { typedef struct _VipsInterpolateBilinearClass {
VipsInterpolateClass parent_class; VipsInterpolateClass parent_class;
/* Precalculated interpolation matricies. int (used for pel sizes up /* Precalculated interpolation matricies. int (used for pel sizes up
* to short), and float (for all others). We go to scale + 1, so * to short), and float (for all others). We go to scale + 1, so
* we can round-to-nearest safely. Don't bother with double, since * we can round-to-nearest safely. Don't bother with double, since
* this is an approximation anyway. * this is an approximation anyway.
@ -310,13 +310,13 @@ typedef struct _VipsInterpolateBilinearClass {
float matrixd[VIPS_TRANSFORM_SCALE + 1][VIPS_TRANSFORM_SCALE + 1][4]; float matrixd[VIPS_TRANSFORM_SCALE + 1][VIPS_TRANSFORM_SCALE + 1][4];
} VipsInterpolateBilinearClass; } VipsInterpolateBilinearClass;
G_DEFINE_TYPE( VipsInterpolateBilinear, vips_interpolate_bilinear, G_DEFINE_TYPE( VipsInterpolateBilinear, vips_interpolate_bilinear,
VIPS_TYPE_INTERPOLATE ); VIPS_TYPE_INTERPOLATE );
/* in this class, name vars in the 2x2 grid as eg. /* in this class, name vars in the 2x2 grid as eg.
* p1 p2 * p1 p2
* p3 p4 * p3 p4
*/ */
/* Interpolate a section ... int8/16 types. /* Interpolate a section ... int8/16 types.
*/ */
@ -377,26 +377,26 @@ G_DEFINE_TYPE( VipsInterpolateBilinear, vips_interpolate_bilinear,
} }
static void static void
vips_interpolate_bilinear_interpolate( VipsInterpolate *interpolate, vips_interpolate_bilinear_interpolate( VipsInterpolate *interpolate,
PEL *out, REGION *in, double x, double y ) PEL *out, REGION *in, double x, double y )
{ {
VipsInterpolateBilinearClass *class = VipsInterpolateBilinearClass *class =
VIPS_INTERPOLATE_BILINEAR_GET_CLASS( interpolate ); VIPS_INTERPOLATE_BILINEAR_GET_CLASS( interpolate );
/* Pel size and line size. /* Pel size and line size.
*/ */
const int ps = IM_IMAGE_SIZEOF_PEL( in->im ); const int ps = IM_IMAGE_SIZEOF_PEL( in->im );
const int ls = IM_REGION_LSKIP( in ); const int ls = IM_REGION_LSKIP( in );
const int b = in->im->Bands; const int b = in->im->Bands;
/* Now go to scaled int. /* Now go to scaled int.
*/ */
const double sx = x * VIPS_TRANSFORM_SCALE; const double sx = x * VIPS_TRANSFORM_SCALE;
const double sy = y * VIPS_TRANSFORM_SCALE; const double sy = y * VIPS_TRANSFORM_SCALE;
const int sxi = FAST_PSEUDO_FLOOR( sx ); const int sxi = FAST_PSEUDO_FLOOR( sx );
const int syi = FAST_PSEUDO_FLOOR( sy ); const int syi = FAST_PSEUDO_FLOOR( sy );
/* Get index into interpolation table and unscaled integer /* Get index into interpolation table and unscaled integer
* position. * position.
*/ */
const int xi = sxi & (VIPS_TRANSFORM_SCALE - 1); const int xi = sxi & (VIPS_TRANSFORM_SCALE - 1);
@ -404,14 +404,14 @@ vips_interpolate_bilinear_interpolate( VipsInterpolate *interpolate,
const int x_int = sxi >> VIPS_TRANSFORM_SHIFT; const int x_int = sxi >> VIPS_TRANSFORM_SHIFT;
const int y_int = syi >> VIPS_TRANSFORM_SHIFT; const int y_int = syi >> VIPS_TRANSFORM_SHIFT;
const PEL *p1 = (PEL *) IM_REGION_ADDR( in, x_int, y_int ); const PEL *p1 = (PEL *) IM_REGION_ADDR( in, x_int, y_int );
const PEL *p2 = p1 + ps; const PEL *p2 = p1 + ps;
const PEL *p3 = p1 + ls; const PEL *p3 = p1 + ls;
const PEL *p4 = p3 + ps; const PEL *p4 = p3 + ps;
int z; int z;
SWITCH_INTERPOLATE( in->im->BandFmt, SWITCH_INTERPOLATE( in->im->BandFmt,
BILINEAR_INT, BILINEAR_FLOAT ); BILINEAR_INT, BILINEAR_FLOAT );
} }
@ -419,7 +419,7 @@ static void
vips_interpolate_bilinear_class_init( VipsInterpolateBilinearClass *class ) vips_interpolate_bilinear_class_init( VipsInterpolateBilinearClass *class )
{ {
VipsObjectClass *object_class = VIPS_OBJECT_CLASS( class ); VipsObjectClass *object_class = VIPS_OBJECT_CLASS( class );
VipsInterpolateClass *interpolate_class = VipsInterpolateClass *interpolate_class =
(VipsInterpolateClass *) class; (VipsInterpolateClass *) class;
int x, y; int x, y;
@ -440,7 +440,7 @@ vips_interpolate_bilinear_class_init( VipsInterpolateBilinearClass *class )
*/ */
X = (double) x / VIPS_TRANSFORM_SCALE; X = (double) x / VIPS_TRANSFORM_SCALE;
Y = (double) y / VIPS_TRANSFORM_SCALE; Y = (double) y / VIPS_TRANSFORM_SCALE;
Xd = 1.0 - X; Xd = 1.0 - X;
Yd = 1.0 - Y; Yd = 1.0 - Y;
/* Weights. /* Weights.
@ -475,7 +475,7 @@ vips_interpolate_bilinear_init( VipsInterpolateBilinear *bilinear )
VipsInterpolate * VipsInterpolate *
vips_interpolate_bilinear_new( void ) vips_interpolate_bilinear_new( void )
{ {
return( VIPS_INTERPOLATE( vips_object_new( return( VIPS_INTERPOLATE( vips_object_new(
VIPS_TYPE_INTERPOLATE_BILINEAR, NULL, NULL, NULL ) ) ); VIPS_TYPE_INTERPOLATE_BILINEAR, NULL, NULL, NULL ) ) );
} }
@ -499,7 +499,6 @@ vips__interpolate_init( void )
{ {
extern GType vips_interpolate_bicubic_get_type( void ); extern GType vips_interpolate_bicubic_get_type( void );
extern GType vips_interpolate_lbb_get_type( void ); extern GType vips_interpolate_lbb_get_type( void );
extern GType vips_interpolate_yafrsmooth_get_type( void );
extern GType vips_interpolate_nohalo1_get_type( void ); extern GType vips_interpolate_nohalo1_get_type( void );
extern GType vips_interpolate_snohalo1_get_type( void ); extern GType vips_interpolate_snohalo1_get_type( void );
extern GType vips_interpolate_nohalo2_get_type( void ); extern GType vips_interpolate_nohalo2_get_type( void );
@ -510,7 +509,6 @@ vips__interpolate_init( void )
#ifdef ENABLE_CXX #ifdef ENABLE_CXX
vips_interpolate_bicubic_get_type(); vips_interpolate_bicubic_get_type();
vips_interpolate_lbb_get_type(); vips_interpolate_lbb_get_type();
vips_interpolate_yafrsmooth_get_type();
vips_interpolate_nohalo1_get_type(); vips_interpolate_nohalo1_get_type();
vips_interpolate_snohalo1_get_type(); vips_interpolate_snohalo1_get_type();
vips_interpolate_nohalo2_get_type(); vips_interpolate_nohalo2_get_type();

View File

@ -1,803 +0,0 @@
/* yafrsmooth interpolator
*/
/*
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
*/
/*
* 2008 (c) Nicolas Robidoux (developer of Yet Another Fast
* Resampler).
*
* Acknowledgement: N. Robidoux's research on YAFRSMOOTH funded in part by
* an NSERC (National Science and Engineering Research Council of
* Canada) Discovery Grant.
*/
/* Hacked for vips by J. Cupitt, 12/11/08.
*
* Bicubic component replaced with the one from bicubbic.cpp.
*/
/*
* YAFRSMOOTH = Yet Another Fast Resampler
*
* Yet Another Fast Resampler is a nonlinear resampler which consists
* of a linear scheme (in this version, Catmull-Rom) plus a nonlinear
* sharpening correction the purpose of which is the straightening of
* diagonal interfaces between flat colour areas.
*
* Key properties:
*
* YAFRSMOOTH (smooth) is interpolatory:
*
* If asked for the value at the center of an input pixel, it will
* return the corresponding value, unchanged.
*
* YAFRSMOOTH (smooth) preserves local averages:
*
* The average of the reconstructed intensity surface over any region
* is the same as the average of the piecewise constant surface with
* values over pixel areas equal to the input pixel values (the
* "nearest neighbour" surface), except for a small amount of blur at
* the boundary of the region. More precicely: YAFRSMOOTH (smooth) is a box
* filtered exact area method.
*
* Main weaknesses of YAFRSMOOTH (smooth):
*
* Weakness 1: YAFRSMOOTH (smooth) improves on Catmull-Rom only for images
* with at least a little bit of smoothness.
*
* Weakness 2: Catmull-Rom introduces a lot of haloing. YAFRSMOOTH (smooth)
* is based on Catmull-Rom, and consequently it too introduces a lot
* of haloing.
*
* More details regarding Weakness 1:
*
* If a portion of the image is such that every pixel has immediate
* neighbours in the horizontal and vertical directions which have
* exactly the same pixel value, then YAFRSMOOTH (smooth) boils down to
* Catmull-Rom, and the computation of the correction is a waste.
* Extreme case: If all the pixels are either pure black or pure white
* in some region, as in some text images (more generally, if the
* region is "bichromatic"), then the YAFRSMOOTH (smooth) correction is 0 in
* the interior of the bichromatic region.
*/
/*
#define DEBUG
*/
#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 <vips/internal.h>
#include "templates.h"
#ifdef WITH_DMALLOC
#include <dmalloc.h>
#endif /*WITH_DMALLOC*/
/* "fast" floor() ... on my laptop, anyway.
*/
#define FLOOR( V ) ((V) >= 0 ? (int)(V) : (int)((V) - 1))
#ifndef restrict
#ifdef __restrict
#define restrict __restrict
#else
#ifdef __restrict__
#define restrict __restrict__
#else
#define restrict
#endif
#endif
#endif
/* Scale sharpening by this to normalise.
*/
#define SMOOTH_SHARPENING_SCALE (0.453125f)
/* Properties.
*/
enum {
PROP_SHARPENING = 1,
PROP_LAST
};
#define VIPS_TYPE_INTERPOLATE_YAFRSMOOTH \
(vips_interpolate_yafrsmooth_get_type())
#define VIPS_INTERPOLATE_YAFRSMOOTH( obj ) \
(G_TYPE_CHECK_INSTANCE_CAST( (obj), \
VIPS_TYPE_INTERPOLATE_YAFRSMOOTH, VipsInterpolateYafrsmooth ))
#define VIPS_INTERPOLATE_YAFRSMOOTH_CLASS( klass ) \
(G_TYPE_CHECK_CLASS_CAST( (klass), \
VIPS_TYPE_INTERPOLATE_YAFRSMOOTH, VipsInterpolateYafrsmoothClass))
#define VIPS_IS_INTERPOLATE_YAFRSMOOTH( obj ) \
(G_TYPE_CHECK_INSTANCE_TYPE( (obj), VIPS_TYPE_INTERPOLATE_YAFRSMOOTH ))
#define VIPS_IS_INTERPOLATE_YAFRSMOOTH_CLASS( klass ) \
(G_TYPE_CHECK_CLASS_TYPE( (klass), VIPS_TYPE_INTERPOLATE_YAFRSMOOTH ))
#define VIPS_INTERPOLATE_YAFRSMOOTH_GET_CLASS( obj ) \
(G_TYPE_INSTANCE_GET_CLASS( (obj), \
VIPS_TYPE_INTERPOLATE_YAFRSMOOTH, VipsInterpolateYafrsmoothClass ))
typedef struct _VipsInterpolateYafrsmooth {
VipsInterpolate parent_object;
/* "sharpening" is a continuous method parameter which is
* proportional to the amount of "diagonal straightening" which the
* nonlinear correction part of the method may add to the underlying
* linear scheme. You may also think of it as a sharpening
* parameter: higher values correspond to more sharpening, and
* negative values lead to strange looking effects.
*
* The default value is sharpening = 29/32 when the scheme being
* "straightened" is Catmull-Rom---as is the case here. This value
* fixes key pixel values near the diagonal boundary between two
* monochrome regions (the diagonal boundary pixel values being set
* to the halfway colour).
*
* If resampling seems to add unwanted texture artifacts, push
* sharpening toward 0. It is not generally not recommended to set
* sharpening to a value larger than 4.
*
* Sharpening is halved because the .5 which has to do with the
* relative coordinates of the evaluation points (which has to do
* with .5*rite_width etc) is folded into the constant to save
* flops. Consequently, the largest recommended value of
* sharpening_over_two is 2=4/2.
*
* In order to simplify interfacing with users, the parameter which
* should be set by the user is normalized so that user_sharpening =
* 1 when sharpening is equal to the recommended value. Consistently
* with the above discussion, values of user_sharpening between 0
* and about 3.625 give good results.
*/
double sharpening;
} VipsInterpolateYafrsmooth;
typedef struct _VipsInterpolateYafrsmoothClass {
VipsInterpolateClass parent_class;
/* Precalculated interpolation matricies. int (used for pel sizes up
* to short), and double (for all others). We go to scale + 1, so
* we can round-to-nearest safely.
*/
/* We could keep a large set of 2d 4x4 matricies, but this actually
* works out slower, since for many resizes the thing will no longer
* fit in L1.
*/
int matrixi[VIPS_TRANSFORM_SCALE + 1][4];
double matrixf[VIPS_TRANSFORM_SCALE + 1][4];
} VipsInterpolateYafrsmoothClass;
/* We need C linkage for this.
*/
extern "C" {
G_DEFINE_TYPE( VipsInterpolateYafrsmooth, vips_interpolate_yafrsmooth,
VIPS_TYPE_INTERPOLATE );
}
/* T is the type of pixels we are computing, D is a type large enough to hold
* (Ta - Tb) ** 2.
*/
/* The 16 values for this interpolation, four constants for this
* interpolation position.
*/
template <typename T, typename D> static float inline
yafrsmooth(
const T uno_one, const T uno_two, const T uno_thr, const T uno_fou,
const T dos_one, const T dos_two, const T dos_thr, const T dos_fou,
const T tre_one, const T tre_two, const T tre_thr, const T tre_fou,
const T qua_one, const T qua_two, const T qua_thr, const T qua_fou,
const double *c )
{
/*
* Computation of the YAFRSMOOTH correction:
*
* Basically, if two consecutive pixel value differences have the
* same sign, the smallest one (in absolute value) is taken to be
* the corresponding slope. If they don't have the same sign, the
* corresponding slope is set to 0.
*
* Four such pairs (vertical and horizontal) of slopes need to be
* computed, one pair for each of the pixels which potentially
* overlap the unit area centered at the interpolation point.
*/
/*
* Beginning of the computation of the "up" horizontal slopes:
*/
const D prem__up = dos_two - dos_one;
const D deux__up = dos_thr - dos_two;
const D troi__up = dos_fou - dos_thr;
/*
* "down" horizontal slopes:
*/
const D prem_dow = tre_two - tre_one;
const D deux_dow = tre_thr - tre_two;
const D troi_dow = tre_fou - tre_thr;
/*
* "left" vertical slopes:
*/
const D prem_left = dos_two - uno_two;
const D deux_left = tre_two - dos_two;
const D troi_left = qua_two - tre_two;
/*
* "right" vertical slopes:
*/
const D prem_rite = dos_thr - uno_thr;
const D deux_rite = tre_thr - dos_thr;
const D troi_rite = qua_thr - tre_thr;
/*
* Back to "up":
*/
const D prem__up_squared = prem__up * prem__up;
const D deux__up_squared = deux__up * deux__up;
const D troi__up_squared = troi__up * troi__up;
/*
* Back to "down":
*/
const D prem_dow_squared = prem_dow * prem_dow;
const D deux_dow_squared = deux_dow * deux_dow;
const D troi_dow_squared = troi_dow * troi_dow;
/*
* Back to "left":
*/
const D prem_left_squared = prem_left * prem_left;
const D deux_left_squared = deux_left * deux_left;
const D troi_left_squared = troi_left * troi_left;
/*
* Back to "right":
*/
const D prem_rite_squared = prem_rite * prem_rite;
const D deux_rite_squared = deux_rite * deux_rite;
const D troi_rite_squared = troi_rite * troi_rite;
/*
* "up":
*/
const D prem__up_times_deux__up = prem__up * deux__up;
const D deux__up_times_troi__up = deux__up * troi__up;
/*
* "down":
*/
const D prem_dow_times_deux_dow = prem_dow * deux_dow;
const D deux_dow_times_troi_dow = deux_dow * troi_dow;
/*
* "left":
*/
const D prem_left_times_deux_left = prem_left * deux_left;
const D deux_left_times_troi_left = deux_left * troi_left;
/*
* "right":
*/
const D prem_rite_times_deux_rite = prem_rite * deux_rite;
const D deux_rite_times_troi_rite = deux_rite * troi_rite;
/*
* Branching parts of the computation of the YAFRSMOOTH correction
* (could be unbranched using arithmetic branching and C99 math
* intrinsics, although the compiler may be smart enough to remove
* the branching on its own):
*/
/*
* "up":
*/
const D prem__up_vs_deux__up =
prem__up_squared < deux__up_squared ? prem__up : deux__up;
const D deux__up_vs_troi__up =
deux__up_squared < troi__up_squared ? deux__up : troi__up;
/*
* "down":
*/
const D prem_dow_vs_deux_dow =
prem_dow_squared < deux_dow_squared ? prem_dow : deux_dow;
const D deux_dow_vs_troi_dow =
deux_dow_squared < troi_dow_squared ? deux_dow : troi_dow;
/*
* "left":
*/
const D prem_left_vs_deux_left =
prem_left_squared < deux_left_squared ? prem_left : deux_left;
const D deux_left_vs_troi_left =
deux_left_squared < troi_left_squared ? deux_left : troi_left;
/*
* "right":
*/
const D prem_rite_vs_deux_rite =
prem_rite_squared < deux_rite_squared ? prem_rite : deux_rite;
const D deux_rite_vs_troi_rite =
deux_rite_squared < troi_rite_squared ? deux_rite : troi_rite;
/*
* Computation of the YAFRSMOOTH slopes.
*/
/*
* "up":
*/
const D mx_left__up =
prem__up_times_deux__up < 0.f ? 0.f : prem__up_vs_deux__up;
const D mx_rite__up =
deux__up_times_troi__up < 0.f ? 0.f : deux__up_vs_troi__up;
/*
* "down":
*/
const D mx_left_dow =
prem_dow_times_deux_dow < 0.f ? 0.f : prem_dow_vs_deux_dow;
const D mx_rite_dow =
deux_dow_times_troi_dow < 0.f ? 0.f : deux_dow_vs_troi_dow;
/*
* "left":
*/
const D my_left__up =
prem_left_times_deux_left < 0.f ? 0.f : prem_left_vs_deux_left;
const D my_left_dow =
deux_left_times_troi_left < 0.f ? 0.f : deux_left_vs_troi_left;
/*
* "right":
*/
const D my_rite__up =
prem_rite_times_deux_rite < 0.f ? 0.f : prem_rite_vs_deux_rite;
const D my_rite_dow =
deux_rite_times_troi_rite < 0.f ? 0.f : deux_rite_vs_troi_rite;
/*
* Assemble the unweighted YAFRSMOOTH correction:
*/
const float yafr =
c[0] * (mx_left__up - mx_rite__up) +
c[1] * (mx_left_dow - mx_rite_dow) +
c[2] * (my_left__up - my_left_dow) +
c[3] * (my_rite__up - my_rite_dow);
return( yafr );
}
/* Pointers to write to / read from, number of bands,
* how many bytes to add to move down a line.
*/
/* T is the type of pixels we are reading and writing, D is a type large
* enough to hold (T1 - T2) ** 2.
*/
/* Fixed-point version for 8/16 bit ints.
*/
template <typename T, typename D, int min_value, int max_value>
static void inline
yafrsmooth_int_tab( PEL *pout, const PEL *pin,
const int bands, const int lskip,
const double sharpening,
const int *cx, const int *cy, const double *cs )
{
T* restrict out = (T *) pout;
const T* restrict in = (T *) pin;
const int b1 = bands;
const int b2 = 2 * bands;
const int b3 = 3 * bands;
const int l1 = lskip / sizeof( T );
const int l2 = 2 * lskip / sizeof( T );
const int l3 = 3 * lskip / sizeof( T );
for( int z = 0; z < bands; z++ ) {
const T uno_one = in[0];
const T uno_two = in[b1];
const T uno_thr = in[b2];
const T uno_fou = in[b3];
const T dos_one = in[l1];
const T dos_two = in[b1 + l1];
const T dos_thr = in[b2 + l1];
const T dos_fou = in[b3 + l1];
const T tre_one = in[l2];
const T tre_two = in[b1 + l2];
const T tre_thr = in[b2 + l2];
const T tre_fou = in[b3 + l2];
const T qua_one = in[l3];
const T qua_two = in[b1 + l3];
const T qua_thr = in[b2 + l3];
const T qua_fou = in[b3 + l3];
const int bicubic = bicubic_int<T>(
uno_one, uno_two, uno_thr, uno_fou,
dos_one, dos_two, dos_thr, dos_fou,
tre_one, tre_two, tre_thr, tre_fou,
qua_one, qua_two, qua_thr, qua_fou,
cx, cy );
const float yafr = yafrsmooth<T, D>(
uno_one, uno_two, uno_thr, uno_fou,
dos_one, dos_two, dos_thr, dos_fou,
tre_one, tre_two, tre_thr, tre_fou,
qua_one, qua_two, qua_thr, qua_fou,
cs );
int result = bicubic +
sharpening * SMOOTH_SHARPENING_SCALE * yafr;
if( result < min_value )
result = min_value;
else if( result > max_value )
result = max_value;
*out = result;
in += 1;
out += 1;
}
}
/* Float version for int/float types.
*/
template <typename T, typename D> static void inline
yafrsmooth_float_tab( PEL *pout, const PEL *pin,
const int bands, const int lskip,
const double sharpening,
const double *cx, const double *cy, const double *cs )
{
T* restrict out = (T *) pout;
const T* restrict in = (T *) pin;
const int b1 = bands;
const int b2 = 2 * bands;
const int b3 = 3 * bands;
const int l1 = lskip / sizeof( T );
const int l2 = 2 * lskip / sizeof( T );
const int l3 = 3 * lskip / sizeof( T );
for( int z = 0; z < bands; z++ ) {
const T uno_one = in[0];
const T uno_two = in[b1];
const T uno_thr = in[b2];
const T uno_fou = in[b3];
const T dos_one = in[l1];
const T dos_two = in[b1 + l1];
const T dos_thr = in[b2 + l1];
const T dos_fou = in[b3 + l1];
const T tre_one = in[l2];
const T tre_two = in[b1 + l2];
const T tre_thr = in[b2 + l2];
const T tre_fou = in[b3 + l2];
const T qua_one = in[l3];
const T qua_two = in[b1 + l3];
const T qua_thr = in[b2 + l3];
const T qua_fou = in[b3 + l3];
const T bicubic = bicubic_float<T>(
uno_one, uno_two, uno_thr, uno_fou,
dos_one, dos_two, dos_thr, dos_fou,
tre_one, tre_two, tre_thr, tre_fou,
qua_one, qua_two, qua_thr, qua_fou,
cx, cy );
const float yafr = yafrsmooth<T, D>(
uno_one, uno_two, uno_thr, uno_fou,
dos_one, dos_two, dos_thr, dos_fou,
tre_one, tre_two, tre_thr, tre_fou,
qua_one, qua_two, qua_thr, qua_fou,
cs );
*out = bicubic + sharpening * SMOOTH_SHARPENING_SCALE * yafr;
in += 1;
out += 1;
}
}
/* Given an offset in [0,1], calculate c0, c1, c2, c3, the yafr-smooth pixel
* weights.
*/
static void inline
calculate_coefficients_smooth( const double x, const double y, double c[4] )
{
const double dx = 1.f - x;
const double dy = 1.f - y;
g_assert( x >= 0 && x < 1 );
g_assert( y >= 0 && y < 1 );
c[0] = dx * x * dy;
c[1] = dx * x * y;
c[2] = dy * y * dx;
c[3] = dy * y * x;
}
/* High-quality double-only version.
*/
static void inline
yafrsmooth_notab( PEL *pout, const PEL *pin,
const int bands, const int lskip,
const double sharpening,
double x, double y )
{
double * restrict out = (double *) pout;
const double * restrict in = (double *) pin;
const int b1 = bands;
const int b2 = 2 * bands;
const int b3 = 3 * bands;
const int l1 = lskip / sizeof( double );
const int l2 = 2 * lskip / sizeof( double );
const int l3 = 3 * lskip / sizeof( double );
double cx[4];
double cy[4];
calculate_coefficients_catmull( x, cx );
calculate_coefficients_catmull( y, cy );
double cs[4];
calculate_coefficients_smooth( x, y, cs );
for( int z = 0; z < bands; z++ ) {
const double uno_one = in[0];
const double uno_two = in[b1];
const double uno_thr = in[b2];
const double uno_fou = in[b3];
const double dos_one = in[l1];
const double dos_two = in[b1 + l1];
const double dos_thr = in[b2 + l1];
const double dos_fou = in[b3 + l1];
const double tre_one = in[l2];
const double tre_two = in[b1 + l2];
const double tre_thr = in[b2 + l2];
const double tre_fou = in[b3 + l2];
const double qua_one = in[l3];
const double qua_two = in[b1 + l3];
const double qua_thr = in[b2 + l3];
const double qua_fou = in[b3 + l3];
const double bicubic = bicubic_float<double>(
uno_one, uno_two, uno_thr, uno_fou,
dos_one, dos_two, dos_thr, dos_fou,
tre_one, tre_two, tre_thr, tre_fou,
qua_one, qua_two, qua_thr, qua_fou,
cx, cy );
const double yafr = yafrsmooth<double, double>(
uno_one, uno_two, uno_thr, uno_fou,
dos_one, dos_two, dos_thr, dos_fou,
tre_one, tre_two, tre_thr, tre_fou,
qua_one, qua_two, qua_thr, qua_fou,
cs );
*out = bicubic + sharpening * SMOOTH_SHARPENING_SCALE * yafr;
in += 1;
out += 1;
}
}
static void
vips_interpolate_yafrsmooth_interpolate( VipsInterpolate *interpolate,
PEL *out, REGION *in, double x, double y )
{
VipsInterpolateYafrsmoothClass *yafrsmooth_class =
VIPS_INTERPOLATE_YAFRSMOOTH_GET_CLASS( interpolate );
VipsInterpolateYafrsmooth *yafrsmooth =
VIPS_INTERPOLATE_YAFRSMOOTH( interpolate );
/* Scaled int.
*/
const double sx = x * VIPS_TRANSFORM_SCALE;
const double sy = y * VIPS_TRANSFORM_SCALE;
const int sxi = FLOOR( sx );
const int syi = FLOOR( sy );
/* Get index into interpolation table and unscaled integer
* position.
*/
const int tx = sxi & (VIPS_TRANSFORM_SCALE - 1);
const int ty = syi & (VIPS_TRANSFORM_SCALE - 1);
const int xi = sxi >> VIPS_TRANSFORM_SHIFT;
const int yi = syi >> VIPS_TRANSFORM_SHIFT;
/* Look up the tables we need.
*/
const int *cxi = yafrsmooth_class->matrixi[tx];
const int *cyi = yafrsmooth_class->matrixi[ty];
const double *cxf = yafrsmooth_class->matrixf[tx];
const double *cyf = yafrsmooth_class->matrixf[ty];
/* Position weights for yafrsmooth.
*/
double cs[4];
calculate_coefficients_smooth( x - xi, y - yi, cs );
/* Back and up one to get the top-left of the 4x4.
*/
const PEL *p = (PEL *) IM_REGION_ADDR( in, xi - 1, yi - 1 );
/* Pel size and line size.
*/
const int bands = in->im->Bands;
const int lskip = IM_REGION_LSKIP( in );
#ifdef DEBUG
printf( "vips_interpolate_yafrsmooth_interpolate: %g %g\n", x, y );
printf( "\tleft=%d, top=%d, width=%d, height=%d\n",
xi - 1, yi - 1, 4, 4 );
#endif /*DEBUG*/
switch( in->im->BandFmt ) {
case IM_BANDFMT_UCHAR:
yafrsmooth_int_tab<unsigned char, int, 0, UCHAR_MAX>(
out, p, bands, lskip,
yafrsmooth->sharpening,
cxi, cyi, cs );
break;
case IM_BANDFMT_CHAR:
yafrsmooth_int_tab<signed char, int, SCHAR_MIN, SCHAR_MAX>(
out, p, bands, lskip,
yafrsmooth->sharpening,
cxi, cyi, cs );
break;
case IM_BANDFMT_USHORT:
yafrsmooth_int_tab<unsigned short, int, 0, USHRT_MAX>(
out, p, bands, lskip,
yafrsmooth->sharpening,
cxi, cyi, cs );
break;
case IM_BANDFMT_SHORT:
yafrsmooth_int_tab<signed short, int, SHRT_MIN, SHRT_MAX>(
out, p, bands, lskip,
yafrsmooth->sharpening,
cxi, cyi, cs );
break;
case IM_BANDFMT_UINT:
yafrsmooth_float_tab<unsigned int, float>(
out, p, bands, lskip,
yafrsmooth->sharpening,
cxf, cyf, cs );
break;
case IM_BANDFMT_INT:
yafrsmooth_float_tab<signed int, float>(
out, p, bands, lskip,
yafrsmooth->sharpening,
cxf, cyf, cs );
break;
case IM_BANDFMT_FLOAT:
yafrsmooth_float_tab<float, float>(
out, p, bands, lskip,
yafrsmooth->sharpening,
cxf, cyf, cs );
break;
case IM_BANDFMT_DOUBLE:
yafrsmooth_notab(
out, p, bands, lskip,
yafrsmooth->sharpening,
x - xi, y - yi );
break;
case IM_BANDFMT_COMPLEX:
yafrsmooth_float_tab<float, float>(
out, p, bands * 2, lskip,
yafrsmooth->sharpening,
cxf, cyf, cs );
break;
case IM_BANDFMT_DPCOMPLEX:
yafrsmooth_notab(
out, p, bands * 2, lskip,
yafrsmooth->sharpening,
x - xi, y - yi );
break;
default:
break;
}
}
static void
vips_interpolate_yafrsmooth_class_init( VipsInterpolateYafrsmoothClass *iclass )
{
GObjectClass *gobject_class = G_OBJECT_CLASS( iclass );
VipsObjectClass *object_class = VIPS_OBJECT_CLASS( iclass );
VipsInterpolateClass *interpolate_class =
VIPS_INTERPOLATE_CLASS( iclass );
GParamSpec *pspec;
gobject_class->set_property = vips_object_set_property;
gobject_class->get_property = vips_object_get_property;
object_class->nickname = "yafrsmooth";
object_class->description = _( "Bicubic plus edge enhance" );
interpolate_class->interpolate =
vips_interpolate_yafrsmooth_interpolate;
interpolate_class->window_size = 4;
/* Build the tables of pre-computed coefficients.
*/
for( int x = 0; x < VIPS_TRANSFORM_SCALE + 1; x++ ) {
calculate_coefficients_catmull(
(float) x / VIPS_TRANSFORM_SCALE,
iclass->matrixf[x] );
for( int i = 0; i < 4; i++ )
iclass->matrixi[x][i] =
iclass->matrixf[x][i] * VIPS_INTERPOLATE_SCALE;
}
/* Create properties.
*/
pspec = g_param_spec_double( "sharpening",
_( "Sharpening" ),
_( "Degree of extra edge enhancement" ),
0, 4, 1,
(GParamFlags) G_PARAM_READWRITE );
g_object_class_install_property( gobject_class,
PROP_SHARPENING, pspec );
vips_object_class_install_argument( object_class, pspec,
VIPS_ARGUMENT_SET_ONCE,
G_STRUCT_OFFSET( VipsInterpolateYafrsmooth, sharpening ) );
}
static void
vips_interpolate_yafrsmooth_init( VipsInterpolateYafrsmooth *yafrsmooth )
{
#ifdef DEBUG
printf( "vips_interpolate_yafrsmooth_init: " );
vips_object_print( VIPS_OBJECT( yafrsmooth ) );
#endif /*DEBUG*/
yafrsmooth->sharpening = 1.0;
}