next up previous contents
Next: 4.2 A more complicated Up: 4. Function dispatch and Previous: 4. Function dispatch and   Contents

4.1 Simple plugin example

As an example, consider this function:

#include <stdio.h>

#include <vips/vips.h>

/* The function we define. Call this from 
 * other parts of your C application. 
 */
int
double_integer( int in )
{
    return( in * 2 );
}

The source for all the example code in this section is in the vips-examples package.

The first step is to make a layer over this function which will make it look like a standard VIPS function. VIPS insists on the following pattern:

The argument descriptor is an array of structures, each describing one argument. For this example, it is:

/* Describe the type of our function. 
 * One input int, and one output int.
 */
static im_arg_desc arg_types[] = {
    IM_INPUT_INT( "in" ),
    IM_OUTPUT_INT( "out" )
};

IM_INPUT_INT() and IM_OUTPUT_INT() are macros defined in <vips/dispatch.h> which make argument types easy to define. Other macros available are listed in table 4.1.


Table 4.1: Argument type macros
Macro Meaning im_object has type
IM_INPUT_IMAGEVEC Vector of input images IMAGE **
IM_INPUT_IMAGE Input image IMAGE *
IM_OUTPUT_IMAGE Output image IMAGE *
IM_RW_IMAGE Read-write image IMAGE *
IM_INPUT_DOUBLE Input double double *
IM_INPUT_DOUBLEVEC Input vector of double im_realvec_object *
IM_OUTPUT_DOUBLE Output double double *
IM_INPUT_INT Input int int *
IM_OUTPUT_INT Output int int *
IM_INPUT_STRING Input string char *
IM_OUTPUT_STRING Output string char *
IM_INPUT_DISPLAY Input display im_col_display *
IM_OUTPUT_DISPLAY Output display im_col_display *
IM_OUTPUT_COMPLEX Output complex double *
IM_INPUT_DMASK Input double array im_mask_object *
IM_OUTPUT_DMASK Output double array to file im_mask_object *
IM_OUTPUT_DMASK_STATS Output double array to screen  
IM_INPUT_IMASK Input int array im_mask_object *
IM_OUTPUT_IMASK Output int array to file im_mask_object *


The argument to the type macro is the name of the argument. These names are used by user-interface programs to provide feedback, and sometimes as variable names. The order in which you list the arguments is the order in which user-interfaces will present them to the user. You should use the following conventions when selecting names and an order for your arguments:

This function sits over double_integer(), providing VIPS with an interface which it can call:

/* Call our function via a VIPS im_object 
 * vector.
 */
static int
double_vec( im_object *argv )
{
    int *in = (int *) argv[0];
    int *out = (int *) argv[1];

    *out = double_integer( *in );

    /* Always succeed.
     */
    return( 0 );
}

Finally, these two pieces of information (the argument description and the VIPS-style function wrapper) can be gathered together into a function description.

/* Description of double_integer.
 */ 
static im_function double_desc = {
    "double_integer",     /* Name */
    "double an integer",  /* Descrip. */
    0,                    /* Flags */
    double_vec,           /* Dispatch */
    IM_NUMBER( arg_types ),/* # of args */
    arg_types             /* Arg list */
};

IM_NUMBER() is a macro which returns the number of elements in a static array. The flags field contains hints which user-interfaces can use for various optimisations. At present, the possible values are:

IM_FN_PIO
This function uses the VIPS PIO system (see the Library Programmers' Guide)

IM_FN_TRANSFORM
This the function transforms coordinates.

IM_FN_PTOP
This is a point-to-point operation, that is, it can be replaced with a look-up table.

IM_FN_NOCACHE
This operation has side effects and should not be cached. Useful for video grabbers, for example.

This function description now needs to be added to the VIPS function database. VIPS groups sets of related functions together in packages. There is only a single function in this example, so we can just write:

/* Group up all the functions in this 
 * file.
 */
static im_function *function_list[] = {
    &double_desc
};

/* Define the package_table symbol. This 
 * is what VIPS looks for when loading 
 * the plugin.
 */
im_package package_table = {
    "example",        /* Package name */
    IM_NUMBER( function_list ),
    function_list     /* Function list */
};

The package has to be named package_table, and has to be exported from the file (that is, not a static). VIPS looks for a symbol of this name when it opens your object file.

This file needs to be made into a dynamically loadable object. On my machine, I can do this with:

example% gcc -fPIC -DPIC -c 
  `pkg-config vips-7.10 --cflags` 
  plug.c -o plug.o
example% gcc -shared plug.o 
  -o double.plg

You can now use double.plg with any of the VIPS applications which support function dispatch. For example:

example% vips -plugin double.plg \
    double_integer 12
24
example%

If you copy double.plg into your VIPS library area (the directory where libvips is installed) it will be automatically loaded by all VIPS programs as they start up.


next up previous contents
Next: 4.2 A more complicated Up: 4. Function dispatch and Previous: 4. Function dispatch and   Contents
John Cupitt 2004-11-02