Difference between revisions of "JavaScript Scripting"

(Functional programming)
(Functional programming)
Line 429: Line 429:
mapAndShow( IJ.getImage(), Math.pow, 3);
mapAndShow( IJ.getImage(), Math.pow, 3);
All the above are examples to give you an idea of what is possible with Javascript and ImageJ.
If you are interested on applying mathematical functions to images, you may be better off using internal ImageJ commands, as listed in the menu "Process - Math":
<source lang="javascript">
var imp = IJ.getImage();
var imp2 = new ImagePlus("copy of " + imp.title, imp.getProcessor().duplicate().convertToFloat());
// Set each pixel to the square of its value:
IJ.run( imp2, "Square", "");

Revision as of 13:13, 18 November 2008

Javascript tutorial for ImageJ

Language basics

Importing packages and classes

By default, all ImageJ and java.lang.* classes are imported.

You can specify further imports by:

// Import all classes under java.io.*

// Import a single class instead


There are two ways:

  • Direct: the variable is globally visible (dangerous! Leads to nasty bugs.)
  • With a var declaration: the variable is local, visible only within the innermost code block.

Local variables are also faster, because they can be efficiently optimized for access. Examples:

// global variable 'imp'
imp = IJ.getImage();

// local variable 'i', visible within the loop only:
for (var i = 0; i < 10; i++ ) {
  IJ.log("i is " + i);

Mixing global and local variables in a sensible way:

// global variables 'base_url' and 'names'
// and local variable 'imp', the latter visible within the loop only:

base_url = "http://rsb.info.nih.gov/ij/images/";

names = ["blobs.gif", "boats.gif", "bridge.gif"];

for (var i = 0; i< names.length; i++) {
  var imp = IJ.openImage( base_url + names[i] );
  // process image
  // ...

// ERROR: variable 'imp' is not visible outside the loop
// IJ.log("The last image opened was: " + imp);


There are both Javascript arrays and native java arrays.

Javascript arrays

There are many ways to create a Javascript array. Here are a few:

// One dimensional:
var names = ["blobs.gif", "boats.gif", "bridge.gif"];
IJ.log("We have " + names.length + " names.");

// Two dimensional:
var coords = [[10, 20, 30],   // X coords
              [15, 25, 35]];  // Y coords

IJ.log( "x0, y0 = " + coords[0][0] + ", " + coords[1][0] );
IJ.log( "All X coords: " + coords[0] );

// Uneven dimensions:
var coords = [[10, 20, 30],               // X coords
              [15, 25, 35, 45, 55, 75]];  // Y coords
IJ.log( "Number of X coords: " + coords[0].length );
IJ.log( "Number of Y coords: " + coords[1].length );

Arrays in Javascript are extremely flexible:

// Empty arrays:
var names = new Array();
IJ.log("First name is: " + names[0]); // --> prints "undefined", i.e. null.

// Creating array entries at arbitrary index positions:
names[0] = "Table";
names[5] = "Window";
IJ.log("Number of names: " + names.length); // --> prints 6 ! All other entries are "undefined", null.

// Using the array as a dictionary:
names["one"] = 1;
IJ.log("Number of names: " + names.length); // --> still prints 6! But now the array has a map in it as well.
IJ.log("The 'one' is " + names["one"]);     // --> prints 1

// Array entries can contain anything, including other arrays!
names[3] = new Array();
names[3][0] = "Ok";
names[3][1] = "Good";
names[3][2] = ["Arrays", "are", "very", "flexible"]; // another array!

Native Java arrays

Native java arrays can be passed to java functions and methods directly. For example, to create an array of pixels:

width = 512
height = 512
pixels = new java.lang.reflect.Array.newInstance(java.lang.Byte.TYPE, width * height);

To manipulate such arrays, just do so as if they were Javascript arrays. Beware, though, that now you are limited to numerical indices only, and within the array size only!

// Subtract 25 to each pixel:
for (var i = 0; i < pixels.length; i++) {
  pixels[i] -= 25;

Above, beware of all problems derived from manipulating signed byte[] arrays, whose values should be made unsigned first, modified, then signed back into the array.


Simple example:

function invertImage(imp) {
  var ip = imp.getProcessor();

// Obtain the current image:
var imp = IJ.getImage();

// Invoke our function

// Update screen:

The number of arguments you invoke an image with is flexible. All arguments with which a function is invoked are collected in a variable named arguments.

Each function is an object, and has a variable this which provides access to its internal fields, such as name:

For example:

function createImage(width, height) {
  IJ.log( "Function name: " + this.name);
  IJ.log( "Number of arguments: " + arguments.length);
  // Default image type:
  var type = "8-bit";
  // Check if an extra argument for the image type was provided:
  if (arguments.length > 2) {
    // Check that the extra arg makes any sense:
    if ("RGB" == arguments[2]) {
      type = "RGB";
    } else {
      IJ.log("Don't know how to use " + arguments[2]);
      return null;

  var imp = IJ.createImage("New image", type, width, height, 1);
  return imp; 

var imp = createImage(400, 400, "RGB");

For a complex example see the example script Multithreaded Image Processing in Javascript, which, beyond parallelization, illustrates how to pass functions as arguments to other functions, and how to invoke them with variable number of arguments.

Functions as Objects

Any number of variables may be created on the fly on the body of a function, on its own this self reference pointer.

To create an object in Javascript, just declare a function first that stores the object's data:

// Use uppercase, by convention

function Data(image, annotation) {
    this.image = image;
    this.annotation = annotation;

Then just create it:

var data = new Data(IJ.getImage(), "The current image");

IJ.log("data contains: " + data.image + "\n with annotation: " + data.annotation);

To add methods to manipulate the new Data object, create a function that takes the object as an argument:

function annotate(data) {
    var gd = GenericDialog("Annotate");
    gd.addStringField("New annotation:", data.annotation);
    if (gd.wasCanceled()) return;
    // assign new annotation:
    data.annotation = gd.getNextString();

// Invoke on the existing Data object:

Creating import namespaces

var awt_bindings = new JavaImporter(Packages.java.awt.Frame, Packages.java.awt.Button);

with (awt_bindings) {
  // imported classes visible ONLY in this block
  win = new Frame("Title");
  b = new Button("Press me");

Inspecting fields and methods of an object

So you are returned an object for a function and you don't know what is it.

To print its class within the interpreter:

ob = ...

or to the log window:

ob = ...

To print the list of methods it has, with their return types and argument types:

ob = ...
m = ob.getClass().getMethods();
for (var i=0; i<m.length; i++) IJ.log(m[i]);


All math functions available:

Math.abs(a)     // the absolute value of a
Math.acos(a)    // arc cosine of a
Math.asin(a)    // arc sine of a
Math.atan(a)    // arc tangent of a
Math.atan2(a,b) // arc tangent of a/b
Math.ceil(a)    // integer closest to a and not less than a
Math.cos(a)     // cosine of a
Math.exp(a)     // exponent of a
Math.floor(a)   // integer closest to and not greater than a
Math.log(a)     // log of a base e
Math.max(a,b)   // the maximum of a and b
Math.min(a,b)   // the minimum of a and b
Math.pow(a,b)   // a to the power b
Math.random()   // pseudorandom number in the range 0 to 1
Math.round(a)   // integer closest to a 
Math.sin(a)     // sine of a
Math.sqrt(a)    // square root of a
Math.tan(a)     // tangent of a

Built-in constants:


Trivial example:

var root = Math.sqrt(12);
IJ.log("The root of 12 is " + root);

Functional programming

Supose you want to create a new image with the square values of the pixels in another image.

First, we get a source image (such as the currently active image):

var source = IJ.getImage(); // the current image (an ImagePlus)

Typically, you would then loop through all pixels and apply the result of their square to the other image:

// Return a new ImageProcessor containing the square of each pixel value in ImageProcessor ip
function square(ip) {
  var ip2 = ip.duplicate().convertToFloat();
  var pix = ip.getPixels();

  for (var i = 0; i < pix.length; i++) {
    pix[i] = Math.pow(pix[i], 2);

  return ip2;

var ip2 = square( source.getProcessor() );

// Show the result:
new ImagePlus("square of " + source.title, ip2).show();

But imagine now you want to get an image with the square root instead of the square, or the logarithm. Isn't that the same?

We would have to write similar functions named sqrt and pow3. And so on.

Instead, we should stop and think: there is a common pattern. All we want to do is to apply a function to each pixel in one image, and set the result into the same pixel in another image. In functional programming this pattern is called a map operation. Since Javascript lets us pass functions as arguments, we can define our own map function:

function map(fn, ip) {
  var ip2 = ip.duplicate().convertToFloat();
  var pix = ip2.getPixels();

  for (var i = 0; i < pix.length; i++) {
    pix[i] = fn(pix[i]);

  return ip2;

Now, equipped with our map function, we can apply any mathematical operation we want:

var ip_sqrt = map( Math.sqrt, source.getProcessor() );
var ip_log  = map( Math.log,  source.getProcessor() );

But wait! We didn't pass any extra argument. How can we do a generic function for pow so we can apply a power of 2, or 3, etc?

We can rewrite our map function like this:

function map(fn, ip) {
  var ip2 = ip.duplicate().convertToFloat();
  var pix = ip2.getPixels();

  for (var i = 0; i < pix.length; i++) {
    pix[i] = fn(pix[i], arguments[2]);
  return ip2;

... where arguments[2] is the argument, if any, present beyond any declared arguments. This works because in javascript, functions can accept a variable number of arguments:

var ip2 = map( Math.pow, source.getProcessor(), 2 );
var ip3 = map( Math.pow, source.getProcessor(), 3 );

Our second version of the map function, though, is a bit perverted: in standard functional programming techniques, the function given as arguments would be applied to each element at index i of every list; i.e. the function would receive as many arguments as lists we give to the map. But we don't need that.

So what's the big deal? We have abstracted away a common pattern, looping, but furthermore, we have reduced the complexity of our program. So now, for example, applying an optimization to the map function will improve all the places in our code that use it!

(The same would be true for adding a debugging message, and what not. Anything you want).

For example, since the processing of each pixel is independent of the others, we could parallelize the processing!


function map(fn, ip) {
  var ip2 = ip.duplicate().convertToFloat();
  var pix = ip2.getPixels();

  var n_threads = Runtime.getRuntime().availableProcessors();
  var threads = new Array();

  var ai = new AtomicInteger(0);
  var width = ip.getWidth();
  var height = ip.getHeight();

  var arg = arguments[2];

  for (var t = 0; t < n_threads; t++) {
    threads[t] = new Thread( function() {
        // Process one line at a time:
        for (var line = ai.getAndIncrement(); line < height; line = ai.getAndIncrement()) {
           var offset = line * width;
           for (var i = 0; i < width; i++) {
               // invoke function on each pixel, with the optional extra argument
               pix[offset + i] = fn(pix[offset + i], arg);

  // Wait until all threads finish:
  for (var t = 0; t < n_threads; t++) {
  return ip2;

We would call the now multithreaded map function just like before:

var ip_sqrt = map( Math.sqrt, source.getProcessor() );
var ip_log  = map( Math.log, source.getProcessor() );
var ip2     = map( Math.pow, source.getProcessor(), 2 );
var ip3     = map( Math.pow, source.getProcessor(), 3 );

Above: beware that parallelizing a trivial function like Math.sqrt will likely result in a slower execution, because of multithreading overheads and the extreme contention in accessing the same pixel array from multiple threads. Perhaps you want to have two versions of map: the simple and the parallel one, and use the latter for complex, heavy functions.

For further ease, we could create a show function that avoids further repetitions:

function mapAndShow(imp, fn) {
  var ip1 = imp.getProcessor();
  // Map the function to each pixel, into a new ImageProcessor:
  var ip2 = map(fn, ip1, arguments[2]); // pass any extra argument as well
  // Fix LUT range for best visualization:
  // Open image in a new window:
  new ImagePlus(fn.name + " of " + imp.title, ip2).show();

mapAndShow( IJ.getImage(), Math.sqrt);

mapAndShow( IJ.getImage(), Math.pow, 3);


All the above are examples to give you an idea of what is possible with Javascript and ImageJ. If you are interested on applying mathematical functions to images, you may be better off using internal ImageJ commands, as listed in the menu "Process - Math":

var imp = IJ.getImage();
var imp2 = new ImagePlus("copy of " + imp.title, imp.getProcessor().duplicate().convertToFloat());

// Set each pixel to the square of its value:
IJ.run( imp2, "Square", "");


ImageJ interaction

Opening and creating ImageJ images

imp = new Opener().openImage("/path/to/image.jpg");
// do some processing
// ...

Or easier:

imp = IJ.openImage("/path/to/image.jpg");

Also URLs (in this case, we call directly show(), not keeping the returned image pointer into any variable):


Create an image from scratch, including LUT:

// From scratch:
width = 512
height = 512
pixels = new java.lang.reflect.Array.newInstance(java.lang.Byte.TYPE, width * height);
// process the pixels
// ...
// Create LUT:
channel = new java.lang.reflect.Array.newInstance(java.lang.Byte.TYPE, 256);
for (i=0; i<channel.length; i++)
    channel[i] = Integer(i).byteValue();
cm = new LUT(channel, channel, channel);

// Create the image as 8-bit with the LUT we just created:
imp = new ImagePlus("the title", new ByteProcessor(width, height, pixels, cm));

A more convenient way to create images, with a default grayscale LUT:

imp = ImagePlus("the title", new ByteProcessor(512, 512));
pixels = imp.getProcessor().getPixels();
// do some processing ...
// ...

Running ImageJ commands

To launch a command:

// in a separate thread:

// instead, waiting until it finishes:

To run commands on a specific image:

// Obtain an image to work on:
var imp = IJ.getImage();

// Call the command to add noise to the current image
// which is here the one provided as argument:
IJ.run(imp, "Add Noise", "");

// Subtract 25 to each pixel value:
IJ.run(imp, "Subtract...", "value=25");

Above, you can see what arguments to add to a command by opening the Plugins - Macro Recorder, and then running the command manually. The macro string will print on the recorder window.

Inspect java methods and fields in an object

To print the static fields and methods of ImagePlus class:

s = "";
for (a in ImagePlus) { s += " " + a; }


To print the fields and methods of an instance of ImagePlus (i.e. an image that already exists):

// get the current image
imp = IJ.getImage();
// print fields and methods
s = ""; for (a in imp) { s += " " + a; }

... which prints all method names such as getStatistics isHyperStack etc. and fields like width and height (because there are public 'get' methods for it such as getWidth() and getHeight() .)

Creating a script for ImageJ

Save your javascript script in a text file:

  1. with extension .js
  2. and with an underscore '_' in its name: my_first_script.js

...and just drop it in ImageJ's plugins folder or a subfolder.

On startup, the script will appear in the corresponding menu.

If you add the script after ImageJ was started, just call "Help - Update menus" and it will be picked up.

You can continue modifying and saving the script file. Every time you run it from the menu, it will be read from the file system.

Interfaces and anonymous classes

To create an ImageListener without declaring a new class that implements such java interface, simply use a function that will be mapped to all its methods (as long as they have the same signature, which they do in this case):

ImagePlus.addImageListener( function (imp, name) {
       if (name == "imageOpened") {
              IJ.log("Opened image: " + imp);
      } else if (name == "imageClosed") {
              IJ.log("Closed image: " + imp);
      } else if (name == "imageUpdated") {
              IJ.log("Updated image: " + imp);

Alternatively, one can create an object with declared functions inside to assign then to an anonymous class created on the fly from an interface:

body = {
  run: function () {
// Runnable is an interface
runnable = new Runnable(body);
new Thread(runnable).start();


new Thread( function () { IJ.log("Running!"); } ).start();

What the code above did: to look for an interface that could take a method with no arguments, represented by the function, and instantiate an anonymous class that implements such interface with the function mapped to its method.

See also an example plugin for ImageJ written in javascript.

Multithreaded Image Processing in Javascript

The following example shows how to create a generic function, named multithreader, that accepts another function as argument and executes it in parallel a number of times. As a very simple example, a printer function is passed to the multithreader, and a list of numbers is printed without repeating anyone, and not preserving the order of course.

The multithreader scales up to as many CPU cores as the computer has to offer.

Always remember: only completely independent tasks can be parallelized effectively!

A good strategy for multithreading involves carefully considering the task to parallelize: how small can the chunks be? For an image, a chunk could be a pixel or a line, but often those are too small to overcome the overhead of parallelization.

Despite the simple example below, the multithreader framework function allows variable amount of arguments to be passed, as illustrated in the complete plugin Multithreaded_Image_Processing_in_Javascript.js. The script shows how to generate an image with random pixel values in a multithreaded manner, and how the choice of chunks to process in parallel is made for reasonable effectiveness.

// Now, abstract away the multithreading framework into a function
// that takes another function as argument:

function multithreader(fun, start, end) {
        var threads = new java.lang.reflect.Array.newInstance(java.lang.Thread, Runtime.getRuntime().availableProcessors());
        var ai = new AtomicInteger(start);
        // Prepare arguments: all other arguments passed to this function
        // beyond the mandatory arguments fun, start and end:
        var args = new Array();
        var b = 0;
        IJ.log("Multithreading function \"" + fun.name + "\" with arguments:\n  argument 0 is index from " + start + " to " + end);
        for (var a = 3; a < arguments.length; a++) {
                args[b] = arguments[a];
                IJ.log("  argument " + (b+1) + " is " + args[b]);
        var body = {
                run: function() {
                        for (var i = ai.getAndIncrement(); i <= end; i = ai.getAndIncrement()) {
                                // Execute the function given as argument,
                                // passing to it all optional arguments:
                                fun(i, args);
                                Thread.sleep(100); // NOT NEEDED, just to pretend we are doing something!
        // start all threads
        for (var i = 0; i < threads.length; i++) {
                threads[i] = new Thread(new Runnable(body)); // automatically as Runnable
        // wait until all threads finish
        for (var i = 0; i < threads.length; i++) {

// The actual desired effect: the printer
function printer(i) {
        IJ.log("i is " + i);
 // Execute:
 multithreader(printer, 0, 10);

See the complete file here: Multithreaded_Image_Processing_in_Javascript.js


See also the Scripting comparisons.