[med-svn] [imagej] 02/04: New upstream version 1.51p+dfsg
Andreas Tille
tille at debian.org
Fri Aug 11 22:29:52 UTC 2017
This is an automated email from the git hooks/post-receive script.
tille pushed a commit to branch master
in repository imagej.
commit a544c43baeb49013118e5ccf2aae7dc4a34e590a
Author: Andreas Tille <tille at debian.org>
Date: Sat Aug 12 00:28:00 2017 +0200
New upstream version 1.51p+dfsg
---
IJ_Props.txt | 15 +--
ij/CompositeImage.java | 2 +-
ij/Executer.java | 2 +-
ij/IJ.java | 10 +-
ij/ImageJ.java | 29 ++++-
ij/ImagePlus.java | 45 +++++---
ij/Menus.java | 19 +++-
ij/Prefs.java | 22 +++-
ij/VirtualStack.java | 36 ++++---
ij/gui/EllipseRoi.java | 48 ++++-----
ij/gui/GUI.java | 3 -
ij/gui/GenericDialog.java | 70 +++++-------
ij/gui/HistogramWindow.java | 112 +++++++++++--------
ij/gui/ImageCanvas.java | 12 ++-
ij/gui/ImageWindow.java | 10 +-
ij/gui/Line.java | 89 +++++++++++++++
ij/gui/NewImage.java | 16 ++-
ij/gui/Overlay.java | 17 +++
ij/gui/Plot.java | 2 +-
ij/gui/PlotWindow.java | 2 +-
ij/gui/PointRoi.java | 10 +-
ij/gui/PolygonRoi.java | 7 +-
ij/gui/ProgressBar.java | 3 +
ij/gui/Roi.java | 114 ++++++++++----------
ij/gui/RoiProperties.java | 8 +-
ij/gui/RotatedRectRoi.java | 176 ++++++++++++++++++++++++++++++
ij/gui/ScrollbarWithLabel.java | 1 -
ij/gui/Toolbar.java | 140 +++++++++++++++---------
ij/gui/YesNoCancelDialog.java | 8 +-
ij/io/FileOpener.java | 4 +-
ij/io/ImageReader.java | 3 +-
ij/io/Opener.java | 9 +-
ij/io/RoiDecoder.java | 12 ++-
ij/io/RoiEncoder.java | 16 ++-
ij/io/TiffDecoder.java | 5 +-
ij/macro/Functions.java | 191 +++++++++++++++++++++++++++------
ij/macro/Interpreter.java | 18 +++-
ij/measure/ResultsTable.java | 7 +-
ij/plugin/AVI_Reader.java | 128 ++++++++++++----------
ij/plugin/BatchProcessor.java | 39 +++++--
ij/plugin/Binner.java | 2 +-
ij/plugin/CalibrationBar.java | 5 +-
ij/plugin/ChannelArranger.java | 6 +-
ij/plugin/Colors.java | 2 +-
ij/plugin/Converter.java | 8 +-
ij/plugin/Duplicator.java | 5 +
ij/plugin/FileInfoVirtualStack.java | 4 +-
ij/plugin/FolderOpener.java | 6 ++
ij/plugin/Grid.java | 33 +++++-
ij/plugin/GroupedZProjector.java | 16 ++-
ij/plugin/HyperStackConverter.java | 2 +-
ij/plugin/ImageInfo.java | 15 +++
ij/plugin/LutLoader.java | 5 +-
ij/plugin/Macro_Runner.java | 4 +-
ij/plugin/Options.java | 9 +-
ij/plugin/OverlayCommands.java | 1 -
ij/plugin/PNM_Writer.java | 39 ++++---
ij/plugin/PointToolOptions.java | 28 +++--
ij/plugin/Profiler.java | 8 +-
ij/plugin/Projector.java | 7 +-
ij/plugin/RGBStackMerge.java | 2 +
ij/plugin/Resizer.java | 8 +-
ij/plugin/RoiRotator.java | 2 -
ij/plugin/Scaler.java | 5 +
ij/plugin/ScreenGrabber.java | 21 ++++
ij/plugin/Selection.java | 2 +-
ij/plugin/SimpleCommands.java | 11 ++
ij/plugin/SubstackMaker.java | 10 ++
ij/plugin/ZProjector.java | 2 +-
ij/plugin/Zoom.java | 8 +-
ij/plugin/filter/Analyzer.java | 33 ++++--
ij/plugin/filter/ImageMath.java | 4 +-
ij/plugin/filter/MaximumFinder.java | 57 ++++++++--
ij/plugin/filter/ParticleAnalyzer.java | 8 +-
ij/plugin/frame/ContrastAdjuster.java | 6 +-
ij/plugin/frame/Editor.java | 117 ++++++++++++++++++--
ij/plugin/frame/Recorder.java | 2 +-
ij/plugin/frame/RoiManager.java | 50 ++++-----
ij/plugin/frame/ThresholdAdjuster.java | 27 ++---
ij/process/AutoThresholder.java | 5 +-
ij/process/ByteProcessor.java | 1 -
ij/process/ColorProcessor.java | 104 +++++++++++++-----
ij/process/ImageConverter.java | 2 +
ij/process/ImageProcessor.java | 109 ++++++++++++-------
ij/process/LUT.java | 13 ++-
macros/CommandFinderTool.txt | 3 +
macros/StartupMacros.txt | 5 +-
release-notes.html | 58 +++-------
88 files changed, 1633 insertions(+), 707 deletions(-)
diff --git a/IJ_Props.txt b/IJ_Props.txt
index aecadc9..c6ae54b 100644
--- a/IJ_Props.txt
+++ b/IJ_Props.txt
@@ -201,7 +201,7 @@ zoom04="View 100%[5]",ij.plugin.Zoom("100%")
zoom05="To Selection",ij.plugin.Zoom("to")
zoom06="Scale to Fit",ij.plugin.Zoom("scale")
zoom07="Set... ",ij.plugin.Zoom("set")
-#zoom07="Maximize",ij.plugin.Zoom("max")
+zoom08="Maximize",ij.plugin.Zoom("max")
# Plugins installed in the Image/Overlay submenu
overlay01="Add Selection...[b]",ij.plugin.OverlayCommands("add")
@@ -394,12 +394,13 @@ utilities04="Monitor Events...",ij.plugin.EventListener
utilities05="Monitor Memory...",ij.plugin.frame.MemoryMonitor
utilities06=-
utilities07="Capture Screen[G]",ij.plugin.ScreenGrabber
-utilities08="Capture Image",ij.plugin.ScreenGrabber("image")
-utilities09=-
-utilities10="ImageJ Properties",ij.plugin.JavaProperties
-utilities11="Threads",ij.plugin.ThreadLister
-utilities12="Benchmark",ij.plugin.filter.Benchmark
-utilities13="Reset...",ij.plugin.SimpleCommands("reset")
+utilities08="Capture Delayed...",ij.plugin.ScreenGrabber("delay")
+utilities09="Capture Image",ij.plugin.ScreenGrabber("image")
+utilities10=-
+utilities11="ImageJ Properties",ij.plugin.JavaProperties
+utilities12="Threads",ij.plugin.ThreadLister
+utilities13="Benchmark",ij.plugin.filter.Benchmark
+utilities14="Reset...",ij.plugin.SimpleCommands("reset")
# Plugins installed in the Plugins/New submenu
new_01="Macro",ij.plugin.NewPlugin("macro")
diff --git a/ij/CompositeImage.java b/ij/CompositeImage.java
index 985985d..f74ae17 100644
--- a/ij/CompositeImage.java
+++ b/ij/CompositeImage.java
@@ -210,7 +210,7 @@ public class CompositeImage extends ImagePlus {
setupLuts(nChannels);
LUT cm = lut[currentChannel];
if (mode==COLOR)
- ip.setColorModel(cm);
+ ip.setLut(cm);
if (!(cm.min==0.0&&cm.max==0.0))
ip.setMinAndMax(cm.min, cm.max);
if (!IJ.isMacro()) ContrastAdjuster.update();
diff --git a/ij/Executer.java b/ij/Executer.java
index 4211e2c..4488e6d 100644
--- a/ij/Executer.java
+++ b/ij/Executer.java
@@ -194,7 +194,7 @@ public class Executer implements Runnable {
ed.evaluateScript(".bsh");
else if (isPython)
ed.evaluateScript(".py");
- else
+ else if (!name.contains("_Tool"))
IJ.runMacro(text);
}
return true;
diff --git a/ij/IJ.java b/ij/IJ.java
index 23a6517..10397cc 100644
--- a/ij/IJ.java
+++ b/ij/IJ.java
@@ -562,7 +562,7 @@ public class IJ {
Undo.reset();
System.gc();
lastErrorMessage = "out of memory";
- String tot = Runtime.getRuntime().totalMemory()/1048576L+"MB";
+ String tot = Runtime.getRuntime().maxMemory()/1048576L+"MB";
if (!memMessageDisplayed)
log(">>>>>>>>>>>>>>>>>>>>>>>>>>>");
log("<Out of memory>");
@@ -1333,9 +1333,11 @@ public class IJ {
WindowManager.setWindow(win);
}
long start = System.currentTimeMillis();
- // timeout after 2 seconds unless current thread is event dispatch thread
+ // timeout after 1 second unless current thread is event dispatch thread
String thread = Thread.currentThread().getName();
- int timeout = thread!=null&&thread.indexOf("EventQueue")!=-1?0:2000;
+ int timeout = thread!=null&&thread.indexOf("EventQueue")!=-1?0:1000;
+ if (IJ.isMacOSX() && IJ.isJava18() && timeout>0)
+ timeout = 250; //work around OS X/Java 8 window activation bug
while (true) {
wait(10);
imp = WindowManager.getCurrentImage();
@@ -1811,7 +1813,7 @@ public class IJ {
path = updateExtension(path, ".txt");
format = "Text Image...";
} else if (format.indexOf("text")!=-1 || format.indexOf("txt")!=-1) {
- if (path!=null && !path.endsWith(".xls") && !path.endsWith(".csv"))
+ if (path!=null && !path.endsWith(".xls") && !path.endsWith(".csv") && !path.endsWith(".tsv"))
path = updateExtension(path, ".txt");
format = "Text...";
} else if (format.indexOf("zip")!=-1) {
diff --git a/ij/ImageJ.java b/ij/ImageJ.java
index f640a38..7fcf14f 100644
--- a/ij/ImageJ.java
+++ b/ij/ImageJ.java
@@ -79,7 +79,7 @@ public class ImageJ extends Frame implements ActionListener,
MouseListener, KeyListener, WindowListener, ItemListener, Runnable {
/** Plugins should call IJ.getVersion() or IJ.getFullVersion() to get the version string. */
- public static final String VERSION = "1.51i";
+ public static final String VERSION = "1.51p";
public static final String BUILD = "";
public static Color backgroundColor = new Color(237,237,237);
/** SansSerif, 12-point, plain font. */
@@ -169,7 +169,7 @@ public class ImageJ extends Frame implements ActionListener,
statusLine.addKeyListener(this);
statusLine.addMouseListener(this);
statusBar.add("Center", statusLine);
- progressBar = new ProgressBar(120, 20);
+ progressBar = new ProgressBar(ProgressBar.WIDTH, ProgressBar.HEIGHT);
progressBar.addKeyListener(this);
progressBar.addMouseListener(this);
statusBar.add("East", progressBar);
@@ -192,6 +192,22 @@ public class ImageJ extends Frame implements ActionListener,
setAlwaysOnTop(Prefs.alwaysOnTop);
pack();
setVisible(true);
+ Dimension size = getSize();
+ if (size!=null) {
+ if (IJ.debugMode) IJ.log("size: "+size);
+ if (IJ.isWindows() && size.height>108) {
+ // workaround for IJ window layout and FileDialog freeze problems with Windows 10 Creators Update
+ IJ.wait(10);
+ pack();
+ if (IJ.debugMode) IJ.log("pack()");
+ if (!Prefs.jFileChooserSettingChanged)
+ Prefs.useJFileChooser = true;
+ } else if (IJ.isMacOSX()) {
+ Rectangle maxBounds = GUI.getMaxWindowBounds();
+ if (loc.x+size.width>maxBounds.x+maxBounds.width)
+ setLocation(loc.x, loc.y);
+ }
+ }
}
if (err1!=null)
IJ.error(err1);
@@ -268,6 +284,7 @@ public class ImageJ extends Frame implements ActionListener,
Rectangle maxBounds = GUI.getMaxWindowBounds();
int ijX = Prefs.getInt(IJ_X,-99);
int ijY = Prefs.getInt(IJ_Y,-99);
+ //System.out.println("getPreferredLoc1: "+ijX+" "+ijY+" "+maxBounds);
if (ijX>=maxBounds.x && ijY>=maxBounds.y && ijX<(maxBounds.x+maxBounds.width-75))
return new Point(ijX, ijY);
Dimension tbsize = toolbar.getPreferredSize();
@@ -496,7 +513,7 @@ public class ImageJ extends Frame implements ActionListener,
else if (zoomKey && keyCode==KeyEvent.VK_UP && !ignoreArrowKeys(imp) && Toolbar.getToolId()<Toolbar.SPARE6)
cmd="In [+]";
else if (roi!=null) {
- if ((flags & KeyEvent.ALT_MASK) != 0)
+ if ((flags & KeyEvent.ALT_MASK)!=0 || (flags & KeyEvent.CTRL_MASK)!=0)
roi.nudgeCorner(keyCode);
else
roi.nudge(keyCode);
@@ -652,10 +669,12 @@ public class ImageJ extends Frame implements ActionListener,
/** Called once when ImageJ quits. */
public void savePreferences(Properties prefs) {
Point loc = getLocation();
+ if (IJ.isLinux()) {
+ Rectangle bounds = GUI.getMaxWindowBounds();
+ loc.y = bounds.y;
+ }
prefs.put(IJ_X, Integer.toString(loc.x));
prefs.put(IJ_Y, Integer.toString(loc.y));
- //prefs.put(IJ_WIDTH, Integer.toString(size.width));
- //prefs.put(IJ_HEIGHT, Integer.toString(size.height));
}
public static void main(String args[]) {
diff --git a/ij/ImagePlus.java b/ij/ImagePlus.java
index 6f66790..7fad5bb 100644
--- a/ij/ImagePlus.java
+++ b/ij/ImagePlus.java
@@ -43,6 +43,9 @@ public class ImagePlus implements ImageObserver, Measurements, Cloneable {
/** 32-bit RGB color */
public static final int COLOR_RGB = 4;
+ /** Title of image used by Flatten command */
+ public static final String flattenTitle = "flatten~canvas";
+
/** True if any changes have been made to this image. */
public boolean changes;
@@ -96,8 +99,8 @@ public class ImagePlus implements ImageObserver, Measurements, Cloneable {
/** Constructs an uninitialized ImagePlus. */
public ImagePlus() {
- ID = --currentID;
- title="null";
+ title = (this instanceof CompositeImage)?"composite":"null";
+ setID();
}
/** Constructs an ImagePlus from an Image or BufferedImage. The first
@@ -105,15 +108,15 @@ public class ImagePlus implements ImageObserver, Measurements, Cloneable {
Throws an IllegalStateException if an error occurs while loading the image. */
public ImagePlus(String title, Image img) {
this.title = title;
- ID = --currentID;
if (img!=null)
setImage(img);
+ setID();
}
/** Constructs an ImagePlus from an ImageProcessor. */
public ImagePlus(String title, ImageProcessor ip) {
setProcessor(title, ip);
- ID = --currentID;
+ setID();
}
/** Constructs an ImagePlus from a TIFF, BMP, DICOM, FITS,
@@ -140,16 +143,21 @@ public class ImagePlus implements ImageObserver, Measurements, Cloneable {
setRoi(imp.getRoi());
if (isURL)
this.url = pathOrURL;
- ID = --currentID;
+ setID();
}
}
/** Constructs an ImagePlus from a stack. */
public ImagePlus(String title, ImageStack stack) {
setStack(title, stack);
- ID = --currentID;
+ setID();
}
+ private void setID() {
+ ID = --currentID;
+ //IJ.log("New "+this);
+ }
+
/** Locks the image so other threads can test to see if it
is in use. Returns true if the image was successfully locked.
Beeps, displays a message in the status bar, and returns
@@ -353,7 +361,7 @@ public class ImagePlus implements ImageObserver, Measurements, Cloneable {
}
/** ImageCanvas.paint() calls this method when the
- ImageProcessor has generated new image. */
+ ImageProcessor has generated a new image. */
public void updateImage() {
if (ip!=null)
img = ip.createImage();
@@ -399,6 +407,7 @@ public class ImagePlus implements ImageObserver, Measurements, Cloneable {
if (isVisible())
return;
win = null;
+ //if (ip!=null) throw new IllegalArgumentException();
if ((IJ.isMacro() && ij==null) || Interpreter.isBatchMode()) {
if (isComposite()) ((CompositeImage)this).reset();
ImagePlus img = WindowManager.getCurrentImage();
@@ -1553,6 +1562,9 @@ public class ImagePlus implements ImageObserver, Measurements, Cloneable {
overlay2 = ip2.getOverlay();
if (overlay2!=null)
setOverlay(overlay2);
+ Properties props = ((VirtualStack)stack).getProperties();
+ if (props!=null)
+ setProperty("FHT", props.get("FHT"));
pixels = ip2.getPixels();
} else
pixels = stack.getPixels(currentSlice);
@@ -1657,8 +1669,10 @@ public class ImagePlus implements ImageObserver, Measurements, Cloneable {
deleteRoi();
switch (Toolbar.getToolId()) {
case Toolbar.RECTANGLE:
- int cornerDiameter = Toolbar.getRoundRectArcSize();
- roi = new Roi(sx, sy, this, cornerDiameter);
+ if (Toolbar.getRectToolType()==Toolbar.ROTATED_RECT_ROI)
+ roi = new RotatedRectRoi(sx, sy, this);
+ else
+ roi = new Roi(sx, sy, this, Toolbar.getRoundRectArcSize());
break;
case Toolbar.OVAL:
if (Toolbar.getOvalToolType()==Toolbar.ELLIPSE_ROI)
@@ -1728,9 +1742,11 @@ public class ImagePlus implements ImageObserver, Measurements, Cloneable {
if (rm!=null)
rm.deselect(roi);
}
- roi.notifyListeners(RoiListener.DELETED);
- if (roi instanceof PointRoi)
- ((PointRoi)roi).resetCounters();
+ if (roi!=null) {
+ roi.notifyListeners(RoiListener.DELETED);
+ if (roi instanceof PointRoi)
+ ((PointRoi)roi).resetCounters();
+ }
roi = null;
if (ip!=null)
ip.resetRoi();
@@ -2065,6 +2081,7 @@ public class ImagePlus implements ImageObserver, Measurements, Cloneable {
/** Copies attributes (name, ID, calibration, path) of the specified image to this image. */
public void copyAttributes(ImagePlus imp) {
+ if (IJ.debugMode) IJ.log("copyAttributes: "+imp.getID()+" "+this.getID()+" "+imp+" "+this);
if (imp==null || imp.getWindow()!=null)
throw new IllegalArgumentException("Souce image is null or displayed");
ID = imp.getID();
@@ -2476,7 +2493,9 @@ public class ImagePlus implements ImageObserver, Measurements, Cloneable {
/** Returns a "flattened" version of this image, in RGB format. */
public ImagePlus flatten() {
if (IJ.debugMode) IJ.log("flatten");
+ IJ.wait(50); // wait for screen to be refreshed
ImagePlus imp2 = createImagePlus();
+ imp2.setTitle(flattenTitle);
ImageCanvas ic2 = new ImageCanvas(imp2);
imp2.flatteningCanvas = ic2;
imp2.setRoi(getRoi());
@@ -2689,7 +2708,7 @@ public class ImagePlus implements ImageObserver, Measurements, Cloneable {
}
public String toString() {
- return "img["+getTitle()+" ("+width+"x"+height+"x"+getNChannels()+"x"+getNSlices()+"x"+getNFrames()+")]";
+ return "img[\""+getTitle()+"\" ("+getID()+"), "+getBitDepth()+"-bit, "+width+"x"+height+"x"+getNChannels()+"x"+getNSlices()+"x"+getNFrames()+"]";
}
public void setIJMenuBar(boolean b) {
diff --git a/ij/Menus.java b/ij/Menus.java
index cab9bd9..6b9a510 100644
--- a/ij/Menus.java
+++ b/ij/Menus.java
@@ -207,7 +207,7 @@ public class Menus {
getMenu("Analyze>Gels", true);
Menu toolsMenu = getMenu("Analyze>Tools", true);
- // the plugins will be added later, with a separator
+ // the plugins will be added later, after a separator
addPluginsMenu();
Menu window = getMenu("Window");
@@ -279,11 +279,16 @@ public class Menus {
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, "Tool", "Circle_Tool.ijm");
+ addExample(submenu, "Custom Measurement", "Custom_Measurement.ijm");
+ submenu.addSeparator();
+ addExample(submenu, "Circle Tool", "Circle_Tool.ijm");
+ addExample(submenu, "Star Tool", "Star_Tool.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, "Example Plot", "Example_Plot.js");
addExample(submenu, "Semi-log Plot", "Semi-log_Plot.js");
addExample(submenu, "Arrow Plot", "Arrow_Plot.js");
@@ -294,6 +299,8 @@ public class Menus {
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");
submenu.addActionListener(listener);
menu.add(submenu);
submenu = new Menu("BeanShell");
@@ -313,11 +320,12 @@ public class Menus {
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");
- addExample(submenu, "Gamma Adjuster", "Gamma_Adjuster.java");
submenu.addActionListener(listener);
menu.add(submenu);
menu.addSeparator();
@@ -514,6 +522,7 @@ public class Menus {
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;
@@ -566,6 +575,10 @@ public class Menus {
installUserPlugin(pluginList[i]);
}
}
+ if ((nPlugins-nPlugins0)<=1 && IJ.getDir("imagej")!=null && IJ.getDir("imagej").startsWith("/private")) {
+ pluginsMenu.addSeparator();
+ addPlugInItem(pluginsMenu, "Why are Plugins Missing?", "ij.plugin.SimpleCommands(\"missing\")", 0, false);
+ }
installJarPlugins();
installMacros();
}
diff --git a/ij/Prefs.java b/ij/Prefs.java
index fb4b787..87aa158 100644
--- a/ij/Prefs.java
+++ b/ij/Prefs.java
@@ -54,7 +54,8 @@ public class Prefs {
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;
+ 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;
public static final String OPTIONS2 = "prefs.options2";
/** file.separator system property */
@@ -163,8 +164,14 @@ public class Prefs {
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 = true;
+ /** 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;
-
static Properties ijPrefs = new Properties();
static Properties props = new Properties(ijPrefs);
@@ -477,6 +484,8 @@ public class Prefs {
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;
}
static void saveOptions(Properties prefs) {
@@ -502,7 +511,9 @@ public class Prefs {
+ (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);
+ + (autoRunExamples?AUTO_RUN_EXAMPLES:0) + (showAllPoints?SHOW_ALL_POINTS:0)
+ + (doNotSaveWindowLocations?DO_NOT_SAVE_WINDOW_LOCS:0)
+ + (jFileChooserSettingChanged?JFILE_CHOOSER_CHANGED:0);
prefs.put(OPTIONS2, Integer.toString(options2));
}
@@ -579,7 +590,8 @@ public class Prefs {
/** Saves the Point <code>loc</code> in the preferences
file as a string using the keyword <code>key</code>. */
public static void saveLocation(String key, Point loc) {
- set(key, loc.x+","+loc.y);
+ if (!doNotSaveWindowLocations)
+ set(key, loc.x+","+loc.y);
}
/** Uses the keyword <code>key</code> to retrieve a location
@@ -656,7 +668,7 @@ public class Prefs {
}
public static String defaultResultsExtension() {
- return get("options.ext", ".xls");
+ return get("options.ext", ".csv");
}
}
diff --git a/ij/VirtualStack.java b/ij/VirtualStack.java
index 012b1ed..9ad04ed 100644
--- a/ij/VirtualStack.java
+++ b/ij/VirtualStack.java
@@ -4,8 +4,9 @@ import ij.io.*;
import ij.gui.ImageCanvas;
import ij.util.Tools;
import java.io.*;
-import java.awt.Font;
+import java.awt.*;
import java.awt.image.ColorModel;
+import java.util.Properties;
/** This class represents an array of disk-resident images. */
public class VirtualStack extends ImageStack {
@@ -15,7 +16,8 @@ public class VirtualStack extends ImageStack {
private String[] names;
private String[] labels;
private int bitDepth;
- private ImageProcessor ip;
+ private Properties properties;
+
/** Default constructor. */
public VirtualStack() { }
@@ -108,10 +110,9 @@ public class VirtualStack extends ImageStack {
were 1<=n<=nslices. Returns null if the stack is empty.
*/
public ImageProcessor getProcessor(int n) {
- //IJ.log("getProcessor: "+n+" "+names[n-1]+" "+bitDepth);
if (path==null) {
- if (ip==null)
- ip = new ByteProcessor(getWidth(), getHeight());
+ ImageProcessor ip = new ByteProcessor(getWidth(), getHeight());
+ label(ip, ""+n, Color.white);
return ip;
}
Opener opener = new Opener();
@@ -132,18 +133,13 @@ public class VirtualStack extends ImageStack {
depthThisImage = imp.getBitDepth();
ip = imp.getProcessor();
ip.setOverlay(imp.getOverlay());
+ properties = imp.getProperty("FHT")!=null?imp.getProperties():null;
} else {
File f = new File(path, names[n-1]);
String msg = f.exists()?"Error opening ":"File not found: ";
ip = new ByteProcessor(getWidth(), getHeight());
ip.invert();
- int size = getHeight()/20;
- if (size<9) size=9;
- Font font = new Font("Helvetica", Font.PLAIN, size);
- ip.setFont(font);
- ip.setAntialiasedText(true);
- ip.setColor(0);
- ip.drawString(msg+names[n-1], size, size*2);
+ label(ip, msg+names[n-1], Color.black);
depthThisImage = 8;
}
if (depthThisImage!=bitDepth) {
@@ -161,6 +157,16 @@ public class VirtualStack extends ImageStack {
}
return ip;
}
+
+ private void label(ImageProcessor ip, String msg, Color color) {
+ int size = getHeight()/20;
+ if (size<9) size=9;
+ Font font = new Font("Helvetica", Font.PLAIN, size);
+ ip.setFont(font);
+ ip.setAntialiasedText(true);
+ ip.setColor(color);
+ ip.drawString(msg, size, size*2);
+ }
/** Currently not implemented */
public int saveChanges(int n) {
@@ -236,6 +242,12 @@ public class VirtualStack extends ImageStack {
}
return this;
}
+
+ /** Returns the ImagePlus Properties assoctated with the current slice, or null. */
+ public Properties getProperties() {
+ return properties;
+ }
+
}
diff --git a/ij/gui/EllipseRoi.java b/ij/gui/EllipseRoi.java
index ae40004..9ccb62c 100644
--- a/ij/gui/EllipseRoi.java
+++ b/ij/gui/EllipseRoi.java
@@ -6,7 +6,7 @@ import ij.plugin.frame.Recorder;
import ij.process.FloatPolygon;
import ij.measure.Calibration;
-/** Elliptical region of interest. */
+/** This class implements the ellipse selection tool. */
public class EllipseRoi extends PolygonRoi {
private static final int vertices = 72;
private static double defaultRatio = 0.6;
@@ -21,6 +21,7 @@ public class EllipseRoi extends PolygonRoi {
this.aspectRatio = aspectRatio;
makeEllipse(x1, y1, x2, y2);
state = NORMAL;
+ bounds = null;
}
public EllipseRoi(int sx, int sy, ImagePlus imp) {
@@ -28,6 +29,8 @@ public class EllipseRoi extends PolygonRoi {
type = FREEROI;
xstart = ic.offScreenXD(sx);
ystart = ic.offScreenYD(sy);
+ setDrawOffset(false);
+ bounds = null;
}
public void draw(Graphics g) {
@@ -83,19 +86,14 @@ public class EllipseRoi extends PolygonRoi {
y = r.y;
width = r.width;
height = r.height;
- bounds = poly.getFloatBounds();
- float xbase = (float)bounds.getX();
- float ybase = (float)bounds.getY();
for (int i=0; i<nPoints; i++) {
- xpf[i] = xpf[i]-xbase;
- ypf[i] = ypf[i]-ybase;
+ xpf[i] = xpf[i]-x;
+ ypf[i] = ypf[i]-y;
}
}
protected void handleMouseUp(int screenX, int screenY) {
if (state==CONSTRUCTING) {
- addOffset();
- finishPolygon();
if (Recorder.record) {
double x1 = xpf[handle[2]]+x;
double y1 = ypf[handle[2]]+y;
@@ -113,23 +111,18 @@ public class EllipseRoi extends PolygonRoi {
protected void moveHandle(int sx, int sy) {
double ox = ic.offScreenXD(sx);
double oy = ic.offScreenYD(sy);
- double xbase=x, ybase=y;
- if (bounds!=null) {
- xbase = bounds.x;
- ybase = bounds.y;
- }
- double x1 = xpf[handle[2]]+xbase;
- double y1 = ypf[handle[2]]+ybase;
- double x2 = xpf[handle[0]]+xbase;
- double y2 = ypf[handle[0]]+ybase;
+ double x1 = xpf[handle[2]]+x;
+ double y1 = ypf[handle[2]]+y;
+ double x2 = xpf[handle[0]]+x;
+ double y2 = ypf[handle[0]]+y;
switch(activeHandle) {
case 0:
x2 = ox;
y2 = oy;
break;
case 1:
- double dx = (xpf[handle[3]]+xbase) - ox;
- double dy = (ypf[handle[3]]+ybase) - oy;
+ double dx = (xpf[handle[3]]+x) - ox;
+ double dy = (ypf[handle[3]]+y) - oy;
updateRatio(Math.sqrt(dx*dx+dy*dy), x1, y1, x2, y2);
break;
case 2:
@@ -137,8 +130,8 @@ public class EllipseRoi extends PolygonRoi {
y1 = oy;
break;
case 3:
- dx = (xpf[handle[1]]+xbase) - ox;
- dy = (ypf[handle[1]]+ybase) - oy;
+ dx = (xpf[handle[1]]+x) - ox;
+ dy = (ypf[handle[1]]+y) - oy;
updateRatio(Math.sqrt(dx*dx+dy*dy), x1, y1, x2, y2);
break;
}
@@ -192,16 +185,11 @@ public class EllipseRoi extends PolygonRoi {
/** Returns x1, y1, x2, y2 and aspectRatio as a 5 element array. */
public double[] getParams() {
- double xbase=x, ybase=y;
- if (bounds!=null) {
- xbase = bounds.x;
- ybase = bounds.y;
- }
double[] params = new double[5];
- params[0] = xpf[handle[2]]+xbase;
- params[1] = ypf[handle[2]]+ybase;
- params[2] = xpf[handle[0]]+xbase;
- params[3] = ypf[handle[0]]+ybase;
+ params[0] = xpf[handle[2]]+x;
+ params[1] = ypf[handle[2]]+y;
+ params[2] = xpf[handle[0]]+x;
+ params[3] = ypf[handle[0]]+y;
params[4] = aspectRatio;
return params;
}
diff --git a/ij/gui/GUI.java b/ij/gui/GUI.java
index 04e7825..028f28b 100644
--- a/ij/gui/GUI.java
+++ b/ij/gui/GUI.java
@@ -135,9 +135,6 @@ public class GUI {
/** Lightens overly dark scrollbar background on Windows 8. */
public static void fix(Scrollbar sb) {
- if (isWindows8) {
- sb.setBackground(lightGray);
- }
}
public static boolean showCompositeAdvisory(ImagePlus imp, String title) {
diff --git a/ij/gui/GenericDialog.java b/ij/gui/GenericDialog.java
index e251c9e..4c5a7fb 100644
--- a/ij/gui/GenericDialog.java
+++ b/ij/gui/GenericDialog.java
@@ -40,7 +40,6 @@ import ij.macro.*;
public class GenericDialog extends Dialog implements ActionListener, TextListener,
FocusListener, ItemListener, KeyListener, AdjustmentListener, WindowListener {
- public static final int MAX_SLIDERS = 25;
protected Vector numberField, stringField, checkbox, choice, slider, radioButtonGroups;
protected TextArea textArea1, textArea2;
protected Vector defaultValues,defaultText,defaultStrings,defaultChoiceIndexes;
@@ -58,14 +57,13 @@ FocusListener, ItemListener, KeyListener, AdjustmentListener, WindowListener {
private boolean firstSlider=true;
private boolean invalidNumber;
private String errorMessage;
- private boolean firstPaint = true;
private Hashtable labels;
private boolean macro;
private String macroOptions;
private int topInset, leftInset, bottomInset;
private boolean customInsets;
- private int[] sliderIndexes;
- private double[] sliderScales;
+ private Vector sliderIndexes;
+ private Vector sliderScales;
private Checkbox previewCheckbox; // the "Preview" Checkbox, if any
private Vector dialogListeners; // the Objects to notify on user input
private PlugInFilterRunner pfr; // the PlugInFilterRunner for automatic preview
@@ -81,6 +79,7 @@ FocusListener, ItemListener, KeyListener, AdjustmentListener, WindowListener {
private boolean smartRecording;
private Vector imagePanels;
private static GenericDialog instance;
+ private boolean firstPaint = true;
/** Creates a new GenericDialog with the specified title. Uses the current image
image window as the parent frame or the ImageJ frame if no image windows
@@ -110,8 +109,6 @@ FocusListener, ItemListener, KeyListener, AdjustmentListener, WindowListener {
setForeground(SystemColor.controlText);
setBackground(SystemColor.control);
}
- //if (IJ.isLinux())
- // setBackground(new Color(238, 238, 238));
grid = new GridBagLayout();
c = new GridBagConstraints();
setLayout(grid);
@@ -121,14 +118,6 @@ FocusListener, ItemListener, KeyListener, AdjustmentListener, WindowListener {
addWindowListener(this);
}
- //void showFields(String id) {
- // String s = id+": ";
- // for (int i=0; i<maxItems; i++)
- // if (numberField[i]!=null)
- // s += i+"='"+numberField[i].getText()+"' ";
- // IJ.write(s);
- //}
-
/** Adds a numeric field. The first word of the label must be
unique or command recording will not work.
* @param label the label
@@ -309,7 +298,6 @@ FocusListener, ItemListener, KeyListener, AdjustmentListener, WindowListener {
cb.addKeyListener(this);
add(cb);
checkbox.addElement(cb);
- //ij.IJ.write("addCheckbox: "+ y+" "+cbIndex);
if (!isPreview &&(Recorder.record || macro)) //preview checkbox is not recordable
saveLabel(cb, label);
if (isPreview) previewCheckbox = cb;
@@ -352,9 +340,6 @@ FocusListener, ItemListener, KeyListener, AdjustmentListener, WindowListener {
public void addPreviewCheckbox(PlugInFilterRunner pfr, String label) {
if (previewCheckbox!=null)
return;
- //ImagePlus imp = WindowManager.getCurrentImage();
- //if (imp!=null && imp.isComposite() && ((CompositeImage)imp).getMode()==IJ.COMPOSITE)
- // return;
previewLabel = label;
this.pfr = pfr;
addCheckbox(previewLabel, false, true);
@@ -621,11 +606,10 @@ FocusListener, ItemListener, KeyListener, AdjustmentListener, WindowListener {
if (slider==null) {
slider = new Vector(5);
- sliderIndexes = new int[MAX_SLIDERS];
- sliderScales = new double[MAX_SLIDERS];
+ sliderIndexes = new Vector(5);
+ sliderScales = new Vector(5);
}
Scrollbar s = new Scrollbar(Scrollbar.HORIZONTAL, (int)defaultValue, 1, (int)minValue, (int)maxValue+1);
- GUI.fix(s);
slider.addElement(s);
s.addAdjustmentListener(this);
s.setUnitIncrement(1);
@@ -644,8 +628,8 @@ FocusListener, ItemListener, KeyListener, AdjustmentListener, WindowListener {
tf.addFocusListener(this);
tf.addKeyListener(this);
numberField.addElement(tf);
- sliderIndexes[slider.size()-1] = numberField.size()-1;
- sliderScales[slider.size()-1] = scale;
+ sliderIndexes.add(new Integer(numberField.size()-1));
+ sliderScales.add(new Double(scale));
defaultValues.addElement(new Double(defaultValue/scale));
defaultText.addElement(tf.getText());
tf.setEditable(true);
@@ -826,7 +810,6 @@ FocusListener, ItemListener, KeyListener, AdjustmentListener, WindowListener {
if (macro) {
label = (String)labels.get((Object)tf);
theText = Macro.getValue(macroOptions, label, theText);
- //IJ.write("getNextNumber: "+label+" "+theText);
}
String originalText = (String)defaultText.elementAt(nfIndex);
double defaultValue = ((Double)(defaultValues.elementAt(nfIndex))).doubleValue();
@@ -1167,8 +1150,6 @@ FocusListener, ItemListener, KeyListener, AdjustmentListener, WindowListener {
c.insets = new Insets(15, 0, 0, 0);
grid.setConstraints(buttons, c);
add(buttons);
- if (IJ.isMacintosh())
- setResizable(false);
if (IJ.isMacOSX()&&IJ.isJava18())
instance = this;
pack();
@@ -1176,8 +1157,9 @@ FocusListener, ItemListener, KeyListener, AdjustmentListener, WindowListener {
if (centerDialog) GUI.center(this);
setVisible(true);
recorderOn = Recorder.record;
- IJ.wait(50); // work around for Sun/WinNT bug
+ IJ.wait(25);
}
+
/* For plugins that read their input only via dialogItemChanged, call it at least once */
if (!wasCanceled && dialogListeners!=null && dialogListeners.size()>0) {
resetCounters();
@@ -1319,15 +1301,15 @@ FocusListener, ItemListener, KeyListener, AdjustmentListener, WindowListener {
if (slider==null) return;
Object source = e.getSource();
for (int i=0; i<slider.size(); i++) {
- int index = sliderIndexes[i];
+ int index = ((Integer)sliderIndexes.get(i)).intValue();
if (source==numberField.elementAt(index)) {
TextField tf = (TextField)numberField.elementAt(index);
double value = Tools.parseDouble(tf.getText());
if (!Double.isNaN(value)) {
Scrollbar sb = (Scrollbar)slider.elementAt(i);
- sb.setValue((int)(value*sliderScales[i]));
+ double scale = ((Double)sliderScales.get(i)).doubleValue();
+ sb.setValue((int)(value*scale));
}
- //IJ.log(i+" "+tf.getText());
}
}
}
@@ -1338,6 +1320,7 @@ FocusListener, ItemListener, KeyListener, AdjustmentListener, WindowListener {
public void focusGained(FocusEvent e) {
Component c = e.getComponent();
+ //IJ.log("focusGained: "+c);
if (c instanceof TextField)
((TextField)c).selectAll();
}
@@ -1366,7 +1349,6 @@ FocusListener, ItemListener, KeyListener, AdjustmentListener, WindowListener {
}
}
-
void accessTextFields() {
if (stringField!=null) {
for (int i=0; i<stringField.size(); i++)
@@ -1401,9 +1383,11 @@ FocusListener, ItemListener, KeyListener, AdjustmentListener, WindowListener {
for (int i=0; i<slider.size(); i++) {
if (source==slider.elementAt(i)) {
Scrollbar sb = (Scrollbar)source;
- TextField tf = (TextField)numberField.elementAt(sliderIndexes[i]);
- int digits = sliderScales[i]==1.0?0:2;
- tf.setText(""+IJ.d2s(sb.getValue()/sliderScales[i],digits));
+ int index = ((Integer)sliderIndexes.get(i)).intValue();
+ TextField tf = (TextField)numberField.elementAt(index);
+ double scale = ((Double)sliderScales.get(i)).doubleValue();
+ int digits = scale==1.0?0:2;
+ tf.setText(""+IJ.d2s(sb.getValue()/scale,digits));
}
}
}
@@ -1446,22 +1430,18 @@ FocusListener, ItemListener, KeyListener, AdjustmentListener, WindowListener {
((ImagePanel)imagePanels.get(i)).repaint();
}
}
-
+
public void paint(Graphics g) {
super.paint(g);
- if (firstPaint) {
- if (numberField!=null && IJ.isMacOSX()) {
- // work around for bug on Intel Macs that caused 1st field to be un-editable
- TextField tf = (TextField)(numberField.elementAt(0));
- tf.setEditable(false);
- tf.setEditable(true);
- }
- if (numberField==null && stringField==null)
- okay.requestFocus();
+ if (firstPaint && IJ.isMacOSX() && IJ.isJava18()) {
+ IJ.wait(25);
+ Dimension size = getSize();
+ if (size!=null)
+ setSize(size.width+2,size.height+2);
firstPaint = false;
}
}
-
+
public void windowClosing(WindowEvent e) {
wasCanceled = true;
dispose();
diff --git a/ij/gui/HistogramWindow.java b/ij/gui/HistogramWindow.java
index a9be888..8cd7fb2 100644
--- a/ij/gui/HistogramWindow.java
+++ b/ij/gui/HistogramWindow.java
@@ -23,7 +23,7 @@ public class HistogramWindow extends ImageWindow implements Measurements, Action
static final int BAR_HEIGHT = 12;
static final int XMARGIN = 20;
static final int YMARGIN = 10;
- static final int INTENSITY=0, RED=1, GREEN=2, BLUE=3;
+ static final int INTENSITY1=0, INTENSITY2=1, RGB=2, RED=3, GREEN=4, BLUE=5;
protected ImageStatistics stats;
protected long[] histogram;
@@ -45,7 +45,7 @@ public class HistogramWindow extends ImageWindow implements Measurements, Action
private ImagePlus srcImp; // source image for live histograms
private Thread bgThread; // thread background drawing
private boolean doUpdate; // tells background thread to update
- private int channel; // RGB channel
+ private int rgbMode = -1;
private String blankLabel;
private boolean stackHistogram;
@@ -96,19 +96,41 @@ public class HistogramWindow extends ImageWindow implements Measurements, Action
the same as the image range expect for 32 bit images. */
public void showHistogram(ImagePlus imp, int bins, double histMin, double histMax) {
boolean limitToThreshold = (Analyzer.getMeasurements()&LIMIT)!=0;
- if (channel!=INTENSITY && imp.getType()==ImagePlus.COLOR_RGB) {
+ if (imp.getBitDepth()==24 && rgbMode<INTENSITY1)
+ rgbMode=INTENSITY1;
+ if (rgbMode==RED||rgbMode==GREEN||rgbMode==BLUE) {
+ int channel = rgbMode - 2;
ColorProcessor cp = (ColorProcessor)imp.getProcessor();
ImageProcessor ip = cp.getChannel(channel, null);
ImagePlus imp2 = new ImagePlus("", ip);
imp2.setRoi(imp.getRoi());
stats = imp2.getStatistics(AREA+MEAN+MODE+MIN_MAX, bins, histMin, histMax);
- } else
+ } else if (rgbMode==RGB)
+ stats = RGBHistogram(imp, bins, histMin, histMax);
+ else
stats = imp.getStatistics(AREA+MEAN+MODE+MIN_MAX+(limitToThreshold?LIMIT:0), bins, histMin, histMax);
showHistogram(imp, stats);
}
+
+ private ImageStatistics RGBHistogram(ImagePlus imp, int bins, double histMin, double histMax) {
+ ImageProcessor ip = (ColorProcessor)imp.getProcessor();
+ ip = ip.crop();
+ int w = ip.getWidth();
+ int h = ip.getHeight();
+ ImageProcessor ip2 = new ByteProcessor(w*3, h);
+ ByteProcessor temp = null;
+ for (int i=0; i<3; i++) {
+ temp = ((ColorProcessor)ip).getChannel(i+1,temp);
+ ip2.insert(temp, i*w, 0);
+ }
+ ImagePlus imp2 = new ImagePlus("imp2", ip2);
+ return imp2.getStatistics(AREA+MEAN+MODE+MIN_MAX, bins, histMin, histMax);
+ }
/** Draws the histogram using the specified title and ImageStatistics. */
public void showHistogram(ImagePlus imp, ImageStatistics stats) {
+ if (imp.getBitDepth()==24 && rgbMode<INTENSITY1)
+ rgbMode=INTENSITY1;
stackHistogram = stats.stackStatistics;
if (list==null)
setup(imp);
@@ -180,6 +202,10 @@ public class HistogramWindow extends ImageWindow implements Measurements, Action
}
add(buttons);
pack();
+ if (IJ.isMacOSX() && IJ.isJava18()) {
+ IJ.wait(50);
+ pack();
+ }
}
public void setup() {setup(null);}
@@ -215,8 +241,7 @@ public class HistogramWindow extends ImageWindow implements Measurements, Action
int x, y;
long maxCount2 = 0;
int mode2 = 0;
- long saveModalCount;
-
+ long saveModalCount;
ip.setColor(Color.black);
ip.setLineWidth(1);
decimalPlaces = Analyzer.getPrecision();
@@ -229,10 +254,8 @@ public class HistogramWindow extends ImageWindow implements Measurements, Action
}
}
newMaxCount = histogram[stats.mode];
- if ((newMaxCount>(maxCount2 * 2)) && (maxCount2 != 0)) {
+ if ((newMaxCount>(maxCount2 * 2)) && (maxCount2 != 0))
newMaxCount = (int)(maxCount2 * 1.5);
- //histogram[stats.mode] = newMaxCount;
- }
if (logScale || IJ.shiftKeyDown() && !liveMode())
drawLogPlot(yMax>0?yMax:newMaxCount, ip);
drawPlot(yMax>0?yMax:newMaxCount, ip);
@@ -252,13 +275,13 @@ public class HistogramWindow extends ImageWindow implements Measurements, Action
ImageProcessor ipSource = imp.getProcessor();
float[] pixels = null;
ImageProcessor ipRamp = null;
- if (ipSource instanceof ColorProcessor) {
+ if (rgbMode>=INTENSITY1) {
ipRamp = new FloatProcessor(width, height);
- if (channel==RED)
+ if (rgbMode==RED)
ipRamp.setColorModel(LUT.createLutFromColor(Color.red));
- else if (channel==GREEN)
+ else if (rgbMode==GREEN)
ipRamp.setColorModel(LUT.createLutFromColor(Color.green));
- else if (channel==BLUE)
+ else if (rgbMode==BLUE)
ipRamp.setColorModel(LUT.createLutFromColor(Color.blue));
pixels = (float[])ipRamp.getPixels();
} else
@@ -370,7 +393,21 @@ public class HistogramWindow extends ImageWindow implements Measurements, Action
range = 256;
ip.drawString(d2s(hmin), x - 4, y);
ip.drawString(d2s(hmax), x + HIST_WIDTH - getWidth(hmax, ip) + 10, y);
-
+ if (rgbMode>=INTENSITY1) {
+ x += HIST_WIDTH/2;
+ y += 1;
+ ip.setJustification(ImageProcessor.CENTER_JUSTIFY);
+ boolean weighted = ((ColorProcessor)ip).weightedHistogram();
+ switch (rgbMode) {
+ case INTENSITY1: ip.drawString((weighted?"Intensity (weighted)":"Intensity (unweighted)"), x, y); break;
+ case INTENSITY2: ip.drawString((weighted?"Intensity (unweighted)":"Intensity (weighted)"), x, y); break;
+ case RGB: ip.drawString("R+G+B", x, y); break;
+ case RED: ip.drawString("Red", x, y); break;
+ case GREEN: ip.drawString("Green", x, y); break;
+ case BLUE: ip.drawString("Blue", x, y); break;
+ }
+ ip.setJustification(ImageProcessor.LEFT_JUSTIFY);
+ }
double binWidth = range/stats.nBins;
binWidth = Math.abs(binWidth);
boolean showBins = binWidth!=1.0 || !fixedRange;
@@ -396,21 +433,6 @@ public class HistogramWindow extends ImageWindow implements Measurements, Action
ip.drawString("Bin Width: " + d2s(binWidth), col2, row4);
}
}
-
- /*
- String d2s(double d) {
- if (d==Double.MAX_VALUE||d==-Double.MAX_VALUE)
- return "0";
- else if (Double.isNaN(d))
- return("NaN");
- else if (Double.isInfinite(d))
- return("Infinity");
- else if ((int)d==d)
- return ResultsTable.d2s(d,0);
- else
- return ResultsTable.d2s(d,decimalPlaces);
- }
- */
private String d2s(double d) {
if ((int)d==d)
@@ -542,23 +564,23 @@ public class HistogramWindow extends ImageWindow implements Measurements, Action
private void changeChannel() {
ImagePlus imp = WindowManager.getImage(srcImageID);
- if (imp==null || imp.getType()!=ImagePlus.COLOR_RGB) {
- channel = INTENSITY;
+ if (imp==null || imp.getType()!=ImagePlus.COLOR_RGB)
return;
- } else {
- channel++;
- if (channel>BLUE) channel=INTENSITY;
- showHistogram(imp, 256);
- String name = this.imp.getTitle();
- if (name.startsWith("Red ")) name=name.substring(4);
- else if (name.startsWith("Green ")) name=name.substring(6);
- else if (name.startsWith("Blue ")) name=name.substring(5);
- switch (channel) {
- case INTENSITY: this.imp.setTitle(name); break;
- case RED: this.imp.setTitle("Red "+name); break;
- case GREEN: this.imp.setTitle("Green "+name); break;
- case BLUE: this.imp.setTitle("Blue "+name); break;
- }
+ else {
+ rgbMode++;
+ if (rgbMode>BLUE) rgbMode=INTENSITY1;
+ ColorProcessor cp = (ColorProcessor)imp.getProcessor();
+ boolean weighted = cp.weightedHistogram();
+ if (rgbMode==INTENSITY2) {
+ double[] weights = cp.getRGBWeights();
+ if (weighted)
+ cp.setRGBWeights(1d/3d, 1d/3d, 1d/3d);
+ else
+ cp.setRGBWeights(0.299, 0.587, 0.114);
+ showHistogram(imp, 256);
+ cp.setRGBWeights(weights);
+ } else
+ showHistogram(imp, 256);
}
}
diff --git a/ij/gui/ImageCanvas.java b/ij/gui/ImageCanvas.java
index 0b3c57a..2aafa88 100644
--- a/ij/gui/ImageCanvas.java
+++ b/ij/gui/ImageCanvas.java
@@ -83,6 +83,7 @@ public class ImageCanvas extends Canvas implements MouseListener, MouseMotionLis
private boolean scaleToFit;
private boolean painted;
private boolean hideZoomIndicator;
+ private boolean flattening;
public ImageCanvas(ImagePlus imp) {
this.imp = imp;
@@ -98,7 +99,8 @@ public class ImageCanvas extends Canvas implements MouseListener, MouseMotionLis
addMouseListener(this);
addMouseMotionListener(this);
addKeyListener(ij); // ImageJ handles keyboard shortcuts
- setFocusTraversalKeysEnabled(false);
+ setFocusTraversalKeysEnabled(false);
+ //setScaleToFit(true);
}
void updateImage(ImagePlus imp) {
@@ -208,7 +210,7 @@ public class ImageCanvas extends Canvas implements MouseListener, MouseMotionLis
if (roi!=null || overlay!=null || showAllOverlay!=null || Prefs.paintDoubleBuffered) {
if (roi!=null)
roi.updatePaste();
- if (!IJ.isMacOSX() && imageWidth!=0) {
+ if (imageWidth!=0) {
paintDoubleBuffered(g);
setPaintPending(false);
return;
@@ -284,6 +286,7 @@ public class ImageCanvas extends Canvas implements MouseListener, MouseMotionLis
private void drawOverlay(Overlay overlay, Graphics g) {
if (imp!=null && imp.getHideOverlay() && overlay!=showAllOverlay)
return;
+ flattening = imp!=null && ImagePlus.flattenTitle.equals(imp.getTitle());
if (imp!=null && showAllOverlay!=null && overlay!=showAllOverlay)
overlay.drawLabels(false);
Color labelColor = overlay.getLabelColor();
@@ -458,8 +461,8 @@ public class ImageCanvas extends Canvas implements MouseListener, MouseMotionLis
labelRects[index] = new Rectangle(x2-crossSize2, y2-crossSize2, crossSize, crossSize);
} else
labelRects[index] = new Rectangle(x-3, y-h+1, w+4, h);
- }
- //if (IJ.debugMode && index==0) IJ.log("drawRoiLabel: "+drawingList+" "+label+" "+x+" "+y);
+ }
+ //IJ.log("drawRoiLabel: "+" "+label+" "+x+" "+y+" "+flattening);
g.setColor(labelColor);
g.drawString(label, x+xoffset, y-2+yoffset);
g.setColor(defaultColor);
@@ -790,6 +793,7 @@ public class ImageCanvas extends Canvas implements MouseListener, MouseMotionLis
Note that sx and sy are screen coordinates. */
public void zoomIn(int sx, int sy) {
if (magnification>=32) return;
+ scaleToFit = false;
boolean mouseMoved = sqr(sx-lastZoomSX) + sqr(sy-lastZoomSY) > MAX_MOUSEMOVE_ZOOM*MAX_MOUSEMOVE_ZOOM;
lastZoomSX = sx;
lastZoomSY = sy;
diff --git a/ij/gui/ImageWindow.java b/ij/gui/ImageWindow.java
index 8466c53..596f357 100644
--- a/ij/gui/ImageWindow.java
+++ b/ij/gui/ImageWindow.java
@@ -185,7 +185,6 @@ public class ImageWindow extends Frame implements FocusListener, WindowListener,
int screenHeight = maxWindow.y+maxWindow.height-sliderHeight;
double mag = 1;
while (xbase+width*mag>maxWindow.x+maxWindow.width || ybase+height*mag>=screenHeight) {
- //IJ.log(mag+" "+xbase+" "+width*mag+" "+maxWindow.width);
double mag2 = ImageCanvas.getLowerZoomLevel(mag);
if (mag2==mag) break;
mag = mag2;
@@ -198,14 +197,15 @@ public class ImageWindow extends Frame implements FocusListener, WindowListener,
ic.setMagnification(mag);
if (y+height*mag>screenHeight)
y = ybase;
- if (!updating) setLocation(x, y);
- if (Prefs.open100Percent && ic.getMagnification()<1.0) {
+ if (Prefs.open100Percent && ic.getMagnification()<1.0) {
while(ic.getMagnification()<1.0)
ic.zoomIn(0, 0);
setSize(Math.min(width, maxWindow.width-x), Math.min(height, screenHeight-y));
validate();
} else
pack();
+ if (!updating)
+ setLocation(x, y);
}
Rectangle getMaxWindow(int xloc, int yloc) {
@@ -380,7 +380,6 @@ public class ImageWindow extends Frame implements FocusListener, WindowListener,
}
public void paint(Graphics g) {
- //if (IJ.debugMode) IJ.log("wPaint: " + imp.getTitle());
drawInfo(g);
Rectangle r = ic.getBounds();
int extraWidth = MIN_WIDTH - r.width;
@@ -513,7 +512,6 @@ public class ImageWindow extends Frame implements FocusListener, WindowListener,
int extraHeight = insets.top+insets.bottom + 10;
if (extraHeight==20) extraHeight = 42;
int members = getComponentCount();
- //if (IJ.debugMode) IJ.log("getExtraSize: "+members+" "+insets);
for (int i=1; i<members; i++) {
Component m = getComponent(i);
Dimension d = m.getPreferredSize();
@@ -576,14 +574,12 @@ public class ImageWindow extends Frame implements FocusListener, WindowListener,
}
public void windowClosing(WindowEvent e) {
- //IJ.log("windowClosing: "+imp.getTitle()+" "+closed);
if (closed)
return;
if (ij!=null) {
WindowManager.setCurrentWindow(this);
IJ.doCommand("Close");
} else {
- //setVisible(false);
dispose();
WindowManager.removeWindow(this);
}
diff --git a/ij/gui/Line.java b/ij/gui/Line.java
index 83db8de..7ef6888 100644
--- a/ij/gui/Line.java
+++ b/ij/gui/Line.java
@@ -6,6 +6,8 @@ import ij.plugin.Straightener;
import ij.plugin.frame.Recorder;
import java.awt.*;
import java.awt.image.*;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
import java.awt.event.*;
import java.awt.geom.*;
@@ -625,5 +627,92 @@ public class Line extends Roi {
x1d=xx+x1R; y1d=yy+y1R; x2d=xx+x2R; y2d=yy+y2R;
x1=(int)x1d; y1=(int)y1d; x2=(int)x2d; y2=(int)y2d;
}
+
+ public FloatPolygon getRotationCenter() {
+ double xcenter = x1d + (x2d-x1d)/2.0;
+ double ycenter = y1d + (y2d-y1d)/2.0;
+ FloatPolygon p = new FloatPolygon();
+ p.addPoint(xcenter,ycenter);
+ return p;
+ }
+
+ /**
+ * Dedicated point iterator for thin lines.
+ * The iterator is based on (an improved version of) the algorithm used by
+ * the original method {@code ImageProcessor.getLine(double, double, double, double)}.
+ * Improvements are (a) that the endpoint is drawn too and (b) every line
+ * point is visited only once, duplicates are skipped.
+ *
+ * Author: Wilhelm Burger (04/2017)
+ */
+ public static class PointIterator implements Iterator<Point> {
+ private double x1, y1;
+ private final int n;
+ private final double xinc, yinc;
+ private double x, y;
+ private int u, v;
+ private int u_prev, v_prev;
+ private int i;
+
+ public PointIterator(Line line) {
+ this(line.x1d, line.y1d, line.x2d, line.y2d);
+ }
+
+ public PointIterator(double x1, double y1, double x2, double y2) {
+ this.x1 = x1;
+ this.y1 = y1;
+ double dx = x2 - x1;
+ double dy = y2 - y1;
+ this.n = (int) Math.ceil(Math.sqrt(dx * dx + dy * dy));
+ this.xinc = dx / n;
+ this.yinc = dy / n;
+ x = x1;
+ y = y1;
+ u = (int) Math.round(x - 0.5);
+ v = (int) Math.round(y - 0.5);
+ u_prev = Integer.MIN_VALUE;
+ v_prev = Integer.MIN_VALUE;
+ i = 0;
+ }
+
+ @Override
+ public boolean hasNext() {
+ return i <= n; // needs to be '<=' to include last segment (point)!
+ }
+
+ @Override
+ public Point next() {
+ if (i > n) throw new NoSuchElementException();
+ Point p = new Point(u, v); // the current (next) point
+ moveToNext();
+ return p;
+ }
+
+ // move to next point by skipping duplicate points
+ private void moveToNext() {
+ do {
+ i = i + 1;
+ x = x1 + i * xinc;
+ y = y1 + i * yinc;
+ u_prev = u;
+ v_prev = v;
+ u = (int) Math.round(x - 0.5);
+ v = (int) Math.round(y - 0.5);
+ } while (i <= n && u == u_prev && v == v_prev);
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ @Override
+ public Iterator<Point> iterator() {
+ if (getStrokeWidth() <= 1.0)
+ return new PointIterator(this); // use the specific thin-line iterator
+ else
+ return super.iterator(); // fall back on Roi's iterator
+ }
}
diff --git a/ij/gui/NewImage.java b/ij/gui/NewImage.java
index 9d1f037..b24524d 100644
--- a/ij/gui/NewImage.java
+++ b/ij/gui/NewImage.java
@@ -94,7 +94,7 @@ public class NewImage {
break;
case RGB: pixels2 = new int[width*height];
if (fill==FILL_RANDOM)
- fillRandomRGB(new ColorProcessor(width,height,(int[])pixels2));
+ fillRandomRGB(new ColorProcessor(width,height,(int[])pixels2), false);
break;
}
if ((fill==FILL_WHITE||fill==FILL_RAMP) || ((type==RGB)&&(fill!=FILL_RANDOM)))
@@ -194,7 +194,7 @@ public class NewImage {
}
break;
case FILL_RANDOM:
- fillRandomRGB(ip);
+ fillRandomRGB(ip, true);
break;
}
ImagePlus imp = new ImagePlus(title, ip);
@@ -205,12 +205,18 @@ public class NewImage {
return imp;
}
- private static void fillRandomRGB(ColorProcessor ip) {
+ private static void fillRandomRGB(ColorProcessor ip, boolean sp) {
ByteProcessor rr = new ByteProcessor(width, height);
ByteProcessor gg = new ByteProcessor(width, height);
ByteProcessor bb = new ByteProcessor(width, height);
- rr.add(127); gg.add(127); bb.add(127);
- rr.noise(31); gg.noise(31); bb.noise(31);
+ if (sp) IJ.showProgress(0.0);
+ rr.add(127); if (sp) IJ.showProgress(0.05);
+ gg.add(127); if (sp) IJ.showProgress(0.10);
+ bb.add(127); if (sp) IJ.showProgress(0.15);
+ rr.noise(31); if (sp) IJ.showProgress(0.40);
+ gg.noise(31); if (sp) IJ.showProgress(0.65);
+ bb.noise(31); if (sp) IJ.showProgress(0.90);
+ if (sp) IJ.showProgress(1.0);
ip.setChannel(1,rr); ip.setChannel(2,gg); ip.setChannel(3,bb);
}
diff --git a/ij/gui/Overlay.java b/ij/gui/Overlay.java
index 0ec378b..49f9067 100644
--- a/ij/gui/Overlay.java
+++ b/ij/gui/Overlay.java
@@ -4,6 +4,8 @@ import java.util.Vector;
import java.awt.geom.Rectangle2D;
import ij.*;
import ij.process.ImageProcessor;
+import ij.plugin.filter.Analyzer;
+import ij.measure.ResultsTable;
/** An Overlay is a list of ROIs that can be drawn non-destructively on an Image. */
public class Overlay {
@@ -151,6 +153,21 @@ public class Overlay {
}
}
}
+
+ /** Measures the ROIs in this overlay on the specified image
+ * and returns the results as a ResultsTable.
+ */
+ public ResultsTable measure(ImagePlus imp) {
+ ResultsTable rt = new ResultsTable();
+ for (int i=0; i<size(); i++) {
+ Roi roi = get(i);
+ imp.setRoi(roi);
+ Analyzer analyzer = new Analyzer(imp, rt);
+ analyzer.measure();
+ }
+ imp.deleteRoi();
+ return rt;
+ }
/*
* Duplicate the elements of this overlay which
diff --git a/ij/gui/Plot.java b/ij/gui/Plot.java
index 0abe1d2..b605b76 100644
--- a/ij/gui/Plot.java
+++ b/ij/gui/Plot.java
@@ -1880,7 +1880,7 @@ public class Plot implements Cloneable {
}
}
boolean haveMinorLogNumbers = i2-i1 < 2; //nunbers on log minor ticks only if < 2 decades
- if (minorTicks && (!logYAxis || step > 1.1)) { //'standard' log minor ticks only for full decades
+ if (yMin!=yMax && minorTicks && (!logYAxis || step > 1.1)) { //'standard' log minor ticks only for full decades
step = niceNumber(step*0.19); //non-log: 4 or 5 minor ticks per major tick
if (logYAxis && step < 1) step = 1;
i1 = (int)Math.ceil (Math.min(yMin,yMax)/step-1.e-10);
diff --git a/ij/gui/PlotWindow.java b/ij/gui/PlotWindow.java
index 8df48ce..182d281 100644
--- a/ij/gui/PlotWindow.java
+++ b/ij/gui/PlotWindow.java
@@ -18,7 +18,7 @@ import ij.io.SaveDialog;
* @author Michael Schmid
* @author Wayne Rasband
*/
-public class PlotWindow extends ImageWindow implements ActionListener, ItemListener,
+public class PlotWindow extends ImageWindow implements ActionListener, ItemListener,
ClipboardOwner, ImageListener, RoiListener, Runnable {
/** Display points using a circle 5 pixels in diameter. */
diff --git a/ij/gui/PointRoi.java b/ij/gui/PointRoi.java
index 887851a..d9ed01c 100644
--- a/ij/gui/PointRoi.java
+++ b/ij/gui/PointRoi.java
@@ -691,12 +691,14 @@ public class PointRoi extends PolygonRoi {
return handle;
}
- /** Returns the points as an array of Points. */
+ /** Returns the points as an array of Points.
+ * Wilhelm Burger: modified to use FloatPolygon for correct point positions.
+ */
public Point[] getContainedPoints() {
- Polygon p = getPolygon();
+ FloatPolygon p = getFloatPolygon();
Point[] points = new Point[p.npoints];
for (int i=0; i<p.npoints; i++)
- points[i] = new Point(p.xpoints[i],p.ypoints[i]);
+ points[i] = new Point((int) Math.round(p.xpoints[i] - 0.5f), (int) Math.round(p.ypoints[i] - 0.5f));
return points;
}
@@ -708,7 +710,7 @@ public class PointRoi extends PolygonRoi {
/**
* Custom iterator for points contained in a {@link PointRoi}.
* @author W. Burger
- */
+ */
public Iterator<Point> iterator() {
return new Iterator<Point>() {
final Point[] pnts = getContainedPoints();
diff --git a/ij/gui/PolygonRoi.java b/ij/gui/PolygonRoi.java
index 94c8cd1..dc0ef36 100644
--- a/ij/gui/PolygonRoi.java
+++ b/ij/gui/PolygonRoi.java
@@ -150,8 +150,6 @@ public class PolygonRoi extends Roi {
subPixel = true;
break;
}
- if (this instanceof EllipseRoi)
- subPixel = true;
x = ic.offScreenX(sx);
y = ic.offScreenY(sy);
startXD = subPixelResolution()?ic.offScreenXD(sx):x;
@@ -361,7 +359,6 @@ public class PolygonRoi extends Roi {
xp2[i] = ic.screenXD(xpf[i]+xbase+offset);
yp2[i] = ic.screenYD(ypf[i]+ybase+offset);
}
- //IJ.log(xp2[0]+" "+xpf[0]+" "+xbase+" "+offset+" "+bounds);
} else {
for (int i=0; i<nPoints; i++) {
xp2[i] = ic.screenX(xp[i]+x);
@@ -767,10 +764,10 @@ public class PolygonRoi extends Roi {
return;
int ox=ic.offScreenX(sx), oy=ic.offScreenY(sy);
double oxd=ic.offScreenXD(sx), oyd=ic.offScreenYD(sy);
- if ((IJ.altKeyDown()||IJ.controlKeyDown()) && !(nPoints<=3 && type!=POINT)) {
+ if ((IJ.altKeyDown()||IJ.controlKeyDown()) && !(nPoints<=3 && type!=POINT) && !(this instanceof RotatedRectRoi)) {
deleteHandle(oxd, oyd);
return;
- } else if (IJ.shiftKeyDown() && type!=POINT) {
+ } else if (IJ.shiftKeyDown() && type!=POINT && !(this instanceof RotatedRectRoi)) {
addHandle(oxd, oyd);
return;
}
diff --git a/ij/gui/ProgressBar.java b/ij/gui/ProgressBar.java
index 63ebff1..6cf9969 100644
--- a/ij/gui/ProgressBar.java
+++ b/ij/gui/ProgressBar.java
@@ -11,6 +11,9 @@ import java.awt.image.*;
*/
public class ProgressBar extends Canvas {
+ public static final int WIDTH = 120;
+ public static final int HEIGHT = 20;
+
private int canvasWidth, canvasHeight;
private int x, y, width, height;
private long lastTime = 0;
diff --git a/ij/gui/Roi.java b/ij/gui/Roi.java
index 974d62d..9016006 100644
--- a/ij/gui/Roi.java
+++ b/ij/gui/Roi.java
@@ -81,6 +81,7 @@ public class Roi extends Object implements Cloneable, java.io.Serializable, Iter
private String name;
private int position;
private int channel, slice, frame;
+ private boolean hyperstackPosition;
private Overlay prototypeOverlay;
private boolean subPixel;
private boolean activeOverlayRoi;
@@ -544,7 +545,7 @@ public class Roi extends Object implements Cloneable, java.io.Serializable, Iter
/** Returns the coordinates of the pixels inside this ROI as an array of Points.
* @see #getContainedFloatPoints()
- * @see #Iterator()
+ * @see #iterator()
*/
public Point[] getContainedPoints() {
if (isLine()) {
@@ -1013,18 +1014,22 @@ public class Roi extends Object implements Cloneable, java.io.Serializable, Iter
case KeyEvent.VK_UP:
height--;
if (height<1) height = 1;
+ notifyListeners(RoiListener.MODIFIED);
break;
case KeyEvent.VK_DOWN:
height++;
if ((y+height) > yMax) height = yMax-y;
+ notifyListeners(RoiListener.MODIFIED);
break;
case KeyEvent.VK_LEFT:
width--;
if (width<1) width = 1;
+ notifyListeners(RoiListener.MODIFIED);
break;
case KeyEvent.VK_RIGHT:
width++;
if ((x+width) > xMax) width = xMax-x;
+ notifyListeners(RoiListener.MODIFIED);
break;
}
updateClipRect();
@@ -1683,6 +1688,7 @@ public class Roi extends Object implements Cloneable, java.io.Serializable, Iter
if (n<0) n=0;
position = n;
channel = slice = frame = 0;
+ hyperstackPosition = false;
}
/** Returns the stack position (image number) of this ROI, or
@@ -1705,8 +1711,27 @@ public class Roi extends Object implements Cloneable, java.io.Serializable, Iter
if (frame<0) frame=0;
this.frame = frame;
position = 0;
+ hyperstackPosition = true;
+ }
+
+ /** Returns 'true' if setPosition(C,Z,T) has been called. */
+ public boolean hasHyperStackPosition() {
+ return hyperstackPosition;
}
+ /** Sets the position of this ROI based on the stack position of the specified image. */
+ public void setPosition(ImagePlus imp ) {
+ if (imp==null)
+ return;
+ if (imp.isHyperStack()) {
+ int channel = imp.getDisplayMode()==IJ.COMPOSITE?0:imp.getChannel();
+ setPosition(channel, imp.getSlice(), imp.getFrame());
+ } else if (imp.getStackSize()>1)
+ setPosition(imp.getCurrentSlice());
+ else
+ setPosition(0);
+ }
+
/** Returns the channel position of this ROI, or zero
* if this ROI is not associated with a particular channel.
*/
@@ -1718,7 +1743,7 @@ public class Roi extends Object implements Cloneable, java.io.Serializable, Iter
* if this ROI is not associated with a particular slice.
*/
public final int getZPosition() {
- return slice;
+ return slice==0&&!hyperstackPosition?position:slice;
}
/** Returns the frame position of this ROI, or zero
@@ -1875,7 +1900,6 @@ public class Roi extends Object implements Cloneable, java.io.Serializable, Iter
temp = new int[n];
for (int i=0; i<size; i++)
temp[i] = (int)arr[i];
- //temp[i] = (int)Math.floor(arr[i]+0.5);
return temp;
}
@@ -2024,20 +2048,27 @@ public class Roi extends Object implements Cloneable, java.io.Serializable, Iter
}
public ImageStatistics getStatistics() {
- ImageProcessor ip = getMask();
- Rectangle r = getBounds();
- if (ip==null)
- ip = new ByteProcessor(r.width, r.height);
- Roi roi = (Roi)this.clone();
- roi.setLocation(0.0, 0.0);
+ Roi roi = this;
+ ImageProcessor ip = null;
+ if (imp!=null)
+ ip = imp.getProcessor();
+ boolean noImage = ip==null;
+ Rectangle bounds = null;
+ if (noImage) {
+ roi = (Roi)this.clone();
+ bounds = roi.getBounds();
+ ip = new ByteProcessor(bounds.width, bounds.height);
+ roi.setLocation(0, 0);
+ }
+ if (roi.isLine())
+ roi = null;
ip.setRoi(roi);
- int params = Measurements.AREA+Measurements.CENTROID+Measurements.ELLIPSE
- +Measurements.ELLIPSE+Measurements.CIRCULARITY+Measurements.SHAPE_DESCRIPTORS
- +Measurements.PERIMETER+Measurements.RECT;
- ImageStatistics stats = ImageStatistics.getStatistics(ip, params, null);
- stats.mean = stats.min = stats.max = Double.NaN;
- stats.xCentroid += r.x;
- stats.yCentroid += r.y;
+ ImageStatistics stats = ip.getStatistics();
+ if (noImage) {
+ stats.mean = stats.min = stats.max = Double.NaN;
+ stats.xCentroid+=bounds.x; stats.yCentroid+=bounds.y;
+ }
+ ip.resetRoi();
return stats;
}
@@ -2098,7 +2129,7 @@ public class Roi extends Object implements Cloneable, java.io.Serializable, Iter
}
}
}
-
+
public static void addRoiListener(RoiListener listener) {
listeners.addElement(listener);
}
@@ -2118,53 +2149,18 @@ public class Roi extends Object implements Cloneable, java.io.Serializable, Iter
* @see #getContainedPoints()
* @see #getContainedFloatPoints()
* @author Wilhelm Burger
- */
+ */
public Iterator<Point> iterator() {
- if (isLine() && getStrokeWidth()<=1.0)
- return new RoiPointsIteratorLine();
- else
- return new RoiPointsIteratorMask();
+ // Returns the default (mask-based) point iterator. Note that 'Line' overrides the
+ // iterator() method and returns a specific point iterator.
+ return new RoiPointsIteratorMask();
}
-
- /**
- * Custom iterator over points contained in a straight line-type {@link Roi}.
- * @author W. Burger
- */
- private class RoiPointsIteratorLine implements Iterator<Point> {
- private final FloatPolygon p;
- private int next = 0;
-
- RoiPointsIteratorLine() {
- p = getInterpolatedPolygon();
- }
-
- @Override
- public boolean hasNext() {
- return next<p.npoints;
- }
-
- @Override
- public Point next() {
- if (next >= p.npoints)
- throw new NoSuchElementException();
- int x = (int)Math.round(p.xpoints[next]);
- int y = (int)Math.round(p.ypoints[next]);
- next = next + 1;
- return new Point(x, y);
- }
-
- @Override
- public void remove() {
- throw new UnsupportedOperationException();
- }
-
- }
/**
- * Custom iterator over points contained in a mask-backed {@link Roi}.
- * @author W. Burger
- */
+ * Default iterator over points contained in a mask-backed {@link Roi}.
+ * Author: W. Burger
+ */
private class RoiPointsIteratorMask implements Iterator<Point> {
private final ImageProcessor mask;
private final Rectangle bounds;
diff --git a/ij/gui/RoiProperties.java b/ij/gui/RoiProperties.java
index 6aad86d..eccbd3f 100644
--- a/ij/gui/RoiProperties.java
+++ b/ij/gui/RoiProperties.java
@@ -84,11 +84,8 @@ public class RoiProperties {
antialias = troi.getAntialiased();
}
String position = ""+roi.getPosition();
- int cpos = roi.getCPosition();
- int zpos = roi.getZPosition();
- int tpos = roi.getTPosition();
- if (cpos>0 || zpos>0 || tpos>0)
- position = cpos +","+zpos+","+tpos;
+ if (roi.hasHyperStackPosition())
+ position = roi.getCPosition() +","+roi.getZPosition()+","+ roi.getTPosition();
if (position.equals("0"))
position = "none";
String linec = Colors.colorToString(strokeColor);
@@ -253,6 +250,7 @@ public class RoiProperties {
rois[i].setFillColor(fillColor);
}
imp.draw();
+ imp.getProcessor(); // needed for corect recordering
}
if (listCoordinates) {
if (showPointCounts && (roi instanceof PointRoi))
diff --git a/ij/gui/RotatedRectRoi.java b/ij/gui/RotatedRectRoi.java
new file mode 100644
index 0000000..f7147c9
--- /dev/null
+++ b/ij/gui/RotatedRectRoi.java
@@ -0,0 +1,176 @@
+package ij.gui;
+import java.awt.*;
+import java.awt.image.*;
+import ij.*;
+import ij.plugin.frame.Recorder;
+import ij.process.FloatPolygon;
+import ij.measure.Calibration;
+
+/** This class implements the rotated rectangle selection tool. */
+public class RotatedRectRoi extends PolygonRoi {
+ private double xstart, ystart;
+ private static double DefaultRectWidth = 50;
+ private double rectWidth = DefaultRectWidth;
+
+ public RotatedRectRoi(double x1, double y1, double x2, double y2, double rectWidth) {
+ super(new float[5], new float[5], 5, FREEROI);
+ this.rectWidth = rectWidth;
+ makeRectangle(x1, y1, x2, y2);
+ state = NORMAL;
+ bounds = null;
+ }
+
+ public RotatedRectRoi(int sx, int sy, ImagePlus imp) {
+ super(sx, sy, imp);
+ type = FREEROI;
+ xstart = ic.offScreenXD(sx);
+ ystart = ic.offScreenYD(sy);
+ ImageWindow win = imp.getWindow();
+ int pixels = win!=null?(int)(win.getSize().height/win.getCanvas().getMagnification()):imp.getHeight();
+ if (rectWidth>pixels)
+ rectWidth = pixels/3;
+ setDrawOffset(false);
+ bounds = null;
+ }
+
+ public void draw(Graphics g) {
+ super.draw(g);
+ if (!overlay && ic!=null) {
+ double mag = ic.getMagnification();
+ int size2 = HANDLE_SIZE/2;
+ for (int i=0; i<4; i++)
+ drawHandle(g, hxs(i)-size2, hys(i)-size2);
+ }
+ }
+
+ private int hxs(int index) {
+ int indexPlus1 = index<3?index+1:0;
+ return xp2[index]+(xp2[indexPlus1]-xp2[index])/2;
+ }
+
+ private int hys(int index) {
+ int indexPlus1 = index<3?index+1:0;
+ return yp2[index]+(yp2[indexPlus1]-yp2[index])/2;
+ }
+
+ private double hx(int index) {
+ int indexPlus1 = index<3?index+1:0;
+ return xpf[index]+(xpf[indexPlus1]-xpf[index])/2+x;
+ }
+
+ private double hy(int index) {
+ int indexPlus1 = index<3?index+1:0;
+ return ypf[index]+(ypf[indexPlus1]-ypf[index])/2+y;
+ }
+
+ protected void grow(int sx, int sy) {
+ double x1 = xstart;
+ double y1 = ystart;
+ double x2 = ic.offScreenXD(sx);
+ double y2 = ic.offScreenYD(sy);
+ makeRectangle(x1, y1, x2, y2);
+ imp.draw();
+ }
+
+ void makeRectangle(double x1, double y1, double x2, double y2) {
+ double length = Math.sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1));
+ double angle = Math.atan ((x2-x1)/(y2-y1));
+ double wsa = (rectWidth/2.0)*Math.sin((Math.PI/2.0)+angle);
+ double wca = (rectWidth/2.0)*Math.cos((Math.PI/2)+angle);
+ nPoints = 5;
+ xpf[3] = (float)(x1-wsa);
+ ypf[3] = (float)(y1-wca);
+ xpf[0] = (float)(x1+wsa);
+ ypf[0] = (float)(y1+wca);
+ xpf[1] = (float)(x2+wsa);
+ ypf[1] = (float)(y2+wca);
+ xpf[2] = (float)(x2-wsa);
+ ypf[2] = (float)(y2-wca);
+ xpf[4] = xpf[0];
+ ypf[4] = ypf[0];
+ makePolygonRelative();
+ cachedMask = null;
+ DefaultRectWidth = rectWidth;
+ }
+
+ void makePolygonRelative() {
+ FloatPolygon poly = new FloatPolygon(xpf, ypf, nPoints);
+ Rectangle r = poly.getBounds();
+ x = r.x;
+ y = r.y;
+ width = r.width;
+ height = r.height;
+ bounds = null;
+ for (int i=0; i<nPoints; i++) {
+ xpf[i] = xpf[i]-x;
+ ypf[i] = ypf[i]-y;
+ }
+ }
+
+ protected void handleMouseUp(int screenX, int screenY) {
+ nPoints = 4;
+ state = NORMAL;
+ }
+
+ protected void moveHandle(int sx, int sy) {
+ double ox = ic.offScreenXD(sx);
+ double oy = ic.offScreenYD(sy);
+ double x1 = hx(3);
+ double y1 = hy(3);
+ double x2 = hx(1);
+ double y2 = hy(1);
+ switch(activeHandle) {
+ case 0:
+ double dx = hx(2) - ox;
+ double dy = hy(2) - oy;
+ rectWidth = Math.sqrt(dx*dx+dy*dy);
+ break;
+ case 1:
+ x2 = ox;
+ y2 = oy;
+ break;
+ case 2:
+ dx = hx(0) - ox;
+ dy = hy(0) - oy;
+ rectWidth = Math.sqrt(dx*dx+dy*dy);
+ break;
+ case 3:
+ x1 = ox;
+ y1 = oy;
+ break;
+ }
+ makeRectangle(x1, y1, x2, y2);
+ imp.draw();
+ }
+
+ public int isHandle(int sx, int sy) {
+ int size = HANDLE_SIZE+5;
+ int halfSize = size/2;
+ int index = -1;
+ for (int i=0; i<4; i++) {
+ int sx2 = (int)Math.round(hxs(i)-halfSize), sy2=(int)Math.round(hys(i)-halfSize);
+ if (sx>=sx2 && sx<=sx2+size && sy>=sy2 && sy<=sy2+size) {
+ index = i;
+ break;
+ }
+ }
+ return index;
+ }
+
+ /** Returns x1, y1, x2, y2 and width as a 5 element array. */
+ public double[] getParams() {
+ double[] params = new double[5];
+ params[0] = hx(3);
+ params[1] = hy(3);
+ params[2] = hx(1);
+ params[3] = hy(1);
+ params[4] = rectWidth;
+ return params;
+ }
+
+ /** Always returns true. */
+ public boolean subPixelResolution() {
+ return true;
+ }
+
+}
diff --git a/ij/gui/ScrollbarWithLabel.java b/ij/gui/ScrollbarWithLabel.java
index a8ec84d..3f77d06 100644
--- a/ij/gui/ScrollbarWithLabel.java
+++ b/ij/gui/ScrollbarWithLabel.java
@@ -22,7 +22,6 @@ public class ScrollbarWithLabel extends Panel implements Adjustable, AdjustmentL
super(new BorderLayout(2, 0));
this.stackWindow = stackWindow;
bar = new Scrollbar(Scrollbar.HORIZONTAL, value, visible, minimum, maximum);
- GUI.fix(bar);
icon = new Icon(label);
add(icon, BorderLayout.WEST);
add(bar, BorderLayout.CENTER);
diff --git a/ij/gui/Toolbar.java b/ij/gui/Toolbar.java
index 616b343..6613cde 100644
--- a/ij/gui/Toolbar.java
+++ b/ij/gui/Toolbar.java
@@ -5,7 +5,7 @@ import java.awt.event.*;
import java.io.File;
import java.util.*;
import ij.*;
-import ij.plugin.frame.Recorder;
+import ij.plugin.frame.Recorder;
import ij.plugin.frame.Editor;
import ij.plugin.MacroInstaller;
import ij.plugin.RectToolOptions;
@@ -41,9 +41,10 @@ public class Toolbar extends Canvas implements MouseListener, MouseMotionListene
public static final int DOUBLE_CLICK_THRESHOLD = 650;
+ 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;
- private static final String[] builtInTools = {"Arrow","Brush","Developer Menu","Flood Filler",
+ private static final String[] builtInTools = {"Arrow","Brush","Command Finder", "Developer Menu","Flood Filler",
"LUT Menu","Overlay Brush","Pencil","Pixel Inspector","Selection Rotator", "Spray Can","Stacks Menu"};
private static final String[] builtInTools2 = {"Pixel Inspection Tool","Paintbrush Tool","Flood Fill Tool"};
@@ -51,14 +52,16 @@ public class Toolbar extends Canvas implements MouseListener, MouseMotionListene
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 SIZE = 28;
+ private static final int BUTTON_WIDTH = 28;
+ private static final int BUTTON_HEIGHT = 29;
+ private static final int SIZE = 28; // no longer used
private static final int GAP_SIZE = 9;
private static final int OFFSET = 6;
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 = new Dimension(SIZE*NUM_BUTTONS-(SIZE-GAP_SIZE), SIZE);
+ private Dimension ps = new Dimension(BUTTON_WIDTH*NUM_BUTTONS-(BUTTON_WIDTH-GAP_SIZE), BUTTON_HEIGHT);
private boolean[] down;
private static int current;
private int previous;
@@ -81,7 +84,7 @@ public class Toolbar extends Canvas implements MouseListener, MouseMotionListene
private String icon;
private int startupTime;
private PopupMenu rectPopup, ovalPopup, pointPopup, linePopup, switchPopup;
- private CheckboxMenuItem rectItem, roundRectItem;
+ private CheckboxMenuItem rectItem, roundRectItem, rotatedRectItem;
private CheckboxMenuItem ovalItem, ellipseItem, brushItem;
private CheckboxMenuItem pointItem, multiPointItem;
private CheckboxMenuItem straightLineItem, polyLineItem, freeLineItem, arrowItem;
@@ -90,13 +93,14 @@ public class Toolbar extends Canvas implements MouseListener, MouseMotionListene
private static Color foregroundColor = Prefs.getColor(Prefs.FCOLOR,Color.white);
private static Color backgroundColor = Prefs.getColor(Prefs.BCOLOR,Color.black);
private static int ovalType = OVAL_ROI;
+ private static int rectType = RECT_ROI;
private static boolean multiPointMode = Prefs.multiPointMode;
- private static boolean roundRectMode;
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 BasicStroke widerLine = new BasicStroke(1.5f);
private Color gray = new Color(228,228,228);
private Color brighter = gray.brighter();
@@ -120,7 +124,7 @@ public class Toolbar extends Canvas implements MouseListener, MouseMotionListene
addMouseMotionListener(this);
instance = this;
names[getNumTools()-1] = "\"More Tools\" menu (switch toolsets or add tools)";
- icons[getNumTools()-1] = "C900T1c13>T7c13>"; // ">>"
+ icons[getNumTools()-1] = "C900T1e15>T7e15>"; // ">>"
addPopupMenus();
}
@@ -128,12 +132,15 @@ public class Toolbar extends Canvas implements MouseListener, MouseMotionListene
rectPopup = new PopupMenu();
if (Menus.getFontSize()!=0)
rectPopup.setFont(Menus.getFont());
- rectItem = new CheckboxMenuItem("Rectangle Tool", !roundRectMode);
+ rectItem = new CheckboxMenuItem("Rectangle", rectType==RECT_ROI);
rectItem.addItemListener(this);
rectPopup.add(rectItem);
- roundRectItem = new CheckboxMenuItem("Rounded Rectangle Tool", roundRectMode);
+ 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 = new PopupMenu();
@@ -221,6 +228,7 @@ public class Toolbar extends Canvas implements MouseListener, MouseMotionListene
Graphics2D g2d = (Graphics2D)g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
+ //g2d.setStroke(widerLine);
}
for (int i=0; i<LINE; i++)
drawButton(g, i);
@@ -255,29 +263,31 @@ public class Toolbar extends Canvas implements MouseListener, MouseMotionListene
return;
}
int index = toolIndex(tool);
- int x = index*SIZE + 1;
+ int x = index*BUTTON_WIDTH + 1;
if (tool>=CUSTOM1)
- x -= SIZE-GAP_SIZE;
+ x -= BUTTON_WIDTH-GAP_SIZE;
if (tool!=UNUSED)
- fill3DRect(g, x, 1, SIZE, SIZE-1, !down[tool]);
+ fill3DRect(g, x, 1, BUTTON_WIDTH, BUTTON_HEIGHT-1, !down[tool]);
g.setColor(toolColor);
- x = index*SIZE + OFFSET;
+ x = index*BUTTON_WIDTH + OFFSET;
if (tool>=CUSTOM1)
- x -= SIZE-GAP_SIZE;
+ x -= BUTTON_WIDTH-GAP_SIZE;
int y = OFFSET;
if (down[tool]) { x++; y++;}
this.g = g;
if (tool>=CUSTOM1 && tool<=getNumTools() && icons[tool]!=null) {
- drawIcon(g, tool, x, y);
+ drawIcon(g, tool, x+1, y+1);
return;
}
switch (tool) {
case RECTANGLE:
xOffset = x; yOffset = y;
- if (roundRectMode)
- g.drawRoundRect(x, y+1, 17, 13, 8, 8);
+ if (rectType==ROUNDED_RECT_ROI)
+ g.drawRoundRect(x-1, y+1, 17, 13, 8, 8);
+ else if (rectType==ROTATED_RECT_ROI)
+ polyline(0,10,7,0,15,6,8,16,0,10);
else
- g.drawRect(x, y+1, 17, 13);
+ g.drawRect(x-1, y+1, 17, 13);
drawTriangle(16,15);
return;
case OVAL:
@@ -286,6 +296,7 @@ public class Toolbar extends Canvas implements MouseListener, MouseMotionListene
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
@@ -294,10 +305,10 @@ public class Toolbar extends Canvas implements MouseListener, MouseMotionListene
return;
case POLYGON:
xOffset = x+1; yOffset = y+2;
- polyline(4,0,15,0,15,1,11,5,11,6,14,10,14,11,0,11,0,4,4,0);
+ 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+2;
+ 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:
@@ -308,17 +319,17 @@ public class Toolbar extends Canvas implements MouseListener, MouseMotionListene
m(0,12); d(17,3);
drawDot(0,11); drawDot(17,2);
}
- drawTriangle(12,14);
+ drawTriangle(15,15);
return;
case POLYLINE:
xOffset = x; yOffset = y;
polyline(15,6,11,2,1,2,1,3,7,9,2,14);
- drawTriangle(12,14);
+ drawTriangle(13,15);
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(12,14);
+ drawTriangle(13,15);
return;
case POINT:
xOffset = x; yOffset = y;
@@ -332,7 +343,7 @@ public class Toolbar extends Canvas implements MouseListener, MouseMotionListene
g.setColor(Roi.getColor());
g.fillRect(x+7, y+7, 3, 3);
}
- drawTriangle(14,14);
+ drawTriangle(15,15);
return;
case WAND:
xOffset = x+2; yOffset = y+1;
@@ -370,7 +381,7 @@ public class Toolbar extends Canvas implements MouseListener, MouseMotionListene
polyline(10,7,12,7,12,9);
polyline(8,7,2,13,2,15,4,15,11,8);
g.setColor(backgroundColor);
- polyline(-1,-1,18,-1,18,17,-1,17,-1,-1);
+ polyline(-1,-1,18,-1,18,18,-1,18,-1,-1);
return;
case ANGLE:
xOffset = x; yOffset = y+2;
@@ -463,7 +474,7 @@ public class Toolbar extends Canvas implements MouseListener, MouseMotionListene
}
if (menus[tool]!=null && menus[tool].getItemCount()>0) {
xOffset = x; yOffset = y;
- drawTriangle(14, 14);
+ drawTriangle(15, 15);
}
}
@@ -511,10 +522,12 @@ public class Toolbar extends Canvas implements MouseListener, MouseMotionListene
String hint2 = " (right click to switch; double click to configure)";
switch (tool) {
case RECTANGLE:
- if (roundRectMode)
- IJ.showStatus("Rectangular or *rounded rectangular* selections"+hint);
+ if (rectType==ROUNDED_RECT_ROI)
+ IJ.showStatus("Rectangle, *rounded rect* or rotated rect"+hint);
+ else if (rectType==ROTATED_RECT_ROI)
+ IJ.showStatus("Rectangle, rounded rect or *rotated rect*"+hint);
else
- IJ.showStatus("*Rectangular* or rounded rectangular selections"+hint);
+ IJ.showStatus("*Rectangle*, rounded rect or rotated rect"+hint);
return;
case OVAL:
if (ovalType==BRUSH_ROI)
@@ -621,10 +634,13 @@ public class Toolbar extends Canvas implements MouseListener, MouseMotionListene
name = name.toLowerCase(Locale.US);
boolean ok = true;
if (name.indexOf("round")!=-1) {
- roundRectMode = true;
+ rectType = ROUNDED_RECT_ROI;
+ setTool(RECTANGLE);
+ } else if (name.indexOf("rot")!=-1) {
+ rectType = ROTATED_RECT_ROI;
setTool(RECTANGLE);
} else if (name.indexOf("rect")!=-1) {
- roundRectMode = false;
+ rectType = RECT_ROI;
setTool(RECTANGLE);
} else if (name.indexOf("oval")!=-1) {
ovalType = OVAL_ROI;
@@ -685,7 +701,12 @@ public class Toolbar extends Canvas implements MouseListener, MouseMotionListene
/** Returns the name of the specified tool. */
String getName(int id) {
switch (id) {
- case RECTANGLE: return roundRectMode?"roundrect":"rectangle";
+ case RECTANGLE:
+ switch (rectType) {
+ case RECT_ROI: return "rectangle";
+ case ROUNDED_RECT_ROI: return "roundrect";
+ case ROTATED_RECT_ROI: return "rotrect";
+ }
case OVAL:
switch (ovalType) {
case OVAL_ROI: return "oval";
@@ -749,7 +770,10 @@ public class Toolbar extends Canvas implements MouseListener, MouseMotionListene
previous = current;
if (Recorder.record) {
String name = getName(current);
- if (name!=null) Recorder.record("setTool", name);
+ if (name!=null) {
+ IJ.wait(100); // workaround for OSX/Java 8 bug
+ Recorder.record("setTool", name);
+ }
}
if (legacyMode)
repaint();
@@ -842,16 +866,16 @@ public class Toolbar extends Canvas implements MouseListener, MouseMotionListene
/** Returns the rounded rectangle arc size, or 0 if the rounded rectangle tool is not enabled. */
public static int getRoundRectArcSize() {
- if (!roundRectMode)
- return 0;
- else
+ 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)
- roundRectMode = false;
+ rectType = RECT_ROI;
else {
arcSize = size;
Prefs.set(CORNER_DIAMETER, arcSize);
@@ -860,7 +884,7 @@ public class Toolbar extends Canvas implements MouseListener, MouseMotionListene
ImagePlus imp = WindowManager.getCurrentImage();
Roi roi = imp!=null?imp.getRoi():null;
if (roi!=null && roi.getType()==Roi.RECTANGLE)
- roi.setCornerDiameter(roundRectMode?arcSize:0);
+ roi.setCornerDiameter(rectType==ROUNDED_RECT_ROI?arcSize:0);
}
/** Returns 'true' if the multi-point tool is enabled. */
@@ -868,13 +892,19 @@ public class Toolbar extends Canvas implements MouseListener, MouseMotionListene
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 SIZE;
+ return BUTTON_WIDTH;
}
static void repaintTool(int tool) {
@@ -888,8 +918,6 @@ public class Toolbar extends Canvas implements MouseListener, MouseMotionListene
tb.drawButton(g, tool);
if (g!=null) g.dispose();
}
- //Toolbar tb = getInstance();
- //tb.repaint(tool * SIZE , 0, SIZE, SIZE);
}
// Returns the toolbar position index of the specified tool
@@ -916,9 +944,9 @@ public class Toolbar extends Canvas implements MouseListener, MouseMotionListene
// Returns the tool corresponding to the specified x coordinate
private int toolID(int x) {
- if (x>SIZE*12+GAP_SIZE)
+ if (x>BUTTON_WIDTH*12+GAP_SIZE)
x -= GAP_SIZE;
- int index = x/SIZE;
+ int index = x/BUTTON_WIDTH;
switch (index) {
case 0: return RECTANGLE;
case 1: return OVAL;
@@ -937,7 +965,7 @@ public class Toolbar extends Canvas implements MouseListener, MouseMotionListene
}
private boolean inGap(int x) {
- return x>=(SIZE*12) && x<(SIZE*12+GAP_SIZE);
+ return x>=(BUTTON_WIDTH*12) && x<(BUTTON_WIDTH*12+GAP_SIZE);
}
public void mousePressed(MouseEvent e) {
@@ -982,8 +1010,9 @@ public class Toolbar extends Canvas implements MouseListener, MouseMotionListene
setTool2(newTool);
boolean isRightClick = e.isPopupTrigger()||e.isMetaDown();
if (current==RECTANGLE && isRightClick) {
- rectItem.setState(!roundRectMode);
- roundRectItem.setState(roundRectMode);
+ 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;
@@ -1032,7 +1061,7 @@ public class Toolbar extends Canvas implements MouseListener, MouseMotionListene
ImagePlus imp = WindowManager.getCurrentImage();
switch (current) {
case RECTANGLE:
- if (roundRectMode)
+ if (rectType==ROUNDED_RECT_ROI)
IJ.doCommand("Rounded Rect Tool...");
break;
case OVAL:
@@ -1210,14 +1239,19 @@ public class Toolbar extends Canvas implements MouseListener, MouseMotionListene
public void itemStateChanged(ItemEvent e) {
CheckboxMenuItem item = (CheckboxMenuItem)e.getSource();
String previousName = getToolName();
- if (item==rectItem || item==roundRectItem) {
- roundRectMode = item==roundRectItem;
+ if (item==rectItem || item==roundRectItem || item==rotatedRectItem) {
+ if (item==roundRectItem)
+ rectType = ROUNDED_RECT_ROI;
+ else if (item==rotatedRectItem)
+ rectType = ROTATED_RECT_ROI;
+ else
+ rectType = RECT_ROI;
repaintTool(RECTANGLE);
showMessage(RECTANGLE);
ImagePlus imp = WindowManager.getCurrentImage();
Roi roi = imp!=null?imp.getRoi():null;
if (roi!=null && roi.getType()==Roi.RECTANGLE)
- roi.setCornerDiameter(roundRectMode?arcSize:0);
+ roi.setCornerDiameter(rectType==ROUNDED_RECT_ROI?arcSize:0);
if (!previousName.equals(getToolName()))
IJ.notifyEventListeners(IJEventListener.TOOL_CHANGED);
} else if (item==ovalItem || item==ellipseItem || item==brushItem) {
@@ -1341,7 +1375,7 @@ public class Toolbar extends Canvas implements MouseListener, MouseMotionListene
nExtraTools = 0;
names[getNumTools()-1] = name;
icons[getNumTools()-1] = icon;
- ps = new Dimension(SIZE*NUM_BUTTONS-(SIZE-GAP_SIZE)+nExtraTools*SIZE, SIZE);
+ ps = new Dimension(BUTTON_WIDTH*NUM_BUTTONS-(BUTTON_WIDTH-GAP_SIZE)+nExtraTools*BUTTON_WIDTH, BUTTON_HEIGHT);
IJ.getInstance().pack();
}
}
@@ -1442,7 +1476,7 @@ public class Toolbar extends Canvas implements MouseListener, MouseMotionListene
icons[getNumTools()-1] = icons[getNumTools()-2];
names[getNumTools()-2] = null;
icons[getNumTools()-2] = null;
- ps = new Dimension(SIZE*NUM_BUTTONS-(SIZE-GAP_SIZE)+nExtraTools*SIZE, SIZE);
+ ps = new Dimension(BUTTON_WIDTH*NUM_BUTTONS-(BUTTON_WIDTH-GAP_SIZE)+nExtraTools*BUTTON_WIDTH, BUTTON_HEIGHT);
IJ.getInstance().pack();
tool = getNumTools()-2;
}
@@ -1736,6 +1770,8 @@ public class Toolbar extends Canvas implements MouseListener, MouseMotionListene
(new MacroInstaller()).installFromIJJar("/macros/StacksMenuTool.txt");
} else if (label.startsWith("LUT Menu")) {
(new MacroInstaller()).installFromIJJar("/macros/LUTMenuTool.txt");
+ } else if (label.startsWith("Command Finder")) {
+ (new MacroInstaller()).installFromIJJar("/macros/CommandFinderTool.txt");
} else
ok = false;
return ok;
diff --git a/ij/gui/YesNoCancelDialog.java b/ij/gui/YesNoCancelDialog.java
index 8088225..2a7c273 100644
--- a/ij/gui/YesNoCancelDialog.java
+++ b/ij/gui/YesNoCancelDialog.java
@@ -11,6 +11,10 @@ public class YesNoCancelDialog extends Dialog implements ActionListener, KeyList
private boolean firstPaint = true;
public YesNoCancelDialog(Frame parent, String title, String msg) {
+ this(parent, title, msg, " Yes ", " No ");
+ }
+
+ public YesNoCancelDialog(Frame parent, String title, String msg, String yesLabel, String noLabel) {
super(parent, title, true);
setLayout(new BorderLayout());
Panel panel = new Panel();
@@ -27,8 +31,8 @@ public class YesNoCancelDialog extends Dialog implements ActionListener, KeyList
noB = new Button("Don't Save");
cancelB = new Button(" Cancel ");
} else {
- yesB = new Button(" Yes ");
- noB = new Button(" No ");
+ yesB = new Button(yesLabel);
+ noB = new Button(noLabel);
cancelB = new Button(" Cancel ");
}
yesB.addActionListener(this);
diff --git a/ij/io/FileOpener.java b/ij/io/FileOpener.java
index 8dec36c..fa17780 100644
--- a/ij/io/FileOpener.java
+++ b/ij/io/FileOpener.java
@@ -327,7 +327,7 @@ public class FileOpener {
Calibration cal = imp.getCalibration();
boolean calibrated = false;
if (fi.pixelWidth>0.0 && fi.unit!=null) {
- if (fi.pixelWidth<=0.0001 && fi.unit.equals("cm")) {
+ if (Prefs.convertToMicrons && fi.pixelWidth<=0.0001 && fi.unit.equals("cm")) {
fi.pixelWidth *= 10000.0;
fi.pixelHeight *= 10000.0;
if (fi.pixelDepth!=1.0)
@@ -447,7 +447,7 @@ public class FileOpener {
else if (fi.url!=null && !fi.url.equals(""))
is = new URL(fi.url+fi.fileName).openStream();
else {
- if (fi.directory.length()>0 && !fi.directory.endsWith(Prefs.separator))
+ if (fi.directory.length()>0 && !(fi.directory.endsWith(Prefs.separator)||fi.directory.endsWith("/")))
fi.directory += Prefs.separator;
File f = new File(fi.directory + fi.fileName);
if (gzip) fi.compression = FileInfo.COMPRESSION_UNKNOWN;
diff --git a/ij/io/ImageReader.java b/ij/io/ImageReader.java
index 624bbe6..cd7e656 100644
--- a/ij/io/ImageReader.java
+++ b/ij/io/ImageReader.java
@@ -262,7 +262,6 @@ public class ImageReader {
int base = 0;
float last = 0;
for (int k=0; k<fi.stripOffsets.length; k++) {
- //IJ.log("seek: "+fi.stripOffsets[k]+" "+(in instanceof RandomAccessStream));
if (in instanceof RandomAccessStream)
((RandomAccessStream)in).seek(fi.stripOffsets[k]);
else if (k > 0) {
@@ -877,7 +876,7 @@ public class ImageReader {
return readPixels(is);
}
- byte[] uncompress(byte[] input) {
+ private byte[] uncompress(byte[] input) {
if (fi.compression==FileInfo.PACK_BITS)
return packBitsUncompress(input, fi.rowsPerStrip*fi.width*fi.getBytesPerPixel());
else if (fi.compression==FileInfo.LZW || fi.compression==FileInfo.LZW_WITH_DIFFERENCING)
diff --git a/ij/io/Opener.java b/ij/io/Opener.java
index 758b7a8..9e575f8 100644
--- a/ij/io/Opener.java
+++ b/ij/io/Opener.java
@@ -14,9 +14,8 @@ import java.awt.image.*;
import java.io.*;
import java.net.URL;
import java.net.*;
-import java.util.Hashtable;
+import java.util.*;
import java.util.zip.*;
-import java.util.Locale;
import javax.swing.*;
import javax.swing.filechooser.*;
import java.awt.event.KeyEvent;
@@ -92,7 +91,7 @@ public class Opener {
(new PluginInstaller()).install(path);
return;
}
- boolean fullPath = path.startsWith("/") || path.startsWith("\\") || path.indexOf(":\\")==1 || isURL;
+ boolean fullPath = path.startsWith("/") || path.startsWith("\\") || path.indexOf(":\\")==1 || path.indexOf(":/")==1 || isURL;
if (!fullPath) {
String defaultDir = OpenDialog.getDefaultDirectory();
if (defaultDir!=null)
@@ -1239,7 +1238,7 @@ public class Opener {
return OJJ;
// Results table (tab-delimited or comma-separated tabular text)
- if (name.endsWith(".xls") || name.endsWith(".csv"))
+ if (name.endsWith(".xls") || name.endsWith(".csv") || name.endsWith(".tsv"))
return TABLE;
// AVI
@@ -1319,5 +1318,5 @@ public class Opener {
public static boolean getOpenUsingPlugins() {
return openUsingPlugins;
}
-
+
}
diff --git a/ij/io/RoiDecoder.java b/ij/io/RoiDecoder.java
index 8566bdd..ccccc63 100644
--- a/ij/io/RoiDecoder.java
+++ b/ij/io/RoiDecoder.java
@@ -59,7 +59,7 @@ public class RoiDecoder {
public static final int SUBTYPE = 48;
public static final int OPTIONS = 50;
public static final int ARROW_STYLE = 52;
- public static final int ELLIPSE_ASPECT_RATIO = 52;
+ public static final int FLOAT_PARAM = 52; //ellipse ratio or rotated rect width
public static final int POINT_TYPE= 52;
public static final int ARROW_HEAD_SIZE = 53;
public static final int ROUNDED_RECT_ARC_SIZE = 54;
@@ -87,6 +87,7 @@ public class RoiDecoder {
public static final int ARROW = 2;
public static final int ELLIPSE = 3;
public static final int IMAGE = 4;
+ public static final int ROTATED_RECT = 5;
// options
public static final int SPLINE_FIT = 1;
@@ -296,13 +297,16 @@ public class RoiDecoder {
roiType = Roi.POLYGON;
else if (type==freehand) {
roiType = Roi.FREEROI;
- if (subtype==ELLIPSE) {
+ if (subtype==ELLIPSE || subtype==ROTATED_RECT) {
double ex1 = getFloat(X1);
double ey1 = getFloat(Y1);
double ex2 = getFloat(X2);
double ey2 = getFloat(Y2);
- double aspectRatio = getFloat(ELLIPSE_ASPECT_RATIO);
- roi = new EllipseRoi(ex1,ey1,ex2,ey2,aspectRatio);
+ double param = getFloat(FLOAT_PARAM);
+ if (subtype==ROTATED_RECT)
+ roi = new RotatedRectRoi(ex1,ey1,ex2,ey2,param);
+ else
+ roi = new EllipseRoi(ex1,ey1,ex2,ey2,param);
break;
}
} else if (type==traced)
diff --git a/ij/io/RoiEncoder.java b/ij/io/RoiEncoder.java
index 97ea647..928bd65 100644
--- a/ij/io/RoiEncoder.java
+++ b/ij/io/RoiEncoder.java
@@ -204,14 +204,20 @@ public class RoiEncoder {
putShort(RoiDecoder.STROKE_WIDTH, point.getSize());
}
- if (roi instanceof EllipseRoi) {
- putShort(RoiDecoder.SUBTYPE, RoiDecoder.ELLIPSE);
- double[] p = ((EllipseRoi)roi).getParams();
+ if (roi instanceof RotatedRectRoi || roi instanceof EllipseRoi) {
+ double[] p = null;
+ if (roi instanceof RotatedRectRoi) {
+ putShort(RoiDecoder.SUBTYPE, RoiDecoder.ROTATED_RECT);
+ p = ((RotatedRectRoi)roi).getParams();
+ } else {
+ putShort(RoiDecoder.SUBTYPE, RoiDecoder.ELLIPSE);
+ p = ((EllipseRoi)roi).getParams();
+ }
putFloat(RoiDecoder.X1, (float)p[0]);
putFloat(RoiDecoder.Y1, (float)p[1]);
putFloat(RoiDecoder.X2, (float)p[2]);
putFloat(RoiDecoder.Y2, (float)p[3]);
- putFloat(RoiDecoder.ELLIPSE_ASPECT_RATIO, (float)p[4]);
+ putFloat(RoiDecoder.FLOAT_PARAM, (float)p[4]);
}
// save stroke width, stroke color and fill color (1.43i or later)
@@ -364,7 +370,7 @@ public class RoiEncoder {
//ij.IJ.log("putHeader2: "+hdr2Offset+" "+roiNameSize+" "+roiName);
putInt(RoiDecoder.HEADER2_OFFSET, hdr2Offset);
putInt(hdr2Offset+RoiDecoder.C_POSITION, roi.getCPosition());
- putInt(hdr2Offset+RoiDecoder.Z_POSITION, roi.getZPosition());
+ putInt(hdr2Offset+RoiDecoder.Z_POSITION, roi.hasHyperStackPosition()?roi.getZPosition():0);
putInt(hdr2Offset+RoiDecoder.T_POSITION, roi.getTPosition());
Overlay proto = roi.getPrototypeOverlay();
Color overlayLabelColor = proto.getLabelColor();
diff --git a/ij/io/TiffDecoder.java b/ij/io/TiffDecoder.java
index 9258a27..7420c03 100644
--- a/ij/io/TiffDecoder.java
+++ b/ij/io/TiffDecoder.java
@@ -194,12 +194,13 @@ public class TiffDecoder {
decode an IFD for each image. */
public void saveImageDescription(byte[] description, FileInfo fi) {
String id = new String(description);
- if (!id.startsWith("ImageJ"))
+ boolean createdByImageJ = id.startsWith("ImageJ");
+ if (!createdByImageJ)
saveMetadata(getName(IMAGE_DESCRIPTION), id);
if (id.length()<7) return;
fi.description = id;
int index1 = id.indexOf("images=");
- if (index1>0) {
+ if (index1>0 && createdByImageJ) {
int index2 = id.indexOf("\n", index1);
if (index2>0) {
String images = id.substring(index1+7,index2);
diff --git a/ij/macro/Functions.java b/ij/macro/Functions.java
index ca35e1f..aa7329f 100644
--- a/ij/macro/Functions.java
+++ b/ij/macro/Functions.java
@@ -1068,18 +1068,22 @@ public class Functions implements MacroConstants, Measurements {
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.indexOf("seed")==-1)
- interp.error("'seed' expected");
- interp.getComma();
- dseed = interp.getExpression();
- long seed = (long)dseed;
- if (seed!=dseed)
- interp.error("Seed not integer");
- ran = new Random(seed);
+ 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);
+ } else if (arg.equals("gaussian"))
+ gaussian = true;
+ else
+ interp.error("'seed' or ''gaussian' expected");
}
interp.getRightParen();
if (!Double.isNaN(dseed)) return Double.NaN;
@@ -1087,7 +1091,10 @@ public class Functions implements MacroConstants, Measurements {
interp.getParens();
if (ran==null)
ran = new Random();
- return ran.nextDouble();
+ if (gaussian)
+ return ran.nextGaussian();
+ else
+ return ran.nextDouble();
}
//void setSeed() {
@@ -1244,11 +1251,19 @@ public class Functions implements MacroConstants, Measurements {
}
double getBoolean() {
- String prompt = getStringArg();
+ 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);
+ YesNoCancelDialog d = new YesNoCancelDialog(IJ.getInstance(), title, prompt, yesButton, noButton);
if (d.cancelPressed()) {
interp.done = true;
return 0.0;
@@ -2292,7 +2307,6 @@ public class Functions implements MacroConstants, Measurements {
float size = (float)getFirstArg();
int style = -1;
if (interp.nextToken()!=')') {
- interp.getComma();
String options = getNextString().toLowerCase();
style = 0;
if (options.indexOf("bold") >= 0)
@@ -3244,8 +3258,11 @@ public class Functions implements MacroConstants, Measurements {
TextWindow tw = (TextWindow)frame;
if (isCommand)
handleTextWindowCommand(tw, s2);
- else
+ else {
tw.append(s2);
+ TextPanel tp = tw.getTextPanel();
+ if (tp!=null) tp.setResultsTable(null);
+ }
}
}
@@ -3712,9 +3729,13 @@ public class Functions implements MacroConstants, Measurements {
metadata = (String)imp.getProperty("Info");
} else
metadata = imp.getStack().getSliceLabel(imp.getCurrentSlice());
- } else
+ } else {
metadata = (String)imp.getProperty("Info");
- if (metadata==null) metadata = "";
+ if (metadata==null && imp.getStackSize()>1)
+ metadata = imp.getStack().getSliceLabel(imp.getCurrentSlice());
+ }
+ if (metadata==null)
+ metadata = "";
return metadata;
}
@@ -4180,6 +4201,8 @@ public class Functions implements MacroConstants, Measurements {
Analyzer.setMeasurement(AREA, state);
else if (arg1.equals("mean"))
Analyzer.setMeasurement(MEAN, state);
+ else if (arg1.startsWith("perim"))
+ Analyzer.setMeasurement(PERIMETER, state);
else if (arg1.equals("stack position"))
Analyzer.setMeasurement(STACK_POSITION, state);
else if (arg1.startsWith("std"))
@@ -4202,6 +4225,10 @@ public class Functions implements MacroConstants, Measurements {
Prefs.autoContrast = state;
else if (arg1.equals("antialiasedtext"))
TextRoi.setAntialiasedText(state);
+ else if (arg1.equals("savebatchoutput"))
+ BatchProcessor.saveOutput(state);
+ else if (arg1.startsWith("converttomicrons"))
+ Prefs.convertToMicrons = state;
else
interp.error("Invalid option");
}
@@ -5244,6 +5271,10 @@ public class Functions implements MacroConstants, Measurements {
return showArray();
else if (name.equals("fourier"))
return fourierArray();
+ else if (name.equals("getVertexAngles"))
+ return getVertexAngles();
+ else if (name.equals("rotate"))
+ return rotateArray();
else
interp.error("Unrecognized Array function");
return null;
@@ -5561,16 +5592,33 @@ public class Functions implements MacroConstants, Measurements {
return a;
}
+ Variable[] rotateArray() {
+ interp.getLeftParen();
+ Variable[] a = getArray();
+ interp.getComma();
+ int rot = (int) interp.getExpression();
+ interp.getRightParen();
+ int len = a.length;
+ while(rot<0)
+ rot += len;
+ Variable[] b = new Variable[len];
+ for (int i=0; i<len; i++) {
+ int dest = (i + rot)%len;
+ b[dest] = a[i];
+ }
+ for (int i=0; i<len; i++)
+ a[i]= b[i];
+ return a;
+ }
+
Variable[] findArrayMaxima(boolean minima) {
- boolean excludeOnEdges = false;
+ int edgeMode = 0;
interp.getLeftParen();
Variable[] a = getArray();
double tolerance = getNextArg();
if (interp.nextToken()==',') {
interp.getComma();
- double arg = interp.getBooleanExpression();
- interp.checkBoolean(arg);
- excludeOnEdges = arg==0?false:true;
+ edgeMode = (int)interp.getExpression();
}
interp.getRightParen();
int n = a.length;
@@ -5579,15 +5627,49 @@ public class Functions implements MacroConstants, Measurements {
d[i] = a[i].getValue();
int[] maxima = null;
if (minima)
- maxima = MaximumFinder.findMinima(d, tolerance, excludeOnEdges);
+ maxima = MaximumFinder.findMinima(d, tolerance, edgeMode);
else
- maxima = MaximumFinder.findMaxima(d, tolerance, excludeOnEdges);
+ maxima = MaximumFinder.findMaxima(d, tolerance, edgeMode);
int n2 = maxima.length;
Variable[] a2 = new Variable[n2];
for (int i=0; i<n2; i++)
a2[i] = new Variable(maxima[i]);
return a2;
}
+
+ Variable[] getVertexAngles() {
+ interp.getLeftParen();
+ Variable[] xx = getArray();
+ interp.getComma();
+ Variable[] yy = getArray();
+ interp.getComma();
+ int arm = (int) interp.getExpression();
+ int len = xx.length;
+ if (yy.length != len)
+ interp.error("Same size expected");
+ double[] x = new double[len];
+ double[] y = new double[len];
+ double[] vAngles = new double[len];
+ interp.getRightParen();
+ Variable[] a2 = new Variable[len];
+ for (int jj = 0; jj < len; jj++) {
+ x[jj] = xx[jj].getValue();
+ y[jj] = yy[jj].getValue();
+ }
+ for (int mid = 0; mid < len; mid++) {
+ int left = (mid + 10 * len - arm) % len;
+ int right = (mid + arm) % len;
+ double dotprod = (x[right] - x[mid]) * (x[left] - x[mid]) + (y[right] - y[mid]) * (y[left] - y[mid]);
+ double crossprod = (x[right] - x[mid]) * (y[left] - y[mid]) - (y[right] - y[mid]) * (x[left] - x[mid]);
+ double phi = 180.0 - 180.0 / Math.PI * Math.atan2(crossprod, dotprod);
+ while (phi >= 180.0)
+ phi -= 360.0;
+ vAngles[mid] = phi;
+ }
+ for (int i = 0; i < len; i++)
+ a2[i] = new Variable(vAngles[i]);
+ return a2;
+ }
Variable[] showArray() {
int maxLength = 0;
@@ -5804,16 +5886,14 @@ public class Functions implements MacroConstants, Measurements {
if (roi==null)
return Double.NaN;;
if (imp.getStackSize()>1) {
- if (imp.isHyperStack()) {
+ if (imp.isHyperStack() && roi.hasHyperStackPosition()) {
int c = roi.getCPosition();
int z = roi.getZPosition();
int t = roi.getTPosition();
- if (c>0 || z>0 || t>0) {
- c = c>0?c:imp.getChannel();
- z = z>0?z:imp.getSlice();
- t = t>0?t:imp.getFrame();
- imp.setPosition(c, z, t);
- }
+ 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());
}
@@ -5828,6 +5908,9 @@ public class Functions implements MacroConstants, Measurements {
roi.setLocation(x, y);
imp.draw();
return Double.NaN;
+ } else if (name.equals("measure")) {
+ ResultsTable rt = overlay.measure(imp);
+ rt.show("Results");
} else
interp.error("Unrecognized function name");
return Double.NaN;
@@ -6204,7 +6287,7 @@ public class Functions implements MacroConstants, Measurements {
String properties = roi.getProperties();
return properties!=null?properties:"";
} else if (name.equals("setFillColor")) {
- roi.setFillColor(Colors.decode(getStringArg(),null));
+ roi.setFillColor(getRoiColor());
imp.draw();
return null;
} else if (name.equals("move")) {
@@ -6214,7 +6297,7 @@ public class Functions implements MacroConstants, Measurements {
roi.setName(getStringArg());
return null;
} else if (name.equals("setStrokeColor")) {
- roi.setStrokeColor(Colors.decode(getStringArg(),null));
+ roi.setStrokeColor(getRoiColor());
imp.draw();
return null;
} else if (name.equals("setStrokeWidth")) {
@@ -6225,6 +6308,8 @@ public class Functions implements MacroConstants, Measurements {
String value = "1";
interp.getLeftParen();
String key = getString();
+ if (key.contains(" "))
+ interp.error("Keys contain a space");
if (interp.nextToken()==',') {
interp.getComma();
value = getString();
@@ -6245,6 +6330,52 @@ public class Functions implements MacroConstants, Measurements {
return null;
}
+ /*
+ private String getRoiPosition(Roi roi) {
+ Variable channel = getFirstVariable();
+ Variable slice = getNextVariable();
+ Variable frame = getLastVariable();
+ int c = roi.getCPosition();
+ int z = roi.getZPosition();
+ int t = roi.getTPosition();
+ channel.setValue(c);
+ slice.setValue(z);
+ frame.setValue(t);
+ return null;
+ }
+
+ private String setRoiPosition(ImagePlus imp, Roi roi) {
+ int channel = (int)getFirstArg();
+ int slice = (int)getNextArg();
+ int frame = (int)getLastArg();
+ if (channel<=1 && frame<=1 && !imp.isHyperStack())
+ roi.setPosition(slice);
+ else
+ roi.setPosition(channel, slice, frame);
+ return null;
+ }
+ */
+
+ private Color getRoiColor() {
+ interp.getLeftParen();
+ if (isStringArg()) {
+ Color color = Colors.decode(getString(),null);
+ interp.getRightParen();
+ return color;
+ } else {
+ int r = (int)interp.getExpression();
+ if (interp.nextToken()==')') {
+ interp.getRightParen();
+ return new Color(r);
+ }
+ int g = (int)getNextArg();
+ int b = (int)getLastArg();
+ if (r<0) r=0; if (g<0) g=0; if (b<0) b=0;
+ if (r>255) r=255; if (g>255) g=255; if (b>255) b=255;
+ return new Color(r, g, b);
+ }
+ }
+
private void getContainedPoints(Roi roi) {
Variable xCoordinates = getFirstArrayVariable();
Variable yCoordinates = getLastArrayVariable();
diff --git a/ij/macro/Interpreter.java b/ij/macro/Interpreter.java
index d67eac8..d30708d 100644
--- a/ij/macro/Interpreter.java
+++ b/ij/macro/Interpreter.java
@@ -67,6 +67,7 @@ public class Interpreter implements MacroConstants {
static TextWindow arrayWindow;
int inspectStkIndex = -1;
int inspectSymIndex = -1;
+ boolean evaluating;
/** Interprets the specified string. */
@@ -111,11 +112,23 @@ public class Interpreter implements MacroConstants {
if (func==null)
func = new Functions(this, pgm);
func.plot = null;
- //IJ.showStatus("interpreting");
doStatements();
finishUp();
}
+ /** Evaluates macro code. */
+ /*
+ public void eval(String macro) {
+ Tokenizer tok = new Tokenizer();
+ this.pgm = tok.tokenize(macro);
+ evaluating = true;
+ pushGlobals();
+ if (func==null)
+ func = new Functions(this, pgm);
+ run(0);
+ }
+ */
+
/** Runs an existing macro starting at the specified program counter location. */
public void run(int location) {
topOfStack = topOfGlobals;
@@ -1178,7 +1191,8 @@ public class Interpreter implements MacroConstants {
imageTable = null;
WindowManager.setTempCurrentImage(null);
wasError = true;
- instance = null;
+ if (!evaluating)
+ instance = null;
if (showMessage && message!=null) {
String line = getErrorLine();
done = true;
diff --git a/ij/measure/ResultsTable.java b/ij/measure/ResultsTable.java
index 98877ed..8554270 100644
--- a/ij/measure/ResultsTable.java
+++ b/ij/measure/ResultsTable.java
@@ -437,9 +437,8 @@ public class ResultsTable implements Cloneable {
if (column==null)
throw new IllegalArgumentException("Column is null");
int col = getColumnIndex(column);
- if (col==COLUMN_NOT_FOUND) {
+ if (col==COLUMN_NOT_FOUND)
col = getFreeColumn(column);
- }
setValue(col, row, value);
}
@@ -829,7 +828,7 @@ public class ResultsTable implements Cloneable {
TextWindow win;
if (frame!=null && frame instanceof TextWindow) {
win = (TextWindow)frame;
- if (windowTitle==null || !windowTitle.startsWith("Counts_"))
+ if (!IJ.isMacro() && (windowTitle==null || !windowTitle.startsWith("Counts_")))
win.toFront();
} else {
int width = getLastColumn()<=0?250:400;
@@ -1129,5 +1128,7 @@ public class ResultsTable implements Cloneable {
public String toString() {
return ("ctr="+counter+", hdr="+getColumnHeadings());
}
+
+
}
diff --git a/ij/plugin/AVI_Reader.java b/ij/plugin/AVI_Reader.java
index de13bf9..1e31e53 100644
--- a/ij/plugin/AVI_Reader.java
+++ b/ij/plugin/AVI_Reader.java
@@ -92,9 +92,13 @@ import javax.imageio.ImageIO;
* - can read MJPG files where the frames don't have the same pixel number as the overall video
* 2015-09-28
* - reads most ImageJ AVI1 files with size>4 GB (incorrectly written by ImageJ versions before 1.50b)
+ * 2017-04-21
+ * - bugfix: file was not closed in case of dialog cancelled or some IO errors.
+ * - Tries to recover data from truncated files.
+ *
*
* The AVI format looks like this:
- * RIFF AVI RIFF HEADER, AVI CHUNK
+ * RIFF AVI RIFF HEADER, AVI CHUNK
* | LIST hdrl MAIN AVI HEADER
* | | avih AVI HEADER
* | | LIST strl STREAM LIST(s) (One per stream)
@@ -171,7 +175,7 @@ public class AVI_Reader extends VirtualStack implements PlugIn {
private final static int YV12_COMPRESSION = 0x32315659; //'YV12' - y plane followed by 2x2 subsampled V and U
private final static int NV12_COMPRESSION = 0x3231564E; //'NV12' - y plane followed by 2x2 subsampled interleaved U, V
private final static int NV21_COMPRESSION = 0x3132564E; //'NV21' - y plane followed by 2x2 subsampled interleaved V, U
-
+
private final static int JPEG_COMPRESSION = 0x6765706a; //'jpeg' JPEG compression of individual frames
private final static int JPEG_COMPRESSION2 = 0x4745504a; //'JPEG' JPEG compression of individual frames
private final static int JPEG_COMPRESSION3 = 0x04; //BI_JPEG: JPEG compression of individual frames
@@ -184,7 +188,7 @@ public class AVI_Reader extends VirtualStack implements PlugIn {
private final static long SIZE_MASK = 0xffffffffL; //for conversion of sizes from unsigned int to long
private final static long FOUR_GB = 0x100000000L; //2^32; above this size of data AVI 1 has a problem for sure
- // flags from AVI chunk header
+ // flags from AVI chunk header
private final static int AVIF_HASINDEX = 0x00000010; // Index at end of file?
private final static int AVIF_MUSTUSEINDEX = 0x00000020; // ignored by this plugin
private final static int AVIF_ISINTERLEAVED= 0x00000100; // ignored by this plugin
@@ -230,7 +234,7 @@ public class AVI_Reader extends VirtualStack implements PlugIn {
private ColorModel cm;
private boolean variableLength; //compressed (PNG, JPEG) frames have variable length
//for conversion to ImageJ stack
- private Vector<long[]> frameInfos; //for virtual stack: long[] with frame pos&size in file, time(usec)
+ private Vector<long[]> frameInfos; //for virtual stack: long[] with frame pos&size in file, time(usec)
private ImageStack stack;
private ImagePlus imp;
//for debug messages and error handling
@@ -238,6 +242,7 @@ public class AVI_Reader extends VirtualStack implements PlugIn {
private long startTime;
private boolean aborting;
private boolean displayDialog = true;
+ private String errorText; //error occurred during makeStack, or null
//From AVI Header Chunk
private int dwMicroSecPerFrame;
@@ -299,25 +304,28 @@ public class AVI_Reader extends VirtualStack implements PlugIn {
} catch (Exception e) {
error(exceptionMessage(e));
return;
+ } finally {
+ closeFile(raFile);
}
- if (displayDialog && !showDialog(fileName))
- return; //ask for parameters
- try {
- ImageStack stack = makeStack(path, firstFrame, lastFrame, isVirtual, convertToGray, flipVertical); //read data
- } catch (Exception e) {
- error(exceptionMessage(e));
- return;
- }
- if (stack==null || aborting || (stack.isVirtual()&&stack.getProcessor(1)==null))
+ if (displayDialog && !showDialog(fileName)) //ask for parameters
return;
- if (stack.getSize() == 0) {
- String rangeText = "";
- if (firstFrame>1 || lastFrame!=0)
- rangeText = "\nin Range "+firstFrame+
- (lastFrame>0 ? " - "+lastFrame : " - end");
- error("Error: No Frames Found"+rangeText);
+ errorText = null;
+ ImageStack stack = makeStack(path, firstFrame, lastFrame, isVirtual, convertToGray, flipVertical); //read data
+ if (aborting)
+ return; //error message has been shown already
+ if (stack==null || stack.getSize() == 0 || stack.getProcessor(1)==null) { //read nothing?
+ if (errorText != null)
+ error(errorText);
+ else {
+ String rangeText = "";
+ if (firstFrame > 1 || (lastFrame != 0 && lastFrame != dwTotalFrames))
+ rangeText = "\nin Range "+firstFrame+
+ (lastFrame>0 ? " - "+lastFrame : " - end");
+ error("Error: No Frames Found"+rangeText);
+ }
return;
- }
+ } else if (errorText != null)
+ IJ.showMessage("AVI Reader", errorText); //show the error, e.g. we may have an incomplete stack
imp = new ImagePlus(WindowManager.makeUniqueName(fileName), stack);
if (imp.getBitDepth()==16)
imp.getProcessor().resetMinAndMax();
@@ -335,7 +343,7 @@ public class AVI_Reader extends VirtualStack implements PlugIn {
public ImagePlus getImagePlus() {
return imp;
}
-
+
/** Opens an AVI file as a virtual stack. The ImagePlus is not displayed. */
public static ImagePlus openVirtual(String path) {
return open(path, true);
@@ -357,8 +365,10 @@ public class AVI_Reader extends VirtualStack implements PlugIn {
* @param lastFrame Number of last frame to read or 0 for reading all, -1 for all but last...
* @param isVirtual Whether to return a virtual stack
* @param convertToGray Whether to convert color images to grayscale
- * @return Returns the stack; null on failure.
- * The stack returned may be non-null, but have a length of zero if no suitable frames were found
+ * @return Returns the stack (may be incomplete on error); null on failure.
+ * The stack returned may be non-null, but have a length of zero if no suitable frames were found.
+ * Use <code>getErrorText</code> to determine whether there has been an error reading the file.
+ * For virtual stacks, not that I/O errors may also occur later, when reading the frames.
*/
public ImageStack makeStack (String path, int firstFrame, int lastFrame,
boolean isVirtual, boolean convertToGray, boolean flipVertical) {
@@ -367,37 +377,37 @@ public class AVI_Reader extends VirtualStack implements PlugIn {
this.isVirtual = isVirtual;
this.convertToGray = convertToGray;
this.flipVertical = flipVertical;
- String exceptionMessage = null;
IJ.showProgress(.001);
try {
readAVI(path);
} catch (OutOfMemoryError e) {
stack.trim();
- IJ.showMessage("AVI Reader", "Out of memory. " + stack.getSize() + " of " + dwTotalFrames + " frames will be opened.");
+ errorText = "Out of memory. " + stack.getSize() + " of " + dwTotalFrames + " frames will be opened.";
} catch (Exception e) {
- exceptionMessage = exceptionMessage(e);
+ errorText = exceptionMessage(e);
+ if (isVirtual || stack==null || stack.getSize()==0) //return null only if we have really nothing
+ return null;
} finally {
- try {
- raFile.close();
- if (verbose)
- IJ.log("File closed.");
- } catch (Exception e) {}
+ closeFile(raFile);
+ if (verbose)
+ IJ.log("File closed.");
IJ.showProgress(1.0);
}
- if (exceptionMessage != null) {
- error(exceptionMessage);
- return null;
- }
if (isVirtual && frameInfos != null)
stack = this;
if (stack!=null && cm!=null)
stack.setColorModel(cm);
return stack;
- }
+ }
+
+ /** Returns a description of the error reading the file with <code>makeStack</code> or null if no error */
+ public String getErrorText() {
+ return errorText;
+ }
/** Returns an ImageProcessor for the specified slice of this virtual stack (if it is one)
- where 1<=n<=nslices. Returns null if no virtual stack or no slices.
- */
+ * where 1<=n<=nslices. Returns null if no virtual stack or no slices or error reading the frame.
+ */
public synchronized ImageProcessor getProcessor(int n) {
if (frameInfos==null || frameInfos.size()==0 || raFilePath==null)
return null;
@@ -405,21 +415,15 @@ public class AVI_Reader extends VirtualStack implements PlugIn {
throw new IllegalArgumentException("Argument out of range: "+n);
Object pixels = null;
RandomAccessFile rFile = null;
- String exceptionMessage = null;
try {
rFile = new RandomAccessFile(new File(raFilePath), "r");
long[] frameInfo = (long[])(frameInfos.get(n-1));
pixels = readFrame(rFile, frameInfo[0], (int)frameInfo[1]);
} catch (Exception e) {
- exceptionMessage = exceptionMessage(e);
- } finally {
- try {
- rFile.close();
- } catch (Exception e) {}
- }
- if (exceptionMessage != null) {
- error(exceptionMessage);
+ error(exceptionMessage(e));
return null;
+ } finally {
+ closeFile(rFile);
}
if (pixels == null) return null; //failed
if (pixels instanceof byte[])
@@ -496,9 +500,12 @@ public class AVI_Reader extends VirtualStack implements PlugIn {
/** Read into a (virtual) stack */
private void readAVI(String path) throws Exception, IOException {
-
if (!headerOK) // we have not read the header yet?
openAndReadHeader(path);
+ else {
+ File file = new File(path); // open if currently not open
+ raFile = new RandomAccessFile(file, "r");
+ }
startTime += System.currentTimeMillis();// taking previously elapsed time into account
/** MOVED UP HERE BY JSP*/
if (lastFrame > 0) // last frame number to read: from Dialog
@@ -617,9 +624,13 @@ public class AVI_Reader extends VirtualStack implements PlugIn {
long size = readInt() & SIZE_MASK;
nextPos = raFile.getFilePointer() + size;
- if (nextPos>fileSize || nextPos>endPosition) {
- IJ.log("AVI File Error: '"+fourccString(type)+"' @ 0x"+Long.toHexString(raFile.getFilePointer()-8)+" has invalid length");
- return -1;
+ if (nextPos>endPosition || nextPos>fileSize) {
+ errorText = "AVI File Error: '"+fourccString(type)+"' @ 0x"+Long.toHexString(raFile.getFilePointer()-8)+" has invalid length. File damaged/truncated?";
+ IJ.log(errorText); // this text is also remembered as error message for showing in message box
+ if (fourcc == FOURCC_movi)
+ nextPos = fileSize; // if movie data truncated, try reading what we can get
+ else
+ return -1; // otherwise, nothing to be done
}
if (isList && type == FOURCC_LIST)
type = readInt();
@@ -1011,7 +1022,7 @@ public class AVI_Reader extends VirtualStack implements PlugIn {
if (isPlanarFormat && ((biWidth&1)!=0 || (biHeight&1)!=0))
throw new Exception("Odd size ("+biWidth+"x"+biHeight+") unsupported with "+fourccString(biCompression)+" compression");
// raw & interleaved YUV: scan line is padded with zeroes to be a multiple of four bytes
- scanLineSize = isPlanarFormat ?
+ scanLineSize = isPlanarFormat ?
(biWidth * biBitCount) / 8 : ((biWidth * biBitCount + 31) / 32) * 4;
// a value of biClrUsed=0 means we determine this based on the bits per pixel, if there is a palette
@@ -1397,7 +1408,14 @@ public class AVI_Reader extends VirtualStack implements PlugIn {
}
return s;
}
-
+
+ /** tries to close the given file (if not null) */
+ private void closeFile(RandomAccessFile rFile) {
+ if (rFile != null) try {
+ rFile.close();
+ } catch (Exception e) {}
+ }
+
private void error(String msg) {
aborting = true;
IJ.error("AVI Reader", msg);
@@ -1548,9 +1566,9 @@ public class AVI_Reader extends VirtualStack implements PlugIn {
readableSize += HUFFMAN_LENGTH;
}
}
-
+
public void displayDialog(boolean displayDialog) {
this.displayDialog = displayDialog;
}
-
+
}
diff --git a/ij/plugin/BatchProcessor.java b/ij/plugin/BatchProcessor.java
index 73daf58..7dd008f 100644
--- a/ij/plugin/BatchProcessor.java
+++ b/ij/plugin/BatchProcessor.java
@@ -15,6 +15,7 @@ import java.util.Vector;
private static final String MACRO_FILE_NAME = "BatchMacro.ijm";
private static final String[] formats = {"TIFF", "8-bit TIFF", "JPEG", "GIF", "PNG", "PGM", "BMP", "FITS", "Text Image", "ZIP", "Raw"};
private static String format = Prefs.get("batch.format", formats[0]);
+
private static final String[] code = {
"[Select from list]",
"Add Border",
@@ -32,6 +33,22 @@ import java.util.Vector;
"Show File Info",
"Unsharp Mask",
};
+
+ private static final String help = "<html>"
+ +"<h1>Process>Batch>Virtual Stack</h1>"
+ +"<font size=+1>"
+ +"This command runs macro code on each image in a virtual stack.<br>"
+ +"The processed images are saved in the <i>Output</i> folder,<br>"
+ +"in the specified <i>Format</i>, allowing them to be opened as a<br>"
+ +"virtual stack. Make sure the <i>Output</i> folder is empty<br>"
+ +"before clicking on <i>Process</i>.<br>"
+ +"<br>"
+ +"In the macro code, the 'i' (index) and 'n' (stack size) variables<br>"
+ +"are predefined. Call <i>setOption('SaveBatchOutput',false)</i> to<br>"
+ +"prevent the image currently being processed from being saved,<br>"
+ +"effectively removing it from the output virtual stack.<br> <br>"
+ +"</font>";
+
private String macro = "";
private int testImage;
private Button input, output, open, save, test;
@@ -42,6 +59,7 @@ import java.util.Vector;
private ImagePlus outputImage;
private boolean errorDisplayed;
private String filter;
+ private static boolean saveOutput = true;
public void run(String arg) {
if (arg.equals("stack")) {
@@ -105,9 +123,9 @@ import java.util.Vector;
gd = new NonBlockingGenericDialog("Batch Process");
addPanels(gd);
gd.setInsets(15, 0, 5);
- gd.addChoice("Output Format:", formats, format);
+ gd.addChoice("Output format:", formats, format);
gd.setInsets(0, 0, 5);
- gd.addChoice("Add Macro Code:", code, code[0]);
+ gd.addChoice("Add macro code:", code, code[0]);
if (virtualStack==null)
gd.addStringField("File name contains:", "", 10);
gd.setInsets(15, 10, 0);
@@ -117,6 +135,8 @@ import java.util.Vector;
gd.setOKLabel("Process");
Vector choices = gd.getChoices();
Choice choice = (Choice)choices.elementAt(1);
+ if (virtualStack!=null)
+ gd.addHelp(help);
choice.addItemListener(this);
gd.showDialog();
format = gd.getNextChoice();
@@ -135,12 +155,12 @@ import java.util.Vector;
IJ.showProgress(i, n);
ImageProcessor ip = stack.getProcessor(i);
if (ip==null) return;
- ImagePlus imp = new ImagePlus("", ip);
+ ImagePlus imp = new ImagePlus(i+"/"+stack.getSize(), ip);
if (!macro.equals("")) {
- if (!runMacro("i="+(index++)+";"+macro, imp))
+ if (!runMacro("i="+(index++)+";"+"n="+stack.getSize()+";"+macro, imp))
break;
}
- if (!outputPath.equals("")) {
+ if (saveOutput && !outputPath.equals("")) {
if (format.equals("8-bit TIFF") || format.equals("GIF")) {
if (imp.getBitDepth()==24)
IJ.run(imp, "8-bit Color", "number=256");
@@ -149,6 +169,7 @@ import java.util.Vector;
}
IJ.saveAs(imp, format, outputPath+pad(i));
}
+ saveOutput = true;
imp.close();
}
if (outputPath!=null && !outputPath.equals(""))
@@ -195,7 +216,7 @@ import java.util.Vector;
if (!runMacro("i="+(index++)+";"+macro, imp))
break;
}
- if (!outputPath.equals("")) {
+ if (saveOutput && !outputPath.equals("")) {
if (format.equals("8-bit TIFF") || format.equals("GIF")) {
if (imp.getBitDepth()==24)
IJ.run(imp, "8-bit Color", "number=256");
@@ -207,6 +228,7 @@ import java.util.Vector;
else
IJ.saveAs(imp, format, outputPath+list[i]);
}
+ saveOutput = true;
imp.close();
}
}
@@ -454,6 +476,9 @@ import java.util.Vector;
OpenDialog.setLastDirectory(f.getParent()+File.separator);
OpenDialog.setLastName(f.getName());
}
-
+
+ public static void saveOutput(boolean b) {
+ saveOutput = b;
+ }
}
diff --git a/ij/plugin/Binner.java b/ij/plugin/Binner.java
index b8c3e7f..c7255e0 100644
--- a/ij/plugin/Binner.java
+++ b/ij/plugin/Binner.java
@@ -65,7 +65,7 @@ public class Binner implements PlugIn {
}
if (zshrink>1 && !imp.isHyperStack())
stack2 = shrinkZ(stack2, zshrink);
- ImagePlus imp2 = (ImagePlus)imp.clone();
+ ImagePlus imp2 = imp.createImagePlus();
imp2.setStack("Reduced "+imp.getShortTitle(), stack2);
Calibration cal2 = imp2.getCalibration();
if (cal2.scaled()) {
diff --git a/ij/plugin/CalibrationBar.java b/ij/plugin/CalibrationBar.java
index 3c3b7a1..55737b7 100644
--- a/ij/plugin/CalibrationBar.java
+++ b/ij/plugin/CalibrationBar.java
@@ -56,7 +56,8 @@ public class CalibrationBar implements PlugIn {
int userPadding = 0;
int fontHeight = 0;
boolean boldText;
- boolean flatten;
+ static boolean staticFlatten;
+ boolean flatten = staticFlatten;
Object backupPixels;
byte[] byteStorage;
int[] intStorage;
@@ -166,6 +167,8 @@ public class CalibrationBar implements PlugIn {
zoom = (double)gd.getNextNumber();
boldText = gd.getNextBoolean();
flatten = !gd.getNextBoolean();
+ if (!IJ.isMacro())
+ staticFlatten = flatten;
return true;
}
diff --git a/ij/plugin/ChannelArranger.java b/ij/plugin/ChannelArranger.java
index c70f3d0..3ffce6a 100644
--- a/ij/plugin/ChannelArranger.java
+++ b/ij/plugin/ChannelArranger.java
@@ -131,10 +131,8 @@ public class ChannelArranger implements PlugIn, TextListener {
}
img2.setOverlay(overlay);
}
- if (img.getWindow()!=null) {
- img.changes = false;
- img.close();
- }
+ img.changes = false;
+ img.close();
return img2;
}
diff --git a/ij/plugin/Colors.java b/ij/plugin/Colors.java
index 81a7d42..74ea655 100644
--- a/ij/plugin/Colors.java
+++ b/ij/plugin/Colors.java
@@ -229,5 +229,5 @@ public class Colors implements PlugIn, ItemListener {
names.add(arg);
return (String[])names.toArray(new String[names.size()]);
}
-
+
}
diff --git a/ij/plugin/Converter.java b/ij/plugin/Converter.java
index 2be8ebe..4a68a1f 100644
--- a/ij/plugin/Converter.java
+++ b/ij/plugin/Converter.java
@@ -15,8 +15,12 @@ public class Converter implements PlugIn {
imp = WindowManager.getCurrentImage();
if (imp!=null) {
if (imp.isComposite() && arg.equals("RGB Color") && !imp.getStack().isRGB() && !imp.getStack().isHSB() && !imp.getStack().isLab()) {
- (new RGBStackConverter()).run("");
- imp.setTitle(imp.getTitle()); // updates size in Window menu
+ if (imp.getWindow()==null && !ij.macro.Interpreter.isBatchMode())
+ RGBStackConverter.convertToRGB(imp);
+ else {
+ (new RGBStackConverter()).run("");
+ imp.setTitle(imp.getTitle()); // updates size in Window menu
+ }
} else if (imp.lock()) {
convert(arg);
imp.unlock();
diff --git a/ij/plugin/Duplicator.java b/ij/plugin/Duplicator.java
index 2fd327b..f4c4fcb 100644
--- a/ij/plugin/Duplicator.java
+++ b/ij/plugin/Duplicator.java
@@ -162,6 +162,9 @@ public class Duplicator implements PlugIn, TextListener, ItemListener {
if (roi!=null && roi.isArea())
rect = roi.getBounds();
ImageStack stack = imp.getStack();
+ boolean virtualStack = stack.isVirtual();
+ double min = imp.getDisplayRangeMin();
+ double max = imp.getDisplayRangeMax();
ImageStack stack2 = null;
for (int i=firstSlice; i<=lastSlice; i++) {
if (stack.isVirtual())
@@ -184,6 +187,8 @@ public class Duplicator implements PlugIn, TextListener, ItemListener {
imp2.setDimensions(1, 1, size);
else
imp2.setDimensions(1, size, 1);
+ if (virtualStack)
+ imp2.setDisplayRange(min, max);
Overlay overlay = imp.getOverlay();
if (overlay!=null && !imp.getHideOverlay()) {
Overlay overlay2 = overlay.crop(rect);
diff --git a/ij/plugin/FileInfoVirtualStack.java b/ij/plugin/FileInfoVirtualStack.java
index fa634c0..77244b4 100644
--- a/ij/plugin/FileInfoVirtualStack.java
+++ b/ij/plugin/FileInfoVirtualStack.java
@@ -234,5 +234,5 @@ public class FileInfoVirtualStack extends VirtualStack implements PlugIn {
}
info[nImages-1] = fileInfo;
}
-
- }
+
+}
diff --git a/ij/plugin/FolderOpener.java b/ij/plugin/FolderOpener.java
index e466fa1..9c05b18 100644
--- a/ij/plugin/FolderOpener.java
+++ b/ij/plugin/FolderOpener.java
@@ -3,6 +3,7 @@ import java.awt.*;
import java.io.*;
import java.awt.event.*;
import java.awt.image.ColorModel;
+import java.util.Properties;
import ij.*;
import ij.io.*;
import ij.gui.*;
@@ -305,6 +306,11 @@ public class FolderOpener implements PlugIn {
fi.directory = directory;
imp2.setFileInfo(fi); // saves FileInfo of the first image
imp2.setOverlay(overlay);
+ if (stack instanceof VirtualStack) {
+ Properties props = ((VirtualStack)stack).getProperties();
+ if (props!=null)
+ imp2.setProperty("FHT", props.get("FHT"));
+ }
if (allSameCalibration) {
// use calibration from first image
if (scale!=100.0 && cal.scaled()) {
diff --git a/ij/plugin/Grid.java b/ij/plugin/Grid.java
index 3dc8bd8..348647e 100644
--- a/ij/plugin/Grid.java
+++ b/ij/plugin/Grid.java
@@ -32,6 +32,8 @@ public class Grid implements PlugIn, DialogListener {
private String color = "Cyan";
private boolean bold;
private boolean randomOffset;
+ private boolean centered;
+ private Checkbox centerCheckbox, randomCheckbox;
public void run(String arg) {
imp = IJ.getImage();
@@ -169,8 +171,14 @@ public class Grid implements PlugIn, DialogListener {
gd.addNumericField("Area per point:", areaPerPoint, places, 6, units+"^2");
gd.addChoice("Color:", colors, color);
gd.addCheckbox("Bold", bold);
+ gd.addCheckbox("Center grid on image", centered);
gd.addCheckbox("Random offset", randomOffset);
gd.addDialogListener(this);
+ if (!isMacro) {
+ Vector v = gd.getCheckboxes();
+ centerCheckbox = (Checkbox)v.elementAt(1);
+ randomCheckbox = (Checkbox)v.elementAt(2);
+ }
dialogItemChanged(gd, null);
gd.showDialog();
if (gd.wasCanceled()) {
@@ -193,7 +201,13 @@ public class Grid implements PlugIn, DialogListener {
areaPerPoint = gd.getNextNumber();
color = gd.getNextChoice();
bold = gd.getNextBoolean();
+ centered = gd.getNextBoolean();
randomOffset = gd.getNextBoolean();
+ if (randomOffset) {
+ centered = false;
+ if (centerCheckbox!=null)
+ centerCheckbox.setState(false);
+ }
double minArea= (width*height)/50000.0;
if (type.equals(types[CROSSES])&&minArea<50.0)
minArea = 50.0;
@@ -210,7 +224,10 @@ public class Grid implements PlugIn, DialogListener {
double tileSize = Math.sqrt(areaPerPoint);
tileWidth = tileSize/pixelWidth;
tileHeight = tileSize/pixelHeight;
- if (randomOffset) {
+ if (centered) {
+ xstart = (int)Math.round((width%tileWidth)/2.0);
+ ystart = (int)Math.round((height%tileHeight)/2.0);
+ } else if (randomOffset) {
xstart = (int)(random.nextDouble()*tileWidth);
ystart = (int)(random.nextDouble()*tileHeight);
} else {
@@ -222,10 +239,11 @@ public class Grid implements PlugIn, DialogListener {
if (gd.invalidNumber())
return true;
drawGrid();
- return true;
+ return true;
}
private void drawGrid() {
+ //IJ.log(centered+" "+xstart+" "+ystart);
if (type.equals(types[LINES]))
drawLines();
else if (type.equals(types[HLINES]))
@@ -242,6 +260,7 @@ public class Grid implements PlugIn, DialogListener {
private void getSettings() {
String prefs = Prefs.get(OPTIONS, "Lines,Cyan,-");
+ //IJ.log("options: "+prefs);
String[] options = Tools.split(prefs, ",");
if (options.length>=3) {
type = options[0];
@@ -250,13 +269,19 @@ public class Grid implements PlugIn, DialogListener {
areaPerPoint = saveAreaPerPoint;
color = options[1];
bold = options[2].contains("bold");
+ centered = options[2].contains("centered");
randomOffset = options[2].contains("random");
+ if (centered)
+ randomOffset = false;
}
}
private void saveSettings() {
- String options = type+","+color+","+(bold?"bold":"")+" "+(randomOffset?"random":"");
- Prefs.set(OPTIONS, options);
+ String options = type+","+color+",";
+ String options2 = (bold?"bold ":"")+(centered?"centered ":"")+(randomOffset?"random ":"");
+ if (options2.length()==0)
+ options2 = "-";
+ Prefs.set(OPTIONS, options+options2);
saveAreaPerPoint = areaPerPoint;
}
diff --git a/ij/plugin/GroupedZProjector.java b/ij/plugin/GroupedZProjector.java
index 1991843..ea6f72c 100644
--- a/ij/plugin/GroupedZProjector.java
+++ b/ij/plugin/GroupedZProjector.java
@@ -35,14 +35,26 @@ public class GroupedZProjector implements PlugIn {
if (method<0 || method>=ZProjector.METHODS.length)
return null;
int[] dim = imp.getDimensions();
- imp.setDimensions(1, groupSize, imp.getStackSize()/groupSize);
+ int projectedStackSize = imp.getStackSize()/groupSize;
+ imp.setDimensions(1, groupSize, projectedStackSize);
ZProjector zp = new ZProjector(imp);
zp.setMethod(method);
zp.setStartSlice(1);
zp.setStopSlice(groupSize);
zp.doHyperStackProjection(true);
imp.setDimensions(dim[2], dim[3], dim[4]);
- return zp.getProjection();
+
+ ImagePlus zProjectorOutput = zp.getProjection();
+ int[] zProjectDim = zProjectorOutput.getDimensions();
+ for (int i=2; i<dim.length; i++) {
+ if (dim[i] != 1)
+ zProjectDim[i] = projectedStackSize;
+ else
+ zProjectDim[i] = 1;
+ }
+ // Fix dimensions for output ImagePlus
+ zProjectorOutput.setDimensions(zProjectDim[2], zProjectDim[3], zProjectDim[4]);
+ return zProjectorOutput;
}
boolean showDialog(ImagePlus imp) {
diff --git a/ij/plugin/HyperStackConverter.java b/ij/plugin/HyperStackConverter.java
index 86b937d..6514af6 100644
--- a/ij/plugin/HyperStackConverter.java
+++ b/ij/plugin/HyperStackConverter.java
@@ -86,7 +86,7 @@ public class HyperStackConverter implements PlugIn {
return imp2;
}
- /** Displays the current stack in a HyperStack window. Based on the
+ /** Displays the specified stack in a HyperStack window. Based on the
Stack_to_Image5D class in Joachim Walter's Image5D plugin. */
void convertStackToHS(ImagePlus imp) {
int nChannels = imp.getNChannels();
diff --git a/ij/plugin/ImageInfo.java b/ij/plugin/ImageInfo.java
index 106579a..ed612e2 100644
--- a/ij/plugin/ImageInfo.java
+++ b/ij/plugin/ImageInfo.java
@@ -274,6 +274,9 @@ public class ImageInfo implements PlugIn {
double mag = ic!=null?ic.getMagnification():1.0;
if (mag!=1.0)
s += "Magnification: " + IJ.d2s(mag,2) + "\n";
+ if (ic!=null)
+ s += "ScaleToFit: " + ic.getScaleToFit() + "\n";
+
if (cal.calibrated()) {
s += " \n";
@@ -344,6 +347,18 @@ public class ImageInfo implements PlugIn {
if (cal.calibrated())
s += " \n";
s += "No selection\n";
+ } else if (roi instanceof RotatedRectRoi) {
+ s += "\nRotated rectangle selection\n";
+ double[] p = ((RotatedRectRoi)roi).getParams();
+ double dx = p[2] - p[0];
+ double dy = p[3] - p[1];
+ double major = Math.sqrt(dx*dx+dy*dy);
+ s += " Length: " + IJ.d2s(major,2) + "\n";
+ s += " Width: " + IJ.d2s(p[4],2) + "\n";
+ s += " X1: " + IJ.d2s(p[0],2) + "\n";
+ s += " Y1: " + IJ.d2s(p[1],2) + "\n";
+ s += " X2: " + IJ.d2s(p[2],2) + "\n";
+ s += " Y2: " + IJ.d2s(p[3],2) + "\n";
} else if (roi instanceof EllipseRoi) {
s += "\nElliptical selection\n";
double[] p = ((EllipseRoi)roi).getParams();
diff --git a/ij/plugin/LutLoader.java b/ij/plugin/LutLoader.java
index 0793b4c..be88b8b 100644
--- a/ij/plugin/LutLoader.java
+++ b/ij/plugin/LutLoader.java
@@ -2,6 +2,7 @@ package ij.plugin;
import ij.*;
import ij.io.*;
import ij.process.*;
+import ij.gui.ImageWindow;
import java.awt.*;
import java.io.*;
import java.awt.image.*;
@@ -96,6 +97,8 @@ public class LutLoader extends ImagePlus implements PlugIn {
if (imp.getStackSize()>1)
imp.getStack().setColorModel(cm);
imp.updateAndRepaintWindow();
+ if (IJ.isMacro() && imp.getWindow()!=null)
+ IJ.wait(25);
}
} else
createImage(fi, showImage);
@@ -251,7 +254,7 @@ public class LutLoader extends ImagePlus implements PlugIn {
/** Opens an NIH Image LUT, 768 byte binary LUT or text LUT from a file or URL. */
boolean openLut(FileInfo fi) {
- //IJ.showStatus("Opening: " + fi.directory + fi.fileName);
+ //IJ.log("openLut: " + fi.directory + fi.fileName);
boolean isURL = fi.url!=null && !fi.url.equals("");
int length = 0;
String path = isURL?fi.url:fi.directory+fi.fileName;
diff --git a/ij/plugin/Macro_Runner.java b/ij/plugin/Macro_Runner.java
index 899ba0e..d065add 100644
--- a/ij/plugin/Macro_Runner.java
+++ b/ij/plugin/Macro_Runner.java
@@ -48,7 +48,7 @@ public class Macro_Runner implements PlugIn {
|| name.endsWith("Menu.ijm") || name.endsWith("Menu.txt"))
(new MacroInstaller()).installTool(Menus.getPlugInsPath()+name);
else {
- boolean fullPath = name.startsWith("/") || name.startsWith("\\") || name.indexOf(":\\")==1;
+ boolean fullPath = name.startsWith("/") || name.startsWith("\\") || name.indexOf(":\\")==1 || name.indexOf(":/")==1;
if (fullPath)
path = name;
else
@@ -66,7 +66,7 @@ public class Macro_Runner implements PlugIn {
if (arg==null) arg = "";
if (name.startsWith("ij.jar:"))
return runMacroFromIJJar(name, arg);
- boolean fullPath = name.startsWith("/") || name.startsWith("\\") || name.indexOf(":\\")==1;
+ boolean fullPath = name.startsWith("/") || name.startsWith("\\") || name.indexOf(":\\")==1 || name.indexOf(":/")==1;
String path = name;
boolean exists = false;
if (!fullPath) {
diff --git a/ij/plugin/Options.java b/ij/plugin/Options.java
index 1e56656..75276e7 100644
--- a/ij/plugin/Options.java
+++ b/ij/plugin/Options.java
@@ -41,6 +41,8 @@ public class Options implements PlugIn {
gd.addCheckbox("Reverse CZT order of \">\" and \"<\"", Prefs.reverseNextPreviousOrder);
if (IJ.isMacOSX())
gd.addCheckbox("Don't set Mac menu bar", !Prefs.setIJMenuBar);
+ if (IJ.isLinux())
+ gd.addCheckbox("Save window locations", !Prefs.doNotSaveWindowLocations);
gd.addCheckbox("Debug mode", IJ.debugMode);
gd.addHelp(IJ.URL+"/docs/menus/edit.html#misc");
gd.showDialog();
@@ -73,6 +75,8 @@ public class Options implements PlugIn {
Prefs.reverseNextPreviousOrder = gd.getNextBoolean();
if (IJ.isMacOSX())
Prefs.setIJMenuBar = !gd.getNextBoolean();
+ if (IJ.isLinux())
+ Prefs.doNotSaveWindowLocations = !gd.getNextBoolean();
IJ.setDebugMode(gd.getNextBoolean());
}
@@ -95,7 +99,7 @@ public class Options implements PlugIn {
GenericDialog gd = new GenericDialog("I/O Options");
gd.addNumericField("JPEG quality (0-100):", FileSaver.getJpegQuality(), 0, 3, "");
gd.addNumericField("GIF and PNG transparent index:", Prefs.getTransparentIndex(), 0, 3, "");
- gd.addStringField("File extension for tables (.txt, .xls or .csv):", Prefs.defaultResultsExtension(), 4);
+ gd.addStringField("File extension for tables (.csv, .tsv or .txt):", Prefs.defaultResultsExtension(), 4);
gd.addCheckbox("Use JFileChooser to open/save", Prefs.useJFileChooser);
if (!IJ.isMacOSX())
gd.addCheckbox("Use_file chooser to import sequences", Prefs.useFileChooser);
@@ -126,7 +130,10 @@ public class Options implements PlugIn {
if (!extension.startsWith("."))
extension = "." + extension;
Prefs.set("options.ext", extension);
+ boolean useJFileChooser2 = Prefs.useJFileChooser;
Prefs.useJFileChooser = gd.getNextBoolean();
+ if (Prefs.useJFileChooser!=useJFileChooser2)
+ Prefs.jFileChooserSettingChanged = true;
if (!IJ.isMacOSX())
Prefs.useFileChooser = gd.getNextBoolean();
Prefs.intelByteOrder = gd.getNextBoolean();
diff --git a/ij/plugin/OverlayCommands.java b/ij/plugin/OverlayCommands.java
index 4fc8a68..1a3b67f 100644
--- a/ij/plugin/OverlayCommands.java
+++ b/ij/plugin/OverlayCommands.java
@@ -210,7 +210,6 @@ public class OverlayCommands implements PlugIn {
} else
roi.setPosition(imp.getCurrentSlice());
}
- //IJ.log(roi.getCPosition()+" "+roi.getZPosition()+" "+roi.getTPosition());
}
void hide() {
diff --git a/ij/plugin/PNM_Writer.java b/ij/plugin/PNM_Writer.java
index 89a5d94..e3a3f13 100644
--- a/ij/plugin/PNM_Writer.java
+++ b/ij/plugin/PNM_Writer.java
@@ -31,34 +31,34 @@ public class PNM_Writer implements PlugIn {
ip = ip.duplicate();
ip.invert();
}
- ip = ip.convertToByte(true);
+ if (img.getBitDepth()!=16)
+ ip = ip.convertToByte(true);
isGray = true;
extension = ".pgm";
}
String title=img.getTitle();
int length=title.length();
- for(int i=2;i<5;i++)
- if(length>i+1 && title.charAt(length-i)=='.') {
+ for (int i=2;i<5;i++)
+ if (length>i+1 && title.charAt(length-i)=='.') {
title=title.substring(0,length-i);
break;
}
-
if (path==null || path.equals("")) {
SaveDialog od = new SaveDialog("PNM Writer", title, extension);
String dir=od.getDirectory();
String name=od.getFileName();
- if(name==null)
+ if (name==null)
return;
path = dir + name;
}
-
+ IJ.showStatus("Writing PNM "+path+"...");
+ if (img.getBitDepth()==16) {
+ save16BitImage(ip, path);
+ return;
+ }
try {
- IJ.showStatus("Writing PNM "+path+"...");
- OutputStream fileOutput =
- new FileOutputStream(path);
- DataOutputStream output =
- new DataOutputStream(fileOutput);
-
+ OutputStream fileOutput = new FileOutputStream(path);
+ DataOutputStream output = new DataOutputStream(fileOutput);
int w = img.getWidth(), h = img.getHeight();
output.writeBytes((isGray ? "P5" : "P6")
+ "\n# Written by ImageJ PNM Writer\n"
@@ -87,6 +87,21 @@ public class PNM_Writer implements PlugIn {
}
IJ.showStatus("");
}
+
+ private void save16BitImage(ImageProcessor ip, String path) {
+ ip.resetMinAndMax();
+ int max = (int)ip.getMax();
+ if (max<256) max=256;
+ try {
+ DataOutputStream output = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(path)));
+ output.writeBytes("P5\n# Written by ImageJ PNM Writer\n" + ip.getWidth() + " " + ip.getHeight() + "\n"+max+"\n");
+ for (int i=0; i<ip.getPixelCount(); i++)
+ output.writeShort(ip.get(i));
+ output.close();
+ } catch(IOException e) {
+ IJ.handleException(e);
+ }
+ }
};
diff --git a/ij/plugin/PointToolOptions.java b/ij/plugin/PointToolOptions.java
index 8f8d52d..b1ec290 100644
--- a/ij/plugin/PointToolOptions.java
+++ b/ij/plugin/PointToolOptions.java
@@ -13,6 +13,7 @@ import java.util.*;
public class PointToolOptions implements PlugIn, DialogListener {
private static GenericDialog gd = null;
private boolean multipointTool;
+ private boolean isMacro;
private static final String help = "<html>"
+"<h1>Point Tool</h1>"
@@ -28,7 +29,7 @@ public class PointToolOptions implements PlugIn, DialogListener {
+"</font>";
public void run(String arg) {
- if (gd!=null && gd.isShowing()) {
+ if (gd!=null && gd.isShowing() && !IJ.isMacro()) {
gd.toFront();
update();
} else
@@ -37,14 +38,17 @@ public class PointToolOptions implements PlugIn, DialogListener {
void showDialog() {
String options = IJ.isMacro()?Macro.getOptions():null;
+ isMacro = options!=null;
boolean legacyMacro = false;
- if (options!=null) {
+ if (isMacro) {
options = options.replace("selection=", "color=");
options = options.replace("marker=", "size=");
Macro.setOptions(options);
legacyMacro = options.contains("auto-") || options.contains("add");
}
multipointTool = Toolbar.getMultiPointMode() && !legacyMacro;
+ if (isMacro && !legacyMacro)
+ multipointTool = true;
Color sc =Roi.getColor();
String sname = Colors.getColorName(sc, "Yellow");
Color cc =PointRoi.getDefaultCrossColor();
@@ -85,9 +89,9 @@ public class PointToolOptions implements PlugIn, DialogListener {
public boolean dialogItemChanged(GenericDialog gd, AWTEvent e) {
boolean redraw = false;
// type
- int index = gd.getNextChoiceIndex();
- if (index!=PointRoi.getDefaultType()) {
- PointRoi.setDefaultType(index);
+ int typeIndex = gd.getNextChoiceIndex();
+ if (typeIndex!=PointRoi.getDefaultType()) {
+ PointRoi.setDefaultType(typeIndex);
redraw = true;
}
// color
@@ -99,9 +103,9 @@ public class PointToolOptions implements PlugIn, DialogListener {
Toolbar.getInstance().repaint();
}
// size
- index = gd.getNextChoiceIndex();
- if (index!=PointRoi.getDefaultSize()) {
- PointRoi.setDefaultSize(index);
+ int sizeIndex = gd.getNextChoiceIndex();
+ if (sizeIndex!=PointRoi.getDefaultSize()) {
+ PointRoi.setDefaultSize(sizeIndex);
redraw = true;
}
if (!multipointTool) {
@@ -132,6 +136,14 @@ public class PointToolOptions implements PlugIn, DialogListener {
redraw = true;
}
}
+ if (isMacro) {
+ PointRoi roi = getPointRoi();
+ if (roi!=null) {
+ roi.setPointType(typeIndex);
+ roi.setStrokeColor(sc);
+ roi.setSize(sizeIndex);
+ }
+ }
if (redraw) {
ImagePlus imp = null;
PointRoi roi = getPointRoi();
diff --git a/ij/plugin/Profiler.java b/ij/plugin/Profiler.java
index 82c806e..e18980e 100644
--- a/ij/plugin/Profiler.java
+++ b/ij/plugin/Profiler.java
@@ -9,11 +9,14 @@ import java.awt.event.*;
public class Profiler implements PlugIn, PlotMaker {
ImagePlus imp;
boolean firstTime = true;
+ boolean plotVertically;
public void run(String arg) {
if (arg.equals("set"))
{doOptions(); return;}
imp = IJ.getImage();
+ if (firstTime)
+ plotVertically = Prefs.verticalProfile || IJ.altKeyDown();
Plot plot = getPlot();
firstTime = false;
if (plot==null)
@@ -24,15 +27,12 @@ public class Profiler implements PlugIn, PlotMaker {
public Plot getPlot() {
Roi roi = imp.getRoi();
- //if (roi==null && !firstTime)
- // IJ.run(imp, "Restore Selection", "");
if (roi==null || !(roi.isLine()||roi.getType()==Roi.RECTANGLE)) {
if (firstTime)
IJ.error("Plot Profile", "Line or rectangular selection required");
return null;
}
- boolean averageHorizontally = Prefs.verticalProfile || IJ.altKeyDown();
- ProfilePlot pp = new ProfilePlot(imp, averageHorizontally);
+ ProfilePlot pp = new ProfilePlot(imp, plotVertically);
return pp.getPlot();
}
diff --git a/ij/plugin/Projector.java b/ij/plugin/Projector.java
index 00324e2..468bb13 100644
--- a/ij/plugin/Projector.java
+++ b/ij/plugin/Projector.java
@@ -201,7 +201,6 @@ public class Projector implements PlugIn {
if ((f==0||!allTimePoints)&& c==0) {
buildImp = projImpD;
buildImp.setTitle("BuildStack");
- //buildImp.show();
} else {
Concatenator concat = new Concatenator();
buildImp = concat.concatenate(buildImp, projImpD, false);
@@ -215,9 +214,7 @@ public class Projector implements PlugIn {
finalSlices = 1;
}
if (imp.getNChannels()>1)
- IJ.run( buildImp,
- "Stack to Hyperstack...", "order=xyztc channels=" + finalChannels + " slices=" + finalSlices + " frames=" + finalFrames + " display=Composite");
- //buildImp = WindowManager.getCurrentImage();
+ buildImp = HyperStackConverter.toHyperStack(buildImp, finalChannels, finalSlices, finalFrames, "xyztc", "composite");
if (imp.isComposite()) {
CompositeImage buildImp2 = new CompositeImage(buildImp, 0);
((CompositeImage)buildImp2).copyLuts(imp);
@@ -226,8 +223,6 @@ public class Projector implements PlugIn {
}
buildImp.setTitle("Projections of "+imp.getShortTitle());
buildImp.show();
- if (WindowManager.getImage("Concatenated Stacks") != null)
- WindowManager.getImage("Concatenated Stacks").hide();
}
private void doRGBProjections(ImagePlus imp) {
diff --git a/ij/plugin/RGBStackMerge.java b/ij/plugin/RGBStackMerge.java
index 1857f71..0e645db 100644
--- a/ij/plugin/RGBStackMerge.java
+++ b/ij/plugin/RGBStackMerge.java
@@ -212,6 +212,8 @@ public class RGBStackMerge implements PlugIn {
images[i].close();
}
}
+ if (imp2.getWindow()!=null)
+ IJ.selectWindow(imp2.getID());
}
}
diff --git a/ij/plugin/Resizer.java b/ij/plugin/Resizer.java
index ecfc047..e69340e 100644
--- a/ij/plugin/Resizer.java
+++ b/ij/plugin/Resizer.java
@@ -219,11 +219,9 @@ public class Resizer implements PlugIn, TextListener, ItemListener {
imp2 = resizeZ(imp, newDepth, interpolationMethod);
if (imp2==null)
return null;
- ImageProcessor ip = imp.getProcessor();
- double min = ip.getMin();
- double max = ip.getMax();
- if (bitDepth==16||bitDepth==32)
- imp2.getProcessor().setMinAndMax(min, max);
+ double min = imp.getDisplayRangeMin();
+ double max = imp.getDisplayRangeMax();
+ imp2.setDisplayRange(min, max);
}
if (imp2==null)
return null;
diff --git a/ij/plugin/RoiRotator.java b/ij/plugin/RoiRotator.java
index 135d4ec..4d3be5a 100644
--- a/ij/plugin/RoiRotator.java
+++ b/ij/plugin/RoiRotator.java
@@ -86,8 +86,6 @@ public class RoiRotator implements PlugIn {
poly = new FloatPolygon();
poly.addPoint(x1, y1);
poly.addPoint(x2, y2);
- xcenter = x1 + (x2-x1)/2.0;
- ycenter = y1 + (y2-y1)/2.0;
}
for (int i=0; i<poly.npoints; i++) {
double dx = poly.xpoints[i]-xcenter;
diff --git a/ij/plugin/Scaler.java b/ij/plugin/Scaler.java
index 6c3c70f..20a303d 100644
--- a/ij/plugin/Scaler.java
+++ b/ij/plugin/Scaler.java
@@ -80,6 +80,9 @@ public class Scaler implements PlugIn, TextListener, FocusListener {
boolean crop = r.width!=imp.getWidth() || r.height!=imp.getHeight();
ImageStack stack1 = imp.getStack();
ImageStack stack2 = new ImageStack(newWidth, newHeight);
+ boolean virtualStack = stack1.isVirtual();
+ double min = imp.getDisplayRangeMin();
+ double max = imp.getDisplayRangeMax();
ImageProcessor ip1, ip2;
int method = interpolationMethod;
if (w==1 || h==1)
@@ -99,6 +102,8 @@ public class Scaler implements PlugIn, TextListener, FocusListener {
IJ.showProgress(i, nSlices);
}
imp2.setStack(title, stack2);
+ if (virtualStack)
+ imp2.setDisplayRange(min, max);
Calibration cal = imp2.getCalibration();
if (cal.scaled()) {
cal.pixelWidth *= 1.0/xscale;
diff --git a/ij/plugin/ScreenGrabber.java b/ij/plugin/ScreenGrabber.java
index e6a86fd..ac0024a 100644
--- a/ij/plugin/ScreenGrabber.java
+++ b/ij/plugin/ScreenGrabber.java
@@ -9,16 +9,37 @@ import java.awt.*;
commands may not work on Linux if windows translucency or
special effects are enabled in the windows manager. */
public class ScreenGrabber implements PlugIn {
+ private static int delay = 10;
public void run(String arg) {
ImagePlus imp2 = null;
if (arg.equals("image") || arg.equals("flatten"))
imp2 = captureImage();
+ else if (arg.equals("delay"))
+ imp2 = captureDelayed();
else
imp2 = captureScreen();
if (imp2!=null)
imp2.show();
}
+
+ private ImagePlus captureDelayed() {
+ GenericDialog gd = new GenericDialog("Delayed Capture");
+ gd.addNumericField("Delay (seconds):", delay, 0);
+ gd.showDialog();
+ if (gd.wasCanceled())
+ return null;
+ int delay = (int)gd.getNextNumber();
+ if (delay<0) return null;
+ if (delay>60) delay=60;
+ for (int i=0; i<delay; i++) {
+ IJ.wait(1000);
+ IJ.showStatus("Delayed capture: "+(i+1)+"/"+delay);
+ if (delay>4 && i==delay-2) IJ.beep();
+ }
+ return captureScreen();
+ }
+
/** Captures the entire screen and returns it as an ImagePlus. */
public ImagePlus captureScreen() {
diff --git a/ij/plugin/Selection.java b/ij/plugin/Selection.java
index d5b1dda..3f6235a 100644
--- a/ij/plugin/Selection.java
+++ b/ij/plugin/Selection.java
@@ -12,7 +12,7 @@ import java.awt.event.KeyEvent;
import java.util.Vector;
-/** This plugin implements the commands in the Edit/Section submenu. */
+/** This plugin implements the commands in the Edit/Selection submenu. */
public class Selection implements PlugIn, Measurements {
private ImagePlus imp;
private float[] kernel = {1f, 1f, 1f, 1f, 1f};
diff --git a/ij/plugin/SimpleCommands.java b/ij/plugin/SimpleCommands.java
index 74ac1de..017183e 100644
--- a/ij/plugin/SimpleCommands.java
+++ b/ij/plugin/SimpleCommands.java
@@ -39,6 +39,8 @@ public class SimpleCommands implements PlugIn {
resultsToImage();
else if (arg.equals("display"))
IJ.runMacroFile("ij.jar:ShowAllLuts", null);
+ else if (arg.equals("missing"))
+ showMissingPluginsMessage();
else if (arg.equals("fonts"))
showFonts();
}
@@ -172,5 +174,14 @@ public class SimpleCommands implements PlugIn {
if (ip==null) return;
new ImagePlus("Results Table", ip).show();
}
+
+ private void showMissingPluginsMessage() {
+ IJ.showMessage("Path Randomization",
+ "Plugins were not loaded due to macOS Path Randomization.\n"+
+ "To work around this problem, move ImageJ.app out of the\n"+
+ "ImageJ folder and then copy it back. More information is at\n \n"+
+ IJ.URL+"/docs/install/osx.html#randomization");
+ }
+
}
diff --git a/ij/plugin/SubstackMaker.java b/ij/plugin/SubstackMaker.java
index 311b25f..aed7a72 100644
--- a/ij/plugin/SubstackMaker.java
+++ b/ij/plugin/SubstackMaker.java
@@ -125,6 +125,9 @@ public class SubstackMaker implements PlugIn {
ImagePlus stackList(ImagePlus imp, int count, int[] numList, String stackTitle) throws Exception {
ImageStack stack = imp.getStack();
ImageStack stack2 = null;
+ boolean virtualStack = stack.isVirtual();
+ double min = imp.getDisplayRangeMin();
+ double max = imp.getDisplayRangeMax();
Roi roi = imp.getRoi();
for (int i=0, j=0; i<count; i++) {
int currSlice = numList[i]-j;
@@ -149,6 +152,8 @@ public class SubstackMaker implements PlugIn {
}
ImagePlus impSubstack = imp.createImagePlus();
impSubstack.setStack(stackTitle, stack2);
+ if (virtualStack)
+ impSubstack.setDisplayRange(min, max);
return impSubstack;
}
@@ -156,6 +161,9 @@ public class SubstackMaker implements PlugIn {
ImagePlus stackRange(ImagePlus imp, int first, int last, int inc, String title) throws Exception {
ImageStack stack = imp.getStack();
ImageStack stack2 = null;
+ boolean virtualStack = stack.isVirtual();
+ double min = imp.getDisplayRangeMin();
+ double max = imp.getDisplayRangeMax();
Roi roi = imp.getRoi();
boolean showProgress = stack.getSize()>400 || stack.isVirtual();
for (int i= first, j=0; i<= last; i+=inc) {
@@ -183,6 +191,8 @@ public class SubstackMaker implements PlugIn {
ImagePlus substack = imp.createImagePlus();
substack.setStack(title, stack2);
substack.setCalibration(imp.getCalibration());
+ if (virtualStack)
+ substack.setDisplayRange(min, max);
return substack;
}
}
diff --git a/ij/plugin/ZProjector.java b/ij/plugin/ZProjector.java
index 78b5302..926b2f5 100644
--- a/ij/plugin/ZProjector.java
+++ b/ij/plugin/ZProjector.java
@@ -379,7 +379,7 @@ public class ZProjector implements PlugIn {
int c, z, t;
for (Roi r : overlay.toArray()) {
c = r.getCPosition();
- z = r.getZPosition();
+ z = r.hasHyperStackPosition()?r.getZPosition():0;
t = r.getTPosition();
roi = (Roi)r.clone();
if (z>=startSlice && z<=stopSlice || z==0 || c==0 || t==0) {
diff --git a/ij/plugin/Zoom.java b/ij/plugin/Zoom.java
index ba1cb59..7acfc7b 100644
--- a/ij/plugin/Zoom.java
+++ b/ij/plugin/Zoom.java
@@ -42,9 +42,11 @@ public class Zoom implements PlugIn{
setZoom(imp, ic);
else if (arg.equals("max")) {
ImageWindow win = imp.getWindow();
- win.setBounds(win.getMaximumBounds());
- win.maximize();
- } if (arg.equals("scale"))
+ if (win!=null) {
+ win.maximize();
+ IJ.wait(100);
+ }
+ } else if (arg.equals("scale"))
scaleToFit(imp);
}
diff --git a/ij/plugin/filter/Analyzer.java b/ij/plugin/filter/Analyzer.java
index 0c48e77..4c45641 100644
--- a/ij/plugin/filter/Analyzer.java
+++ b/ij/plugin/filter/Analyzer.java
@@ -9,6 +9,7 @@ import ij.measure.*;
import ij.text.*;
import ij.plugin.MeasurementsWriter;
import ij.plugin.Straightener;
+import ij.plugin.frame.RoiManager;
import ij.util.Tools;
import ij.macro.Interpreter;
@@ -64,8 +65,13 @@ public class Analyzer implements PlugInFilter, Measurements {
this.imp = imp;
}
+ /** Construct a new Analyzer using an ImagePlus object and a ResultsTable. */
+ public Analyzer(ImagePlus imp, ResultsTable rt) {
+ this(imp, Analyzer.getMeasurements(), rt);
+ }
+
/** Construct a new Analyzer using an ImagePlus object and private
- measurement options and results table. */
+ measurement options and a ResultsTable. */
public Analyzer(ImagePlus imp, int measurements, ResultsTable rt) {
this.imp = imp;
this.measurements = measurements;
@@ -80,11 +86,13 @@ public class Analyzer implements PlugInFilter, Measurements {
this.arg = arg;
this.imp = imp;
IJ.register(Analyzer.class);
- if (arg.equals("set"))
- {doSetDialog(); return DONE;}
- else if (arg.equals("sum"))
- {summarize(); return DONE;}
- else if (arg.equals("clear")) {
+ if (arg.equals("set")) {
+ doSetDialog();
+ return DONE;
+ } else if (arg.equals("sum")) {
+ summarize();
+ return DONE;
+ } else if (arg.equals("clear")) {
if (IJ.macroRunning())
unsavedMeasurements = false;
resetCounter();
@@ -688,6 +696,18 @@ public class Analyzer implements PlugInFilter, Measurements {
rt.addValue(ResultsTable.MIN_THRESHOLD, stats.lowerThreshold);
rt.addValue(ResultsTable.MAX_THRESHOLD, stats.upperThreshold);
}
+ if (roi instanceof RotatedRectRoi) {
+ double[] p = ((RotatedRectRoi)roi).getParams();
+ double dx = p[2] - p[0];
+ double dy = p[3] - p[1];
+ double length = Math.sqrt(dx*dx+dy*dy);
+ Calibration cal = imp!=null?imp.getCalibration():null;
+ double pw = 1.0;
+ if (cal!=null && cal.pixelWidth==cal.pixelHeight)
+ pw = cal.pixelWidth;
+ rt.addValue("RRLength", length*pw);
+ rt.addValue("RRWidth", p[4]*pw);
+ }
}
private void clearSummary() {
@@ -919,6 +939,7 @@ public class Analyzer implements PlugInFilter, Measurements {
}
umeans = null;
systemRT.reset();
+ RoiManager.resetMultiMeasureResults();
unsavedMeasurements = false;
if (tp!=null) tp.clear();
summarized = false;
diff --git a/ij/plugin/filter/ImageMath.java b/ij/plugin/filter/ImageMath.java
index fd1785b..7005fda 100644
--- a/ij/plugin/filter/ImageMath.java
+++ b/ij/plugin/filter/ImageMath.java
@@ -9,7 +9,7 @@ import java.awt.*;
public class ImageMath implements ExtendedPlugInFilter, DialogListener {
public static final String MACRO_KEY = "math.macro";
- private int flags = DOES_ALL|SUPPORTS_MASKING|KEEP_PREVIEW|PARALLELIZE_STACKS;
+ private int flags = DOES_ALL|SUPPORTS_MASKING|KEEP_PREVIEW;
private String arg;
private ImagePlus imp;
private boolean canceled;
@@ -31,6 +31,8 @@ public class ImageMath implements ExtendedPlugInFilter, DialogListener {
this.arg = arg;
this.imp = imp;
IJ.register(ImageMath.class);
+ if (!arg.equals("macro") || Interpreter.getInstance()==null)
+ flags |= PARALLELIZE_STACKS;
return flags;
}
diff --git a/ij/plugin/filter/MaximumFinder.java b/ij/plugin/filter/MaximumFinder.java
index a14d3f7..3ec36e8 100644
--- a/ij/plugin/filter/MaximumFinder.java
+++ b/ij/plugin/filter/MaximumFinder.java
@@ -252,29 +252,42 @@ public class MaximumFinder implements ExtendedPlugInFilter, DialogListener {
}
/**
- * Calculates peak positions of 1D array N.Vischer, 13-sep-2013
+ * Calculates peak positions of 1D array N.Vischer, 06-mar-2017
*
* @param xx Array containing peaks.
* @param tolerance Depth of a qualified valley must exceed tolerance.
* Tolerance must be >= 0. Flat tops are marked at their centers.
- * @param excludeOnEdges If 'true', a peak is only
- * accepted if it is separated by two qualified valleys. If 'false', a peak
- * is also accepted if separated by one qualified valley and by a border.
+ * @param edgeMode 0=include, 1=exclude, 3=circular
+ * edgeMode = 0 (include edges) peak may be separated by one qualified valley and by a border.
+ * edgeMode = 1 (exclude edges) peak must be separated by two qualified valleys
+ * edgeMode = 2 (circular) array is regarded to be circular
* @return Positions of peaks, sorted with decreasing amplitude
*/
- public static int[] findMaxima(double[] xx, double tolerance, boolean excludeOnEdges) {
- boolean includeEdge = !excludeOnEdges;
+ public static int[] findMaxima(double[] xx, double tolerance, int edgeMode ) {
+ final int INCLUDE_EDGE = 0;
+ final int CIRCULAR = 2;
int len = xx.length;
+ int origLen = len;
if (len<2)
return new int[0];
if (tolerance < 0)
tolerance = 0;
+ if(edgeMode==CIRCULAR){
+ double[] cascade3 = new double[len * 3];
+ for (int jj = 0; jj <len; jj++){
+ cascade3[jj] = xx[jj];
+ cascade3[jj + len] = xx[jj];
+ cascade3[jj + 2*len] = xx[jj];
+ }
+ len *= 3;
+ xx = cascade3;
+ }
int[] maxPositions = new int[len];
double max = xx[0];
double min = xx[0];
int maxPos = 0;
int lastMaxPos = -1;
- boolean leftValleyFound = includeEdge;
+ boolean leftValleyFound = (edgeMode == INCLUDE_EDGE);
int maxCount = 0;
for (int jj = 1; jj < len; jj++) {
double val = xx[jj];
@@ -299,7 +312,7 @@ public class MaximumFinder implements ExtendedPlugInFilter, DialogListener {
max = val;
}
}
- if (includeEdge) {
+ if (edgeMode == INCLUDE_EDGE) {
if (maxCount > 0 && maxPositions[maxCount - 1] != lastMaxPos)
maxPositions[maxCount++] = lastMaxPos;
if (maxCount == 0 && max - min >= tolerance)
@@ -325,20 +338,42 @@ public class MaximumFinder implements ExtendedPlugInFilter, DialogListener {
int pos = maxPositions[rankPositions[jj]];
returnArr[maxCount - jj - 1] = pos;//use descending order
}
+ if(edgeMode == CIRCULAR){
+ int count = 0;
+ for(int jj = 0; jj < returnArr.length;jj++){
+ int pos = returnArr[jj] - origLen;
+ if(pos >= 0 && pos < origLen )//pick maxima from cascade center part
+ returnArr[count++] = pos;
+ }
+ int[] returrn2Arr = new int[count];
+ System.arraycopy(returnArr, 0, returrn2Arr, 0, count);
+ returnArr = returrn2Arr;
+
+ }
return returnArr;
}
+ public static int[] findMaxima(double[] xx, double tolerance, boolean excludeOnEdges) {
+ int edgeBehavior = (excludeOnEdges) ? 1 : 0;
+ return findMaxima(xx, tolerance, edgeBehavior);
+ }
+
/**
* Returns minimum positions of array xx, sorted with decreasing strength
*/
- public static int[] findMinima(double[] xx, double tolerance, boolean includeEdges) {
+ public static int[] findMinima(double[] xx, double tolerance, boolean excludeEdges ) {
+ int edgeMode = (excludeEdges) ? 1 : 0;
+ return findMinima(xx, tolerance, edgeMode);
+ }
+
+ public static int[] findMinima(double[] xx, double tolerance, int edgeMode) {
int len = xx.length;
double[] negArr = new double[len];
for (int jj = 0; jj < len; jj++)
negArr[jj] = -xx[jj];
- int[] minPositions = findMaxima(negArr, tolerance, includeEdges);
+ int[] minPositions = findMaxima(negArr, tolerance, edgeMode);
return minPositions;
- }
+ }
/** Find the maxima of an image.
* @param ip The input image
diff --git a/ij/plugin/filter/ParticleAnalyzer.java b/ij/plugin/filter/ParticleAnalyzer.java
index 663fee2..70d4e3d 100644
--- a/ij/plugin/filter/ParticleAnalyzer.java
+++ b/ij/plugin/filter/ParticleAnalyzer.java
@@ -605,12 +605,8 @@ public class ParticleAnalyzer implements PlugInFilter, Measurements {
ip.reset();
if (displaySummary && IJ.getInstance()!=null)
updateSliceSummary();
- if (addToManager && roiManager!=null) {
- if (imp.getWindow()!=null)
- roiManager.setEditMode(imp, true);
- else
- roiManager.runCommand("show all with labels");
- }
+ if (addToManager && roiManager!=null)
+ roiManager.setEditMode(imp, true);
maxParticleCount = (particleCount > maxParticleCount) ? particleCount : maxParticleCount;
totalCount += particleCount;
if (!canceled)
diff --git a/ij/plugin/frame/ContrastAdjuster.java b/ij/plugin/frame/ContrastAdjuster.java
index 80bbcde..c1431f4 100644
--- a/ij/plugin/frame/ContrastAdjuster.java
+++ b/ij/plugin/frame/ContrastAdjuster.java
@@ -125,7 +125,6 @@ public class ContrastAdjuster extends PlugInDialog implements Runnable,
// min slider
if (!windowLevel) {
minSlider = new Scrollbar(Scrollbar.HORIZONTAL, sliderRange/2, 1, 0, sliderRange);
- GUI.fix(minSlider);
c.gridy = y++;
c.insets = new Insets(2, 10, 0, 10);
gridbag.setConstraints(minSlider, c);
@@ -140,7 +139,6 @@ public class ContrastAdjuster extends PlugInDialog implements Runnable,
// max slider
if (!windowLevel) {
maxSlider = new Scrollbar(Scrollbar.HORIZONTAL, sliderRange/2, 1, 0, sliderRange);
- GUI.fix(maxSlider);
c.gridy = y++;
c.insets = new Insets(2, 10, 0, 10);
gridbag.setConstraints(maxSlider, c);
@@ -154,7 +152,6 @@ public class ContrastAdjuster extends PlugInDialog implements Runnable,
// brightness slider
brightnessSlider = new Scrollbar(Scrollbar.HORIZONTAL, sliderRange/2, 1, 0, sliderRange);
- GUI.fix(brightnessSlider);
c.gridy = y++;
c.insets = new Insets(windowLevel?12:2, 10, 0, 10);
gridbag.setConstraints(brightnessSlider, c);
@@ -171,7 +168,6 @@ public class ContrastAdjuster extends PlugInDialog implements Runnable,
// contrast slider
if (!balance) {
contrastSlider = new Scrollbar(Scrollbar.HORIZONTAL, sliderRange/2, 1, 0, sliderRange);
- GUI.fix(contrastSlider);
c.gridy = y++;
c.insets = new Insets(2, 10, 0, 10);
gridbag.setConstraints(contrastSlider, c);
@@ -722,7 +718,7 @@ public class ContrastAdjuster extends PlugInDialog implements Runnable,
previousImageID = 0;
((ColorProcessor)ip).caSnapshot(false);
setup();
- imp.deleteRoi();
+ //imp.deleteRoi();
if (Recorder.record) {
if (Recorder.scriptMode())
Recorder.recordCall("IJ.run(imp, \"Apply LUT\", \"\");");
diff --git a/ij/plugin/frame/Editor.java b/ij/plugin/frame/Editor.java
index 28aa89c..0c9951b 100644
--- a/ij/plugin/frame/Editor.java
+++ b/ij/plugin/frame/Editor.java
@@ -16,7 +16,7 @@ import ij.io.SaveDialog;
/** This is a simple TextArea based editor for editing and compiling plugins. */
public class Editor extends PlugInFrame implements ActionListener, ItemListener,
- TextListener, ClipboardOwner, MacroConstants, Runnable, Debugger {
+ TextListener, KeyListener, ClipboardOwner, MacroConstants, Runnable, Debugger {
/** ImportPackage statements added in front of scripts. Contains no
newlines so that lines numbers in error messages are not changed. */
@@ -40,11 +40,13 @@ public class Editor extends PlugInFrame implements ActionListener, ItemListener,
public static final int MAX_SIZE=28000, XINC=10, YINC=18;
public static final int MONOSPACED=1, MENU_BAR=2;
- public static final int MACROS_MENU_ITEMS = 12;
+ public static final int MACROS_MENU_ITEMS = 13;
static final String FONT_SIZE = "editor.font.size";
static final String FONT_MONO= "editor.font.mono";
static final String CASE_SENSITIVE= "editor.case-sensitive";
static final String DEFAULT_DIR= "editor.dir";
+ static final String INSERT_SPACES= "editor.spaces";
+ static final String TAB_INC= "editor.tab-inc";
private TextArea ta;
private String path;
protected boolean changes;
@@ -85,6 +87,10 @@ public class Editor extends PlugInFrame implements ActionListener, ItemListener,
private ArrayList undoBuffer = new ArrayList();
private boolean performingUndo;
private boolean checkForCurlyQuotes;
+ private static int tabInc = (int)Prefs.get(TAB_INC, 3);
+ private static boolean insertSpaces = Prefs.get(INSERT_SPACES, false);
+ CheckboxMenuItem insertSpacesItem;
+
public Editor() {
this(16, 60, 0, MENU_BAR);
@@ -96,6 +102,7 @@ public class Editor extends PlugInFrame implements ActionListener, ItemListener,
addMenuBar(options);
ta = new TextArea(rows, columns);
ta.addTextListener(this);
+ ta.addKeyListener(this);
if (IJ.isLinux()) ta.setBackground(Color.white);
addKeyListener(IJ.getInstance()); // ImageJ handles keyboard shortcuts
add(ta);
@@ -104,8 +111,10 @@ public class Editor extends PlugInFrame implements ActionListener, ItemListener,
fontSize = 0;
if (fontSize>=sizes.length)
fontSize = sizes.length-1;
- setFont();
+ setFont();
positionWindow();
+ if (IJ.isJava16() && !IJ.isJava18() && !IJ.isLinux())
+ insertSpaces = false;
}
void addMenuBar(int options) {
@@ -124,9 +133,6 @@ public class Editor extends PlugInFrame implements ActionListener, ItemListener,
mb.add(m);
m = new Menu("Edit");
- //String key = IJ.isMacintosh()?" Cmd ":" Ctrl+";
- //MenuItem item = new MenuItem("Undo"+key+"Z");
- //item.setEnabled(false);
MenuItem item = new MenuItem("Undo",new MenuShortcut(KeyEvent.VK_Z));
m.add(item);
m.addSeparator();
@@ -156,6 +162,11 @@ public class Editor extends PlugInFrame implements ActionListener, ItemListener,
m.addSeparator();
m.add(new MenuItem("Select All", new MenuShortcut(KeyEvent.VK_A)));
m.add(new MenuItem("Balance", new MenuShortcut(KeyEvent.VK_B,false)));
+ m.add(new MenuItem("Detab..."));
+ insertSpacesItem = new CheckboxMenuItem("Tab Key Inserts Spaces");
+ insertSpacesItem.addItemListener(this);
+ insertSpacesItem.setState(insertSpaces);
+ m.add(insertSpacesItem);
m.add(new MenuItem("Zap Gremlins"));
m.add(new MenuItem("Copy to Image Info"));
m.addActionListener(this);
@@ -216,6 +227,7 @@ public class Editor extends PlugInFrame implements ActionListener, ItemListener,
macrosMenu.add(new MenuItem("Macro Functions...", new MenuShortcut(KeyEvent.VK_M, true)));
macrosMenu.add(new MenuItem("Function Finder...", new MenuShortcut(KeyEvent.VK_F, true)));
macrosMenu.addSeparator();
+ macrosMenu.add(new MenuItem("Evaluate Macro"));
macrosMenu.add(new MenuItem("Evaluate JavaScript", new MenuShortcut(KeyEvent.VK_J, false)));
macrosMenu.add(new MenuItem("Evaluate BeanShell", new MenuShortcut(KeyEvent.VK_B, true)));
macrosMenu.add(new MenuItem("Evaluate Python", new MenuShortcut(KeyEvent.VK_P, false)));
@@ -409,6 +421,13 @@ public class Editor extends PlugInFrame implements ActionListener, ItemListener,
new MacroRunner(text, debug?this:null);
}
+ void evaluateMacro() {
+ String title = getTitle();
+ if (title.endsWith(".js")||title.endsWith("..bsh")||title.endsWith(".py"))
+ setTitle(title.substring(0,title.length()-3)+".ijm");
+ runMacro(false);
+ }
+
void evaluateJavaScript() {
if (!getTitle().endsWith(".js"))
setTitle(SaveDialog.setExtension(getTitle(), ".js"));
@@ -421,9 +440,18 @@ public class Editor extends PlugInFrame implements ActionListener, ItemListener,
text = ta.getSelectedText();
if (text.equals(""))
return;
+ boolean strictMode = false;
+ if (IJ.isJava18()) {
+ // text.matches("^( |\t)*(\"use strict\"|'use strict')");
+ String text40 = text.substring(0,Math.min(40,text.length()));
+ strictMode = text40.contains("'use strict'") || text40.contains("\"use strict\"");
+ }
text = getJSPrefix("") + text;
- if (IJ.isJava18())
+ if (IJ.isJava18()) {
text = "load(\"nashorn:mozilla_compat.js\");" + text;
+ if (strictMode)
+ text = "'use strict';" + text;
+ }
if ((IJ.isJava16() && !(IJ.isMacOSX()&&!IJ.is64Bit()))) {
// Use JavaScript engine built into Java 6 and later.
IJ.runPlugIn("ij.plugin.JavaScriptEvaluator", text);
@@ -695,6 +723,8 @@ public class Editor extends PlugInFrame implements ActionListener, ItemListener,
showMacroFunctions();
else if ("Function Finder...".equals(what))
functionFinder = new FunctionFinder(this);
+ else if ("Evaluate Macro".equals(what))
+ evaluateMacro();
else if ("Evaluate JavaScript".equals(what))
evaluateJavaScript();
else if ("Evaluate BeanShell".equals(what))
@@ -727,6 +757,8 @@ public class Editor extends PlugInFrame implements ActionListener, ItemListener,
gotoLine();
else if ("Balance".equals(what))
balance();
+ else if ("Detab...".equals(what))
+ detab();
else if ("Zap Gremlins".equals(what))
zapGremlins();
else if ("Make Text Larger".equals(what))
@@ -889,10 +921,31 @@ public class Editor extends PlugInFrame implements ActionListener, ItemListener,
if (IJ.isMacOSX()) // screen update bug work around
ta.setCaretPosition(ta.getCaretPosition());
}
+
+ public void keyPressed(KeyEvent e) {
+ }
+
+ public void keyReleased(KeyEvent e) {
+ int pos = ta.getCaretPosition();
+ if (insertSpaces && pos>0 && e.getKeyCode()==KeyEvent.VK_TAB) {
+ String spaces = " ";
+ for (int i=1; i<tabInc; i++)
+ spaces += " ";
+ ta.replaceRange(spaces, pos-1, pos);
+ }
+ }
+
+ public void keyTyped(KeyEvent e) {
+ }
public void itemStateChanged(ItemEvent e) {
CheckboxMenuItem item = (CheckboxMenuItem)e.getSource();
- setFont();
+ String cmd = e.getItem().toString();
+ if ("Tab Key Inserts Spaces".equals(cmd)) {
+ insertSpaces = e.getStateChange()==1;
+ Prefs.set(INSERT_SPACES, insertSpaces);
+ } else
+ setFont();
}
/** Override windowActivated in PlugInFrame to
@@ -1210,6 +1263,54 @@ public class Editor extends PlugInFrame implements ActionListener, ItemListener,
else
IJ.showMessage("Zap Gremlins", "No invalid characters found");
}
+
+
+ private void detab() {
+ GenericDialog gd = new GenericDialog("Detab", this);
+ gd.addNumericField("Spaces per tab: ", tabInc, 0);
+ gd.addCheckbox("Tab key inserts spaces: ", insertSpaces);
+ gd.showDialog();
+ if (gd.wasCanceled())
+ return;
+ int tabInc2 = tabInc;
+ tabInc = (int)gd.getNextNumber();
+ if (tabInc<1) tabInc=1;
+ if (tabInc>8) tabInc=8;
+ if (tabInc!=tabInc2)
+ Prefs.set(TAB_INC, tabInc);
+ boolean insertSpaces2 = insertSpaces;
+ insertSpaces = gd.getNextBoolean();
+ if (insertSpaces!=insertSpaces2) {
+ Prefs.set(INSERT_SPACES, insertSpaces);
+ insertSpacesItem.setState(insertSpaces);
+ }
+ int nb = 0;
+ int pos = 1;
+ String text = ta.getText();
+ if (text.indexOf('\t')<0)
+ return;
+ char[] chars = new char[text.length()];
+ chars = text.toCharArray();
+ StringBuffer sb = new StringBuffer((int)(chars.length*1.25));
+ for (int i=0; i<chars.length; i++) {
+ char c = chars[i];
+ if (c=='\t') {
+ nb = tabInc - ((pos-1)%tabInc);
+ while(nb>0) {
+ sb.append(' ');
+ ++pos;
+ --nb;
+ }
+ } else if (c=='\n') {
+ sb.append(c);
+ pos = 1;
+ } else {
+ sb.append(c);
+ ++pos;
+ }
+ }
+ ta.setText(sb.toString());
+ }
void selectAll() {
ta.selectAll();
diff --git a/ij/plugin/frame/Recorder.java b/ij/plugin/frame/Recorder.java
index 62fb2bd..aab9222 100644
--- a/ij/plugin/frame/Recorder.java
+++ b/ij/plugin/frame/Recorder.java
@@ -555,7 +555,7 @@ public class Recorder extends PlugInFrame implements PlugIn, ActionListener, Ima
}
static boolean isTextOrTable(String path) {
- return path.endsWith(".txt") || path.endsWith(".csv") || path.endsWith(".xls");
+ return path.endsWith(".txt") || path.endsWith(".csv") || path.endsWith(".xls") || path.endsWith(".tsv");
}
static boolean isSaveAs() {
diff --git a/ij/plugin/frame/RoiManager.java b/ij/plugin/frame/RoiManager.java
index 37bb49a..9e8305c 100644
--- a/ij/plugin/frame/RoiManager.java
+++ b/ij/plugin/frame/RoiManager.java
@@ -396,7 +396,7 @@ public class RoiManager extends PlugInFrame implements ActionListener, ItemListe
listModel.addElement(label);
roi.setName(label);
Roi roiCopy = (Roi)roi.clone();
- setRoiPosition(imp, roiCopy);
+ roiCopy.setPosition(imp);
if (lineWidth>1)
roiCopy.setStrokeWidth(lineWidth);
if (color!=null)
@@ -568,7 +568,7 @@ public class RoiManager extends PlugInFrame implements ActionListener, ItemListe
if (clone) {
String name = (String)listModel.getElementAt(index);
Roi roi2 = (Roi)roi.clone();
- setRoiPosition(imp, roi2);
+ roi2.setPosition(imp);
roi.setName(name);
roi2.setName(name);
rois.set(index, roi2);
@@ -594,7 +594,7 @@ public class RoiManager extends PlugInFrame implements ActionListener, ItemListe
Roi roi = (Roi)rois.get(index);
roi.setName(name2);
int position = getSliceNumber(name2);
- if (position>0 && roi.getCPosition()==0 && roi.getZPosition()==0 && roi.getTPosition()==0)
+ if (position>0 && !roi.hasHyperStackPosition())
roi.setPosition(position);
rois.set(index, roi);
listModel.setElementAt(name2, index);
@@ -631,13 +631,9 @@ public class RoiManager extends PlugInFrame implements ActionListener, ItemListe
if (imp==null || roi==null)
return false;
if (setSlice) {
- int c = roi.getCPosition();
- int z = roi.getZPosition();
- int t = roi.getTPosition();
boolean hyperstack = imp.isHyperStack();
- //IJ.log("restore: "+hyperstack+" "+c+" "+z+" "+t);
- if (hyperstack && (c>0||z>0||t>0))
- imp.setPosition(c, z, t);
+ if (hyperstack && roi.hasHyperStackPosition())
+ imp.setPosition(roi.getCPosition(), roi.getZPosition(), roi.getTPosition());
else {
String label = (String)listModel.getElementAt(index);
int n = getSliceNumber(roi, label);
@@ -968,7 +964,7 @@ public class RoiManager extends PlugInFrame implements ActionListener, ItemListe
appendResults = cmd.contains("append")?true:false;
if (IJ.isMacro()) {
if (cmd.startsWith("multi-measure")) {
- measureAll = cmd.contains(" measure") && nSlices>1;
+ measureAll = cmd.contains(" measure") && nSlices>1; // measure-all
onePerSlice = cmd.contains(" one");
appendResults = cmd.contains(" append");
} else {
@@ -1229,8 +1225,6 @@ public class RoiManager extends PlugInFrame implements ActionListener, ItemListe
Font font = null;
int justification = TextRoi.LEFT;
double opacity = -1;
- int position = -1;
- int cpos=-1, zpos=-1, tpos=-1;
int pointType = -1;
int pointSize = -1;
if (showDialog) {
@@ -1254,10 +1248,6 @@ public class RoiManager extends PlugInFrame implements ActionListener, ItemListe
color = rpRoi.getStrokeColor();
fillColor = rpRoi.getFillColor();
defaultColor = color;
- position = rpRoi.getPosition();
- cpos = rpRoi.getCPosition();
- zpos = rpRoi.getZPosition();
- tpos = rpRoi.getTPosition();
if (rpRoi instanceof TextRoi) {
font = ((TextRoi)rpRoi).getCurrentFont();
justification = ((TextRoi)rpRoi).getJustification();
@@ -1284,10 +1274,12 @@ public class RoiManager extends PlugInFrame implements ActionListener, ItemListe
if (color!=null) roi.setStrokeColor(color);
if (lineWidth>=0) roi.setStrokeWidth(lineWidth);
roi.setFillColor(fillColor);
- if (cpos>0 || zpos>0 || tpos>0)
- roi.setPosition(cpos, zpos, tpos);
- else if (position!=-1)
- roi.setPosition(position);
+ if (rpRoi!=null) {
+ if (rpRoi.hasHyperStackPosition())
+ roi.setPosition(rpRoi.getCPosition(), rpRoi.getZPosition(), rpRoi.getTPosition());
+ else
+ roi.setPosition(rpRoi.getPosition());
+ }
if (roi instanceof TextRoi) {
roi.setImage(imp);
if (font!=null)
@@ -2137,7 +2129,6 @@ public class RoiManager extends PlugInFrame implements ActionListener, ItemListe
/** Adds the current selection to the ROI Manager, using the
specified color (a 6 digit hex string) and line width. */
public boolean runCommand(String cmd, String hexColor, double lineWidth) {
- //setRoiPosition();
if (hexColor==null && lineWidth==1.0 && (IJ.altKeyDown()&&!Interpreter.isBatchMode()))
addRoi(true);
else {
@@ -2146,16 +2137,7 @@ public class RoiManager extends PlugInFrame implements ActionListener, ItemListe
}
return true;
}
-
- private void setRoiPosition(ImagePlus imp, Roi roi) {
- if (imp==null || roi==null)
- return;
- if (imp.isHyperStack())
- roi.setPosition(imp.getChannel(), imp.getSlice(), imp.getFrame());
- else if (imp.getStackSize()>1)
- roi.setPosition(imp.getCurrentSlice());
- }
-
+
/** Assigns the ROI at the specified index to the current image. */
public void select(int index) {
select(null, index);
@@ -2241,7 +2223,7 @@ public class RoiManager extends PlugInFrame implements ActionListener, ItemListe
public void close() {
super.close();
instance = null;
- mmResults = mmResults2 = null;
+ resetMultiMeasureResults();
Prefs.saveLocation(LOC_KEY, getLocation());
if (!showAllCheckbox.getState() || IJ.macroRunning())
return;
@@ -2456,6 +2438,10 @@ public class RoiManager extends PlugInFrame implements ActionListener, ItemListe
}
}
+ public static void resetMultiMeasureResults() {
+ mmResults = mmResults2 = null;
+ }
+
// This class runs the "Multi Measure" command in a separate thread
private class MultiMeasureRunner implements Runnable {
private Thread thread;
diff --git a/ij/plugin/frame/ThresholdAdjuster.java b/ij/plugin/frame/ThresholdAdjuster.java
index 0235f05..7db342f 100644
--- a/ij/plugin/frame/ThresholdAdjuster.java
+++ b/ij/plugin/frame/ThresholdAdjuster.java
@@ -117,7 +117,6 @@ public class ThresholdAdjuster extends PlugInDialog implements PlugIn, Measureme
// minThreshold slider
minSlider = new Scrollbar(Scrollbar.HORIZONTAL, sliderRange/3, 1, 0, sliderRange);
- GUI.fix(minSlider);
c.gridx = 0;
c.gridy = y++;
c.gridwidth = 1;
@@ -142,7 +141,6 @@ public class ThresholdAdjuster extends PlugInDialog implements PlugIn, Measureme
// maxThreshold slider
maxSlider = new Scrollbar(Scrollbar.HORIZONTAL, sliderRange*2/3, 1, 0, sliderRange);
- GUI.fix(maxSlider);
c.gridx = 0;
c.gridy = y++;
c.gridwidth = 1;
@@ -405,7 +403,8 @@ public class ThresholdAdjuster extends PlugInDialog implements PlugIn, Measureme
else
{minThreshold=0; maxThreshold=threshold;}
}
- if (minThreshold>255) minThreshold = 255;
+ if (minThreshold>255)
+ minThreshold = 255;
if (Recorder.record) {
boolean stack = stackHistogram!=null && stackHistogram.getState();
String options = method+(darkb?" dark":"")+(stack?" stack":"");
@@ -417,18 +416,8 @@ public class ThresholdAdjuster extends PlugInDialog implements PlugIn, Measureme
}
/** Scales threshold levels in the range 0-255 to the actual levels. */
- void scaleUpAndSet(ImageProcessor ip, double minThreshold, double maxThreshold) {
- if (!(ip instanceof ByteProcessor) && minThreshold!=ImageProcessor.NO_THRESHOLD) {
- double min = ip.getMin();
- double max = ip.getMax();
- if (max>min) {
- minThreshold = min + (minThreshold/255.0)*(max-min);
- maxThreshold = min + (maxThreshold/255.0)*(max-min);
- } else
- minThreshold = maxThreshold = min;
- }
- ip.setThreshold(minThreshold, maxThreshold, lutColor);
- //ip.setSnapshotPixels(null); // disable undo removed 20140206 M. Schmid
+ void scaleUpAndSet(ImageProcessor ip, double lower, double upper) {
+ ip.scaleAndSetThreshold(lower, upper, lutColor);
}
/** Scales a threshold level to the range 0-255. */
@@ -525,11 +514,11 @@ public class ThresholdAdjuster extends PlugInDialog implements PlugIn, Measureme
max = cal.getCValue((int)max);
}
if (((int)min==min && (int)max==max) || (ip instanceof ShortProcessor) || max>99999.0) {
- label1.setText(""+(int)min);
- label2.setText(""+(int)max);
+ label1.setText(ResultsTable.d2s(min,0));
+ label2.setText(ResultsTable.d2s(max,0));
} else {
- label1.setText(""+IJ.d2s(min,2));
- label2.setText(""+IJ.d2s(max,2));
+ label1.setText(""+(min<-3.4e38?"-3.4e38":ResultsTable.d2s(min,2)));
+ label2.setText(""+ResultsTable.d2s(max,max==Double.MAX_VALUE?0:2));
}
}
}
diff --git a/ij/process/AutoThresholder.java b/ij/process/AutoThresholder.java
index 1415aa8..395c824 100644
--- a/ij/process/AutoThresholder.java
+++ b/ij/process/AutoThresholder.java
@@ -581,10 +581,9 @@ public class AutoThresholder {
Tprev = threshold;
temp = (w1+Math.sqrt(sqterm))/w0;
- if (Double.isNaN(temp)) {
- IJ.log ("MinError(I): NaN, not converging.");
+ if (Double.isNaN(temp))
threshold = Tprev;
- } else
+ else
threshold =(int) Math.floor(temp);
}
return threshold;
diff --git a/ij/process/ByteProcessor.java b/ij/process/ByteProcessor.java
index 8dabef8..37dd30e 100644
--- a/ij/process/ByteProcessor.java
+++ b/ij/process/ByteProcessor.java
@@ -311,7 +311,6 @@ public class ByteProcessor extends ImageProcessor {
/** Sets the foreground drawing color. */
public void setColor(Color color) {
- //if (ij.IJ.altKeyDown()) throw new IllegalArgumentException("setColor: "+color);
drawingColor = color;
fgColor = getBestIndex(color);
}
diff --git a/ij/process/ColorProcessor.java b/ij/process/ColorProcessor.java
index 456fc97..7cc90ef 100644
--- a/ij/process/ColorProcessor.java
+++ b/ij/process/ColorProcessor.java
@@ -649,7 +649,7 @@ public class ColorProcessor extends ImageProcessor {
public static final int RGB_NOISE=0, RGB_MEDIAN=1, RGB_FIND_EDGES=2,
RGB_ERODE=3, RGB_DILATE=4, RGB_THRESHOLD=5, RGB_ROTATE=6,
- RGB_SCALE=7, RGB_RESIZE=8, RGB_TRANSLATE=9;
+ RGB_SCALE=7, RGB_RESIZE=8, RGB_TRANSLATE=9, RGB_MIN=10, RGB_MAX=11;
/** Performs the specified filter on the red, green and blue planes of this image. */
public void filterRGB(int type, double arg) {
@@ -748,6 +748,16 @@ public class ColorProcessor extends ImageProcessor {
ij.IJ.showStatus("Translating blue");
b.translate(arg, arg2); showProgress(0.90);
break;
+ case RGB_MIN:
+ r.filter(MIN); showProgress(0.40);
+ g.filter(MIN); showProgress(0.65);
+ b.filter(MIN); showProgress(0.90);
+ break;
+ case RGB_MAX:
+ r.filter(MAX); showProgress(0.40);
+ g.filter(MAX); showProgress(0.65);
+ b.filter(MAX); showProgress(0.90);
+ break;
}
R = (byte[])r.getPixels();
@@ -1139,43 +1149,66 @@ public class ColorProcessor extends ImageProcessor {
showProgress(1.0);
}
- /** 3x3 unweighted smoothing. */
+ /** A 3x3 filter operation, where the argument (ImageProcessor.BLUR_MORE, FIND_EDGES,
+ MEDIAN_FILTER, MIN or MAX) determines the filter type. */
public void filter(int type) {
- int p1, p2, p3, p4, p5, p6, p7, p8, p9;
- int inc = roiHeight/25;
- if (inc<1) inc = 1;
+ if (type == FIND_EDGES)
+ filterRGB(RGB_FIND_EDGES, 0, 0);
+ else if (type == MEDIAN_FILTER)
+ filterRGB(RGB_MEDIAN, 0, 0);
+ else if (type == MIN)
+ filterRGB(RGB_MIN, 0, 0);
+ else if (type == MAX)
+ filterRGB(RGB_MAX, 0, 0);
+ else
+ blurMore();
+ }
+
+ /** BLUR MORE: 3x3 unweighted smoothing is implemented directly, does not convert the image to three ByteProcessors. */
+ private void blurMore() {
+ int p1 = 0, p2, p3, p4 = 0, p5, p6, p7 = 0, p8, p9;
- int[] pixels2 = (int[])getPixelsCopy();
- int offset, rsum=0, gsum=0, bsum=0;
- int rowOffset = width;
- for (int y=yMin; y<=yMax; y++) {
- offset = xMin + y * width;
- p1 = 0;
- p2 = pixels2[offset-rowOffset-1];
- p3 = pixels2[offset-rowOffset];
- p4 = 0;
- p5 = pixels2[offset-1];
- p6 = pixels2[offset];
- p7 = 0;
- p8 = pixels2[offset+rowOffset-1];
- p9 = pixels2[offset+rowOffset];
+ int[] prevRow = new int[width];
+ int[] thisRow = new int[width];
+ int[] nextRow = new int[width];
+ System.arraycopy(pixels, Math.max(roiY-1,0)*width, thisRow, 0, width);
+ System.arraycopy(pixels, roiY*width, nextRow, 0, width);
+ for (int y=roiY; y<roiY+roiHeight; y++) {
+ int[] tmp = prevRow;
+ prevRow = thisRow;
+ thisRow = nextRow;
+ nextRow = tmp;
+ if (y < height-1)
+ System.arraycopy(pixels, (y+1)*width, nextRow, 0, width);
+ else
+ nextRow = thisRow;
+ int offset = roiX + y*width;
- for (int x=xMin; x<=xMax; x++) {
+ p2 = prevRow[roiX==0 ? roiX : roiX-1];
+ p3 = prevRow[roiX];
+ p5 = thisRow[roiX==0 ? roiX : roiX-1];
+ p6 = thisRow[roiX];
+ p8 = nextRow[roiX==0 ? roiX : roiX-1];
+ p9 = nextRow[roiX];
+
+ for (int x=roiX; x<roiX+roiWidth; x++) {
p1 = p2; p2 = p3;
- p3 = pixels2[offset-rowOffset+1];
p4 = p5; p5 = p6;
- p6 = pixels2[offset+1];
p7 = p8; p8 = p9;
- p9 = pixels2[offset+rowOffset+1];
- rsum = (p1 & 0xff0000) + (p2 & 0xff0000) + (p3 & 0xff0000) + (p4 & 0xff0000) + (p5 & 0xff0000)
+ if (x < width-1) {
+ p3 = prevRow[x+1];
+ p6 = thisRow[x+1];
+ p9 = nextRow[x+1];
+ }
+ int rsum = (p1 & 0xff0000) + (p2 & 0xff0000) + (p3 & 0xff0000) + (p4 & 0xff0000) + (p5 & 0xff0000)
+ (p6 & 0xff0000) + (p7 & 0xff0000) + (p8 & 0xff0000) + (p9 & 0xff0000);
- gsum = (p1 & 0xff00) + (p2 & 0xff00) + (p3 & 0xff00) + (p4 & 0xff00) + (p5 & 0xff00)
+ int gsum = (p1 & 0xff00) + (p2 & 0xff00) + (p3 & 0xff00) + (p4 & 0xff00) + (p5 & 0xff00)
+ (p6 & 0xff00) + (p7 & 0xff00) + (p8 & 0xff00) + (p9 & 0xff00);
- bsum = (p1 & 0xff) + (p2 & 0xff) + (p3 & 0xff) + (p4 & 0xff) + (p5 & 0xff)
+ int bsum = (p1 & 0xff) + (p2 & 0xff) + (p3 & 0xff) + (p4 & 0xff) + (p5 & 0xff)
+ (p6 & 0xff) + (p7 & 0xff) + (p8 & 0xff) + (p9 & 0xff);
- pixels[offset++] = 0xff000000 | ((rsum/9) & 0xff0000) | ((gsum/9) & 0xff00) | (bsum/9);
+ pixels[offset++] = 0xff000000 | (((rsum+(4<<16))/9) & 0xff0000) | (((gsum+(4<<8))/9) & 0xff00) | ((bsum+4)/9);
}
- if (y%inc==0)
+ if (roiHeight*roiWidth>1000000 && (y&0xff)==0)
showProgress((double)(y-roiY)/roiHeight);
}
showProgress(1.0);
@@ -1231,6 +1264,14 @@ public class ColorProcessor extends ImageProcessor {
return histogram;
}
+ public synchronized boolean weightedHistogram() {
+ if (weights!=null && (weights[0]!=1d/3d||weights[1]!=1d/3d||weights[2]!=1d/3d))
+ return true;
+ if (rWeight!=1d/3d || gWeight!=1d/3d || bWeight!=1d/3d)
+ return true;
+ return false;
+ }
+
/** Performs a convolution operation using the specified kernel. */
public void convolve(float[] kernel, int kernelWidth, int kernelHeight) {
int size = width*height;
@@ -1282,7 +1323,7 @@ public class ColorProcessor extends ImageProcessor {
weights[2] = bWeight;
return weights;
}
-
+
/** This is a thread-safe (non-static) version of setWeightingFactors(). */
public void setRGBWeights(double rweight, double gweight, double bweight) {
weights = new double[3];
@@ -1291,6 +1332,11 @@ public class ColorProcessor extends ImageProcessor {
weights[2] = bweight;
}
+ /** This is a thread-safe (non-static) version of setWeightingFactors(). */
+ public void setRGBWeights(double[] weights) {
+ this.weights = weights;
+ }
+
/** Returns the values set by setRGBWeights(), or null if setRGBWeights() has not been called. */
public double[] getRGBWeights() {
return weights;
diff --git a/ij/process/ImageConverter.java b/ij/process/ImageConverter.java
index 9dafc34..159f2cf 100644
--- a/ij/process/ImageConverter.java
+++ b/ij/process/ImageConverter.java
@@ -81,6 +81,8 @@ public class ImageConverter {
/** Converts this ImagePlus to RGB. */
public void convertToRGB() {
+ if (imp.getBitDepth()==24)
+ return;
if (imp.getStackSize()>1) {
new StackConverter(imp).convertToRGB();
return;
diff --git a/ij/process/ImageProcessor.java b/ij/process/ImageProcessor.java
index 5f96fb8..d8caf83 100644
--- a/ij/process/ImageProcessor.java
+++ b/ij/process/ImageProcessor.java
@@ -7,9 +7,6 @@ import ij.util.*;
import ij.plugin.filter.GaussianBlur;
import ij.plugin.Binner;
import ij.process.AutoThresholder.Method;
-import ij.gui.Roi;
-import ij.gui.ShapeRoi;
-import ij.gui.Overlay;
import ij.Prefs;
import ij.measure.Measurements;
@@ -164,6 +161,8 @@ public abstract class ImageProcessor implements Cloneable {
public void setColorModel(ColorModel cm) {
if (cm!=null && !(cm instanceof IndexColorModel))
throw new IllegalArgumentException("IndexColorModel required");
+ if (cm!=null && cm instanceof LUT)
+ cm = ((LUT)cm).getColorModel();
this.cm = cm;
baseCM = null;
rLUT1 = rLUT2 = null;
@@ -182,9 +181,13 @@ public abstract class ImageProcessor implements Cloneable {
}
public void setLut(LUT lut) {
- setColorModel(lut);
- if (lut!=null && (lut.min!=0.0||lut.max!=0.0))
- setMinAndMax(lut.min, lut.max);
+ if (lut==null)
+ setColorModel(null);
+ else {
+ setColorModel(lut.getColorModel());
+ if (lut.min!=0.0 || lut.max!=0.0)
+ setMinAndMax(lut.min, lut.max);
+ }
}
@@ -240,9 +243,15 @@ public abstract class ImageProcessor implements Cloneable {
int minDistance = Integer.MAX_VALUE;
int distance;
int minIndex = 0;
- int r1=c.getRed();
- int g1=c.getGreen();
- int b1=c.getBlue();
+ int r1 = c.getRed();
+ int g1 = c.getGreen();
+ int b1 = c.getBlue();
+ if (!(r1==g1&&g1==b1&&r1==b1) && icm==defaultColorModel) {
+ double[] w = ColorProcessor.getWeightingFactors();
+ r1 = (int)Math.round(3*r1*w[0]);
+ g1 = (int)Math.round(3*g1*w[1]);
+ b1 = (int)Math.round(3*b1*w[2]);
+ }
int r2,b2,g2;
for (int i=0; i<mapSize; i++) {
r2 = rLUT[i]&0xff; g2 = gLUT[i]&0xff; b2 = bLUT[i]&0xff;
@@ -556,14 +565,7 @@ public abstract class ImageProcessor implements Cloneable {
{lower=0.0; upper=threshold;}
}
if (lower>255) lower = 255;
- if (notByteData) {
- if (max>min) {
- lower = min + (lower/255.0)*(max-min);
- upper = min + (upper/255.0)*(max-min);
- } else
- lower = upper = min;
- }
- setThreshold(lower, upper, lutUpdate);
+ scaleAndSetThreshold(lower, upper, lutUpdate);
}
/** Automatically sets the lower and upper threshold levels, where 'method'
@@ -575,14 +577,12 @@ public abstract class ImageProcessor implements Cloneable {
throw new IllegalArgumentException("Invalid thresholding method");
if (this instanceof ColorProcessor)
return;
- double min=0.0, max=0.0;
boolean notByteData = !(this instanceof ByteProcessor);
ImageProcessor ip2 = this;
if (notByteData) {
ImageProcessor mask = ip2.getMask();
Rectangle rect = ip2.getRoi();
resetMinAndMax();
- min = getMin(); max = getMax();
ip2 = convertToByte(true);
ip2.setMask(mask);
ip2.setRoi(rect);
@@ -633,16 +633,33 @@ public abstract class ImageProcessor implements Cloneable {
else
{lower=0.0; upper=threshold;}
}
- if (notByteData) {
+ scaleAndSetThreshold(lower, upper, lutUpdate);
+
+ }
+
+ /** Set the threshold using a 0-255 range. */
+ public void scaleAndSetThreshold(double lower, double upper, int lutUpdate) {
+ int bitDepth = getBitDepth();
+ if (bitDepth!=8 && lower!=NO_THRESHOLD) {
+ double min = getMin();
+ double max = getMax();
if (max>min) {
- lower = min + (lower/255.0)*(max-min);
- upper = min + (upper/255.0)*(max-min);
+ if (bitDepth==16 && lower==0.0)
+ lower = 0.0;
+ else if (bitDepth==32 && lower==0.0)
+ lower = -Float.MAX_VALUE;
+ else
+ lower = min + (lower/255.0)*(max-min);
+ if (bitDepth==16 && upper==255.0)
+ upper = 65535;
+ else if (bitDepth==32 && upper==255.0)
+ upper = Float.MAX_VALUE;
+ else
+ upper = min + (upper/255.0)*(max-min);
} else
lower = upper = min;
}
setThreshold(lower, upper, lutUpdate);
- //if (notByteData && lutUpdate!=NO_LUT_UPDATE)
- // setLutAnimation(true);
}
/** Disables thresholding. */
@@ -962,18 +979,24 @@ public abstract class ImageProcessor implements Cloneable {
}
/**
- Returns an array containing the pixel values along the
- line starting at (x1,y1) and ending at (x2,y2). For byte
- and short images, returns calibrated values if a calibration
- table has been set using setCalibrationTable().
- @see ImageProcessor#setInterpolate
+ * Returns an array containing the pixel values along the
+ * line starting at (x1,y1) and ending at (x2,y2). Pixel
+ * values are sampled using getInterpolatedValue(double,double)
+ * if interpolatiion is enabled or getPixelValue(int,int) if it is not.
+ * For byte and short images, returns calibrated values if a
+ * calibration table has been set using setCalibrationTable().
+ * The length of the returned array, minus one, is approximately
+ * equal to the length of the line.
+ * @see ImageProcessor#setInterpolate
+ * @see ImageProcessor#getPixelValue
+ * @see ImageProcessor#getInterpolatedValue
*/
public double[] getLine(double x1, double y1, double x2, double y2) {
double dx = x2-x1;
double dy = y2-y1;
int n = (int)Math.round(Math.sqrt(dx*dx + dy*dy));
- double xinc = dx/n;
- double yinc = dy/n;
+ double xinc = n>0?dx/n:0;
+ double yinc = n>0?dy/n:0;
if (!((xinc==0&&n==height) || (yinc==0&&n==width)))
n++;
double[] data = new double[n];
@@ -986,15 +1009,16 @@ public abstract class ImageProcessor implements Cloneable {
ry += yinc;
}
} else {
+ rx-=0.5; ry-=0.5;
for (int i=0; i<n; i++) {
- data[i] = getPixelValue((int)(rx+0.5), (int)(ry+0.5));
+ data[i] = getPixelValue((int)Math.round(rx), (int)Math.round(ry));
rx += xinc;
ry += yinc;
}
}
return data;
}
-
+
/** Returns the pixel values along the horizontal line starting at (x,y). */
public void getRow(int x, int y, int[] data, int length) {
for (int i=0; i<length; i++)
@@ -1162,6 +1186,13 @@ public abstract class ImageProcessor implements Cloneable {
lineTo(x, y);
}
}
+
+ /** Fills a rectangle. */
+ public void fillRect(int x, int y, int width, int height) {
+ setRoi(x, y, width, height);
+ fill();
+ resetRoi();
+ }
/** Draws an elliptical shape. */
public void drawOval(int x, int y, int width, int height) {
@@ -1365,7 +1396,7 @@ public abstract class ImageProcessor implements Cloneable {
/** Sets the font used by drawString(). */
public void setFont(Font font) {
this.font = font;
- fontMetrics = null;
+ fontMetrics = null;
boldFont = font.isBold();
}
@@ -1552,7 +1583,7 @@ public abstract class ImageProcessor implements Cloneable {
/** Draws the specified ROI on this image using the stroke
width, stroke color and fill color defined by roi.setStrokeWidth,
- roi.setStrokeColor() and roi.setFillColor(). Works best with RGB
+ roi.setStrokeColor() and roi.setFillColor(). Works with RGB
images. Does not work with 16-bit and float images.
Requires Java 1.6.
@see ImageProcessor#draw
@@ -2003,7 +2034,7 @@ public abstract class ImageProcessor implements Cloneable {
mean 0.0 and the specified standard deviation, to this image or ROI. */
public abstract void noise(double standardDeviation);
- /** Creates a new processor containing an image
+ /** Returns a new processor containing an image
that corresponds to the current ROI. */
public abstract ImageProcessor crop();
@@ -2021,18 +2052,18 @@ public abstract class ImageProcessor implements Cloneable {
*/
public abstract void scale(double xScale, double yScale);
- /** Creates a new ImageProcessor containing a scaled copy of this image or ROI.
+ /** Returns a new ImageProcessor containing a scaled copy of this image or ROI.
@see ij.process.ImageProcessor#setInterpolate
*/
public abstract ImageProcessor resize(int dstWidth, int dstHeight);
- /** Creates a new ImageProcessor containing a scaled copy
+ /** Returns a new ImageProcessor containing a scaled copy
of this image or ROI, with the aspect ratio maintained. */
public ImageProcessor resize(int dstWidth) {
return resize(dstWidth, (int)(dstWidth*((double)roiHeight/roiWidth)));
}
- /** Creates a new ImageProcessor containing a scaled copy of this image or ROI.
+ /** Returns a new ImageProcessor containing a scaled copy of this image or ROI.
@param dstWidth Image width of the resulting ImageProcessor
@param dstHeight Image height of the resulting ImageProcessor
@param useAverging True means that the averaging occurs to avoid
diff --git a/ij/process/LUT.java b/ij/process/LUT.java
index b04a377..8a69b3b 100644
--- a/ij/process/LUT.java
+++ b/ij/process/LUT.java
@@ -8,6 +8,7 @@ import java.awt.Color;
lower and upper bound to be specified. */
public class LUT extends IndexColorModel implements Cloneable {
public double min, max;
+ private IndexColorModel cm;
/** Constructs a LUT from red, green and blue byte arrays, which must have a length of 256. */
public LUT(byte r[], byte g[], byte b[]) {
@@ -37,7 +38,17 @@ import java.awt.Color;
static byte[] getBlues(IndexColorModel cm) {
byte[] blues=new byte[256]; cm.getBlues(blues); return blues;
}
-
+
+ public IndexColorModel getColorModel() {
+ if (cm==null) {
+ byte[] reds=new byte[256]; getReds(reds);
+ byte[] greens=new byte[256]; getGreens(greens);
+ byte[] blues=new byte[256]; getBlues(blues);
+ cm = new IndexColorModel(8, getMapSize(), reds, greens, blues);
+ }
+ return cm;
+ }
+
public byte[] getBytes() {
int size = getMapSize();
if (size!=256) return null;
diff --git a/macros/CommandFinderTool.txt b/macros/CommandFinderTool.txt
new file mode 100644
index 0000000..979ebae
--- /dev/null
+++ b/macros/CommandFinderTool.txt
@@ -0,0 +1,3 @@
+ macro "Command Finder Action Tool - C026O00ddBccL0066" {
+ run("Find Commands...");
+ }
diff --git a/macros/StartupMacros.txt b/macros/StartupMacros.txt
index 7adb066..aa6d561 100644
--- a/macros/StartupMacros.txt
+++ b/macros/StartupMacros.txt
@@ -1,7 +1,8 @@
-// "StartupMacros"
+// Default startup macros
+ macro "Command Finder Built-in Tool" {}
macro "Developer Menu Built-in Tool" {}
- macro "Stacks Menu Built-in Tool" {}
macro "Brush Built-in Tool" {}
macro "Flood Filler Built-in Tool" {}
macro "Arrow Built-in Tool" {}
+
diff --git a/release-notes.html b/release-notes.html
index 5729f94..32da2e0 100644
--- a/release-notes.html
+++ b/release-notes.html
@@ -5,48 +5,24 @@
</head>
<body>
-<li> <u>1.51i 16 December 2016</u>
+<li> <u>1.51p 22 June 2017</u>
<ul>
-<li> Thanks to John Brear, the particle analyzer allows particles to
-be selected on circularity values greater than 1.0.
-<li> Thanks to Johan Doornenbal, the <i>Image>Scale</i> command works
-when Width or Height are not given.
-<li> Thanks to Mirekslouf, labeling of point selections in overlays now
-reflects the state of the "Label points" checkbox in the "Point Tool" dialog.
-<li> Thanks to Bastian Schmidt, added code to the DICOM importer to handle tags of
-type SS (signed 16-bit), UL (unsigned 32-bit) and SL (signed 32-bit).
-<li> Thanks to Michael Schmid, added static ZAxisProfiler.getPlot(ImagePlus) and
-ZAxisProfiler.getPlot(ImagePlus,String) methods, where the string argument can
-be either "time" or "z-axis".
-<li> Added the ImagePlus.getAllStatistics() method and removed
-the median calculation done in the ImagePlus.getStatistics() method
-in previous versions of ImageJ 1.51.
-<li> Thanks to Benjamen Gyori, added the ImageProcessor.getStats() method,
-which is up to 70 times faster than ImageProcessor.getStatistics().
-<li> Added the FolderOpener.open(path,"virtual") method.
-<li> Thanks to Michael Schmid, added static getNumParams() methods
-to the CurveFitter class.
-<li> Thanks to Gabriel Landini, fixed a bug that caused the <i>Image>Duplicate</i>
-command to not be correctly recorded with single images when the recorder
-was not in "Macro" mode.
-<li> Thanks to Gunjan Pandey, fixed a bug that caused plugins that used the
-ROI Manager to fail when they were called from batch mode macros. Note
-that the ROI Manager is not displayed in batch mode macros unless it is opened
-using run("ROI Manager�") prier to entering batch mode.
-<li> Thanks to Olivier Burri, fixed a bug the caused the "Append results" option
-of the ROI Manager's "Multi Measure" command to be ignored if the
-"One row per slice" option was not enabled.
-<li> Fixed a bug that sometimes caused the doCommand("Point Tool...") macro
-function to display the legacy point tool dialog instead of the non-modal
-multi-point tool dialog.
-<li> Worked around a OS X/Java 8 bug that caused image windows to
-be maximized when moved if a modal GenericDialog was open.
-<li> Thanks to Norbert Vischer, fixed a v1.50 regression that caused the
-<i>Edit>Selection>Properties</i> command to not work as expected
-with multi-point selections. Use the alt+y shortcut to display
-multi-point selection counts.
-</ul>
-
+<li> When adding a hyperstack ROI to the ROI Manager, the channel position
+ is set to 0 (display in all channels) if the display mode is "Composite".
+ <li> Added the setOption("ConvertToMicrons",boolean) macro function. When this
+ option is set, units in TIFF images are converted to microns if the pixel width
+ is less than 0.0001 cm.
+ <li> Thanks to Norbert vischer, worked around a bug in Java 8 on OS X that
+ sometimes caused painting of GenericDialogs to be incomplete.
+ <li> Thanks to Rainer Engel, fixed a bug that caused macros that
+ passed variables using "&" notation to fail if they used the
+ <i>Process>Math>Macro</i> command to process a stack.
+ <li> Thanks to Philippe Carl, fixed a 1.51o regression that sometimes
+ caused ImageJ to freeze on Windows when opening or processing
+ image stacks.
+ </ul>
+
<a href="http://imagej.nih.gov/ij">Home</a>
</body>
</html>
+
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-med/imagej.git
More information about the debian-med-commit
mailing list