Chapter 3 - A Simple Example

As a first example, let's produce a simple plugin. This plugin will do brightness, ie, multiply each pixel by a user-input value.

In a file called newBright.C, we will first add the routine to set up the UI. When Chalice loads a plugin, it calls a function called upiCreateParameters(), which, as the name suggests, defines the parameters your plugin will present to the user. In our plugin, this would look like

CPIDSOEXPORT void upiCreateParameters( void )
{
    // First let's add a "Tab":
    cpiAddTab( "Parameters" );

    // Now let's add the brightness parameter
	cpiAddFloat( "Brightness", 1.0F, 0.0F, 10.0F, P_ANIMATE );
}
Notice that the first call is to cpiAddTab(). This should always be the case - you define a tab first, then put parameters into it. Our one parameter is of type float (cpiAddFloat()), but in the next chapter we will see what other kinds of UI inputs we could add.

Next, we need to define what happens when the image is cooked. Whenever a custom node is called on to produce an image, the routine upiProcessImage() is called. This routine has a single argument, which is a pointer to an image (for processing multiple inputs, see Chapter 5).

This is what our routine might look like:

CPIDSOEXPORT
int upiProcessImage( CPI_Image *result )
{
    // First, we get the brightness parameter
    float brightness;
    if(cpiGetFloat("Brightness", result->info.time, &brightness) != 0)
    {
        cpiError( "Could not get brightness parameter" );
        return -1;
    }

    // We calculate how many pixels we have
    int numpix = result->info.sizeX * result->info.sizeY * 
	                        result->info.channels;

    // Now we look at what type of image we have and call 
	// the right Brightness
    switch( result->info.pelType )
    {
        case P_INT8:
            Brightness( (unsigned char *)result->data, brightness,
                    (float)UCHAR_MAX, numpix );
            break;

        case P_INT16:
            Brightness( (unsigned short *)result->data, brightness,
                    (float)USHRT_MAX, numpix );
            break;

        case P_FLOAT32:
            Brightness( (float *)result->data, brightness,
                    1.0F, numpix );
            break;

        default:
            cpiError( "Unknown pixel type" );
            return -1;
    }

    return 0;
}
Now we need to define the routine Brightness() which we called in upiProcessImage(). By using a C++ template, we only have to do this once, and then let the compiler produce the 3 different versions we actually need (one for each of 8 bit, 16 bit and float image types). Our routine looks like this:

template <class TYPE>
void Brightness( TYPE *d, float brightness, float max, int numpix )
{
    float val;

    // Go through all pixels
    while( numpix-- )
    {
        // Apply the brightness
        val = (float)*d * brightness;

        // Clip the result to make sure it's within range
        if( val > max ) val = max;
        if( val < 0 ) val = 0;

        // We're done, go to the next pixel
        *d = val;
        d++;
    }
}
The final file should look like this:
#include <stdlib.h>
#include <stdio.h>
#include <limits.h>
#include <memory.h>
#include "cpi.h"

CPIDSOEXPORT void upiCreateParameters( void )
{
    // First let's add a "Tab":
    cpiAddTab( "Parameters" );

    // Now let's add the brightness parameter
    cpiAddFloat( "Brightness", 1.0F, 0.0F, 10.0F, P_ANIMATE );
}

template <class TYPE>
void Brightness( TYPE *d, float brightness, float max, int numpix )
{
    float val;

    // Go through all pixels
    while( numpix-- )
    {
        // Apply the brightness
        val = (float)*d * brightness;

        // Clip the result to make sure it's within range
        if( val > max ) val = max;
        if( val < 0 ) val = 0;

        // We're done, go to the next pixel
        *d = val;
        d++;
    }
}

CPIDSOEXPORT
int upiProcessImage( CPI_Image *result )
{
    // First, we get the brightness parameter
    float brightness;
    if(cpiGetFloat("Brightness", result->info.time, &brightness) != 0)
    {
        cpiError( "Could not get brightness parameter" );
        return -1;
    }

    // We calculate how many pixels we have
    int numpix = result->info.sizeX * result->info.sizeY *
	                    result->info.channels;

    // Now we look at what type of image we have and call 
	// the right Brightness
    switch( result->info.pelType )
    {
        case P_INT8:
            Brightness( (unsigned char *)result->data, brightness,
                    (float)UCHAR_MAX, numpix );
            break;

        case P_INT16:
            Brightness( (unsigned short *)result->data, brightness,
                    (float)USHRT_MAX, numpix );
            break;

        case P_FLOAT32:
            Brightness( (float *)result->data, brightness,
                    1.0F, numpix );
            break;

        default:
            cpiError( "Unknown pixel type" );
            return -1;
    }

    return 0;
}
This file is provided in the examples, ready to compile. You can now compile, install and run this as per the instructions in Chapter 2:
> CC -shared -o newBright.so newBright.C -all libcpi.a
> cp MyPlugin.so /usr/grail/chalice1.6/plugIns
> builddialogs MyPlugin
> chalice
(note: you will need to be root to run some of the above commands. Please see Chapter 2 for details)
[Previous Page] [Next Page]
[Table of Contents] [Index]

Copyright © 1998 Silicon Grail Inc.
710 Seward Street, Hollywood, CA 90038