Difference between revisions of "PlugIn Design Guidelines"

(oops -- noted by GL)
Line 1: Line 1:
 
<h3>Key concepts</h3>
 
<h3>Key concepts</h3>
We favor a style of plugin design that enables execution of the plugin:
+
We favor a style of ImageJ plugin design that enables execution of the plugin:
 
<ol>
 
<ol>
 
<li>From the menus.</li>
 
<li>From the menus.</li>

Revision as of 11:37, 22 December 2008

Key concepts

We favor a style of ImageJ plugin design that enables execution of the plugin:

  1. From the menus.
  2. From a macro.
  3. From any other plugin or script.

The key point is to separate the setup from the execution. For the purpose, we place the setup within the run method (any dialogs, for example) and the execution in another method.

A second key point is never to show images unless within the run method. There's nothing more annoying than a plugin that assumes there is no other plugin running, or that its invocation will happen always from the menus.

Example java plugin

For example, a plugin that duplicates and scales an image:

/* SAVE in a file named Duplicate_and_Scale.java under the plugins folder! */
import ij.plugin.PlugIn;
import ij.IJ;
import ij.ImagePlus;
import ij.gui.GenericDialog;
import ij.process.ImageProcessor;

/** Duplicate and scale the current image. */
public class Duplicate_and_Scale implements PlugIn {

	/** Ask for parameters and then execute.*/
	public void run(String arg) {
		// 1 - Obtain the currently active image:
		ImagePlus imp = IJ.getImage();
		if (null == imp) return;

		// 2 - Ask for parameters:
		GenericDialog gd = new GenericDialog("Scale");
		gd.addNumericField("width:", imp.getWidth(), 0);
		gd.addNumericField("height:", imp.getHeight(), 0);
		gd.addStringField("name:", imp.getTitle());
		gd.showDialog();
		if (gd.wasCanceled()) return;

		// 3 - Retrieve parameters from the dialog
		int width = (int)gd.getNextNumber();
		int height = (int)gd.getNextNumber();
		String name = gd.getNextString();

		// 4 - Execute!
		Object[] result = exec(imp, name, width, height);

		// 5 - If all went well, show the image:
		if (null != result) {
			ImagePlus scaled = (ImagePlus) result[1];
			scaled.show();
		}
	}

	/** Execute the plugin functionality: duplicate and scale the given image.
	 * @return an Object[] array with the name and the scaled ImagePlus.
	 * Does NOT show the new, scaled image; just returns it. */
	public Object[] exec(ImagePlus imp, String new_name, int width, int height) {
		// 0 - Check validity of parameters
		if (null == imp) return null;
		if (width <= 0 || height <= 0) return null;
		if (null == new_name) new_name = imp.getTitle();

		// 1 - Perform the duplication and resizing
		ImageProcessor ip = imp.getProcessor().resize(width, height);
		ImagePlus scaled = new ImagePlus(new_name, ip);

		// 2 - Return the new name and the scaled image
		return new Object[]{new_name, scaled};
	}
}

Compiling the plugin

Save the java code in a java file with the same name of the class. For the above it would be Duplicate_and_Scale.java.

To compile the plugin, place it in fiji/plugins folder. Then you have two options:

  1. Either call "Plugins - Compile and Run" from the menus
  2. ... or compile it from a terminal with ./fiji --javac plugins/Duplicate_and_Scale.java

To make the plugin appear in the PlugIns menu, restart Fiji or, better, just call "Help - Update Menus".

Running the plugin

To run the plugin, just call that menu item named "Duplicate and Scale".

From a macro

To run the plugin from a macro, do:

IJ.run("Duplicate and Scale", "name=[scaled copy] width=500 height=700");

From a java plugin

To run the plugin from another java plugin, do:

ImagePlus source = ...; // any image

Duplicate_and_Scale das = new Duplicate_and_Scale();
Object[] result = das.exec(source, "Scaled Copy", 500, 700);
if (null != result) {
	String name = (String) result[0];
	ImagePlus scaled = (ImagePlus) result[1];
}

From javascript

To run the plugin from a javascript, do:

var source = ...; // any image
var das = new Duplicate_and_Scale();
var result = das.exec(source, "Scaled Copy", 500, 700);
if (result) {
	var name = result[0];
	var imp = result[1];
}

As a special case, since the above example plugin needs only one image, we can provide such image semidirectly with the new Thread-safe current image concept. Keep in mind that then the plugin will show the new scaled image, not return it!

var source = ...; // any image
IJ.run(source, "Duplicate and Scale", "name=[scaled copy] width=500 height=700");

Above, ImageJ's macro system provides the source image as the return value of the IJ.getImage() call within the plugin's run method. Then, the macro arguments are fed directly into the GenericDialog entries of the same name, and the rest of the run method calls the exec method without ever showing the dialog.