Language Summary

Structure of a Jiffle script

A script consists of the script body, optionally preceded by one or more special blocks which are used to declare variables and control runtime options. We’ll return to these blocks later (skip ahead to Special blocks if you can’t wait), but first let’s look at the general features of the language.

Comments

/*
 * C-style block comments
 * are supported
 * in jiffle
 */

// As are line comments

Variables

Types and variable declaration

Jiffle supports the following types of variables:

Scalar
A single value. In Jiffle all scalar values correspond to Java type Double.
Array
A dynamically sized array of scalar values.
Image
A variables that stands for a source or destination image in a script.

Note

Support for multi-dimensional arrays is yet to be added.

Jiffle uses lazy declaration for scalar variables. In other words, you can just start using a variable name in the script body. In this snippet:

// The variable val required no prior declaration
val = max(0, image1 - image2);

In contrast, array variables must be declared before use so that Jiffle can distinguish them from scalars:

// declares an empty array
foo = [];

// declares an array with initial values
bar = [1, 2, 42];

Unlike languages such as Ruby, it is invalid to change the type type of a variable within a script:

// Create an array variable
foo = [1, 2, 3];

// Now if you try to use it as a scalar you will get a compile-time error
foo = 42;

// Creating a scalar variable bar, then attempting to do an array operation
// with it (<< is the append operator) will also make the compiler unhappy
bar = 42;
bar << 43; // error

Names

Variable names must begin with a letter, optionally followed by any combination of letters, digits, underscores and dots. Letters can be upper or lower case. Variable names are case-sensitive.

See also Reserved words

Scope

All scalar and list variables which first appear in the body of the script have pixel-scope: their values are discarded after each destination pixel is processed. Variables declared in the init block, when present, have image-scope: their values persist between pixels:

init {
    // An image-scope variable with an initial value
    foo = 0;
}

// A variable which first appears in the script body
// has pixel scope
bar = 0;

Operators

Arithmetic operators

Symbol Description
^ Raise to power
* Multiply
/ Divide
% Modulo (remainder)
+ Add
- Subtract
= Assignment
+= Additive assignment
-= Subtractive assignment
*= Multiplicative assignment
/= Divisive assignment
%= Modulo assignment

Logical operators

Symbol Description
&& logical AND
|| logical OR
^| logical XOR
== equality test
!= inequality test
> greater than
>= greater than or equal to
<= less than
< less than or equal to
! logical complement

Ternary expression

Example:

// set foo to 1 if bar > 10; otherwise 0
foo = bar > 10 ? 1 : 0;

See also Logical functions

Control flow

If-else statements

You can use the familiar if-else statement in a Jiffle script:

if (foo > 0) n++ ;

if (bar == 42) {
  result = 1;
} else {
  result = 0;
}

Loops

One of the features of Jiffle that makes for concise scripts is that you don’t need to write the code to loop through source and destination images because the runtime system does that for you. So many of your scripts will not need any loop statements. However, Jiffle does provide loop constructs which are useful when working with pixel neighbourhoods or performing iterative calculations.

foreach loop

Probably most of the times when you need to use a loop in a Jiffle script it will be a foreach loop. The general form is:

foreach (var in elements) target
where:

var is a scalar variable that will be set to each value of elements in turn;

elements is an array or sequence (see below);

target is a single statement or a block of code delimited by curly brackets.

This example iterates through a 3x3 pixel neighbourhood and counts the number of values that are greater than a threshold value. It uses sequence notation, which has the form lowValue:highValue. Each loop variable is set to -1, 0, 1 in turn. The loop variables are then used to access a relative pixel position in the source image (see Absolute pixel position):

// Iterate through pixels in a 3x3 neighbourhood
n = 0;
foreach (dy in -1:1) {
    foreach (dx in -1:1) {
        n += srcimage[dx, dy] > someValue;
    }
}

Here is the same example, but this time using the array form of the foreach loop:

// Iterate through pixels in a 3x3 neighbourhood
delta = [-1, 0, 1];
n = 0;
foreach (dy in delta) {
    foreach (dx in delta) {
        n += srcimage[dx, dy] > someValue;
    }
}

while loop

A conditional loop which executes the target statement or block while its conditional expression is non-zero:

ynbr = y() - 500;
total = 0;
while (ynbr <= y() + 500) {
    xnbr = x() - 500;
    while (xnbr <= x() + 500) {
        total += srcimage[$xnbr, $ynbr];
        xnbr += 100;
    }
    ynbr += 100;
}

until loop

A conditional loop which executes the target statement or block until its conditional expression is non-zero:

ynbr = y() - 500;
total = 0;
until (ynbr > y() + 500) {
    xnbr = x() - 500;
    until (xnbr > x() + 500) {
        total += srcimage[$xnbr, $ynbr];
        xnbr += 100;
    }
    ynbr += 100;
}

break and breakif statements

Jiffle provides the break statement to unconditionally exit a loop:

n = 0;
foreach (i in 1:10) {
    if (foo[i] != null) {
        n++ ;
    } else {
        break;
    }
}

There is also a breakif statement:

n = 0;
foreach (i in 1:10) {
    breakif(foo[i] == null);
    n++ ;
}

Functions

General numeric functions

