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 function should be int-valued, and return 0 for success and non-zero for error. It should set `im_error()`.

- The function should take a single argument: a pointer to a `NULL`-terminated array of `im_objects`.

- Each `im_object` represents one argument to the function (either output or input) in the form specified by the corresponding entry in the function's argument descriptor.

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:

- Names should be entirely in lower-case and contain no special characters, apart from the digits 0-9 and the underscore character `_'.

- Names should indicate the function of the argument. For example, `im_add()` has the following argument names:

      example% vips -help im_add
      vips: args: in1 in2 out
      where:
          in1 is of type "image"
          in2 is of type "image"
          out is of type "image"
      add two images, from package
          "arithmetic"
      flags:
          (PIO function)
          (no coordinate transformation)
          (point-to-point operation)

- You should order arguments with large input objects first, then output objects, then any extra arguments or options. For example, `im_extract()` has the following sequence of arguments:

      example% vips -help im_extract
      vips: args: input output left top
          width height channel
      where:
          input is of type "image"
          output is of type "image"
          left is of type "integer"
          top is of type "integer"
          width is of type "integer"
          height is of type "integer"
          channel is of type "integer"
      extract area/band, from package
          "conversion"
      flags:
          (PIO function)
          (no coordinate transformation)
          (point-to-point operation)

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: 4.2 A more complicated Up: 4. Function dispatch and Previous: 4. Function dispatch and Contents