Plugin API C

How to create a Filters plugin in C/C++
To see how to create a FiltersPlugin, we will create a new one ! This new Plugin will be very basic : it add noise on a input image.

1 - Create a new C project : a/ type must be 'DLL' ->in Visual C++ 2005 you have to set the property 'Configuration Type'='Dynaic Library (.dll)' b/ the generated binary file name must be 'FiltersPlugin_Noise.dll' ->in Visual C++ 2005 you have to set the property 'Output File'='$(OutDir)\FiltersPlugin_Noise.dll'

2 - Copy and add this files in your project : FiltersTutorial/FiltersPlugin_/C/dllInterface.cpp FiltersTutorial/FiltersPlugin_/C/dllInterface.DEF FiltersTutorial/FiltersPlugin_/C/wrapper_filtersDll.c    FiltersTutorial/FiltersPlugin_/C/wrapper_filtersDll.h     FiltersTutorial/FiltersPlugin_/C/main.c     FiltersTutorial/FiltersPlugin_/C/main.h	(all this files are not necessary to create a FilterPlugin, but it can help a lot !)

3 - Export functions with the help of 'dllInterface.DEF' : ->in Visual C++ 2005 you have to set the property 'Module Definition File'='.\dllInterface.DEF'

4 - Change the project options to set the destination directory to the location of Filters ->Example : set the destination path to 'C:\FiltersTutorial\Bin' ->in Visual C++ 2005 you have to set the property 'Output Directory'

5 - Build the project ->Actually the new Plugin do nothing, but we can already test it in a Delphi project ! (for a final example, you can have a look on the project 'testplugin')

6 - Now we will add 2 parameters of our plugin : The parameter 'inImage' : the input image The parameter 'outImage' : the image where we have to draw the result ->it's always a good practice to provide output images as parameters (of course, when the size of output images can't be known, the filter must create it and provide it as a 'Output') a/ Well, in the unit 'main.h', add this protected variable : ... protected: PFBitmap32 _inImageParameter; PFBitmap32 _outImageParameter; ...    b/ Well, in the unit 'main.cpp', set it to NULL in the constructor : ... TFiltersPlugin::TFiltersPlugin {	_inImageParameter = NULL; _outImageParameter = NULL; _unsetRegionOfInterest; } ...    c/ Our Plugin has to declare this 2 parameters: ... __int64 TFiltersPlugin::_getParametersCount { return 2; }

void TFiltersPlugin::_getParameterName( const __int32 aIndex, char* aName ) {	switch( aIndex ){ case 0 : strcpy( aName, "inImage" ); break; case 1 : strcpy( aName, "outImage" ); break; } }

void TFiltersPlugin::_getParameterHelp( const __int32 aIndex, char* aHelp ) {	switch( aIndex ){ case 0 : strcpy( aHelp, "the input image" ); break; case 1 : strcpy( aHelp, "the output image (must be of the same size than [inImage])" ); break; } }

void TFiltersPlugin::_setParameterImage( const char* aName, const PFBitmap32 aImage ) {	if( strcmp("inImage", aName)==0 )_inImageParameter = aImage; else if( strcmp("outImage", aName)==0 )_outImageParameter = aImage; } ...

7 - Now we do the real job of our plugin : add noise ! ... // It's a scholar example, and not a good and fast method ! void TFiltersPlugin::_run(void) {	int x, xMin, xMax, y, yMin, yMax; TFColor32* pDest; TFRect roi; int r;