Name Description Arguments Returns Notes
abs(x) Absolute value double value absolute value of x  
acos(x) Arc-cosine value in range [-1,1] angle in radians  
asin(x) Arc-sine value in range [-1,1] angle in radians  
atan(x) Arc-tangent value in range [-1,1] angle in radians  
cos(x) Cosine angle in radians cosine [-1, 1]  
degToRad(x) Degrees to radians angle in radians angle in degrees  
exp(x) Exponential double value e to the power x  
floor(x) Floor double value integer part of x as a double  
isinf(x) Is infinite double value 1 if x is positive or negative infinity; 0 otherwise  
isnan(x) Is NaN double value 1 if x is equal to Java’s Double.NaN; 0 otherwise  
isnull(x) Is null double value 1 if x is null; 0 otherwise Equivalent to isnan(x)
log(x) Natural logarithm positive value logarithm to base e  
log(x, b) General logarithm x: positive value; b: base logarithm to base b  
radToDeg(x) Radians to degrees angle in radians angle in degrees  
rand(x) Pseudo-random number double value value in range [0, x) Volatile function
randInt(x) Pseudo-random number double value integer part of value in range [0, x) Equivalent to floor(rand(x))
round(x) Round double value rounded value  
round(x, n) Round to multiple of n x: double value; n: whole number value rounded to nearest multiple of n E.g. round(44.5, 10) returns 40
sin(x) Sine angle in radians sine [-1, 1]  
sqrt(x) Square-root non-negative value square-root of x  
tan(x) Tangent angle in radians double value  

Logical functions

Name Description Arguments Returns
con(x) Conditional double value 1 if x is non-zero; 0 otherwise
con(x, a) Conditional double values a if x is non-zero; 0 otherwise
con(x, a, b) Conditional double values a if x is non-zero; b otherwise
con(x, a, b, c) Conditional double values a if x is positive; b if x is zero; c if x is negative

Statistical functions

Name Description Arguments Returns
max(x, y) Maximum double values maximum of x and y
max(ar) Maximum array maximum of array values
mean(ar) Mean array mean of array values
min(x, y) Minimum double values minimum of x and y
min(ar) Minimum array minimum of array values
median(ar) Median array median of array values
mode(ar) Mode array mode of array values
range(ar) Range array range of array values
sdev(ar) Standard deviation array sample standard deviation of array values
sum(ar) Sum array sum of array values
variance(ar) Variance array sample variance of array values

Processing area functions

Name Returns
height() Height of the processing area (world units)
width() Width of the processing area (world units)
xmin() Minimum X ordinate of the processing area (world units)
ymin() Minimum Y ordinate of the processing area (world units)
xmax() Maximum X ordinate of the processing area (world units)
ymax() Maximum Y ordinate of the processing area (world units)
x() X ordinate of the current processing position (world units)
y() Y ordinate of the current processing position (world units)
xres() Pixel width (world units)
yres() Pixel height (world units)

Special blocks

The options block

Used to set options for Jiffle’s runtime behaviour. Presently, only the outside option is supported.

For example, this tells Jiffle to return a value of 0 for any pixel value request that falls outside the bounds of the source image:

options {
    outside = 0;
}

The following script retrieves the maximum value in a 3x3 kernel centred on each source image and writes it to the destination image. It uses the outside option to treat kernel locations beyond the source image’s edge as null values which will be ignored by the max function:

// This script implements a max filter with a 3x3
// neighbourhood (kernel)

// Set option to treat locations outside the source image
// area as null values
options { outside = null; }

foreach (dy in -1:1) {
  foreach (dx in -1:1) {
      values << src[dx, dy];
  }
}

dest = max(values);

If the outside option is not set, any request for a value beyond an image’s bounds will cause a JiffleRuntimeException.

The images block

Used to associate variables with source (read-only) and destination (write-only) images. Example:

images {
    foo = read;
    bar = read;
    result = write;
}

As shown in the above snippet, the block contains declarations of the form name = (read | write). If this block is provided, the Jiffle compiler expects that it contains declarations for all image variables used in the script. It not provided, variable names can be defined as representing source or destination images using methods provided by the Jiffle and JiffleBuilder classes. These methods are described further in The Jiffle run-time system.

The init block

This block declares variables that will have image scope during processing (as discussed in Scope).

Each variable can optionally be assigned an intial value as foo is here:

init {
    foo = 42;
    bar;
}

If an initial value is not provided, one must be injected at run-time. See XXXX for more details.

Specifying source image position

Pixel position and image band are specified using square bracket notation.

Absolute pixel position

Absolute positions are specified using a $ prefix (similar to the syntax used in some spreadsheet programs):

// Example: access the value at x=50 y=42
value = srcimage[ $50, $42 ];

Variables and expressions can also appear in the brackets:

value = srcimage[ $xpos, $(min(width() - 1, y() + 10)) ];

Relative pixel position

When values are not prefixed they are treated as offsets, relative to the current processing position:

// Example: access the value at x+2, y-1
value = srcimage[ 2, -1 ];

As with absolute positions, variables and expressions can also be used:

value = srcimage[ dx, dy ];

Specifying the band

The image band is specified as a single value, variable or expression in square brackets. It is always treated as an absolute specifier:

// Get value from band 2 at the current processing position
value = srcimage[ 2 ];

As with pixel position, the band can be specified using a variable or an expression.

Specifying both pixel and band

When specifying both band and pixel position, the band comes first:

// Get the value for band 1, pixel position x=50, y=42
value = srcimage[ 1 ][ $50, $42 ]

// Get the value for band 1 at offset dx=-1, dy=3
value = srcimage[ 1 ][ -1, 3 ]

Reserved words

The following are reserved words in Jiffle and may not be used as variable names:

  • booleana
  • break
  • breakif
  • con
  • doublea
  • else
  • false
  • floata
  • foreach
  • if
  • images
  • in
  • init
  • inta
  • null
  • options
  • read
  • true
  • until
  • while
  • write

a reserved for future use