Difference between revisions of "Introduction into Macro Programming"

(Add categories scripting and tutorials to macro programming)
(Syntax-highlight code (pretending that macros are Java because the syntax is so similar))
Line 19: Line 19:
 
A variable can be assigned like this:
 
A variable can be assigned like this:
  
factor = 1024;
+
<source lang="java">
 +
factor = 1024;
 +
</source>
  
 
In this example, ''factor'' is the name of the variable, ''1024'' is the value assigned to the variable. The semicolon tells ImageJ that the assignment is done.
 
In this example, ''factor'' is the name of the variable, ''1024'' is the value assigned to the variable. The semicolon tells ImageJ that the assignment is done.
Line 25: Line 27:
 
Example: assign text to a variable:
 
Example: assign text to a variable:
  
message = "Hello, World!";
+
<source lang="java">
 +
message = "Hello, World!";
 +
</source>
  
 
In this case, the variable is named ''message'', and the text ''Hello, World!'' is assigned to it; Text is specified inside double quotes.
 
In this case, the variable is named ''message'', and the text ''Hello, World!'' is assigned to it; Text is specified inside double quotes.
Line 33: Line 37:
 
You can use variables in ''expressions'': you can calculate with numeric variables, and you can concatenate text and text variables. Example:
 
You can use variables in ''expressions'': you can calculate with numeric variables, and you can concatenate text and text variables. Example:
  
x = 2;
+
<source lang="java">
y = 3;
+
x = 2;
result = x * x + y + y;
+
y = 3;
 +
result = x * x + y + y;
 +
</source>
  
 
This assigns the variable ''x'' the value 2, the variable ''y'' the value 3, and then assigns the variable ''result'' the square of ''x'' plus the square of ''y''.
 
This assigns the variable ''x'' the value 2, the variable ''y'' the value 3, and then assigns the variable ''result'' the square of ''x'' plus the square of ''y''.
Line 41: Line 47:
 
This example shows how to concatenate a fixed text with the value of a variable:
 
This example shows how to concatenate a fixed text with the value of a variable:
  
name = "Bob";
+
<source lang="java">
msg = "Those days are over, " + name;
+
name = "Bob";
 +
msg = "Those days are over, " + name;
 +
</source>
  
 
'''Note:''' a common pitfall is to include the name of a variable in a string. The following code demonstrates this:
 
'''Note:''' a common pitfall is to include the name of a variable in a string. The following code demonstrates this:
  
title = "Macro";
+
<source lang="java">
write("The name: title"); // this is wrong
+
title = "Macro";
write("The name: " + title); // this is right
+
write("The name: title"); // this is wrong
 +
write("The name: " + title); // this is right
 +
</source>
  
 
In the first ''write'' call, a literal ''title'' will be printed instead of the value of the variable of that name.
 
In the first ''write'' call, a literal ''title'' will be printed instead of the value of the variable of that name.
Line 54: Line 64:
 
It is especially important to keep this in mind when calling plugins:
 
It is especially important to keep this in mind when calling plugins:
  
r = 2; // the radius
+
<source lang="java">
run("Gaussian Blur...", "radius=r"); // this is wrong, r will not be evaluated
+
r = 2; // the radius
run("Gausian Blur...", "radius=" + r); // this is correct
+
run("Gaussian Blur...", "radius=r"); // this is wrong, r will not be evaluated
 +
run("Gausian Blur...", "radius=" + r); // this is correct
 +
</source>
  
 
== Self-referencing assignments ==
 
== Self-referencing assignments ==
Line 62: Line 74:
 
When a variable is assigned, the right-hand side is evaluated first, and only then the assignment is performed. This allows you to double the value of a variable:
 
When a variable is assigned, the right-hand side is evaluated first, and only then the assignment is performed. This allows you to double the value of a variable:
  
amount = amount * 2;
+
<source lang="java">
 +
amount = amount * 2;
 +
</source>
  
 
First, ''amount * 2'' is evaluated. The result is then assigned back to the variable ''amount'', effectively doubling  it.
 
First, ''amount * 2'' is evaluated. The result is then assigned back to the variable ''amount'', effectively doubling  it.
Line 68: Line 82:
 
A very important operation is to increment a variable's value by one:
 
A very important operation is to increment a variable's value by one:
  
counter = counter + 1;
+
<source lang="java">
 +
