package ij.plugin;
import ij.*;
import ij.gui.GenericDialog;
import ij.process.ImageProcessor;
import ij.process.LUT;
import java.util.ArrayList;
import java.util.List;
import java.awt.Color;
public class SubHyperstackMaker implements PlugIn {
public void run(final String arg) {
final ImagePlus input = WindowManager.getCurrentImage();
if (input == null) {
IJ.showMessage("No image open.");
return;
}
if (input.getStackSize() == 1) {
IJ.showMessage("Image is not a stack.");
return;
}
final int cCount = input.getNChannels();
final int zCount = input.getNSlices();
final int tCount = input.getNFrames();
final boolean hasC = cCount > 1;
final boolean hasZ = zCount > 1;
final boolean hasT = tCount > 1;
final GenericDialog gd = new GenericDialog("Subhyperstack Maker");
gd.addMessage("Enter a range (e.g. 2-14), a range with increment\n"
+ "(e.g. 1-100-2) or a list (e.g. 7,9,25,27)", null, Color.darkGray);
if (hasC) gd.addStringField("Channels:", "1-" + cCount, 40);
if (hasZ) gd.addStringField("Slices:", "1-" + zCount, 40);
if (hasT) gd.addStringField("Frames:", "1-" + tCount, 40);
gd.showDialog();
if (gd.wasCanceled()) return;
final String cString = hasC ? gd.getNextString() : "1";
final String zString = hasZ ? gd.getNextString() : "1";
final String tString = hasT ? gd.getNextString() : "1";
final ImagePlus output =
makeSubhyperstack(input, cString, zString, tString);
output.show();
}
public static ImagePlus makeSubhyperstack(final ImagePlus input,
final String cString, final String zString, final String tString)
{
final ArrayList<Integer> cList = parseList(cString, input.getNChannels());
final ArrayList<Integer> zList = parseList(zString, input.getNSlices());
final ArrayList<Integer> tList = parseList(tString, input.getNFrames());
return makeSubhyperstack(input, cList, zList, tList);
}
public static ImagePlus makeSubhyperstack(final ImagePlus input,
final List<Integer> cList, final List<Integer> zList,
final List<Integer> tList)
{
if (cList.size() == 0) {
throw new IllegalArgumentException("Must specify at least one channel");
}
if (zList.size() == 0) {
throw new IllegalArgumentException("Must specify at least one slice");
}
if (tList.size() == 0) {
throw new IllegalArgumentException("Must specify at least one frame");
}
final ImageStack inputStack = input.getImageStack();
final int cCount = input.getNChannels();
final int zCount = input.getNSlices();
final int tCount = input.getNFrames();
for (final int c : cList)
check("C", c, cCount);
for (final int z : zList)
check("Z", z, zCount);
for (final int t : tList)
check("T", t, tCount);
final String title = WindowManager.getUniqueName(input.getTitle());
ImagePlus output =
input.createHyperStack(title, cList.size(), zList.size(), tList.size(),
input.getBitDepth());
final ImageStack outputStack = output.getImageStack();
int oc = 0, oz, ot;
for (final int c : cList) {
oc++;
oz = 0;
for (final int z : zList) {
oz++;
ot = 0;
for (final int t : tList) {
ot++;
final int i = input.getStackIndex(c, z, t);
final int oi = output.getStackIndex(oc, oz, ot);
final String label = inputStack.getSliceLabel(i);
final ImageProcessor ip = inputStack.getProcessor(i);
outputStack.setSliceLabel(label, oi);
outputStack.setPixels(ip.getPixels(), oi);
}
}
}
if (input instanceof CompositeImage) {
final CompositeImage compositeInput = (CompositeImage) input;
final CompositeImage compositeOutput =
new CompositeImage(output, compositeInput.getMode());
oc = 0;
for (final int c : cList) {
oc++;
final LUT table = compositeInput.getChannelLut(c);
compositeOutput.setChannelLut(table, oc);
compositeOutput.setPositionWithoutUpdate(oc, 1, 1);
compositeInput.setPositionWithoutUpdate(c, 1, 1);
final double min = compositeInput.getDisplayRangeMin();
final double max = compositeInput.getDisplayRangeMax();
compositeOutput.setDisplayRange(min, max);
}
output = compositeOutput;
}
return output;
}
private static void
check(final String name, final int index, final int count)
{
if (index < 1 || index > count) {
throw new IllegalArgumentException("Invalid " + name + " index: " +
index);
}
}
private static ArrayList<Integer> parseList(final String planeString,
int count)
{
final ArrayList<Integer> list = new ArrayList<Integer>();
for (final String token : planeString.split("\\s*,\\s*")) {
final int dash1 = token.indexOf("-");
final int dash2 = token.lastIndexOf("-");
if (dash1 < 0) {
final int index;
try {
index = Integer.parseInt(token);
}
catch (final NumberFormatException exc) {
throw new IllegalArgumentException("Invalid number: " + token);
}
if (index < 1 || index > count) {
throw new IllegalArgumentException("Invalid number: " + token);
}
list.add(Integer.parseInt(token));
}
else {
final int min, max, step;
try {
min = Integer.parseInt(token.substring(0, dash1));
if (dash1 == dash2) {
max = Integer.parseInt(token.substring(dash1 + 1));
step = 1;
}
else {
max = Integer.parseInt(token.substring(dash1 + 1, dash2));
step = Integer.parseInt(token.substring(dash2 + 1));
}
}
catch (final NumberFormatException exc) {
throw new IllegalArgumentException("Invalid range: " + token);
}
if (min < 1 || min > max || max > count || step < 1) {
throw new IllegalArgumentException("Invalid range: " + token);
}
for (int index = min; index <= max; index += step) {
list.add(index);
}
}
}
return list;
}
}