// if we have input images if( (_inImageParameter!=NULL) && (_outImageParameter!=NULL) ){ // both input images must be of the same size //if( (_inImageParameter->Width==_outImageParameter->Width) && (_inImageParameter->Height==_outImageParameter->Height) ){ if( image_isSameSize( _inImageParameter, _outImageParameter ) == TRUE ){ // we start by copy the [inImage] to [outImage] image_copyImageToImage( _inImageParameter, _outImageParameter ); // we get the ROI (if ROI=(-1,-1)(-1,-1), then getValidROI return the full image) image_getValidROI( _inImageParameter, &_roi, &roi ); // for each pixel in the ROI xMin = ceil( roi.Left ); xMax = ceil( roi.Right ); yMin = ceil( roi.Top ); yMax = ceil( roi.Bottom ); pDest = _outImageParameter->Bits; for( y=yMin; y<=yMax ; y++ ){ for( x=xMin; x<=xMax; x++ ){ // sometime we add salt and pepper noise int RANGE_MIN = 0; int RANGE_MAX = 2*100; int r = (((double) rand / (double) RAND_MAX) * RANGE_MAX + RANGE_MIN); if (r==0){ *pDest = clBlack32; }else if( r==1 ){ *pDest = clWhite32; }					pDest++; }			}		}	} } ...

8 - We can add a parameter to add more or less noise. a/ We add the parameter 'scale' ... protected: __int64 _scale; ...    b/ Set it to a default value in the constructor : ... TFiltersPlugin::TFiltersPlugin {	_inImageParameter = NULL; _outImageParameter = NULL; _scale = 100; _unsetRegionOfInterest; } ...    c/ Our Plugin has now to declare 3 parameters: ...

__int64 TFiltersPlugin::_getParametersCount { return 3; }

void TFiltersPlugin::_getParameterName( const __int32 aIndex, char* aName ) {	switch( aIndex ){ case 0 : strcpy( aName, "inImage" ); break; case 1 : strcpy( aName, "outImage" ); break; case 2 : strcpy( aName, "scale" ); break; } }

void TFiltersPlugin::_getParameterHelp( const __int32 aIndex, char* aHelp ) {	switch( aIndex ){ case 0 : strcpy( aHelp, "the input image" ); break; case 1 : strcpy( aHelp, "the output image (must be of the same size than [inImage])" ); break; case 2 : strcpy( aHelp, "if scale=100, then for each pixel, there is 1/scale chance to have noise" ); break; } }

void TFiltersPlugin::_setParameterInteger( const char* aName, const __int64 aValue ) {	if( strcmp("scale", aName)==0 )_scale = aValue; } ...    d/ And we use it in our process ... void TFiltersPlugin::_run(void) ...					int RANGE_MAX = 2*_scale; ... } ...

by edurand ->for any question : filters@edurand.com

The final code in Microsoft Visual Studio Express C/C++

 * 1) include 
 * 2) include 
 * 3) include 
 * 4) include 


 * 1) include "main.h"

TFiltersPlugin::TFiltersPlugin {	_inImageParameter = NULL; _outImageParameter = NULL; _scale = 100; _unsetRegionOfInterest; }

TFiltersPlugin::~TFiltersPlugin { }

// It's a scholar example, and not a good and fast method ! void TFiltersPlugin::_run(void) {	int x, xMin, xMax, y, yMin, yMax; TFColor32* pDest; TFRect roi; int r;

// if we have input images if( (_inImageParameter!=NULL) && (_outImageParameter!=NULL) ){ // both input images must be of the same size //if( (_inImageParameter->Width==_outImageParameter->Width) && (_inImageParameter->Height==_outImageParameter->Height) ){ if( image_isSameSize( _inImageParameter, _outImageParameter ) == TRUE ){ // we start by copy the [inImage] to [outImage] image_copyImageToImage( _inImageParameter, _outImageParameter ); // we get the ROI (if ROI=(-1,-1)(-1,-1), then getValidROI return the full image) image_getValidROI( _inImageParameter, &_roi, &roi ); // for each pixel in the ROI xMin = ceil( roi.Left ); xMax = ceil( roi.Right ); yMin = ceil( roi.Top ); yMax = ceil( roi.Bottom ); pDest = _outImageParameter->Bits; for( y=yMin; y<=yMax ; y++ ){ for( x=xMin; x<=xMax; x++ ){ // sometime we add salt and pepper noise int RANGE_MIN = 0; int RANGE_MAX = 2*_scale; int r = (((double) rand / (double) RAND_MAX) * RANGE_MAX + RANGE_MIN); if (r==0){ *pDest = clBlack32; }else if( r==1 ){ *pDest = clWhite32; }					pDest++; }			}		}	} }