counter = counter + 1;
 +
</source>
  
 
It is so important that there is a short form for it:
 
It is so important that there is a short form for it:
  
// This statement does the same as counter = counter + 1;
+
<source lang="java">
counter++;
+
// This statement does the same as counter = counter + 1;
 +
counter++;
 +
</source>
  
 
= Functions =
 
= Functions =
Line 81: Line 99:
 
This example writes ''Hello, World!'' to the ''Log'' window:
 
This example writes ''Hello, World!'' to the ''Log'' window:
  
write("Hello, World!");
+
<source lang="java">
 +
write("Hello, World!");
 +
</source>
  
 
As before, a semicolon signifies the end of the statement. The name of the function is ''write'', and the parameter list is enclosed in parentheses. In the case of ''write'', there is only one parameter. If there are more parameters to be passed, they have to be separated by commas:
 
As before, a semicolon signifies the end of the statement. The name of the function is ''write'', and the parameter list is enclosed in parentheses. In the case of ''write'', there is only one parameter. If there are more parameters to be passed, they have to be separated by commas:
  
newImage("My pretty new image", "8-bit black", 640, 480, 1);
+
<source lang="java">
 +
newImage("My pretty new image", "8-bit black", 640, 480, 1);
 +
</source>
  
 
Like ''write'', ''newImage'' is a builtin function of ImageJ. The order of the parameters is relevant, this is the way the function knows what each parameter means.
 
Like ''write'', ''newImage'' is a builtin function of ImageJ. The order of the parameters is relevant, this is the way the function knows what each parameter means.
Line 93: Line 115:
 
For recurring tasks, you can define your own functions:
 
For recurring tasks, you can define your own functions:
  
function closeImageByTitle(title) {
+
<source lang="java">
        selectWindow(title);
+
function closeImageByTitle(title) {
        close();
+
        selectWindow(title);
}
+
        close();
 +
}
 +
