Binding

Binding — Writing bindings for libvips

There are full libvips bindings for quite a few environments now: C, C++, command-line, Ruby, PHP, Lua, Python and JavaScript (node).

This chapter runs through the four main styles that have been found to work well. If you want to write a new binding, one of these should be close to what you need.

Don’t bind the top-level C API

The libvips C API (vips_add() and so on) is very inconvenient and dangerous to use from other languages due to its heavy use of varargs.

It’s much better to use the layer below. This lower layer is structured as create operator, set parameters, execute, extract results. For example, you can execute vips_invert() like this:

/* compile with
 *
 * gcc -g -Wall callvips.c `pkg-config vips --cflags --libs`
 *
 */

#include <vips/vips.h>

int
main( int argc, char **argv )
{
    VipsImage *in;
    VipsImage *out;
    VipsOperation *op;
    VipsOperation *new_op;
    GValue gvalue = { 0 };

    if( VIPS_INIT( argv[0] ) ) 
        /* This shows the vips error buffer and quits with a fail exit
         * code.
         */
        vips_error_exit( NULL ); 

    /* This will print a table of any ref leaks on exit, very handy for
     * development.
     */
    vips_leak_set( TRUE );

    if( argc != 3 )
        vips_error_exit( "usage: %s input-filename output-filename", 
            argv[0] );

    if( !(in = vips_image_new_from_file( argv[1], NULL )) )
        vips_error_exit( NULL ); 

    /* Create a new operator from a nickname. NULL for unknown operator.
     */
    op = vips_operation_new( "invert" );

    /* Init a gvalue as an image, set it to in, use the gvalue to set the
     * operator property.
     */
    g_value_init( &gvalue, VIPS_TYPE_IMAGE );
    g_value_set_object( &gvalue, in );
    g_object_set_property( G_OBJECT( op ), "in", &gvalue );
    g_value_unset( &gvalue );

    /* We no longer need in: op will hold a ref to it as long as it needs
     * it. 
     */
    g_object_unref( in ); 

    /* Call the operation. This will look up the operation+args in the vips
     * operation cache and either return a previous operation, or build
     * this one. In either case, we have a new ref we must release.
     */
    if( !(new_op = vips_cache_operation_build( op )) ) {
        g_object_unref( op );
        vips_error_exit( NULL ); 
    }
    g_object_unref( op );
    op = new_op;

    /* Now get the result from op. g_value_get_object() does not ref the
     * object, so we need to make a ref for out to hold.
     */
    g_value_init( &gvalue, VIPS_TYPE_IMAGE );
    g_object_get_property( G_OBJECT( op ), "out", &gvalue );
    out = VIPS_IMAGE( g_value_get_object( &gvalue ) );
    g_object_ref( out ); 
    g_value_unset( &gvalue );

    /* All done: we can unref op. The output objects from op actually hold
     * refs back to it, so before we can unref op, we must unref them. 
     */
    vips_object_unref_outputs( VIPS_OBJECT( op ) ); 
    g_object_unref( op );

    if( vips_image_write_to_file( out, argv[2], NULL ) )
        vips_error_exit( NULL ); 

    g_object_unref( out );

    return( 0 ); 
}

libvips has a couple of extra things to let you examine the arguments and types of an operator at runtime. Use vips_argument_map() to loop over all the arguments of an operator, and vips_object_get_argument() to fetch the type and flags of a specific argument.

Use vips_operation_get_flags() to get general information about an operator.