removed all traces of yafrsmooth (obsolete prototype)
This commit is contained in:
parent
16d6518965
commit
7de848e644
2
TODO
2
TODO
@ -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.
|
||||||
|
@ -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, ")" );
|
||||||
}
|
}
|
||||||
|
@ -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 \
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
|
@ -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;
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user