</source>
  
 
Note that the ''title'' is just another [[#Variables|variable]], which is implicitly assigned when the function is called. In other words, this call will execute the code in above definition, with the variable ''title'' set to ''My pretty new image'':
 
Note that the ''title'' is just another [[#Variables|variable]], which is implicitly assigned when the function is called. In other words, this call will execute the code in above definition, with the variable ''title'' set to ''My pretty new image'':
  
closeImageByTitle("My pretty new image");
+
<source lang="java">
 +
closeImageByTitle("My pretty new image");
 +
</source>
  
 
= Comments =
 
= Comments =
Line 106: Line 132:
 
When you read your code again in six months from now, you want to understand what your code does, and why. For this, you can add comments, i.e. text which is ignored by ImageJ when it executes the macro. Example:
 
When you read your code again in six months from now, you want to understand what your code does, and why. For this, you can add comments, i.e. text which is ignored by ImageJ when it executes the macro. Example:
  
// This variable contains the radius of the circle to be drawn
+
<source lang="java">
r = 15;
+
// This variable contains the radius of the circle to be drawn
 +
r = 15;
 +
</source>
  
 
Everything after the two slashes up to the end of the line is a comment.
 
Everything after the two slashes up to the end of the line is a comment.
Line 115: Line 143:
 
You can also have multi-line comments enclosed in ''/* ... */'' blocks:
 
You can also have multi-line comments enclosed in ''/* ... */'' blocks:
  
/*
+
<source lang="java">
  It turned out in practice that 0.5 is a good choice for alpha, because
+
/*
  it leads to fewer artifacts than anything larger, and it is large enough
+
It turned out in practice that 0.5 is a good choice for alpha, because
  to guarantee a quick convergence.
+
it leads to fewer artifacts than anything larger, and it is large enough
*/
+
to guarantee a quick convergence.
alpha = 0.5;
+
*/
 +
alpha = 0.5;
 +
</source>
  
 
== Commented-out code ==
 
== Commented-out code ==
Line 126: Line 156:
 
When reading macros written by other people, you will often find the concept of ''commented-out code''. This is code that is pretended to be a comment so that it is not executed. Example:
 
When reading macros written by other people, you will often find the concept of ''commented-out code''. This is code that is pretended to be a comment so that it is not executed. Example:
  
a = 0.5;
+
<source lang="java">
// write("value of a: " + a);
+
a = 0.5;
run("Gaussian Blur...", "radius=" + a);
+
// write("value of a: " + a);
 +
run("Gaussian Blur...", "radius=" + a);
 +
</source>
  
 
Typical uses for commented-out code are instructions that help with debugging, but are too verbose (or too slow) for regular execution of the macro.
 
Typical uses for commented-out code are instructions that help with debugging, but are too verbose (or too slow) for regular execution of the macro.
Line 136: Line 168:
 
Sometimes, you need to execute a certain part of the code if and only if a certain condition is met. Example:
 
Sometimes, you need to execute a certain part of the code if and only if a certain condition is met. Example:
  
// If the image is not binary, abort
+
<source lang="java">
if (!is(“binary”)) {
+
// If the image is not binary, abort
exit(“You need a binary image for this macro!”);
+
if (!is(“binary”)) {
}
+
exit(“You need a binary image for this macro!”);
 +
}
 +
</source>
  
 
There are several parts to a conditional block: the ''if'' keyword, the condition inside the parentheses, and the code block enclosed in curly braces.
 
There are several parts to a conditional block: the ''if'' keyword, the condition inside the parentheses, and the code block enclosed in curly braces.
Line 153: Line 187:
 
You can optionally add an ''else'' clause, i.e. a code block that is executed when the condition is <b>not</b> met. Example:
 
You can optionally add an ''else'' clause, i.e. a code block that is executed when the condition is <b>not</b> met. Example:
  
if (is("binary")) {
+
<source lang="java">
        write("The current image is binary");
+
if (is("binary")) {
}
+
        write("The current image is binary");
else {
+
}
        write("The current image is not binary");
+
else {
}
+
        write("The current image is not binary");
 +
}
 +
</source>
  
 
= Loops =
 
= Loops =
Line 164: Line 200:
 
To repeat instructions several times, loops are used. Example:
 
To repeat instructions several times, loops are used. Example:
  
for (i = 0; i < 10; i++) {
+
<source lang="java">
        run("Dilate");
+
for (i = 0; i < 10; i++) {
}
+
        run("Dilate");
 +
}
 +
</source>
  
 
This code will run ''Dilate'' ten times. The syntax of the ''for'' loop consists of the ''for'' keyword, followed by three statements enclosed in parentheses, and the code block to be executed.
 
This code will run ''Dilate'' ten times. The syntax of the ''for'' loop consists of the ''for'' keyword, followed by three statements enclosed in parentheses, and the code block to be executed.
Line 190: Line 228:
 
In some cases, you might need to edit the recorded macro to make it usable with other images than the one you used to record the macro with. Example: when you merge channels, you end up with a statement like this:
 
In some cases, you might need to edit the recorded macro to make it usable with other images than the one you used to record the macro with. Example: when you merge channels, you end up with a statement like this:
  
run("Merge Channels...",
+
<source lang="java">
    "red=[Edges of boats.gif] green=boats.gif blue=boats.gif gray=*None*");
+
run("Merge Channels...",
 +
    "red=[Edges of boats.gif] green=boats.gif blue=boats.gif gray=*None*");
 +
</source>
  
 
The parameters passed to ''Merge Channels...'' depend very much on the current image's name. One possible solution looks like this:
 
The parameters passed to ''Merge Channels...'' depend very much on the current image's name. One possible solution looks like this:
  
title = getTitle();
+
<source lang="java">
run("Merge Channels...",
+
title = getTitle();
 +
run("Merge Channels...",
 
     "red=[Edges of " + title + "] green=" + title + " blue=" + title + " gray=*None*");
 
     "red=[Edges of " + title + "] green=" + title + " blue=" + title + " gray=*None*");
 +
</source>
  
 
Note that we need to use string concatenation in order to insert the current image's name in place of ''boats.gif'', as described in [[#Using_variables|above]].
 
Note that we need to use string concatenation in order to insert the current image's name in place of ''boats.gif'', as described in [[#Using_variables|above]].
Line 203: Line 245:
 
In order to allow spaces in the name, you might also want to add extra ''[...]'' around the title:
 
In order to allow spaces in the name, you might also want to add extra ''[...]'' around the title:
  
title = getTitle();
+
<source lang="java">
run("Merge Channels...",
+
title = getTitle();
 +
run("Merge Channels...",
 
     "red=[Edges of " + title + "] green=[" + title + "] blue=[" + title + "] gray=*None*");
 
     "red=[Edges of " + title + "] green=[" + title + "] blue=[" + title + "] gray=*None*");
 +
</source>
  
 
= Installing macros =
 
= Installing macros =
Line 211: Line 255:
 
To install keyboard shortcuts or tool icons, you need to [http://rsb.info.nih.gov/ij/developer/macro/macros.html#tools wrap macro code in ''macro'' blocks]:
 
To install keyboard shortcuts or tool icons, you need to [http://rsb.info.nih.gov/ij/developer/macro/macros.html#tools wrap macro code in ''macro'' blocks]:
  
macro "Title of the macro" {
+
<source lang="java">
        write("Hello, world!");
+
macro "Title of the macro" {
}
+
      write("Hello, world!");
 +
}
 +
</source>
  
 
Then you need to ''install'' them:
 
Then you need to ''install'' them:
Line 223: Line 269:
 
Keyboard shortcuts can be defined by adding the key within brackets at the end of the macro name. Example:
 
Keyboard shortcuts can be defined by adding the key within brackets at the end of the macro name. Example:
  
// install a keyboard shortcut: when pressing Ctrl+J,
+
<source lang="java">
// the user is asked for JPEG quality and for a location
+
// install a keyboard shortcut: when pressing Ctrl+J,
// to save the current image as .jpg file
+
// the user is asked for JPEG quality and for a location
+
// to save the current image as .jpg file
macro "Save As JPEG... [j]" {
+
 
quality = call("ij.plugin.JpegWriter.getQuality");
+
macro "Save As JPEG... [j]" {
quality = getNumber("JPEG quality (0-100):", quality);
+
quality = call("ij.plugin.JpegWriter.getQuality");
run("Input/Output...", "jpeg="+quality);
+
quality = getNumber("JPEG quality (0-100):", quality);
saveAs("Jpeg");
+
run("Input/Output...", "jpeg="+quality);
}
+
saveAs("Jpeg");
 +
}
 +
</source>
  
 
== Tool icons ==
 
== Tool icons ==
Line 238: Line 286:
 
By choosing a macro name that ends in ''Action Tool'', you can install new tools into the toolbar:
 
By choosing a macro name that ends in ''Action Tool'', you can install new tools into the toolbar:
  
// A click on the empty rectangle will have the same
+
<source lang="java">
// effect as File>Save As>Jpeg...
+
// A click on the empty rectangle will have the same
+
// effect as File>Save As>Jpeg...
macro "Save As JPEG Action Tool - C000R11ee" {
+
 
saveAs("Jpeg");
+
macro "Save As JPEG Action Tool - C000R11ee" {
}
+
saveAs("Jpeg");
 +
}
 +
</source>
  
 
The icon is defined by a funny-looking string (in this case, ''C000R11ee''). To learn how to define your own icon, please have a look [http://rsb.info.nih.gov/ij/developer/macro/macros.html#icons here].
 
The icon is defined by a funny-looking string (in this case, ''C000R11ee''). To learn how to define your own icon, please have a look [http://rsb.info.nih.gov/ij/developer/macro/macros.html#icons here].
Line 249: Line 299:
 
Many tools open an option dialog upon double-click on the icon. You can do that, too, by choosing a name that ends in ''Action Tool Options'':
 
Many tools open an option dialog upon double-click on the icon. You can do that, too, by choosing a name that ends in ''Action Tool Options'':
  
// A right-click on the tool icon lets the user change
+
<source lang="java">
// the JPEG Quality
+
// A right-click on the tool icon lets the user change
+
// the JPEG Quality
macro "Save As JPEG Action Tool Options" {
+
 
quality = call("ij.plugin.JpegWriter.getQuality");
+
macro "Save As JPEG Action Tool Options" {
quality = getNumber("JPEG quality (0-100):", quality);
+
quality = call("ij.plugin.JpegWriter.getQuality");
run("Input/Output...", "jpeg="+quality);
+
quality = getNumber("JPEG quality (0-100):", quality);
}
+
run("Input/Output...", "jpeg="+quality);
 +
}
 +
</source>
  
 
= Further documentation =
 
= Further documentation =

Revision as of 07:55, 6 May 2011

Why Macros?

Macros can be used to

  • automate repetitive tasks
  • document what you did
  • share common procedures
  • add tools to the toolbar
  • add keyboard shortcuts

Variables

The most important concept when starting to program macros are variables. A variable is a placeholder for a changing entity. It has a name and a value, which can be numeric or text (so-called strings).

Variables are needed whenever you want to execute the same code several times, but for different images, parameters, etc

Variables can also be used to store user input obtained through a dialog.

A variable can be assigned like this:

factor = 1024;

In this example, factor is the name of the variable, 1024 is the value assigned to the variable. The semicolon tells ImageJ that the assignment is done.

Example: assign text to a variable:

message = "Hello, World!";

In this case, the variable is named message, and the text Hello, World! is assigned to it; Text is specified inside double quotes.

Using variables

You can use variables in expressions: you can calculate with numeric variables, and you can concatenate text and text variables. Example:

x = 2;
y = 3;
result = x * x + y + y;

This assigns the variable x the value 2, the variable y the value 3, and then assigns the variable result the square of x plus the square of y.

This example shows how to concatenate a fixed text with the value of a variable:

name = "Bob";
msg = "Those days are over, " + name;

Note: a common pitfall is to include the name of a variable in a string. The following code demonstrates this:

title = "Macro";
write("The name: title"); // this is wrong
write("The name: " + title); // this is right

In the first write call, a literal title will be printed instead of the value of the variable of that name.

It is especially important to keep this in mind when calling plugins:

r = 2; // the radius
run("Gaussian Blur...", "radius=r"); // this is wrong, r will not be evaluated
run("Gausian Blur...", "radius=" + r); // this is correct

Self-referencing assignments

When a variable is assigned, the right-hand side is evaluated first, and only then the assignment is performed. This allows you to double the value of a variable:

amount = amount * 2;

First, amount * 2 is evaluated. The result is then assigned back to the variable amount, effectively doubling it.

A very important operation is to increment a variable's value by one:

counter = counter + 1;

It is so important that there is a short form for it:

// This statement does the same as counter = counter + 1;
counter++;

Functions

Most of the time, you will call functions which implement the actions you want to execute. Functions have names, like variables, but they also have parameters that you can pass to the functions. ImageJ comes with many predefined functions that you can call to perform specific calculations or other operations.

This example writes Hello, World! to the Log window:

write("Hello, World!");

As before, a semicolon signifies the end of the statement. The name of the function is write, and the parameter list is enclosed in parentheses. In the case of write, there is only one parameter. If there are more parameters to be passed, they have to be separated by commas:

newImage("My pretty new image", "8-bit black", 640, 480, 1);

Like write, newImage is a builtin function of ImageJ. The order of the parameters is relevant, this is the way the function knows what each parameter means.

Defining functions

For recurring tasks, you can define your own functions:

function closeImageByTitle(title) {
        selectWindow(title);
        close();
}

Note that the title is just another variable, which is implicitly assigned when the function is called. In other words, this call will execute the code in above definition, with the variable title set to My pretty new image:

closeImageByTitle("My pretty new image");

Comments

When you read your code again in six months from now, you want to understand what your code does, and why. For this, you can add comments, i.e. text which is ignored by ImageJ when it executes the macro. Example:

// This variable contains the radius of the circle to be drawn
r = 15;

Everything after the two slashes up to the end of the line is a comment.

Multi-line comments

You can also have multi-line comments enclosed in /* ... */ blocks:

/*
 It turned out in practice that 0.5 is a good choice for alpha, because
 it leads to fewer artifacts than anything larger, and it is large enough
 to guarantee a quick convergence.
*/
alpha = 0.5;

Commented-out code

When reading macros written by other people, you will often find the concept of commented-out code. This is code that is pretended to be a comment so that it is not executed. Example:

a = 0.5;
// write("value of a: " + a);
run("Gaussian Blur...", "radius=" + a);

Typical uses for commented-out code are instructions that help with debugging, but are too verbose (or too slow) for regular execution of the macro.

Conditional code blocks

Sometimes, you need to execute a certain part of the code if and only if a certain condition is met. Example:

// If the image is not binary, abort
if (!is(“binary”)) {
	exit(“You need a binary image for this macro!”);
}

There are several parts to a conditional block: the if keyword, the condition inside the parentheses, and the code block enclosed in curly braces.

In this case, the condition calls the function is to ask whether the current image is binary, and the exclamation mark negates the result, i.e. !is("binary") yields true if and only if the current image is not binary (as opposed to is("binary"), which returns true in the opposite case).

If the code block consists of only one statement, the curly braces may be omitted, but it is a good practice to keep them (for example, nested conditional blocks are much easier to understand with curly braces than without).

Likewise, it is a good practice to indent the code inside the conditional block (i.e. to add white space in front of the lines inside the block). This makes reading the code much easier, too.

else

You can optionally add an else clause, i.e. a code block that is executed when the condition is not met. Example:

if (is("binary")) {
        write("The current image is binary");
}
else {
        write("The current image is not binary");
}

Loops

To repeat instructions several times, loops are used. Example:

for (i = 0; i < 10; i++) {
        run("Dilate");
}

This code will run Dilate ten times. The syntax of the for loop consists of the for keyword, followed by three statements enclosed in parentheses, and the code block to be executed.

The three statements defining how often to run the code block are the

  1. initializer: typically, a counter variable is initialized, in this case i to the value zero,
  2. the condition: as long as this condition is met (here i < 10), the code block is executed,
  3. the incrementor: this statement is executed after the code block, just before testing again whether the block should be executed again.

In this example, the variable i is first initialized to zero, then the condition is checked, and as i is smaller than 10, the code block is executed. After that, i is incremented, and the condition is checked again. As 1 is still smaller than 10, the code block is executed again. This repeats for the values 2, 3, ..., 9, but after the variable i was incremented from 9 to 10, the condition does not hold true anymore, so the loop is finished.

Even if the counter variable was not used inside the code block in this example, you are free to do so, of course.

Note that starting with 0 and testing for the condition "smaller than 10" will result in the code block being run 10 times. It is the standard way to execute a certain block of code a fixed number of times.

The recorder

Typically, macros are not written from scratch, but recorded using the Macro Recorder: Just click on Plugins>Macros>Record... and perform some actions. These actions will be recorded in the recorder window, and you can hit the Create button to open the recorded instructions in an editor:

Macro recorder.png

In some cases, you might need to edit the recorded macro to make it usable with other images than the one you used to record the macro with. Example: when you merge channels, you end up with a statement like this:

run("Merge Channels...",
    "red=[Edges of boats.gif] green=boats.gif blue=boats.gif gray=*None*");

The parameters passed to Merge Channels... depend very much on the current image's name. One possible solution looks like this:

title = getTitle();
run("Merge Channels...",
     "red=[Edges of " + title + "] green=" + title + " blue=" + title + " gray=*None*");

Note that we need to use string concatenation in order to insert the current image's name in place of boats.gif, as described in above.

In order to allow spaces in the name, you might also want to add extra [...] around the title:

title = getTitle();
run("Merge Channels...",
     "red=[Edges of " + title + "] green=[" + title + "] blue=[" + title + "] gray=*None*");

Installing macros

To install keyboard shortcuts or tool icons, you need to wrap macro code in macro blocks:

macro "Title of the macro" {
       write("Hello, world!");
}

Then you need to install them:

Install Macros.png

Keyboard shortcuts

Keyboard shortcuts can be defined by adding the key within brackets at the end of the macro name. Example:

// install a keyboard shortcut: when pressing Ctrl+J,
// the user is asked for JPEG quality and for a location
// to save the current image as .jpg file

macro "Save As JPEG... [j]" {
	quality = call("ij.plugin.JpegWriter.getQuality");
	quality = getNumber("JPEG quality (0-100):", quality);
	run("Input/Output...", "jpeg="+quality);
	saveAs("Jpeg");
}

Tool icons

By choosing a macro name that ends in Action Tool, you can install new tools into the toolbar:

// A click on the empty rectangle will have the same
// effect as File>Save As>Jpeg...

macro "Save As JPEG Action Tool - C000R11ee" {
	saveAs("Jpeg");
}

The icon is defined by a funny-looking string (in this case, C000R11ee). To learn how to define your own icon, please have a look here.

Many tools open an option dialog upon double-click on the icon. You can do that, too, by choosing a name that ends in Action Tool Options:

// A right-click on the tool icon lets the user change
// the JPEG Quality

macro "Save As JPEG Action Tool Options" {
	quality = call("ij.plugin.JpegWriter.getQuality");
	quality = getNumber("JPEG quality (0-100):", quality);
	run("Input/Output...", "jpeg="+quality);
}

Further documentation

A complete description of the macro language, a reference of the built-in functions, and examples can be found here.