Menus.WINDOW_MENU_ITEMS && !(IJ.macroRunning()&&WindowManager.getImageCount()==0)) {
+ GenericDialog gd = new GenericDialog("ImageJ", this);
+ gd.addMessage("Are you sure you want to quit ImageJ?");
+ gd.showDialog();
+ quitting = !gd.wasCanceled();
+ windowClosed = false;
+ }
+ if (!quitting)
+ return;
+ if (!WindowManager.closeAllWindows()) {
+ quitting = false;
+ return;
+ }
+ if (applet==null) {
+ saveWindowLocations();
+ Prefs.set(ImageWindow.LOC_KEY,null); // don't save image window location
+ Prefs.savePreferences();
+ }
+ IJ.cleanup();
+ dispose();
+ if (exitWhenQuitting)
+ System.exit(0);
+ }
+
+ void saveWindowLocations() {
+ Window win = WindowManager.getWindow("B&C");
+ if (win!=null)
+ Prefs.saveLocation(ContrastAdjuster.LOC_KEY, win.getLocation());
+ win = WindowManager.getWindow("Threshold");
+ if (win!=null)
+ Prefs.saveLocation(ThresholdAdjuster.LOC_KEY, win.getLocation());
+ win = WindowManager.getWindow("Results");
+ if (win!=null) {
+ Prefs.saveLocation(TextWindow.LOC_KEY, win.getLocation());
+ Dimension d = win.getSize();
+ Prefs.set(TextWindow.WIDTH_KEY, d.width);
+ Prefs.set(TextWindow.HEIGHT_KEY, d.height);
+ }
+ win = WindowManager.getWindow("Log");
+ if (win!=null) {
+ Prefs.saveLocation(TextWindow.LOG_LOC_KEY, win.getLocation());
+ Dimension d = win.getSize();
+ Prefs.set(TextWindow.LOG_WIDTH_KEY, d.width);
+ Prefs.set(TextWindow.LOG_HEIGHT_KEY, d.height);
+ }
+ win = WindowManager.getWindow("ROI Manager");
+ if (win!=null)
+ Prefs.saveLocation(RoiManager.LOC_KEY, win.getLocation());
+ }
+
+ public static String getCommandName() {
+ return commandName!=null?commandName:"null";
+ }
+
+ public static void setCommandName(String name) {
+ commandName = name;
+ }
+
+ public void resize() {
+ double scale = Prefs.getGuiScale();
+ toolbar.init();
+ statusLine.setFont(new Font("SansSerif", Font.PLAIN, (int)(13*scale)));
+ progressBar.init((int)(ProgressBar.WIDTH*scale), (int)(ProgressBar.HEIGHT*scale));
+ pack();
+ }
+
+ /** Handles exceptions on the EDT. */
+ public static class ExceptionHandler implements Thread.UncaughtExceptionHandler {
+
+ // for EDT exceptions
+ public void handle(Throwable thrown) {
+ handleException(Thread.currentThread().getName(), thrown);
+ }
+
+ // for other uncaught exceptions
+ public void uncaughtException(Thread thread, Throwable thrown) {
+ handleException(thread.getName(), thrown);
+ }
+
+ protected void handleException(String tname, Throwable e) {
+ if (Macro.MACRO_CANCELED.equals(e.getMessage()))
+ return;
+ CharArrayWriter caw = new CharArrayWriter();
+ PrintWriter pw = new PrintWriter(caw);
+ e.printStackTrace(pw);
+ String s = caw.toString();
+ if (s!=null && s.contains("ij.")) {
+ if (IJ.getInstance()!=null)
+ s = IJ.getInstance().getInfo()+"\n"+s;
+ IJ.log(s);
+ }
+ }
+
+ } // inner class ExceptionHandler
+
+}
diff --git a/mrj/26/ij/ImageJApplet.java b/mrj/26/ij/ImageJApplet.java
new file mode 100644
index 00000000..e820e01b
--- /dev/null
+++ b/mrj/26/ij/ImageJApplet.java
@@ -0,0 +1,37 @@
+package ij;
+
+import ij.stub.Applet;
+
+/**
+ Runs ImageJ as an applet and optionally opens up to
+ nine images using URLs passed as a parameters.
+
+ Here is an example applet tag that launches ImageJ as an applet
+ and passes it the URLs of two images:
+
+ <applet archive="../ij.jar" code="ij.ImageJApplet.class" width=0 height=0>
+ <param name=url1 value="http://imagej.nih.gov/ij/images/FluorescentCells.jpg">
+ <param name=url2 value="http://imagej.nih.gov/ij/images/blobs.gif">
+ </applet>
+
+ To use plugins, add them to ij.jar and add entries to IJ_Props.txt file (in ij.jar) that will
+ create commands for them in the Plugins menu, or a submenu. There are examples
+ of such entries in IJ.Props.txt, in the "Plugins installed in the Plugins menu" section.
+
+ Macros contained in a file named "StartupMacros.txt", in the same directory as the HTML file
+ containing the applet tag, will be installed on startup.
+ @deprecated All methods can unconditionally throw since removal of Applets in Java 26.
+*/
+@Deprecated(since = "IJ XX; Java 26")
+public class ImageJApplet extends Applet {
+
+ /** Starts ImageJ if it's not already running. */
+ public void init() {
+ throw new UnsupportedOperationException("Java 26 has removed Applets");
+ }
+
+ public void destroy() {
+ throw new UnsupportedOperationException("Java 26 has removed Applets");
+ }
+}
+
diff --git a/mrj/26/ij/Menus.java b/mrj/26/ij/Menus.java
new file mode 100644
index 00000000..d3fca3c2
--- /dev/null
+++ b/mrj/26/ij/Menus.java
@@ -0,0 +1,1747 @@
+package ij;
+import ij.process.*;
+import ij.stub.Applet;
+import ij.util.*;
+import ij.gui.ImageWindow;
+import ij.plugin.MacroInstaller;
+import ij.gui.Toolbar;
+import ij.macro.Interpreter;
+import java.awt.*;
+import java.awt.image.*;
+import java.awt.event.*;
+import java.util.*;
+import java.io.*;
+import java.awt.event.*;
+import java.util.zip.*;
+
+/**
+This class installs and updates ImageJ's menus. Note that menu labels,
+even in submenus, must be unique. This is because ImageJ uses a single
+hash table for all menu labels. If you look closely, you will see that
+File->Import->Text Image... and File->Save As->Text Image... do not use
+the same label. One of the labels has an extra space.
+
+@see ImageJ
+*/
+
+public class Menus {
+
+ public static final char PLUGINS_MENU = 'p';
+ public static final char IMPORT_MENU = 'i';
+ public static final char SAVE_AS_MENU = 's';
+ public static final char SHORTCUTS_MENU = 'h'; // 'h'=hotkey
+ public static final char ABOUT_MENU = 'a';
+ public static final char FILTERS_MENU = 'f';
+ public static final char TOOLS_MENU = 't';
+ public static final char UTILITIES_MENU = 'u';
+
+ public static final int WINDOW_MENU_ITEMS = 6; // fixed items at top of Window menu
+
+ public static final int NORMAL_RETURN = 0;
+ public static final int COMMAND_IN_USE = -1;
+ public static final int INVALID_SHORTCUT = -2;
+ public static final int SHORTCUT_IN_USE = -3;
+ public static final int NOT_INSTALLED = -4;
+ public static final int COMMAND_NOT_FOUND = -5;
+
+ public static final int MAX_OPEN_RECENT_ITEMS = 15;
+
+ private static Menus instance;
+ private static MenuBar mbar;
+ private static CheckboxMenuItem gray8Item,gray16Item,gray32Item,
+ color256Item,colorRGBItem,RGBStackItem,HSBStackItem,LabStackItem,HSB32Item;
+ private static PopupMenu popup;
+
+ private static ImageJ ij;
+ private static Applet applet;
+ private Hashtable demoImagesTable = new Hashtable();
+ private static String ImageJPath, pluginsPath, macrosPath;
+ private static Properties menus;
+ private static Properties menuSeparators;
+ private static Menu pluginsMenu, saveAsMenu, shortcutsMenu, utilitiesMenu, macrosMenu;
+ static Menu window, openRecentMenu;
+ private static Hashtable pluginsTable;
+
+ private static int nPlugins, nMacros;
+ private static Hashtable shortcuts;
+ private static Hashtable macroShortcuts;
+ private static Vector pluginsPrefs; // commands saved in IJ_Prefs
+ static int windowMenuItems2; // non-image windows listed in Window menu + separator
+ private String error;
+ private String jarError;
+ private String pluginError;
+ private boolean isJarErrorHeading;
+ private static boolean installingJars, duplicateCommand;
+ private static Vector jarFiles; // JAR files in plugins folder with "_" in their name
+ private Map menuEntry2jarFile = new HashMap();
+ private static Vector macroFiles; // Macros and scripts in the plugins folder
+ private static int userPluginsIndex; // First user plugin or submenu in Plugins menu
+ private static boolean addSorted;
+ private static int defaultFontSize = IJ.isWindows()?15:0;
+ private static int fontSize;
+ private static double scale = 1.0;
+ private static Font cachedFont;
+
+ static boolean jnlp; // true when using Java WebStart
+ public static int setMenuBarCount;
+
+ Menus(ImageJ ijInstance, Applet appletInstance) {
+ ij = ijInstance;
+ String title = ij!=null?ij.getTitle():null;
+ applet = appletInstance;
+ instance = this;
+ fontSize = Prefs.getInt(Prefs.MENU_SIZE, defaultFontSize);
+ }
+
+ String addMenuBar() {
+ scale = Prefs.getGuiScale();
+ //if ((scale>=1.5&&scale<2.0) || (scale>=2.5&&scale<3.0))
+ // scale = (int)Math.round(scale);
+ nPlugins = nMacros = userPluginsIndex = 0;
+ addSorted = installingJars = duplicateCommand = false;
+ error = null;
+ mbar = null;
+ menus = new Properties();
+ pluginsTable = new Hashtable();
+ shortcuts = new Hashtable();
+ pluginsPrefs = new Vector();
+ macroShortcuts = null;
+ setupPluginsAndMacrosPaths();
+ Menu file = getMenu("File");
+ Menu newMenu = getMenu("File>New", true);
+ addPlugInItem(file, "Open...", "ij.plugin.Commands(\"open\")", KeyEvent.VK_O, false);
+ addPlugInItem(file, "Open Next", "ij.plugin.NextImageOpener", KeyEvent.VK_O, true);
+ Menu openSamples = getMenu("File>Open Samples", true);
+ openSamples.addSeparator();
+ addPlugInItem(openSamples, "Cache Sample Images ", "ij.plugin.URLOpener(\"cache\")", 0, false);
+ addOpenRecentSubMenu(file);
+ Menu importMenu = getMenu("File>Import", true);
+ Menu showFolderMenu = new Menu("Show Folder");
+ fixFontSize(showFolderMenu);
+ file.add(showFolderMenu);
+ addPlugInItem(showFolderMenu, "Image", "ij.plugin.SimpleCommands(\"showdirImage\")", 0, false);
+ addPlugInItem(showFolderMenu, "Plugins", "ij.plugin.SimpleCommands(\"showdirPlugins\")", 0, false);
+ addPlugInItem(showFolderMenu, "Macros", "ij.plugin.SimpleCommands(\"showdirMacros\")", 0, false);
+ addPlugInItem(showFolderMenu, "LUTs", "ij.plugin.SimpleCommands(\"showdirLuts\")", 0, false);
+ addPlugInItem(showFolderMenu, "ImageJ", "ij.plugin.SimpleCommands(\"showdirImageJ\")", 0, false);
+ addPlugInItem(showFolderMenu, "temp", "ij.plugin.SimpleCommands(\"showdirTemp\")", 0, false);
+ addPlugInItem(showFolderMenu, "Home", "ij.plugin.SimpleCommands(\"showdirHome\")", 0, false);
+ file.addSeparator();
+ addPlugInItem(file, "Close", "ij.plugin.Commands(\"close\")", KeyEvent.VK_W, false);
+ addPlugInItem(file, "Close All", "ij.plugin.Commands(\"close-all\")", KeyEvent.VK_W, true);
+ addPlugInItem(file, "Save", "ij.plugin.Commands(\"save\")", KeyEvent.VK_S, false);
+ saveAsMenu = getMenu("File>Save As", true);
+ addPlugInItem(file, "Revert", "ij.plugin.Commands(\"revert\")", KeyEvent.VK_R, true);
+ file.addSeparator();
+ addPlugInItem(file, "Page Setup...", "ij.plugin.filter.Printer(\"setup\")", 0, false);
+ addPlugInItem(file, "Print...", "ij.plugin.filter.Printer(\"print\")", KeyEvent.VK_P, false);
+
+ Menu edit = getMenu("Edit");
+ addPlugInItem(edit, "Undo", "ij.plugin.Commands(\"undo\")", KeyEvent.VK_Z, false);
+ edit.addSeparator();
+ addPlugInItem(edit, "Cut", "ij.plugin.Clipboard(\"cut\")", KeyEvent.VK_X, false);
+ addPlugInItem(edit, "Copy", "ij.plugin.Clipboard(\"copy\")", KeyEvent.VK_C, false);
+ addPlugInItem(edit, "Copy to System", "ij.plugin.Clipboard(\"scopy\")", 0, false);
+ addPlugInItem(edit, "Paste", "ij.plugin.Clipboard(\"paste\")", KeyEvent.VK_V, false);
+ addPlugInItem(edit, "Paste Control...", "ij.plugin.frame.PasteController", 0, false);
+ edit.addSeparator();
+ addPlugInItem(edit, "Clear", "ij.plugin.filter.Filler(\"clear\")", 0, false);
+ addPlugInItem(edit, "Clear Outside", "ij.plugin.filter.Filler(\"outside\")", 0, false);
+ addPlugInItem(edit, "Fill", "ij.plugin.filter.Filler(\"fill\")", KeyEvent.VK_F, false);
+ addPlugInItem(edit, "Draw", "ij.plugin.filter.Filler(\"draw\")", KeyEvent.VK_D, false);
+ addPlugInItem(edit, "Invert", "ij.plugin.filter.Filters(\"invert\")", KeyEvent.VK_I, true);
+ edit.addSeparator();
+ getMenu("Edit>Selection", true);
+ Menu optionsMenu = getMenu("Edit>Options", true);
+
+ Menu image = getMenu("Image");
+ Menu imageType = getMenu("Image>Type");
+ gray8Item = addCheckboxItem(imageType, "8-bit", "ij.plugin.Converter(\"8-bit\")");
+ gray16Item = addCheckboxItem(imageType, "16-bit", "ij.plugin.Converter(\"16-bit\")");
+ gray32Item = addCheckboxItem(imageType, "32-bit", "ij.plugin.Converter(\"32-bit\")");
+ color256Item = addCheckboxItem(imageType, "8-bit Color", "ij.plugin.Converter(\"8-bit Color\")");
+ colorRGBItem = addCheckboxItem(imageType, "RGB Color", "ij.plugin.Converter(\"RGB Color\")");
+ imageType.add(new MenuItem("-"));
+ RGBStackItem = addCheckboxItem(imageType, "RGB Stack", "ij.plugin.Converter(\"RGB Stack\")");
+ HSBStackItem = addCheckboxItem(imageType, "HSB Stack", "ij.plugin.Converter(\"HSB Stack\")");
+ HSB32Item = addCheckboxItem(imageType, "HSB (32-bit)", "ij.plugin.Converter(\"HSB (32-bit)\")");
+ LabStackItem = addCheckboxItem(imageType, "Lab Stack", "ij.plugin.Converter(\"Lab Stack\")");
+ image.add(imageType);
+
+ image.addSeparator();
+ getMenu("Image>Adjust", true);
+ addPlugInItem(image, "Show Info...", "ij.plugin.ImageInfo", KeyEvent.VK_I, false);
+ addPlugInItem(image, "Properties...", "ij.plugin.filter.ImageProperties", KeyEvent.VK_P, true);
+ getMenu("Image>Color", true);
+ getMenu("Image>Stacks", true);
+ getMenu("Image>Stacks>Animation_", true);
+ getMenu("Image>Stacks>Tools_", true);
+ Menu hyperstacksMenu = getMenu("Image>Hyperstacks", true);
+ image.addSeparator();
+ addPlugInItem(image, "Crop", "ij.plugin.Resizer(\"crop\")", KeyEvent.VK_X, true);
+ addPlugInItem(image, "Duplicate...", "ij.plugin.Duplicator", KeyEvent.VK_D, true);
+ addPlugInItem(image, "Rename...", "ij.plugin.SimpleCommands(\"rename\")", 0, false);
+ addPlugInItem(image, "Scale...", "ij.plugin.Scaler", KeyEvent.VK_E, false);
+ getMenu("Image>Transform", true);
+ getMenu("Image>Zoom", true);
+ getMenu("Image>Overlay", true);
+ image.addSeparator();
+ getMenu("Image>Lookup Tables", true);
+
+ Menu process = getMenu("Process");
+ addPlugInItem(process, "Smooth", "ij.plugin.filter.Filters(\"smooth\")", KeyEvent.VK_S, true);
+ addPlugInItem(process, "Sharpen", "ij.plugin.filter.Filters(\"sharpen\")", 0, false);
+ addPlugInItem(process, "Find Edges", "ij.plugin.filter.Filters(\"edge\")", 0, false);
+ addPlugInItem(process, "Find Maxima...", "ij.plugin.filter.MaximumFinder", 0, false);
+ addPlugInItem(process, "Enhance Contrast...", "ij.plugin.ContrastEnhancer", 0, false);
+ getMenu("Process>Noise", true);
+ getMenu("Process>Shadows", true);
+ getMenu("Process>Binary", true);
+ getMenu("Process>Math", true);
+ getMenu("Process>FFT", true);
+ Menu filtersMenu = getMenu("Process>Filters", true);
+ process.addSeparator();
+ getMenu("Process>Batch", true);
+ addPlugInItem(process, "Image Calculator...", "ij.plugin.ImageCalculator", 0, false);
+ addPlugInItem(process, "Subtract Background...", "ij.plugin.filter.BackgroundSubtracter", 0, false);
+ addItem(process, "Repeat Command", KeyEvent.VK_R, false);
+
+ Menu analyzeMenu = getMenu("Analyze");
+ addPlugInItem(analyzeMenu, "Measure", "ij.plugin.filter.Analyzer", KeyEvent.VK_M, false);
+ addPlugInItem(analyzeMenu, "Analyze Particles...", "ij.plugin.filter.ParticleAnalyzer", 0, false);
+ addPlugInItem(analyzeMenu, "Summarize", "ij.plugin.filter.Analyzer(\"sum\")", 0, false);
+ addPlugInItem(analyzeMenu, "Distribution...", "ij.plugin.Distribution", 0, false);
+ addPlugInItem(analyzeMenu, "Label", "ij.plugin.filter.Filler(\"label\")", 0, false);
+ addPlugInItem(analyzeMenu, "Clear Results", "ij.plugin.filter.Analyzer(\"clear\")", 0, false);
+ addPlugInItem(analyzeMenu, "Set Measurements...", "ij.plugin.filter.Analyzer(\"set\")", 0, false);
+ analyzeMenu.addSeparator();
+ addPlugInItem(analyzeMenu, "Set Scale...", "ij.plugin.filter.ScaleDialog", 0, false);
+ addPlugInItem(analyzeMenu, "Calibrate...", "ij.plugin.filter.Calibrator", 0, false);
+ if (IJ.isMacOSX()) {
+ addPlugInItem(analyzeMenu, "Histogram", "ij.plugin.Histogram", 0, false);
+ shortcuts.put(Integer.valueOf(KeyEvent.VK_H),"Histogram");
+ } else
+ addPlugInItem(analyzeMenu, "Histogram", "ij.plugin.Histogram", KeyEvent.VK_H, false);
+ addPlugInItem(analyzeMenu, "Plot Profile", "ij.plugin.Profiler(\"plot\")", KeyEvent.VK_K, false);
+ addPlugInItem(analyzeMenu, "Surface Plot...", "ij.plugin.SurfacePlotter", 0, false);
+ getMenu("Analyze>Gels", true);
+ Menu toolsMenu = getMenu("Analyze>Tools", true);
+
+ // the plugins will be added later, after a separator
+ addPluginsMenu();
+
+ Menu window = getMenu("Window");
+ addPlugInItem(window, "Show All", "ij.plugin.WindowOrganizer(\"show\")", KeyEvent.VK_CLOSE_BRACKET, false);
+ String key = IJ.isWindows()?"enter":"return";
+ addPlugInItem(window, "Main Window ["+key+"]", "ij.plugin.WindowOrganizer(\"imagej\")", 0, false);
+ addPlugInItem(window, "Put Behind [tab]", "ij.plugin.Commands(\"tab\")", 0, false);
+ addPlugInItem(window, "Cascade", "ij.plugin.WindowOrganizer(\"cascade\")", 0, false);
+ addPlugInItem(window, "Tile", "ij.plugin.WindowOrganizer(\"tile\")", 0, false);
+ window.addSeparator();
+
+ Menu help = getMenu("Help");
+ addPlugInItem(help, "ImageJ Website...", "ij.plugin.BrowserLauncher", 0, false);
+ help.addSeparator();
+ addPlugInItem(help, "Dev. Resources...", "ij.plugin.BrowserLauncher(\""+IJ.URL2+"/developer/index.html\")", 0, false);
+ addPlugInItem(help, "Macro Functions...", "ij.plugin.BrowserLauncher(\"https://wsr.imagej.net/developer/macro/functions.html\")", 0, false);
+ Menu examplesMenu = getExamplesMenu(ij);
+ addPlugInItem(examplesMenu, "Open as Panel", "ij.plugin.SimpleCommands(\"opencp\")", 0, false);
+ help.add(examplesMenu);
+ help.addSeparator();
+ addPlugInItem(help, "Update ImageJ...", "ij.plugin.ImageJ_Updater", 0, false);
+ addPlugInItem(help, "Release Notes...", "ij.plugin.BrowserLauncher(\"https://wsr.imagej.net/notes.html\")", 0, false);
+ addPlugInItem(help, "Refresh Menus", "ij.plugin.ImageJ_Updater(\"menus\")", 0, false);
+ help.addSeparator();
+ Menu aboutMenu = getMenu("Help>About Plugins", true);
+ addPlugInItem(help, "About ImageJ...", "ij.plugin.AboutBox", 0, false);
+
+ if (applet==null) {
+ menuSeparators = new Properties();
+ installPlugins();
+ }
+
+ // make sure "Quit" is the last item in the File menu
+ file.addSeparator();
+ addPlugInItem(file, "Quit", "ij.plugin.Commands(\"quit\")", 0, false);
+
+ //System.out.println("MenuBar.setFont: "+fontSize+" "+scale+" "+getFont());
+ if (fontSize!=0 || scale>1.0)
+ mbar.setFont(getFont());
+ if (ij!=null) {
+ ij.setMenuBar(mbar);
+ Menus.setMenuBarCount++;
+ }
+
+ // Add deleted sample images to commands table
+ pluginsTable.put("Lena (68K)", "ij.plugin.URLOpener(\"lena-std.tif\")");
+ pluginsTable.put("Bridge (174K)", "ij.plugin.URLOpener(\"bridge.gif\")");
+
+ if (pluginError!=null)
+ error = error!=null?error+="\n"+pluginError:pluginError;
+ if (jarError!=null)
+ error = error!=null?error+="\n"+jarError:jarError;
+ return error;
+ }
+
+ public static Menu getExamplesMenu(ActionListener listener) {
+ Menu menu = new Menu("Examples");
+ Menu submenu = new Menu("Plots");
+ addExample(submenu, "Example Plot", "Example_Plot_.ijm");
+ addExample(submenu, "Semi-log Plot", "Semi-log_Plot_.ijm");
+ addExample(submenu, "Arrow Plot", "Arrow_Plot_.ijm");
+ addExample(submenu, "Damped Wave Plot", "Damped_Wave_Plot_.ijm");
+ addExample(submenu, "Dynamic Plot", "Dynamic_Plot_.ijm");
+ addExample(submenu, "Dynamic Plot 2D", "Dynamic_Plot_2D_.ijm");
+ addExample(submenu, "Custom Plot Symbols", "Custom_Plot_Symbols_.ijm");
+ addExample(submenu, "Histograms", "Histograms_.ijm");
+ addExample(submenu, "Bar Charts", "Bar_Charts_.ijm");
+ addExample(submenu, "Shapes", "Plot_Shapes_.ijm");
+ addExample(submenu, "Plot Styles", "Plot_Styles_.ijm");
+ addExample(submenu, "Random Data", "Random_Data_.ijm");
+ addExample(submenu, "Plot Results", "Plot_Results_.ijm");
+ addExample(submenu, "Plot With Spectrum", "Plot_With_Spectrum_.ijm");
+ submenu.addActionListener(listener);
+ menu.add(submenu);
+
+ submenu = new Menu("Tools");
+ addExample(submenu, "Annular Selection", "Annular_Selection_Tool.ijm");
+ addExample(submenu, "Big Cursor", "Big_Cursor_Tool.ijm");
+ addExample(submenu, "Circle Tool", "Circle_Tool.ijm");
+ addExample(submenu, "Point Picker", "Point_Picker_Tool.ijm");
+ addExample(submenu, "Star Tool", "Star_Tool.ijm");
+ addExample(submenu, "Animated Icon Tool", "Animated_Icon_Tool.ijm");
+ submenu.addActionListener(listener);
+ menu.add(submenu);
+
+ submenu = new Menu("Macro");
+ addExample(submenu, "Sphere", "Sphere.ijm");
+ addExample(submenu, "Dialog Box", "Dialog_Box.ijm");
+ addExample(submenu, "Process Folder", "Batch_Process_Folder.ijm");
+ addExample(submenu, "OpenDialog Demo", "OpenDialog_Demo.ijm");
+ addExample(submenu, "Save All Images", "Save_All_Images.ijm");
+ addExample(submenu, "Sine/Cosine Table", "Sine_Cosine_Table.ijm");
+ addExample(submenu, "Non-numeric Table", "Non-numeric_Table.ijm");
+ addExample(submenu, "Overlay", "Overlay.ijm");
+ addExample(submenu, "Stack Overlay", "Stack_Overlay.ijm");
+ addExample(submenu, "Array Functions", "Array_Functions.ijm");
+ addExample(submenu, "Dual Progress Bars", "Dual_Progress_Bars.ijm");
+ addExample(submenu, "Grab Viridis Colormap", "Grab_Viridis_Colormap.ijm");
+ addExample(submenu, "Custom Measurement", "Custom_Measurement.ijm");
+ addExample(submenu, "Synthetic Images", "Synthetic_Images.ijm");
+ addExample(submenu, "Spiral Rotation", "Spiral_Rotation.ijm");
+ addExample(submenu, "Curve Fitting", "Curve_Fitting.ijm");
+ addExample(submenu, "Colors of 2021", "Colors_of_2021.ijm");
+ addExample(submenu, "Turtle Graphics", "Turtle_Graphics.ijm");
+ addExample(submenu, "Easter Eggs", "Easter_Eggs.ijm");
+ submenu.addActionListener(listener);
+ menu.add(submenu);
+
+ submenu = new Menu("JavaScript");
+ addExample(submenu, "Sphere", "Sphere.js");
+ addExample(submenu, "Plasma Cloud", "Plasma_Cloud.js");
+ addExample(submenu, "Cloud Debugger", "Cloud_Debugger.js");
+ addExample(submenu, "Synthetic Images", "Synthetic_Images.js");
+ addExample(submenu, "Points", "Points.js");
+ addExample(submenu, "Spiral Rotation", "Spiral_Rotation.js");
+ addExample(submenu, "Example Plot", "Example_Plot.js");
+ addExample(submenu, "Semi-log Plot", "Semi-log_Plot.js");
+ addExample(submenu, "Arrow Plot", "Arrow_Plot.js");
+ addExample(submenu, "Dynamic Plot", "Dynamic_Plot.js");
+ addExample(submenu, "Plot Styles", "Plot_Styles.js");
+ addExample(submenu, "Plot Random Data", "Plot_Random_Data.js");
+ addExample(submenu, "Histogram Plots", "Histogram_Plots.js");
+ addExample(submenu, "JPEG Quality Plot", "JPEG_Quality_Plot.js");
+ addExample(submenu, "Process Folder", "Batch_Process_Folder.js");
+ addExample(submenu, "Sine/Cosine Table", "Sine_Cosine_Table.js");
+ addExample(submenu, "Non-numeric Table", "Non-numeric_Table.js");
+ addExample(submenu, "Overlay", "Overlay.js");
+ addExample(submenu, "Stack Overlay", "Stack_Overlay.js");
+ addExample(submenu, "Dual Progress Bars", "Dual_Progress_Bars.js");
+ addExample(submenu, "Gamma Adjuster", "Gamma_Adjuster.js");
+ addExample(submenu, "Custom Measurement", "Custom_Measurement.js");
+ addExample(submenu, "Terabyte VirtualStack", "Terabyte_VirtualStack.js");
+ addExample(submenu, "Event Listener", "Event_Listener.js");
+ addExample(submenu, "FFT Filter", "FFT_Filter.js");
+ addExample(submenu, "Curve Fitting", "Curve_Fitting.js");
+ addExample(submenu, "Overlay Text", "Overlay_Text.js");
+ addExample(submenu, "Crop Multiple Rois", "Crop_Multiple_Rois.js");
+ addExample(submenu, "Show all LUTs", "Show_all_LUTs.js");
+ addExample(submenu, "Dialog Demo", "Dialog_Demo.js");
+ submenu.addActionListener(listener);
+ menu.add(submenu);
+ submenu = new Menu("BeanShell");
+ addExample(submenu, "Sphere", "Sphere.bsh");
+ addExample(submenu, "Example Plot", "Example_Plot.bsh");
+ addExample(submenu, "Semi-log Plot", "Semi-log_Plot.bsh");
+ addExample(submenu, "Arrow Plot", "Arrow_Plot.bsh");
+ addExample(submenu, "Sine/Cosine Table", "Sine_Cosine_Table.bsh");
+ submenu.addActionListener(listener);
+ menu.add(submenu);
+ submenu = new Menu("Python");
+ addExample(submenu, "Sphere", "Sphere.py");
+ addExample(submenu, "Animated Gaussian Blur", "Animated_Gaussian_Blur.py");
+ addExample(submenu, "Spiral Rotation", "Spiral_Rotation.py");
+ addExample(submenu, "Overlay", "Overlay.py");
+ submenu.addActionListener(listener);
+ menu.add(submenu);
+ submenu = new Menu("Java");
+ addExample(submenu, "Sphere", "Sphere_.java");
+ addExample(submenu, "Plasma Cloud", "Plasma_Cloud.java");
+ addExample(submenu, "Gamma Adjuster", "Gamma_Adjuster.java");
+ addExample(submenu, "Plugin", "My_Plugin.java");
+ addExample(submenu, "Plugin Filter", "Filter_Plugin.java");
+ addExample(submenu, "Plugin Frame", "Plugin_Frame.java");
+ addExample(submenu, "Plugin Tool", "Prototype_Tool.java");
+ submenu.addActionListener(listener);
+ menu.add(submenu);
+ menu.addSeparator();
+ CheckboxMenuItem item = new CheckboxMenuItem("Autorun Examples");
+ menu.add(item);
+ item.addItemListener(ij);
+ item.setState(Prefs.autoRunExamples);
+ fixFontSize(menu);
+ return menu;
+ }
+
+ private static void addExample(Menu menu, String label, String command) {
+ MenuItem item = new MenuItem(label);
+ menu.add(item);
+ item.setActionCommand(command);
+ fixFontSize(item);
+ }
+
+ void addOpenRecentSubMenu(Menu menu) {
+ openRecentMenu = getMenu("File>Open Recent");
+ for (int i=0; i0)
+ key = key.substring(0, index);
+ for (int count=1; count<100; count++) {
+ value = Prefs.getString(key + (count/10)%10 + count%10);
+ if (value==null)
+ break;
+ if (count==1)
+ menu.add(submenu);
+ if (value.equals("-"))
+ submenu.addSeparator();
+ else
+ addPluginItem(submenu, value);
+ }
+ if (name.equals("Lookup Tables") && applet==null)
+ addLuts(submenu);
+ fixFontSize(submenu);
+ return submenu;
+ }
+
+ static void addLuts(Menu submenu) {
+ String path = IJ.getDirectory("luts");
+ if (path==null) return;
+ File f = new File(path);
+ String[] list = null;
+ if (applet==null && f.exists() && f.isDirectory())
+ list = f.list();
+ if (list==null) return;
+ if (IJ.isLinux() || IJ.isMacOSX())
+ Arrays.sort(list);
+ submenu.addSeparator();
+ for (int i=0; i0) {
+ String shortcut = command.substring(openBracket+1,command.length()-1);
+ keyCode = convertShortcutToCode(shortcut);
+ boolean functionKey = keyCode>=KeyEvent.VK_F1 && keyCode<=KeyEvent.VK_F12;
+ if (keyCode>0 && !functionKey)
+ command = command.substring(0,openBracket);
+ }
+ }
+ if (keyCode>=KeyEvent.VK_F1 && keyCode<=KeyEvent.VK_F12) {
+ shortcuts.put(Integer.valueOf(keyCode),command);
+ keyCode = 0;
+ } else if (keyCode>=265 && keyCode<=290) {
+ keyCode -= 200;
+ shift = true;
+ }
+ addItem(submenu,command,keyCode,shift);
+ while(s.charAt(lastComma+1)==' ' && lastComma+2') {
+ String submenu = value.substring(2,value.length()-1);
+ //Menu menu = getMenu("Plugins>" + submenu, true);
+ Menu menu = addSubMenu(pluginsMenu, submenu);
+ if (submenu.equals("Shortcuts"))
+ shortcutsMenu = menu;
+ else if (submenu.equals("Utilities"))
+ utilitiesMenu = menu;
+ else if (submenu.equals("Macros"))
+ macrosMenu = menu;
+ } else
+ addPluginItem(pluginsMenu, value);
+ }
+ userPluginsIndex = pluginsMenu.getItemCount();
+ if (userPluginsIndex<0) userPluginsIndex = 0;
+ }
+
+ /** Install plugins using "pluginxx=" keys in IJ_Prefs.txt.
+ Plugins not listed in IJ_Prefs are added to the end
+ of the Plugins menu. */
+ void installPlugins() {
+ int nPlugins0 = nPlugins;
+ String value, className;
+ char menuCode;
+ Menu menu;
+ String[] pluginList = getPlugins();
+ String[] pluginsList2 = null;
+ Hashtable skipList = new Hashtable();
+ for (int index=0; index<100; index++) {
+ value = Prefs.getString("plugin" + (index/10)%10 + index%10);
+ if (value==null)
+ break;
+ menuCode = value.charAt(0);
+ switch (menuCode) {
+ case PLUGINS_MENU: default: menu = pluginsMenu; break;
+ case IMPORT_MENU: menu = getMenu("File>Import"); break;
+ case SAVE_AS_MENU: menu = getMenu("File>Save As"); break;
+ case SHORTCUTS_MENU: menu = shortcutsMenu; break;
+ case ABOUT_MENU: menu = getMenu("Help>About Plugins"); break;
+ case FILTERS_MENU: menu = getMenu("Process>Filters"); break;
+ case TOOLS_MENU: menu = getMenu("Analyze>Tools"); break;
+ case UTILITIES_MENU: menu = utilitiesMenu; break;
+ }
+ String prefsValue = value;
+ value = value.substring(2,value.length()); //remove menu code and coma
+ className = value.substring(value.lastIndexOf(',')+1,value.length());
+ boolean found = className.startsWith("ij.");
+ if (!found && pluginList!=null) { // does this plugin exist?
+ if (pluginsList2==null)
+ pluginsList2 = getStrippedPlugins(pluginList);
+ for (int i=0; i0)
+ className = className.substring(0, argStart);
+ }
+ skipList.put(className, "");
+ }
+ }
+ if (pluginList!=null) {
+ for (int i=0; i0) {
+ dir = name.substring(0, slashIndex);
+ name = name.substring(slashIndex+1, name.length());
+ menu = getPluginsSubmenu(dir);
+ slashIndex = name.indexOf('/');
+ if (slashIndex>0) {
+ String dir2 = name.substring(0, slashIndex);
+ name = name.substring(slashIndex+1, name.length());
+ String menuName = "Plugins>"+dir+">"+dir2;
+ menu = getMenu(menuName);
+ dir += File.separator+dir2;
+ }
+ }
+ String command = name.replace('_',' ');
+ if (command.endsWith(".js")||command.endsWith(".py"))
+ command = command.substring(0, command.length()-3); //remove ".js" or ".py"
+ else
+ command = command.substring(0, command.length()-4); //remove ".txt", ".ijm" or ".bsh"
+ command = command.trim();
+ if (pluginsTable.get(command)!=null) // duplicate command?
+ command = command + " Macro";
+ MenuItem item = new MenuItem(command);
+ addOrdered(menu, item);
+ item.addActionListener(ij);
+ String path = (dir!=null?dir+File.separator:"") + name;
+ pluginsTable.put(command, "ij.plugin.Macro_Runner(\""+path+"\")");
+ nMacros++;
+ }
+
+ static int addPluginSeparatorIfNeeded(Menu menu) {
+ if (menuSeparators == null)
+ return 0;
+ Integer i = (Integer)menuSeparators.get(menu);
+ if (i == null) {
+ if (menu.getItemCount() > 0)
+ addSeparator(menu);
+ i = Integer.valueOf(menu.getItemCount());
+ menuSeparators.put(menu, i);
+ }
+ return i.intValue();
+ }
+
+ /** Inserts 'item' into 'menu' in alphanumeric order. */
+ static void addOrdered(Menu menu, MenuItem item) {
+ String label = item.getLabel();
+ int start = addPluginSeparatorIfNeeded(menu);
+ for (int i=start; i=3 && !s.startsWith("#"))
+ entries.add(s);
+ }
+ }
+ catch (IOException e) {}
+ finally {
+ try {if (lnr!=null) lnr.close();}
+ catch (IOException e) {}
+ }
+ for (int j=0; j")) {
+ int firstComma = s.indexOf(',');
+ if (firstComma==-1 || firstComma<=8)
+ menu = null;
+ else {
+ String name = s.substring(8, firstComma);
+ menu = getPluginsSubmenu(name);
+ }
+ } else if (s.startsWith("\"") || s.startsWith("Plugins")) {
+ String name = getSubmenuName(jar);
+ if (name!=null)
+ menu = getPluginsSubmenu(name);
+ else
+ menu = pluginsMenu;
+ addSorted = true;
+ } else {
+ int firstQuote = s.indexOf('"');
+ String name = firstQuote<0 ? s : s.substring(0, firstQuote).trim();
+ int comma = name.indexOf(',');
+ if (comma >= 0)
+ name = name.substring(0, comma);
+ if (name.startsWith("Help>About")) // for backward compatibility
+ name = "Help>About Plugins";
+ menu = getMenu(name);
+ }
+ int firstQuote = s.indexOf('"');
+ if (firstQuote==-1)
+ return;
+ s = s.substring(firstQuote, s.length()); // remove menu
+ if (menu!=null) {
+ addPluginSeparatorIfNeeded(menu);
+ addPluginItem(menu, s);
+ addSorted = false;
+ }
+ String menuEntry = s;
+ if (s.startsWith("\"")) {
+ int quote = s.indexOf('"', 1);
+ menuEntry = quote<0?s.substring(1):s.substring(1, quote);
+ } else {
+ int comma = s.indexOf(',');
+ if (comma > 0)
+ menuEntry = s.substring(0, comma);
+ }
+ if (duplicateCommand) {
+ if (jarError==null) jarError = "";
+ addJarErrorHeading(jar);
+ String jar2 = (String)menuEntry2jarFile.get(menuEntry);
+ if (jar2 != null && jar2.startsWith(pluginsPath))
+ jar2 = jar2.substring(pluginsPath.length());
+ jarError += " Duplicate command: " + s
+ + (jar2 != null ? " (already in " + jar2 + ")"
+ : "") + "\n";
+ } else
+ menuEntry2jarFile.put(menuEntry, jar);
+ duplicateCommand = false;
+ }
+
+ void addJarErrorHeading(String jar) {
+ if (!isJarErrorHeading) {
+ if (!jarError.equals(""))
+ jarError += " \n";
+ jarError += "Plugin configuration error: " + jar + "\n";
+ isJarErrorHeading = true;
+ }
+ }
+
+ /** Returns the specified ImageJ menu (e.g., "File>New") or null if it is not found. */
+ public static Menu getImageJMenu(String menuPath) {
+ if (menus==null && !GraphicsEnvironment.isHeadless())
+ IJ.init();
+ if (menus==null)
+ return null;
+ if (menus.get(menuPath)!=null)
+ return getMenu(menuPath, false);
+ else
+ return null;
+ }
+
+ private static Menu getMenu(String menuPath) {
+ if (GraphicsEnvironment.isHeadless())
+ return null;
+ else
+ return getMenu(menuPath, false);
+ }
+
+ private static Menu getMenu(String menuName, boolean readFromProps) {
+ if (menuName.endsWith(">"))
+ menuName = menuName.substring(0, menuName.length() - 1);
+ Menu result = (Menu)menus.get(menuName);
+ if (result==null) {
+ int offset = menuName.lastIndexOf('>');
+ if (offset < 0) {
+ result = new Menu(menuName);
+ if (mbar == null)
+ mbar = new MenuBar();
+ if (menuName.equals("Help"))
+ mbar.setHelpMenu(result);
+ else
+ mbar.add(result);
+ if (menuName.equals("Window"))
+ window = result;
+ else if (menuName.equals("Plugins"))
+ pluginsMenu = result;
+ } else {
+ String parentName = menuName.substring(0, offset);
+ String menuItemName = menuName.substring(offset + 1);
+ Menu parentMenu = getMenu(parentName);
+ result = new Menu(menuItemName);
+ addPluginSeparatorIfNeeded(parentMenu);
+ if (readFromProps)
+ result = addSubMenu(parentMenu, menuItemName);
+ else if (parentName.startsWith("Plugins") && menuSeparators != null)
+ addItemSorted(parentMenu, result, parentName.equals("Plugins")?userPluginsIndex:0);
+ else
+ parentMenu.add(result);
+ if (menuName.equals("File>Open Recent"))
+ openRecentMenu = result;
+ }
+ menus.put(menuName, result);
+ }
+ //System.out.println("menuName: "+menuName);
+ if (IJ.isWindows() && menuName!=null && menuName.contains(">"))
+ fixFontSize(result);
+ return result;
+ }
+
+ Menu getPluginsSubmenu(String submenuName) {
+ return getMenu("Plugins>" + submenuName);
+ }
+
+ String getSubmenuName(String jarPath) {
+ //IJ.log("getSubmenuName: \n"+jarPath+"\n"+pluginsPath);
+ if (pluginsPath == null)
+ return null;
+ if (jarPath.startsWith(pluginsPath))
+ jarPath = jarPath.substring(pluginsPath.length() - 1);
+ int index = jarPath.lastIndexOf(File.separatorChar);
+ if (index<0) return null;
+ String name = jarPath.substring(0, index);
+ index = name.lastIndexOf(File.separatorChar);
+ if (index<0) return null;
+ name = name.substring(index+1);
+ if (name.equals("plugins")) return null;
+ return name;
+ }
+
+ static void addItemSorted(Menu menu, MenuItem item, int startingIndex) {
+ String itemLabel = item.getLabel();
+ int count = menu.getItemCount();
+ boolean inserted = false;
+ for (int i=startingIndex; i0 && name.indexOf("$")==-1
+ && name.indexOf("/_")==-1 && !name.startsWith("_")) {
+ if (Character.isLowerCase(name.charAt(0))&&name.indexOf("/")!=-1)
+ continue;
+ if (sb==null) sb = new StringBuffer();
+ String className = name.substring(0, name.length()-6);
+ int slashIndex = className.lastIndexOf('/');
+ String plugins = "Plugins";
+ if (slashIndex >= 0) {
+ plugins += ">" + className.substring(0, slashIndex).replace('/', '>').replace('_', ' ');
+ name = className.substring(slashIndex + 1);
+ } else
+ name = className;
+ name = name.replace('_', ' ');
+ className = className.replace('/', '.');
+ sb.append(plugins + ", \""+name+"\", "+className+"\n");
+ }
+ }
+ jarFile.close();
+ }
+ catch (Throwable e) {
+ IJ.log(jar+": "+e);
+ }
+ if (sb==null)
+ return null;
+ else
+ return new ByteArrayInputStream(sb.toString().getBytes());
+ }
+
+ /** Returns a list of the plugins with directory names removed. */
+ String[] getStrippedPlugins(String[] plugins) {
+ String[] plugins2 = new String[plugins.length];
+ int slashPos;
+ for (int i=0; i=0)
+ plugins2[i] = plugins[i].substring(slashPos+1,plugins2[i].length());
+ }
+ return plugins2;
+ }
+
+ void setupPluginsAndMacrosPaths() {
+ ImageJPath = pluginsPath = macrosPath = null;
+ String currentDir = Prefs.getHomeDir(); // "user.dir"
+ if (currentDir==null)
+ return;
+ if (currentDir.endsWith("plugins"))
+ ImageJPath = pluginsPath = currentDir+File.separator;
+ else {
+ String ijDir = Prefs.getPluginsDirProperty();
+ if (ijDir==null)
+ ijDir = currentDir;
+ else if (ijDir.equals("user.home")) {
+ ijDir = System.getProperty("user.home");
+ if (!(new File(ijDir+File.separator+"plugins")).isDirectory())
+ ijDir = ijDir + File.separator + "ImageJ";
+ // needed to run plugins when ImageJ launched using Java WebStart
+ if (applet==null)
+ System.setSecurityManager(null);
+ jnlp = true;
+ }
+ pluginsPath = ijDir+File.separator+"plugins"+File.separator;
+ macrosPath = ijDir+File.separator+"macros"+File.separator;
+ ImageJPath = ijDir+File.separator;
+ }
+ File f = pluginsPath!=null?new File(pluginsPath):null;
+ if (f==null || !f.isDirectory()) {
+ ImageJPath = currentDir+File.separator;
+ pluginsPath = ImageJPath+"plugins"+File.separator;
+ f = new File(pluginsPath);
+ if (!f.isDirectory()) {
+ String altPluginsPath = System.getProperty("plugins.dir");
+ if (altPluginsPath!=null) {
+ f = new File(altPluginsPath);
+ if (!f.isDirectory())
+ altPluginsPath = null;
+ else {
+ ImageJPath = f.getParent() + File.separator;
+ pluginsPath = ImageJPath + f.getName() + File.separator;
+ macrosPath = ImageJPath+"macros"+File.separator;
+ }
+ }
+ if (altPluginsPath==null)
+ ImageJPath = pluginsPath = null;
+ }
+ }
+ f = macrosPath!=null?new File(macrosPath):null;
+ if (f!=null && !f.isDirectory()) {
+ macrosPath = currentDir+File.separator+"macros"+File.separator;
+ f = new File(macrosPath);
+ if (!f.isDirectory())
+ macrosPath = null;
+ }
+ if (IJ.debugMode) {
+ IJ.log("Menus.setupPluginsAndMacrosPaths");
+ IJ.log(" user.dir: "+currentDir);
+ IJ.log(" plugins.dir: "+System.getProperty("plugins.dir"));
+ IJ.log(" ImageJPath: "+ImageJPath);
+ IJ.log(" pluginsPath: "+pluginsPath);
+ }
+ }
+
+ /** Returns a list of the plugins in the plugins menu. */
+ public static synchronized String[] getPlugins() {
+ File f = pluginsPath!=null?new File(pluginsPath):null;
+ if (f==null || (f!=null && !f.isDirectory()))
+ return null;
+ String[] list = f.list();
+ if (list==null)
+ return null;
+ Vector v = new Vector();
+ jarFiles = null;
+ macroFiles = null;
+ for (int i=0; i=0;
+ if (hasUnderscore && isClassFile && name.indexOf('$')<0 ) {
+ name = name.substring(0, name.length()-6); // remove ".class"
+ v.addElement(name);
+ } else if (hasUnderscore && (name.endsWith(".jar") || name.endsWith(".zip"))) {
+ if (jarFiles==null) jarFiles = new Vector();
+ jarFiles.addElement(pluginsPath + name);
+ } else if (validMacroName(name,hasUnderscore)) {
+ if (macroFiles==null) macroFiles = new Vector();
+ macroFiles.addElement(name);
+ } else {
+ if (!isClassFile)
+ checkSubdirectory(pluginsPath, name, v);
+ }
+ }
+ list = new String[v.size()];
+ v.copyInto((String[])list);
+ StringSorter.sort(list);
+ return list;
+ }
+
+ /** Looks for plugins and jar files in a subdirectory of the plugins directory. */
+ private static void checkSubdirectory(String path, String dir, Vector v) {
+ if (dir.endsWith(".java"))
+ return;
+ File f = new File(path, dir);
+ if (!f.isDirectory())
+ return;
+ String[] list = f.list();
+ if (list==null)
+ return;
+ dir += "/";
+ int classCount=0, otherCount=0;
+ String className = null;
+ for (int i=0; i=0;
+ if (hasUnderscore && name.endsWith(".class") && name.indexOf('$')<0) {
+ name = name.substring(0, name.length()-6); // remove ".class"
+ v.addElement(dir+name);
+ classCount++;
+ className = name;
+ } else if (hasUnderscore && (name.endsWith(".jar") || name.endsWith(".zip"))) {
+ if (jarFiles==null) jarFiles = new Vector();
+ jarFiles.addElement(f.getPath() + File.separator + name);
+ otherCount++;
+ } else if (validMacroName(name,hasUnderscore)) {
+ if (macroFiles==null) macroFiles = new Vector();
+ macroFiles.addElement(dir + name);
+ otherCount++;
+ } else {
+ File f2 = new File(f, name);
+ if (f2.isDirectory()) installSubdirectorMacros(f2, dir+name);
+ }
+ }
+ if (Prefs.moveToMisc && classCount==1 && otherCount==0 && dir.indexOf("_")==-1)
+ v.setElementAt("Miscellaneous/" + className,
+ v.size() - 1);
+ }
+
+ /** Installs macros and scripts located in subdirectories. */
+ private static void installSubdirectorMacros(File f2, String dir) {
+ if (dir.endsWith("Launchers")) return;
+ String[] list = f2.list();
+ if (list==null) return;
+ for (int i=0; i=0;
+ if (validMacroName(name,hasUnderscore)) {
+ if (macroFiles==null) macroFiles = new Vector();
+ macroFiles.addElement(dir+"/"+name);
+ }
+ }
+ }
+
+ private static boolean validMacroName(String name, boolean hasUnderscore) {
+ return (hasUnderscore&&name.endsWith(".txt")) || name.endsWith(".ijm")
+ || name.endsWith(".js") || name.endsWith(".bsh") || name.endsWith(".py");
+ }
+
+ /** Installs a plugin in the Plugins menu using the class name,
+ with underscores replaced by spaces, as the command. */
+ void installUserPlugin(String className) {
+ installUserPlugin(className, false);
+ }
+
+ public void installUserPlugin(String className, boolean force) {
+ int slashIndex = className.indexOf('/');
+ String menuName = slashIndex < 0 ? "Plugins" : "Plugins>" +
+ className.substring(0, slashIndex).replace('/', '>');
+ Menu menu = getMenu(menuName);
+ String command = className;
+ if (slashIndex>0) {
+ command = className.substring(slashIndex+1);
+ }
+ command = command.replace('_',' ');
+ //command = command.trim();
+ boolean itemExists = (pluginsTable.get(command)!=null);
+ if(force && itemExists)
+ return;
+
+ if (!force && itemExists) // duplicate command?
+ command = command + " Plugin";
+ MenuItem item = new MenuItem(command);
+ if (force)
+ addItemSorted(menu,item,0);
+ else
+ addOrdered(menu, item);
+ item.addActionListener(ij);
+ pluginsTable.put(command, className.replace('/', '.'));
+ nPlugins++;
+ }
+
+ void installPopupMenu(ImageJ ij) {
+ String s;
+ int count = 0;
+ MenuItem mi;
+ popup = new PopupMenu("");
+ if (fontSize!=0 || scale>1.0)
+ popup.setFont(getCachedFont());
+ while (true) {
+ count++;
+ s = Prefs.getString("popup" + (count/10)%10 + count%10);
+ if (s==null)
+ break;
+ if (s.equals("-"))
+ popup.addSeparator();
+ else if (!s.equals("")) {
+ mi = new MenuItem(s);
+ mi.addActionListener(ij);
+ popup.add(mi);
+ }
+ }
+ }
+
+ public static MenuBar getMenuBar() {
+ return mbar;
+ }
+
+ public static Menu getMacrosMenu() {
+ return macrosMenu;
+ }
+
+ public static Menu getOpenRecentMenu() {
+ return openRecentMenu;
+ }
+
+ public int getMacroCount() {
+ return nMacros;
+ }
+
+ public int getPluginCount() {
+ return nPlugins;
+ }
+
+ static final int RGB_STACK=10, HSB_STACK=11, LAB_STACK=12, HSB32_STACK=13;
+
+ /** Updates the Image/Type and Window menus. */
+ public static void updateMenus() {
+ if (ij==null) return;
+ gray8Item.setState(false);
+ gray16Item.setState(false);
+ gray32Item.setState(false);
+ color256Item.setState(false);
+ colorRGBItem.setState(false);
+ RGBStackItem.setState(false);
+ HSBStackItem.setState(false);
+ LabStackItem.setState(false);
+ HSB32Item.setState(false);
+ ImagePlus imp = WindowManager.getCurrentImage();
+ if (imp==null)
+ return;
+ int type = imp.getType();
+ if (imp.getStackSize()>1) {
+ ImageStack stack = imp.getStack();
+ if (stack.isRGB())
+ type = RGB_STACK;
+ else if (stack.isHSB())
+ type = HSB_STACK;
+ else if (stack.isLab())
+ type = LAB_STACK;
+ else if (stack.isHSB32())
+ type = HSB32_STACK;
+ }
+ switch (type) {
+ case ImagePlus.GRAY8:
+ gray8Item.setState(true);
+ break;
+ case ImagePlus.GRAY16:
+ gray16Item.setState(true);
+ break;
+ case ImagePlus.GRAY32:
+ gray32Item.setState(true);
+ break;
+ case ImagePlus.COLOR_256:
+ color256Item.setState(true);
+ break;
+ case ImagePlus.COLOR_RGB:
+ colorRGBItem.setState(true);
+ break;
+ case RGB_STACK:
+ RGBStackItem.setState(true);
+ break;
+ case HSB_STACK:
+ HSBStackItem.setState(true);
+ break;
+ case LAB_STACK:
+ LabStackItem.setState(true);
+ break;
+ case HSB32_STACK:
+ HSB32Item.setState(true);
+ break;
+ }
+
+ //update Window menu
+ int nItems = window.getItemCount();
+ int start = WINDOW_MENU_ITEMS + windowMenuItems2;
+ int index = start + WindowManager.getCurrentIndex();
+ try { // workaround for Linux/Java 5.0/bug
+ for (int i=start; i=2)
+ index--;
+ window.insert(item, index);
+ windowMenuItems2++;
+ if (windowMenuItems2==1) {
+ window.insertSeparator(WINDOW_MENU_ITEMS+windowMenuItems2);
+ windowMenuItems2++;
+ }
+ }
+
+ /** Adds one image to the end of the Window menu. */
+ static synchronized void addWindowMenuItem(ImagePlus imp) {
+ if (ij==null)
+ return;
+ String name = imp.getTitle();
+ String size = ImageWindow.getImageSize(imp);
+ CheckboxMenuItem item = new CheckboxMenuItem(name+" "+size);
+ item.setActionCommand("" + imp.getID());
+ window.add(item);
+ fixFontSize(item);
+ item.addItemListener(ij);
+ }
+
+ /** Removes the specified item from the Window menu. */
+ static synchronized void removeWindowMenuItem(int index) {
+ //IJ.log("removeWindowMenuItem: "+index+" "+windowMenuItems2+" "+window.getItemCount());
+ if (ij==null)
+ return;
+ try {
+ if (index>=0 && index-1)
+ label = label.substring(0, index);
+ }
+ if (item!=null && label.equals(oldLabel) && (imp==null||(""+imp.getID()).equals(cmd))) {
+ String size = "";
+ if (imp!=null)
+ size = " " + ImageWindow.getImageSize(imp);
+ item.setLabel(newLabel+size);
+ return;
+ }
+ }
+ } catch (Exception e) {}
+ }
+
+ /** Adds a file path to the beginning of the File/Open Recent submenu. */
+ public static synchronized void addOpenRecentItem(String path) {
+ if (ij==null) return;
+ int count = openRecentMenu.getItemCount();
+ for (int i=0; iImport"); break;
+ case SAVE_AS_MENU: menu = getMenu("File>Save As"); break;
+ case SHORTCUTS_MENU: menu = shortcutsMenu; break;
+ case ABOUT_MENU: menu = getMenu("Help>About Plugins"); break;
+ case FILTERS_MENU: menu = getMenu("Process>Filters"); break;
+ case TOOLS_MENU: menu = getMenu("Analyze>Tools"); break;
+ case UTILITIES_MENU: menu = utilitiesMenu; break;
+ default: return 0;
+ }
+ int code = convertShortcutToCode(shortcut);
+ MenuItem item;
+ boolean functionKey = code>=KeyEvent.VK_F1 && code<=KeyEvent.VK_F12;
+ if (code==0)
+ item = new MenuItem(command);
+ else if (functionKey) {
+ command += " [F"+(code-KeyEvent.VK_F1+1)+"]";
+ shortcuts.put(Integer.valueOf(code),command);
+ item = new MenuItem(command);
+ } else {
+ shortcuts.put(Integer.valueOf(code),command);
+ int keyCode = code;
+ boolean shift = false;
+ if (keyCode>=265 && keyCode<=290) {
+ keyCode -= 200;
+ shift = true;
+ }
+ item = new MenuItem(command, new MenuShortcut(keyCode, shift));
+ }
+ menu.add(item);
+ item.addActionListener(ij);
+ pluginsTable.put(command, plugin);
+ shortcut = code>0 && !functionKey?"["+shortcut+"]":"";
+ pluginsPrefs.addElement(menuCode+",\""+command+shortcut+"\","+plugin);
+ return NORMAL_RETURN;
+ }
+
+ /** Deletes a command installed by Plugins/Shortcuts/Add Shortcut. */
+ public static int uninstallPlugin(String command) {
+ boolean found = false;
+ for (Enumeration en=pluginsPrefs.elements(); en.hasMoreElements();) {
+ String cmd = (String)en.nextElement();
+ if (cmd.contains(command)) {
+ boolean ok = pluginsPrefs.removeElement((Object)cmd);
+ found = true;
+ break;
+ }
+ }
+ if (found)
+ return NORMAL_RETURN;
+ else
+ return COMMAND_NOT_FOUND;
+
+ }
+
+ public static boolean commandInUse(String command) {
+ if (pluginsTable.get(command)!=null)
+ return true;
+ else
+ return false;
+ }
+
+ public static int convertShortcutToCode(String shortcut) {
+ int code = 0;
+ int len = shortcut.length();
+ if (len==2 && shortcut.charAt(0)=='F') {
+ code = KeyEvent.VK_F1+(int)shortcut.charAt(1)-49;
+ if (code>=KeyEvent.VK_F1 && code<=KeyEvent.VK_F9)
+ return code;
+ else
+ return 0;
+ }
+ if (len==3 && shortcut.charAt(0)=='F') {
+ code = KeyEvent.VK_F10+(int)shortcut.charAt(2)-48;
+ if (code>=KeyEvent.VK_F10 && code<=KeyEvent.VK_F12)
+ return code;
+ else
+ return 0;
+ }
+ if (len==2 && shortcut.charAt(0)=='N') { // numeric keypad
+ code = KeyEvent.VK_NUMPAD0+(int)shortcut.charAt(1)-48;
+ if (code>=KeyEvent.VK_NUMPAD0 && code<=KeyEvent.VK_NUMPAD9)
+ return code;
+ switch (shortcut.charAt(1)) {
+ case '/': return KeyEvent.VK_DIVIDE;
+ case '*': return KeyEvent.VK_MULTIPLY;
+ case '-': return KeyEvent.VK_SUBTRACT;
+ case '+': return KeyEvent.VK_ADD;
+ case '.': return KeyEvent.VK_DECIMAL;
+ default: return 0;
+ }
+ }
+ if (len!=1)
+ return 0;
+ int c = (int)shortcut.charAt(0);
+ if (c>=65&&c<=90) //A-Z
+ code = KeyEvent.VK_A+c-65 + 200;
+ else if (c>=97&&c<=122) //a-z
+ code = KeyEvent.VK_A+c-97;
+ else if (c>=48&&c<=57) //0-9
+ code = KeyEvent.VK_0+c-48;
+ return code;
+ }
+
+ void installStartupMacroSet() {
+ if (macrosPath==null) {
+ MacroInstaller.installFromJar("/macros/StartupMacros.txt");
+ return;
+ }
+ String path = macrosPath + "StartupMacros.txt";
+ File f = new File(path);
+ if (!f.exists()) {
+ path = macrosPath + "StartupMacros.ijm";
+ f = new File(path);
+ if (!f.exists()) {
+ (new MacroInstaller()).installFromIJJar("/macros/StartupMacros.txt");
+ return;
+ }
+ } else {
+ if ("StartupMacros.fiji.ijm".equals(f.getName()))
+ path = f.getPath();
+ }
+ String libraryPath = macrosPath + "Library.txt";
+ f = new File(libraryPath);
+ boolean isLibrary = f.exists();
+ try {
+ MacroInstaller mi = new MacroInstaller();
+ if (isLibrary) mi.installLibrary(libraryPath);
+ mi.installStartupMacros(path);
+ nMacros += mi.getMacroCount();
+ } catch (Exception e) {}
+ }
+
+ static boolean validShortcut(String shortcut) {
+ int len = shortcut.length();
+ if (shortcut.equals(""))
+ return true;
+ else if (len==1)
+ return true;
+ else if (shortcut.startsWith("F") && (len==2 || len==3))
+ return true;
+ else
+ return false;
+ }
+
+ /** Returns 'true' if this keyboard shortcut is in use. */
+ public static boolean shortcutInUse(String shortcut) {
+ int code = convertShortcutToCode(shortcut);
+ if (shortcuts.get(Integer.valueOf(code))!=null)
+ return true;
+ else
+ return false;
+ }
+
+ /** Set the size (in points) used for the fonts in ImageJ menus.
+ Set the size to 0 to use the Java default size. */
+ public static void setFontSize(int size) {
+ if (size<9 && size!=0) size = 9;
+ if (size>24) size = 24;
+ fontSize = size;
+ }
+
+ /** Returns the size (in points) used for the fonts in ImageJ menus. Returns
+ 0 if the default font size is being used or if this is a Macintosh. */
+ public static int getFontSize() {
+ return fontSize;
+ }
+
+ public static Font getFont() {
+ return getFont(true);
+ }
+
+ public static Font getFont(boolean checkSize) {
+ int size = fontSize==0?13:fontSize;
+ if (size<7)
+ size = 7;
+ if (scale>1.0 && !checkSize)
+ size = 13;
+ int size0 = size;
+ size = (int)Math.round(size*scale);
+ //if (cachedFont==null) System.out.println("getFont: "+size0+" "+size+" "+fontSize+" "+scale+" "+checkSize);
+ if (checkSize && IJ.isWindows() && size>17)
+ size = 17; // On Windows, the menu bar font size is set 12 if you set it to >17
+ Font menuFont = new Font("SanSerif", Font.PLAIN, size);
+ return menuFont;
+ }
+
+ public static Font getCachedFont() {
+ if (cachedFont==null)
+ cachedFont = getFont(false);
+ return cachedFont;
+ }
+
+ /** Called once when ImageJ quits. */
+ public static void savePreferences(Properties prefs) {
+ if (pluginsPrefs==null)
+ return;
+ int index = 0;
+ for (Enumeration en=pluginsPrefs.elements(); en.hasMoreElements();) {
+ String key = "plugin" + (index/10)%10 + index%10;
+ String value = (String)en.nextElement();
+ prefs.put(key, value);
+ index++;
+ }
+ int n = openRecentMenu.getItemCount();
+ for (int i=0; i");
+ if (index==-1 || index==menuPath.length()-1)
+ return;
+ String label = menuPath.substring(index+1, menuPath.length());
+ menuPath = menuPath.substring(0, index);
+ pluginsTable.put(label, plugin);
+ addItem(getMenu(menuPath), label, 0, false);
+ }
+
+ /** Work around Windows bug that limits menu bar sub-menu to 17 points. */
+ private static void fixFontSize(MenuItem item) {
+ if (IJ.isWindows() && item!=null)
+ item.setFont(getCachedFont());
+ }
+
+}
diff --git a/mrj/26/ij/Prefs.java b/mrj/26/ij/Prefs.java
new file mode 100644
index 00000000..ba6ee38b
--- /dev/null
+++ b/mrj/26/ij/Prefs.java
@@ -0,0 +1,833 @@
+package ij;
+import ij.stub.Applet;
+import ij.util.Java2;
+import java.io.*;
+import java.util.*;
+import java.net.URL;
+import java.awt.*;
+import ij.io.*;
+import ij.util.Tools;
+import ij.gui.*;
+import ij.plugin.filter.*;
+import ij.process.ImageConverter;
+import ij.plugin.Animator;
+import ij.process.FloatBlitter;
+import ij.plugin.GelAnalyzer;
+import ij.process.ColorProcessor;
+import ij.text.TextWindow;
+
+/**
+This class contains the ImageJ preferences, which are
+loaded from the "IJ_Props.txt" and "IJ_Prefs.txt" files.
+@see ImageJ
+*/
+public class Prefs {
+
+ public static final String PROPS_NAME = "IJ_Props.txt";
+ public static final String PREFS_NAME = "IJ_Prefs.txt";
+ public static final String DIR_IMAGE = "dir.image";
+ public static final String FCOLOR = "fcolor";
+ public static final String BCOLOR = "bcolor";
+ public static final String ROICOLOR = "roicolor";
+ public static final String SHOW_ALL_COLOR = "showcolor";
+ public static final String JPEG = "jpeg";
+ public static final String FPS = "fps";
+ public static final String DIV_BY_ZERO_VALUE = "div-by-zero";
+ public static final String NOISE_SD = "noise.sd";
+ public static final String MENU_SIZE = "menu.size";
+ public static final String GUI_SCALE = "gui.scale";
+ public static final String THREADS = "threads";
+ public static final String KEY_PREFIX = ".";
+
+ private static final int USE_POINTER=1<<0, ANTIALIASING=1<<1, INTERPOLATE=1<<2, ONE_HUNDRED_PERCENT=1<<3,
+ BLACK_BACKGROUND=1<<4, JFILE_CHOOSER=1<<5, UNUSED=1<<6, BLACK_CANVAS=1<<7, WEIGHTED=1<<8,
+ AUTO_MEASURE=1<<9, REQUIRE_CONTROL=1<<10, USE_INVERTING_LUT=1<<11, ANTIALIASED_TOOLS=1<<12,
+ INTEL_BYTE_ORDER=1<<13, DOUBLE_BUFFER=1<<14, NO_POINT_LABELS=1<<15, NO_BORDER=1<<16,
+ SHOW_ALL_SLICE_ONLY=1<<17, COPY_HEADERS=1<<18, NO_ROW_NUMBERS=1<<19,
+ MOVE_TO_MISC=1<<20, ADD_TO_MANAGER=1<<21, RUN_SOCKET_LISTENER=1<<22,
+ MULTI_POINT_MODE=1<<23, ROTATE_YZ=1<<24, FLIP_XZ=1<<25,
+ DONT_SAVE_HEADERS=1<<26, DONT_SAVE_ROW_NUMBERS=1<<27, NO_CLICK_TO_GC=1<<28,
+ AVOID_RESLICE_INTERPOLATION=1<<29, KEEP_UNDO_BUFFERS=1<<30;
+ public static final String OPTIONS = "prefs.options";
+
+ public static final String vistaHint = ""; // no longer used
+
+ private static final int USE_SYSTEM_PROXIES=1<<0, USE_FILE_CHOOSER=1<<1,
+ SUBPIXEL_RESOLUTION=1<<2, ENHANCED_LINE_TOOL=1<<3, SKIP_RAW_DIALOG=1<<4,
+ REVERSE_NEXT_PREVIOUS_ORDER=1<<5, AUTO_RUN_EXAMPLES=1<<6, SHOW_ALL_POINTS=1<<7,
+ DO_NOT_SAVE_WINDOW_LOCS=1<<8, JFILE_CHOOSER_CHANGED=1<<9,
+ CANCEL_BUTTON_ON_RIGHT=1<<10, IGNORE_RESCALE_SLOPE=1<<11,
+ NON_BLOCKING_DIALOGS=1<<12, FIXED_DICOM_SCALING=1<<13,
+ CALIBRATE_CONVERSIONS=1<<14;
+ public static final String OPTIONS2 = "prefs.options2";
+
+ /** file.separator system property */
+ public static String separator = System.getProperty("file.separator");
+ /** Use pointer cursor instead of cross */
+ public static boolean usePointerCursor;
+ /** No longer used */
+ public static boolean antialiasedText;
+ /** Display images scaled <100% using bilinear interpolation */
+ public static boolean interpolateScaledImages;
+ /** Open images at 100% magnification*/
+ public static boolean open100Percent;
+ /** Backgound is black in binary images*/
+ public static boolean blackBackground;
+ /** Use JFileChooser instead of FileDialog to open and save files. */
+ public static boolean useJFileChooser;
+ /** Color to grayscale conversion is weighted (0.299, 0.587, 0.114) if the variable is true. */
+ public static boolean weightedColor;
+ /** Use black image border. */
+ public static boolean blackCanvas;
+ /** Point tool auto-measure mode. */
+ public static boolean pointAutoMeasure;
+ /** Point tool auto-next slice mode (not saved in IJ_Prefs). */
+ public static boolean pointAutoNextSlice;
+ /** Require control or command key for keybaord shortcuts. */
+ public static boolean requireControlKey;
+ /** Open 8-bit images with inverting LUT so 0 is white and 255 is black. */
+ public static boolean useInvertingLut;
+ /** Draw tool icons using antialiasing (always true). */
+ public static boolean antialiasedTools = true;
+ /** Export TIFF and Raw using little-endian byte order. */
+ public static boolean intelByteOrder = true;
+ /** No longer used */
+ public static boolean doubleBuffer = true;
+ /** Do not label multiple points created using point tool. */
+ public static boolean noPointLabels;
+ /** Disable Edit/Undo command. */
+ public static boolean disableUndo;
+ /** Do not draw black border around image. */
+ public static boolean noBorder;
+ /** Only show ROIs associated with current slice in Roi Manager "Show All" mode. */
+ public static boolean showAllSliceOnly = true;
+ /** Include column headers when copying tables to clipboard. */
+ public static boolean copyColumnHeaders;
+ /** Do not include row numbers when copying tables to clipboard. */
+ public static boolean noRowNumbers;
+ /** Move isolated plugins to Miscellaneous submenu. */
+ public static boolean moveToMisc;
+ /** Add points to ROI Manager. */
+ public static boolean pointAddToManager;
+ /** Add points to overlay. */
+ public static boolean pointAddToOverlay;
+ /** Extend the borders to foreground for binary erosions and closings. */
+ public static boolean padEdges;
+ /** Run the SocketListener. */
+ public static boolean runSocketListener;
+ /** Use MultiPoint tool. */
+ public static boolean multiPointMode;
+ /** Open DICOMs as 32-bit float images */
+ public static boolean openDicomsAsFloat;
+ /** Ignore Rescale Slope when opening DICOMs */
+ public static boolean ignoreRescaleSlope;
+ /** Assume DICOM volumes use identical RescaleSlope and RescaleIntercept across all slices */
+ public static boolean fixedDicomScaling;
+ /** Plot rectangular selectons vertically */
+ public static boolean verticalProfile;
+ /** Rotate YZ orthogonal views 90 degrees */
+ public static boolean rotateYZ;
+ /** Rotate XZ orthogonal views 180 degrees */
+ public static boolean flipXZ;
+ /** Don't save Results table column headers */
+ public static boolean dontSaveHeaders;
+ /** Don't save Results table row numbers */
+ public static boolean dontSaveRowNumbers;
+ /** Don't run garbage collector when user clicks in status bar */
+ public static boolean noClickToGC;
+ /** Angle tool measures reflex angle */
+ public static boolean reflexAngle;
+ /** Avoid interpolation when re-slicing */
+ public static boolean avoidResliceInterpolation;
+ /** Preserve undo (snapshot) buffers when switching images */
+ public static boolean keepUndoBuffers;
+ /** Use ROI names as "show all" labels in the ROI Manager */
+ public static boolean useNamesAsLabels;
+ /** Set the "java.net.useSystemProxies" property */
+ public static boolean useSystemProxies;
+ /** Use the file chooser to import and export image sequences on Windows and Linux*/
+ public static boolean useFileChooser;
+ /** Use sub-pixel resolution with line selections */
+ public static boolean subPixelResolution;
+ /** Adjust contrast when scrolling stacks */
+ public static boolean autoContrast;
+ /** Allow lines to be created with one click at start and another at the end */
+ public static boolean enhancedLineTool;
+ /** Keep arrow selection after adding to overlay */
+ public static boolean keepArrowSelections;
+ /** Aways paint images using double buffering */
+ public static boolean paintDoubleBuffered;
+ /** Do not display dialog when opening .raw files */
+ public static boolean skipRawDialog;
+ /** Reverse channel-slice-frame priority used by Next Slice and Previous Slice commands. */
+ public static boolean reverseNextPreviousOrder;
+ /** Automatically run examples in Help/Examples menu. */
+ public static boolean autoRunExamples = true;
+ /** Ignore stack positions when displaying points. */
+ public static boolean showAllPoints;
+ /** Show ImageJ menu bar on image window activation on Macs. */
+ public static boolean setIJMenuBar = IJ.isMacOSX();
+ /** "ImageJ" window is always on top. */
+ public static boolean alwaysOnTop;
+ /** Automatically spline fit line selections */
+ public static boolean splineFitLines;
+ /** Enable this option to workaround a bug with some Linux window
+ managers that causes windows to wander down the screen. */
+ public static boolean doNotSaveWindowLocations;
+ /** Use JFileChooser setting changed/ */
+ public static boolean jFileChooserSettingChanged;
+ /** Convert tiff units to microns if pixel width is less than 0.0001 cm. */
+ public static boolean convertToMicrons = true;
+ /** Wand tool "Smooth if thresholded" option */
+ public static boolean smoothWand;
+ /** "Close All" command running */
+ public static boolean closingAll;
+ /** Dialog "Cancel" button is on right on Linux */
+ public static boolean dialogCancelButtonOnRight;
+ /** Support TRANSFORM Undo in macros */
+ public static boolean supportMacroUndo;
+ /** Use NonBlockingGenericDialogs in filters */
+ public static boolean nonBlockingFilterDialogs;
+ /** Turn live display on plots automatically */
+ public static boolean autoLivePlots;
+ /** Use full range for 16-bit inversions */
+ public static boolean fullRange16bitInversions;
+ /** Calibrate image type conversions */
+ public static boolean calibrateConversions;
+ /** Open grayscale RGB JPEGs as RGB */
+ public static boolean openGrayscaleJpegsAsRGB;
+ /** Scroll stacks using mouse wheel */
+ public static boolean mouseWheelStackScrolling = true;
+
+ //Save location of moved image windows */
+ //public static boolean saveImageLocation = true;
+
+ static boolean commandLineMacro;
+ static Properties ijPrefs = new Properties();
+ static Properties props = new Properties(ijPrefs);
+ static String prefsDir;
+ static String imagesURL;
+ static String ImageJDir;
+ static String pluginsDirProperty;
+ static int threads;
+ static int transparentIndex = -1;
+ private static boolean resetPreferences;
+ private static double guiScale = 1.0;
+ private static Properties locKeys = new Properties();
+ private static String propertiesPath; // location of custom IJ_Props.txt
+ private static String preferencesPath; // location of custom IJ_Prefs.txt
+
+ /** Saves the value of the string text in the preferences
+ * file using the keyword key. The string can be
+ * retrieved using the appropriate get() method.
+ * @see #get(String,String)
+ */
+ public static void set(String key, String text) {
+ if (key.indexOf('.')<1)
+ throw new IllegalArgumentException("Key must have a prefix");
+ if (text==null)
+ ijPrefs.remove(KEY_PREFIX+key);
+ else
+ ijPrefs.put(KEY_PREFIX+key, text);
+ }
+
+ /** Saves the value of the integer value in the preferences
+ * file using the keyword key. The value can be
+ * retrieved using the appropriate get() method.
+ * @see #get(String,double)
+ */
+ public static void set(String key, int value) {
+ set(key, Integer.toString(value));
+ }
+
+ /** Saves the value of the double value in the preferences
+ * file using the keyword key. The value can be
+ * retrieved using the appropriate get() method.
+ * @see #get(String,double)
+ */
+ public static void set(String key, double value) {
+ set(key, ""+value);
+ }
+
+ /** Saves the value of the boolean value in the preferences
+ * file using the keyword key. The value can be
+ * retrieved using the appropriate get() method.
+ * @see #get(String,boolean)
+ */
+ public static void set(String key, boolean value) {
+ set(key, ""+value);
+ }
+
+ /** Uses the keyword key to retrieve a string from the
+ preferences file. Returns defaultValue if the key
+ is not found. */
+ public static String get(String key, String defaultValue) {
+ String value = ijPrefs.getProperty(KEY_PREFIX+key);
+ if (value == null)
+ return defaultValue;
+ else
+ return value;
+ }
+
+ /** Uses the keyword key to retrieve a number from the
+ preferences file. Returns defaultValue if the key
+ is not found. */
+ public static double get(String key, double defaultValue) {
+ String s = ijPrefs.getProperty(KEY_PREFIX+key);
+ Double d = null;
+ if (s!=null) {
+ try {d = Double.valueOf(s);}
+ catch (NumberFormatException e) {d = null;}
+ if (d!=null)
+ return(d.doubleValue());
+ }
+ return defaultValue;
+ }
+
+ /** Uses the keyword key to retrieve a boolean from
+ the preferences file. Returns defaultValue if
+ the key is not found. */
+ public static boolean get(String key, boolean defaultValue) {
+ String value = ijPrefs.getProperty(KEY_PREFIX+key);
+ if (value==null)
+ return defaultValue;
+ else
+ return value.equals("true");
+ }
+
+ /**
+ * Finds and loads the configuration file ("IJ_Props.txt")
+ * and the preferences file ("IJ_Prefs.txt").
+ *
+ * @param ij
+ * @return an error message if "IJ_Props.txt" not found.
+ */
+ public static String load(Object ij) {
+ return load(ij, null);
+ }
+
+ /** Finds and loads the configuration file ("IJ_Props.txt")
+ * and the preferences file ("IJ_Prefs.txt").
+ * @return an error message if "IJ_Props.txt" not found.
+ */
+ @Deprecated(since = "IJ XX; Java 26")
+ public static String load(Object ij, Applet applet) {
+ if (ImageJDir==null)
+ ImageJDir = System.getProperty("user.dir");
+ if (ij!=null) {
+ InputStream f = null;
+ try { // Look for IJ_Props.txt in ImageJ folder
+ f = new FileInputStream(ImageJDir+"/"+PROPS_NAME);
+ propertiesPath = ImageJDir+"/"+PROPS_NAME;
+ } catch (FileNotFoundException e) {
+ f = null;
+ }
+ if (f==null) {
+ // Look in ij.jar if not found in ImageJ folder
+ f = ij.getClass().getResourceAsStream("/"+PROPS_NAME);
+ }
+ if (applet!=null)
+ return loadAppletProps(f, applet);
+ if (f==null)
+ return PROPS_NAME+" not found in ij.jar or in "+ImageJDir;
+ f = new BufferedInputStream(f);
+ try {
+ props.load(f);
+ f.close();
+ } catch (IOException e) {
+ return("Error loading "+PROPS_NAME);
+ }
+ imagesURL = props.getProperty(IJ.isJava18()?"images.location":"images.location2");
+ }
+ loadPreferences();
+ loadOptions();
+ guiScale = get(GUI_SCALE, 1.0);
+ return null;
+ }
+
+ /*
+ static void dumpPrefs() {
+ System.out.println("");
+ Enumeration e = ijPrefs.keys();
+ while (e.hasMoreElements()) {
+ String key = (String) e.nextElement();
+ System.out.println(key+": "+ijPrefs.getProperty(key));
+ }
+ }
+ */
+
+ @Deprecated(since = "IJ XX; Java 26")
+ static String loadAppletProps(InputStream f, Applet applet) {
+ if (f==null)
+ return PROPS_NAME+" not found in ij.jar";
+ try {
+ props.load(f);
+ f.close();
+ }
+ catch (IOException e) {return("Error loading "+PROPS_NAME);}
+ try {
+ URL url = new URL(applet.getDocumentBase(), "images/");
+ imagesURL = url.toString();
+ }
+ catch (Exception e) {}
+ return null;
+ }
+
+ /** Returns the URL of the directory that contains the ImageJ sample images. */
+ public static String getImagesURL() {
+ return imagesURL;
+ }
+
+ /** Sets the URL of the directory that contains the ImageJ sample images. */
+ public static void setImagesURL(String url) {
+ imagesURL = url;
+ }
+
+ /** Obsolete, replaced by getImageJDir(), which, unlike this method,
+ returns a path that ends with File.separator. */
+ public static String getHomeDir() {
+ return ImageJDir;
+ }
+
+ /** Returns the path, ending in File.separator, to the ImageJ directory. */
+ public static String getImageJDir() {
+ String path = Menus.getImageJPath();
+ if (path==null) {
+ String ijPath = ImageJDir;
+ if (ijPath==null)
+ ijPath = getPluginsDirProperty();
+ if (ijPath==null)
+ ijPath = System.getProperty("user.dir");
+ return ijPath + File.separator;
+ } else
+ return path;
+ }
+
+ public static String getPluginsDirProperty() {
+ if (pluginsDirProperty==null) {
+ String ijDir = System.getProperty("plugins.dir");
+ if (ijDir!=null) {
+ if (ijDir.endsWith("/")||ijDir.endsWith("\\"))
+ ijDir = ijDir.substring(0, ijDir.length()-1);
+ if (ijDir.endsWith("/plugins")||ijDir.endsWith("\\plugins"))
+ ijDir = ijDir.substring(0, ijDir.length()-8);
+ pluginsDirProperty = ijDir;
+ } else
+ pluginsDirProperty = "";
+ }
+ return pluginsDirProperty.length()>0?pluginsDirProperty:null;
+ }
+
+ /** Returns the path to the directory where the
+ preferences file (IJPrefs.txt) is saved. */
+ public static String getPrefsDir() {
+ // look in current directory
+ if (prefsDir==null) {
+ String cwd = System.getProperty("user.dir");
+ File f = new File(cwd+File.separator+PREFS_NAME);
+ if (f.exists()) {
+ prefsDir = cwd;
+ preferencesPath = cwd+"/"+PREFS_NAME;
+ }
+ // look in ImageJ directory
+ if (prefsDir==null) {
+ String ijDir = getImageJDir();
+ ijDir = ijDir.substring(0, ijDir.length()-1);
+ f = new File(ijDir+File.separator+PREFS_NAME);
+ if (f.exists()) {
+ prefsDir = ijDir;
+ preferencesPath = ijDir+"/"+PREFS_NAME;
+ }
+ }
+ // use home directory
+ if (prefsDir==null) {
+ String dir = System.getProperty("user.home");
+ if (IJ.isMacOSX())
+ dir += "/Library/Preferences";
+ else
+ dir += File.separator+".imagej";
+ prefsDir = dir;
+ }
+ }
+ return prefsDir;
+ }
+
+ /** Sets the path to the ImageJ directory. */
+ static void setHomeDir(String path) {
+ if (path.endsWith(File.separator) || path.endsWith("/"))
+ path = path.substring(0, path.length()-1);
+ ImageJDir = path;
+ }
+
+ /** Returns the default directory, if any, or null. */
+ public static String getDefaultDirectory() {
+ if (commandLineMacro)
+ return null;
+ else
+ return getString(DIR_IMAGE);
+ }
+
+ /** Returns the file.separator system property. */
+ public static String getFileSeparator() {
+ return separator;
+ }
+
+ /** Opens the ImageJ preferences file ("IJ_Prefs.txt") file. */
+ static void loadPreferences() {
+ String path = getPrefsDir()+separator+PREFS_NAME;
+ boolean ok = loadPrefs(path);
+ if (!ok) { // not found
+ if (IJ.isWindows())
+ path = ImageJDir +separator+PREFS_NAME;
+ else
+ path = System.getProperty("user.home")+separator+PREFS_NAME; //User's home dir
+ ok = loadPrefs(path);
+ if (ok)
+ new File(path).delete();
+ }
+
+ }
+
+ static boolean loadPrefs(String path) {
+ try {
+ InputStream is = new BufferedInputStream(new FileInputStream(path));
+ ijPrefs.load(is);
+ is.close();
+ return true;
+ } catch (Exception e) {
+ return false;
+ }
+ }
+
+ /** Saves user preferences in the IJ_Prefs.txt properties file. */
+ public static void savePreferences() {
+ String path = null;
+ commandLineMacro = false;
+ try {
+ Properties prefs = new Properties();
+ String dir = OpenDialog.getDefaultDirectory();
+ if (dir!=null)
+ prefs.put(DIR_IMAGE, dir);
+ prefs.put(ROICOLOR, Tools.c2hex(Roi.getColor()));
+ prefs.put(SHOW_ALL_COLOR, Tools.c2hex(ImageCanvas.getShowAllColor()));
+ prefs.put(FCOLOR, Tools.c2hex(Toolbar.getForegroundColor()));
+ prefs.put(BCOLOR, Tools.c2hex(Toolbar.getBackgroundColor()));
+ prefs.put(JPEG, Integer.toString(FileSaver.getJpegQuality()));
+ prefs.put(FPS, Double.toString(Animator.getFrameRate()));
+ prefs.put(DIV_BY_ZERO_VALUE, Double.toString(FloatBlitter.divideByZeroValue));
+ prefs.put(NOISE_SD, Double.toString(Filters.getSD()));
+ if (threads>1) prefs.put(THREADS, Integer.toString(threads));
+ if (IJ.isMacOSX()) useJFileChooser = false;
+ if (!IJ.isLinux()) dialogCancelButtonOnRight = false;
+ saveOptions(prefs);
+ savePluginPrefs(prefs);
+ ImageJ ij = IJ.getInstance();
+ if (ij!=null)
+ ij.savePreferences(prefs);
+ Menus.savePreferences(prefs);
+ ParticleAnalyzer.savePreferences(prefs);
+ Analyzer.savePreferences(prefs);
+ ImportDialog.savePreferences(prefs);
+ PlotWindow.savePreferences(prefs);
+ NewImage.savePreferences(prefs);
+ String prefsDir = getPrefsDir();
+ path = prefsDir+separator+PREFS_NAME;
+ if (prefsDir.endsWith(".imagej")) {
+ File f = new File(prefsDir);
+ if (!f.exists()) f.mkdir(); // create .imagej directory
+ }
+ if (resetPreferences) {
+ File f = new File(path);
+ if (!f.exists())
+ IJ.error("Edit>Options>Reset", "Unable to reset preferences. File not found at\n"+path);
+ boolean rtn = f.delete();
+ resetPreferences = false;
+ } else
+ savePrefs(prefs, path);
+ } catch (Throwable t) {
+ String msg = t.getMessage();
+ if (msg==null) msg = ""+t;
+ int delay = 4000;
+ try {
+ new TextWindow("Error Saving Preferences:\n"+path, msg, 500, 200);
+ IJ.wait(delay);
+ } catch (Throwable t2) {}
+ }
+ }
+
+ /** Delete the preferences file when ImageJ quits. */
+ public static void resetPreferences() {
+ resetPreferences = true;
+ }
+
+ static void loadOptions() {
+ int defaultOptions = ANTIALIASING+AVOID_RESLICE_INTERPOLATION+ANTIALIASED_TOOLS+MULTI_POINT_MODE
+ +(!IJ.isMacOSX()?RUN_SOCKET_LISTENER:0)+BLACK_BACKGROUND;
+ int options = getInt(OPTIONS, defaultOptions);
+ usePointerCursor = (options&USE_POINTER)!=0;
+ //antialiasedText = (options&ANTIALIASING)!=0;
+ antialiasedText = false;
+ interpolateScaledImages = (options&INTERPOLATE)!=0;
+ open100Percent = (options&ONE_HUNDRED_PERCENT)!=0;
+ blackBackground = (options&BLACK_BACKGROUND)!=0;
+ useJFileChooser = (options&JFILE_CHOOSER)!=0;
+ weightedColor = (options&WEIGHTED)!=0;
+ if (weightedColor)
+ ColorProcessor.setWeightingFactors(0.299, 0.587, 0.114);
+ blackCanvas = (options&BLACK_CANVAS)!=0;
+ requireControlKey = (options&REQUIRE_CONTROL)!=0;
+ useInvertingLut = (options&USE_INVERTING_LUT)!=0;
+ intelByteOrder = (options&INTEL_BYTE_ORDER)!=0;
+ noBorder = (options&NO_BORDER)!=0;
+ //showAllSliceOnly = (options&SHOW_ALL_SLICE_ONLY)!=0;
+ copyColumnHeaders = (options©_HEADERS)!=0;
+ noRowNumbers = (options&NO_ROW_NUMBERS)!=0;
+ moveToMisc = (options&MOVE_TO_MISC)!=0;
+ runSocketListener = (options&RUN_SOCKET_LISTENER)!=0;
+ multiPointMode = (options&MULTI_POINT_MODE)!=0;
+ rotateYZ = (options&ROTATE_YZ)!=0;
+ flipXZ = (options&FLIP_XZ)!=0;
+ //dontSaveHeaders = (options&DONT_SAVE_HEADERS)!=0;
+ //dontSaveRowNumbers = (options&DONT_SAVE_ROW_NUMBERS)!=0;
+ noClickToGC = (options&NO_CLICK_TO_GC)!=0;
+ avoidResliceInterpolation = (options&AVOID_RESLICE_INTERPOLATION)!=0;
+ keepUndoBuffers = (options&KEEP_UNDO_BUFFERS)!=0;
+
+ defaultOptions = (!IJ.isMacOSX()?USE_FILE_CHOOSER:0);
+ int options2 = getInt(OPTIONS2, defaultOptions);
+ useSystemProxies = (options2&USE_SYSTEM_PROXIES)!=0;
+ useFileChooser = (options2&USE_FILE_CHOOSER)!=0;
+ subPixelResolution = (options2&SUBPIXEL_RESOLUTION)!=0;
+ enhancedLineTool = (options2&ENHANCED_LINE_TOOL)!=0;
+ skipRawDialog = (options2&SKIP_RAW_DIALOG)!=0;
+ reverseNextPreviousOrder = (options2&REVERSE_NEXT_PREVIOUS_ORDER)!=0;
+ autoRunExamples = (options2&AUTO_RUN_EXAMPLES)!=0;
+ showAllPoints = (options2&SHOW_ALL_POINTS)!=0;
+ doNotSaveWindowLocations = (options2&DO_NOT_SAVE_WINDOW_LOCS)!=0;
+ jFileChooserSettingChanged = (options2&JFILE_CHOOSER_CHANGED)!=0;
+ dialogCancelButtonOnRight = (options2&CANCEL_BUTTON_ON_RIGHT)!=0;
+ ignoreRescaleSlope = (options2&IGNORE_RESCALE_SLOPE)!=0;
+ nonBlockingFilterDialogs = (options2&NON_BLOCKING_DIALOGS)!=0;
+ fixedDicomScaling = (options2&FIXED_DICOM_SCALING)!=0;
+ //calibrateConversions = (options2&CALIBRATE_CONVERSIONS)!=0;
+ }
+
+ static void saveOptions(Properties prefs) {
+ int options = (usePointerCursor?USE_POINTER:0) + (antialiasedText?ANTIALIASING:0)
+ + (interpolateScaledImages?INTERPOLATE:0) + (open100Percent?ONE_HUNDRED_PERCENT:0)
+ + (blackBackground?BLACK_BACKGROUND:0) + (useJFileChooser?JFILE_CHOOSER:0)
+ + (blackCanvas?BLACK_CANVAS:0) + (weightedColor?WEIGHTED:0)
+ + (requireControlKey?REQUIRE_CONTROL:0)
+ + (useInvertingLut?USE_INVERTING_LUT:0)
+ + (intelByteOrder?INTEL_BYTE_ORDER:0) + (doubleBuffer?DOUBLE_BUFFER:0)
+ + (noPointLabels?NO_POINT_LABELS:0) + (noBorder?NO_BORDER:0)
+ + (showAllSliceOnly?SHOW_ALL_SLICE_ONLY:0) + (copyColumnHeaders?COPY_HEADERS:0)
+ + (noRowNumbers?NO_ROW_NUMBERS:0) + (moveToMisc?MOVE_TO_MISC:0)
+ + (runSocketListener?RUN_SOCKET_LISTENER:0)
+ + (multiPointMode?MULTI_POINT_MODE:0) + (rotateYZ?ROTATE_YZ:0)
+ + (flipXZ?FLIP_XZ:0) + (dontSaveHeaders?DONT_SAVE_HEADERS:0)
+ + (dontSaveRowNumbers?DONT_SAVE_ROW_NUMBERS:0) + (noClickToGC?NO_CLICK_TO_GC:0)
+ + (avoidResliceInterpolation?AVOID_RESLICE_INTERPOLATION:0)
+ + (keepUndoBuffers?KEEP_UNDO_BUFFERS:0);
+ prefs.put(OPTIONS, Integer.toString(options));
+
+ int options2 = (useSystemProxies?USE_SYSTEM_PROXIES:0)
+ + (useFileChooser?USE_FILE_CHOOSER:0) + (subPixelResolution?SUBPIXEL_RESOLUTION:0)
+ + (enhancedLineTool?ENHANCED_LINE_TOOL:0) + (skipRawDialog?SKIP_RAW_DIALOG:0)
+ + (reverseNextPreviousOrder?REVERSE_NEXT_PREVIOUS_ORDER:0)
+ + (autoRunExamples?AUTO_RUN_EXAMPLES:0) + (showAllPoints?SHOW_ALL_POINTS:0)
+ + (doNotSaveWindowLocations?DO_NOT_SAVE_WINDOW_LOCS:0)
+ + (jFileChooserSettingChanged?JFILE_CHOOSER_CHANGED:0)
+ + (dialogCancelButtonOnRight?CANCEL_BUTTON_ON_RIGHT:0)
+ + (ignoreRescaleSlope?IGNORE_RESCALE_SLOPE:0)
+ + (nonBlockingFilterDialogs?NON_BLOCKING_DIALOGS:0)
+ + (fixedDicomScaling?FIXED_DICOM_SCALING:0);
+ //+ (calibrateConversions?CALIBRATE_CONVERSIONS:0);
+ prefs.put(OPTIONS2, Integer.toString(options2));
+ }
+
+ /** Saves the Point loc in the preferences
+ file as a string using the keyword key. */
+ public static void saveLocation(String key, Point loc) {
+ if (!doNotSaveWindowLocations)
+ set(key, loc!=null?loc.x+","+loc.y:null);
+ }
+
+ /** Uses the keyword key to retrieve a location
+ from the preferences file. Returns null if the
+ key is not found or the location is not valid (e.g., offscreen). */
+ public static Point getLocation(String key) {
+ String value = ijPrefs.getProperty(KEY_PREFIX+key);
+ if (value==null) return null;
+ int index = value.indexOf(",");
+ if (index==-1) return null;
+ double xloc = Tools.parseDouble(value.substring(0, index));
+ if (Double.isNaN(xloc) || index==value.length()-1) return null;
+ double yloc = Tools.parseDouble(value.substring(index+1));
+ if (Double.isNaN(yloc)) return null;
+ Point p = new Point((int)xloc, (int)yloc);
+ Rectangle bounds = GUI.getScreenBounds(p); // get bounds of screen that contains p
+ if (bounds!=null && p.x+100<=bounds.x+bounds.width && p.y+ 40<=bounds.y+bounds.height) {
+ if (locKeys.get(key)==null) { // first time for this key?
+ locKeys.setProperty(key, "");
+ Rectangle primaryScreen = GUI.getMaxWindowBounds();
+ ImageJ ij = IJ.getInstance();
+ Point ijLoc = ij!=null?ij.getLocation():null;
+ //System.out.println("getLoc: "+key+" "+(ijLoc!=null&&primaryScreen.contains(ijLoc)) + " "+!primaryScreen.contains(p));
+ if ((ijLoc!=null&&primaryScreen.contains(ijLoc)) && !primaryScreen.contains(p))
+ return null; // return null if "ImageJ" window on primary screen and this location is not
+ }
+ return p;
+ } else
+ return null;
+ }
+
+ /** Save plugin preferences. */
+ static void savePluginPrefs(Properties prefs) {
+ Enumeration e = ijPrefs.keys();
+ while (e.hasMoreElements()) {
+ String key = (String) e.nextElement();
+ if (key.indexOf(KEY_PREFIX) == 0)
+ prefs.put(key, ijPrefs.getProperty(key));
+ }
+ }
+
+ public static void savePrefs(Properties prefs, String path) throws IOException{
+ FileOutputStream fos = new FileOutputStream(path);
+ BufferedOutputStream bos = new BufferedOutputStream(fos);
+ prefs.store(bos, "ImageJ "+ImageJ.VERSION+" Preferences");
+ bos.close();
+ }
+
+ /** Returns the number of threads used by PlugInFilters to process images and stacks. */
+ public static int getThreads() {
+ if (threads==0) {
+ threads = getInt(THREADS, 0);
+ int processors = Runtime.getRuntime().availableProcessors();
+ if (threads<1 || threads>processors)
+ threads = processors;
+ }
+ return threads;
+ }
+
+ /** Sets the number of threads (1-32) used by PlugInFilters to process stacks. */
+ public static void setThreads(int n) {
+ if (n<1) n = 1;
+ threads = n;
+ }
+
+ /** Sets the transparent index (0-255), or set to -1 to disable transparency. */
+ public static void setTransparentIndex(int index) {
+ if (index<-1 || index>255) index = -1;
+ transparentIndex = index;
+ }
+
+ /** Returns the transparent index (0-255), or -1 if transparency is disabled. */
+ public static int getTransparentIndex() {
+ return transparentIndex;
+ }
+
+ public static Properties getControlPanelProperties() {
+ return ijPrefs;
+ }
+
+ public static String defaultResultsExtension() {
+ return get("options.ext", ".csv");
+ }
+
+ /** Sets the GenericDialog and Command Finder text scale (0.5 to 3.0). */
+ public static void setGuiScale(double scale) {
+ if (scale>=0.5 && scale<=3.0) {
+ guiScale = scale;
+ set(GUI_SCALE, guiScale);
+ Roi.resetDefaultHandleSize();
+ }
+ }
+
+ /** Returns the GenericDialog and Command Finder text scale. */
+ public static double getGuiScale() {
+ return guiScale;
+ }
+
+ /** Returns the custom properties (IJ_Props.txt) file path. */
+ public static String getCustomPropsPath() {
+ return propertiesPath;
+ }
+
+ /** Returns the custom preferences (IJ_Prefs.txt) file path. */
+ public static String getCustomPrefsPath() {
+ return preferencesPath;
+ }
+
+ /** Retrieves a string from IJ_Props or IJ_Prefs.txt.
+ Does not retrieve strings set using Prefs.set(). */
+ public static String getString(String key, String defaultString) {
+ if (props==null)
+ return defaultString;
+ String s = props.getProperty(key);
+ if (s==null)
+ return defaultString;
+ else
+ return s;
+ }
+
+ /** Retrieves a string from string in IJ_Props or IJ_Prefs.txt. */
+ public static String getString(String key) {
+ return props.getProperty(key);
+ }
+
+ /** Retrieves a number from IJ_Props or IJ_Prefs.txt.
+ Does not retrieve numbers set using Prefs.set(). */
+ public static int getInt(String key, int defaultValue) {
+ if (props==null) //workaround for Netscape JIT bug
+ return defaultValue;
+ String s = props.getProperty(key);
+ if (s!=null) {
+ try {
+ return Integer.decode(s).intValue();
+ } catch (NumberFormatException e) {IJ.log(""+e);}
+ }
+ return defaultValue;
+ }
+
+ /** Retrieves a number from IJ_Props or IJ_Prefs.txt.
+ Does not retrieve numbers set using Prefs.set(). */
+ public static double getDouble(String key, double defaultValue) {
+ if (props==null)
+ return defaultValue;
+ String s = props.getProperty(key);
+ Double d = null;
+ if (s!=null) {
+ try {d = Double.valueOf(s);}
+ catch (NumberFormatException e){d = null;}
+ if (d!=null)
+ return(d.doubleValue());
+ }
+ return defaultValue;
+ }
+
+ /** Retrieves a boolean from IJ_Props or IJ_Prefs.txt.
+ Does not retrieve boolean set using Prefs.set(). */
+ public static boolean getBoolean(String key, boolean defaultValue) {
+ if (props==null) return defaultValue;
+ String s = props.getProperty(key);
+ if (s==null)
+ return defaultValue;
+ else
+ return s.equals("true");
+ }
+
+ /** Finds a color in IJ_Props or IJ_Prefs.txt. */
+ public static Color getColor(String key, Color defaultColor) {
+ int i = getInt(key, 0xaaa);
+ if (i == 0xaaa)
+ return defaultColor;
+ return new Color((i >> 16) & 0xFF, (i >> 8) & 0xFF, i & 0xFF);
+ }
+
+ public static boolean commandLineMacro() {
+ return commandLineMacro;
+ }
+
+}
+
diff --git a/mrj/26/ij/WindowManager.java b/mrj/26/ij/WindowManager.java
new file mode 100644
index 00000000..ba944c5a
--- /dev/null
+++ b/mrj/26/ij/WindowManager.java
@@ -0,0 +1,657 @@
+package ij;
+
+import java.awt.CheckboxMenuItem;
+import java.awt.Dialog;
+import java.awt.Frame;
+import java.awt.KeyboardFocusManager;
+import java.awt.MenuItem;
+import java.awt.Window;
+import java.util.ArrayList;
+import java.util.Hashtable;
+import java.util.Vector;
+
+import ij.gui.HistogramWindow;
+import ij.gui.ImageWindow;
+import ij.gui.PlotWindow;
+import ij.macro.Interpreter;
+import ij.plugin.frame.Commands;
+import ij.plugin.frame.Editor;
+import ij.plugin.frame.PlugInFrame;
+import ij.plugin.frame.Recorder;
+import ij.text.TextWindow;
+import ij.util.Tools;
+
+/** This class consists of static methods used to manage ImageJ's windows. */
+public class WindowManager {
+
+ public static boolean checkForDuplicateName;
+ private static Vector imageList = new Vector(); // list of image windows
+ private static Vector activations = new Vector(); // list of image windows, ordered by activation time
+ private static Vector nonImageList = new Vector(); // list of non-image windows (Frames and Dialogs)
+ private static ImageWindow currentWindow; // active image window
+ private static Window frontWindow;
+ private static Window frontTable;
+ private static Frame frontFrame;
+ private static Hashtable tempImageTable = new Hashtable();
+
+ private WindowManager() {
+ }
+
+ /** Makes the image contained in the specified window the active image. */
+ public static void setCurrentWindow(ImageWindow win) {
+ if (win==null || win.isClosed() || win.getImagePlus()==null) // deadlock-"wait to lock"
+ return;
+ //IJ.log("setCurrentWindow: "+win.getImagePlus().getTitle()+" ("+(currentWindow!=null?currentWindow.getImagePlus().getTitle():"null") + ")");
+ setWindow(win);
+ tempImageTable.remove(Thread.currentThread());
+ if (win==currentWindow || imageList.size()==0)
+ return;
+ if (currentWindow!=null) {
+ // free up pixel buffers used by current window
+ ij.ImagePlus imp = currentWindow.getImagePlus();
+ if (imp!=null ) {
+ if (!Prefs.keepUndoBuffers)
+ imp.trimProcessor();
+ imp.saveRoi();
+ }
+ }
+ ij.Undo.reset();
+ currentWindow = win;
+ activations.remove(win);
+ activations.add(win);
+ Menus.updateMenus();
+ if (IJ.recording() && !IJ.isMacro())
+ Recorder.record("selectImage", win.getImagePlus().getTitle());
+ }
+
+ /** Returns the active ImageWindow. */
+ public static ImageWindow getCurrentWindow() {
+ return currentWindow;
+ }
+
+ static int getCurrentIndex() {
+ return imageList.indexOf(currentWindow);
+ }
+
+ /** Returns a reference to the active image or null if there isn't one.
+ * @see IJ#getImage
+ */
+ public static ij.ImagePlus getCurrentImage() {
+ ij.ImagePlus img = (ij.ImagePlus)tempImageTable.get(Thread.currentThread());
+ //String str = (img==null)?" null":"";
+ if (img==null)
+ img = getActiveImage();
+ //if (img!=null) IJ.log("getCurrentImage: "+img.getTitle()+" "+Thread.currentThread().hashCode()+str);
+ return img;
+ }
+
+ /** Makes the specified image temporarily the active
+ image for this thread. Call again with a null
+ argument to revert to the previous active image. */
+ public static void setTempCurrentImage(ij.ImagePlus img) {
+ //IJ.log("setTempImage: "+(img!=null?""+img:"null")+" "+Thread.currentThread().hashCode());
+ if (img==null)
+ tempImageTable.remove(Thread.currentThread());
+ else
+ tempImageTable.put(Thread.currentThread(), img);
+ }
+
+ /** Sets a temporary image for the specified thread. */
+ public static void setTempCurrentImage(Thread thread, ij.ImagePlus img) {
+ if (thread==null)
+ throw new RuntimeException("thread==null");
+ if (img==null)
+ tempImageTable.remove(thread);
+ else
+ tempImageTable.put(thread, img);
+ }
+
+ /** Returns the active ImagePlus. */
+ private static ij.ImagePlus getActiveImage() {
+ if (currentWindow!=null)
+ return currentWindow.getImagePlus();
+ else if (frontWindow!=null && (frontWindow instanceof ImageWindow))
+ return frontWindow!=null?((ImageWindow)frontWindow).getImagePlus():null;
+ else if (imageList.size()>0) {
+ ij.ImagePlus imp = getFocusManagerActiveImage();
+ if (imp!=null)
+ return imp;
+ ImageWindow win = (ImageWindow)imageList.get(imageList.size()-1);
+ return win.getImagePlus();
+ } else
+ return Interpreter.getLastBatchModeImage();
+ }
+
+ private static ij.ImagePlus getFocusManagerActiveImage() {
+ if (IJ.isMacro())
+ return null;
+ KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager();
+ Window win = kfm.getActiveWindow();
+ ij.ImagePlus imp = null;
+ if (win!=null && (win instanceof ImageWindow))
+ imp = ((ImageWindow)win).getImagePlus();
+ return imp;
+ }
+
+ /** Returns the number of open image windows. */
+ public static int getWindowCount() {
+ int count = imageList.size();
+ return count;
+ }
+
+ /** Returns the number of open images. */
+ public static int getImageCount() {
+ int count = imageList.size();
+ count += Interpreter.getBatchModeImageCount();
+ if (count==0 && getCurrentImage()!=null)
+ count = 1;
+ return count;
+ }
+
+ /** Returns the front most window or null. */
+ public static Window getActiveWindow() {
+ return frontWindow;
+ }
+
+ /** Returns the Window containing the active table, or null.
+ * @see ij.measure.ResultsTable#getActiveTable
+ */
+ public static Window getActiveTable() {
+ return frontTable;
+ }
+
+ /** Obsolete; replaced by getActiveWindow. */
+ public static Frame getFrontWindow() {
+ return frontFrame;
+ }
+
+ /** Returns a list of the IDs of open images. Returns
+ null if no image windows are open. */
+ public synchronized static int[] getIDList() {
+ int nWindows = imageList.size();
+ int[] batchModeImages = Interpreter.getBatchModeImageIDs();
+ int nBatchImages = batchModeImages.length;
+ if ((nWindows+nBatchImages)==0)
+ return null;
+ int[] list = new int[nWindows+nBatchImages];
+ for (int i=0; i0)
+ imageID = getNthImageID(imageID);
+ if (imageID==0 || getImageCount()==0)
+ return null;
+ ij.ImagePlus imp2 = Interpreter.getBatchModeImage(imageID);
+ if (imp2!=null)
+ return imp2;
+ ij.ImagePlus imp = null;
+ for (int i=0; ilist.length)
+ return 0;
+ else
+ return list[n-1];
+ } else {
+ if (n>imageList.size()) return 0;
+ ImageWindow win = (ImageWindow)imageList.get(n-1);
+ if (win!=null)
+ return win.getImagePlus().getID();
+ else
+ return 0;
+ }
+ }
+
+
+ /** Returns the first image that has the specified title or null if it is not found. */
+ public synchronized static ij.ImagePlus getImage(String title) {
+ int[] wList = getIDList();
+ if (wList==null) return null;
+ for (int i=0; i=0) {
+ Menus.removeWindowMenuItem(index);
+ nonImageList.removeElement(win);
+ }
+ if (win!=null && win==frontTable)
+ frontTable = null;
+ }
+ setWindow(null);
+ }
+
+ /** Removes the specified Frame from the Window menu. */
+ public static void removeWindow(Frame win) {
+ removeWindow((Window)win);
+ }
+
+ private static void removeImageWindow(ImageWindow win) {
+ int index = imageList.indexOf(win);
+ if (index==-1)
+ return; // not on the window list
+ try {
+ synchronized(WindowManager.class) {
+ imageList.remove(win);
+ }
+ activations.remove(win);
+ if (imageList.size()>1 && !Prefs.closingAll) {
+ ImageWindow win2 = activations.size()>0?(ImageWindow)activations.get(activations.size()-1):null;
+ setCurrentWindow(win2);
+ } else
+ currentWindow = null;
+ setTempCurrentImage(null); //???
+ int nonImageCount = nonImageList.size();
+ if (nonImageCount>0)
+ nonImageCount++;
+ Menus.removeWindowMenuItem(nonImageCount+index);
+ Menus.updateMenus();
+ ij.Undo.reset();
+ } catch (Exception e) { }
+ }
+
+ /** The specified Window becomes the front window. */
+ public static void setWindow(Window win) {
+ //System.out.println("setWindow(W): "+win);
+ frontWindow = win;
+ if (win instanceof Frame)
+ frontFrame = (Frame)win;
+ }
+
+ /** The specified frame becomes the front window, the one returnd by getFrontWindow(). */
+ public static void setWindow(Frame win) {
+ frontWindow = win;
+ frontFrame = win;
+ if (win!=null && win instanceof TextWindow && !(win instanceof Editor) && !"Log".equals(((TextWindow)win).getTitle()))
+ frontTable = win;
+ //System.out.println("Set window(F): "+(win!=null?win.getTitle():"null"));
+ }
+
+ /** Closes all windows. Stops and returns false if an image or Editor "save changes" dialog is canceled. */
+ public synchronized static boolean closeAllWindows() {
+ Prefs.closingAll = true;
+ while (imageList.size()>0) {
+ if (!((ImageWindow)imageList.get(0)).close()) {
+ Prefs.closingAll = false;
+ return false;
+ }
+ if (!quittingViaMacro())
+ IJ.wait(100);
+ }
+ Prefs.closingAll = false;
+ Frame[] nonImages = getNonImageWindows();
+ for (int i=0; i0) // remove image size (e.g., " 90K")
+ menuItemLabel = menuItemLabel.substring(0, lastSpace);
+ String idString = item.getActionCommand();
+ int id = (int)Tools.parseDouble(idString, 0);
+ ij.ImagePlus imp = WindowManager.getImage(id);
+ if (imp==null) return;
+ ImageWindow win1 = imp.getWindow();
+ if (win1==null) return;
+ setCurrentWindow(win1);
+ toFront(win1);
+ int index = imageList.indexOf(win1);
+ int n = Menus.window.getItemCount();
+ int start = Menus.WINDOW_MENU_ITEMS+Menus.windowMenuItems2;
+ for (int j=start; j1.0) {
+ TEXT_GAP = (int)(TEXT_GAP*SCALE);
+ textGap = centerOnScreen?0:TEXT_GAP;
+ }
+ if (Prefs.blackCanvas && getClass().getName().equals("ij.gui.ImageWindow")) {
+ setForeground(Color.white);
+ setBackground(Color.black);
+ } else {
+ setForeground(Color.black);
+ if (IJ.isLinux())
+ setBackground(ImageJ.backgroundColor);
+ else
+ setBackground(Color.white);
+ }
+ boolean openAsHyperStack = imp.getOpenAsHyperStack();
+ ij = IJ.getInstance();
+ this.imp = imp;
+ if (ic==null) {
+ ic = (this instanceof ij.gui.PlotWindow) ? new ij.gui.PlotCanvas(imp) : new ij.gui.ImageCanvas(imp);
+ newCanvas=true;
+ }
+ this.ic = ic;
+ ImageWindow previousWindow = imp.getWindow();
+ setLayout(new ij.gui.ImageLayout(ic));
+ add(ic);
+ addFocusListener(this);
+ addWindowListener(this);
+ addWindowStateListener(this);
+ addKeyListener(ij);
+ setFocusTraversalKeysEnabled(false);
+ if (!(this instanceof ij.gui.StackWindow))
+ addMouseWheelListener(this);
+ setResizable(true);
+ if (!(this instanceof ij.gui.HistogramWindow &&IJ.isMacro()&&Interpreter.isBatchMode())) {
+ WindowManager.addWindow(this);
+ imp.setWindow(this);
+ }
+ if (previousWindow!=null) {
+ if (newCanvas)
+ setLocationAndSize(false);
+ else
+ ic.update(previousWindow.getCanvas());
+ Point loc = previousWindow.getLocation();
+ setLocation(loc.x, loc.y);
+ if (!(this instanceof ij.gui.StackWindow || this instanceof ij.gui.PlotWindow)) { //layout now unless components will be added later
+ pack();
+ if (IJ.isMacro())
+ imp.setDeactivated(); //prepare for waitTillActivated (imp may have been activated before if it gets a new Window now)
+ show();
+ }
+ if (ic.getMagnification()!=0.0)
+ imp.setTitle(imp.getTitle());
+ boolean unlocked = imp.lockSilently();
+ boolean changes = imp.changes;
+ imp.changes = false;
+ previousWindow.close();
+ imp.changes = changes;
+ if (unlocked)
+ imp.unlock();
+ if (this.imp!=null)
+ this.imp.setOpenAsHyperStack(openAsHyperStack);
+ WindowManager.setCurrentWindow(this);
+ } else {
+ setLocationAndSize(false);
+ if (ij!=null && !IJ.isMacintosh()) {
+ Image img = ij.getIconImage();
+ if (img!=null) try {
+ setIconImage(img);
+ } catch (Exception e) {}
+ }
+ if (nextLocation!=null)
+ setLocation(nextLocation);
+ else if (centerOnScreen)
+ GUI.center(this);
+ nextLocation = null;
+ centerOnScreen = false;
+ if (Interpreter.isBatchMode() || (IJ.getInstance()==null&&this instanceof ij.gui.HistogramWindow)) {
+ WindowManager.setTempCurrentImage(imp);
+ Interpreter.addBatchModeImage(imp);
+ } else {
+ if (IJ.isMacro())
+ imp.setDeactivated(); //prepare for waitTillActivated (imp may have been activated previously and gets a new Window now)
+ show();
+ }
+ }
+ }
+
+ private void setLocationAndSize(boolean updating) {
+ if (imp==null)
+ return;
+ int width = imp.getWidth();
+ int height = imp.getHeight();
+
+ // load preferences file location
+ Point loc = Prefs.getLocation(LOC_KEY);
+ Rectangle bounds = null;
+ if (loc!=null) {
+ bounds = GUI.getMaxWindowBounds(loc);
+ if (bounds!=null && (loc.x>bounds.x+bounds.width/3||loc.y>bounds.y+bounds.height/3)
+ && (loc.x+width>bounds.x+bounds.width||loc.y+height>bounds.y+bounds.height)) {
+ loc = null;
+ bounds = null;
+ }
+ }
+ // if loc not valid, use screen bounds of visible window (this) or of main window (ij) if not visible yet (updating == false)
+ Rectangle maxWindow = bounds!=null?bounds: GUI.getMaxWindowBounds(updating?this: ij);
+
+ if (WindowManager.getWindowCount()<=1)
+ xbase = -1;
+ if (width>maxWindow.width/2 && xbase>maxWindow.x+5+XINC*6)
+ xbase = -1;
+ if (xbase==-1) {
+ count = 0;
+ if (loc!=null) {
+ xbase = loc.x;
+ ybase = loc.y;
+ } else if (ij!=null) {
+ Rectangle ijBounds = ij.getBounds();
+ if (ijBounds.y-maxWindow.xmaxWindow.x+maxWindow.width) {
+ xbase = maxWindow.x+maxWindow.width - width - 10;
+ if (xbasescreenWidth || ybase+height*mag>=screenHeight) {
+ double mag2 = ImageCanvas.getLowerZoomLevel(mag);
+ if (mag2==mag) break;
+ mag = mag2;
+ }
+ }
+
+ if (mag<1.0) {
+ initialMagnification = mag;
+ ic.setSize((int)(width*mag), (int)(height*mag));
+ }
+ ic.setMagnification(mag);
+ if (y+height*mag>screenHeight)
+ y = ybase;
+ if (Prefs.open100Percent && ic.getMagnification()<1.0) {
+ while(ic.getMagnification()<1.0)
+ ic.zoomIn(0, 0);
+ setSize(Math.min(width, screenWidth-x), Math.min(height, screenHeight-y));
+ validate();
+ } else
+ pack();
+ if (!updating)
+ setLocation(x, y);
+ }
+
+ Rectangle getMaxWindow(int xloc, int yloc) {
+ return GUI.getMaxWindowBounds(new Point(xloc, yloc));
+ }
+
+ public double getInitialMagnification() {
+ return initialMagnification;
+ }
+
+ public Insets getInsets() {
+ return getInsets(true);
+ }
+
+ /** Override Container getInsets() to make room for some text above the image.
+ * With "includeSmallImageMargins", also includes the margins for padding an image
+ * that is too small for the window size. */
+ public Insets getInsets(boolean includeSmallImageMargins) {
+ Insets insets = super.getInsets();
+ if (imp==null)
+ return insets;
+ double mag = ic.getMagnification();
+ int extraWidth = 0, extraHeight = 0;
+ if (includeSmallImageMargins) {
+ extraWidth = (int)((MIN_WIDTH - imp.getWidth()*mag)/2.0);
+ if (extraWidth<0) extraWidth = 0;
+ extraHeight = (int)((MIN_HEIGHT - imp.getHeight()*mag)/2.0);
+ if (extraHeight<0) extraHeight = 0;
+ }
+ insets = new Insets(insets.top+textGap+extraHeight, insets.left+extraWidth, insets.bottom+extraHeight, insets.right+extraWidth);
+ return insets;
+ }
+
+ /** Draws the subtitle. */
+ public void drawInfo(Graphics g) {
+ if (imp==null)
+ return;
+ if (textGap!=0) {
+ Insets insets = super.getInsets();
+ Color savec = null;
+ if (imp.isComposite()) {
+ CompositeImage ci = (CompositeImage)imp;
+ if (ci.getMode()==IJ.COMPOSITE) {
+ savec = g.getColor();
+ Color c = ci.getChannelColor();
+ if (Color.green.equals(c))
+ c = new Color(0,180,0);
+ g.setColor(c);
+ }
+ }
+ Java2.setAntialiasedText(g, true);
+ if (SCALE>1.0) {
+ Font font = new Font("SansSerif", Font.PLAIN, (int)(12*SCALE));
+ g.setFont(font);
+ }
+ g.drawString(createSubtitle(), insets.left+5, insets.top+TEXT_GAP);
+ if (savec!=null)
+ g.setColor(savec);
+ }
+ }
+
+ /** Creates the subtitle. */
+ public String createSubtitle() {
+ String s="";
+ if (imp==null)
+ return s;
+ int stackSize = imp.getStackSize();
+ if (stackSize>1) {
+ ImageStack stack = imp.getStack();
+ int currentSlice = imp.getCurrentSlice();
+ s += currentSlice+"/"+stackSize;
+ String label = stack.getShortSliceLabel(currentSlice);
+ if (label!=null && label.length()>0) {
+ if (imp.isHyperStack()) label = label.replace(';', ' ');
+ s += " (" + label + ")";
+ }
+ if ((this instanceof ij.gui.StackWindow) && running2) {
+ return s;
+ }
+ s += "; ";
+ } else {
+ String label = imp.getProp("Slice_Label");
+ if (label==null && imp.hasImageStack())
+ label = imp.getStack().getSliceLabel(1);
+ if (label!=null && label.length()>0) {
+ int newline = label.indexOf('\n');
+ if (newline>0)
+ label = label.substring(0, newline);
+ int len = label.length();
+ if (len>4 && label.charAt(len-4)=='.' && !Character.isDigit(label.charAt(len-1)))
+ label = label.substring(0,len-4);
+ if (label.length()>60)
+ label = label.substring(0, 60)+"...";
+ s = "\""+label + "\"; ";
+ }
+ }
+ int type = imp.getType();
+ Calibration cal = imp.getCalibration();
+ if (cal.scaled()) {
+ boolean unitsMatch = cal.getXUnit().equals(cal.getYUnit());
+ double cwidth = imp.getWidth()*cal.pixelWidth;
+ double cheight = imp.getHeight()*cal.pixelHeight;
+ int digits = Tools.getDecimalPlaces(cwidth, cheight);
+ if (digits>2) digits=2;
+ if (unitsMatch) {
+ s += IJ.d2s(cwidth,digits) + "x" + IJ.d2s(cheight,digits)
+ + " " + cal.getUnits() + " (" + imp.getWidth() + "x" + imp.getHeight() + "); ";
+ } else {
+ s += d2s(cwidth) + " " + cal.getXUnit() + " x "
+ + d2s(cheight) + " " + cal.getYUnit()
+ + " (" + imp.getWidth() + "x" + imp.getHeight() + "); ";
+ }
+ } else
+ s += imp.getWidth() + "x" + imp.getHeight() + " pixels; ";
+ switch (type) {
+ case ImagePlus.GRAY8:
+ case ImagePlus.COLOR_256:
+ s += "8-bit";
+ break;
+ case ImagePlus.GRAY16:
+ s += "16-bit";
+ break;
+ case ImagePlus.GRAY32:
+ s += "32-bit";
+ break;
+ case ImagePlus.COLOR_RGB:
+ s += imp.isRGB() ? "RGB" : "32-bit (int)";
+ break;
+ }
+ if (imp.isInvertedLut())
+ s += " (inverting LUT)";
+ return s+"; "+getImageSize(imp);
+ }
+
+ public static String getImageSize(ImagePlus imp) {
+ if (imp==null)
+ return null;
+ double size = imp.getSizeInBytes()/1024.0;
+ String s2=null, s3=null;
+ if (size<1024.0)
+ {s2=IJ.d2s(size,0); s3="K";}
+ else if (size<10000.0)
+ {s2=IJ.d2s(size/1024.0,1); s3="MB";}
+ else if (size<1048576.0)
+ {s2=IJ.d2s(Math.round(size/1024.0),0); s3="MB";}
+ else
+ {s2=IJ.d2s(size/1048576.0,1); s3="GB";}
+ if (s2.endsWith(".0")) s2 = s2.substring(0, s2.length()-2);
+ return s2+s3;
+ }
+
+ private String d2s(double n) {
+ int digits = Tools.getDecimalPlaces(n);
+ if (digits>2) digits=2;
+ return IJ.d2s(n,digits);
+ }
+
+ public void paint(Graphics g) {
+ drawInfo(g);
+ Rectangle r = ic.getBounds();
+ int extraWidth = MIN_WIDTH - r.width;
+ int extraHeight = MIN_HEIGHT - r.height;
+ if (extraWidth<=0 && extraHeight<=0 && !Prefs.noBorder && !IJ.isLinux())
+ g.drawRect(r.x-1, r.y-1, r.width+1, r.height+1);
+ }
+
+ /** Removes this window from the window list and disposes of it.
+ Returns false if the user cancels the "save changes" dialog. */
+ public boolean close() {
+ boolean isRunning = running || running2;
+ running = running2 = false;
+ if (imp==null) return true;
+ boolean virtual = imp.getStackSize()>1 && imp.getStack().isVirtual();
+ if (isRunning) IJ.wait(500);
+ if (imp==null) return true;
+ boolean changes = imp.changes;
+ ij.gui.Roi roi = imp.getRoi();
+ if (roi!=null && (roi instanceof ij.gui.PointRoi) && ((ij.gui.PointRoi)roi).promptBeforeDeleting())
+ changes = true;
+ if (ij==null || ij.quittingViaMacro() || IJ.getApplet()!=null || Interpreter.isBatchMode() || IJ.macroRunning() || virtual)
+ changes = false;
+ if (changes) {
+ String msg;
+ String name = imp.getTitle();
+ if (name.length()>22)
+ msg = "Save changes to\n" + "\"" + name + "\"?";
+ else
+ msg = "Save changes to \"" + name + "\"?";
+ if (imp.isLocked())
+ msg += "\nWARNING: This image is locked.\nProbably, processing is unfinished (slow or still previewing).";
+ toFront();
+ ij.gui.YesNoCancelDialog d = new ij.gui.YesNoCancelDialog(this, "ImageJ", msg);
+ if (d.cancelPressed())
+ return false;
+ else if (d.yesPressed()) {
+ FileSaver fs = new FileSaver(imp);
+ if (!fs.save()) return false;
+ }
+ }
+ closed = true;
+ if (WindowManager.getWindowCount()==0) {
+ xloc = 0;
+ yloc = 0;
+ }
+ WindowManager.removeWindow(this);
+ if (ij!=null && ij.quitting()) // this may help avoid thread deadlocks
+ return true;
+ Rectangle bounds = getBounds();
+ if (!IJ.isMacro()
+ && bounds.y0)
+ sw.removeScrollbars();
+ else if (stackSize>1 && nScrollbars==0)
+ sw.addScrollbars(imp);
+ }
+ pack();
+ repaint();
+ maxBounds = getMaximumBounds();
+ setMaximizedBounds(maxBounds);
+ setMaxBoundsTime = System.currentTimeMillis();
+ }
+
+ public ij.gui.ImageCanvas getCanvas() {
+ return ic;
+ }
+
+
+ static ImagePlus getClipboard() {
+ return ImagePlus.getClipboard();
+ }
+
+ public Rectangle getMaximumBounds() {
+ Rectangle maxWindow = GUI.getMaxWindowBounds(this);
+ if (imp==null)
+ return maxWindow;
+ double width = imp.getWidth();
+ double height = imp.getHeight();
+ double iAspectRatio = width/height;
+ maxWindowBounds = maxWindow;
+ if (iAspectRatio/((double)maxWindow.width/maxWindow.height)>0.75) {
+ maxWindow.y += 22; // uncover ImageJ menu bar
+ maxWindow.height -= 22;
+ }
+ Dimension extraSize = getExtraSize();
+ double maxWidth = maxWindow.width-extraSize.width;
+ double maxHeight = maxWindow.height-extraSize.height;
+ double mAspectRatio = maxWidth/maxHeight;
+ int wWidth, wHeight;
+ double mag;
+ if (iAspectRatio>=mAspectRatio) {
+ mag = maxWidth/width;
+ wWidth = maxWindow.width;
+ wHeight = (int)(height*mag+extraSize.height);
+ } else {
+ mag = maxHeight/height;
+ wHeight = maxWindow.height;
+ wWidth = (int)(width*mag+extraSize.width);
+ }
+ int xloc = (int)(maxWidth-wWidth)/2;
+ if (xlocmaxWindow.x+maxWindow.width-wWidth)
+ xloc = maxWindow.x;
+ wWidth = Math.min(wWidth, maxWindow.x-xloc+maxWindow.width);
+ wHeight = Math.min(wHeight, maxWindow.height);
+ return new Rectangle(xloc, maxWindow.y, wWidth, wHeight);
+ }
+
+ Dimension getExtraSize() {
+ Insets insets = getInsets();
+ int extraWidth = insets.left+insets.right + 10;
+ int extraHeight = insets.top+insets.bottom + 10;
+ if (extraHeight==20) extraHeight = 42;
+ int members = getComponentCount();
+ for (int i=1; iwidth) srcRect.x = width-srcRect.width;
+ } else {
+ srcRect.y += rotation*amount*Math.max(height/200, 1);
+ if (srcRect.y<0) srcRect.y = 0;
+ if (srcRect.y+srcRect.height>height) srcRect.y = height-srcRect.height;
+ }
+ if (srcRect.x!=xstart || srcRect.y!=ystart)
+ ic.repaint();
+ }
+
+ /** Copies the current ROI to the clipboard. The entire
+ image is copied if there is no ROI. */
+ public void copy(boolean cut) {
+ imp.copy(cut);
+ }
+
+
+ public void paste() {
+ imp.paste();
+ }
+
+ /** This method is called by ImageCanvas.mouseMoved(MouseEvent).
+ @see ij.gui.ImageCanvas#mouseMoved
+ */
+ public void mouseMoved(int x, int y) {
+ imp.mouseMoved(x, y);
+ }
+
+ public String toString() {
+ return imp!=null?imp.getTitle():"";
+ }
+
+ /** Causes the next image to be opened to be centered on the screen
+ and displayed without informational text above the image. */
+ public static void centerNextImage() {
+ centerOnScreen = true;
+ }
+
+ /** Causes the next image to be displayed at the specified location. */
+ public static void setNextLocation(Point loc) {
+ nextLocation = loc;
+ }
+
+ /** Causes the next image to be displayed at the specified location. */
+ public static void setNextLocation(int x, int y) {
+ nextLocation = new Point(x, y);
+ }
+
+ /** Moves and resizes this window. Changes the
+ magnification so the image fills the window. */
+ public void setLocationAndSize(int x, int y, int width, int height) {
+ setBounds(x, y, width, height);
+ getCanvas().fitToWindow();
+ pack();
+ }
+
+ @Override
+ public void setLocation(int x, int y) {
+ super.setLocation(x, y);
+ }
+
+ public void setSliderHeight(int height) {
+ sliderHeight = height;
+ }
+
+ public int getSliderHeight() {
+ return sliderHeight;
+ }
+
+ public static void setImageJMenuBar(ImageWindow win) {
+ ImageJ ij = IJ.getInstance();
+ boolean setMenuBar = true;
+ ImagePlus imp = win.getImagePlus();
+ if (imp!=null)
+ setMenuBar = imp.setIJMenuBar();
+ MenuBar mb = Menus.getMenuBar();
+ if (mb!=null && mb==win.getMenuBar())
+ setMenuBar = false;
+ setMenuBarTime = 0L;
+ if (setMenuBar && ij!=null && !ij.quitting()) {
+ IJ.wait(10); // may be needed for Java 1.4 on OS X
+ long t0 = System.currentTimeMillis();
+ win.setMenuBar(mb);
+ long time = System.currentTimeMillis()-t0;
+ setMenuBarTime = time;
+ Menus.setMenuBarCount++;
+ if (time>2000L)
+ Prefs.setIJMenuBar = false;
+ }
+ if (imp!=null) imp.setIJMenuBar(true);
+ }
+
+} //class ImageWindow
diff --git a/mrj/26/ij/gui/Toolbar.java b/mrj/26/ij/gui/Toolbar.java
new file mode 100644
index 00000000..fc5b58bf
--- /dev/null
+++ b/mrj/26/ij/gui/Toolbar.java
@@ -0,0 +1,2166 @@
+package ij.gui;
+
+import java.awt.BasicStroke;
+import java.awt.Canvas;
+import java.awt.CheckboxMenuItem;
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Event;
+import java.awt.Font;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.Menu;
+import java.awt.MenuBar;
+import java.awt.MenuItem;
+import java.awt.Polygon;
+import java.awt.PopupMenu;
+import java.awt.RenderingHints;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.ItemEvent;
+import java.awt.event.ItemListener;
+import java.awt.event.KeyEvent;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+import java.awt.event.MouseMotionListener;
+import java.awt.image.BufferedImage;
+import java.io.File;
+import java.util.Arrays;
+import java.util.Hashtable;
+import java.util.Locale;
+import java.util.Timer;
+import java.util.TimerTask;
+
+import javax.imageio.ImageIO;
+
+import ij.IJ;
+import ij.IJEventListener;
+import ij.ImageJ;
+import ij.ImagePlus;
+import ij.Menus;
+import ij.Prefs;
+import ij.WindowManager;
+import ij.macro.Program;
+import ij.plugin.MacroInstaller;
+import ij.plugin.frame.*;
+import ij.plugin.tool.MacroToolRunner;
+import ij.plugin.tool.PlugInTool;
+
+/** The ImageJ toolbar. */
+public class Toolbar extends Canvas implements MouseListener, MouseMotionListener, ItemListener, ActionListener {
+
+ public static final int RECTANGLE = 0;
+ public static final int OVAL = 1;
+ public static final int POLYGON = 2;
+ public static final int FREEROI = 3;
+ public static final int LINE = 4;
+ public static final int POLYLINE = 5;
+ public static final int FREELINE = 6;
+ public static final int POINT = 7, CROSSHAIR = 7;
+ public static final int WAND = 8;
+ public static final int TEXT = 9;
+ public static final int UNUSED = 10;
+ public static final int MAGNIFIER = 11;
+ public static final int HAND = 12;
+ public static final int DROPPER = 13;
+ public static final int ANGLE = 14;
+ public static final int CUSTOM1 = 15;
+ public static final int CUSTOM2 = 16;
+ public static final int CUSTOM3 = 17;
+ public static final int CUSTOM4 = 18;
+ public static final int CUSTOM5 = 19;
+ public static final int CUSTOM6 = 20;
+ public static final int CUSTOM7 = 21;
+
+ public static final int DOUBLE_CLICK_THRESHOLD = 650; //ms
+
+ public static final int RECT_ROI=0, ROUNDED_RECT_ROI=1, ROTATED_RECT_ROI=2;
+ public static final int OVAL_ROI=0, ELLIPSE_ROI=1, BRUSH_ROI=2;
+
+ public static final String[] builtInTools = {"Arrow","Brush","Command Finder", "Developer Menu","Flood Filler",
+ "Label Maker","LUT Menu","Overlay Brush","Pencil","Pixel Inspector","Selection Rotator",
+ "Spray Can","Stacks Menu","ROI Menu"};
+ private static final String[] builtInTools2 = {"Pixel Inspection Tool","Paintbrush Tool","Flood Fill Tool"};
+
+ private static final int NUM_TOOLS = 23;
+ private static final int MAX_EXTRA_TOOLS = 8;
+ private static final int MAX_TOOLS = NUM_TOOLS+MAX_EXTRA_TOOLS;
+ private static final int NUM_BUTTONS = 21;
+ private static final int BUTTON_WIDTH = 30;
+ private static final int BUTTON_HEIGHT = 31;
+ private static final int SIZE = 28; // no longer used
+ private static final int GAP_SIZE = 9;
+ private static final int OFFSET = 7;
+ private static final String BRUSH_SIZE = "toolbar.brush.size";
+ public static final String CORNER_DIAMETER = "toolbar.arc.size";
+ public static String TOOL_KEY = "toolbar.tool";
+
+ private Dimension ps;
+ private boolean[] down;
+ private static int current;
+ private int previousTool;
+ private int x,y;
+ private int xOffset, yOffset;
+ private long mouseDownTime;
+ private Graphics g;
+ private static Toolbar instance;
+ private int mpPrevious = RECTANGLE;
+ private String[] names = new String[MAX_TOOLS];
+ private String[] icons = new String[MAX_TOOLS];
+ private PlugInTool[] tools = new PlugInTool[MAX_TOOLS];
+ private PopupMenu[] menus = new PopupMenu[MAX_TOOLS];
+ private int nExtraTools;
+ private MacroInstaller macroInstaller;
+ private boolean addingSingleTool;
+ private boolean installingStartupTool;
+ private boolean doNotSavePrefs;
+ private int pc;
+ private String icon;
+ private int startupTime;
+ private PopupMenu rectPopup, ovalPopup, pointPopup, linePopup, zoomPopup, pickerPopup, switchPopup;
+ private CheckboxMenuItem rectItem, roundRectItem, rotatedRectItem;
+ private CheckboxMenuItem ovalItem, ellipseItem, brushItem;
+ private CheckboxMenuItem pointItem, multiPointItem;
+ private CheckboxMenuItem straightLineItem, polyLineItem, freeLineItem, arrowItem;
+ private String currentSet = "Startup Macros";
+ private Timer pressTimer;
+ private static int longClickDelay = 600; //ms
+ private boolean disableRecording;
+
+ private static Color foregroundColor = Prefs.getColor(Prefs.FCOLOR,Color.white);
+ private static Color backgroundColor = Prefs.getColor(Prefs.BCOLOR,Color.black);
+ private static double foregroundValue = Double.NaN;
+ private static double backgroundValue = Double.NaN;
+ private static int ovalType = OVAL_ROI;
+ private static int rectType = RECT_ROI;
+ private static boolean multiPointMode = Prefs.multiPointMode;
+ private static boolean arrowMode;
+ private static int brushSize = (int)Prefs.get(BRUSH_SIZE, 15);
+ private static int arcSize = (int)Prefs.get(CORNER_DIAMETER, 20);
+ private int lineType = LINE;
+ private static boolean legacyMode;
+ private static double dscale = 1.0;
+ private static int scale = 1;
+ private static int buttonWidth;
+ private static int buttonHeight;
+ private static int gapSize;
+ private static int offset;
+
+ private Color gray = new Color(228,228,228);
+ private Color brighter = gray.brighter();
+ private Color darker = new Color(180, 180, 180);
+ private Color evenDarker = new Color(110, 110, 110);
+ private Color triangleColor = new Color(150, 0, 0);
+ private Color toolColor = new Color(0, 25, 45);
+
+ /** Obsolete public constants */
+ public static final int SPARE1=UNUSED, SPARE2=CUSTOM1, SPARE3=CUSTOM2, SPARE4=CUSTOM3,
+ SPARE5=CUSTOM4, SPARE6=CUSTOM5, SPARE7=CUSTOM6, SPARE8=CUSTOM7, SPARE9=22;
+
+
+ public Toolbar() {
+ init();
+ down = new boolean[MAX_TOOLS];
+ resetButtons();
+ down[0] = true;
+ setForeground(Color.black);
+ setBackground(ImageJ.backgroundColor);
+ addMouseListener(this);
+ addMouseMotionListener(this);
+ instance = this;
+ names[getNumTools()-1] = "\"More Tools\" menu (switch toolsets or add tools)";
+ icons[getNumTools()-1] = "C900T0d18>T6d18>"; // ">>"
+ addPopupMenus();
+ }
+
+ public void init() {
+ dscale = Prefs.getGuiScale();
+ scale = (int)Math.round(dscale);
+ if ((dscale>=1.5&&dscale<2.0) || (dscale>=2.5&&dscale<3.0))
+ dscale = scale;
+ if (dscale>1.0) {
+ buttonWidth = (int)((BUTTON_WIDTH-2)*dscale);
+ buttonHeight = (int)((BUTTON_HEIGHT-2)*dscale);
+ offset = (int)Math.round((OFFSET-1)*dscale);
+ } else {
+ buttonWidth = BUTTON_WIDTH;
+ buttonHeight = BUTTON_HEIGHT;
+ offset = OFFSET;
+ }
+ gapSize = GAP_SIZE;
+ ps = new Dimension(buttonWidth*NUM_BUTTONS-(buttonWidth-gapSize), buttonHeight);
+ }
+
+ void addPopupMenus() {
+ rectPopup = newPopupMenu();
+ rectItem = new CheckboxMenuItem("Rectangle", rectType==RECT_ROI);
+ rectItem.addItemListener(this);
+ rectPopup.add(rectItem);
+ roundRectItem = new CheckboxMenuItem("Rounded Rectangle", rectType==ROUNDED_RECT_ROI);
+ roundRectItem.addItemListener(this);
+ rectPopup.add(roundRectItem);
+ rotatedRectItem = new CheckboxMenuItem("Rotated Rectangle", rectType==ROTATED_RECT_ROI);
+ rotatedRectItem.addItemListener(this);
+ rectPopup.add(rotatedRectItem);
+ add(rectPopup);
+
+ ovalPopup = newPopupMenu();
+ ovalItem = new CheckboxMenuItem("Oval selections", ovalType==OVAL_ROI);
+ ovalItem.addItemListener(this);
+ ovalPopup.add(ovalItem);
+ ellipseItem = new CheckboxMenuItem("Elliptical selections", ovalType==ELLIPSE_ROI);
+ ellipseItem.addItemListener(this);
+ ovalPopup.add(ellipseItem);
+ brushItem = new CheckboxMenuItem("Selection Brush Tool", ovalType==BRUSH_ROI);
+ brushItem.addItemListener(this);
+ ovalPopup.add(brushItem);
+ add(ovalPopup);
+
+ pointPopup = newPopupMenu();
+ pointItem = new CheckboxMenuItem("Point Tool", !multiPointMode);
+ pointItem.addItemListener(this);
+ pointPopup.add(pointItem);
+ multiPointItem = new CheckboxMenuItem("Multi-point Tool", multiPointMode);
+ multiPointItem.addItemListener(this);
+ pointPopup.add(multiPointItem);
+ add(pointPopup);
+
+ linePopup = newPopupMenu();
+ straightLineItem = new CheckboxMenuItem("Straight Line", lineType==LINE&&!arrowMode);
+ straightLineItem.addItemListener(this);
+ linePopup.add(straightLineItem);
+ polyLineItem = new CheckboxMenuItem("Segmented Line", lineType==POLYLINE);
+ polyLineItem.addItemListener(this);
+ linePopup.add(polyLineItem);
+ freeLineItem = new CheckboxMenuItem("Freehand Line", lineType==FREELINE);
+ freeLineItem.addItemListener(this);
+ linePopup.add(freeLineItem);
+ arrowItem = new CheckboxMenuItem("Arrow tool", lineType==LINE&&!arrowMode);
+ arrowItem.addItemListener(this);
+ linePopup.add(arrowItem);
+ add(linePopup);
+
+ zoomPopup = newPopupMenu();
+ addMenuItem(zoomPopup, "Reset Zoom");
+ addMenuItem(zoomPopup, "Zoom In");
+ addMenuItem(zoomPopup, "Zoom Out");
+ addMenuItem(zoomPopup, "View 100%");
+ addMenuItem(zoomPopup, "Zoom To Selection");
+ addMenuItem(zoomPopup, "Scale to Fit");
+ addMenuItem(zoomPopup, "Set...");
+ addMenuItem(zoomPopup, "Maximize");
+ add(zoomPopup);
+
+ pickerPopup = newPopupMenu();
+ addMenuItem(pickerPopup, "White/Black");
+ addMenuItem(pickerPopup, "Black/White");
+ addMenuItem(pickerPopup, "Red");
+ addMenuItem(pickerPopup, "Green");
+ addMenuItem(pickerPopup, "Blue");
+ addMenuItem(pickerPopup, "Yellow");
+ addMenuItem(pickerPopup, "Cyan");
+ addMenuItem(pickerPopup, "Magenta");
+ pickerPopup.addSeparator();
+ addMenuItem(pickerPopup, "Foreground...");
+ addMenuItem(pickerPopup, "Background...");
+ addMenuItem(pickerPopup, "Colors...");
+ addMenuItem(pickerPopup, "Color Picker...");
+ add(pickerPopup);
+
+ switchPopup = newPopupMenu();
+ add(switchPopup);
+ }
+
+ private PopupMenu newPopupMenu() {
+ PopupMenu popup = new PopupMenu();
+ ij.gui.GUI.scalePopupMenu(popup);
+ //System.out.println("newPopupMenu: "+popup.getFont());
+ return popup;
+ }
+
+ private void addMenuItem(PopupMenu menu, String command) {
+ MenuItem item = new MenuItem(command);
+ item.addActionListener(this);
+ menu.add(item);
+ }
+
+ /** Returns the ID of the current tool (Toolbar.RECTANGLE, Toolbar.OVAL, etc.). */
+ public static int getToolId() {
+ int id = current;
+ if (legacyMode) {
+ if (id==CUSTOM1)
+ id=UNUSED;
+ else if (id>=CUSTOM2)
+ id--;
+ }
+ return id;
+ }
+
+ /** Returns the ID of the tool whose name (the description displayed in the status bar)
+ starts with the specified string, or -1 if the tool is not found. */
+ public int getToolId(String name) {
+ int tool = -1;
+ for (int i=0; i1.0)
+ g2d.setStroke(new BasicStroke(IJ.isMacOSX()?1.4f:1.25f));
+ } else
+ g2d.setStroke(new BasicStroke(scale));
+ }
+
+ private void fill3DRect(Graphics g, int x, int y, int width, int height, boolean raised) {
+ if (null==g) return;
+ if (raised)
+ g.setColor(gray);
+ else
+ g.setColor(darker);
+ g.fillRect(x+1, y+1, width-2, height-2);
+ g.setColor(raised ? brighter : evenDarker);
+ g.drawLine(x, y, x, y + height - 1);
+ g.drawLine(x + 1, y, x + width - 2, y);
+ g.setColor(raised ? evenDarker : brighter);
+ g.drawLine(x + 1, y + height - 1, x + width - 1, y + height - 1);
+ g.drawLine(x + width - 1, y, x + width - 1, y + height - 2);
+ }
+
+ private void drawButton(Graphics g, int tool) {
+ if (g==null) return;
+ if (legacyMode) {
+ if (tool==UNUSED)
+ tool = CUSTOM1;
+ else if (tool>=CUSTOM1)
+ tool++;
+ if ((tool==POLYLINE && lineType!=POLYLINE) || (tool==FREELINE && lineType!=FREELINE))
+ return;
+ }
+ int index = toolIndex(tool);
+ int x = index*buttonWidth + 1*scale;
+ if (tool>=CUSTOM1)
+ x -= buttonWidth-gapSize;
+ if (tool!=UNUSED)
+ fill3DRect(g, x, 1, buttonWidth, buttonHeight-1, !down[tool]);
+ g.setColor(toolColor);
+ x = index*buttonWidth + offset;
+ if (tool>=CUSTOM1)
+ x -= buttonWidth-gapSize;
+ int y = offset;
+ if (dscale==1.3) {x++; y++;}
+ if (dscale==1.4) {x+=2; y+=2;}
+ if (down[tool]) { x++; y++;}
+ this.g = g;
+ if (tool>=CUSTOM1 && tool<=getNumTools() && icons[tool]!=null) {
+ drawIcon(g, tool, x+1*scale, y+1*scale);
+ return;
+ }
+ switch (tool) {
+ case RECTANGLE:
+ xOffset = x; yOffset = y;
+ if (rectType==ROUNDED_RECT_ROI)
+ g.drawRoundRect(x-1*scale, y+1*scale, 17*scale, 13*scale, 8*scale, 8*scale);
+ else if (rectType==ROTATED_RECT_ROI)
+ polyline(0,10,7,0,15,6,8,16,0,10);
+ else
+ g.drawRect(x-1*scale, y+1*scale, 17*scale, 13*scale);
+ drawTriangle(16,16);
+ return;
+ case OVAL:
+ xOffset = x; yOffset = y;
+ if (ovalType==BRUSH_ROI) {
+ yOffset = y - 1;
+ polyline(6,4,8,2,12,1,15,2,16,4,15,7,12,8,9,11,9,14,6,16,2,16,0,13,1,10,4,9,6,7,6,4);
+ } else if (ovalType==ELLIPSE_ROI) {
+ xOffset = x - 1;
+ yOffset = y + 1;
+ polyline(11,0,13,0,14,1,15,1,16,2,17,3,17,7,12,12,11,12,10,13,8,13,7,14,4,14,3,13,2,13,1,12,1,11,0,10,0,9,1,8,1,7,6,2,7,2,8,1,10,1,11,0);
+ } else
+ g.drawOval(x, y+1*scale, 17*scale, 13*scale);
+ drawTriangle(16,16);
+ return;
+ case POLYGON:
+ xOffset = x+1; yOffset = y+2;
+ polyline(4,0,15,0,15,1,11,5,11,6,14,11,14,12,0,12,0,4,4,0);
+ return;
+ case FREEROI:
+ xOffset = x; yOffset = y+3;
+ polyline(2,0,5,0,7,3,10,3,12,0,15,0,17,2,17,5,16,8,13,10,11,11,6,11,4,10,1,8,0,6,0,2,2,0);
+ return;
+ case LINE:
+ if (arrowMode) {
+ xOffset = x; yOffset = y;
+ m(1,14); d(14,1); m(6,5); d(14,1); m(10,9); d(14,1); m(6,5); d(10,9);
+ } else {
+ xOffset = x-1; yOffset = y-1;
+ m(1,17); d(18,0);
+ drawDot(0,16); drawDot(17,0);
+ }
+ drawTriangle(16,16);
+ return;
+ case POLYLINE:
+ xOffset = x; yOffset = y;
+ polyline(15,6,11,2,1,2,1,3,7,9,2,14);
+ drawTriangle(14,16);
+ return;
+ case FREELINE:
+ xOffset = x; yOffset = y;
+ polyline(16,4,14,6,12,6,9,3,8,3,6,7,2,11,1,11);
+ drawTriangle(14,16);
+ return;
+ case POINT:
+ xOffset = x; yOffset = y;
+ if (multiPointMode) {
+ drawPoint(1,3); drawPoint(9,0); drawPoint(15,5);
+ drawPoint(10,11); drawPoint(2,13);
+ } else {
+ m(1,8); d(6,8); d(6,6); d(10,6); d(10,10); d(6,10); d(6,9);
+ m(8,1); d(8,5); m(11,8); d(15,8); m(8,11); d(8,15);
+ m(8,8); d(8,8);
+ g.setColor(ij.gui.Roi.getColor());
+ m(7,7); d(9,7);
+ m(7,8); d(9,8);
+ m(7,9); d(9,9);
+ }
+ drawTriangle(16,16);
+ return;
+ case WAND:
+ xOffset = x+2; yOffset = y+1;
+ dot(4,0); m(2,0); d(3,1); d(4,2); m(0,0); d(1,1);
+ m(0,2); d(1,3); d(2,4); dot(0,4); m(3,3); d(15,15);
+ g.setColor(ij.gui.Roi.getColor());
+ m(1,2); d(3,2); m(2,1); d(2,3);
+ return;
+ case TEXT:
+ xOffset = x; yOffset = y;
+ m(1,16); d(9,0); d(16,16);
+ m(0,16); d(2,16);
+ m(15,16); d(17,16);
+ m(4,10); d(13,10);
+ return;
+ case MAGNIFIER:
+ xOffset = x; yOffset = y;
+ g.drawOval(x+3, y, 13*scale, 13*scale);
+ m(5,12); d(-1,18);
+ drawTriangle(15,17);
+ return;
+ case HAND:
+ xOffset = x; yOffset = y;
+ polyline(5,17,5,16,0,11,0,8,1,8,5,11,5,2,8,2,8,8,8,0,11,0,11,8,11,1,14,1,14,9,14,3,17,3,17,12,16,13,16,17);
+ return;
+ case DROPPER:
+ // draw foreground/background rectangles
+ g.setColor(backgroundColor);
+ g.fillRect(x+2*scale, y+3*scale, 15*scale, 16*scale);
+ g.drawRect(x, y+2*scale, 13*scale, 13*scale);
+ g.setColor(foregroundColor);
+ g.fillRect(x, y+2*scale, 13*scale, 13*scale);
+ // draw dropper icon
+ xOffset = x+3; yOffset = y-4;
+ g.setColor(toolColor);
+ m(12,2); d(14,2);
+ m(11,3); d(15,3);
+ m(11,4); d(15,4);
+ m(8,5); d(15,5);
+ m(9,6); d(14,6);
+ polyline(10,7,12,7,12,9);
+ polyline(9,6,2,13,2,15,4,15,11,8);
+ g.setColor(gray);
+ polygon(9,6,2,13,2,15,4,15,11,8);
+ drawTriangle(12,21);
+ return;
+ case ANGLE:
+ xOffset = x; yOffset = y+3;
+ m(0,11); d(13,-1); m(0,11); d(16,11);
+ m(10,11); d(10,8); m(9,7); d(9,6); dot(8,5);
+ drawDot(13,-2); drawDot(16,10);
+ return;
+ }
+ }
+
+ void drawTriangle(int x, int y) {
+ g.setColor(triangleColor);
+ xOffset+=x*scale; yOffset+=y*scale;
+ m(0,0); d(4,0); m(1,1); d(3,1); m(2,2); d(2,2);
+ }
+
+ void drawDot(int x, int y) {
+ g.fillRect(xOffset+x*scale, yOffset+y*scale, 2*scale, 2*scale);
+ }
+
+ void drawPoint(int x, int y) {
+ g.setColor(toolColor);
+ m(x-3,y); d(x+3,y);
+ m(x,y-3); d(x,y+3);
+ g.setColor(ij.gui.Roi.getColor());
+ dot(x,y); dot(x-1,y-1);
+ }
+
+ void drawIcon(Graphics g, int tool, int x, int y) {
+ if (null==g) return;
+ icon = icons[tool];
+ if (icon==null) return;
+ int x1, y1, x2, y2;
+ pc = 0;
+ if (icon.trim().startsWith("icon:")) {
+ String path = IJ.getDir("macros")+"toolsets/icons/"+icon.substring(icon.indexOf(":")+1);
+ try {
+ BufferedImage bi = ImageIO.read(new File(path));
+ if (scale==1)
+ g.drawImage(bi,x-5,y-5,null);
+ else {
+ int size = Math.max(bi.getWidth(),bi.getHeight());
+ g.drawImage(bi,x-5*scale,y-5*scale, size*scale,size*scale,null);
+ }
+ } catch (Exception e) {
+ IJ.error("Toolbar", "Error reading tool icon:\n"+path);
+ }
+ } else {
+ while (true) {
+ char command = icon.charAt(pc++);
+ if (pc>=icon.length()) break;
+ switch (command) {
+ case 'B': x+=v(); y+=v(); break; // adjust base
+ case 'N': x-=v(); y-=v(); break; // adjust base negatively
+ case 'R': g.drawRect(x+v(), y+v(), v(), v()); break; // rectangle
+ case 'F': g.fillRect(x+v(), y+v(), v(), v()); break; // filled rectangle
+ case 'O': g.drawOval(x+v(), y+v(), v(), v()); break; // oval
+ case 'V': case 'o': g.fillOval(x+v(), y+v(), v(), v()); break; // filled oval
+ case 'C': // set color
+ int saveScale = scale;
+ scale = 1;
+ int v1=v(), v2=v(), v3=v();
+ int red=v1*16, green=v2*16, blue=v3*16;
+ if (red>255) red=255; if (green>255) green=255; if (blue>255) blue=255;
+ Color color = v1==1&&v2==2&&v3==3?foregroundColor:new Color(red,green,blue);
+ g.setColor(color);
+ scale = saveScale;
+ break;
+ case 'L': g.drawLine(x+v(), y+v(), x+v(), y+v()); break; // line
+ case 'D': g.fillRect(x+v(), y+v(), scale, scale); break; // dot
+ case 'P': // polyline
+ Polygon p = new Polygon();
+ p.addPoint(x+v(), y+v());
+ while (true) {
+ x2=v(); if (x2==0) break;
+ y2=v(); if (y2==0) break;
+ p.addPoint(x+x2, y+y2);
+ }
+ g.drawPolyline(p.xpoints, p.ypoints, p.npoints);
+ break;
+ case 'G': case 'H':// polygon or filled polygon
+ p = new Polygon();
+ p.addPoint(x+v(), y+v());
+ while (true) {
+ x2=v(); y2=v();
+ if (x2==0 && y2==0 && p.npoints>2)
+ break;
+ p.addPoint(x+x2, y+y2);
+ }
+ if (command=='G')
+ g.drawPolygon(p.xpoints, p.ypoints, p.npoints);
+ else
+ g.fillPolygon(p.xpoints, p.ypoints, p.npoints);
+ break;
+ case 'T': // text (one character)
+ x2 = x+v()-2;
+ y2 = y+v();
+ int size = v()*10+v()+1;
+ char[] c = new char[1];
+ c[0] = pc=icon.length()) break;
+ }
+ }
+ if (menus[tool]!=null && menus[tool].getItemCount()>0) {
+ xOffset = x; yOffset = y;
+ drawTriangle(15, 16);
+ }
+ }
+
+ int v() {
+ if (pc>=icon.length()) return 0;
+ char c = icon.charAt(pc++);
+ switch (c) {
+ case '0': return 0*scale;
+ case '1': return 1*scale;
+ case '2': return 2*scale;
+ case '3': return 3*scale;
+ case '4': return 4*scale;
+ case '5': return 5*scale;
+ case '6': return 6*scale;
+ case '7': return 7*scale;
+ case '8': return 8*scale;
+ case '9': return 9*scale;
+ case 'a': return 10*scale;
+ case 'b': return 11*scale;
+ case 'c': return 12*scale;
+ case 'd': return 13*scale;
+ case 'e': return 14*scale;
+ case 'f': return 15*scale;
+ case 'g': return 16*scale;
+ case 'h': return 17*scale;
+ case 'i': return 18*scale;
+ case 'j': return 19*scale;
+ case 'k': return 20*scale;
+ case 'l': return 21*scale;
+ case 'm': return 22*scale;
+ case 'n': return 23*scale;
+ default: return 0;
+ }
+ }
+
+ private void showMessage(int tool) {
+ if (IJ.statusBarProtected())
+ return;
+ if (tool>=UNUSED && tool=UNUSED && current=CUSTOM1)
+ tool++;
+ if (IJ.debugMode) IJ.log("Toolbar.setTool: "+tool);
+ if ((tool==current&&!(tool==RECTANGLE||tool==OVAL||tool==POINT)) || tool<0 || tool>=getNumTools()-1)
+ return;
+ if (tool>=CUSTOM1&&tool<=getNumTools()-2) {
+ if (names[tool]==null)
+ names[tool] = "Spare tool"; // enable tool
+ if (names[tool].indexOf("Action Tool")!=-1)
+ return;
+ }
+ if (isLine(tool)) lineType = tool;
+ setTool2(tool);
+ }
+
+ private void setTool2(int tool) {
+ if (!isValidTool(tool)) return;
+ String previousName = getToolName();
+ previousTool = current;
+ current = tool;
+ Graphics g = this.getGraphics();
+ if (g==null)
+ return;
+ down[current] = true;
+ if (current!=previousTool)
+ down[previousTool] = false;
+ Graphics2D g2d = (Graphics2D)g;
+ g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+ setStrokeWidth(g2d);
+ drawButton(g, previousTool);
+ drawButton(g, current);
+ if (null==g) return;
+ g.dispose();
+ showMessage(current);
+ if (IJ.recording()) {
+ String name = getName(current);
+ if (name!=null && name.equals("dropper")) disableRecording=true;
+ if (name!=null && !disableRecording) {
+ IJ.wait(100); // workaround for OSX/Java 8 bug
+ Recorder.record("setTool", name);
+ }
+ if (name!=null && !name.equals("dropper")) disableRecording=false;
+ }
+ if (legacyMode)
+ repaint();
+ if (!previousName.equals(getToolName())) {
+ IJ.notifyEventListeners(IJEventListener.TOOL_CHANGED);;
+ repaint();
+ }
+ }
+
+ boolean isValidTool(int tool) {
+ if (tool<0 || tool>=getNumTools())
+ return false;
+ if (tool>=CUSTOM1 && tool=0) {
+ int v = (int)value;
+ if (v>255) v=255;
+ setForegroundColor(new Color(v,v,v));
+ }
+ foregroundValue = value;
+ }
+
+ public static double getBackgroundValue() {
+ return backgroundValue;
+ }
+
+ /** Sets the background color to grayscale, where value
+ is between 0 (black) and 255 (white). */
+ public static void setBackgroundValue(double value) {
+ if (value>=0) {
+ int v = (int)value;
+ if (v>255) v=255;
+ setBackgroundColor(new Color(v,v,v));
+ }
+ backgroundValue = value;
+ }
+
+ private static void setRoiColor(Color c) {
+ ImagePlus imp = WindowManager.getCurrentImage();
+ if (imp==null) return;
+ ij.gui.Roi roi = imp.getRoi();
+ if (roi!=null && (roi.isDrawingTool())) {
+ roi.setStrokeColor(c);
+ imp.draw();
+ }
+ }
+
+ /** Returns the size of the selection brush tool, or 0 if the brush tool is not enabled. */
+ public static int getBrushSize() {
+ if (ovalType==BRUSH_ROI)
+ return brushSize;
+ else
+ return 0;
+ }
+
+ /** Set the size of the selection brush tool, in pixels. */
+ public static void setBrushSize(int size) {
+ brushSize = size;
+ if (brushSize<1) brushSize = 1;
+ Prefs.set(BRUSH_SIZE, brushSize);
+ }
+
+ /** Returns the rounded rectangle arc size, or 0 if the rounded rectangle tool is not enabled. */
+ public static int getRoundRectArcSize() {
+ if (rectType==ROUNDED_RECT_ROI)
+ return arcSize;
+ else
+ return 0;
+ }
+
+ /** Sets the rounded rectangle corner diameter (pixels). */
+ public static void setRoundRectArcSize(int size) {
+ if (size<=0)
+ rectType = RECT_ROI;
+ else {
+ arcSize = size;
+ Prefs.set(CORNER_DIAMETER, arcSize);
+ }
+ repaintTool(RECTANGLE);
+ ImagePlus imp = WindowManager.getCurrentImage();
+ ij.gui.Roi roi = imp!=null?imp.getRoi():null;
+ if (roi!=null && roi.getType()== ij.gui.Roi.RECTANGLE)
+ roi.setCornerDiameter(rectType==ROUNDED_RECT_ROI?arcSize:0);
+ }
+
+ /** Returns 'true' if the multi-point tool is enabled. */
+ public static boolean getMultiPointMode() {
+ return multiPointMode;
+ }
+
+ /** Returns the rectangle tool type (RECT_ROI, ROUNDED_RECT_ROI or ROTATED_RECT_ROI). */
+ public static int getRectToolType() {
+ return rectType;
+ }
+
+ /** Returns the oval tool type (OVAL_ROI, ELLIPSE_ROI or BRUSH_ROI). */
+ public static int getOvalToolType() {
+ return ovalType;
+ }
+
+ /** Returns the button width (button spacing). */
+ public static int getButtonSize() {
+ return buttonWidth;
+ }
+
+ public static void repaintTool(int tool) {
+ Toolbar tb = getInstance();
+ if (tb!=null) {
+ Graphics g = tb.getGraphics();
+ if (IJ.debugMode) IJ.log("Toolbar.repaintTool: "+tool+" "+g);
+ if (g==null) return;
+ if (dscale>1.0)
+ tb.setStrokeWidth((Graphics2D)g);
+ ((Graphics2D)g).setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+ tb.drawButton(g, tool);
+ if (g!=null) g.dispose();
+ }
+ }
+
+ // Returns the toolbar position index of the specified tool
+ int toolIndex(int tool) {
+ switch (tool) {
+ case RECTANGLE: return 0;
+ case OVAL: return 1;
+ case POLYGON: return 2;
+ case FREEROI: return 3;
+ case LINE: return 4;
+ case POLYLINE: return 4;
+ case FREELINE: return 4;
+ case POINT: return 6;
+ case WAND: return 7;
+ case TEXT: return 8;
+ case MAGNIFIER: return 9;
+ case HAND: return 10;
+ case DROPPER: return 11;
+ case ANGLE: return 5;
+ case UNUSED: return 12;
+ default: return tool - 2;
+ }
+ }
+
+ // Returns the tool corresponding to the specified x coordinate
+ private int toolID(int x) {
+ if (x>buttonWidth*12+gapSize)
+ x -= gapSize;
+ int index = x/buttonWidth;
+ switch (index) {
+ case 0: return RECTANGLE;
+ case 1: return OVAL;
+ case 2: return POLYGON;
+ case 3: return FREEROI;
+ case 4: return lineType;
+ case 5: return ANGLE;
+ case 6: return POINT;
+ case 7: return WAND;
+ case 8: return TEXT;
+ case 9: return MAGNIFIER;
+ case 10: return HAND;
+ case 11: return DROPPER;
+ default: return index + 3;
+ }
+ }
+
+ private boolean inGap(int x) {
+ return x>=(buttonWidth*12) && x<(buttonWidth*12+gapSize);
+ }
+
+ public void triggerPopupMenu(int newTool, MouseEvent e, boolean isRightClick, boolean isLongPress) {
+ mpPrevious = current;
+ if (isMacroTool(newTool)) {
+ String name = names[newTool];
+ if (newTool==UNUSED || name.contains("Unused Tool"))
+ return;
+ if (name.indexOf("Action Tool")!=-1) {
+ if (e.isPopupTrigger()||e.isMetaDown()) {
+ name = name.endsWith(" ")?name:name+" ";
+ tools[newTool].runMacroTool(name+"Options");
+ } else {
+ //drawTool(newTool, true);
+ //IJ.wait(50);
+ drawTool(newTool, false);
+ runMacroTool(newTool);
+ }
+ return;
+ } else {
+ name = name.endsWith(" ")?name:name+" ";
+ tools[newTool].runMacroTool(name+"Selected");
+ }
+ }
+ if (!isLongPress)
+ setTool2(newTool);
+ int x = e.getX();
+ int y = e.getY();
+ if (current==RECTANGLE && isRightClick) {
+ rectItem.setState(rectType==RECT_ROI);
+ roundRectItem.setState(rectType==ROUNDED_RECT_ROI);
+ rotatedRectItem.setState(rectType==ROTATED_RECT_ROI);
+ if (IJ.isMacOSX()) IJ.wait(10);
+ rectPopup.show(e.getComponent(),x,y);
+ mouseDownTime = 0L;
+ }
+ if (current==OVAL && isRightClick) {
+ ovalItem.setState(ovalType==OVAL_ROI);
+ ellipseItem.setState(ovalType==ELLIPSE_ROI);
+ brushItem.setState(ovalType==BRUSH_ROI);
+ if (IJ.isMacOSX()) IJ.wait(10);
+ ovalPopup.show(e.getComponent(),x,y);
+ mouseDownTime = 0L;
+ }
+ if (current==POINT && isRightClick) {
+ pointItem.setState(!multiPointMode);
+ multiPointItem.setState(multiPointMode);
+ if (IJ.isMacOSX()) IJ.wait(10);
+ pointPopup.show(e.getComponent(),x,y);
+ mouseDownTime = 0L;
+ }
+ if (isLine(current) && isRightClick) {
+ straightLineItem.setState(lineType==LINE&&!arrowMode);
+ polyLineItem.setState(lineType==POLYLINE);
+ freeLineItem.setState(lineType==FREELINE);
+ arrowItem.setState(lineType==LINE&&arrowMode);
+ if (IJ.isMacOSX()) IJ.wait(10);
+ linePopup.show(e.getComponent(),x,y);
+ mouseDownTime = 0L;
+ }
+ if (current==MAGNIFIER && isRightClick) {
+ zoomPopup.show(e.getComponent(),x,y);
+ mouseDownTime = 0L;
+ }
+ if (current==DROPPER && isRightClick) {
+ pickerPopup.show(e.getComponent(),x,y);
+ mouseDownTime = 0L;
+ }
+ if (isMacroTool(current) && isRightClick) {
+ String name = names[current].endsWith(" ")?names[current]:names[current]+" ";
+ tools[current].runMacroTool(name+"Options");
+ }
+ if (isPlugInTool(current) && isRightClick) {
+ tools[current].showPopupMenu(e, this);
+ }
+ }
+
+ public void mousePressed(final MouseEvent e) {
+ boolean disablePopup = false;
+ int x = e.getX();
+ if (inGap(x))
+ return;
+ final int newTool = toolID(x);
+ if (newTool==getNumTools()-1) {
+ showSwitchPopupMenu(e);
+ return;
+ }
+ if (!isValidTool(newTool))
+ return;
+ if (menus[newTool]!=null && menus[newTool].getItemCount()>0) {
+ menus[newTool].show(e.getComponent(), e.getX(), e.getY());
+ return;
+ }
+ int flags = e.getModifiers();
+ boolean isRightClick = e.isPopupTrigger()||(!IJ.isMacintosh()&&(flags&Event.META_MASK)!=0);
+ boolean doubleClick = newTool==current && (System.currentTimeMillis()-mouseDownTime)<=DOUBLE_CLICK_THRESHOLD;
+ mouseDownTime = System.currentTimeMillis();
+ if (!doubleClick || isRightClick) {
+ triggerPopupMenu(newTool, e, isRightClick, false);
+ if (isRightClick) mouseDownTime = 0L;
+ } else if(!isRightClick) { //double click
+ if (isMacroTool(current)) {
+ String name = names[current].endsWith(" ")?names[current]:names[current]+" ";
+ tools[current].runMacroTool(name+"Options");
+ return;
+ }
+ if (isPlugInTool(current)) {
+ tools[current].showOptionsDialog();
+ return;
+ }
+ ImagePlus imp = WindowManager.getCurrentImage();
+ switch (current) {
+ case RECTANGLE:
+ if (rectType==ROUNDED_RECT_ROI)
+ IJ.doCommand("Rounded Rect Tool...");
+ else {
+ disablePopup = true;
+ IJ.doCommand("Roi Defaults...");
+ }
+ break;
+ case OVAL:
+ showBrushDialog();
+ break;
+ case MAGNIFIER:
+ if (imp!=null) {
+ ij.gui.ImageCanvas ic = imp.getCanvas();
+ if (ic!=null) ic.unzoom();
+ }
+ break;
+ case LINE: case POLYLINE: case FREELINE:
+ if (current==LINE && arrowMode) {
+ IJ.doCommand("Arrow Tool...");
+ } else
+ IJ.runPlugIn("ij.plugin.frame.LineWidthAdjuster", "");
+ break;
+ case ANGLE:
+ showAngleDialog();
+ break;
+ case POINT:
+ IJ.doCommand("Point Tool...");
+ break;
+ case WAND:
+ IJ.doCommand("Wand Tool...");
+ break;
+ case TEXT:
+ IJ.run("Fonts...");
+ break;
+ case DROPPER:
+ IJ.doCommand("Color Picker...");
+ setTool2(mpPrevious);
+ break;
+ default:
+ }
+ }
+
+ if (!isRightClick && longClickDelay>0 && !disablePopup) {
+ if (pressTimer==null)
+ pressTimer = new Timer();
+ pressTimer.schedule(new TimerTask() {
+ public void run() {
+ if (pressTimer != null) {
+ pressTimer.cancel();
+ pressTimer = null;
+ }
+ triggerPopupMenu(newTool, e, true, true);
+ }
+ }, longClickDelay);
+ }
+
+ }
+
+ public void mouseReleased(MouseEvent e) {
+ if (pressTimer!=null) {
+ pressTimer.cancel();
+ pressTimer = null;
+ }
+ }
+
+ void showSwitchPopupMenu(MouseEvent e) {
+ String path = IJ.getDir("macros")+"toolsets/";
+ if (path==null)
+ return;
+ boolean applet = IJ.getApplet()!=null;
+ File f = new File(path);
+ String[] list;
+ if (!applet && f.exists() && f.isDirectory()) {
+ list = f.list();
+ if (list==null) return;
+ Arrays.sort(list);
+ } else
+ list = new String[0];
+ switchPopup.removeAll();
+ path = IJ.getDir("macros") + "StartupMacros.txt";
+ f = new File(path);
+ if (!f.exists()) {
+ path = IJ.getDir("macros") + "StartupMacros.ijm";
+ f = new File(path);
+ }
+ if (!applet && f.exists())
+ addItem("Startup Macros");
+ else
+ addItem("StartupMacros*");
+ for (int i=0; i=5)
+ pluginsMenu = menuBar.getMenu(5);
+ if (pluginsMenu==null || !"Plugins".equals(pluginsMenu.getLabel()))
+ return;
+ n = pluginsMenu.getItemCount();
+ Menu toolsMenu = null;
+ for (int i=0; i=CUSTOM1 && tool=CUSTOM1 && toolTools submenu.\n"+
+ " \n"+
+ "Hold the shift key down while selecting a\n"+
+ "toolset to view its source code.\n"+
+ " \n"+
+ "More macro toolsets are available at\n"+
+ " <"+IJ.URL2+"/macros/toolsets/>\n"+
+ " \n"+
+ "Plugin tools can be downloaded from\n"+
+ "the Tools section of the Plugins page at\n"+
+ " <"+IJ.URL2+"/plugins/>\n"
+ );
+ return;
+ } else if (label.endsWith("*")) {
+ // load from ij.jar
+ MacroInstaller mi = new MacroInstaller();
+ label = label.substring(0, label.length()-1) + ".txt";
+ path = "/macros/"+label;
+ if (IJ.shiftKeyDown())
+ showCode(label, mi.openFromIJJar(path));
+ else {
+ resetTools();
+ mi.installFromIJJar(path);
+ }
+ } else {
+ // load from ImageJ/macros/toolsets
+ if (label.equals("Startup Macros")) {
+ installStartupMacros();
+ return;
+ } else if (label.endsWith(" "))
+ path = IJ.getDir("macros")+"toolsets"+File.separator+label.substring(0, label.length()-1)+".ijm";
+ else
+ path = IJ.getDir("macros")+"toolsets"+File.separator+label+".txt";
+ try {
+ if (IJ.shiftKeyDown()) {
+ IJ.open(path);
+ IJ.setKeyUp(KeyEvent.VK_SHIFT);
+ } else
+ new MacroInstaller().run(path);
+ } catch(Exception ex) {}
+ }
+ }
+ }
+
+ private void removeTools() {
+ removeMacroTools();
+ setTool(RECTANGLE);
+ currentSet = "Startup Macros";
+ resetPrefs();
+ if (nExtraTools>0) {
+ String name = names[getNumTools()-1];
+ String icon = icons[getNumTools()-1];
+ nExtraTools = 0;
+ names[getNumTools()-1] = name;
+ icons[getNumTools()-1] = icon;
+ ps = new Dimension(buttonWidth*NUM_BUTTONS-(BUTTON_WIDTH-gapSize)+nExtraTools*BUTTON_WIDTH, buttonHeight);
+ IJ.getInstance().pack();
+ }
+ }
+
+ private void resetPrefs() {
+ for (int i=0; i<7; i++) {
+ String key = TOOL_KEY+(i/10)%10+i%10;
+ if (!Prefs.get(key, "").equals(""))
+ Prefs.set(key, "");
+ }
+ }
+
+ public static void restoreTools() {
+ Toolbar tb = Toolbar.getInstance();
+ if (tb!=null) {
+ if (tb.getToolId()>=UNUSED)
+ tb.setTool(RECTANGLE);
+ tb.installStartupMacros();
+ }
+ }
+
+ private void installStartupMacros() {
+ resetTools();
+ String path = IJ.getDir("macros")+"StartupMacros.txt";
+ File f = new File(path);
+ if (!f.exists()) {
+ path = IJ.getDir("macros")+"StartupMacros.ijm";
+ f = new File(path);
+ }
+ if (!f.exists()) {
+ path = IJ.getDir("macros")+"StartupMacros.fiji.ijm";
+ f = new File(path);
+ }
+ if (!f.exists()) {
+ IJ.error("StartupMacros not found in\n \n"+IJ.getDir("macros"));
+ return;
+ }
+ if (IJ.shiftKeyDown()) {
+ IJ.open(path);
+ IJ.setKeyUp(KeyEvent.VK_SHIFT);
+ } else {
+ try {
+ MacroInstaller mi = new MacroInstaller();
+ mi.installFile(path);
+ } catch
+ (Exception ex) {}
+ }
+ }
+
+ public void actionPerformed(ActionEvent e) {
+ MenuItem item = (MenuItem)e.getSource();
+ String cmd = e.getActionCommand();
+ PopupMenu popup = (PopupMenu)item.getParent();
+
+ if (zoomPopup==popup) {
+ if ("Zoom In".equals(cmd))
+ IJ.runPlugIn("ij.plugin.Zoom", "in");
+ else if ("Zoom Out".equals(cmd))
+ IJ.runPlugIn("ij.plugin.Zoom", "out");
+ else if ("Reset Zoom".equals(cmd))
+ IJ.runPlugIn("ij.plugin.Zoom", "orig");
+ else if ("View 100%".equals(cmd))
+ IJ.runPlugIn("ij.plugin.Zoom", "100%");
+ else if ("Zoom To Selection".equals(cmd))
+ IJ.runPlugIn("ij.plugin.Zoom", "to");
+ else if ("Scale to Fit".equals(cmd))
+ IJ.runPlugIn("ij.plugin.Zoom", "scale");
+ else if ("Set...".equals(cmd))
+ IJ.runPlugIn("ij.plugin.Zoom", "set");
+ else if ("Maximize".equals(cmd))
+ IJ.runPlugIn("ij.plugin.Zoom", "max");
+ disableRecording = true;
+ setTool(previousTool);
+ disableRecording = false;
+ return;
+ }
+
+ if (pickerPopup==popup) {
+ if ("White/Black".equals(cmd)) {
+ setAndRecordForgroundColor(Color.white);
+ setAndRecordBackgroundColor(Color.black);
+ } else if ("Black/White".equals(cmd)) {
+ setAndRecordForgroundColor(Color.black);
+ setAndRecordBackgroundColor(Color.white);
+ } else if ("Red".equals(cmd))
+ setAndRecordForgroundColor(Color.red);
+ else if ("Green".equals(cmd))
+ setAndRecordForgroundColor(Color.green);
+ else if ("Blue".equals(cmd))
+ setAndRecordForgroundColor(Color.blue);
+ else if ("Yellow".equals(cmd))
+ setAndRecordForgroundColor(Color.yellow);
+ else if ("Cyan".equals(cmd))
+ setAndRecordForgroundColor(Color.cyan);
+ else if ("Magenta".equals(cmd))
+ setAndRecordForgroundColor(Color.magenta);
+ else if ("Foreground...".equals(cmd))
+ setAndRecordForgroundColor(new ij.gui.ColorChooser("Select Foreground Color", foregroundColor, false).getColor());
+ else if ("Background...".equals(cmd))
+ setAndRecordBackgroundColor(new ij.gui.ColorChooser("Select Background Color", backgroundColor, false).getColor());
+ else if ("Colors...".equals(cmd)) {
+ IJ.run("Colors...", "");
+ Recorder.setForegroundColor(getForegroundColor());
+ Recorder.setBackgroundColor(getBackgroundColor());
+ } else
+ IJ.run("Color Picker...", "");
+ if (!"Color Picker".equals(cmd))
+ ColorPicker.update();
+ setTool(previousTool);
+ return;
+ }
+
+ int tool = -1;
+ for (int i=CUSTOM1; i=0 && (toolTip.length()-index)>4;
+ int tool =-1;
+ for (int i=CUSTOM1; i<=getNumTools()-2; i++) {
+ if (names[i]==null || toolTip.startsWith(names[i])) {
+ tool = i;
+ break;
+ }
+ }
+ if (tool==CUSTOM1)
+ legacyMode = toolTip.startsWith("Select and Transform Tool"); //TrakEM2
+ if (tool==-1 && (nExtraTools0 && toolTip.charAt(index-1)==' ')
+ names[tool] = toolTip.substring(0, index-1);
+ else
+ names[tool] = toolTip.substring(0, index);
+ } else {
+ if (toolTip.endsWith("-"))
+ toolTip = toolTip.substring(0, toolTip.length()-1);
+ else if (toolTip.endsWith("- "))
+ toolTip = toolTip.substring(0, toolTip.length()-2);
+ names[tool] = toolTip;
+ }
+ if (tool==current && (names[tool].indexOf("Action Tool")!=-1||names[tool].indexOf("Unused Tool")!=-1))
+ setTool(RECTANGLE);
+ if (names[tool].endsWith(" Menu Tool"))
+ installMenu(tool);
+ if (IJ.debugMode) IJ.log("Toolbar.addTool: "+tool+" "+toolTip);
+ return tool;
+ }
+
+ void installMenu(int tool) {
+ Program pgm = macroInstaller.getProgram();
+ Hashtable h = pgm.getMenus();
+ if (h==null) return;
+ String[] commands = (String[])h.get(names[tool]);
+ if (commands==null)
+ return;
+ if (menus[tool]==null) {
+ menus[tool] = new PopupMenu("");
+ ij.gui.GUI.scalePopupMenu(menus[tool]);
+ add(menus[tool] );
+ } else
+ menus[tool].removeAll();
+ for (int i=0; i0 || custom1Name==null)
+ setPrefs(tool);
+ }
+ }
+
+ private void setPrefs(int id) {
+ if (doNotSavePrefs)
+ return;
+ boolean ok = isBuiltInTool(names[id]);
+ String prefsName = instance.names[id];
+ if (!ok) {
+ String name = names[id];
+ int i = name.indexOf(" ("); // remove any hint in parens
+ if (i>0) {
+ name = name.substring(0, i);
+ prefsName=name;
+ }
+ }
+ int index = id - CUSTOM1;
+ String key = TOOL_KEY + (index/10)%10 + index%10;
+ Prefs.set(key, prefsName);
+ }
+
+ private boolean isBuiltInTool(String name) {
+ for (int i=0; i=CUSTOM1)
+ instance.setTool(RECTANGLE);
+ instance.resetTools();
+ instance.repaint();
+ }
+ }
+
+ /** Adds a plugin tool to the first available toolbar slot,
+ or to the last slot if the toolbar is full. */
+ public static void addPlugInTool(PlugInTool tool) {
+ if (instance==null) return;
+ String nameAndIcon = tool.getToolName()+" - "+tool.getToolIcon();
+ instance.addingSingleTool = true;
+ int id = instance.addTool(nameAndIcon);
+ instance.addingSingleTool = false;
+ if (id!=-1) {
+ instance.tools[id] = tool;
+ if (instance.menus[id]!=null)
+ instance.menus[id].removeAll();
+ instance.repaintTool(id);
+ if (!instance.installingStartupTool)
+ instance.setTool(id);
+ else
+ instance.installingStartupTool = false;
+ instance.setPrefs(id);
+ }
+ }
+
+ public static PlugInTool getPlugInTool() {
+ PlugInTool tool = null;
+ if (instance==null)
+ return null;
+ if (current2;
+ return rtn;
+ }
+
+ public static boolean installStartupMacrosTools() {
+ String customTool0 = Prefs.get(Toolbar.TOOL_KEY+"00", "");
+ return customTool0.equals("") || Character.isDigit(customTool0.charAt(0));
+ }
+
+ public int getNumTools() {
+ return NUM_TOOLS + nExtraTools;
+ }
+
+ /** Sets the tool menu long click delay in milliseconds
+ * (default is 600). Set to 0 to disable long click triggering.
+ */
+ public static void setLongClickDelay(int delay) {
+ longClickDelay = delay;
+ }
+
+ /** Sets the icon of the specified macro or plugin tool.
+ * See: Help>Examples>Tool>Animated Icon Tool;
+ */
+ public static void setIcon(String toolName, String icon) {
+ if (instance==null)
+ return;
+ int tool = 0;
+ for (int i=CUSTOM1; i0) {
+ instance.icons[tool] = icon;
+ Graphics2D g = (Graphics2D)instance.getGraphics();
+ instance.setStrokeWidth(g);
+ instance.drawButton(g, tool);
+ }
+ }
+
+}
diff --git a/mrj/26/ij/io/PluginClassLoader.java b/mrj/26/ij/io/PluginClassLoader.java
new file mode 100644
index 00000000..b5016ba8
--- /dev/null
+++ b/mrj/26/ij/io/PluginClassLoader.java
@@ -0,0 +1,313 @@
+package ij.io;
+
+import ij.IJ;
+import java.io.*;
+import java.lang.classfile.CodeTransform;
+import java.lang.classfile.FieldModel;
+import java.lang.classfile.MethodTransform;
+import java.lang.classfile.instruction.FieldInstruction;
+import java.lang.classfile.instruction.InvokeInstruction;
+import java.net.*;
+import java.lang.classfile.ClassFile;
+import java.lang.classfile.ClassTransform;
+import java.lang.constant.ClassDesc;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.security.CodeSource;
+import java.security.cert.Certificate;
+import java.util.HashMap;
+import java.util.Map;
+
+/** ImageJ uses this class loader to load plugins and resources from the
+ * plugins directory and immediate subdirectories. This class loader will
+ * also load classes and resources from JAR files.
+ *
+ * The class loader searches for classes and resources in the following order:
+ *
+ * - Plugins directory
+ * - Subdirectories of the Plugins directory
+ * - JAR and ZIP files in the plugins directory and subdirectories
+ *
+ * The class loader does not recurse into subdirectories beyond the first level.
+*/
+public class PluginClassLoader extends URLClassLoader {
+ protected String path;
+ private static final Map METADATA_CACHE = new HashMap<>();
+ private static final Map APPLET_REMAP = Map.of(
+ ClassDesc.of("java.applet.Applet"), ClassDesc.of("ij.stub.Applet"),
+ ClassDesc.of("java.applet.AppletContext"), ClassDesc.of("ij.stub.AppletContext"),
+ ClassDesc.of("java.applet.AppletStub"), ClassDesc.of("ij.stub.AppletStub"),
+ ClassDesc.of("java.applet.AudioClip"), ClassDesc.of("ij.stub.AudioClip")
+ );
+ private static final ClassTransform APPLET_TRANSFORMER = createTransform();
+
+ static {
+ registerAsParallelCapable();
+ }
+
+ /**
+ * Creates a new PluginClassLoader that searches in the directory path
+ * passed as a parameter. The constructor automatically finds all JAR and ZIP
+ * files in the path and first level of subdirectories. The JAR and ZIP files
+ * are stored in a Vector for future searches.
+ * @param path the path to the plugins directory.
+ */
+ public PluginClassLoader(String path) {
+ super(new URL[0], IJ.class.getClassLoader());
+ init(path);
+ }
+
+ /** This version of the constructor is used when ImageJ is launched using Java WebStart. */
+ public PluginClassLoader(String path, boolean callSuper) {
+ super(new URL[0], Thread.currentThread().getContextClassLoader());
+ init(path);
+ }
+
+ void init(String path) {
+ this.path = path;
+
+ //find all JAR files on the path and subdirectories
+ File f = new File(path);
+ try {
+ // Add plugin directory to search path
+ addURL(f.toURI().toURL());
+ } catch (MalformedURLException e) {
+ ij.IJ.log("PluginClassLoader: "+e);
+ }
+ String[] list = f.list();
+ if (list==null)
+ return;
+ for (int i=0; i findClass(String name) throws ClassNotFoundException {
+ // Exclude java classes from remapping
+ if (name.startsWith("java.") || name.startsWith("javax.") || name.startsWith("sun.")) {
+ return super.findClass(name);
+ }
+
+ var resourceName = name.replace('.', '/').concat(".class");
+
+ var resourceUrl = findResource(resourceName);
+ if (resourceUrl == null) {
+ IO.println("Resource not found: " + resourceName);
+ throw new ClassNotFoundException(name);
+ }
+
+ try {
+ var conn = resourceUrl.openConnection();
+
+ try (InputStream in = conn.getInputStream()) {
+ var bytes = in.readAllBytes();
+ var remapped = maybeRemapAppletRefs(bytes);
+
+ var lastDot = name.lastIndexOf('.');
+ if (lastDot != -1) {
+ var pkg = name.substring(0, lastDot);
+ if (getDefinedPackage(pkg) == null) {
+ definePackage(pkg, null, null, null, null, null, null, null);
+ }
+ }
+
+ try {
+ var basePath = getCodeSourcePath(resourceUrl, resourceName);
+
+ CodeSource codeSource = null;
+ if (conn instanceof JarURLConnection jarURLConnection) {
+ var jarEntry = jarURLConnection.getJarEntry();
+ if (jarEntry != null) {
+ codeSource = new CodeSource(resourceUrl, jarEntry.getCodeSigners());
+ }
+ }
+
+ if (codeSource == null) {
+ codeSource = getCodeSource(basePath, conn);
+ }
+
+ //Files.write(Paths.get(name + ".class"), remapped);
+
+ return defineClass(name, remapped, 0, remapped.length, codeSource);
+ } catch (IOException | IllegalStateException e) {
+ throw new ClassNotFoundException(name, e);
+ }
+ } catch (IOException e) {
+ throw new ClassNotFoundException(name, e);
+ }
+ } catch (IOException e) {
+ throw new ClassNotFoundException(name, e);
+ }
+ }
+
+ private static byte[] maybeRemapAppletRefs(byte[] classBytes) {
+ var cf = ClassFile.of();
+ return cf.transformClass(cf.parse(classBytes), APPLET_TRANSFORMER);
+ }
+
+ private static ClassTransform createTransform() {
+ CodeTransform codeTransform = (codeBuilder, e) -> {
+ switch (e) {
+ case InvokeInstruction i -> {
+ var owner = i.owner().asSymbol();
+ var type = i.typeSymbol();
+ var rOwner = APPLET_REMAP.get(i.owner().asSymbol());
+ var rType = APPLET_REMAP.get(type.returnType());
+
+ if (rOwner != null || rType != null) {
+ if (rType != null) {
+ type = type.changeReturnType(rType);
+ }
+ if (rOwner != null) {
+ owner = rOwner;
+ }
+ codeBuilder.invoke(i.opcode(), owner, i.name().stringValue(), type, i.isInterface());
+ } else {
+ codeBuilder.accept(i);
+ }
+ }
+ case FieldInstruction f -> {
+ var type = APPLET_REMAP.get(f.typeSymbol());
+ if (type != null) {
+ codeBuilder.fieldAccess(f.opcode(), f.owner().asSymbol(), f.name().stringValue(), type);
+ } else {
+ codeBuilder.accept(f);
+ }
+ }
+ default -> codeBuilder.accept(e);
+ }
+ };
+
+ var methodTransform = MethodTransform.transformingCode(codeTransform);
+
+ ClassTransform fieldRemapper = (classBuilder, e) -> {
+ switch (e) {
+ case FieldModel f -> {
+ var rf = APPLET_REMAP.get(f.fieldTypeSymbol());
+ if (rf != null) {
+ classBuilder.withField(f.fieldName().stringValue(), rf, f.flags().flagsMask());
+ } else {
+ classBuilder.accept(f);
+ }
+ }
+ default -> classBuilder.accept(e);
+ }
+ };
+
+ return fieldRemapper.andThen(ClassTransform.transformingMethods(methodTransform));
+ }
+
+ private CodeSource getCodeSource(URI base, URLConnection conn) {
+ try {
+ return METADATA_CACHE.computeIfAbsent(base, (URI uri) -> {
+ try {
+ if (conn instanceof JarURLConnection jarURLConnection) {
+ return new CodeSource(jarURLConnection.getJarFileURL(), jarURLConnection.getCertificates());
+ }
+
+ var path = Path.of(uri);
+
+ if (Files.isDirectory(path)) {
+ return new CodeSource(path.toUri().toURL(), (Certificate[]) null);
+ }
+ } catch (IOException e) {
+ if (IJ.debugMode) {
+ e.printStackTrace();
+ }
+ }
+
+ return null;
+ });
+ } catch (IllegalStateException e) {
+ if (IJ.debugMode) {
+ e.printStackTrace();
+ }
+
+ return null;
+ }
+ }
+
+ private URI getCodeSourcePath(URL url, String className) throws IllegalStateException {
+ try {
+ if ("jar".equals(url.getProtocol())) {
+ var file = url.getFile();
+ var sep = file.indexOf("!/");
+
+ if (sep == -1) {
+ throw new IllegalStateException("Invalid jar url: " + url);
+ }
+
+ return new URI("jar:" + file.substring(0, sep) + "!/");
+ } else {
+ var path = Path.of(url.toURI());
+ var classPath = Path.of(className);
+
+ if (!path.endsWith(classPath)) {
+ throw new IllegalStateException("URL does not end with resource: " + className);
+ }
+
+ var base = path;
+ for (int i = 0; i < classPath.getNameCount(); i++) {
+ base = base.getParent();
+ if (base == null) break;
+ }
+
+ if (base == null) {
+ throw new IllegalStateException("Cannot determine code source for " + url);
+ }
+
+ return base.toUri();
+ }
+ } catch (Exception e) {
+ throw new IllegalStateException("Failed to get CodeSource path", e);
+ }
+ }
+}
diff --git a/mrj/26/ij/macro/Functions.java b/mrj/26/ij/macro/Functions.java
new file mode 100644
index 00000000..62b5456f
--- /dev/null
+++ b/mrj/26/ij/macro/Functions.java
@@ -0,0 +1,8599 @@
+package ij.macro;
+
+import java.awt.Color;
+import java.awt.Dialog;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.Frame;
+import java.awt.GraphicsEnvironment;
+import java.awt.Point;
+import java.awt.Polygon;
+import java.awt.Rectangle;
+import java.awt.Shape;
+import java.awt.TextArea;
+import java.awt.Toolkit;
+import java.awt.Window;
+import java.awt.datatransfer.Clipboard;
+import java.awt.datatransfer.DataFlavor;
+import java.awt.datatransfer.StringSelection;
+import java.awt.datatransfer.Transferable;
+import java.awt.event.KeyEvent;
+import java.awt.geom.Ellipse2D;
+import java.awt.geom.GeneralPath;
+import java.awt.geom.Rectangle2D;
+import java.awt.image.IndexColorModel;
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.CharArrayWriter;
+import java.io.DataInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Locale;
+import java.util.Properties;
+import java.util.Random;
+import java.util.Vector;
+
+import ij.CompositeImage;
+import ij.IJ;
+import ij.ImageJ;
+import ij.ImagePlus;
+import ij.ImageStack;
+import ij.Macro;
+import ij.Menus;
+import ij.Prefs;
+import ij.Undo;
+import ij.WindowManager;
+import ij.gui.Arrow;
+import ij.gui.EllipseRoi;
+import ij.gui.GenericDialog;
+import ij.gui.HistogramWindow;
+import ij.gui.ImageCanvas;
+import ij.gui.ImageWindow;
+import ij.gui.Line;
+import ij.gui.NonBlockingGenericDialog;
+import ij.gui.Overlay;
+import ij.gui.Plot;
+import ij.gui.PlotWindow;
+import ij.gui.PointRoi;
+import ij.gui.PolygonRoi;
+import ij.gui.ProfilePlot;
+import ij.gui.Roi;
+import ij.gui.RotatedRectRoi;
+import ij.gui.ShapeRoi;
+import ij.gui.StackWindow;
+import ij.gui.TextRoi;
+import ij.gui.Toolbar;
+import ij.gui.WaitForUserDialog;
+import ij.gui.Wand;
+import ij.gui.YesNoCancelDialog;
+import ij.io.FileInfo;
+import ij.io.FileSaver;
+import ij.io.OpenDialog;
+import ij.io.Opener;
+import ij.io.SaveDialog;
+import ij.measure.Calibration;
+import ij.measure.CurveFitter;
+import ij.measure.Measurements;
+import ij.measure.ResultsTable;
+import ij.plugin.BatchProcessor;
+import ij.plugin.Colors;
+import ij.plugin.FITS_Reader;
+import ij.plugin.FolderOpener;
+import ij.plugin.ImageCalculator;
+import ij.plugin.ImageInfo;
+import ij.plugin.MacroInstaller;
+import ij.plugin.Macro_Runner;
+import ij.plugin.Orthogonal_Views;
+import ij.plugin.Straightener;
+import ij.plugin.filter.*;
+import ij.plugin.frame.*;
+import ij.process.AutoThresholder;
+import ij.process.ColorProcessor;
+import ij.process.FHT;
+import ij.process.FloatBlitter;
+import ij.process.FloatPolygon;
+import ij.process.FloatProcessor;
+import ij.process.FloodFiller;
+import ij.process.ImageConverter;
+import ij.process.ImageProcessor;
+import ij.process.ImageStatistics;
+import ij.process.LUT;
+import ij.process.ShortProcessor;
+import ij.process.StackStatistics;
+import ij.text.*;
+import ij.util.IJMath;
+import ij.util.Tools;
+import ij.util.WildcardMatch;
+
+
+/** This class implements the built-in macro functions. */
+public class Functions implements ij.macro.MacroConstants, Measurements {
+ ij.macro.Interpreter interp;
+ ij.macro.Program pgm;
+ boolean updateNeeded;
+ boolean autoUpdate = true;
+ ImageProcessor defaultIP;
+ ImagePlus defaultImp;
+ int imageType;
+ boolean fontSet;
+ Color globalColor;
+ double globalValue = Double.NaN;
+ int globalLineWidth;
+ Plot plot;
+ static int plotID;
+ int justification = ImageProcessor.LEFT_JUSTIFY;
+ Font font;
+ GenericDialog gd;
+ PrintWriter writer;
+ boolean altKeyDown, shiftKeyDown;
+ boolean antialiasedText = IJ.isMacOSX()?true:false; //non-antialiased text is broken on macOS
+ boolean nonScalableText;
+ StringBuffer buffer;
+ RoiManager roiManager;
+ Properties props;
+ CurveFitter fitter;
+ boolean showFitDialog;
+ boolean logFitResults;
+ boolean resultsPending;
+ Overlay offscreenOverlay;
+ Overlay overlayClipboard;
+ static Roi roiClipboard;
+ GeneralPath overlayPath;
+ boolean overlayDrawLabels;
+ ResultsTable currentTable;
+ ResultsTable unUpdatedTable;
+
+ // save/restore settings
+ boolean saveSettingsCalled;
+ boolean usePointerCursor, hideProcessStackDialog;
+ float divideByZeroValue;
+ int jpegQuality;
+ int saveLineWidth;
+ boolean doScaling;
+ boolean weightedColor;
+ double[] weights;
+ boolean interpolateScaledImages, open100Percent, blackCanvas;
+ boolean useJFileChooser,debugMode;
+ Color foregroundColor, backgroundColor, roiColor;
+ boolean pointAutoMeasure, requireControlKey, useInvertingLut;
+ boolean disablePopup;
+ int measurements;
+ int decimalPlaces;
+ boolean blackBackground;
+ boolean autoContrast;
+ static WaitForUserDialog waitForUserDialog;
+ int pasteMode;
+ boolean expandableArrays = true;
+ int plotWidth;
+ int plotHeight;
+ int plotFontSize;
+ boolean plotInterpolate;
+ boolean plotNoGridLines;
+ boolean plotNoTicks;
+ boolean profileVerticalProfile;
+ boolean profileSubPixelResolution;
+ boolean waitForCompletion = true;
+
+
+ Functions(ij.macro.Interpreter interp, ij.macro.Program pgm) {
+ this.interp = interp;
+ this.pgm = pgm;
+ }
+
+ void doFunction(int type) {
+ switch (type) {
+ case RUN: doRun(); break;
+ case SELECT: selectWindow(); break;
+ case WAIT: IJ.wait((int)getArg()); break;
+ case BEEP: interp.getParens(); IJ.beep(); break;
+ case RESET_MIN_MAX: interp.getParens(); IJ.resetMinAndMax(); resetImage(); break;
+ case RESET_THRESHOLD: interp.getParens(); IJ.resetThreshold(); resetImage(); break;
+ case PRINT: case WRITE: print(); break;
+ case DO_WAND: doWand(); break;
+ case SET_MIN_MAX: setMinAndMax(); break;
+ case SET_THRESHOLD: setThreshold(); break;
+ case SET_TOOL: setTool(); break;
+ case SET_FOREGROUND: setForegroundColor(); break;
+ case SET_BACKGROUND: setBackgroundColor(); break;
+ case SET_COLOR: setColor(); break;
+ case MAKE_LINE: makeLine(); break;
+ case MAKE_ARROW: makeArrow(); break;
+ case MAKE_OVAL: makeOval(); break;
+ case MAKE_RECTANGLE: makeRectangle(); break;
+ case MAKE_ROTATED_RECT: makeRotatedRectangle(); break;
+ case DUMP: interp.dump(); break;
+ case LINE_TO: lineTo(); break;
+ case MOVE_TO: moveTo(); break;
+ case DRAW_LINE: drawLine(); break;
+ case REQUIRES: requires(); break;
+ case AUTO_UPDATE: autoUpdate = getBooleanArg(); break;
+ case UPDATE_DISPLAY: interp.getParens(); updateNeeded=true; updateDisplay(); break;
+ case DRAW_STRING: drawString(); break;
+ case SET_PASTE_MODE: IJ.setPasteMode(getStringArg()); break;
+ case DO_COMMAND: doCommand(); break;
+ case SHOW_STATUS: showStatus(); break;
+ case SHOW_PROGRESS: showProgress(); break;
+ case SHOW_MESSAGE: showMessage(false); break;
+ case SHOW_MESSAGE_WITH_CANCEL: showMessage(true); break;
+ case SET_PIXEL: case PUT_PIXEL: setPixel(); break;
+ case SNAPSHOT: case RESET: case FILL: doIPMethod(type); break;
+ case SET_LINE_WIDTH: setLineWidth((int)getArg()); break;
+ case CHANGE_VALUES: changeValues(); break;
+ case SELECT_IMAGE: selectImage(); break;
+ case EXIT: exit(); break;
+ case SET_LOCATION: setLocation(); break;
+ case GET_CURSOR_LOC: getCursorLoc(); break;
+ case GET_LINE: getLine(); break;
+ case GET_VOXEL_SIZE: getVoxelSize(); break;
+ case GET_HISTOGRAM: getHistogram(); break;
+ case GET_BOUNDING_RECT: case GET_BOUNDS: getBounds(true); break;
+ case GET_LUT: getLut(); break;
+ case SET_LUT: setLut(); break;
+ case GET_COORDINATES: getCoordinates(); break;
+ case MAKE_SELECTION: makeSelection(); break;
+ case SET_RESULT: setResult(null); break;
+ case UPDATE_RESULTS: updateResults(); break;
+ case SET_BATCH_MODE: setBatchMode(); break;
+ case SET_JUSTIFICATION: setJustification(); break;
+ case SET_Z_COORDINATE: setZCoordinate(); break;
+ case GET_THRESHOLD: getThreshold(); break;
+ case GET_PIXEL_SIZE: getPixelSize(); break;
+ case SETUP_UNDO: interp.getParens(); Undo.setup(Undo.MACRO, getImage()); break;
+ case SAVE_SETTINGS: saveSettings(); break;
+ case RESTORE_SETTINGS: restoreSettings(); break;
+ case SET_KEY_DOWN: setKeyDown(); break;
+ case OPEN: open(); break;
+ case SET_FONT: setFont(); break;
+ case GET_MIN_AND_MAX: getMinAndMax(); break;
+ case CLOSE: close(); break;
+ case SET_SLICE: setSlice(); break;
+ case NEW_IMAGE: newImage(); break;
+ case SAVE: IJ.save(getStringArg()); break;
+ case SAVE_AS: saveAs(); break;
+ case SET_AUTO_THRESHOLD: setAutoThreshold(); break;
+ case RENAME: getImage().setTitle(getStringArg()); break;
+ case GET_STATISTICS: getStatistics(true); break;
+ case GET_RAW_STATISTICS: getStatistics(false); break;
+ case FLOOD_FILL: floodFill(); break;
+ case RESTORE_PREVIOUS_TOOL: restorePreviousTool(); break;
+ case SET_VOXEL_SIZE: setVoxelSize(); break;
+ case GET_LOCATION_AND_SIZE: getLocationAndSize(); break;
+ case GET_DATE_AND_TIME: getDateAndTime(); break;
+ case SET_METADATA: setMetadata(); break;
+ case CALCULATOR: imageCalculator(); break;
+ case SET_RGB_WEIGHTS: setRGBWeights(); break;
+ case MAKE_POLYGON: makePolygon(); break;
+ case SET_SELECTION_NAME: setSelectionName(); break;
+ case DRAW_RECT: case FILL_RECT: case DRAW_OVAL: case FILL_OVAL: drawOrFill(type); break;
+ case SET_OPTION: setOption(); break;
+ case SHOW_TEXT: showText(); break;
+ case SET_SELECTION_LOC: setSelectionLocation(); break;
+ case GET_DIMENSIONS: getDimensions(); break;
+ case WAIT_FOR_USER: waitForUser(); break;
+ case MAKE_POINT: makePoint(); break;
+ case MAKE_TEXT: makeText(); break;
+ case MAKE_ELLIPSE: makeEllipse(); break;
+ case GET_DISPLAYED_AREA: getDisplayedArea(); break;
+ case TO_SCALED: toScaled(); break;
+ case TO_UNSCALED: toUnscaled(); break;
+ }
+ }
+
+ final double getFunctionValue(int type) {
+ double value = 0.0;
+ switch (type) {
+ case GET_PIXEL: value = getPixel(); break;
+ case ABS: case COS: case EXP: case FLOOR: case LOG: case ROUND:
+ case SIN: case SQRT: case TAN: case ATAN: case ASIN: case ACOS:
+ value = math(type);
+ break;
+ case MATH: value = doMath(); break;
+ case MAX_OF: case MIN_OF: case POW: case ATAN2: value=math2(type); break;
+ case GET_TIME: interp.getParens(); value=System.currentTimeMillis(); break;
+ case GET_WIDTH: interp.getParens(); value=getImage().getWidth(); break;
+ case GET_HEIGHT: interp.getParens(); value=getImage().getHeight(); break;
+ case RANDOM: value=random(); break;
+ case GET_COUNT: case NRESULTS: value=getResultsCount(); break;
+ case GET_RESULT: value=getResult(null); break;
+ case GET_NUMBER: value=getNumber(); break;
+ case NIMAGES: value=getImageCount(); break;
+ case NSLICES: value=getStackSize(); break;
+ case LENGTH_OF: value=lengthOf(); break;
+ case GET_ID: interp.getParens(); value=getImage().getID(); break;
+ case BIT_DEPTH: interp.getParens(); value = getImage().getBitDepth(); break;
+ case SELECTION_TYPE: value=getSelectionType(); break;
+ case IS_OPEN: value=isOpen(); break;
+ case IS_ACTIVE: value=isActive(); break;
+ case INDEX_OF: value=indexOf(null); break;
+ case LAST_INDEX_OF: value=getFirstString().lastIndexOf(getLastString()); break;
+ case CHAR_CODE_AT: value=charCodeAt(); break;
+ case GET_BOOLEAN: value=getBoolean(); break;
+ case STARTS_WITH: case ENDS_WITH: value = startsWithEndsWith(type); break;
+ case IS_NAN: value = Double.isNaN(getArg())?1:0; break;
+ case GET_ZOOM: value = getZoom(); break;
+ case PARSE_FLOAT: value = parseDouble(getStringArg()); break;
+ case PARSE_INT: value = parseInt(); break;
+ case IS_KEY_DOWN: value = isKeyDown(); break;
+ case GET_SLICE_NUMBER: interp.getParens(); value=getImage().getCurrentSlice(); break;
+ case SCREEN_WIDTH: case SCREEN_HEIGHT: value = getScreenDimension(type); break;
+ case CALIBRATE: value = getImage().getCalibration().getCValue(getArg()); break;
+ case ROI_MANAGER: value = roiManager(); break;
+ case TOOL_ID: interp.getParens(); value = Toolbar.getToolId(); break;
+ case IS: value = is(); break;
+ case GET_VALUE: value = getValue(); break;
+ case STACK: value = doStack(); break;
+ case MATCHES: value = matches(null); break;
+ case GET_STRING_WIDTH: value = getStringWidth(); break;
+ case FIT: value = fit(); break;
+ case OVERLAY: value = doOverlay(); break;
+ case SELECTION_CONTAINS: value = selectionContains(); break;
+ case PLOT: value = doPlot(); break;
+ default:
+ interp.error("Numeric function expected");
+ }
+ return value;
+ }
+
+ String getStringFunction(int type) {
+ String str;
+ switch (type) {
+ case D2S: str = d2s(); break;
+ case TO_HEX: str = toString(16); break;
+ case TO_BINARY: str = toString(2); break;
+ case GET_TITLE: interp.getParens(); str=getImage().getTitle(); break;
+ case GET_STRING: str = getStringDialog(); break;
+ case SUBSTRING: str=substring(null); break;
+ case FROM_CHAR_CODE: str = fromCharCode(); break;
+ case GET_INFO: str = getInfo(); break;
+ case GET_IMAGE_INFO: interp.getParens(); str = getImageInfo(); break;
+ case GET_DIRECTORY: case GET_DIR: str = getDirectory(); break;
+ case GET_ARGUMENT: interp.getParens(); str=interp.argument!=null?interp.argument:""; break;
+ case TO_LOWER_CASE: str = getStringArg().toLowerCase(Locale.US); break;
+ case TO_UPPER_CASE: str = getStringArg().toUpperCase(Locale.US); break;
+ case RUN_MACRO: str = runMacro(false); break;
+ case EVAL: str = runMacro(true); break;
+ case TO_STRING: str = doToString(); break;
+ case REPLACE: str = replace(null); break;
+ case DIALOG: str = doDialog(); break;
+ case GET_METADATA: str = getMetadata(); break;
+ case FILE: str = doFile(); break;
+ case SELECTION_NAME: str = selectionName(); break;
+ case GET_VERSION: interp.getParens(); str = IJ.getVersion(); break;
+ case GET_RESULT_LABEL: str = getResultLabel(); break;
+ case CALL: str = call(); break;
+ case STRING: str = doString(); break;
+ case EXT: str = doExt(); break;
+ case EXEC: str = exec(); break;
+ case LIST: str = doList(); break;
+ case DEBUG: str = debug(); break;
+ case IJ_CALL: str = doIJ(); break;
+ case GET_RESULT_STRING: str = getResultString(null); break;
+ case TRIM: str = trim(); break;
+ default:
+ str="";
+ interp.error("String function expected");
+ }
+ return str;
+ }
+
+ ij.macro.Variable[] getArrayFunction(int type) {
+ ij.macro.Variable[] array;
+ switch (type) {
+ case GET_PROFILE: array=getProfile(); break;
+ case NEW_ARRAY: array = newArray(); break;
+ case SPLIT: array = split(); break;
+ case GET_FILE_LIST: array = getFileList(); break;
+ case GET_FONT_LIST: array = getFontList(); break;
+ case NEW_MENU: array = newMenu(); break;
+ case GET_LIST: array = getList(); break;
+ case ARRAY_FUNC: array = doArray(); break;
+ default:
+ array = null;
+ interp.error("Array function expected");
+ }
+ return array;
+ }
+
+ // Functions returning a string must be added
+ // to isStringFunction(String,int).
+ ij.macro.Variable getVariableFunction(int type) {
+ ij.macro.Variable var = null;
+ switch (type) {
+ case TABLE: var = doTable(); break;
+ case ROI: var = doRoi(); break;
+ case ROI_MANAGER2: var = doRoiManager(); break;
+ case PROPERTY: var = doProperty(); break;
+ case IMAGE: var = doImage(); break;
+ case COLOR: var = doColor(); break;
+ default:
+ interp.error("Variable function expected");
+ }
+ if (var==null)
+ var = new ij.macro.Variable(Double.NaN);
+ return var;
+ }
+
+ private void setLineWidth(int width) {
+ if (WindowManager.getCurrentImage()!=null) {
+ if (overlayPath!=null && width!=globalLineWidth)
+ addDrawingToOverlay(getImage());
+ getProcessor().setLineWidth(width);
+ }
+ globalLineWidth = width;
+ }
+
+ private double doMath() {
+ interp.getToken();
+ if (interp.token!='.')
+ interp.error("'.' expected");
+ interp.getToken();
+ if (!(interp.token==WORD||interp.token==NUMERIC_FUNCTION))
+ interp.error("Function name expected: ");
+ String name = interp.tokenString;
+ if (name.equals("min"))
+ return Math.min(getFirstArg(), getLastArg());
+ else if (name.equals("max"))
+ return Math.max(getFirstArg(), getLastArg());
+ else if (name.equals("pow"))
+ return Math.pow(getFirstArg(), getLastArg());
+ else if (name.equals("atan2"))
+ return Math.atan2(getFirstArg(), getLastArg());
+ else if (name.equals("constrain"))
+ return Math.min(Math.max(getFirstArg(), getNextArg()), getLastArg());
+ else if (name.equals("map")) {
+ double value = getFirstArg();
+ double fromLow = getNextArg();
+ double fromHigh = getNextArg();
+ double toLow = getNextArg();
+ double toHigh = getLastArg();
+ return (value-fromLow)*(toHigh-toLow)/(fromHigh-fromLow)+toLow;
+ }
+ double arg = getArg();
+ if (name.equals("ceil"))
+ return Math.ceil(arg);
+ else if (name.equals("abs"))
+ return Math.abs(arg);
+ else if (name.equals("cos"))
+ return Math.cos(arg);
+ else if (name.equals("exp"))
+ return Math.exp(arg);
+ else if (name.equals("floor"))
+ return Math.floor(arg);
+ else if (name.equals("log"))
+ return Math.log(arg);
+ else if (name.equals("log10"))
+ return Math.log10(arg);
+ else if (name.equals("round"))
+ return Math.round(arg);
+ else if (name.equals("sin"))
+ return Math.sin(arg);
+ else if (name.equals("sqr"))
+ return arg*arg;
+ else if (name.equals("sqrt"))
+ return Math.sqrt(arg);
+ else if (name.equals("tan"))
+ return Math.tan(arg);
+ else if (name.equals("atan"))
+ return Math.atan(arg);
+ else if (name.equals("asin"))
+ return Math.asin(arg);
+ else if (name.equals("acos"))
+ return Math.acos(arg);
+ else if (name.equals("erf"))
+ return IJMath.erf(arg);
+ else if (name.equals("toRadians"))
+ return Math.toRadians(arg);
+ else if (name.equals("toDegrees"))
+ return Math.toDegrees(arg);
+ else
+ interp.error("Unrecognized function name");
+ return Double.NaN;
+ }
+
+ final double math(int type) {
+ double arg = getArg();
+ switch (type) {
+ case ABS: return Math.abs(arg);
+ case COS: return Math.cos(arg);
+ case EXP: return Math.exp(arg);
+ case FLOOR: return Math.floor(arg);
+ case LOG: return Math.log(arg);
+ case ROUND: return Math.floor(arg + 0.5);
+ case SIN: return Math.sin(arg);
+ case SQRT: return Math.sqrt(arg);
+ case TAN: return Math.tan(arg);
+ case ATAN: return Math.atan(arg);
+ case ASIN: return Math.asin(arg);
+ case ACOS: return Math.acos(arg);
+ default: return 0.0;
+ }
+ }
+
+ final double math2(int type) {
+ double a1 = getFirstArg();
+ double a2 = getLastArg();
+ switch (type) {
+ case MIN_OF: return Math.min(a1, a2);
+ case MAX_OF: return Math.max(a1, a2);
+ case POW: return Math.pow(a1, a2);
+ case ATAN2: return Math.atan2(a1, a2);
+ default: return 0.0;
+ }
+ }
+
+ final String getString() {
+ String str = interp.getStringTerm();
+ while (true) {
+ interp.getToken();
+ if (interp.token=='+')
+ str += interp.getStringTerm();
+ else {
+ interp.putTokenBack();
+ break;
+ }
+ };
+ return str;
+ }
+
+ final boolean isStringFunction() {
+ ij.macro.Symbol symbol = pgm.table[interp.tokenAddress];
+ return symbol.type==D2S;
+ }
+
+ final double getArg() {
+ interp.getLeftParen();
+ double arg = interp.getExpression();
+ interp.getRightParen();
+ return arg;
+ }
+
+ final double getFirstArg() {
+ interp.getLeftParen();
+ return interp.getExpression();
+ }
+
+ final double getNextArg() {
+ interp.getComma();
+ return interp.getExpression();
+ }
+
+ final double getLastArg() {
+ interp.getComma();
+ double arg = interp.getExpression();
+ interp.getRightParen();
+ return arg;
+ }
+
+ String getStringArg() {
+ interp.getLeftParen();
+ String arg = getString();
+ interp.getRightParen();
+ return arg;
+ }
+
+ final String getFirstString() {
+ interp.getLeftParen();
+ return getString();
+ }
+
+ final String getNextString() {
+ interp.getComma();
+ return getString();
+ }
+
+ final String getLastString() {
+ interp.getComma();
+ String arg = getString();
+ interp.getRightParen();
+ return arg;
+ }
+
+ boolean getBooleanArg() {
+ interp.getLeftParen();
+ double arg = interp.getBooleanExpression();
+ interp.checkBoolean(arg);
+ interp.getRightParen();
+ return arg==0?false:true;
+ }
+
+ final ij.macro.Variable getVariableArg() {
+ interp.getLeftParen();
+ ij.macro.Variable v = getVariable();
+ interp.getRightParen();
+ return v;
+ }
+
+ final ij.macro.Variable getFirstVariable() {
+ interp.getLeftParen();
+ return getVariable();
+ }
+
+ final ij.macro.Variable getNextVariable() {
+ interp.getComma();
+ return getVariable();
+ }
+
+ final ij.macro.Variable getLastVariable() {
+ interp.getComma();
+ ij.macro.Variable v = getVariable();
+ interp.getRightParen();
+ return v;
+ }
+
+ final ij.macro.Variable getVariable() {
+ interp.getToken();
+ if (interp.token!=WORD)
+ interp.error("Variable expected");
+ ij.macro.Variable v = interp.lookupLocalVariable(interp.tokenAddress);
+ if (v==null)
+ v = interp.push(interp.tokenAddress, 0.0, null, interp);
+ ij.macro.Variable[] array = v.getArray();
+ if (array!=null) {
+ int index = interp.getIndex();
+ checkIndex(index, 0, v.getArraySize()-1);
+ v = array[index];
+ }
+ return v;
+ }
+
+ final ij.macro.Variable getFirstArrayVariable() {
+ interp.getLeftParen();
+ return getArrayVariable();
+ }
+
+ final ij.macro.Variable getNextArrayVariable() {
+ interp.getComma();
+ return getArrayVariable();
+ }
+
+ final ij.macro.Variable getLastArrayVariable() {
+ interp.getComma();
+ ij.macro.Variable v = getArrayVariable();
+ interp.getRightParen();
+ return v;
+ }
+
+ final ij.macro.Variable getArrayVariable() {
+ interp.getToken();
+ if (interp.token!=WORD)
+ interp.error("Variable expected");
+ ij.macro.Variable v = interp.lookupLocalVariable(interp.tokenAddress);
+ if (v==null)
+ v = interp.push(interp.tokenAddress, 0.0, null, interp);
+ return v;
+ }
+
+ final double[] getFirstArray() {
+ interp.getLeftParen();
+ return getNumericArray();
+ }
+
+ final double[] getNextArray() {
+ interp.getComma();
+ return getNumericArray();
+ }
+
+ final double[] getLastArray() {
+ interp.getComma();
+ double[] a = getNumericArray();
+ interp.getRightParen();
+ return a;
+ }
+
+ double[] getNumericArray() {
+ ij.macro.Variable[] a1 = getArray();
+ double[] a2 = new double[a1.length];
+ for (int i=0; iupper)
+ interp.error("Index ("+index+") is outside of the "+lower+"-"+upper+" range");
+ }
+
+ void doRun() {
+ interp.getLeftParen();
+ String arg1 = getString();
+ interp.getToken();
+ if (!(interp.token==')' || interp.token==','))
+ interp.error("',' or ')' expected");
+ String arg2 = null;
+ if (interp.token==',') {
+ arg2 = getString();
+ interp.getRightParen();
+ }
+ IJ.run(this.interp, arg1, arg2);
+ resetImage();
+ IJ.setKeyUp(IJ.ALL_KEYS);
+ shiftKeyDown = altKeyDown = false;
+ }
+
+ private void selectWindow() {
+ String title = getStringArg();
+ if (resultsPending && "Results".equals(title)) {
+ ResultsTable rt = ResultsTable.getResultsTable();
+ if (rt!=null && rt.size()>0)
+ rt.show("Results");
+ }
+ IJ.selectWindow(title);
+ resetImage();
+ }
+
+ void setForegroundColor() {
+ boolean isImage = WindowManager.getCurrentImage()!=null;
+ int lnWidth = 0;
+ if (isImage)
+ lnWidth = getProcessor().getLineWidth();
+ int red=0, green=0, blue=0;
+ int arg1 = (int)getFirstArg();
+ if (interp.nextToken()==')') {
+ interp.getRightParen();
+ red = (arg1&0xff0000)>>16;
+ green = (arg1&0xff00)>>8;
+ blue = arg1&0xff;
+ } else {
+ red = arg1;
+ green = (int)getNextArg();
+ blue = (int)getLastArg();
+ }
+ IJ.setForegroundColor(red, green, blue);
+ resetImage();
+ if (isImage)
+ setLineWidth(lnWidth);
+ globalColor = null;
+ globalValue = Double.NaN;
+ }
+
+ void setBackgroundColor() {
+ int red=0, green=0, blue=0;
+ int arg1 = (int)getFirstArg();
+ if (interp.nextToken()==')') {
+ interp.getRightParen();
+ red = (arg1&0xff0000)>>16;
+ green = (arg1&0xff00)>>8;
+ blue = arg1&0xff;
+ } else {
+ red = arg1;
+ green = (int)getNextArg();
+ blue = (int)getLastArg();
+ }
+ IJ.setBackgroundColor(red, green, blue);
+ resetImage();
+ }
+
+ void setColor() {
+ interp.getLeftParen();
+ if (isStringArg()) {
+ globalColor = getColor();
+ globalValue = Double.NaN;
+ ImagePlus imp = WindowManager.getCurrentImage();
+ if (imp!=null) {
+ if (overlayPath!=null)
+ addDrawingToOverlay(imp);
+ getProcessor().setColor(globalColor);
+ getProcessor().fillColorSet(true);
+ }
+ interp.getRightParen();
+ return;
+ }
+ double arg1 = interp.getExpression();
+ if (interp.nextToken()==')') {
+ interp.getRightParen();
+ setColor(arg1);
+ return;
+ }
+ int red=(int)arg1, green=(int)getNextArg(), blue=(int)getLastArg();
+ if (red<0) red=0; if (green<0) green=0; if (blue<0) blue=0;
+ if (red>255) red=255; if (green>255) green=255; if (blue>255) blue=255;
+ globalColor = new Color(red, green, blue);
+ globalValue = Double.NaN;
+ if (WindowManager.getCurrentImage()!=null) {
+ getProcessor().setColor(globalColor);
+ getProcessor().fillColorSet(true);
+ }
+ }
+
+ void setColor(double value) {
+ ImageProcessor ip = getProcessor();
+ ImagePlus imp = getImage();
+ switch (imp.getBitDepth()) {
+ case 8:
+ if (value<0 || value>255)
+ interp.error("Argument out of 8-bit range (0-255)");
+ ip.setValue(value);
+ break;
+ case 16:
+ if (imp.getLocalCalibration().isSigned16Bit())
+ value += 32768;
+ if (value<0 || value>65535)
+ interp.error("Argument out of 16-bit range (0-65535)");
+ ip.setValue(value);
+ break;
+ default:
+ ip.setValue(value);
+ break;
+ }
+ globalValue = value;
+ globalColor = null;
+ ip.fillColorSet(true);
+ }
+
+ void makeLine() {
+ double x1d = getFirstArg();
+ double y1d = getNextArg();
+ double x2d = getNextArg();
+ interp.getComma();
+ double y2d = interp.getExpression();
+ interp.getToken();
+ if (interp.token==')')
+ IJ.makeLine(x1d, y1d, x2d, y2d);
+ else {
+ Polygon points = new Polygon();
+ points.addPoint((int)Math.round(x1d),(int)Math.round(y1d));
+ points.addPoint((int)Math.round(x2d),(int)Math.round(y2d));
+ while (interp.token==',') {
+ int x = (int)Math.round(interp.getExpression());
+ if (points.npoints==2 && interp.nextToken()==')') {
+ interp.getRightParen();
+ Roi line = new Line(x1d, y1d, x2d, y2d);
+ line.updateWideLine((float)x);
+ getImage().setRoi(line);
+ return;
+ }
+ interp.getComma();
+ int y = (int)Math.round(interp.getExpression());
+ points.addPoint(x,y);
+ interp.getToken();
+ }
+ getImage().setRoi(new PolygonRoi(points, Roi.POLYLINE));
+ }
+ resetImage();
+ }
+
+ void makeArrow() {
+ String options = "";
+ double x1 = getFirstArg();
+ double y1 = getNextArg();
+ double x2 = getNextArg();
+ double y2 = getNextArg();
+ if (interp.nextToken()==',')
+ options = getNextString();
+ interp.getRightParen();
+ Arrow arrow = new Arrow(x1, y1, x2, y2);
+ arrow.setStyle(options);
+ getImage().setRoi(arrow);
+ }
+
+ void makeOval() {
+ Roi previousRoi = getImage().getRoi();
+ if (shiftKeyDown||altKeyDown) getImage().saveRoi();
+ IJ.makeOval(getFirstArg(), getNextArg(), getNextArg(), getLastArg());
+ Roi roi = getImage().getRoi();
+ if (previousRoi!=null && roi!=null)
+ updateRoi(roi);
+ resetImage();
+ shiftKeyDown = altKeyDown = false;
+ IJ.setKeyUp(IJ.ALL_KEYS);
+ }
+
+ void makeRectangle() {
+ Roi previousRoi = getImage().getRoi();
+ if (shiftKeyDown||altKeyDown) getImage().saveRoi();
+ double x = getFirstArg();
+ double y = getNextArg();
+ double w = getNextArg();
+ double h = getNextArg();
+ int arcSize = 0;
+ if (interp.nextToken()==',') {
+ interp.getComma();
+ arcSize = (int)interp.getExpression();
+ }
+ interp.getRightParen();
+ if (arcSize<1)
+ IJ.makeRectangle(x, y, w, h);
+ else {
+ ImagePlus imp = getImage();
+ imp.setRoi(new Roi(x,y,w,h,arcSize));
+ }
+ Roi roi = getImage().getRoi();
+ if (previousRoi!=null && roi!=null)
+ updateRoi(roi);
+ resetImage();
+ shiftKeyDown = altKeyDown = false;
+ IJ.setKeyUp(IJ.ALL_KEYS);
+ }
+
+ void makeRotatedRectangle() {
+ getImage().setRoi(new RotatedRectRoi(getFirstArg(), getNextArg(), getNextArg(), getNextArg(), getLastArg()));
+ resetImage();
+ }
+
+ ImagePlus getImage() {
+ ImagePlus imp = IJ.getImage(interp);
+ if (imp.getWindow()==null && IJ.getInstance()!=null && !interp.isBatchMode() && WindowManager.getTempCurrentImage()==null)
+ throw new RuntimeException(Macro.MACRO_CANCELED);
+ defaultIP = null;
+ defaultImp = imp;
+ return imp;
+ }
+
+ void resetImage() {
+ defaultImp = null;
+ defaultIP = null;
+ fontSet = false;
+ }
+
+ ImageProcessor getProcessor() {
+ if (defaultIP==null) {
+ defaultIP = getImage().getProcessor();
+ if (globalLineWidth>0)
+ defaultIP.setLineWidth(globalLineWidth);
+ if (globalColor!=null)
+ defaultIP.setColor(globalColor);
+ else if (!Double.isNaN(globalValue))
+ defaultIP.setValue(globalValue);
+ else
+ defaultIP.setColor(Toolbar.getForegroundColor());
+ }
+ return defaultIP;
+ }
+
+ int getType() {
+ imageType = getImage().getType();
+ return imageType;
+ }
+
+ void setPixel() {
+ interp.getLeftParen();
+ int a1 = (int)interp.getExpression();
+ interp.getComma();
+ double a2 = interp.getExpression();
+ interp.getToken();
+ ImageProcessor ip = getProcessor();
+ if (interp.token==',') {
+ double a3 = interp.getExpression();
+ interp.getRightParen();
+ if (ip instanceof FloatProcessor)
+ ip.putPixelValue(a1, (int)a2, a3);
+ else
+ ip.putPixel(a1, (int)a2, (int)a3);
+ } else {
+ if (interp.token!=')') interp.error("')' expected");
+ if (ip instanceof ColorProcessor)
+ ip.set(a1, (int)a2);
+ else
+ ip.setf(a1, (float)a2);
+ }
+ updateNeeded = true;
+ }
+
+ double getPixel() {
+ interp.getLeftParen();
+ double a1 = interp.getExpression();
+ ImageProcessor ip = getProcessor();
+ double value = 0.0;
+ interp.getToken();
+ if (interp.token==',') {
+ double a2 = interp.getExpression();
+ interp.getRightParen();
+ int ia1 = (int)a1;
+ int ia2 = (int)a2;
+ if (a1==ia1 && a2==ia2) {
+ if (ip instanceof FloatProcessor)
+ value = ip.getPixelValue(ia1, ia2);
+ else
+ value = ip.getPixel(ia1, ia2);
+ } else {
+ if (ip instanceof ColorProcessor)
+ value = ip.getPixelInterpolated(a1, a2);
+ else {
+ ImagePlus imp = getImage();
+ Calibration cal = imp.getCalibration();
+ imp.setCalibration(null);
+ ip = imp.getProcessor();
+ value = ip.getInterpolatedValue(a1, a2);
+ imp.setCalibration(cal);
+ }
+ }
+ } else {
+ if (interp.token!=')') interp.error("')' expected");
+ if (ip instanceof ColorProcessor)
+ value = ip.get((int)a1);
+ else
+ value = ip.getf((int)a1);
+ }
+ return value;
+ }
+
+ void setZCoordinate() {
+ int z = (int)getArg();
+ int n = z + 1;
+ ImagePlus imp = getImage();
+ ImageStack stack = imp.getStack();
+ int size = stack.size();
+ if (z<0 || z>=size)
+ interp.error("Z coordinate ("+z+") is out of 0-"+(size-1)+ " range");
+ this.defaultIP = stack.getProcessor(n);
+ }
+
+ void moveTo() {
+ interp.getLeftParen();
+ int a1 = (int)Math.round(interp.getExpression());
+ interp.getComma();
+ int a2 = (int)Math.round(interp.getExpression());
+ interp.getRightParen();
+ getProcessor().moveTo(a1, a2);
+ }
+
+ void lineTo() {
+ interp.getLeftParen();
+ int a1 = (int)Math.round(interp.getExpression());
+ interp.getComma();
+ int a2 = (int)Math.round(interp.getExpression());
+ interp.getRightParen();
+ ImageProcessor ip = getProcessor();
+ ip.lineTo(a1, a2);
+ updateAndDraw();
+ }
+
+ void drawLine() {
+ interp.getLeftParen();
+ int x1 = (int)Math.round(interp.getExpression());
+ interp.getComma();
+ int y1 = (int)Math.round(interp.getExpression());
+ interp.getComma();
+ int x2 = (int)Math.round(interp.getExpression());
+ interp.getComma();
+ int y2 = (int)Math.round(interp.getExpression());
+ interp.getRightParen();
+ ImageProcessor ip = getProcessor();
+ ip.drawLine(x1, y1, x2, y2);
+ updateAndDraw();
+ }
+
+ void doIPMethod(int type) {
+ interp.getParens();
+ ImageProcessor ip = getProcessor();
+ switch (type) {
+ case SNAPSHOT: ip.snapshot(); break;
+ case RESET:
+ ip.reset();
+ updateNeeded = true;
+ break;
+ case FILL:
+ ImagePlus imp = getImage();
+ Roi roi = imp.getRoi();
+ if (roi==null) {
+ ip.resetRoi();
+ ip.fill();
+ } else {
+ ip.setRoi(roi);
+ ip.fill(ip.getMask());
+ }
+ imp.updateAndDraw();
+ break;
+ }
+ }
+
+ void updateAndDraw() {
+ if (autoUpdate) {
+ ImagePlus imp = defaultImp;
+ if (imp==null)
+ imp = getImage();
+ imp.updateChannelAndDraw();
+ imp.changes = true;
+ } else
+ updateNeeded = true;
+ }
+
+ void updateDisplay() {
+ if (updateNeeded && WindowManager.getImageCount()>0) {
+ ImagePlus imp = getImage();
+ imp.updateAndDraw();
+ updateNeeded = false;
+ }
+ }
+
+ void drawString() {
+ interp.getLeftParen();
+ String str = getString();
+ interp.getComma();
+ int x = (int)(interp.getExpression()+0.5);
+ interp.getComma();
+ int y = (int)(interp.getExpression()+0.5);
+ Color background = null;
+ if (interp.nextToken()==',') {
+ interp.getComma();
+ background = getColor();
+ }
+ interp.getRightParen();
+ ImageProcessor ip = getProcessor();
+ setFont(ip);
+ ip.setJustification(justification);
+ ip.setAntialiasedText(antialiasedText);
+ if (background!=null)
+ ip.drawString(str, x, y, background);
+ else
+ ip.drawString(str, x, y);
+ updateAndDraw();
+ }
+
+ void setFont(ImageProcessor ip) {
+ if (font!=null && !fontSet)
+ ip.setFont(font);
+ fontSet = true;
+ }
+
+ void setJustification() {
+ String str = getStringArg().toLowerCase(Locale.US);
+ int just = ImageProcessor.LEFT_JUSTIFY;
+ if (str.equals("center"))
+ just = ImageProcessor.CENTER_JUSTIFY;
+ else if (str.equals("right"))
+ just = ImageProcessor.RIGHT_JUSTIFY;
+ justification = just;
+ }
+
+ void changeValues() {
+ double darg1 = getFirstArg();
+ double darg2 = getNextArg();
+ double darg3 = getLastArg();
+ ImagePlus imp = getImage();
+ ImageProcessor ip = getProcessor();
+ Roi roi = imp.getRoi();
+ ImageProcessor mask = null;
+ if (roi==null || !roi.isArea()) {
+ ip.resetRoi();
+ roi = null;
+ } else {
+ ip.setRoi(roi);
+ mask = ip.getMask();
+ if (mask!=null) ip.snapshot();
+ }
+ int xmin=0, ymin=0, xmax=imp.getWidth(), ymax=imp.getHeight();
+ if (roi!=null) {
+ Rectangle r = roi.getBounds();
+ xmin=r.x; ymin=r.y; xmax=r.x+r.width; ymax=r.y+r.height;
+ }
+ boolean isFloat = getType()==ImagePlus.GRAY32;
+ if (imp.getBitDepth()==24) {
+ darg1 = (int)darg1&0xffffff;
+ darg2 = (int)darg2&0xffffff;
+ }
+ double v;
+ for (int y=ymin; y=darg1 && v<=darg2;
+ if (Double.isNaN(darg1) && Double.isNaN(darg2) && Double.isNaN(v))
+ replace = true;
+ if (replace) {
+ if (isFloat)
+ ip.putPixelValue(x, y, darg3);
+ else
+ ip.putPixel(x, y, (int)darg3);
+ }
+ }
+ }
+ if (mask!=null) ip.reset(mask);
+ imp.updateAndDraw();
+ updateNeeded = false;
+ }
+
+ void requires() {
+ if (IJ.versionLessThan(getStringArg()))
+ interp.done = true;
+ }
+
+ Random ran;
+ double random() {
+ double dseed = Double.NaN;
+ boolean gaussian = false;
+ if (interp.nextToken()=='(') {
+ interp.getLeftParen();
+ if (isStringArg()) {
+ String arg = getString().toLowerCase(Locale.US);
+ if (arg.equals("seed")) {
+ interp.getComma();
+ dseed = interp.getExpression();
+ long seed = (long)dseed;
+ if (seed!=dseed)
+ interp.error("Seed not integer");
+ ran = new Random(seed);
+ ImageProcessor.setRandomSeed(seed);
+ } else if (arg.equals("gaussian"))
+ gaussian = true;
+ else
+ interp.error("'seed' or ''gaussian' expected");
+ }
+ interp.getRightParen();
+ if (!Double.isNaN(dseed)) return Double.NaN;
+ }
+ ImageProcessor.setRandomSeed(Double.NaN);
+ interp.getParens();
+ if (ran==null)
+ ran = new Random();
+ if (gaussian)
+ return ran.nextGaussian();
+ else
+ return ran.nextDouble();
+ }
+
+ double getResult(ResultsTable rt) {
+ interp.getLeftParen();
+ String column = getString();
+ int row = -1;
+ if (interp.nextToken()==',') {
+ interp.getComma();
+ row = (int)interp.getExpression();
+ }
+ if (interp.nextToken()==',') {
+ interp.getComma();
+ String title = getString();
+ rt = getResultsTable(title);
+ }
+ if (rt==null)
+ rt = getResultsTable(true);
+ interp.getRightParen();
+ int counter = rt.size();
+ if (row==-1) row = counter-1;
+ if (row<0 || row>=counter)
+ interp.error("Row ("+row+") out of range");
+ int col = rt.getColumnIndex(column);
+ if (!rt.columnExists(col))
+ return Double.NaN;
+ else {
+ double value = rt.getValueAsDouble(col, row);
+ if (Double.isNaN(value)) {
+ String s = rt.getStringValue(col, row);
+ if (s!=null && !s.equals("NaN"))
+ value = Tools.parseDouble(s);
+ }
+ return value;
+ }
+ }
+
+ String getResultString(ResultsTable rt) {
+ interp.getLeftParen();
+ String column = getString();
+ int row = -1;
+ if (interp.nextToken()==',') {
+ interp.getComma();
+ row = (int)interp.getExpression();
+ }
+ if (interp.nextToken()==',') {
+ interp.getComma();
+ String title = getString();
+ rt = getResultsTable(title);
+ }
+ interp.getRightParen();
+ if (rt==null)
+ rt = getResultsTable(true);
+ int counter = rt.size();
+ if (row==-1) row = counter-1;
+ if (row<0 || row>=counter)
+ interp.error("Row ("+row+") out of range");
+ int col = rt.getColumnIndex(column);
+ if (rt.columnExists(col))
+ return rt.getStringValue(col, row);
+ else {
+ String label = null;
+ if ("Label".equals(column))
+ label = rt.getLabel(row);
+ return label!=null?label:"null";
+ }
+ }
+
+ String getResultLabel() {
+ int row = (int)getArg();
+ ResultsTable rt = getResultsTable(true);
+ int counter = rt.size();
+ if (row<0 || row>=counter)
+ interp.error("Row ("+row+") out of range");
+ String label = rt.getLabel(row);
+ if (label!=null)
+ return label;
+ else {
+ label = rt.getStringValue("Label", row);
+ return label!=null?label:"";
+ }
+ }
+
+ private ResultsTable getResultsTable(boolean reportErrors) {
+ ResultsTable rt = Analyzer.getResultsTable();
+ int size = rt.size();
+ if (size==0) {
+ Frame frame = WindowManager.getFrontWindow();
+ if (frame==null || (frame instanceof Editor))
+ frame = WindowManager.getFrame("Results");
+ if (frame!=null && (frame instanceof TextWindow)) {
+ TextPanel tp = ((TextWindow)frame).getTextPanel();
+ rt = tp.getOrCreateResultsTable();
+ size = rt!=null?rt.size():0;
+ }
+ }
+ if (size==0) {
+ Window win = WindowManager.getActiveTable();
+ if (win!=null && (win instanceof TextWindow)) {
+ TextPanel tp = ((TextWindow)win).getTextPanel();
+ rt = tp.getOrCreateResultsTable();
+ size = rt!=null?rt.size():0;
+ }
+ }
+ if (size==0 && reportErrors)
+ interp.error("No results found");
+ return rt;
+ }
+
+ void setResult(ResultsTable rt) {
+ interp.getLeftParen();
+ String column = getString();
+ interp.getComma();
+ int row = (int)interp.getExpression();
+ interp.getComma();
+ double value = 0.0;
+ String stringValue = null;
+ boolean isLabel = column.equals("Label");
+ if (isStringArg() || isLabel)
+ stringValue = getString();
+ else
+ value = interp.getExpression();
+ if (interp.nextToken()==',') {
+ interp.getComma();
+ String title = getString();
+ rt = getResultsTable(title);
+ }
+ interp.getRightParen();
+ if (rt==null) {
+ rt = Analyzer.getResultsTable();
+ resultsPending = true;
+ } else
+ unUpdatedTable = rt;
+ if (row<0 || row>rt.size())
+ interp.error("Row ("+row+") out of range");
+ if (row==rt.size())
+ rt.incrementCounter();
+ try {
+ if (stringValue!=null) {
+ if (isLabel)
+ rt.setLabel(stringValue, row);
+ else
+ rt.setValue(column, row, stringValue);
+ } else
+ rt.setValue(column, row, value);
+ } catch (Exception e) {
+ interp.error(""+e.getMessage());
+ }
+ }
+
+ void updateResults() {
+ interp.getParens();
+ ResultsTable rt = Analyzer.getResultsTable();
+ rt.show("Results");
+ resultsPending = false;
+ }
+
+ double getNumber() {
+ String prompt = getFirstString();
+ double defaultValue = getLastArg();
+ String title = interp.macroName!=null?interp.macroName:"";
+ if (title.endsWith(" Options"))
+ title = title.substring(0, title.length()-8);
+ GenericDialog gd = new GenericDialog(title);
+ int decimalPlaces = (int)defaultValue==defaultValue?0:2;
+ gd.addNumericField(prompt, defaultValue, decimalPlaces);
+ gd.showDialog();
+ if (gd.wasCanceled()) {
+ interp.done = true;
+ return defaultValue;
+ }
+ double v = gd.getNextNumber();
+ if (gd.invalidNumber())
+ return defaultValue;
+ else
+ return v;
+ }
+
+ double getBoolean() {
+ interp.getLeftParen();
+ String prompt = getString();
+ String yesButton = " Yes ";
+ String noButton = " No ";
+ if (interp.nextToken()==',') {
+ yesButton = getNextString();
+ noButton = getNextString();
+ }
+ interp.getRightParen();
+ String title = interp.macroName!=null?interp.macroName:"";
+ if (title.endsWith(" Options"))
+ title = title.substring(0, title.length()-8);
+ YesNoCancelDialog d = new YesNoCancelDialog(IJ.getInstance(), title, prompt, yesButton, noButton);
+ if (d.cancelPressed()) {
+ interp.done = true;
+ return 0.0;
+ } else if (d.yesPressed())
+ return 1.0;
+ else
+ return 0.0;
+ }
+
+ String getStringDialog() {
+ interp.getLeftParen();
+ String prompt = getString();
+ interp.getComma();
+ String defaultStr = getString();
+ interp.getRightParen();
+
+ String title = interp.macroName!=null?interp.macroName:"";
+ if (title.endsWith(" Options"))
+ title = title.substring(0, title.length()-8);
+ GenericDialog gd = new GenericDialog(title);
+ gd.addStringField(prompt, defaultStr, 20);
+ gd.showDialog();
+ String str = "";
+ if (gd.wasCanceled())
+ interp.done = true;
+ else
+ str = gd.getNextString();
+ return str;
+ }
+
+ String d2s() {
+ return IJ.d2s(getFirstArg(), (int)getLastArg());
+ }
+
+ String toString(int base) {
+ int arg = (int)getArg();
+ if (base==2)
+ return Integer.toBinaryString(arg);
+ else
+ return Integer.toHexString(arg);
+ }
+
+ double getStackSize() {
+ interp.getParens();
+ return getImage().getStackSize();
+ }
+
+ double getImageCount() {
+ interp.getParens();
+ return WindowManager.getImageCount();
+ }
+
+ double getResultsCount() {
+ interp.getParens();
+ return Analyzer.getResultsTable().getCounter();
+ }
+
+ void getCoordinates() {
+ ij.macro.Variable xCoordinates = getFirstArrayVariable();
+ ij.macro.Variable yCoordinates = getLastArrayVariable();
+ ImagePlus imp = getImage();
+ Roi roi = imp.getRoi();
+ if (roi==null)
+ interp.error("Selection required");
+ ij.macro.Variable[] xa, ya;
+ if (roi.getType()==Roi.LINE) {
+ xa = new ij.macro.Variable[2];
+ ya = new ij.macro.Variable[2];
+ Line line = (Line)roi;
+ xa[0] = new ij.macro.Variable(line.x1d);
+ ya[0] = new ij.macro.Variable(line.y1d);
+ xa[1] = new ij.macro.Variable(line.x2d);
+ ya[1] = new ij.macro.Variable(line.y2d);
+ } else {
+ FloatPolygon fp = roi.getFloatPolygon();
+ if (fp!=null) {
+ xa = new ij.macro.Variable[fp.npoints];
+ ya = new ij.macro.Variable[fp.npoints];
+ for (int i=0; i0 && s2!=null && (s2.equals(",")||s2.equals(";")))
+ strings = s1.split(s2,-1);
+ else if (s1.length()>0 && s2!=null && s2.length()>=3 && s2.startsWith("(")&&s2.endsWith(")")) {
+ s2 = s2.substring(1,s2.length()-1);
+ strings = s1.split(s2,-1);
+ } else
+ strings = (s2==null||s2.equals(""))?Tools.split(s1):Tools.split(s1, s2);
+ ij.macro.Variable[] array = new ij.macro.Variable[strings.length];
+ for (int i=0; i0) {
+ String[] list2 = new String[n];
+ int j = 0;
+ for (int i=0; i65535)
+ interp.error("Value (" + value + ") out of 0-65535 range");
+ chars[count++] = (char)value;
+ if (interp.nextToken()==',')
+ interp.getToken();
+ }
+ interp.getRightParen();
+ return new String(chars, 0, count);
+ }
+
+ String getInfo() {
+ if (interp.nextNextToken()==STRING_CONSTANT
+ || (interp.nextToken()=='('&&interp.nextNextToken()!=')'))
+ return getInfo(getStringArg());
+ else {
+ interp.getParens();
+ return getWindowContents();
+ }
+ }
+
+ String getInfo(String key) {
+ String lowercaseKey = key.toLowerCase(Locale.US);
+ int len = lowercaseKey.length();
+ if (lowercaseKey.equals("command.name")) {
+ return ImageJ.getCommandName();
+ } else if (lowercaseKey.equals("overlay")) {
+ Overlay overlay = getImage().getOverlay();
+ if (overlay==null)
+ return "";
+ else
+ return overlay.toString();
+ } else if (lowercaseKey.equals("log")) {
+ String log = IJ.getLog();
+ return log!=null?log:"";
+ } else if (key.indexOf(".")==-1) {
+ ImagePlus imp = getImage();
+ String value = imp.getStringProperty(key);
+ if (value!=null) return value;
+ } else if (lowercaseKey.equals("micrometer.abbreviation")) {
+ return "\u00B5m";
+ } else if (lowercaseKey.equals("image.title")) {
+ return getImage().getTitle();
+ } else if (lowercaseKey.equals("image.subtitle")) {
+ ImagePlus imp = getImage();
+ ImageWindow win = imp.getWindow();
+ return win!=null?win.createSubtitle():"";
+ } else if (lowercaseKey.equals("slice.label")) {
+ ImagePlus imp = getImage();
+ String label = null;
+ if (imp.getStackSize()==1)
+ label = imp.getProp("Slice_Label");
+ else
+ label = imp.getStack().getShortSliceLabel(imp.getCurrentSlice());
+ return label!=null?label:"";
+ } else if (lowercaseKey.equals("window.contents")) {
+ return getWindowContents();
+ } else if (lowercaseKey.equals("image.description")) {
+ String description = "";
+ FileInfo fi = getImage().getOriginalFileInfo();
+ if (fi!=null) description = fi.description;
+ if (description==null) description = "";
+ return description;
+ } else if (lowercaseKey.equals("image.filename")) {
+ String name= "";
+ FileInfo fi = getImage().getOriginalFileInfo();
+ if (fi!=null && fi.fileName!=null) name= fi.fileName;
+ return name;
+ } else if (lowercaseKey.equals("image.directory")) {
+ String dir= "";
+ FileInfo fi = getImage().getOriginalFileInfo();
+ if (fi!=null && fi.directory!=null) dir= fi.directory;
+ return dir;
+ } else if (lowercaseKey.equals("selection.name")||lowercaseKey.equals("roi.name")) {
+ ImagePlus imp = getImage();
+ Roi roi = imp.getRoi();
+ String name = roi!=null?roi.getName():null;
+ return name!=null?name:"";
+ } else if (lowercaseKey.equals("selection.color")||lowercaseKey.equals("roi.color")) {
+ ImagePlus imp = getImage();
+ Roi roi = imp.getRoi();
+ if (roi==null)
+ interp.error("No selection");
+ Color color = roi.getStrokeColor();
+ return Colors.colorToString(color);
+ } else if (lowercaseKey.equals("font.name")) {
+ resetImage();
+ ImageProcessor ip = getProcessor();
+ setFont(ip);
+ return ip.getFont().getName();
+ } else if (lowercaseKey.equals("threshold.method")) {
+ return ThresholdAdjuster.getMethod();
+ } else if (lowercaseKey.equals("threshold.mode")) {
+ return ThresholdAdjuster.getMode();
+ } else if (lowercaseKey.equals("window.type")) {
+ return getWindowType();
+ } else if (lowercaseKey.equals("window.title")||lowercaseKey.equals("window.name")) {
+ return getWindowTitle();
+ } else if (lowercaseKey.equals("macro.filepath")) {
+ String path = Macro_Runner.getFilePath();
+ return path!=null?path:"null";
+ } else {
+ String value = "";
+ try {
+ value = System.getProperty(key);
+ } catch (Exception e) {};
+ if (value==null)
+ return("Invalid key");
+ else
+ return value;
+ }
+ return "";
+ }
+
+ private String getWindowTitle() {
+ Window win = WindowManager.getActiveWindow();
+ if (IJ.debugMode) IJ.log("getWindowTitle: "+win);
+ if (win==null)
+ return "";
+ else if (win instanceof Frame)
+ return ((Frame)win).getTitle();
+ else if (win instanceof Dialog)
+ return ((Dialog)win).getTitle();
+ else
+ return "";
+ }
+
+ private String getWindowType() {
+ Window win = WindowManager.getActiveWindow();
+ if (win==null)
+ return "";
+ String type = win.getClass().getName();
+ if (win instanceof TextWindow) {
+ TextPanel tp = ((TextWindow)win).getTextPanel();
+ if (tp.getColumnHeadings().isEmpty() && tp.getResultsTable()==null)
+ type = "Text";
+ else {
+ if (tp.getResultsTable()!=null)
+ type = "ResultsTable";
+ else
+ type = "Table";
+ }
+ } else if (type.equals("ij.gui.PlotWindow"))
+ type = "Plot";
+ else if (type.equals("ij.gui.HistogramWindow"))
+ type = "Histogram";
+ else if (win instanceof ImageWindow)
+ type = "Image";
+ else {
+ if (type.contains(".")) //strip off hierarchy
+ type = type.substring(type.lastIndexOf('.')+1);
+ }
+ return type;
+ }
+
+ String getWindowContents() {
+ Frame frame = WindowManager.getFrontWindow();
+ if (frame!=null && frame instanceof TextWindow) {
+ TextPanel tp = ((TextWindow)frame).getTextPanel();
+ return tp.getText();
+ } else if (frame!=null && frame instanceof Editor) {
+ return ((Editor)frame).getText();
+ } else if (frame!=null && frame instanceof Recorder) {
+ return ((Recorder)frame).getText();
+ } else
+ return getImageInfo();
+ }
+
+ String getImageInfo() {
+ ImagePlus imp = getImage();
+ ImageInfo infoPlugin = new ImageInfo();
+ return infoPlugin.getImageInfo(imp);
+ }
+
+ public String getDirectory() {
+ String dir = IJ.getDirectory(getStringArg());
+ if (dir==null) dir = "";
+ return dir;
+ }
+
+ double getSelectionType() {
+ interp.getParens();
+ double type = -1;
+ if (WindowManager.getImageCount()==0)
+ return type;
+ ImagePlus imp = getImage();
+ Roi roi = imp.getRoi();
+ if (roi!=null)
+ type = roi.getType();
+ return type;
+ }
+
+ void showMessage(boolean withCancel) {
+ String message;
+ interp.getLeftParen();
+ String title = getString();
+ if (interp.nextToken()==',') {
+ interp.getComma();
+ message = getString();
+ } else {
+ message = title;
+ title = "";
+ }
+ interp.getRightParen();
+ if (withCancel) {
+ boolean rtn = IJ.showMessageWithCancel(title, message);
+ if (!rtn) {
+ interp.finishUp();
+ throw new RuntimeException(Macro.MACRO_CANCELED);
+ }
+ } else
+ IJ.showMessage(title, message);
+ }
+
+ double lengthOf() {
+ int length = 0;
+ interp.getLeftParen();
+ switch (interp.nextToken()) {
+ case STRING_CONSTANT:
+ case STRING_FUNCTION:
+ case USER_FUNCTION:
+ length = getString().length();
+ break;
+ case WORD:
+ if (pgm.code[interp.pc+2]=='[') {
+ length = getString().length();
+ break;
+ }
+ interp.getToken();
+ ij.macro.Variable v = interp.lookupVariable();
+ if (v==null) return 0.0;
+ String s = v.getString();
+ if (s!=null)
+ length = s.length();
+ else {
+ ij.macro.Variable[] array = v.getArray();
+ if (array!=null)
+ length = v.getArraySize();
+ else
+ interp.error("String or array expected");
+ }
+ break;
+ default:
+ interp.error("String or array expected");
+ }
+ interp.getRightParen();
+ return length;
+ }
+
+ void getCursorLoc() {
+ ij.macro.Variable x = getFirstVariable();
+ ij.macro.Variable y = getNextVariable();
+ ij.macro.Variable z = getNextVariable();
+ ij.macro.Variable flags = getLastVariable();
+ ImagePlus imp = getImage();
+ ImageCanvas ic = imp.getCanvas();
+ if (ic==null) return;
+ Point p = ic.getCursorLoc();
+ x.setValue(p.x);
+ y.setValue(p.y);
+ z.setValue(imp.getCurrentSlice()-1);
+ Roi roi = imp.getRoi();
+ flags.setValue(ic.getModifiers()+((roi!=null)&&roi.contains(p.x,p.y)?32:0));
+ }
+
+ void getLine() {
+ ij.macro.Variable vx1 = getFirstVariable();
+ ij.macro.Variable vy1 = getNextVariable();
+ ij.macro.Variable vx2 = getNextVariable();
+ ij.macro.Variable vy2 = getNextVariable();
+ ij.macro.Variable lineWidth = getLastVariable();
+ ImagePlus imp = getImage();
+ double x1=-1, y1=-1, x2=-1, y2=-1;
+ Roi roi = imp.getRoi();
+ if (roi!=null && roi.getType()==Roi.LINE) {
+ Line line = (Line)roi;
+ x1=line.x1d; y1=line.y1d; x2=line.x2d; y2=line.y2d;
+ }
+ vx1.setValue(x1);
+ vy1.setValue(y1);
+ vx2.setValue(x2);
+ vy2.setValue(y2);
+ lineWidth.setValue(roi!=null?roi.getStrokeWidth():1);
+ }
+
+ void getVoxelSize() {
+ ij.macro.Variable width = getFirstVariable();
+ ij.macro.Variable height = getNextVariable();
+ ij.macro.Variable depth = getNextVariable();
+ ij.macro.Variable unit = getLastVariable();
+ ImagePlus imp = getImage();
+ Calibration cal = imp.getCalibration();
+ width.setValue(cal.pixelWidth);
+ height.setValue(cal.pixelHeight);
+ depth.setValue(cal.pixelDepth);
+ unit.setString(cal.getUnits());
+ }
+
+ void getHistogram() {
+ interp.getLeftParen();
+ ij.macro.Variable values = null;
+ if (interp.nextToken()==NUMBER)
+ interp.getExpression();
+ else
+ values = getArrayVariable();
+ ij.macro.Variable counts = getNextArrayVariable();
+ interp.getComma();
+ int nBins = (int)interp.getExpression();
+ ImagePlus imp = getImage();
+ double histMin=0.0, histMax=0.0;
+ boolean setMinMax = false;
+ int bitDepth = imp.getBitDepth();
+ if (interp.nextToken()==',') {
+ histMin = getNextArg();
+ histMax = getLastArg();
+ if (bitDepth==8 || bitDepth==24)
+ interp.error("16 or 32-bit image required to set histMin and histMax");
+ setMinMax = true;
+ } else
+ interp.getRightParen();
+ if (nBins==65536 && bitDepth==16) {
+ ij.macro.Variable[] array = counts.getArray();
+ ImageProcessor ip = imp.getProcessor();
+ Roi roi = imp.getRoi();
+ if (roi!=null)
+ ip.setRoi(roi);
+ int[] hist = ip.getHistogram();
+ if (array!=null && array.length==nBins) {
+ for (int i=0; ix.length || n>y.length)
+ interp.error("Array too short");
+ } else {
+ interp.getRightParen();
+ if (y.length!=n)
+ interp.error("Arrays are not the same length");
+ }
+ ImagePlus imp = getImage();
+ boolean floatCoordinates = false;
+ for (int i=0; i=currentPlot.getNumPlotObjects())
+ interp.error("Index out of bounds");
+ currentPlot.setStyle(index, getLastString());
+ if (plot == null)
+ currentPlot.updateImage();
+ return Double.NaN;
+ } else if (name.equals("makeHighResolution")) {
+ return makeHighResolution(currentPlot);
+ } else if (name.equals("setColor")) {
+ return setPlotColor(currentPlot);
+ } else if (name.equals("setBackgroundColor")) {
+ return setPlotBackgroundColor(currentPlot);
+ } else if (name.equals("setFontSize")) {
+ return setPlotFontSize(currentPlot, false);
+ } else if (name.equals("setAxisLabelSize")) {
+ return setPlotFontSize(currentPlot, true);
+ } else if (name.equals("setXYLabels")) {
+ currentPlot.setXYLabels(getFirstString(), getLastString());
+ currentPlot.updateImage();
+ return Double.NaN;
+ } else if (name.equals("setFormatFlags")) {
+ return setPlotFormatFlags(currentPlot);
+ } else if (name.equals("useTemplate")) {
+ return fromPlot(currentPlot, 't');
+ } else if (name.equals("setOptions")) {
+ return setPlotOptions(currentPlot);
+ } else if (name.equals("addFromPlot")) {
+ return fromPlot(currentPlot, 'a');
+ } else if (name.equals("getFrameBounds")) {
+ return getPlotFrameBounds(currentPlot);
+ } else if (name.equals("objectCount")||name.equals("getNumObjects")) {
+ return currentPlot.getNumPlotObjects();
+ } else if (name.equals("add")) {
+ return addToPlot(currentPlot);
+ } else if (name.equals("replace")) {
+ return replacePlot(currentPlot);
+ } else if (name.equals("addText") || name.equals("drawLabel")) {
+ return addPlotText(currentPlot);
+ } else if (name.equals("enableLive")) {
+ return enableLivePlot(currentPlot);
+ } else if (name.equals("update")) {
+ return updatePlot(currentPlot);
+ }
+ // the following commands need a plot under construction
+ if (plot==null)
+ interp.error("No plot defined");
+ if (name.equals("show")) {
+ return showPlot();
+ } else if (name.equals("drawLine")) {
+ return drawPlotLine(false);
+ } else if (name.equals("drawNormalizedLine")) {
+ return drawPlotLine(true);
+ } else if (name.equals("drawVectors")) {
+ return drawPlotVectors();
+ } else if (name.equals("drawShapes")) {
+ return drawShapes();
+ } else if (name.equals("drawGrid")) {
+ interp.getParens();
+ plot.drawShapes("redraw_grid", null);
+ return Double.NaN;
+ } else if (name.startsWith("setLineWidth")) {
+ plot.setLineWidth((float)getArg());
+ return Double.NaN;
+ } else if (name.startsWith("setJustification")) {
+ setJustification();
+ return Double.NaN;
+ } else if (name.equals("addHistogram")) {
+ interp.getLeftParen();
+ ij.macro.Variable[] arrV = getArray();
+ interp.getComma();
+ double binWidth = interp.getExpression();
+ double binCenter = 0;
+ interp.getToken();
+ if (interp.token == ',')
+ binCenter = interp.getExpression();
+ else
+ interp.putTokenBack();
+ interp.getRightParen();
+ int len1 = arrV.length;
+ double[] arrD = new double[len1];
+ for (int i=0; i= 2 boxes
+ }
+ nBoxes = arr.length;
+ if (jj > 0 && arr2D[0].length != nBoxes) {
+ interp.error("Arrays must have same length (" + nBoxes + ")");
+ return Double.NaN;
+ }
+ if (arr2D == null) {
+ arr2D = new double[nCoords][nBoxes];
+ }
+ for (int boxNo = 0; boxNo < nBoxes; boxNo++) {
+ arr2D[jj][boxNo] = arr[boxNo];
+ }
+ }
+ }
+ interp.getRightParen();
+ float[][] floatArr = new float[nCoords][nBoxes];
+ for (int row = 0; row < nCoords; row++) {
+ floatArr[row] = Tools.toFloat(arr2D[row]);
+ }
+ ArrayList shapeData = new ArrayList();
+ for (int box = 0; box < nBoxes; box++) {
+ float[] coords = new float[nCoords];
+ for (int coord = 0; coord < nCoords; coord++) {
+ coords[coord] = (float) (arr2D[coord][box]);
+ }
+ shapeData.add(coords);
+ }
+ plot.drawShapes(type, shapeData);
+ return Double.NaN;
+ }
+
+ double setPlotColor(Plot plot) {
+ interp.getLeftParen();
+ Color color = getColor();
+ Color color2 = null;
+ if (interp.nextToken()!=')') {
+ interp.getComma();
+ color2 = getColor();
+ }
+ plot.setColor(color, color2);
+ interp.getRightParen();
+ return Double.NaN;
+ }
+
+ double setPlotBackgroundColor(Plot plot) {
+ interp.getLeftParen();
+ Color color = getColor();
+ interp.getRightParen();
+ plot.setBackgroundColor(color);
+ return Double.NaN;
+ }
+
+ double setPlotFontSize(Plot plot, boolean forAxisLabels) {
+ float size = (float)getFirstArg();
+ int style = -1;
+ if (interp.nextToken()!=')') {
+ String options = getNextString().toLowerCase();
+ style = 0;
+ if (options.indexOf("bold") >= 0)
+ style |= Font.BOLD;
+ if (options.indexOf("ital") >= 0)
+ style |= Font.ITALIC;
+ }
+ interp.getRightParen();
+ if (forAxisLabels)
+ plot.setAxisLabelFont(style, size);
+ else
+ plot.setFont(style, size);
+ plot.updateImage();
+ return Double.NaN;
+ }
+
+ double setPlotFormatFlags(Plot plot) {
+ String flagString = getStringArg();
+ try {
+ int flags = Integer.parseInt(flagString, 2);
+ plot.setFormatFlags(flags);
+ plot.updateImage();
+ } catch (NumberFormatException e) {
+ interp.error("Plot format flags not binary");
+ }
+ return Double.NaN;
+ }
+
+ /** Plot.useTemplate with 't', Plot.addFromPlot with 'a' */
+ double fromPlot(Plot plot, char type) {
+ ImagePlus sourceImp = null;
+ interp.getLeftParen();
+ if (isStringArg()) {
+ String title = getString();
+ sourceImp = WindowManager.getImage(title);
+ if (sourceImp==null)
+ interp.error("Image \""+title+"\" not found");
+ } else {
+ int id = (int)interp.getExpression();
+ sourceImp = WindowManager.getImage(id);
+ if (sourceImp==null)
+ interp.error("Image ID="+id+" not found");
+ }
+ Plot sourcePlot = (Plot)(sourceImp.getProperty(Plot.PROPERTY_KEY));
+ if (sourcePlot==null)
+ interp.error("No plot: "+sourceImp.getTitle());
+ if (type == 'a') {
+ int objectIndex = (int)getNextArg();
+ if (objectIndex < 0 || objectIndex > plot.getNumPlotObjects())
+ interp.error("Plot "+sourceImp.getTitle()+" has "+plot.getNumPlotObjects()+"items, no number "+objectIndex);
+ plot.addObjectFromPlot(sourcePlot, objectIndex);
+ plot.updateImage();
+ } else
+ plot.useTemplate(sourcePlot);
+ interp.getRightParen();
+ return Double.NaN;
+ }
+
+ double addPlotLegend(Plot plot) {
+ String labels = getFirstString();
+ String options = "auto";
+ if (interp.nextToken()!=')')
+ options = getLastString();
+ else
+ interp.getRightParen();
+ plot.setColor(Color.BLACK);
+ plot.setLineWidth(1);
+ plot.addLegend(labels, options);
+ return Double.NaN;
+ }
+
+ double getPlotLimits(Plot plot) {
+ double[] limits = plot.getLimits();
+ getFirstVariable().setValue(limits[0]); //xMin
+ getNextVariable().setValue(limits[1]); //xMax
+ getNextVariable().setValue(limits[2]); //yMin
+ getLastVariable().setValue(limits[3]); //yMax
+ return Double.NaN;
+ }
+
+ double getPlotFrameBounds(Plot plot) {
+ Rectangle r = plot.getDrawingFrame();
+ getFirstVariable().setValue(r.x);
+ getNextVariable().setValue(r.y);
+ getNextVariable().setValue(r.width);
+ getLastVariable().setValue(r.height);
+ return Double.NaN;
+ }
+
+ double makeHighResolution(Plot plot) {
+ String title = getFirstString();
+ double scale = getNextArg();
+ boolean antialiasedText = true;
+ if (interp.nextToken()!=')') {
+ String options = getLastString().toLowerCase();
+ if (options.indexOf("disable")!=-1)
+ antialiasedText = false;
+ } else
+ interp.getRightParen();
+ plot.makeHighResolution(title, (float)scale, antialiasedText, true);
+ return Double.NaN;
+ }
+
+ double addToPlot(Plot currentPlot) {
+ String shape = getFirstString();
+ int what = Plot.toShape(shape);
+ double[] x = getNextArray();
+ double[] y;
+ double[] errorBars = null;
+ String label = null;
+ if (interp.nextToken()==')') {
+ y = x;
+ x = new double[y.length];
+ for (int i=0; iindex2)
+ interp.error("beginIndex>endIndex");
+ checkIndex(index1, 0, s.length());
+ checkIndex(index2, 0, s.length());
+ return s.substring(index1, index2);
+ }
+
+ private String getStringFunctionArg(String s) {
+ if (s==null) {
+ s=getFirstString();
+ interp.getComma();
+ } else
+ interp.getLeftParen();
+ return s;
+ }
+
+ int indexOf(String s1) {
+ s1 = getStringFunctionArg(s1);
+ String s2 = getString();
+ int fromIndex = 0;
+ if (interp.nextToken()==',') {
+ fromIndex = (int)getLastArg();
+ checkIndex(fromIndex, 0, s1.length()-1);
+ } else
+ interp.getRightParen();
+ if (fromIndex==0)
+ return s1.indexOf(s2);
+ else
+ return s1.indexOf(s2, fromIndex);
+ }
+
+ int startsWithEndsWith(int type) {
+ String s1 = getFirstString();
+ String s2 = getLastString();
+ if (type==STARTS_WITH)
+ return s1.startsWith(s2)?1:0;
+ else
+ return s1.endsWith(s2)?1:0;
+ }
+
+ double isActive() {
+ int id = (int)getArg();
+ ImagePlus imp = WindowManager.getCurrentImage();
+ if (imp==null || imp.getID()!=id)
+ return 0.0; //false
+ else
+ return 1.0; //true
+ }
+
+ double isOpen() {
+ interp.getLeftParen();
+ if (isStringArg()) {
+ String title = getString();
+ interp.getRightParen();
+ return isOpen(title)?1.0:0.0;
+ } else {
+ int id = (int)interp.getExpression();
+ interp.getRightParen();
+ return WindowManager.getImage(id)==null?0.0:1.0;
+ }
+ }
+
+ boolean isOpen(String title) {
+ boolean open = WindowManager.getWindow(title)!=null;
+ if (open)
+ return true;
+ else if (ij.macro.Interpreter.isBatchMode() && ij.macro.Interpreter.imageTable!=null) {
+ for (Enumeration en = ij.macro.Interpreter.imageTable.elements(); en.hasMoreElements();) {
+ ImagePlus imp = (ImagePlus)en.nextElement();
+ if (imp!=null && imp.getTitle().equals(title))
+ return true;
+ }
+ }
+ return false;
+ }
+
+ boolean isStringArg() {
+ int nextToken = pgm.code[interp.pc+1];
+ int tok = nextToken&0xff;
+ if (tok==STRING_CONSTANT||tok==STRING_FUNCTION) return true;
+ if (tok==VARIABLE_FUNCTION && interp.isString(interp.pc+1)) return true;
+ if (tok!=WORD) return false;
+ ij.macro.Variable v = interp.lookupVariable(nextToken>>TOK_SHIFT);
+ if (v==null) return false;
+ int type = v.getType();
+ if (type!= ij.macro.Variable.ARRAY)
+ return v.getType()== ij.macro.Variable.STRING;
+ ij.macro.Variable[] array = v.getArray();
+ if (array.length==0 || interp.nextNextToken()=='.') return false;
+ return array[0].getType()== ij.macro.Variable.STRING;
+ }
+
+ void exit() {
+ String msg = null;
+ if (interp.nextToken()=='(') {
+ interp.getLeftParen();
+ if (interp.nextToken()!=')')
+ msg = getString();
+ interp.getRightParen();
+ }
+ interp.finishUp();
+ if (msg!=null)
+ IJ.showMessage("Macro", msg);
+ throw new RuntimeException(Macro.MACRO_CANCELED);
+ }
+
+ private void showStatus () {
+ interp.getLeftParen();
+ String s = getString();
+ String options = null;
+ if (interp.nextToken()==',') {
+ interp.getComma();
+ options = getString();
+ }
+ interp.getRightParen();
+ boolean withSign = s.startsWith("!");
+ if (withSign)
+ s = s.substring(1);
+ IJ.protectStatusBar(false);
+ if (options!=null)
+ IJ.showStatus(s, options);
+ else
+ IJ.showStatus(s);
+ IJ.protectStatusBar(withSign);
+ interp.statusUpdated = true;
+ }
+
+ void showProgress() {
+ ImageJ ij = IJ.getInstance();
+ ij.gui.ProgressBar progressBar = ij!=null?ij.getProgressBar():null;
+ interp.getLeftParen();
+ double arg1 = interp.getExpression();
+ if (interp.nextToken()==',') {
+ interp.getComma();
+ double arg2 = interp.getExpression();
+ if (progressBar!=null) progressBar.show((arg1+1.0)/arg2, true);
+ } else
+ if (progressBar!=null) progressBar.show(arg1, true);
+ interp.getRightParen();
+ interp.showingProgress = true;
+ }
+
+ void saveSettings() {
+ interp.getParens();
+ usePointerCursor = Prefs.usePointerCursor;
+ hideProcessStackDialog = IJ.hideProcessStackDialog;
+ divideByZeroValue = FloatBlitter.divideByZeroValue;
+ jpegQuality = FileSaver.getJpegQuality();
+ saveLineWidth = Line.getWidth();
+ doScaling = ImageConverter.getDoScaling();
+ weightedColor = Prefs.weightedColor;
+ weights = ColorProcessor.getWeightingFactors();
+ interpolateScaledImages = Prefs.interpolateScaledImages;
+ open100Percent = Prefs.open100Percent;
+ blackCanvas = Prefs.blackCanvas;
+ useJFileChooser = Prefs.useJFileChooser;
+ debugMode = IJ.debugMode;
+ foregroundColor =Toolbar.getForegroundColor();
+ backgroundColor =Toolbar.getBackgroundColor();
+ roiColor = Roi.getColor();
+ pointAutoMeasure = Prefs.pointAutoMeasure;
+ requireControlKey = Prefs.requireControlKey;
+ useInvertingLut = Prefs.useInvertingLut;
+ saveSettingsCalled = true;
+ measurements = Analyzer.getMeasurements();
+ decimalPlaces = Analyzer.getPrecision();
+ blackBackground = Prefs.blackBackground;
+ autoContrast = Prefs.autoContrast;
+ pasteMode = Roi.getCurrentPasteMode();
+ plotWidth = PlotWindow.plotWidth;
+ plotHeight = PlotWindow.plotHeight;
+ plotFontSize = PlotWindow.getDefaultFontSize();
+ plotInterpolate = PlotWindow.interpolate;
+ plotNoGridLines = PlotWindow.noGridLines;
+ plotNoTicks = PlotWindow.noTicks;
+ profileVerticalProfile = Prefs.verticalProfile;
+ profileSubPixelResolution = Prefs.subPixelResolution;
+ }
+
+ void restoreSettings() {
+ interp.getParens();
+ if (!saveSettingsCalled)
+ interp.error("saveSettings() not called");
+ Prefs.usePointerCursor = usePointerCursor;
+ IJ.hideProcessStackDialog = hideProcessStackDialog;
+ FloatBlitter.divideByZeroValue = divideByZeroValue;
+ FileSaver.setJpegQuality(jpegQuality);
+ Line.setWidth(saveLineWidth);
+ ImageConverter.setDoScaling(doScaling);
+ if (weightedColor!=Prefs.weightedColor) {
+ ColorProcessor.setWeightingFactors(weights[0], weights[1], weights[2]);
+ Prefs.weightedColor = !(weights[0]==1d/3d && weights[1]==1d/3d && weights[2]==1d/3d);
+ }
+ Prefs.interpolateScaledImages = interpolateScaledImages;
+ Prefs.open100Percent = open100Percent;
+ Prefs.blackCanvas = blackCanvas;
+ Prefs.useJFileChooser = useJFileChooser;
+ Prefs.useInvertingLut = useInvertingLut;
+ IJ.setDebugMode(debugMode);
+ Toolbar.setForegroundColor(foregroundColor);
+ Toolbar.setBackgroundColor(backgroundColor);
+ Roi.setColor(roiColor);
+ Analyzer.setMeasurements(measurements);
+ Analyzer.setPrecision(decimalPlaces);
+ ColorProcessor.setWeightingFactors(weights[0], weights[1], weights[2]);
+ Prefs.blackBackground = blackBackground;
+ Prefs.autoContrast = autoContrast;
+ Roi.setPasteMode(pasteMode);
+ PlotWindow.plotWidth = plotWidth;
+ PlotWindow.plotHeight = plotHeight;
+ PlotWindow.setDefaultFontSize(plotFontSize);
+ PlotWindow.interpolate = plotInterpolate;
+ PlotWindow.noGridLines = plotNoGridLines;
+ PlotWindow.noTicks = plotNoTicks;
+ Prefs.verticalProfile = profileVerticalProfile;
+ Prefs.subPixelResolution = profileSubPixelResolution;
+ }
+
+ void setKeyDown() {
+ String keys = getStringArg();
+ keys = keys.toLowerCase(Locale.US);
+ altKeyDown = keys.indexOf("alt")!=-1;
+ if (altKeyDown)
+ IJ.setKeyDown(KeyEvent.VK_ALT);
+ else
+ IJ.setKeyUp(KeyEvent.VK_ALT);
+ shiftKeyDown = keys.indexOf("shift")!=-1;
+ if (shiftKeyDown)
+ IJ.setKeyDown(KeyEvent.VK_SHIFT);
+ else
+ IJ.setKeyUp(KeyEvent.VK_SHIFT);
+ boolean controlKeyDown = keys.indexOf("control")!=-1;
+ if (controlKeyDown)
+ IJ.setKeyDown(KeyEvent.VK_CONTROL);
+ else
+ IJ.setKeyUp(KeyEvent.VK_CONTROL);
+ if (keys.equals("space"))
+ IJ.setKeyDown(KeyEvent.VK_SPACE);
+ else
+ IJ.setKeyUp(KeyEvent.VK_SPACE);
+ if (keys.indexOf("esc")!=-1)
+ abortPluginOrMacro();
+ else
+ interp.keysSet = true;
+ }
+
+ void abortPluginOrMacro() {
+ ij.macro.Interpreter.abortPrevious();
+ IJ.setKeyDown(KeyEvent.VK_ESCAPE);
+ ImagePlus imp = WindowManager.getCurrentImage();
+ if (imp!=null) {
+ ImageWindow win = imp.getWindow();
+ if (win!=null) {
+ win.running = false;
+ win.running2 = false;
+ }
+ }
+ }
+
+ void open() {
+ File f = null;
+ interp.getLeftParen();
+ if (interp.nextToken()==')') {
+ interp.getRightParen();
+ IJ.open();
+ } else {
+ double n = Double.NaN;
+ String options = null;
+ String path = getString();
+ f = new File(path);
+ if (interp.nextToken()==',') {
+ interp.getComma();
+ if (isStringArg())
+ options = getString();
+ else
+ n = interp.getExpression();
+ }
+ interp.getRightParen();
+ if (!Double.isNaN(n)) {
+ try {
+ IJ.open(path, (int)n);
+ } catch (Exception e) {
+ String msg = e.getMessage();
+ if (msg!=null&&msg.indexOf("canceled")==-1)
+ interp.error(""+msg);
+ }
+ } else {
+ if (f!=null&&f.isDirectory()) {
+ FolderOpener fo = new FolderOpener();
+ if (options!=null && options.contains("virtual"))
+ fo.openAsVirtualStack(true);
+ ImagePlus imp = fo.openFolder(path);
+ if (imp!=null) imp.show();
+ } else
+ IJ.open(path);
+ }
+ if (path!=null&&!path.equals("")&&f!=null) {
+ OpenDialog.setLastDirectory(f.getParent()+File.separator);
+ OpenDialog.setLastName(f.getName());
+ }
+ }
+ resetImage();
+ }
+
+ double roiManager() {
+ String cmd = getFirstString();
+ cmd = cmd.toLowerCase();
+ String path = null;
+ String color = null;
+ double lineWidth = 1.0;
+ int index=0;
+ double dx=0.0, dy=0.0;
+ double countOrIndex=Double.NaN;
+ boolean twoArgCommand = cmd.equals("open")||cmd.equals("save")||cmd.equals("rename")
+ ||cmd.equals("set color")||cmd.equals("set fill color")||cmd.equals("set line width")
+ ||cmd.equals("associate")||cmd.equals("centered")||cmd.equals("usenames")
+ ||cmd.equals("save selected");
+ boolean select = cmd.equals("select");
+ boolean multiSelect = false;
+ boolean add = cmd.equals("add");
+ if (twoArgCommand)
+ path = getLastString();
+ else if (add) {
+ if (interp.nextToken()==',') {
+ interp.getComma();
+ color = interp.getString();
+ }
+ if (interp.nextToken()==',') {
+ interp.getComma();
+ lineWidth = interp.getExpression();
+ }
+ interp.getRightParen();
+ } else if (select) {
+ interp.getComma();
+ multiSelect = isArrayArg();
+ if (!multiSelect) {
+ index = (int)interp.getExpression();
+ interp.getRightParen();
+ }
+ } else if (cmd.equals("translate")) {
+ dx = getNextArg();
+ dy = getLastArg();
+ } else
+ interp.getRightParen();
+ if (RoiManager.getInstance()==null&&roiManager==null) {
+ if (ij.macro.Interpreter.isBatchMode())
+ roiManager = new RoiManager(true);
+ else
+ IJ.run("ROI Manager...");
+ }
+ RoiManager rm = roiManager!=null?roiManager:RoiManager.getInstance();
+ if (rm==null)
+ interp.error("ROI Manager not found");
+ if (multiSelect)
+ return setMultipleIndexes(rm);
+ if (twoArgCommand)
+ rm.runCommand(cmd, path);
+ else if (add)
+ rm.runCommand("Add", color, lineWidth);
+ else if (select) {
+ int n = rm.getCount();
+ checkIndex(index, 0, n-1);
+ if (shiftKeyDown || altKeyDown) {
+ rm.select(index, shiftKeyDown, altKeyDown);
+ shiftKeyDown = altKeyDown = false;
+ } else
+ rm.select(index);
+ } else if (cmd.equals("count")||cmd.equals("size"))
+ countOrIndex = rm.getCount();
+ else if (cmd.equals("index"))
+ countOrIndex = rm.getSelectedIndex();
+ else if (cmd.equals("translate")) {
+ rm.translate(dx, dy);
+ return Double.NaN;
+ } else {
+ if (!rm.runCommand(cmd))
+ interp.error("Invalid ROI Manager command");
+ }
+ return countOrIndex;
+ }
+
+ boolean isArrayArg() {
+ int nextToken = pgm.code[interp.pc+1];
+ int tok = nextToken&0xff;
+ if (tok==ARRAY_FUNCTION) return true;
+ if (tok!=WORD) return false;
+ ij.macro.Variable v = interp.lookupVariable(nextToken>>TOK_SHIFT);
+ if (v==null) return false;
+ int nextNextToken = pgm.code[interp.pc+2];
+ return v.getType()== ij.macro.Variable.ARRAY && nextNextToken!='[';
+ }
+
+ double setMultipleIndexes(RoiManager rm) {
+ if (interp.nextToken()==',')
+ interp.getComma();
+ double[] indexes = getNumericArray();
+ interp.getRightParen();
+ int[] selectedIndexes = new int[indexes.length];
+ int count = rm.getCount();
+ for (int i=0; i=count)
+ interp.error("Invalid index: "+selectedIndexes[i]);
+ }
+ rm.setSelectedIndexes(selectedIndexes);
+ return Double.NaN;
+ }
+
+ void setFont() {
+ String name = getFirstString();
+ int size = 0;
+ int style = 0;
+ if (name.equals("user")) {
+ name = TextRoi.getDefaultFontName();
+ size = TextRoi.getDefaultFontSize();
+ style = TextRoi.getDefaultFontStyle();
+ antialiasedText = TextRoi.isAntialiased();
+ interp.getRightParen();
+ } else {
+ size = (int)getNextArg();
+ antialiasedText = IJ.isMacOSX()?true:false || size>=14;
+ if (interp.nextToken()==',') {
+ String styles = getLastString().toLowerCase();
+ if (styles.contains("bold")) style += Font.BOLD;
+ if (styles.contains("italic")) style += Font.ITALIC;
+ if (styles.contains("nonscal")) nonScalableText=true;
+ if (styles.contains("anti")) antialiasedText=true;
+ if (styles.contains("non-")||styles.contains("no-")) antialiasedText=false;
+ } else
+ interp.getRightParen();
+ }
+ font = new Font(name, style, size);
+ fontSet = false;
+ }
+
+ void getMinAndMax() {
+ ij.macro.Variable min = getFirstVariable();
+ ij.macro.Variable max = getLastVariable();
+ ImagePlus imp = getImage();
+ double v1 = imp.getDisplayRangeMin();
+ double v2 = imp.getDisplayRangeMax();
+ Calibration cal = imp.getCalibration();
+ v1 = cal.getCValue(v1);
+ v2 = cal.getCValue(v2);
+ min.setValue(v1);
+ max.setValue(v2);
+ }
+
+ void selectImage() {
+ interp.getLeftParen();
+ if (isStringArg()) {
+ String title = getString();
+ if (!isOpen(title))
+ interp.error("\""+title+"\" not found");
+ selectImage(title);
+ interp.getRightParen();
+ } else {
+ int id = (int)interp.getExpression();
+ if (WindowManager.getImage(id)==null)
+ interp.error("Image "+id+" not found");
+ IJ.selectWindow(id);
+ interp.getRightParen();
+ }
+ resetImage();
+ }
+
+ void selectImage(String title) {
+ if (ij.macro.Interpreter.isBatchMode()) {
+ if (ij.macro.Interpreter.imageTable!=null) {
+ for (Enumeration en = ij.macro.Interpreter.imageTable.elements(); en.hasMoreElements();) {
+ ImagePlus imp = (ImagePlus)en.nextElement();
+ if (imp!=null) {
+ if (imp.getTitle().equals(title)) {
+ ImagePlus imp2 = WindowManager.getCurrentImage();
+ if (imp2!=null && imp2!=imp) imp2.saveRoi();
+ WindowManager.setTempCurrentImage(imp);
+ ij.macro.Interpreter.activateImage(imp);
+ return;
+ }
+ }
+ }
+ }
+ selectWindowManagerImage(title);
+ } else
+ selectWindowManagerImage(title);
+ }
+
+ void notFound(String title) {
+ interp.error(title+" not found");
+ }
+
+ void selectWindowManagerImage(String title) {
+ long start = System.currentTimeMillis();
+ while (System.currentTimeMillis()-start<4000) { // 4 sec timeout
+ int[] wList = WindowManager.getIDList();
+ int len = wList!=null?wList.length:0;
+ for (int i=0; inSlices)
+ interp.error("Argument must be >=1 and <="+nSlices);
+ else {
+ if (imp.isHyperStack())
+ imp.setPosition(n);
+ else
+ imp.setSlice(n);
+ }
+ resetImage();
+ }
+
+ void newImage() {
+ String title = getFirstString();
+ String type = getNextString();
+ int width = (int)getNextArg();
+ int height = (int)getNextArg();
+ int depth = (int)getNextArg();
+ int c=-1, z=-1, t=-1;
+ if (interp.nextToken()==')')
+ interp.getRightParen();
+ else {
+ c = depth;
+ z = (int)getNextArg();
+ t = (int)getLastArg();
+ }
+ if (width<1 || height<1)
+ interp.error("Width or height < 1");
+ if (c<0)
+ IJ.newImage(title, type, width, height, depth);
+ else {
+ ImagePlus imp = IJ.createImage(title, type, width, height, c, z, t);
+ imp.show();
+ }
+ resetImage();
+ }
+
+ void saveAs() {
+ String format = getFirstString();
+ String path = null;
+ boolean oneArg = false;
+ if (interp.nextToken()==',')
+ path = getLastString();
+ else {
+ interp.getRightParen();
+ oneArg = true;
+ }
+ if (oneArg && (format.contains(File.separator)||format.contains("/")))
+ IJ.save(format); // assume argument is a path
+ else
+ IJ.saveAs(format, path);
+ }
+
+ double getZoom() {
+ interp.getParens();
+ ImagePlus imp = getImage();
+ ImageCanvas ic = imp.getCanvas();
+ if (ic==null)
+ {interp.error("Image not displayed"); return 0.0;}
+ else
+ return ic.getMagnification();
+ }
+
+ void setAutoThreshold() {
+ String mString = null;
+ if (interp.nextToken()=='(') {
+ interp.getLeftParen();
+ if (isStringArg())
+ mString = getString();
+ interp.getRightParen();
+ }
+ ImagePlus img = getImage();
+ ImageProcessor ip = getProcessor();
+ if (ip instanceof ColorProcessor)
+ interp.error("Non-RGB image expected");
+ ip.setRoi(img.getRoi());
+ if (mString!=null) {
+ try {
+ img.setAutoThreshold(mString);
+ } catch (Exception e) {
+ interp.error(""+e.getMessage());
+ }
+ } else
+ ip.setAutoThreshold(ImageProcessor.ISODATA2, ImageProcessor.RED_LUT);
+ img.updateAndDraw();
+ resetImage();
+ }
+
+ double parseDouble(String s) {
+ if (s==null) return 0.0;
+ s = s.trim();
+ if (s.indexOf(' ')!=-1) s = s.substring(0, s.indexOf(' '));
+ return Tools.parseDouble(s);
+ }
+
+ double parseInt() {
+ String s = getFirstString();
+ int radix = 10;
+ if (interp.nextToken()==',') {
+ interp.getComma();
+ radix = (int)interp.getExpression();
+ if (radix<2||radix>36) radix = 10;
+ }
+ interp.getRightParen();
+ double n;
+ try {
+ if (radix==10) {
+ n = parseDouble(s);
+ if (!Double.isNaN(n)) n = Math.round(n);
+ } else
+ n = Integer.parseInt(s, radix);
+ } catch (NumberFormatException e) {
+ n = Double.NaN;
+ }
+ return n;
+ }
+
+ void print() {
+ interp.inPrint = true;
+ String s = getFirstString();
+ if (interp.nextToken()==',') {
+ if (s.startsWith("[") && s.endsWith("]")) {
+ printToWindow(s);
+ return;
+ } else if (s.equals("~0~")) {
+ if (writer==null)
+ interp.error("File not open");
+ String s2 = getLastString();
+ if (s2.endsWith("\n"))
+ writer.print(s2);
+ else
+ writer.println(s2);
+ interp.inPrint = false;
+ return;
+ }
+ StringBuffer sb = new StringBuffer(s);
+ do {
+ sb.append(" ");
+ sb.append(getNextString());
+ } while (interp.nextToken()==',');
+ s = sb.toString();
+ }
+ interp.getRightParen();
+ interp.log(s);
+ interp.inPrint = false;
+ }
+
+ void printToWindow(String s) {
+ String title = s.substring(1, s.length()-1);
+ String s2 = getLastString();
+ boolean isCommand = s2.startsWith("\\");
+ Frame frame = WindowManager.getFrame(title);
+ if (frame==null)
+ interp.error("Window not found");
+ boolean isEditor = frame instanceof Editor;
+ if (!(isEditor || frame instanceof TextWindow))
+ interp.error("Window is not text window");
+ if (isEditor) {
+ Editor ed = (Editor)frame;
+ ed.setIsMacroWindow(true);
+ if (isCommand)
+ handleEditorCommand(ed, s2);
+ else
+ ed.append(s2);
+ } else {
+ TextWindow tw = (TextWindow)frame;
+ if (isCommand)
+ handleTextWindowCommand(tw, s2);
+ else {
+ tw.append(s2);
+ TextPanel tp = tw.getTextPanel();
+ if (tp!=null) tp.setResultsTable(null);
+ }
+ }
+ }
+
+ void handleEditorCommand(Editor ed, String s) {
+ if (s.startsWith("\\Update:")) {
+ TextArea ta = ed.getTextArea();
+ ta.setText(s.substring(8, s.length()));
+ ta.setEditable(false);
+ } else if (s.equals("\\Close"))
+ ed.close();
+ else
+ ed.append(s);
+ }
+
+ void handleTextWindowCommand(TextWindow tw, String s) {
+ TextPanel tp = tw.getTextPanel();
+ if (s.startsWith("\\Update:")) {
+ int n = tp.getLineCount();
+ String s2 = s.substring(8, s.length());
+ if (n==0)
+ tp.append(s2);
+ else
+ tp.setLine(n-1, s2);
+ } else if (s.startsWith("\\Update")) {
+ int cindex = s.indexOf(":");
+ if (cindex==-1)
+ {tp.append(s); return;}
+ String nstr = s.substring(7, cindex);
+ int line = (int)Tools.parseDouble(nstr, -1);
+ if (line<0) interp.error("Row index<0 or NaN");
+ int count = tp.getLineCount();
+ while (line>=count) {
+ tp.append("");
+ count++;
+ }
+ String s2 = s.substring(cindex+1, s.length());
+ tp.setLine(line, s2);
+ } else if (s.equals("\\Clear"))
+ tp.clear();
+ else if (s.equals("\\Close"))
+ tw.close();
+ else if (s.startsWith("\\Headings:"))
+ tp.setColumnHeadings(s.substring(10));
+ else
+ tp.append(s);
+ }
+
+
+ double isKeyDown() {
+ double value = 0.0;
+ String key = getStringArg().toLowerCase(Locale.US);
+ if (key.indexOf("alt")!=-1) value = IJ.altKeyDown()==true?1.0:0.0;
+ else if (key.indexOf("shift")!=-1) value = IJ.shiftKeyDown()==true?1.0:0.0;
+ else if (key.indexOf("space")!=-1) value = IJ.spaceBarDown()==true?1.0:0.0;
+ else if (key.indexOf("control")!=-1) value = IJ.controlKeyDown()==true?1.0:0.0;
+ else interp.error("Invalid key");
+ return value;
+ }
+
+ String runMacro(boolean eval) {
+ interp.getLeftParen();
+ String name = getString();
+ String arg = null;
+ if (interp.nextToken()==',') {
+ interp.getComma();
+ arg = getString();
+ }
+ interp.getRightParen();
+ if (eval) {
+ if (arg!=null && (name.equals("script")||name.equals("js")))
+ return (new Macro_Runner()).runJavaScript(arg, "");
+ else if (arg!=null && (name.equals("bsh")))
+ return Macro_Runner.runBeanShell(arg,"");
+ else if (arg!=null && (name.equals("python")))
+ return Macro_Runner.runPython(arg,"");
+ else
+ return IJ.runMacro(name, arg);
+ } else
+ return IJ.runMacroFile(name, arg);
+ }
+
+ void setThreshold() {
+ double lower = getFirstArg();
+ double upper = getNextArg();
+ String mode = null;
+ if (interp.nextToken()==',') {
+ interp.getComma();
+ mode = getString();
+ }
+ interp.getRightParen();
+ IJ.setThreshold(lower, upper, mode);
+ resetImage();
+ }
+
+ void drawOrFill(int type) {
+ int x = (int)getFirstArg();
+ int y = (int)getNextArg();
+ int width = (int)getNextArg();
+ int height = (int)getLastArg();
+ ImageProcessor ip = getProcessor();
+ switch (type) {
+ case DRAW_RECT: ip.drawRect(x, y, width, height); break;
+ case FILL_RECT: ip.setRoi(x, y, width, height); ip.fill(); break;
+ case DRAW_OVAL: ip.drawOval(x, y, width, height); break;
+ case FILL_OVAL: ip.fillOval(x, y, width, height); break;
+ }
+ updateAndDraw();
+ }
+
+ double getScreenDimension(int type) {
+ interp.getParens();
+ Dimension screen = IJ.getScreenSize();
+ if (type==SCREEN_WIDTH)
+ return screen.width;
+ else
+ return screen.height;
+ }
+
+ void getStatistics(boolean calibrated) {
+ ij.macro.Variable count = getFirstVariable();
+ ij.macro.Variable mean=null, min=null, max=null, std=null, hist=null;
+ int params = AREA+MEAN+MIN_MAX;
+ interp.getToken();
+ int arg = 1;
+ while (interp.token==',') {
+ arg++;
+ switch (arg) {
+ case 2: mean = getVariable(); break;
+ case 3: min = getVariable(); break;
+ case 4: max = getVariable(); break;
+ case 5: std = getVariable(); params += STD_DEV; break;
+ case 6: hist = getArrayVariable(); break;
+ default: interp.error("')' expected");
+ }
+ interp.getToken();
+ }
+ if (interp.token!=')') interp.error("')' expected");
+ ImagePlus imp = getImage();
+ Calibration cal = calibrated?imp.getCalibration():null;
+ ImageProcessor ip = getProcessor();
+ ImageStatistics stats = null;
+ Roi roi = imp.getRoi();
+ int lineWidth = Line.getWidth();
+ if (roi!=null && roi.isLine() && lineWidth>1) {
+ ImageProcessor ip2;
+ if (roi.getType()==Roi.LINE) {
+ ip2 = ip;
+ Rectangle saveR = ip2.getRoi();
+ ip2.setRoi(roi.getPolygon());
+ stats = ImageStatistics.getStatistics(ip2, params, cal);
+ ip2.setRoi(saveR);
+ } else {
+ ip2 = (new Straightener()).straightenLine(imp, lineWidth);
+ stats = ImageStatistics.getStatistics(ip2, params, cal);
+ }
+ } else if (roi!=null && roi.isLine()) {
+ ProfilePlot profile = new ProfilePlot(imp);
+ double[] values = profile.getProfile();
+ ImageProcessor ip2 = new FloatProcessor(values.length, 1, values);
+ if (roi instanceof Line) {
+ Line l = (Line)roi;
+ if ((l.y1==l.y2||l.x1==l.x2)&&l.x1==l.x1d&& l.y1==l.y1d&& l.x2==l.x2d&& l.y2==l.y2d)
+ ip2.setRoi(0, 0, ip2.getWidth()-1, 1);
+ }
+ stats = ImageStatistics.getStatistics(ip2, params, cal);
+ } else {
+ ip.setRoi(roi);
+ stats = ImageStatistics.getStatistics(ip, params, cal);
+ }
+ if (calibrated)
+ count.setValue(stats.area);
+ else
+ count.setValue(stats.pixelCount);
+ if (mean!=null) mean.setValue(stats.mean);
+ if (min!=null) min.setValue(stats.min);
+ if (max!=null) max.setValue(stats.max);
+ if (std!=null) std.setValue(stats.stdDev);
+ if (hist!=null) {
+ boolean is16bit = !calibrated && ip instanceof ShortProcessor && stats.histogram16!=null;
+ int[] histogram = is16bit?stats.histogram16:stats.histogram;
+ int bins = is16bit?(int)(stats.max+1):histogram.length;
+ ij.macro.Variable[] array = new ij.macro.Variable[bins];
+ int hmax = is16bit?(int)stats.max:255;
+ for (int i=0; i<=hmax; i++)
+ array[i] = new ij.macro.Variable(histogram[i]);
+ hist.setArray(array);
+ }
+ }
+
+ String replace(String s1) {
+ s1 = getStringFunctionArg(s1);
+ String s2 = getString();
+ String s3 = getLastString();
+ if (s2.length()==1) {
+ StringBuilder sb = new StringBuilder(s1.length());
+ for (int i=0; i1?"label":"info";
+ }
+ String metadata = null;
+ if (type.contains("info"))
+ metadata = (String)imp.getProperty("Info");
+ else
+ metadata = imp.getStack().getSliceLabel(imp.getCurrentSlice());
+ if (metadata==null)
+ metadata = "";
+ return metadata;
+ }
+
+ ImagePlus getImageArg() {
+ ImagePlus img = null;
+ if (isStringArg()) {
+ String title = getString();
+ img = WindowManager.getImage(title);
+ } else {
+ int id = (int)interp.getExpression();
+ img = WindowManager.getImage(id);
+ }
+ if (img==null) interp.error("Image not found");
+ return img;
+ }
+
+ void imageCalculator() {
+ String operator = getFirstString();
+ interp.getComma();
+ ImagePlus img1 = getImageArg();
+ interp.getComma();
+ ImagePlus img2 = getImageArg();
+ interp.getRightParen();
+ ImageCalculator ic = new ImageCalculator();
+ ic.calculate(operator, img1, img2);
+ resetImage();
+ }
+
+ void setRGBWeights() {
+ double r = getFirstArg();
+ double g = getNextArg();
+ double b = getLastArg();
+ if (interp.rgbWeights==null)
+ interp.rgbWeights = ColorProcessor.getWeightingFactors();
+ ColorProcessor.setWeightingFactors(r, g, b);
+ }
+
+ private void makePolygon() {
+ Polygon points = new Polygon();
+ points.addPoint((int)Math.round(getFirstArg()), (int)Math.round(getNextArg()));
+ interp.getToken();
+ while (interp.token==',') {
+ int x = (int)Math.round(interp.getExpression());
+ interp.getComma();
+ int y = (int)Math.round(interp.getExpression());
+ points.addPoint(x,y);
+ interp.getToken();
+ }
+ if (points.npoints<3)
+ interp.error("Fewer than 3 points");
+ ImagePlus imp = getImage();
+ Roi previousRoi = imp.getRoi();
+ if (shiftKeyDown||altKeyDown) imp.saveRoi();
+ imp.setRoi(new PolygonRoi(points, Roi.POLYGON));
+ Roi roi = imp.getRoi();
+ if (previousRoi!=null && roi!=null)
+ updateRoi(roi);
+ resetImage();
+ shiftKeyDown = altKeyDown = false;
+ }
+
+ void updateRoi(Roi roi) {
+ if (shiftKeyDown || altKeyDown)
+ roi.update(shiftKeyDown, altKeyDown);
+ shiftKeyDown = altKeyDown = false;
+ }
+
+ String doFile() {
+ interp.getToken();
+ if (interp.token!='.')
+ interp.error("'.' expected");
+ interp.getToken();
+ if (!(interp.token==WORD || interp.token==STRING_FUNCTION || interp.token==NUMERIC_FUNCTION || interp.token==PREDEFINED_FUNCTION))
+ interp.error("Function name expected: ");
+ String name = interp.tokenString;
+ if (name.equals("open"))
+ return openFile();
+ else if (name.equals("openAsString"))
+ return openAsString();
+ else if (name.equals("openAsRawString"))
+ return openAsRawString();
+ else if (name.equals("openUrlAsString"))
+ return IJ.openUrlAsString(getStringArg());
+ else if (name.equals("openDialog"))
+ return openDialog();
+ else if (name.equals("close"))
+ return closeFile();
+ else if (name.equals("separator")) {
+ interp.getParens();
+ return File.separator;
+ } else if (name.equals("directory")) {
+ interp.getParens();
+ String lastDir = OpenDialog.getLastDirectory();
+ return lastDir!=null?lastDir:"";
+ } else if (name.equals("name")) {
+ interp.getParens();
+ String lastName = OpenDialog.getLastName();
+ return lastName!=null?lastName:"";
+ } else if (name.equals("nameWithoutExtension")) {
+ interp.getParens();
+ return nameWithoutExtension();
+ } else if (name.equals("rename")) {
+ File f1 = new File(getFirstString());
+ File f2 = new File(getLastString());
+ if (checkPath(f1) && checkPath(f2))
+ return f1.renameTo(f2)?"1":"0";
+ else
+ return "0";
+ } else if (name.equals("copy")) {
+ String f1 = getFirstString();
+ String f2 = getLastString();
+ String err = Tools.copyFile(f1, f2);
+ if (err.length()>0)
+ interp.error(err);
+ return null;
+ } else if (name.equals("append")) {
+ String err = IJ.append(getFirstString(), getLastString());
+ if (err!=null) interp.error(err);
+ return null;
+ } else if (name.equals("saveString")) {
+ String err = IJ.saveString(getFirstString(), getLastString());
+ if (err!=null) interp.error(err);
+ return null;
+ } else if (name.startsWith("setDefaultDir")) {
+ OpenDialog.setDefaultDirectory(getStringArg());
+ return null;
+ } else if (name.startsWith("getDefaultDir")) {
+ String dir = OpenDialog.getDefaultDirectory();
+ return dir!=null?dir:"";
+ } else if (name.equals("openSequence")) {
+ openSequence();
+ return null;
+ }
+
+ File f = new File(getStringArg());
+ if (name.equals("getLength")||name.equals("length"))
+ return ""+f.length();
+ else if (name.equals("getNameWithoutExtension")) {
+ String name2 = f.getName();
+ int dotIndex = name2.lastIndexOf(".");
+ if (dotIndex>=0)
+ name2 = name2.substring(0, dotIndex);
+ return name2;
+ } else if (name.equals("getName")) {
+ return f.getName();
+ } else if (name.equals("getDirectory")) {
+ String parent = f.getParent();
+ return parent!=null?parent.replaceAll("\\\\", "/")+"/":"";
+ } else if (name.equals("getAbsolutePath"))
+ return f.getAbsolutePath();
+ else if (name.equals("getParent"))
+ return f.getParent();
+ else if (name.equals("exists"))
+ return f.exists()?"1":"0";
+ else if (name.equals("isDirectory"))
+ return f.isDirectory()?"1":"0";
+ else if (name.equals("isFile"))
+ return f.isFile()?"1":"0";
+ else if (name.equals("makeDirectory")||name.equals("mkdir")) {
+ f.mkdir(); return null;
+ } else if (name.equals("lastModified"))
+ return ""+f.lastModified();
+ else if (name.equals("dateLastModified"))
+ return (new Date(f.lastModified())).toString();
+ else if (name.equals("delete"))
+ return f.delete()?"1":"0";
+ else
+ interp.error("Unrecognized File function "+name);
+ return null;
+ }
+
+ private void openSequence() {
+ String path = getFirstString();
+ String options = "";
+ if (interp.nextToken()==',')
+ options = getNextString();
+ interp.getRightParen();
+ ImagePlus imp = FolderOpener.open(path, options);
+ if (imp!=null)
+ imp.show();
+ }
+
+ String nameWithoutExtension() {
+ String name = OpenDialog.getLastName();
+ if (name==null) return "";
+ int dotIndex = name.lastIndexOf(".");
+ if (dotIndex>=0 && (name.length()-dotIndex)<=5)
+ name = name.substring(0, dotIndex);
+ return name;
+ }
+
+ boolean checkPath(File f) {
+ String path = f.getPath();
+ if (path.equals("0") || path.equals("NaN")) {
+ interp.error("Invalid path");
+ return false;
+ } else
+ return true;
+ }
+
+ String openDialog() {
+ String title = getStringArg();
+ OpenDialog od = new OpenDialog(title, null);
+ String directory = od.getDirectory();
+ String name = od.getFileName();
+ if (name==null)
+ return "";
+ else
+ return directory+name;
+ }
+
+ void setSelectionName() {
+ Roi roi = getImage().getRoi();
+ if (roi==null)
+ interp.error("No selection");
+ else
+ roi.setName(getStringArg());
+ }
+
+ String selectionName() {
+ Roi roi = getImage().getRoi();
+ String name = null;
+ if (roi==null)
+ interp.error("No selection");
+ else
+ name = roi.getName();
+ return name!=null?name:"";
+ }
+
+ String openFile() {
+ if (writer!=null) {
+ interp.error("Currently, only one file can be open at a time");
+ return"";
+ }
+ String path = getFirstString();
+ String defaultName = null;
+ if (interp.nextToken()==')')
+ interp.getRightParen();
+ else
+ defaultName = getLastString();
+ if (path.equals("") || defaultName!=null) {
+ String title = defaultName!=null?path:"openFile";
+ defaultName = defaultName!=null?defaultName:"log.txt";
+ SaveDialog sd = new SaveDialog(title, defaultName, ".txt");
+ if (sd.getFileName()==null) return "";
+ path = sd.getDirectory()+sd.getFileName();
+ } else {
+ File file = new File(path);
+ if (file.exists() && !(path.endsWith(".txt")||path.endsWith(".java")||path.endsWith(".xls")
+ ||path.endsWith(".csv")||path.endsWith(".tsv")||path.endsWith(".ijm")
+ ||path.endsWith(".html")||path.endsWith(".htm")))
+ interp.error("File exists and suffix is not '.txt', '.java', etc.");
+ }
+ try {
+ FileOutputStream fos = new FileOutputStream(path);
+ BufferedOutputStream bos = new BufferedOutputStream(fos);
+ writer = new PrintWriter(bos);
+ }
+ catch (IOException e) {
+ interp.error("File open error \n\""+e.getMessage()+"\"\n");
+ return "";
+ }
+ return "~0~";
+ }
+
+ String openAsString() {
+ String path = getStringArg();
+ String str = IJ.openAsString(path);
+ if (str==null)
+ interp.done = true;
+ else if (str.startsWith("Error: "))
+ interp.error(str);
+ return str;
+ }
+
+ String openAsRawString() {
+ long max = 5000;
+ String path = getFirstString();
+ boolean specifiedMax = false;
+ if (interp.nextToken()==',') {
+ max = (long)getNextArg();
+ specifiedMax = true;
+ }
+ interp.getRightParen();
+ if (path.equals("")) {
+ OpenDialog od = new OpenDialog("Open As String", "");
+ String directory = od.getDirectory();
+ String name = od.getFileName();
+ if (name==null) return "";
+ path = directory + name;
+ }
+ String str = "";
+ File file = new File(path);
+ if (!file.exists())
+ interp.error("File not found");
+ try {
+ StringBuffer sb = new StringBuffer(5000);
+ long len = file.length();
+ if (max>len || (path.endsWith(".txt")&&!specifiedMax))
+ max = len;
+ InputStream in = new BufferedInputStream(new FileInputStream(path));
+ DataInputStream dis = new DataInputStream(in);
+ byte[] buffer = new byte[(int)max];
+ dis.readFully(buffer);
+ dis.close();
+ char[] buffer2 = new char[buffer.length];
+ for (int i=0; i0) {
+ argClasses = new Class[args.length];
+ for(int i=0;i0) {
+ try {
+ Class[] argClasses = new Class[args.length];
+ for(int i=0;i params = new ArrayList();
+ while (interp.nextToken()==',')
+ params.add(getNextArg());
+ interp.getRightParen();
+ return String.format(command, params.toArray());
+ } catch (Exception e) {
+ interp.error(""+e);
+ }
+ return null;
+ }
+
+ private String join() {
+ interp.getLeftParen();
+ String delimiter = ", ";
+ ij.macro.Variable[] arr = getArray();
+ if (interp.nextToken()==',')
+ delimiter = getNextString();
+ interp.getRightParen();
+ return joinArray(arr, delimiter).toString();
+ }
+
+ private StringBuilder joinArray(ij.macro.Variable[] a, String delimiter) {
+ int len = a.length;
+ StringBuilder sb = new StringBuilder(len*6);
+ for (int i=0; iimp.getNChannels())
+ interp.error("Invalid channel: "+channel);
+ if (((CompositeImage)imp).getMode()!=IJ.COMPOSITE)
+ ((CompositeImage)imp).setMode(IJ.COMPOSITE);
+ boolean[] active = ((CompositeImage)imp).getActiveChannels();
+ active[channel-1] = active[channel-1]?false:true;
+ imp.updateAndDraw();
+ Channels.updateChannels();
+ }
+
+ void setDisplayMode(ImagePlus imp, String mode) {
+ mode = mode.toLowerCase(Locale.US);
+ if (!imp.isComposite())
+ interp.error("Composite image required");
+ int m = -1;
+ if (mode.equals("composite"))
+ m = IJ.COMPOSITE;
+ else if (mode.equals("color"))
+ m = IJ.COLOR;
+ else if (mode.startsWith("gray"))
+ m = IJ.GRAYSCALE;
+ if (m==-1)
+ interp.error("Invalid mode");
+ ((CompositeImage)imp).setMode(m);
+ imp.updateAndDraw();
+ }
+
+ void swapStackImages(ImagePlus imp) {
+ int n1 = (int)getFirstArg();
+ int n2 = (int)getLastArg();
+ ImageStack stack = imp.getStack();
+ int size = stack.size();
+ if (n1<1||n1>size||n2<1||n2>size)
+ interp.error("Argument out of range");
+ Object pixels = stack.getPixels(n1);
+ String label = stack.getSliceLabel(n1);
+ stack.setPixels(stack.getPixels(n2), n1);
+ stack.setSliceLabel(stack.getSliceLabel(n2), n1);
+ stack.setPixels(pixels, n2);
+ stack.setSliceLabel(label, n2);
+ int current = imp.getCurrentSlice();
+ if (imp.isComposite()) {
+ CompositeImage ci = (CompositeImage)imp;
+ if (ci.getMode()==IJ.COMPOSITE) {
+ ci.reset();
+ imp.updateAndDraw();
+ imp.repaintWindow();
+ return;
+ }
+ }
+ if (n1==current || n2==current)
+ imp.setStack(null, stack);
+ }
+
+ void getDisplayMode(ImagePlus imp) {
+ ij.macro.Variable v = getVariableArg();
+ String mode = "";
+ if (imp.isComposite())
+ mode = ((CompositeImage)imp).getModeAsString();
+ v.setString(mode);
+ }
+
+ void getPosition(ImagePlus imp) {
+ ij.macro.Variable channel = getFirstVariable();
+ ij.macro.Variable slice = getNextVariable();
+ ij.macro.Variable frame = getLastVariable();
+ int c = imp.getChannel();
+ int z = imp.getSlice();
+ int t = imp.getFrame();
+ if (c*z*t>imp.getStackSize())
+ {c=1; z=imp.getCurrentSlice(); t=1;}
+ channel.setValue(c);
+ slice.setValue(z);
+ frame.setValue(t);
+ }
+
+ void setPosition(ImagePlus img) {
+ int channel = (int)getFirstArg();
+ int slice = (int)getNextArg();
+ int frame = (int)getLastArg();
+ img.setPosition(channel, slice, frame);
+ }
+
+ void setDimensions(ImagePlus img) {
+ int c = (int)getFirstArg();
+ int z = (int)getNextArg();
+ int t = (int)getLastArg();
+ img.setDimensions(c, z, t);
+ if (img.getWindow()==null) img.setOpenAsHyperStack(true);
+ }
+
+ void setTool() {
+ interp.getLeftParen();
+ if (isStringArg()) {
+ boolean ok = IJ.setTool(getString());
+ if (!ok) interp.error("Unrecognized tool name");
+ } else
+ IJ.setTool((int)interp.getExpression());
+ interp.getRightParen();
+ }
+
+ String doToString() {
+ interp.getLeftParen();
+ if (interp.nextNextToken()==',') {//1.53t bug fix
+ double n = interp.getExpression();
+ int digits = (int)getLastArg();
+ return IJ.d2s(n, digits);
+ }
+ String s = getString();
+ interp.getToken();
+ if (interp.token==',') {
+ double value = Tools.parseDouble(s);
+ s = IJ.d2s(value, (int)interp.getExpression());
+ interp.getToken();
+ }
+ if (interp.token!=')') interp.error("')' expected");
+ return s;
+ }
+
+ double matches(String str) {
+ str = getStringFunctionArg(str);
+ String regex = getString();
+ interp.getRightParen();
+ try {
+ return str.matches(regex)?1.0:0.0;
+ } catch (Exception e) {
+ interp.error(""+e);
+ return 0.0;
+ }
+ }
+
+ void waitForUser() {
+ IJ.wait(50);
+ if (waitForUserDialog!=null && waitForUserDialog.isShowing())
+ interp.error("Duplicate call");
+ String title = "Action Required";
+ String text = " Click \"OK\" to continue ";
+ if (interp.nextToken()=='(') {
+ title = getFirstString();
+ if (interp.nextToken()==',')
+ text = getLastString();
+ else {
+ text = title;
+ title = "Action Required";
+ interp.getRightParen();
+ }
+ }
+ waitForUserDialog = new WaitForUserDialog(title, text);
+ ij.macro.Interpreter instance = ij.macro.Interpreter.getInstance();
+ interp.waitingForUser = true;
+ waitForUserDialog.show();
+ interp.waitingForUser = false;
+ ij.macro.Interpreter.setInstance(instance); // works around bug caused by use of drawing tools
+ if (waitForUserDialog.escPressed() || IJ.escapePressed())
+ throw new RuntimeException(Macro.MACRO_CANCELED);
+ }
+
+ void abortDialog() {
+ if (waitForUserDialog!=null && waitForUserDialog.isVisible())
+ waitForUserDialog.close();
+ }
+
+ double getStringWidth() {
+ resetImage();
+ ImageProcessor ip = getProcessor();
+ setFont(ip);
+ return ip.getStringWidth(getStringArg());
+ }
+
+ String doList() {
+ interp.getToken();
+ if (interp.token!='.')
+ interp.error("'.' expected");
+ interp.getToken();
+ if (!(interp.token==WORD||interp.token==ARRAY_FUNCTION||interp.token==NUMERIC_FUNCTION))
+ interp.error("Function name expected: ");
+ if (props==null)
+ props = new Properties();
+ String value = null;
+ String name = interp.tokenString;
+ if (name.equals("get")) {
+ value = props.getProperty(getStringArg());
+ value = value!=null?value:"";
+ } else if (name.equals("getValue")) {
+ value = props.getProperty(getStringArg());
+ if (value==null) interp.error("Value not found");
+ } else if (name.equals("set")||name.equals("add")||name.equals("put"))
+ props.setProperty(getFirstString(), getLastString());
+ else if (name.equals("clear")||name.equals("reset")) {
+ interp.getParens();
+ props.clear();
+ } else if (name.equals("setList"))
+ setPropertiesFromString(props);
+ else if (name.equals("getList"))
+ value = getPropertiesAsString(props);
+ else if (name.equals("size")||name.equals("getSize")) {
+ interp.getParens();
+ value = ""+props.size();
+ } else if (name.equals("setMeasurements"))
+ setMeasurements();
+ else if (name.equals("setCommands"))
+ setCommands();
+ else if (name.equals("indexOf")) {
+ int index = -1;
+ String key = getStringArg();
+ int size = props.size();
+ String[] keyArr = new String[size];
+ String[] valueArr = new String[size];
+ listToArrays(keyArr, valueArr);
+ for (int i = 0; i < size; i++) {
+ if (keyArr[i].equals(key)) {
+ index = i;
+ break;
+ }
+ }
+ value = "" + index;
+ } else if (name.equals("fromArrays")) {
+ interp.getLeftParen();
+ String[] keys = getStringArray();
+ interp.getComma();
+ String[] values = getStringArray();
+ if (values.length != keys.length) {
+ interp.error("Arrays must have same length");
+ }
+ props.clear();
+ for (int i = 0; i < keys.length; i++) {
+ if (keys[i].equals("")) {
+ interp.error("Key cannot be an empty string");
+ }
+ props.setProperty(keys[i], values[i]);
+ }
+ interp.getRightParen();
+ } else if (name.equals("toArrays")) {
+ ij.macro.Variable keys = getFirstArrayVariable();
+ ij.macro.Variable values = getLastArrayVariable();
+
+ int size = props.size();
+ String[] keyArr = new String[size];
+ String[] valueArr = new String[size];
+
+ listToArrays(keyArr, valueArr);
+ ij.macro.Variable[] keysVar, valuesVar;
+ keysVar = new ij.macro.Variable[size];
+ valuesVar = new ij.macro.Variable[size];
+ for (int i = 0; i < size; i++) {
+ keysVar[i] = new ij.macro.Variable();
+ keysVar[i].setString(keyArr[i]);
+ valuesVar[i] = new ij.macro.Variable();
+ valuesVar[i].setString(valueArr[i]);
+ }
+ keys.setArray(keysVar);
+ values.setArray(valuesVar);
+ } else {
+ interp.error("Unrecognized List function");
+ }
+ return value;
+ }
+
+ void listToArrays(String[] keys, String[] values) {
+ Vector v = new Vector();
+ for (Enumeration en = props.keys(); en.hasMoreElements();) {
+ v.addElement(en.nextElement());
+ }
+ for (int i = 0; i < keys.length; i++) {
+ keys[i] = (String) v.elementAt(i);
+ }
+ Arrays.sort(keys);
+ for (int i = 0; i < keys.length; i++) {
+ values[i] = (String) props.get(keys[i]);
+ }
+ }
+
+ void setCommands() {
+ interp.getParens();
+ Hashtable commands = Menus.getCommands();
+ props = new Properties();
+ for (Enumeration en=commands.keys(); en.hasMoreElements();) {
+ String command = (String)en.nextElement();
+ props.setProperty(command, (String)commands.get(command));
+ }
+ }
+
+ void setMeasurements() {
+ String arg = "";
+ if (interp.nextToken()=='(') {
+ interp.getLeftParen();
+ if (interp.nextToken() != ')')
+ arg = getString().toLowerCase(Locale.US);
+ interp.getRightParen();
+ }
+ props.clear();
+ ImagePlus imp = getImage();
+ int measurements = ALL_STATS + SLICE;
+ if (arg.contains("limit"))
+ measurements += LIMIT;
+ ImageStatistics stats = imp.getStatistics(measurements);
+ ResultsTable rt = new ResultsTable();
+ Analyzer analyzer = new Analyzer(imp, measurements, rt);
+ analyzer.saveResults(stats, imp.getRoi());
+ for (int i=0; i<=rt.getLastColumn(); i++) {
+ if (rt.columnExists(i)) {
+ String name = rt.getColumnHeading(i);
+ String value = ""+rt.getValueAsDouble(i, 0);
+ props.setProperty(name, value);
+ }
+ }
+ }
+
+ void makePoint() {
+ double x = getFirstArg();
+ double y = getNextArg();
+ String options = null;
+ if (interp.nextToken()==',')
+ options = getNextString();
+ interp.getRightParen();
+ if (options==null) {
+ if ((int)x==x && (int)y==y)
+ IJ.makePoint((int)x, (int)y);
+ else
+ IJ.makePoint(x, y);
+ } else {
+ if (options!=null && options.equals("add")) { //add point to multi-point selection
+ IJ.setKeyDown(KeyEvent.VK_SHIFT);
+ if ((int)x==x && (int)y==y)
+ IJ.makePoint((int)x, (int)y);
+ else
+ IJ.makePoint(x, y);
+ } else
+ getImage().setRoi(new PointRoi(x, y, options));
+ }
+ resetImage();
+ shiftKeyDown = altKeyDown = false;
+ }
+
+ void makeText() {
+ String text = getFirstString();
+ int x = (int)getNextArg();
+ int y = (int)getLastArg();
+ ImagePlus imp = getImage();
+ Font font = this.font;
+ boolean nullFont = font==null;
+ if (nullFont)
+ font = imp.getProcessor().getFont();
+ TextRoi roi = new TextRoi(x, y, text, font);
+ if (!nullFont)
+ roi.setAntiAlias(antialiasedText);
+ imp.setRoi(roi);
+ }
+
+ void makeEllipse() {
+ ImagePlus imp = getImage();
+ Roi previousRoi = imp.getRoi();
+ if (shiftKeyDown||altKeyDown)
+ imp.saveRoi();
+ double x1 = getFirstArg();
+ double y1 = getNextArg();
+ double x2 = getNextArg();
+ double y2 = getNextArg();
+ double aspectRatio = getLastArg();
+ Roi roi = new EllipseRoi(x1,y1,x2,y2,aspectRatio);
+ imp.setRoi(roi);
+ if (previousRoi!=null && roi!=null)
+ updateRoi(roi);
+ resetImage();
+ shiftKeyDown = altKeyDown = false;
+ }
+
+ double fit() {
+ interp.getToken();
+ if (interp.token!='.')
+ interp.error("'.' expected");
+ interp.getToken();
+ if (!(interp.token==WORD||interp.token==ARRAY_FUNCTION))
+ interp.error("Function name expected: ");
+ if (props==null)
+ props = new Properties();
+ String name = interp.tokenString;
+ if (name.equals("doFit"))
+ return fitCurve(false);
+ if (name.equals("doWeightedFit"))
+ return fitCurve(true);
+ else if (name.equals("getEquation"))
+ return getEquation();
+ else if (name.equals("nEquations")) {
+ interp.getParens();
+ return CurveFitter.fitList.length;
+ } else if (name.equals("showDialog")) {
+ showFitDialog = true;
+ return Double.NaN;
+ } else if (name.equals("logResults")) {
+ logFitResults = true;
+ return Double.NaN;
+ }
+ if (fitter==null)
+ interp.error("No fit");
+ if (name.equals("f"))
+ return fitter.f(fitter.getParams(), getArg());
+ else if (name.equals("plot")) {
+ interp.getParens();
+ Fitter.plot(fitter);
+ return Double.NaN;
+ } else if (name.equals("nParams")) {
+ interp.getParens();
+ return fitter.getNumParams();
+ } else if (name.equals("p")) {
+ int index = (int)getArg();
+ checkIndex(index, 0, fitter.getNumParams()-1);
+ double[] p = fitter.getParams();
+ return indexlen) i2 = len;
+ int len2 = i2-i1;
+ if (len2<0) len2=0;
+ if (len2>len) len2=len;
+ interp.getRightParen();
+ ij.macro.Variable[] a2 = new ij.macro.Variable[len2];
+ for (int i=0; ilen) size = len;
+ ij.macro.Variable[] a2 = new ij.macro.Variable[size];
+ for (int i=0; imax) max = value;
+ }
+ minv.setValue(min);
+ if (maxv!=null) maxv.setValue(max);
+ if (mean!=null) mean.setValue(sum/n);
+ if (std!=null) {
+ double stdDev = (n*sum2-sum*sum)/n;
+ stdDev = Math.sqrt(stdDev/(n-1.0));
+ std.setValue(stdDev);
+ }
+ return a;
+ }
+
+ ij.macro.Variable[] getSequence() {
+ int n = (int)getArg();
+ ij.macro.Variable[] a = new ij.macro.Variable[n];
+ for (int i=0; i= 180.0)
+ phi -= 360.0;
+ vAngles[mid] = phi;
+ }
+ for (int i = 0; i < len; i++)
+ a2[i] = new ij.macro.Variable(vAngles[i]);
+ return a2;
+ }
+
+ ij.macro.Variable[] showArray() {
+ int maxLength = 0;
+ String title = "Arrays";
+ ArrayList arrays = new ArrayList();
+ ArrayList names = new ArrayList();
+ interp.getLeftParen();
+ do {
+ if (isStringArg() && !isArrayArg())
+ title = getString();
+ else {
+ int symbolTableAddress = pgm.code[interp.pc+1]>>TOK_SHIFT;
+ names.add(pgm.table[symbolTableAddress].str);
+ ij.macro.Variable[] a = getArray();
+ arrays.add(a);
+ if (a.length>maxLength)
+ maxLength = a.length;
+ }
+ interp.getToken();
+ } while (interp.token==',');
+ if (interp.token!=')')
+ interp.error("')' expected");
+ int n = arrays.size();
+ if (n==1) {
+ if (title.equals("Arrays"))
+ title = (String)names.get(0);
+ names.set(0, "Value");
+ }
+ ResultsTable rt = new ResultsTable();
+ //rt.setPrecision(Analyzer.getPrecision());
+ int openParenIndex = title.indexOf("(");
+ boolean showRowNumbers = false;
+ if (openParenIndex>=0) {
+ String options = title.substring(openParenIndex, title.length());
+ title = title.substring(0, openParenIndex);
+ title = title.trim();
+ showRowNumbers = options.contains("row") || options.contains("1");
+ if (!showRowNumbers && options.contains("index")) {
+ for (int i=0; i=a.length) {
+ rt.setValue(heading, i, "");
+ continue;
+ }
+ String s = a[i].getString();
+ if (s!=null)
+ rt.setValue(heading, i, s);
+ else
+ rt.setValue(heading, i, a[i].getValue());
+ }
+ }
+ rt.show(title);
+ waitUntilActivated(title);
+ return null;
+ }
+
+ double charCodeAt() {
+ String str = getFirstString();
+ int index = (int)getLastArg();
+ checkIndex(index, 0, str.length()-1);
+ return str.charAt(index);
+ }
+
+ void doWand() {
+ int x = (int)getFirstArg();
+ int y = (int)getNextArg();
+ double tolerance = 0.0;
+ String mode = null;
+ if (interp.nextToken()==',') {
+ tolerance = getNextArg();
+ mode = getNextString();
+ }
+ interp.getRightParen();
+ IJ.doWand(x, y, tolerance, mode);
+ resetImage();
+ }
+
+ private String doIJ() {
+ interp.getToken();
+ if (interp.token!='.')
+ interp.error("'.' expected");
+ interp.getToken();
+ if (!(interp.token==WORD||interp.token==NUMERIC_FUNCTION))
+ interp.error("Function name expected: ");
+ String name = interp.tokenString;
+ if (name.equals("pad"))
+ return pad();
+ else if (name.equals("deleteRows"))
+ IJ.deleteRows((int)getFirstArg(), (int)getLastArg());
+ else if (name.equals("log"))
+ IJ.log(getStringArg());
+ else if (name.equals("freeMemory"))
+ {interp.getParens(); return IJ.freeMemory();}
+ else if (name.equals("currentMemory"))
+ {interp.getParens(); return ""+IJ.currentMemory();}
+ else if (name.equals("maxMemory"))
+ {interp.getParens(); return ""+IJ.maxMemory();}
+ else if (name.equals("getToolName"))
+ {interp.getParens(); return ""+IJ.getToolName();}
+ else if (name.equals("redirectErrorMessages"))
+ {interp.getParens(); IJ.redirectErrorMessages(); return null;}
+ else if (name.equals("renameResults"))
+ renameResults();
+ else if (name.equals("getFullVersion"))
+ {interp.getParens(); return ""+IJ.getFullVersion();}
+ else if (name.equals("checksum"))
+ return checksum();
+ else
+ interp.error("Unrecognized IJ function name");
+ return null;
+ }
+
+ private String checksum(){
+ String method = getFirstString();
+ String src = getLastString();
+ method = method.toUpperCase();
+ if (method.contains("FILE") && method.contains("MD5"))
+ return Tools.getHash("MD5", true, src);
+ if (method.contains("STRING") && method.contains("MD5"))
+ return Tools.getHash("MD5", false, src);
+ if (method.contains("FILE") && method.contains("SHA-256"))
+ return Tools.getHash("SHA-256", true, src);
+ if (method.contains("STRING") && method.contains("SHA-256"))
+ return Tools.getHash("SHA-256", false, src);
+ interp.error("must contain 'file' or 'string' and 'MD5' or 'SHA-256'");
+ return "0";
+ }
+
+ private String pad() {
+ int intArg = 0;
+ String stringArg = null;
+ interp.getLeftParen();
+ if (isStringArg())
+ stringArg = getString();
+ else
+ intArg = (int)interp.getExpression();
+ int digits = (int)getLastArg();
+ if (stringArg!=null)
+ return IJ.pad(stringArg, digits);
+ else
+ return IJ.pad(intArg, digits);
+ }
+
+ private void renameResults() {
+ String arg1 = getFirstString();
+ String arg2 = null;
+ if (interp.nextToken()==')')
+ interp.getRightParen();
+ else
+ arg2 = getLastString();
+ if (resultsPending) {
+ ResultsTable rt = Analyzer.getResultsTable();
+ if (rt!=null && rt.size()>0)
+ rt.show("Results");
+ resultsPending = false;
+ }
+ if (arg2!=null)
+ IJ.renameResults(arg1, arg2);
+ else
+ IJ.renameResults(arg1);
+ }
+
+ double doOverlay() {
+ interp.getToken();
+ if (interp.token!='.')
+ interp.error("'.' expected");
+ interp.getToken();
+ if (!(interp.token==WORD||interp.token==ARRAY_FUNCTION
+ || interp.token==PREDEFINED_FUNCTION||interp.token==USER_FUNCTION))
+ interp.error("Function name expected");
+ String name = interp.tokenString;
+ ImagePlus imp = getImage();
+ if (name.equals("lineTo"))
+ return overlayLineTo();
+ else if (name.equals("moveTo"))
+ return overlayMoveTo();
+ else if (name.equals("drawLine"))
+ return overlayDrawLine();
+ else if (name.equals("drawRect"))
+ return overlayDrawRectOrEllipse(imp, false);
+ else if (name.equals("drawEllipse"))
+ return overlayDrawRectOrEllipse(imp, true);
+ else if (name.equals("drawString"))
+ return overlayDrawString(imp);
+ else if (name.equals("add"))
+ return addDrawing(imp);
+ else if (name.equals("show"))
+ return showOverlay(imp);
+ else if (name.equals("hide"))
+ return hideOverlay(imp);
+ else if (name.equals("selectable"))
+ return overlaySelectable(imp);
+ else if (name.equals("remove"))
+ return removeOverlay(imp);
+ else if (name.equals("clear"))
+ return clearOverlay(imp);
+ else if (name.equals("paste")) {
+ interp.getParens();
+ if (overlayClipboard==null)
+ interp.error("Overlay clipboard empty");
+ getImage().setOverlay(overlayClipboard);
+ return Double.NaN;
+ } else if (name.equals("pasteAndMerge")) {
+ return Double.NaN;
+ } else if (name.equals("drawLabels")) {
+ overlayDrawLabels = getBooleanArg();
+ Overlay overlay = imp.getOverlay();
+ if (overlay!=null) {
+ overlay.drawLabels(overlayDrawLabels);
+ imp.draw();
+ }
+ return Double.NaN;
+ } else if (name.equals("useNamesAsLabels")) {
+ boolean useNames = getBooleanArg();
+ Overlay overlay = imp.getOverlay();
+ if (overlay!=null) {
+ overlay.drawNames(useNames);
+ imp.draw();
+ }
+ return Double.NaN;
+ }
+ Overlay overlay = imp.getOverlay();
+ int size = overlay!=null?overlay.size():0;
+ if (overlay==null && name.equals("size")) {
+ interp.getParens();
+ return 0.0;
+ } else if (name.equals("hidden")) {
+ return overlay!=null && imp.getHideOverlay()?1.0:0.0;
+ } else if (name.equals("addSelection") || name.equals("addRoi")) {
+ return overlayAddSelection(imp, overlay);
+ } else if (name.equals("setPosition")) {
+ addDrawingToOverlay(imp);
+ return overlaySetPosition(overlay);
+ } else if (name.equals("setFillColor"))
+ return overlaySetFillColor(overlay);
+ else if (name.equals("indexAt")) {
+ int x = (int)getFirstArg();
+ int y = (int)getLastArg();
+ return overlay!=null?overlay.indexAt(x,y):-1;
+ } else if (name.equals("getType")) {
+ int index = (int)getArg();
+ if (overlay==null || index==-1) return -1;
+ checkIndex(index, 0, size-1);
+ return overlay.get(index).getType();
+ }
+ if (overlay==null)
+ interp.error("No overlay");
+ if (name.equals("size")||name.equals("getSize")) {
+ interp.getParens();
+ return size;
+ } else if (name.equals("copy")) {
+ interp.getParens();
+ overlayClipboard = getImage().getOverlay();
+ return Double.NaN;
+ } else if (name.equals("update")) {
+ int index = (int)getArg();
+ checkIndex(index, 0, size-1);
+ overlay.set(imp.getRoi(), index);
+ return Double.NaN;
+ } else if (name.equals("removeSelection")||name.equals("removeRoi")) {
+ int index = (int)getArg();
+ checkIndex(index, 0, size-1);
+ overlay.remove(index);
+ imp.draw();
+ return Double.NaN;
+ } else if (name.equals("activateSelection")||name.equals("activateSelectionAndWait")||name.equals("activateRoi")) {
+ boolean waitForDisplayRefresh = name.equals("activateSelectionAndWait");
+ return activateSelection(imp, overlay, waitForDisplayRefresh);
+ } else if (name.equals("moveSelection")) {
+ int index = (int)getFirstArg();
+ int x = (int)getNextArg();
+ int y = (int)getLastArg();
+ checkIndex(index, 0, size-1);
+ Roi roi = overlay.get(index);
+ roi.setLocation(x, y);
+ imp.draw();
+ return Double.NaN;
+ } else if (name.equals("measure")) {
+ ResultsTable rt = overlay.measure(imp);
+ if (IJ.getInstance()==null)
+ Analyzer.setResultsTable(rt);
+ else
+ rt.show("Results");
+ } else if (name.equals("fill")) {
+ interp.getLeftParen();
+ Color foreground = getColor();
+ Color background = null;
+ if (interp.nextToken()!=')') {
+ interp.getComma();
+ background = getColor();
+ }
+ interp.getRightParen();
+ overlay.fill(imp, foreground, background);
+ return Double.NaN;
+ } else if (name.equals("flatten")) {
+ IJ.runPlugIn("ij.plugin.OverlayCommands", "flatten");
+ return Double.NaN;
+ } else if (name.equals("setLabelFontSize")) {
+ int fontSize = (int)getFirstArg();
+ String options = null;
+ if (interp.nextToken()!=')')
+ options = getLastString();
+ else
+ interp.getRightParen();
+ overlay.setLabelFontSize(fontSize, options);
+ return Double.NaN;
+ } else if (name.equals("setLabelColor")) {
+ interp.getLeftParen();
+ Color color = getColor();
+ if (interp.nextToken()==',') {
+ interp.getComma();
+ Color ignore = getColor();
+ overlay.drawBackgrounds(true);
+ }
+ interp.getRightParen();
+ overlay.setLabelColor(color);
+ overlay.drawLabels(true);
+ return Double.NaN;
+ } else if (name.equals("setStrokeColor")) {
+ interp.getLeftParen();
+ Color color = getColor();
+ interp.getRightParen();
+ overlay.setStrokeColor(color);
+ return Double.NaN;
+ } else if (name.equals("setStrokeWidth")) {
+ overlay.setStrokeWidth(getArg());
+ return Double.NaN;
+ } else if (name.equals("removeRois")) {
+ overlay.remove(getStringArg());
+ return Double.NaN;
+ } else if (name.equals("getBounds")) {
+ return getOverlayElementBounds(overlay);
+ } else if (name.equals("cropAndSave")) {
+ Roi[] rois = overlay.toArray();
+ imp.cropAndSave(rois, getFirstString(), getLastString());
+ return Double.NaN;
+ } else if (name.equals("xor")) {
+ double[] arg = getFirstArray();
+ interp.getRightParen();
+ int[] indexes = new int[arg.length];
+ for (int i=0; i1) {
+ if (imp.isHyperStack() && roi.hasHyperStackPosition()) {
+ int c = roi.getCPosition();
+ int z = roi.getZPosition();
+ int t = roi.getTPosition();
+ c = c>0?c:imp.getChannel();
+ z = z>0?z:imp.getSlice();
+ t = t>0?t:imp.getFrame();
+ imp.setPosition(c, z, t);
+ } else if (roi.getPosition()>0)
+ imp.setSlice(roi.getPosition());
+ }
+ if (wait) { // wait for display to finish updating
+ ImageCanvas ic = imp.getCanvas();
+ if (ic!=null) ic.setPaintPending(true);
+ imp.setRoi(roi, !ij.macro.Interpreter.isBatchMode());
+ long t0 = System.currentTimeMillis();
+ do {
+ IJ.wait(5);
+ } while (ic!=null && ic.getPaintPending() && System.currentTimeMillis()-t0<50);
+ } else
+ imp.setRoi(roi, !ij.macro.Interpreter.isBatchMode());
+ if (Analyzer.addToOverlay())
+ ResultsTable.selectRow(roi);
+ return Double.NaN;
+ }
+
+ private double getOverlayElementBounds(Overlay overlay) {
+ int index = (int)getFirstArg();
+ ij.macro.Variable x = getNextVariable();
+ ij.macro.Variable y = getNextVariable();
+ ij.macro.Variable width = getNextVariable();
+ ij.macro.Variable height = getLastVariable();
+ Roi roi = overlay.get(index);
+ if (roi==null)
+ return Double.NaN;
+ Rectangle2D.Double r = roi.getFloatBounds();
+ x.setValue(r.x);
+ y.setValue(r.y);
+ width.setValue(r.width);
+ height.setValue(r.height);
+ return Double.NaN;
+ }
+
+ double overlayAddSelection(ImagePlus imp, Overlay overlay) {
+ String strokeColor = null;
+ double strokeWidth = Double.NaN;
+ String fillColor = null;
+ if (interp.nextToken()=='(') {
+ interp.getLeftParen();
+ if (isStringArg()) {
+ strokeColor = getString();
+ if (interp.nextToken()==',') {
+ interp.getComma();
+ strokeWidth = interp.getExpression();
+ if (interp.nextToken()==',') {
+ interp.getComma();
+ fillColor = interp.getString();
+ }
+ }
+ }
+ interp.getRightParen();
+ }
+ Roi roi = imp.getRoi();
+ if (roi==null)
+ interp.error("No selection");
+ if (offscreenOverlay!=null) {
+ imp.setOverlay(offscreenOverlay);
+ offscreenOverlay = null;
+ overlay = imp.getOverlay();
+ }
+ if (overlay==null)
+ overlay = new Overlay();
+ if (strokeColor!=null && !strokeColor.equals("")) {
+ roi.setFillColor(null);
+ roi.setStrokeColor(Colors.decode(strokeColor, Color.black));
+ }
+ if (!Double.isNaN(strokeWidth))
+ roi.setStrokeWidth(strokeWidth);
+ if (fillColor!=null && !fillColor.equals(""))
+ roi.setFillColor(Colors.decode(fillColor, Color.black));
+ overlay.add(roi);
+ imp.setOverlay(overlay);
+ return Double.NaN;
+ }
+
+ double overlaySetPosition(Overlay overlay) {
+ int c=0, z=0, t=0;
+ int nargs = 1;
+ int n = (int)getFirstArg();
+ if (interp.nextToken()==',') {
+ nargs = 3;
+ c = n;
+ z = (int)getNextArg();
+ t = (int)getLastArg();
+ } else
+ interp.getRightParen();
+ if (overlay==null)
+ overlay = offscreenOverlay;
+ if (overlay==null)
+ interp.error("No overlay");
+ int size = overlay.size();
+ if (size==0)
+ return Double.NaN;
+ if (nargs==1)
+ overlay.get(size-1).setPosition(n);
+ else if (nargs==3)
+ overlay.get(size-1).setPosition(c, z, t);
+ return Double.NaN;
+ }
+
+ double overlaySetFillColor(Overlay overlay) {
+ interp.getLeftParen();
+ Color color = getColor();
+ interp.getRightParen();
+ if (overlay==null)
+ overlay = offscreenOverlay;
+ if (overlay==null)
+ interp.error("No overlay");
+ int size = overlay.size();
+ if (size>0)
+ overlay.get(size-1).setFillColor(color);
+ return Double.NaN;
+ }
+
+ double overlayMoveTo() {
+ if (overlayPath==null)
+ overlayPath = new GeneralPath();
+ interp.getLeftParen();
+ float x = (float)interp.getExpression();
+ interp.getComma();
+ float y = (float)interp.getExpression();
+ interp.getRightParen();
+ overlayPath.moveTo(x, y);
+ return Double.NaN;
+ }
+
+ double overlayLineTo() {
+ if (overlayPath==null) {
+ overlayPath = new GeneralPath();
+ overlayPath.moveTo(0, 0);
+ }
+ interp.getLeftParen();
+ float x = (float)interp.getExpression();
+ interp.getComma();
+ float y = (float)interp.getExpression();
+ interp.getRightParen();
+ overlayPath.lineTo(x, y);
+ return Double.NaN;
+ }
+
+ double overlayDrawLine() {
+ if (overlayPath==null) overlayPath = new GeneralPath();
+ interp.getLeftParen();
+ float x1 = (float)interp.getExpression();
+ interp.getComma();
+ float y1 = (float)interp.getExpression();
+ interp.getComma();
+ float x2 = (float)interp.getExpression();
+ interp.getComma();
+ float y2 = (float)interp.getExpression();
+ interp.getRightParen();
+ overlayPath.moveTo(x1, y1);
+ overlayPath.lineTo(x2, y2);
+ return Double.NaN;
+ }
+
+ double overlayDrawRectOrEllipse(ImagePlus imp, boolean ellipse) {
+ addDrawingToOverlay(imp);
+ float x = (float)Math.round(getFirstArg());
+ float y = (float)Math.round(getNextArg());
+ float w = (float)Math.round(getNextArg());
+ float h = (float)Math.round(getLastArg());
+ Shape shape = null;
+ if (ellipse)
+ shape = new Ellipse2D.Float(x, y, w, h);
+ else
+ shape = new Rectangle2D.Float(x, y, w, h);
+ Roi roi = new ShapeRoi(shape);
+ addRoi(imp, roi);
+ return Double.NaN;
+ }
+
+ double overlayDrawString(ImagePlus imp) {
+ addDrawingToOverlay(imp);
+ String text = getFirstString();
+ int x = (int)getNextArg();
+ int y = (int)getNextArg();
+ double angle = 0.0;
+ if (interp.nextToken()==',')
+ angle = getLastArg();
+ else
+ interp.getRightParen();
+ Font font = this.font;
+ boolean nullFont = font==null;
+ if (nullFont)
+ font = imp.getProcessor().getFont();
+ TextRoi roi = new TextRoi(text, x, y, font); // use drawString() compatible constructor
+ if (!nullFont && !antialiasedText)
+ roi.setAntiAlias(false);
+ roi.setAngle(angle);
+ roi.setJustification(justification);
+ if (nonScalableText)
+ roi.setNonScalable(true);
+ addRoi(imp, roi);
+ return Double.NaN;
+ }
+
+ double addDrawing(ImagePlus imp) {
+ interp.getParens();
+ addDrawingToOverlay(imp);
+ return Double.NaN;
+ }
+
+ void addDrawingToOverlay(ImagePlus imp) {
+ if (overlayPath==null)
+ return;
+ Roi roi = new ShapeRoi(overlayPath);
+ overlayPath = null;
+ addRoi(imp, roi);
+ }
+
+ void addRoi(ImagePlus imp, Roi roi){
+ Overlay overlay = imp.getOverlay();
+ if (overlay==null) {
+ if (offscreenOverlay==null)
+ offscreenOverlay = new Overlay();
+ overlay = offscreenOverlay;
+ }
+ if (globalColor!=null)
+ roi.setStrokeColor(globalColor);
+ roi.setStrokeWidth(getProcessor().getLineWidth());
+ overlay.add(roi);
+ }
+
+ double showOverlay(ImagePlus imp) {
+ interp.getParens();
+ addDrawingToOverlay(imp);
+ if (offscreenOverlay!=null) {
+ imp.setOverlay(offscreenOverlay);
+ offscreenOverlay = null;
+ } else
+ imp.setHideOverlay(false);
+ return Double.NaN;
+ }
+
+ double hideOverlay(ImagePlus imp) {
+ interp.getParens();
+ imp.setHideOverlay(true);
+ return Double.NaN;
+ }
+
+ double overlaySelectable(ImagePlus imp) {
+ boolean selectable = getBooleanArg();
+ Overlay overlay = imp.getOverlay();
+ if (overlay!=null)
+ overlay.selectable(selectable);
+ return Double.NaN;
+ }
+
+ double removeOverlay(ImagePlus imp) {
+ interp.getParens();
+ imp.setOverlay(null);
+ offscreenOverlay = null;
+ return Double.NaN;
+ }
+
+ double clearOverlay(ImagePlus imp) {
+ interp.getParens();
+ offscreenOverlay = null;
+ Overlay overlay = imp.getOverlay();
+ if (overlay!=null)
+ overlay.clear();
+ return Double.NaN;
+ }
+
+ private ij.macro.Variable doTable() {
+ interp.getToken();
+ if (interp.token!='.')
+ interp.error("'.' expected");
+ interp.getToken();
+ if (!(interp.token==WORD || interp.token==NUMERIC_FUNCTION || interp.token==PREDEFINED_FUNCTION || interp.token==STRING_FUNCTION))
+ interp.error("Function name expected: ");
+ String name = interp.tokenString;
+ if (name.equals("create"))
+ return resetTable();
+ else if (name.equals("size"))
+ return new ij.macro.Variable(getResultsTable(getTitleArg()).size());
+ else if (name.equals("get"))
+ return new ij.macro.Variable(getResult(getRT(null)));
+ else if (name.equals("getColumn"))
+ return getColumn();
+ else if (name.equals("columnExists"))
+ return columnExists();
+ else if (name.equals("getString"))
+ return new ij.macro.Variable(getResultString(getRT(null)));
+ else if (name.equals("set"))
+ return setTableValue();
+ else if (name.equals("setColumn"))
+ return setTableColumn();
+ else if (name.equals("reset"))
+ return resetTable();
+ else if (name.equals("update"))
+ return updateTable();
+ else if (name.equals("applyMacro"))
+ return applyMacroToTable();
+ else if (name.equals("deleteRows"))
+ return deleteRows();
+ else if (name.equals("deleteColumn"))
+ return deleteColumn();
+ else if (name.equals("renameColumn"))
+ return renameColumn();
+ else if (name.equals("save"))
+ return saveTable();
+ else if (name.equals("open"))
+ return openTable();
+ else if (name.equals("title"))
+ return new ij.macro.Variable(getResultsTable(getTitleArg()).getTitle());
+ else if (name.equals("headings"))
+ return new ij.macro.Variable(getResultsTable(getTitleArg()).getColumnHeadings());
+ else if (name.equals("allHeadings"))
+ return getAllHeadings();
+ else if (name.equals("showRowNumbers"))
+ return showRowNumbers(true);
+ else if (name.equals("showRowIndexes"))
+ return showRowNumbers(false);
+ else if (name.startsWith("saveColumnHeader"))
+ return saveColumnHeaders();
+ else if (name.equals("sort"))
+ return sortTable();
+ else if (name.equals("hideRowNumbers")) {
+ getResultsTable(getTitleArg()).showRowNumbers(false);
+ return null;
+ } else if (name.equals("rename")) {
+ renameResults();
+ return null;
+ } else if (name.startsWith("showArray")) {
+ showArray();
+ return null;
+ } else if (name.equals("getSelectionStart"))
+ return getSelectionStart();
+ else if (name.equals("getSelectionEnd"))
+ return getSelectionEnd();
+ else if (name.equals("setSelection"))
+ return setSelection();
+ else if (name.equals("setLocAndSize") || name.equals("setLocationAndSize"))
+ return setTableLocAndSize();
+ else if (name.equals("showHistogramTable") || name.equals("list"))
+ return tableList();
+ else
+ interp.error("Unrecognized function name");
+ return null;
+ }
+
+ private ij.macro.Variable tableList() {
+ ImagePlus img = WindowManager.getCurrentImage();
+ boolean isHistogram = false;
+ if (img!=null) {
+ ImageWindow win = img.getWindow();
+ if (win!=null && win instanceof HistogramWindow) {
+ ((HistogramWindow)win).showList();
+ isHistogram = true;
+ }
+ }
+ if (!isHistogram)
+ interp.error("No histogram window");
+ return null;
+ }
+
+ private ij.macro.Variable setTableLocAndSize() {
+ double x = getFirstArg();
+ double y = getNextArg();
+ double width = getNextArg();
+ double height = getNextArg();
+ String title = getTitle();
+ if (title==null) {
+ ResultsTable rt = getResultsTable(title);
+ title = rt.getTitle();
+ }
+ Frame frame = WindowManager.getFrame(title);
+ if (frame!=null) {
+ Point loc = frame.getLocation();
+ Dimension size = frame.getSize();
+ frame.setLocation(Double.isNaN(x)?loc.x:(int)x, Double.isNaN(y)?loc.y:(int)y);
+ frame.setSize(Double.isNaN(width)?size.width:(int)width, Double.isNaN(height)?size.height:(int)height);
+ }
+ return null;
+ }
+
+ private ij.macro.Variable setSelection() {
+ interp.getLeftParen();
+ double from = interp.getExpression();
+ interp.getComma();
+ double to = interp.getExpression();
+ ResultsTable rt = getResultsTable(getTitle());
+ String title = rt.getTitle();
+ Frame f = WindowManager.getFrame(title);
+ if (f!=null && (f instanceof TextWindow)){
+ TextWindow tWin = (TextWindow)f;
+ if (from == -1 && to == -1)
+ tWin.getTextPanel().resetSelection();
+ else
+ tWin.getTextPanel().setSelection((int)from, (int)to);
+ return null;
+ }
+ interp.error("\""+title+"\" table not found");
+ return null;
+ }
+
+ private ij.macro.Variable getSelectionStart() {
+ int selStart = -1;
+ ResultsTable rt = getResultsTable(getTitleArg());
+ String title = rt.getTitle();
+ Frame f = WindowManager.getFrame(title);
+ if (f!=null && (f instanceof TextWindow)){
+ TextWindow tWin = (TextWindow)f;
+ selStart = tWin.getTextPanel().getSelectionStart();
+ return new ij.macro.Variable(selStart);
+ }
+ return new ij.macro.Variable(selStart);
+ }
+
+ private ij.macro.Variable getSelectionEnd() {
+ int selEnd = -1;
+ ResultsTable rt = getResultsTable(getTitleArg());
+ String title = rt.getTitle();
+ Frame f = WindowManager.getFrame(title);
+ if (f!=null && (f instanceof TextWindow)){
+ TextWindow tWin = (TextWindow)f;
+ selEnd = tWin.getTextPanel().getSelectionEnd();
+ return new ij.macro.Variable(selEnd);
+ }
+ interp.error("\""+title+"\" table not found");
+ return new ij.macro.Variable(selEnd);
+ }
+
+ private ij.macro.Variable setTableValue() {
+ ResultsTable rt = getRT(null);
+ setResult(rt);
+ return null;
+ }
+
+ private ij.macro.Variable setTableColumn() {
+ String column = getFirstString();
+ ij.macro.Variable[] array = new ij.macro.Variable[0];
+ if (interp.nextToken()!=')') {
+ interp.getComma();
+ array = getArray();
+ }
+ ResultsTable rt = getResultsTable(getTitle());
+ rt.setColumn(column, array);
+ rt.show(rt.getTitle());
+ return null;
+ }
+
+ private ij.macro.Variable updateTable() {
+ String title = getTitleArg();
+ ResultsTable rt = getResultsTable(title);
+ rt.show(rt.getTitle());
+ unUpdatedTable = null;
+ if (rt==Analyzer.getResultsTable())
+ resultsPending = false;
+ return null;
+ }
+
+ private ij.macro.Variable resetTable() {
+ String title = getTitleArg();
+ ResultsTable rt = null;
+ if ("Results".equals(title)) {
+ rt = Analyzer.getResultsTable();
+ rt.showRowNumbers(false);
+ rt.reset();
+ rt.show("Results");
+ toFront("Results");
+ return null;
+ }
+ if (getRT(title)==null) {
+ rt = new ResultsTable();
+ rt.show(title);
+ waitUntilActivated(title);
+ } else {
+ rt = getResultsTable(title);
+ rt.reset();
+ toFront(title);
+ if (rt==Analyzer.getResultsTable())
+ resultsPending = true;
+ }
+ return null;
+ }
+
+ private void waitUntilActivated(String title) {
+ long start = System.currentTimeMillis();
+ while (true) {
+ IJ.wait(5);
+ Frame frame = WindowManager.getFrontWindow();
+ String title2 = frame!=null?frame.getTitle():null;
+ if (title.equals(title2))
+ return;
+ if ((System.currentTimeMillis()-start)>200)
+ break;
+ }
+ }
+
+
+ private void toFront(String title) {
+ if (title==null)
+ return;
+ Frame frame = WindowManager.getFrame(title);
+ if (frame!=null) {
+ frame.toFront();
+ WindowManager.setWindow(frame);
+ }
+ }
+
+ private ij.macro.Variable applyMacroToTable() {
+ String macro = getFirstString();
+ String title = getTitle();
+ if (macro.equals("Results")) {
+ macro = title;
+ title = "Results";
+ }
+ ResultsTable rt = getResultsTable(title);
+ rt.applyMacro(macro);
+ rt.show(rt.getTitle());
+ return null;
+ }
+
+ private ij.macro.Variable deleteRows() {
+ int row1 = (int)getFirstArg();
+ int row2 = (int)getNextArg();
+ String title = getTitle();
+ ResultsTable rt = getResultsTable(title);
+ int tableSize = rt.size();
+ rt.deleteRows(row1, row2);
+ ImagePlus imp = WindowManager.getCurrentImage();
+ if (imp!=null)
+ Overlay.updateTableOverlay(imp, row1, row2, tableSize);
+ rt.show(rt.getTitle());
+ return null;
+ }
+
+ private ij.macro.Variable deleteColumn() {
+ String column = getFirstString();
+ String title = getTitle();
+ ResultsTable rt = getResultsTable(title);
+ try {
+ rt.deleteColumn(column);
+ unUpdatedTable = rt;
+ } catch (Exception e) {
+ interp.error(e.getMessage());
+ }
+ return null;
+ }
+
+ private ij.macro.Variable getColumn() {
+ String col = getFirstString();
+ ResultsTable rt = getResultsTable(getTitle());
+ ij.macro.Variable column = null;
+ try {
+ column = new ij.macro.Variable(rt.getColumnAsVariables(col));
+ } catch (Exception e) {
+ interp.error(e.getMessage());
+ }
+ return column;
+ }
+
+ private ij.macro.Variable columnExists() {
+ String col = getFirstString();
+ ResultsTable rt = getResultsTable(getTitle());
+ return new ij.macro.Variable(rt.columnExists(col)?1:0);
+ }
+
+ private ij.macro.Variable renameColumn() {
+ String oldName = getFirstString();
+ String newName = getNextString();
+ String title = getTitle();
+ ResultsTable rt = getResultsTable(title);
+ try {
+ rt.renameColumn(oldName, newName);
+ unUpdatedTable = rt;
+ } catch (Exception e) {
+ interp.error(e.getMessage());
+ }
+ return null;
+ }
+
+ private ij.macro.Variable showRowNumbers(boolean numbers) {
+ boolean show = (int)getFirstArg()!=0;
+ ResultsTable rt = getResultsTable(getTitle());
+ if (numbers)
+ rt.showRowNumbers(show);
+ else
+ rt.showRowIndexes(show);
+ unUpdatedTable = rt;
+ return null;
+ }
+
+ private ij.macro.Variable saveColumnHeaders() {
+ boolean save = (int)getFirstArg()!=0;
+ ResultsTable rt = getResultsTable(getTitle());
+ rt.saveColumnHeaders(save);
+ unUpdatedTable = rt;
+ return null;
+ }
+
+ private ij.macro.Variable sortTable() {
+ String column = getFirstString();
+ ResultsTable rt = getResultsTable(getTitle());
+ try {
+ rt.sort(column);
+ } catch (Exception e) {
+ interp.error(e.getMessage());
+ }
+ rt.show(rt.getTitle());
+ return null;
+ }
+
+ private ij.macro.Variable saveTable() {
+ String path = getFirstString();
+ ResultsTable rt = getResultsTable(getTitle());
+ try {
+ rt.saveAs(path);
+ } catch (Exception e) {
+ String msg = e.getMessage();
+ if (msg!=null && !msg.startsWith("Macro canceled"))
+ interp.error(msg);
+ }
+ return null;
+ }
+
+ private ij.macro.Variable openTable() {
+ String path = getFirstString();
+ String title = getTitle();
+ if (title==null)
+ title = new File(path).getName();
+ ResultsTable rt = null;
+ try {
+ rt = rt.open(path);
+ } catch (Exception e) {
+ String msg = e.getMessage();
+ if (!msg.startsWith("Macro canceled"))
+ interp.error(msg);
+ }
+ rt.show(title);
+ return null;
+ }
+
+ private ij.macro.Variable getAllHeadings() {
+ interp.getParens();
+ String[] headings = ResultsTable.getDefaultHeadings();
+ StringBuilder sb = new StringBuilder(250);
+ for (int i=0; i255) r=255; if (g>255) g=255; if (b>255) b=255;
+ return new Color(r, g, b);
+ }
+ }
+
+ private void getContainedPoints(Roi roi) {
+ ij.macro.Variable xCoordinates = getFirstArrayVariable();
+ ij.macro.Variable yCoordinates = getLastArrayVariable();
+ FloatPolygon points = roi.getContainedFloatPoints();
+ ij.macro.Variable[] xa = new ij.macro.Variable[points.npoints];
+ ij.macro.Variable[] ya = new ij.macro.Variable[points.npoints];
+ for (int i=0; iRoi.MAX_ROI_GROUP)
+ interp.error("Group out of range");
+ rm.setGroup(group);
+ return null;
+ } else if (name.equals("selectGroup")) {
+ rm.selectGroup((int)getArg());
+ return null;
+ } else if (name.equals("selectPosition")) {
+ rm.selectPosition((int)getFirstArg(),(int)getNextArg(),(int)getLastArg());
+ return null;
+ } else if (name.equals("getName")) {
+ String roiName = rm.getName((int)getArg());
+ return new ij.macro.Variable(roiName!=null?roiName:"");
+ } else if (name.equals("getIndex")) {
+ return new ij.macro.Variable(rm.getIndex(getStringArg()));
+ } else if (name.equals("setPosition")) {
+ setRoiManagerPosition(rm);
+ return null;
+ } else if (name.equals("multiCrop")) {
+ rm.multiCrop(getFirstString(),getLastString());
+ return null;
+ } else if (name.equals("scale")) {
+ rm.scale(getFirstArg(),getNextArg(), getLastArg()==1?true:false);
+ return null;
+ } else if (name.equals("rotate")) {
+ double angle = getFirstArg();
+ if (interp.nextToken()==')') {
+ interp.getRightParen();
+ rm.rotate(angle);
+ } else
+ rm.rotate(angle, getNextArg(), getLastArg());
+ return null;
+ } else if (name.equals("translate")) {
+ rm.translate(getFirstArg(),getLastArg());
+ return null;
+ } else if (name.equals("delete")) {
+ rm.delete((int)getArg());
+ return null;
+ } else
+ interp.error("Unrecognized RoiManager function");
+ return null;
+ }
+
+ private void setRoiManagerPosition(RoiManager rm) {
+ int channel = (int)getFirstArg();
+ if (interp.nextToken()==')') {
+ interp.getRightParen();
+ rm.setPosition(channel);
+ return;
+ }
+ int slice = (int)getNextArg();
+ int frame = (int)getLastArg();
+ rm.setPosition(channel, slice, frame);
+ }
+
+ private ij.macro.Variable doProperty() {
+ interp.getToken();
+ if (interp.token!='.')
+ interp.error("'.' expected");
+ interp.getToken();
+ if (!(interp.token==WORD||interp.token==STRING_FUNCTION||interp.token==NUMERIC_FUNCTION||interp.token==ARRAY_FUNCTION))
+ interp.error("Function name expected: ");
+ String name = interp.tokenString;
+ ImagePlus imp = getImage();
+ if (name.equals("set")) {
+ String key = getFirstString();
+ String value = getLastString();
+ if (value.length()==0) value = null;
+ imp.setProp(key, value);
+ return null;
+ } else if (name.equals("get")) {
+ String value = imp.getProp(getStringArg());
+ return new ij.macro.Variable(value!=null?value:"");
+ } else if (name.equals("getNumber") || name.equals("getValue")) {
+ String svalue = imp.getProp(getStringArg());
+ double nvalue = svalue!=null?Tools.parseDouble(svalue):Double.NaN;
+ return new ij.macro.Variable(nvalue);
+ } else if (name.equals("getInfo")) {
+ interp.getParens();
+ String value = (String)imp.getProperty("Info");
+ return new ij.macro.Variable(value!=null?value:"");
+ } else if (name.equals("setInfo")) {
+ imp.setProperty("Info", getStringArg());
+ return null;
+ } else if (name.equals("getSliceLabel")) {
+ String label = imp.getStack().getSliceLabel(imp.getCurrentSlice());
+ if (interp.nextToken()=='(') {
+ if (interp.nextNextToken()==')')
+ interp.getParens();
+ else
+ label = imp.getStack().getSliceLabel((int)getArg());
+ }
+ ij.macro.Variable v = new ij.macro.Variable(label!=null?label:"");
+ return v;
+ } else if (name.equals("setSliceLabel")) {
+ String label = getFirstString();
+ int slice = imp.getCurrentSlice();
+ if (interp.nextToken()==',')
+ slice = (int)getLastArg();
+ else
+ interp.getRightParen();
+ if (slice<1 || slice>imp.getStackSize())
+ interp.error("Argument must be >=1 and <="+imp.getStackSize());
+ imp.getStack().setSliceLabel(label, slice);
+ if (!ij.macro.Interpreter.isBatchMode()) imp.repaintWindow();
+ return null;
+ } else if (name.equals("getDicomTag")) {
+ String value = imp.getStringProperty(getStringArg());
+ return new ij.macro.Variable(value!=null?value:"");
+ } else if (name.equals("setList")) {
+ setPropertiesFromString(imp.getImageProperties());
+ return null;
+ } else if (name.equals("getList")) {
+ return new ij.macro.Variable(getPropertiesAsString(imp.getImageProperties()));
+ } else
+ interp.error("Unrecognized Property function");
+ return null;
+ }
+
+ private void setPropertiesFromString(Properties props) {
+ String list = getStringArg();
+ props.clear();
+ try {
+ InputStream is = new ByteArrayInputStream(list.getBytes("utf-8"));
+ props.load(is);
+ } catch(Exception e) {
+ interp.error(""+e);
+ }
+ }
+
+ private String getPropertiesAsString(Properties props) {
+ interp.getParens();
+ Vector v = new Vector();
+ for (Enumeration en=props.keys(); en.hasMoreElements();)
+ v.addElement(en.nextElement());
+ String[] keys = new String[v.size()];
+ for (int i=0; i>16);
+ array[1] = new ij.macro.Variable((rgb&0xff00)>>8);
+ array[2] = new ij.macro.Variable(rgb&0xff);
+ return new ij.macro.Variable(array);
+ } else if (name.equals("setLut")) {
+ setLut();
+ return null;
+ } else if (name.equals("getLut")) {
+ getLut();
+ return null;
+ } else if (name.equals("wavelengthToColor")) {
+ Color c = Colors.wavelengthToColor(getArg());
+ return new ij.macro.Variable(Colors.colorToString(c));
+ } else
+ interp.error("Unrecognized Color function");
+ return null;
+ }
+
+ private ij.macro.Variable setForegroundOrBackground(boolean foreground) {
+ interp.getLeftParen();
+ Color color = null;
+ if (isStringArg()) {
+ String arg = getString();
+ interp.getRightParen();
+ color = Colors.decode(arg, Color.black);
+ } else {
+ int red = (int)interp.getExpression();
+ int green = (int)getNextArg();
+ int blue = (int)getLastArg();
+ color = Colors.toColor(red, green, blue);
+ }
+ if (foreground)
+ Toolbar.setForegroundColor(color);
+ else
+ Toolbar.setBackgroundColor(color);
+ return null;
+ }
+
+} // class Functions
diff --git a/mrj/26/ij/plugin/Commands.java b/mrj/26/ij/plugin/Commands.java
new file mode 100644
index 00000000..9c24b759
--- /dev/null
+++ b/mrj/26/ij/plugin/Commands.java
@@ -0,0 +1,182 @@
+package ij.plugin;
+
+import java.awt.Window;
+import java.io.File;
+
+import ij.IJ;
+import ij.ImageJ;
+import ij.ImagePlus;
+import ij.Prefs;
+import ij.Undo;
+import ij.WindowManager;
+import ij.gui.GenericDialog;
+import ij.gui.ImageWindow;
+import ij.gui.NewImage;
+import ij.io.FileSaver;
+import ij.io.Opener;
+import ij.macro.Interpreter;
+import ij.plugin.frame.*;
+import ij.stub.Applet;
+import ij.text.TextWindow;
+
+/** Runs miscellaneous File and Window menu commands. */
+public class Commands implements ij.plugin.PlugIn {
+
+ public void run(String cmd) {
+ if (cmd.equals("new")) {
+ if (IJ.altKeyDown())
+ IJ.runPlugIn("ij.plugin.HyperStackMaker", "");
+ else
+ new NewImage();
+ } else if (cmd.equals("open")) {
+ if (Prefs.useJFileChooser && !IJ.macroRunning())
+ new Opener().openMultiple();
+ else
+ new Opener().open();
+ } else if (cmd.equals("close"))
+ close();
+ else if (cmd.equals("close-all"))
+ closeAll();
+ else if (cmd.equals("save"))
+ save();
+ else if (cmd.equals("revert"))
+ revert();
+ else if (cmd.equals("undo"))
+ undo();
+ else if (cmd.equals("ij")) {
+ ImageJ ij = IJ.getInstance();
+ if (ij!=null) ij.toFront();
+ } else if (cmd.equals("tab"))
+ WindowManager.putBehind();
+ else if (cmd.equals("quit")) {
+ ImageJ ij = IJ.getInstance();
+ if (ij!=null) ij.quit();
+ } else if (cmd.equals("startup"))
+ openStartupMacros();
+ }
+
+ void revert() {
+ ImagePlus imp = WindowManager.getCurrentImage();
+ if (imp!=null)
+ imp.revert();
+ else
+ IJ.noImage();
+ }
+
+ void save() {
+ ImagePlus imp = WindowManager.getCurrentImage();
+ if (imp!=null) {
+ if (imp.getStackSize()>1) {
+ imp.setIgnoreFlush(true);
+ new FileSaver(imp).save();
+ imp.setIgnoreFlush(false);
+ } else
+ new FileSaver(imp).save();
+ } else
+ IJ.noImage();
+ }
+
+ void undo() {
+ ImagePlus imp = WindowManager.getCurrentImage();
+ if (imp!=null)
+ Undo.undo();
+ else
+ IJ.noImage();
+ }
+
+ void close() {
+ ImagePlus imp = WindowManager.getCurrentImage();
+ Window win = WindowManager.getActiveWindow();
+ if (win==null || (Interpreter.isBatchMode() && win instanceof ImageWindow))
+ closeImage(imp);
+ else if (win instanceof PlugInFrame && !"Commands".equals(((PlugInFrame)win).getTitle()))
+ ((PlugInFrame)win).close();
+ else if (win instanceof PlugInDialog)
+ ((PlugInDialog)win).close();
+ else if (win instanceof TextWindow)
+ ((TextWindow)win).close();
+ else
+ closeImage(imp);
+ }
+
+ /** Closes all image windows, or returns 'false' if the user cancels the unsaved changes dialog box. */
+ public static boolean closeAll() {
+ int[] list = WindowManager.getIDList();
+ if (list!=null) {
+ int imagesWithChanges = 0;
+ for (int i=0; i0 && !IJ.macroRunning()) {
+ GenericDialog gd = new GenericDialog("Close All");
+ String msg = null;
+ String pronoun = null;
+ if (imagesWithChanges==1) {
+ msg = "There is one image";
+ pronoun = "It";
+ } else {
+ msg = "There are "+imagesWithChanges+" images";
+ pronoun = "They";
+ }
+ gd.addMessage(msg+" with unsaved changes. "+pronoun
+ +" will\nbe closed without being saved if you click \"OK\".");
+ gd.showDialog();
+ if (gd.wasCanceled())
+ return false;
+ }
+ Prefs.closingAll = true;
+ for (int i=0; iMacros>Open Startup Macros command
+ void openStartupMacros() {
+ Applet applet = IJ.getApplet();
+ if (applet!=null)
+ IJ.run("URL...", "url="+IJ.URL2+"/applet/StartupMacros.txt");
+ else {
+ String path = IJ.getDirectory("macros")+"StartupMacros.txt";
+ File f = new File(path);
+ if (!f.exists()) {
+ path = IJ.getDirectory("macros")+"StartupMacros.ijm";
+ f = new File(path);
+ }
+ if (!f.exists()) {
+ path = IJ.getDirectory("macros")+"StartupMacros.fiji.ijm";
+ f = new File(path);
+ }
+ if (!f.exists())
+ IJ.error("\"StartupMacros.txt\" not found in ImageJ/macros/");
+ else
+ IJ.open(path);
+ }
+ }
+
+}
+
+
+
diff --git a/mrj/26/ij/plugin/Converter.java b/mrj/26/ij/plugin/Converter.java
new file mode 100644
index 00000000..f18569a9
--- /dev/null
+++ b/mrj/26/ij/plugin/Converter.java
@@ -0,0 +1,214 @@
+package ij.plugin;
+
+import ij.IJ;
+import ij.ImagePlus;
+import ij.ImageStack;
+import ij.Macro;
+import ij.Menus;
+import ij.Undo;
+import ij.WindowManager;
+import ij.gui.GenericDialog;
+import ij.gui.ImageWindow;
+import ij.gui.Roi;
+import ij.process.ImageConverter;
+import ij.process.ImageProcessor;
+import ij.process.LUT;
+import ij.process.StackConverter;
+
+/** Implements the conversion commands in the Image/Type submenu. */
+public class Converter implements ij.plugin.PlugIn {
+
+ /** obsolete */
+ public static boolean newWindowCreated;
+ private ImagePlus imp;
+
+ public void run(String arg) {
+ imp = WindowManager.getCurrentImage();
+ if (imp!=null) {
+ if ("RGB Color".equals(arg))
+ imp.setProp(LUT.nameKey,null);
+ if (imp.isComposite() && arg.equals("RGB Color") && !imp.getStack().isRGB() && !imp.getStack().isHSB() && !imp.getStack().isLab()) {
+ if (imp.getWindow()==null && !ij.macro.Interpreter.isBatchMode())
+ ij.plugin.RGBStackConverter.convertToRGB(imp);
+ else {
+ (new ij.plugin.RGBStackConverter()).run("");
+ imp.setTitle(imp.getTitle()); // updates size in Window menu
+ }
+ } else if (imp.isComposite() && imp.getNChannels()>1 && imp.getNChannels()==imp.getStackSize() && arg.equals("RGB Stack")) {
+ convertCompositeToRGBStack(imp);
+ } else if (imp.lock()) {
+ convert(arg);
+ imp.unlock();
+ imp.setTitle(imp.getTitle());
+ } else
+ IJ.log("<>");
+ } else
+ IJ.noImage();
+ }
+
+ /** Converts the ImagePlus to the specified image type. The string
+ argument corresponds to one of the labels in the Image/Type submenu
+ ("8-bit", "16-bit", "32-bit", "8-bit Color", "RGB Color", "RGB Stack", "HSB Stack", "Lab Stack" or "HSB (32-bit)"). */
+ public void convert(String item) {
+ int type = imp.getType();
+ ImageStack stack = null;
+ if (imp.getStackSize()>1)
+ stack = imp.getStack();
+ String msg = "Converting to " + item;
+ IJ.showStatus(msg + "...");
+ long start = System.currentTimeMillis();
+ Roi roi = imp.getRoi();
+ imp.deleteRoi();
+ if (imp.isThreshold())
+ imp.getProcessor().resetThreshold();
+ boolean saveChanges = imp.changes;
+ imp.changes = IJ.getApplet()==null; //if not applet, set 'changes' flag
+ ImageWindow win = imp.getWindow();
+ try {
+ if (stack!=null) {
+ boolean wasVirtual = stack.isVirtual();
+ // do stack conversions
+ if (stack.isRGB() && item.equals("RGB Color")) {
+ new ImageConverter(imp).convertRGBStackToRGB();
+ if (win!=null) new ImageWindow(imp, imp.getCanvas()); // replace StackWindow with ImageWindow
+ } else if (stack.isHSB() && item.equals("RGB Color")) {
+ new ImageConverter(imp).convertHSBToRGB();
+ if (win!=null) new ImageWindow(imp, imp.getCanvas());
+ } else if (stack.isHSB32() && item.equals("RGB Color")) {
+ new ImageConverter(imp).convertHSB32ToRGB();
+ if (win!=null) new ImageWindow(imp, imp.getCanvas());
+ } else if (stack.isLab() && item.equals("RGB Color")) {
+ new ImageConverter(imp).convertLabToRGB();
+ if (win!=null) new ImageWindow(imp, imp.getCanvas());
+ } else if (item.equals("8-bit"))
+ new StackConverter(imp).convertToGray8();
+ else if (item.equals("16-bit"))
+ new StackConverter(imp).convertToGray16();
+ else if (item.equals("32-bit"))
+ new ImageConverter(imp).convertToGray32();
+ else if (item.equals("RGB Color"))
+ new StackConverter(imp).convertToRGB();
+ else if (item.equals("RGB Stack"))
+ new StackConverter(imp).convertToRGBHyperstack();
+ else if (item.equals("HSB Stack"))
+ new StackConverter(imp).convertToHSBHyperstack();
+ else if (item.equals("HSB (32-bit)"))
+ new StackConverter(imp).convertToHSB32Hyperstack();
+ else if (item.equals("Lab Stack"))
+ new StackConverter(imp).convertToLabHyperstack();
+ else if (item.equals("8-bit Color")) {
+ int nColors = getNumber();
+ if (nColors!=0)
+ new StackConverter(imp).convertToIndexedColor(nColors);
+ } else throw new IllegalArgumentException();
+ if (wasVirtual) imp.setTitle(imp.getTitle());
+ } else {
+ // do single image conversions
+ Undo.setup(Undo.TYPE_CONVERSION, imp);
+ ImageConverter ic = new ImageConverter(imp);
+ if (item.equals("8-bit"))
+ ic.convertToGray8();
+ else if (item.equals("16-bit"))
+ ic.convertToGray16();
+ else if (item.equals("32-bit"))
+ ic.convertToGray32();
+ else if (item.equals("RGB Stack")) {
+ Undo.reset(); // Reversible; no need for Undo
+ ic.convertToRGBStack();
+ } else if (item.equals("HSB Stack")) {
+ Undo.reset();
+ ic.convertToHSB();
+ } else if (item.equals("HSB (32-bit)")) {
+ Undo.reset();
+ ic.convertToHSB32();
+ } else if (item.equals("Lab Stack")) {
+ Undo.reset();
+ ic.convertToLab();
+ } else if (item.equals("RGB Color")) {
+ ic.convertToRGB();
+ } else if (item.equals("8-bit Color")) {
+ int nColors = getNumber();
+ start = System.currentTimeMillis();
+ if (nColors!=0)
+ ic.convertRGBtoIndexedColor(nColors);
+ } else {
+ imp.changes = saveChanges;
+ return;
+ }
+ IJ.showProgress(1.0);
+ }
+ if ("RGB Color".equals(item))
+ imp.setProp(LUT.nameKey,null);
+ }
+ catch (IllegalArgumentException e) {
+ unsupportedConversion(imp);
+ IJ.showStatus("");
+ Undo.reset();
+ imp.changes = saveChanges;
+ Menus.updateMenus();
+ Macro.abort();
+ return;
+ }
+ if (roi!=null)
+ imp.setRoi(roi);
+ IJ.showTime(imp, start, "");
+ imp.repaintWindow();
+ Menus.updateMenus();
+ }
+
+ void unsupportedConversion(ImagePlus imp) {
+ IJ.error("Converter",
+ "Supported Conversions:\n" +
+ " \n" +
+ "8-bit -> 16-bit*\n" +
+ "8-bit -> 32-bit*\n" +
+ "8-bit -> RGB Color*\n" +
+ "16-bit -> 8-bit*\n" +
+ "16-bit -> 32-bit*\n" +
+ "16-bit -> RGB Color*\n" +
+ "32-bit -> 8-bit*\n" +
+ "32-bit -> 16-bit\n" +
+ "32-bit -> RGB Color*\n" +
+ "8-bit Color -> 8-bit (grayscale)*\n" +
+ "8-bit Color -> RGB Color\n" +
+ "RGB -> 8-bit (grayscale)*\n" +
+ "RGB -> 8-bit Color*\n" +
+ "RGB -> RGB Stack*\n" +
+ "RGB -> HSB Stack*\n" +
+ "RGB -> Lab Stack\n" +
+ "RGB Stack -> RGB Color\n" +
+ "HSB Stack -> RGB Color\n" +
+ " \n" +
+ "* works with stacks\n"
+ );
+ }
+
+ int getNumber() {
+ if (imp.getType()!=ImagePlus.COLOR_RGB)
+ return 256;
+ GenericDialog gd = new GenericDialog("MedianCut");
+ gd.addNumericField("Number of Colors (2-256):", 256, 0);
+ gd.showDialog();
+ if (gd.wasCanceled())
+ return 0;
+ int n = (int)gd.getNextNumber();
+ if (n<2) n = 2;
+ if (n>256) n = 256;
+ return n;
+ }
+
+ private void convertCompositeToRGBStack(ImagePlus imp) {
+ imp.setDisplayMode(IJ.COLOR);
+ if (imp.getNChannels()!=imp.getStackSize())
+ IJ.run(imp, "Reduce Dimensionality...", "channels");
+ ImagePlus[] channels = ij.plugin.ChannelSplitter.split(imp);
+ ImageStack stack = new ImageStack();
+ for (int i=0; i
+ DICOM dcm = new DICOM(is);
+ dcm.run("Name");
+ dcm.show();
+
+ */
+ public DICOM(InputStream is) {
+ this(new BufferedInputStream(is));
+ }
+
+ /** Constructs a DICOM reader that using an BufferredInputStream. */
+ public DICOM(BufferedInputStream bis) {
+ inputStream = bis;
+ }
+
+ public void run(String arg) {
+ OpenDialog od = new OpenDialog("Open Dicom...", arg);
+ String directory = od.getDirectory();
+ String fileName = od.getFileName();
+ if (fileName==null)
+ return;
+ DicomDecoder dd = new DicomDecoder(directory, fileName);
+ dd.inputStream = inputStream;
+ FileInfo fi = null;
+ try {
+ fi = dd.getFileInfo();
+ } catch (IOException e) {
+ String msg = e.getMessage();
+ IJ.showStatus("");
+ if (msg.indexOf("EOF")<0&&showErrors) {
+ IJ.error("DICOM Reader", e.getClass().getName()+"\n \n"+msg);
+ return;
+ } else if (!dd.dicmFound()&&showErrors) {
+ msg = "This does not appear to be a valid\n"
+ + "DICOM file. It does not have the\n"
+ + "characters 'DICM' at offset 128.";
+ IJ.error("DICOM Reader", msg);
+ return;
+ }
+ }
+ if (gettingInfo) {
+ info = dd.getDicomInfo();
+ return;
+ }
+ if (fi!=null && fi.width>0 && fi.height>0 && fi.offset>0) {
+ FileOpener fo = new FileOpener(fi);
+ ImagePlus imp = fo.openImage();
+ // Avoid opening as float even if slope != 1.0 in case ignoreRescaleSlope or fixedDicomScaling
+ // were checked in the DICOM preferences.
+ boolean openAsFloat = (dd.rescaleSlope!=1.0 && !(Prefs.ignoreRescaleSlope || Prefs.fixedDicomScaling))
+ || Prefs.openDicomsAsFloat;
+ String options = Macro.getOptions();
+ if (openAsFloat) {
+ IJ.run(imp, "32-bit", "");
+ if (dd.rescaleSlope!=1.0)
+ IJ.run(imp, "Multiply...", "value="+dd.rescaleSlope+" stack");
+ if (dd.rescaleIntercept!=0.0)
+ IJ.run(imp, "Add...", "value="+dd.rescaleIntercept+" stack");
+ if (imp.getStackSize()>1) {
+ imp.setSlice(imp.getStackSize()/2);
+ ImageStatistics stats = imp.getRawStatistics();
+ imp.setDisplayRange(stats.min,stats.max);
+ }
+ } else if (fi.fileType==FileInfo.GRAY16_SIGNED) {
+ if (dd.rescaleIntercept!=0.0 && (dd.rescaleSlope==1.0||Prefs.fixedDicomScaling)) {
+ double[] coeff = new double[2];
+ coeff[0] = dd.rescaleSlope*(-32768) + dd.rescaleIntercept;
+ coeff[1] = dd.rescaleSlope;
+ imp.getCalibration().setFunction(Calibration.STRAIGHT_LINE, coeff, "Gray Value");
+ }
+ } else if (dd.rescaleIntercept!=0.0 &&
+ (dd.rescaleSlope==1.0||Prefs.fixedDicomScaling||fi.fileType==FileInfo.GRAY8)) {
+ double[] coeff = new double[2];
+ coeff[0] = dd.rescaleIntercept;
+ coeff[1] = dd.rescaleSlope;
+ imp.getCalibration().setFunction(Calibration.STRAIGHT_LINE, coeff, "Gray Value");
+ }
+ Macro.setOptions(options);
+ if (dd.windowWidth>0.0) {
+ double min = dd.windowCenter-dd.windowWidth/2;
+ double max = dd.windowCenter+dd.windowWidth/2;
+ if (!openAsFloat) {
+ Calibration cal = imp.getCalibration();
+ min = cal.getRawValue(min);
+ max = cal.getRawValue(max);
+ }
+ ImageProcessor ip = imp.getProcessor();
+ ip.setMinAndMax(min, max);
+ if (IJ.debugMode) IJ.log("window: "+min+"-"+max);
+ }
+ if (imp.getStackSize()>1)
+ setStack(fileName, imp.getStack());
+ else
+ setProcessor(fileName, imp.getProcessor());
+ setCalibration(imp.getCalibration());
+ setProperty("Info", dd.getDicomInfo());
+ setFileInfo(fi); // needed for revert
+ if (arg.equals("")) show();
+ } else if (showErrors)
+ IJ.error("DICOM Reader","Unable to decode DICOM header.");
+ IJ.showStatus("");
+ }
+
+ /** Opens the specified file as a DICOM. Does not
+ display a message if there is an error.
+ Here is an example:
+
+ DICOM dcm = new DICOM();
+ dcm.open(path);
+ if (dcm.getWidth()==0)
+ IJ.log("Error opening '"+path+"'");
+ else
+ dcm.show();
+
+ */
+ public void open(String path) {
+ showErrors = false;
+ run(path);
+ }
+
+ /** Returns the DICOM tags of the specified file as a string. */
+ public String getInfo(String path) {
+ showErrors = false;
+ gettingInfo = true;
+ run(path);
+ return info;
+ }
+
+ /** Convert 16-bit signed to unsigned if all pixels>=0. */
+ void convertToUnsigned(ImagePlus imp, FileInfo fi) {
+ ImageProcessor ip = imp.getProcessor();
+ short[] pixels = (short[])ip.getPixels();
+ int min = Integer.MAX_VALUE;
+ int value;
+ for (int i=0; i=32768) {
+ for (int i=0; i60)
+ s = s.substring(0,60);
+ return s;
+ }
+
+ int getByte() throws IOException {
+ int b = f.read();
+ if (b ==-1)
+ throw new IOException("unexpected EOF");
+ ++location;
+ return b;
+ }
+
+ int getShort() throws IOException {
+ int b0 = getByte();
+ int b1 = getByte();
+ if (littleEndian)
+ return ((b1 << 8) + b0);
+ else
+ return ((b0 << 8) + b1);
+ }
+
+ int getSShort() throws IOException {
+ short b0 = (short)getByte();
+ short b1 = (short)getByte();
+ if (littleEndian)
+ return ((b1 << 8) + b0);
+ else
+ return ((b0 << 8) + b1);
+ }
+
+ final int getInt() throws IOException {
+ int b0 = getByte();
+ int b1 = getByte();
+ int b2 = getByte();
+ int b3 = getByte();
+ if (littleEndian)
+ return ((b3<<24) + (b2<<16) + (b1<<8) + b0);
+ else
+ return ((b0<<24) + (b1<<16) + (b2<<8) + b3);
+ }
+
+ long getUInt() throws IOException {
+ long b0 = getByte();
+ long b1 = getByte();
+ long b2 = getByte();
+ long b3 = getByte();
+ if (littleEndian)
+ return ((b3<<24) + (b2<<16) + (b1<<8) + b0);
+ else
+ return ((b0<<24) + (b1<<16) + (b2<<8) + b3);
+ }
+
+ double getDouble() throws IOException {
+ int b0 = getByte();
+ int b1 = getByte();
+ int b2 = getByte();
+ int b3 = getByte();
+ int b4 = getByte();
+ int b5 = getByte();
+ int b6 = getByte();
+ int b7 = getByte();
+ long res = 0;
+ if (littleEndian) {
+ res += b0;
+ res += ( ((long)b1) << 8);
+ res += ( ((long)b2) << 16);
+ res += ( ((long)b3) << 24);
+ res += ( ((long)b4) << 32);
+ res += ( ((long)b5) << 40);
+ res += ( ((long)b6) << 48);
+ res += ( ((long)b7) << 56);
+ } else {
+ res += b7;
+ res += ( ((long)b6) << 8);
+ res += ( ((long)b5) << 16);
+ res += ( ((long)b4) << 24);
+ res += ( ((long)b3) << 32);
+ res += ( ((long)b2) << 40);
+ res += ( ((long)b1) << 48);
+ res += ( ((long)b0) << 56);
+ }
+ return Double.longBitsToDouble(res);
+ }
+
+ float getFloat() throws IOException {
+ int b0 = getByte();
+ int b1 = getByte();
+ int b2 = getByte();
+ int b3 = getByte();
+ int res = 0;
+ if (littleEndian) {
+ res += b0;
+ res += ( ((long)b1) << 8);
+ res += ( ((long)b2) << 16);
+ res += ( ((long)b3) << 24);
+ } else {
+ res += b3;
+ res += ( ((long)b2) << 8);
+ res += ( ((long)b1) << 16);
+ res += ( ((long)b0) << 24);
+ }
+ return Float.intBitsToFloat(res);
+ }
+
+ byte[] getLut(int length) throws IOException {
+ if ((length&1)!=0) { // odd
+ String dummy = getString(length);
+ return null;
+ }
+ length /= 2;
+ byte[] lut = new byte[length];
+ for (int i=0; i>>8);
+ return lut;
+ }
+
+ int getLength() throws IOException {
+ int b0 = getByte();
+ int b1 = getByte();
+ int b2 = getByte();
+ int b3 = getByte();
+
+ // We cannot know whether the VR is implicit or explicit
+ // without the full DICOM Data Dictionary for public and
+ // private groups.
+
+ // We will assume the VR is explicit if the two bytes
+ // match the known codes. It is possible that these two
+ // bytes are part of a 32-bit length for an implicit VR.
+
+ vr = (b0<<8) + b1;
+
+ switch (vr) {
+ case OB: case OW: case SQ: case UN: case UT:
+ case OF: case OL: case OD: case UC: case UR:
+ case OV: case SV: case UV:
+ // Explicit VR with 32-bit length if other two bytes are zero
+ if ( (b2 == 0) || (b3 == 0) ) return getInt();
+ // Implicit VR with 32-bit length
+ vr = IMPLICIT_VR;
+ if (littleEndian)
+ return ((b3<<24) + (b2<<16) + (b1<<8) + b0);
+ else
+ return ((b0<<24) + (b1<<16) + (b2<<8) + b3);
+ case AE: case AS: case AT: case CS: case DA: case DS: case DT: case FD:
+ case FL: case IS: case LO: case LT: case PN: case SH: case SL: case SS:
+ case ST: case TM: case UI: case UL: case US: case QQ:
+ // Explicit vr with 16-bit length
+ if (littleEndian)
+ return ((b3<<8) + b2);
+ else
+ return ((b2<<8) + b3);
+ default:
+ // Implicit VR with 32-bit length...
+ vr = IMPLICIT_VR;
+ if (littleEndian)
+ return ((b3<<24) + (b2<<16) + (b1<<8) + b0);
+ else
+ return ((b0<<24) + (b1<<16) + (b2<<8) + b3);
+ }
+ }
+
+ int getNextTag() throws IOException {
+ int groupWord = getShort();
+ if (groupWord==0x0800 && bigEndianTransferSyntax) {
+ littleEndian = false;
+ groupWord = 0x0008;
+ }
+ int elementWord = getShort();
+ int tag = groupWord<<16 | elementWord;
+ elementLength = getLength();
+
+ // hack needed to read some GE files
+ // The element length must be even!
+ if (elementLength==13 && !oddLocations) elementLength = 10;
+
+ // "Undefined" element length.
+ // This is a sort of bracket that encloses a sequence of elements.
+ if (elementLength==-1) {
+ elementLength = 0;
+ inSequence = true;
+ }
+ //IJ.log("getNextTag: "+tag+" "+elementLength);
+ return tag;
+ }
+
+ FileInfo getFileInfo() throws IOException {
+ long skipCount;
+ FileInfo fi = new FileInfo();
+ int bitsAllocated = 16;
+ fi.fileFormat = fi.RAW;
+ fi.fileName = fileName;
+ if (directory.indexOf("://")>0) { // is URL
+ URL u = new URL(directory+fileName);
+ inputStream = new BufferedInputStream(u.openStream());
+ fi.inputStream = inputStream;
+ } else if (inputStream!=null)
+ fi.inputStream = inputStream;
+ else
+ fi.directory = directory;
+ fi.width = 0;
+ fi.height = 0;
+ fi.offset = 0;
+ fi.intelByteOrder = true;
+ fi.fileType = FileInfo.GRAY16_UNSIGNED;
+ fi.fileFormat = FileInfo.DICOM;
+ int samplesPerPixel = 1;
+ int planarConfiguration = 0;
+ String photoInterpretation = "";
+
+ if (inputStream!=null) {
+ // Use large buffer to allow URL stream to be reset after reading header
+ f = inputStream;
+ f.mark(400000);
+ } else
+ f = new BufferedInputStream(new FileInputStream(directory + fileName));
+ if (IJ.debugMode) {
+ IJ.log("");
+ IJ.log("DicomDecoder: decoding "+fileName);
+ }
+
+ int[] bytes = new int[ID_OFFSET];
+ for (int i=0; i-1||s.indexOf("1.2.5")>-1) {
+ f.close();
+ String msg = "ImageJ cannot open compressed DICOM images.\n \n";
+ msg += "Transfer Syntax UID = "+s;
+ throw new IOException(msg);
+ }
+ if (s.indexOf("1.2.840.10008.1.2.2")>=0)
+ bigEndianTransferSyntax = true;
+ break;
+ case MODALITY:
+ modality = getString(elementLength);
+ addInfo(tag, modality);
+ break;
+ case NUMBER_OF_FRAMES:
+ s = getString(elementLength);
+ addInfo(tag, s);
+ double frames = s2d(s);
+ if (frames>1.0)
+ fi.nImages = (int)frames;
+ break;
+ case SAMPLES_PER_PIXEL:
+ samplesPerPixel = getShort();
+ addInfo(tag, samplesPerPixel);
+ break;
+ case PHOTOMETRIC_INTERPRETATION:
+ photoInterpretation = getString(elementLength);
+ addInfo(tag, photoInterpretation);
+ break;
+ case PLANAR_CONFIGURATION:
+ planarConfiguration = getShort();
+ addInfo(tag, planarConfiguration);
+ break;
+ case ROWS:
+ fi.height = getShort();
+ addInfo(tag, fi.height);
+ break;
+ case COLUMNS:
+ fi.width = getShort();
+ addInfo(tag, fi.width);
+ break;
+ case IMAGER_PIXEL_SPACING: case PIXEL_SPACING:
+ String scale = getString(elementLength);
+ getSpatialScale(fi, scale);
+ addInfo(tag, scale);
+ break;
+ case SLICE_THICKNESS: case SLICE_SPACING:
+ String spacing = getString(elementLength);
+ fi.pixelDepth = s2d(spacing);
+ addInfo(tag, spacing);
+ break;
+ case BITS_ALLOCATED:
+ bitsAllocated = getShort();
+ if (bitsAllocated==8)
+ fi.fileType = FileInfo.GRAY8;
+ else if (bitsAllocated==32)
+ fi.fileType = FileInfo.GRAY32_UNSIGNED;
+ addInfo(tag, bitsAllocated);
+ break;
+ case PIXEL_REPRESENTATION:
+ int pixelRepresentation = getShort();
+ if (pixelRepresentation==1) {
+ fi.fileType = FileInfo.GRAY16_SIGNED;
+ signed = true;
+ }
+ addInfo(tag, pixelRepresentation);
+ break;
+ case WINDOW_CENTER:
+ String center = getString(elementLength);
+ int index = center.indexOf('\\');
+ if (index!=-1) center = center.substring(index+1);
+ windowCenter = s2d(center);
+ addInfo(tag, center);
+ break;
+ case WINDOW_WIDTH:
+ String width = getString(elementLength);
+ index = width.indexOf('\\');
+ if (index!=-1) width = width.substring(index+1);
+ windowWidth = s2d(width);
+ addInfo(tag, width);
+ break;
+ case RESCALE_INTERCEPT:
+ String intercept = getString(elementLength);
+ rescaleIntercept = s2d(intercept);
+ addInfo(tag, intercept);
+ break;
+ case RESCALE_SLOPE:
+ String slop = getString(elementLength);
+ rescaleSlope = s2d(slop);
+ addInfo(tag, slop);
+ break;
+ case RED_PALETTE:
+ fi.reds = getLut(elementLength);
+ addInfo(tag, elementLength/2);
+ break;
+ case GREEN_PALETTE:
+ fi.greens = getLut(elementLength);
+ addInfo(tag, elementLength/2);
+ break;
+ case BLUE_PALETTE:
+ fi.blues = getLut(elementLength);
+ addInfo(tag, elementLength/2);
+ break;
+ case FLOAT_PIXEL_DATA:
+ fi.fileType = FileInfo.GRAY32_FLOAT;
+ // continue without break
+ case PIXEL_DATA:
+ // Start of image data...
+ if (elementLength!=0) {
+ fi.offset = location;
+ addInfo(tag, location);
+ decodingTags = false;
+ } else
+ addInfo(tag, null);
+ break;
+ case 0x7F880010:
+ // What is this? - RAK
+ if (elementLength!=0) {
+ fi.offset = location+4;
+ decodingTags = false;
+ }
+ break;
+ default:
+ // Not used, skip over it...
+ addInfo(tag, null);
+ }
+ } // while(decodingTags)
+
+ if (fi.fileType==FileInfo.GRAY8) {
+ if (fi.reds!=null && fi.greens!=null && fi.blues!=null
+ && fi.reds.length==fi.greens.length
+ && fi.reds.length==fi.blues.length) {
+ fi.fileType = FileInfo.COLOR8;
+ fi.lutSize = fi.reds.length;
+
+ }
+ }
+
+ if (fi.fileType==FileInfo.GRAY32_UNSIGNED && signed)
+ fi.fileType = FileInfo.GRAY32_INT;
+
+ if (samplesPerPixel==3 && photoInterpretation.startsWith("RGB")) {
+ if (planarConfiguration==0)
+ fi.fileType = FileInfo.RGB;
+ else if (planarConfiguration==1)
+ fi.fileType = FileInfo.RGB_PLANAR;
+ } else if (photoInterpretation.endsWith("1 "))
+ fi.whiteIsZero = true;
+
+ if (!littleEndian)
+ fi.intelByteOrder = false;
+
+ if (IJ.debugMode) {
+ IJ.log("width: " + fi.width);
+ IJ.log("height: " + fi.height);
+ IJ.log("images: " + fi.nImages);
+ IJ.log("bits allocated: " + bitsAllocated);
+ IJ.log("offset: " + fi.offset);
+ }
+
+ if (inputStream!=null)
+ f.reset();
+ else
+ f.close();
+ return fi;
+ }
+
+ String getDicomInfo() {
+ String s = new String(dicomInfo);
+ char[] chars = new char[s.length()];
+ s.getChars(0, s.length(), chars, 0);
+ for (int i=0; i>>16;
+ //if (group!=previousGroup && (previousInfo!=null&&previousInfo.indexOf("Sequence:")==-1))
+ // dicomInfo.append("\n");
+ previousGroup = group;
+ previousInfo = info;
+ dicomInfo.append(tag2hex(tag)+info+"\n");
+ }
+ if (IJ.debugMode) {
+ if (info==null) info = "";
+ vrLetters[0] = (byte)(vr >> 8);
+ vrLetters[1] = (byte)(vr & 0xFF);
+ String VR = new String(vrLetters);
+ IJ.log("(" + tag2hex(tag) + VR
+ + " " + elementLength
+ + " bytes from "
+ + (location-elementLength)+") "
+ + info);
+ }
+ }
+
+ void addInfo(int tag, int value) throws IOException {
+ addInfo(tag, Integer.toString(value));
+ }
+
+ String getHeaderInfo(int tag, String value) throws IOException {
+ if (tag==ITEM_DELIMINATION || tag==SEQUENCE_DELIMINATION) {
+ inSequence = false;
+ if (!IJ.debugMode) return null;
+ }
+ String key = i2hex(tag);
+ //while (key.length()<8)
+ // key = '0' + key;
+ String id = (String)dictionary.get(key);
+ if (id!=null) {
+ if (vr==IMPLICIT_VR && id!=null)
+ vr = (id.charAt(0)<<8) + id.charAt(1);
+ id = id.substring(2);
+ }
+ if (tag==ITEM)
+ return id!=null?id+":":null;
+ if (value!=null)
+ return id+": "+value;
+ switch (vr) {
+ case FD:
+ if (elementLength==8)
+ value = Double.toString(getDouble());
+ else
+ for (int i=0; i44) value=null;
+ break;
+ case SQ:
+ value = "";
+ if (tag==ACQUISITION_CONTEXT_SEQUENCE)
+ acquisitionSequence = true;
+ if (tag==VIEW_CODE_SEQUENCE)
+ acquisitionSequence = false;
+ boolean privateTag = ((tag>>16)&1)!=0;
+ if (tag!=ICON_IMAGE_SEQUENCE && !privateTag)
+ break;
+ // else fall through and skip icon image sequence or private sequence
+ default:
+ long skipCount = (long)elementLength;
+ while (skipCount > 0) skipCount -= f.skip(skipCount);
+ location += elementLength;
+ value = "";
+ }
+ if (value!=null && id==null && !value.equals(""))
+ return "---: "+value;
+ else if (id==null)
+ return null;
+ else
+ return id+": "+value;
+ }
+
+ static char[] buf8 = new char[8];
+
+ /** Converts an int to an 8 byte hex string. */
+ String i2hex(int i) {
+ for (int pos=7; pos>=0; pos--) {
+ buf8[pos] = Tools.hexDigits[i&0xf];
+ i >>>= 4;
+ }
+ return new String(buf8);
+ }
+
+ char[] buf10;
+
+ String tag2hex(int tag) {
+ if (buf10==null) {
+ buf10 = new char[11];
+ buf10[4] = ',';
+ buf10[9] = ' ';
+ }
+ int pos = 8;
+ while (pos>=0) {
+ buf10[pos] = Tools.hexDigits[tag&0xf];
+ tag >>>= 4;
+ pos--;
+ if (pos==4) pos--; // skip coma
+ }
+ return new String(buf10);
+ }
+
+ double s2d(String s) {
+ if (s==null) return 0.0;
+ if (s.startsWith("\\"))
+ s = s.substring(1);
+ Double d;
+ try {d = Double.valueOf(s);}
+ catch (NumberFormatException e) {d = null;}
+ if (d!=null)
+ return(d.doubleValue());
+ else
+ return(0.0);
+ }
+
+ void getSpatialScale(FileInfo fi, String scale) {
+ double xscale=0, yscale=0;
+ int i = scale.indexOf('\\');
+ if (i>0) {
+ yscale = s2d(scale.substring(0, i));
+ xscale = s2d(scale.substring(i+1));
+ }
+ if (xscale!=0.0 && yscale!=0.0) {
+ fi.pixelWidth = xscale;
+ fi.pixelHeight = yscale;
+ fi.unit = "mm";
+ }
+ }
+
+ boolean dicmFound() {
+ return dicmFound;
+ }
+
+}
+
+
+class DicomDictionary {
+
+ Properties getDictionary() {
+ Properties p = new Properties();
+ for (int i=0; i1) {
+ for (int i=0; i=limit && !IJ.is64Bit()) {
+ if (!IJ.showMessageWithCancel(title,
+ "Note: setting the memory limit to a value\n"
+ +"greater than "+limit+"MB on a 32-bit system\n"
+ +"may cause ImageJ to fail to start. The title of\n"
+ +"the Edit>Options>Memory & Threads dialog\n"
+ +"box changes to \"Memory (64-bit)\" when ImageJ\n"
+ +"is running on a 64-bit version of Java."))
+ return;
+ }
+ try {
+ String s2 = s.substring(index2);
+ if (s2.startsWith("g"))
+ s2 = "m"+s2.substring(1);
+ String s3 = s.substring(0, index1) + max2 + s2;
+ FileOutputStream fos = new FileOutputStream(f);
+ PrintWriter pw = new PrintWriter(fos);
+ pw.print(s3);
+ pw.close();
+ } catch (IOException e) {
+ String error = e.getMessage();
+ if (error==null || error.equals("")) error = ""+e;
+ String name = IJ.isMacOSX()?"Info.plist":"ImageJ.cfg";
+ String msg =
+ "Unable to update the file \"" + name + "\".\n"
+ + " \n"
+ + "\"" + error + "\"";
+ IJ.showMessage("Memory", msg);
+ return;
+ }
+ String hint = "";
+ if (IJ.isWindows() && max2>640 && max2>max)
+ hint = "\nDelete the \"ImageJ.cfg\" file, located in the ImageJ folder,\nif ImageJ fails to start.";
+ IJ.showMessage("Memory", "The new " + max2 +"MB limit will take effect after ImageJ is restarted."+hint);
+ }
+
+ public long getMemorySetting() {
+ if (IJ.getApplet()!=null) return 0L;
+ long max = 0L;
+ if (IJ.isMacOSX()) {
+ String appPath = System.getProperty("java.class.path");
+ if (appPath==null) return 0L;
+ int index = appPath.indexOf(".app/");
+ if (index==-1) return 0L;
+ appPath = appPath.substring(0,index+5);
+ max = getMemorySetting(appPath+"Contents/Info.plist");
+ } else
+ max = getMemorySetting("ImageJ.cfg");
+ return max;
+ }
+
+ void showError() {
+ int max = (int)(maxMemory()/1048576L);
+ String msg =
+ "ImageJ is unable to change the memory limit. For \n"
+ + "more information, refer to the installation notes at\n \n"
+ + " "+IJ.URL2+"/docs/install/\n"
+ + " \n";
+ if (fileMissing) {
+ if (IJ.isMacOSX())
+ msg += "The ImageJ application (ImageJ.app) was not found.\n \n";
+ else if (IJ.isWindows())
+ msg += "ImageJ.cfg not found.\n \n";
+ fileMissing = false;
+ }
+ if (max>0)
+ msg += "Current limit: " + max + "MB";
+ IJ.showMessage("Memory", msg);
+ }
+
+ long getMemorySetting(String file) {
+ String path = file.startsWith("/")?file:Prefs.getImageJDir()+file;
+ if (IJ.debugMode) IJ.log("getMemorySetting: "+path);
+ f = new File(path);
+ if (!f.exists()) {
+ fileMissing = true;
+ return 0L;
+ }
+ long max = 0L;
+ try {
+ int size = (int)f.length();
+ byte[] buffer = new byte[size];
+ FileInputStream in = new FileInputStream(f);
+ in.read(buffer, 0, size);
+ s = new String(buffer, 0, size, "ISO8859_1");
+ in.close();
+ index1 = s.indexOf("-mx");
+ if (index1==-1) index1 = s.indexOf("-Xmx");
+ if (index1==-1) return 0L;
+ if (s.charAt(index1+1)=='X') index1+=4; else index1+=3;
+ index2 = index1;
+ while (index2 getApplets();
+
+ void showDocument(URL url);
+
+ public void showDocument(URL url, String target);
+
+ void showStatus(String status);
+
+ public void setStream(String key, InputStream stream) throws IOException;
+
+ public InputStream getStream(String key);
+
+ public Iterator getStreamKeys();
+}
diff --git a/mrj/26/ij/stub/AppletStub.java b/mrj/26/ij/stub/AppletStub.java
new file mode 100644
index 00000000..b5e9a4e7
--- /dev/null
+++ b/mrj/26/ij/stub/AppletStub.java
@@ -0,0 +1,17 @@
+package ij.stub;
+
+import java.net.URL;
+
+public interface AppletStub {
+ boolean isActive();
+
+ URL getDocumentBase();
+
+ URL getCodeBase();
+
+ String getParameter(String name);
+
+ AppletContext getAppletContext();
+
+ void appletResize(int width, int height);
+}
diff --git a/mrj/26/ij/stub/AudioClip.java b/mrj/26/ij/stub/AudioClip.java
new file mode 100644
index 00000000..4e24db10
--- /dev/null
+++ b/mrj/26/ij/stub/AudioClip.java
@@ -0,0 +1,9 @@
+package ij.stub;
+
+public interface AudioClip {
+ void play();
+
+ void loop();
+
+ void stop();
+}
diff --git a/pom.xml b/pom.xml
index 2225bd96..ba9381a6 100644
--- a/pom.xml
+++ b/pom.xml
@@ -98,6 +98,8 @@
true
+
+ 3.15.0
@@ -136,6 +138,7 @@
maven-compiler-plugin
+ ${maven-compiler-plugin.version}
default-compile
@@ -147,6 +150,7 @@
tests/**
+ mrj/**
9
@@ -161,6 +165,7 @@
**/module-info.java
tests/**
+ mrj/**
+ true
+
+
@@ -180,6 +210,16 @@
1.6
+
+ maven-jar-plugin
+
+
+
+ true
+
+
+
+
maven-javadoc-plugin