void TFiltersPlugin::_run( const char* aCommand ) {	_run; }

__int64 TFiltersPlugin::_getParametersCount { return 3; }

void TFiltersPlugin::_getParameterName( const __int32 aIndex, char* aName ) {	switch( aIndex ){ case 0 : strcpy( aName, "inImage" ); break; case 1 : strcpy( aName, "outImage" ); break; case 2 : strcpy( aName, "scale" ); break; } }

void TFiltersPlugin::_getParameterHelp( const __int32 aIndex, char* aHelp ) {	switch( aIndex ){ case 0 : strcpy( aHelp, "the input image" ); break; case 1 : strcpy( aHelp, "the output image (must be of the same size than [inImage])" ); break; case 2 : strcpy( aHelp, "if scale=100, then for each pixel, there is 1/scale chance to have noise" ); break; } }

void TFiltersPlugin::_setParameterInteger( const char* aName, const __int64 aValue ) {	if( strcmp("scale", aName)==0 )_scale = aValue; }

void TFiltersPlugin::_setParameterFloat( const char* aName, const float aValue ) { }

void TFiltersPlugin::_setParameterBoolean( const char* aName, const bool aValue ) { }

void TFiltersPlugin::_setParameterString( const char* aName, const char* aValue ) { }

void TFiltersPlugin::_setParameterImage( const char* aName, const PFBitmap32 aImage ) {	if( strcmp("inImage", aName)==0 )_inImageParameter = aImage; else if( strcmp("outImage", aName)==0 )_outImageParameter = aImage; }

void TFiltersPlugin::_setParameterImagesCount( const char* aName, const __int32 aCount ) { }

void TFiltersPlugin::_setParameterImagesImageAtIndex( const char* aName, const PFBitmap32 aImage, const __int32 aIndex ) { }

void TFiltersPlugin::_setParameterPointer( const char* aName, const Pointer aPointer ) { }

__int32 TFiltersPlugin::_getOutputsCount { return 0; }

void TFiltersPlugin::_getOutputName( const __int32 aIndex, char* aName ) { }

PFBitmap32 TFiltersPlugin::_getOutputImage( const char* aName ) {	return NULL; }

__int32 TFiltersPlugin::_getOutputImagesCount( const char* aName ) {	return 0; }

PFBitmap32 TFiltersPlugin::_getOutputImagesImageAtIndex( const char* aName, const __int32 aIndex ) {	return NULL; }

__int32 TFiltersPlugin::_getOutputInteger( const char* aName ) {	return -1; }

float TFiltersPlugin::_getOutputFloat( const char* aName ) {	return -1.0; }

__int32 TFiltersPlugin::_getOutputArrayPointersCount( const char* aName ) {	return 0; }

Pointer TFiltersPlugin::_getOutputArrayPointersPointerAtIndex( const char* aName, const __int32 aIndex ) {	return NULL; }

void TFiltersPlugin::_setRegionOfInterest( const PFRect roi ) {	_roi = *roi; }

void TFiltersPlugin::_unsetRegionOfInterest {	_roi.Left = _roi.Top = _roi.Right = _roi.Bottom = -1; }

The final code in Eclipse C/C++

 * 1) include 
 * 2) include 
 * 3) include 
 * 4) include 


 * 1) include "main.h"

TFiltersPlugin::TFiltersPlugin {	_inImageParameter = NULL; _outImageParameter = NULL; _scale = 100; _unsetRegionOfInterest; }

TFiltersPlugin::~TFiltersPlugin { }

// It's a scholar example, and not a good and fast method ! void TFiltersPlugin::_run(void) {	int x, xMin, xMax, y, yMin, yMax; TFColor32* pDest; TFRect roi; int r;

