Writing an HDR Shop Plugin

Note that this section requires knowledge of C or C++.

HDR Shop supports a flexible plug-in architecture that lets a user write a new image editing operation and integrate it with the HDR Shop interface. Plug-ins are special stand-alone command-line programs that receive parameters via the command-line arguments. Because the interface with HDR Shop uses command-line arguments and the standard pipes, a plug-in can be written in any language and perform arbitrary processing on an image. For this tutorial, we will assume the language of choice is C++.

We will illustrate how to write a plug-in with a simple example plug-in that blurs an image and optionally halfsizes the image as well.

The plug-in communicates with HDR Shop via the stdin stream. When the plugin is invoked with a single command-line argument "--help" or "/?" it must output its list of parameters in a specific format and then exit.

Our plug-in will output the following message to stderr:<

This is a simple test plugin to blur an image.
HDR ShopFLAGS:
HDR ShopVERSION: 1.0.1
USAGE: sample_plugin [input.pfm] [output.pfm] [options]
OPTIONS:
	/V:[int=10]  		Blur Variance
	/D			Downsample 50%

The plugin must list information about itself in the following blocks:

Options are specified one per line. Each option has an identifier string, an optional parameter descriptor, and a description string. Each line should begin (ignoring whitespace) with an identifier string. For example, "/V:" and "/D" are the identifier strings in our sample plugin. The identifier is terminated by either whitespace or a parameter descriptor. This gives us a little bit of leeway as to how we want to specify our options; if we wanted, we could instead use "--variance=", or "-downsample" as identifiers.

Parameter descriptors are enclosed in square brackets: [], except for a multiple-selection, which is surrounded by curly braces: {}. Inside the square brackets is the descriptor type, followed by an optional default value. If a default value is specified, then HDR Shop will initialize the option's generated user interface to that value.

The available parameter descriptor types are:

Type Descriptor Default Example (identifier + descriptor) Notes
boolean   false /downsample If this option is present on the command line, the value is true, otherwise false
integer [integer=X],[int=X] X --iterations=[int=6]  
string [string=X],[str=X] X /greeting:[string=Hello World!]  
float [float=X] X /pi=[float] In all cases, if the user specifies no value for an option,
that option is not sent as a command-line argument.
input
filename
[inputfilename=X] X /C:[inputfilename=my default.cfg] Specifies a file that the plugin will read
output
filename
[outputfilename=X] X /debugout=[outputfilename=debug.txt] Specifies a file that the plugin will write
rectangle [selection] See notes /s[selection] The user-interface for this option is a checkbox, defaulting to checked.
When checked, the current selection in HDR Shop will be sent to the plugin,
in the format: 100,100,200,200 (that's top,left,bottom,right).
If there is no selection, the size of the entire image is returned.
multiple
choice
{String1|String2|...|StringN} String1 --algorithm:{|fast|accurate|weird} Multiple selection from the given list of strings.
The first value is the default.

When the plugin is selected by the user, HDR Shop will execute "sample_plugin --help" and parse the resulting text. HDR Shop will then create a dialogue box where the user can enter the values of all the plugin options. When the user has selected the options and clicks "Execute," HDR Shop will call the plugin again, this time with all of the options packaged as command line arguments. Options are passed to the plugin in the same format they are specified above. For example, if the user selects a "Blur Variance" value of 15, HDR Shop will pass the command-line argument /V:15. If the user has selected the "Downsample" option, HDR Shop will pass the argument /D, otherwise it will leave off the argument.

For plugins that manipulate images, HDR Shop passes them as .pfm files. See below for details on how to parse these files. HDR Shop writes the current image to a temporary .pfm file, which it passes the plugin. If the plug-in is supposed to return in image to HDR Shop, HDR Shop specifies the name of the temporary file that the plugin should save the .pfm file to.

Now lets get to the actual source code for the plugin:

	int main(int argc, char *argv[])
	{
		char *inputfilename = 0;
		char *outputfilename = 0;
		int downsample = 0;
		int variance = 10;

		if (argc == 1)	{
			printHelp();
			exit(0);
		}

		for (x = 1; x < argc; x++) {
			if (argv[x][0] == '-') {
				if (argv[x][1] == '-') {
					if (strncmp("help", &argv[x][2], 4) == 0) {
						printHelp();
						exit(0);
					}
				}
			}
			else if (argv[x][0] == '/') {
				switch(argv[x][1]) {
				case '?':
					printHelp();
					exit(0);
					break;
				case 'V':
					variance = atoi(argv[x]+3);
					break;
				case 'D':
					downsample = 1;
					break;
				}
			}
			else  {
				if (inputfilename == 0) 
					inputfilename = argv[x];
				else 
					outputfilename = argv[x];
			}
		}
		...

This section parses the command line arguments. If the program is passed /? or --help, it calls printHelp() which prints the message detailed above to stderr and then exits. Otherwise, the program looks for the forward-slash flag to indicate command line options. If the option is ?, it prints the help message. Otherwise, if the option is V, it parses the remaining part of the string for the integer value of variance. If the option is D, it sets the downsample flag to true. Finally, if the command line argument is not an option, it is assumed to be the input filename.

If the input filename has been read, it is assumed to be the output filename.

			if (!inputfilename)
				doError(1);
			if (!outputfilename)
				doError(2);

			floatimage fimg;
			if (!fimg.LoadPFM(inputfilename))
				doError(3);

			fimg.fast_gaussian_blur(variance);
			if (downsample)
				fimg.halfsize();
			
			if (!fimg.SavePFM(outputfilename))
				doError(4);

			return 0;
}

The function doError() just prints an error string to stderr and then calls exit() with a nonzero value to indicate to HDR Shop that an error occurred. HDR Shop will display everything that was output to stderr to the user as an error message. The floatimage class is a utility class. It provides a number of useful functions like file i/o from various formats, antialiased pixel reads, bluring, convolution, and other utilities. The full source code for floatimage and this sample plug-in is availible for download here.

Once the plug-in has been compiled into a working executable, it must be placed in a subdirectoy called "plugins" that is in the same directory as the HDR Shop executable. The name of the plug-in will appear in the plugins pulldown menu.