// if we have input images if( (_inImageParameter!=NULL) && (_outImageParameter!=NULL) ){ // both input images must be of the same size //if( (_inImageParameter->Width==_outImageParameter->Width) && (_inImageParameter->Height==_outImageParameter->Height) ){ if( image_isSameSize( _inImageParameter, _outImageParameter ) == TRUE ){ // we start by copy the [inImage] to [outImage] image_copyImageToImage( _inImageParameter, _outImageParameter ); // we get the ROI (if ROI=(-1,-1)(-1,-1), then getValidROI return the full image) image_getValidROI( _inImageParameter, &_roi, &roi ); // for each pixel in the ROI xMin = ceil( roi.Left ); xMax = ceil( roi.Right ); yMin = ceil( roi.Top ); yMax = ceil( roi.Bottom ); pDest = _outImageParameter->Bits; for( y=yMin; y<=yMax ; y++ ){ for( x=xMin; x<=xMax; x++ ){ // sometime we add salt and pepper noise int RANGE_MIN = 0; int RANGE_MAX = 2*_scale; int r = (((double) rand / (double) RAND_MAX) * RANGE_MAX + RANGE_MIN); if (r==0){ *pDest = clBlack32; }else if( r==1 ){ *pDest = clWhite32; }					pDest++; }			}		}	} }

void TFiltersPlugin::_run( const char* aCommand ) {	_run; }

__int64 TFiltersPlugin::_getParametersCount { return 3; }

void TFiltersPlugin::_getParameterName( const __int32 aIndex, char* aName ) {	switch( aIndex ){ case 0 : strcpy( aName, "inImage" ); break; case 1 : strcpy( aName, "outImage" ); break; case 2 : strcpy( aName, "scale" ); break; } }

void TFiltersPlugin::_getParameterHelp( const __int32 aIndex, char* aHelp ) {	switch( aIndex ){ case 0 : strcpy( aHelp, "the input image" ); break; case 1 : strcpy( aHelp, "the output image (must be of the same size than [inImage])" ); break; case 2 : strcpy( aHelp, "if scale=100, then for each pixel, there is 1/scale chance to have noise" ); break; } }

void TFiltersPlugin::_setParameterInteger( const char* aName, const __int64 aValue ) {	if( strcmp("scale", aName)==0 )_scale = aValue; }

void TFiltersPlugin::_setParameterFloat( const char* aName, const float aValue ) { }

void TFiltersPlugin::_setParameterBoolean( const char* aName, const bool aValue ) { }

void TFiltersPlugin::_setParameterString( const char* aName, const char* aValue ) { }

void TFiltersPlugin::_setParameterImage( const char* aName, const PFBitmap32 aImage ) {	if( strcmp("inImage", aName)==0 )_inImageParameter = aImage; else if( strcmp("outImage", aName)==0 )_outImageParameter = aImage; }

void TFiltersPlugin::_setParameterImagesCount( const char* aName, const __int32 aCount ) { }

void TFiltersPlugin::_setParameterImagesImageAtIndex( const char* aName, const PFBitmap32 aImage, const __int32 aIndex ) { }

void TFiltersPlugin::_setParameterPointer( const char* aName, const Pointer aPointer ) { }

__int32 TFiltersPlugin::_getOutputsCount { return 0; }

void TFiltersPlugin::_getOutputName( const __int32 aIndex, char* aName ) { }

PFBitmap32 TFiltersPlugin::_getOutputImage( const char* aName ) {	return NULL; }

__int32 TFiltersPlugin::_getOutputImagesCount( const char* aName ) {	return 0; }

PFBitmap32 TFiltersPlugin::_getOutputImagesImageAtIndex( const char* aName, const __int32 aIndex ) {	return NULL; }

__int32 TFiltersPlugin::_getOutputInteger( const char* aName ) {	return -1; }

float TFiltersPlugin::_getOutputFloat( const char* aName ) {	return -1.0; }

__int32 TFiltersPlugin::_getOutputArrayPointersCount( const char* aName ) {	return 0; }

Pointer TFiltersPlugin::_getOutputArrayPointersPointerAtIndex( const char* aName, const __int32 aIndex ) {	return NULL; }

void TFiltersPlugin::_setRegionOfInterest( const PFRect roi ) {	_roi = *roi; }

void TFiltersPlugin::_unsetRegionOfInterest {	_roi.Left = _roi.Top = _roi.Right = _roi.Bottom = -1; }