Skip to content
Commits on Source (8)
......@@ -435,31 +435,29 @@ open02="Bat Cochlea Volume (19K)",ij.plugin.URLOpener("bat-cochlea-volume.zip")
open03="Bat Cochlea Renderings (449K)",ij.plugin.URLOpener("bat-cochlea-renderings.zip")
open04="Blobs (25K)[B]",ij.plugin.URLOpener("blobs.gif")
open05="Boats (356K)",ij.plugin.URLOpener("boats.gif")
open06="Bridge (174K)",ij.plugin.URLOpener("bridge.gif")
open07="Cardio (768K, RGB DICOM)",ij.plugin.URLOpener("cardio.dcm.zip")
open08="Cell Colony (31K)",ij.plugin.URLOpener("Cell_Colony.jpg")
open09="Clown (14K)",ij.plugin.URLOpener("clown.jpg")
open10="Confocal Series (2.2MB)",ij.plugin.URLOpener("confocal-series.zip")
open11="CT (420K, 16-bit DICOM)",ij.plugin.URLOpener("ct.dcm.zip")
open12="Dot Blot (7K)",ij.plugin.URLOpener("Dot_Blot.jpg")
open13="Embryos (42K)",ij.plugin.URLOpener("embryos.jpg")
open14="Fluorescent Cells (400K)",ij.plugin.URLOpener("FluorescentCells.zip")
open15="Fly Brain (1MB)",ij.plugin.URLOpener("flybrain.zip")
open16="Gel (105K)",ij.plugin.URLOpener("gel.gif")
open17="HeLa Cells (1.3M, 48-bit RGB)",ij.plugin.URLOpener("hela-cells.zip")
open18="Image with Overlay",ij.plugin.URLOpener("ImageWithOverlay.zip")
open19="Leaf (36K)",ij.plugin.URLOpener("leaf.jpg")
open20="Lena (68K)",ij.plugin.URLOpener("lena-std.tif")
open21="Line Graph (21K)",ij.plugin.URLOpener("LineGraph.jpg")
open22="Mitosis (26MB, 5D stack)",ij.plugin.URLOpener("Spindly-GFP.zip")
open23="MRI Stack (528K)",ij.plugin.URLOpener("mri-stack.zip")
open24="M51 Galaxy (177K, 16-bits)",ij.plugin.URLOpener("m51.zip")
open25="Neuron (1.6M, 5 channels)",ij.plugin.URLOpener("Rat_Hippocampal_Neuron.zip")
open26="Nile Bend (1.9M)",ij.plugin.URLOpener("NileBend.jpg")
open27="Organ of Corti (2.8M, 4D stack)",ij.plugin.URLOpener("organ-of-corti.zip")
open28="Particles (75K)",ij.plugin.URLOpener("particles.gif")
open29="T1 Head (2.4M, 16-bits)",ij.plugin.URLOpener("t1-head.zip")
open30="T1 Head Renderings (736K)",ij.plugin.URLOpener("t1-rendering.zip")
open31="TEM Filter (112K)",ij.plugin.URLOpener("TEM_filter_sample.jpg")
open32="Tree Rings (48K)",ij.plugin.URLOpener("Tree_Rings.jpg")
open06="Cardio (768K, RGB DICOM)",ij.plugin.URLOpener("cardio.dcm.zip")
open07="Cell Colony (31K)",ij.plugin.URLOpener("Cell_Colony.jpg")
open08="Clown (14K)",ij.plugin.URLOpener("clown.jpg")
open09="Confocal Series (2.2MB)",ij.plugin.URLOpener("confocal-series.zip")
open10="CT (420K, 16-bit DICOM)",ij.plugin.URLOpener("ct.dcm.zip")
open11="Dot Blot (7K)",ij.plugin.URLOpener("Dot_Blot.jpg")
open12="Embryos (42K)",ij.plugin.URLOpener("embryos.jpg")
open13="Fluorescent Cells (400K)",ij.plugin.URLOpener("FluorescentCells.zip")
open14="Fly Brain (1MB)",ij.plugin.URLOpener("flybrain.zip")
open15="Gel (105K)",ij.plugin.URLOpener("gel.gif")
open16="HeLa Cells (1.3M, 48-bit RGB)",ij.plugin.URLOpener("hela-cells.zip")
open17="Image with Overlay",ij.plugin.URLOpener("ImageWithOverlay.zip")
open18="Leaf (36K)",ij.plugin.URLOpener("leaf.jpg")
open19="Line Graph (21K)",ij.plugin.URLOpener("LineGraph.jpg")
open20="Mitosis (26MB, 5D stack)",ij.plugin.URLOpener("Spindly-GFP.zip")
open21="MRI Stack (528K)",ij.plugin.URLOpener("mri-stack.zip")
open22="M51 Galaxy (177K, 16-bits)",ij.plugin.URLOpener("m51.zip")
open23="Neuron (1.6M, 5 channels)",ij.plugin.URLOpener("Rat_Hippocampal_Neuron.zip")
open24="Nile Bend (1.9M)",ij.plugin.URLOpener("NileBend.jpg")
open25="Organ of Corti (2.8M, 4D stack)",ij.plugin.URLOpener("organ-of-corti.zip")
open26="Particles (75K)",ij.plugin.URLOpener("particles.gif")
open27="T1 Head (2.4M, 16-bits)",ij.plugin.URLOpener("t1-head.zip")
open28="T1 Head Renderings (736K)",ij.plugin.URLOpener("t1-rendering.zip")
open29="TEM Filter (112K)",ij.plugin.URLOpener("TEM_filter_sample.jpg")
open30="Tree Rings (48K)",ij.plugin.URLOpener("Tree_Rings.jpg")
imagej (1.52p-1) unstable; urgency=medium
* Team upload.
* New upstream version
* debhelper-compat 12
* Standards-Version: 4.4.0
* Re-add some docs to main package
* Provide extremely simple autopkgtest (just output help screen)
-- Andreas Tille <tille@debian.org> Thu, 08 Aug 2019 14:11:51 +0200
imagej (1.52j-1) unstable; urgency=medium
* Team upload.
......
......@@ -3,13 +3,13 @@ Maintainer: Debian Med Packaging Team <debian-med-packaging@lists.alioth.debian.
Uploaders: David Miguel Susano Pinto <carandraug+dev@gmail.com>
Section: science
Priority: optional
Build-Depends: debhelper (>= 12~)
Build-Depends: debhelper-compat (= 12)
Build-Depends-Indep: ant,
default-jdk-doc,
default-jdk-headless,
javahelper,
maven-repo-helper
Standards-Version: 4.3.0
Standards-Version: 4.4.0
Vcs-Browser: https://salsa.debian.org/med-team/imagej
Vcs-Git: https://salsa.debian.org/med-team/imagej.git
Homepage: https://imagej.nih.gov/ij
......
IJ_Props.txt
release-notes.html
Tests: run-unit-test
Depends: @
Restrictions: allow-stderr
#!/bin/bash
set -e
pkg=imagej
if [ "${AUTOPKGTEST_TMP}" = "" ] ; then
AUTOPKGTEST_TMP=$(mktemp -d /tmp/${pkg}-test.XXXXXX)
# Double quote below to expand the temporary directory variable now versus
# later is on purpose.
# shellcheck disable=SC2064
trap "rm -rf ${AUTOPKGTEST_TMP}" 0 INT QUIT ABRT PIPE TERM
fi
imagej -h
......@@ -199,10 +199,11 @@ public class IJ {
((PlugIn)thePlugIn).run(arg);
else
new PlugInFilterRunner(thePlugIn, commandName, arg);
}
catch (ClassNotFoundException e) {
if (IJ.getApplet()==null)
} catch (ClassNotFoundException e) {
log("Plugin or class not found: \"" + className + "\"\n(" + e+")");
String path = Prefs.getCustomPropsPath();
if (path!=null);
log("Error may be due to custom properties at " + path);
}
catch (InstantiationException e) {log("Unable to load plugin (ins)");}
catch (IllegalAccessException e) {log("Unable to load plugin, possibly \nbecause it is not public.");}
......@@ -231,7 +232,9 @@ public class IJ {
new PlugInFilterRunner(thePlugIn, commandName, arg);
}
catch (ClassNotFoundException e) {
if (className.contains("_") && !suppressPluginNotFoundError)
if (className.startsWith("macro:"))
runMacro(className.substring(6));
else if (className.contains("_") && !suppressPluginNotFoundError)
error("Plugin or class not found: \"" + className + "\"\n(" + e+")");
}
catch (NoClassDefFoundError e) {
......@@ -581,7 +584,7 @@ public class IJ {
/**Displays a "no images are open" dialog box.*/
public static void noImage() {
String msg = "There are no images open.";
String msg = "There are no images open";
if (macroInterpreter!=null) {
macroInterpreter.abort(msg);
macroInterpreter = null;
......@@ -659,11 +662,6 @@ public class IJ {
macro or JavaScript is running, it is aborted. Writes to the
Java console if the ImageJ window is not present.*/
public static void error(String msg) {
if (macroInterpreter!=null) {
macroInterpreter.abort(msg);
macroInterpreter = null;
return;
}
error(null, msg);
if (Thread.currentThread().getName().endsWith("JavaScript"))
throw new RuntimeException(Macro.MACRO_CANCELED);
......@@ -675,6 +673,11 @@ public class IJ {
macro or JavaScript is running, it is aborted. Writes to the
Java console if the ImageJ window is not present. */
public static void error(String title, String msg) {
if (macroInterpreter!=null) {
macroInterpreter.abort(msg);
macroInterpreter = null;
return;
}
if (msg!=null && msg.endsWith(Macro.MACRO_CANCELED))
return;
String title2 = title!=null?title:"ImageJ";
......@@ -1550,7 +1553,7 @@ public class IJ {
if (EventQueue.isDispatchThread())
new MacroRunner(smoothMacro); // run on separate thread
else
IJ.runMacro(smoothMacro);
Macro.eval(smoothMacro);
}
}
}
......@@ -1605,6 +1608,14 @@ public class IJ {
return img;
}
/**The macro interpreter uses this method to call getImage().*/
public static ImagePlus getImage(Interpreter interpreter) {
macroInterpreter = interpreter;
ImagePlus imp = getImage();
macroInterpreter = null;
return imp;
}
/** Returns the active image or stack slice as an ImageProcessor, or displays
an error message and aborts the plugin or macro if no images are open. */
public static ImageProcessor getProcessor() {
......@@ -1930,9 +1941,9 @@ public class IJ {
} else if (format.indexOf("lut")!=-1) {
path = updateExtension(path, ".lut");
format = "LUT...";
} else if (format.indexOf("results")!=-1 || format.indexOf("measurements")!=-1) {
} else if (format.contains("results") || format.contains("measurements") || format.contains("table")) {
format = "Results...";
} else if (format.indexOf("selection")!=-1 || format.indexOf("roi")!=-1) {
} else if (format.contains("selection") || format.contains("roi")) {
path = updateExtension(path, ".roi");
format = "Selection...";
} else if (format.indexOf("xy")!=-1 || format.indexOf("coordinates")!=-1) {
......@@ -2213,23 +2224,8 @@ public class IJ {
/** Returns the size, in pixels, of the primary display. */
public static Dimension getScreenSize() {
Rectangle bounds = GUI.getZeroBasedMaxBounds();
if (bounds!=null)
Rectangle bounds = GUI.getScreenBounds();
return new Dimension(bounds.width, bounds.height);
if (isWindows()) // GraphicsEnvironment.getConfigurations is *very* slow on Windows
return Toolkit.getDefaultToolkit().getScreenSize();
if (GraphicsEnvironment.isHeadless())
return new Dimension(0, 0);
// Can't use Toolkit.getScreenSize() on Linux because it returns
// size of all displays rather than just the primary display.
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice[] gd = ge.getScreenDevices();
GraphicsConfiguration[] gc = gd[0].getConfigurations();
bounds = gc[0].getBounds();
if ((bounds.x==0&&bounds.y==0) || (IJ.isLinux()&&gc.length>1))
return new Dimension(bounds.width, bounds.height);
else
return Toolkit.getDefaultToolkit().getScreenSize();
}
/** Returns, as an array of strings, a list of the LUTs in the Image/Lookup Tables menu. */
......
......@@ -18,7 +18,6 @@ import java.awt.image.*;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
/**
This frame is the main ImageJ class.
<p>
......@@ -47,7 +46,7 @@ The following command line options are recognized by ImageJ:
-batch path [arg]
Runs a macro or script (JavaScript, BeanShell or Python) in
batch (no GUI) mode, passing it an optional argument.
batch (no GUI) mode, passing an optional argument.
ImageJ exits when the macro finishes.
-eval "macro code"
......@@ -78,8 +77,8 @@ 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.52j";
public static final String BUILD = ""; //42
public static final String VERSION = "1.52p";
public static final String BUILD = ""; //61
public static Color backgroundColor = new Color(237,237,237);
/** SansSerif, 12-point, plain font. */
public static final Font SansSerif12 = new Font("SansSerif", Font.PLAIN, 12);
......@@ -165,11 +164,12 @@ public class ImageJ extends Frame implements ActionListener,
statusBar.setForeground(Color.black);
statusBar.setBackground(backgroundColor);
statusLine = new JLabel();
statusLine.setFont(new Font("SansSerif", Font.PLAIN, 13));
double scale = Prefs.getGuiScale();
statusLine.setFont(new Font("SansSerif", Font.PLAIN, (int)(13*scale)));
statusLine.addKeyListener(this);
statusLine.addMouseListener(this);
statusBar.add("Center", statusLine);
progressBar = new ProgressBar(ProgressBar.WIDTH, ProgressBar.HEIGHT);
progressBar = new ProgressBar((int)(ProgressBar.WIDTH*scale), (int)(ProgressBar.HEIGHT*scale));
progressBar.addKeyListener(this);
progressBar.addMouseListener(this);
statusBar.add("East", progressBar);
......@@ -186,10 +186,10 @@ public class ImageJ extends Frame implements ActionListener,
setCursor(Cursor.getDefaultCursor()); // work-around for JDK 1.1.8 bug
if (mode!=NO_SHOW) {
if (IJ.isWindows()) try {setIcon();} catch(Exception e) {}
setLocation(loc.x, loc.y);
setResizable(false);
setAlwaysOnTop(Prefs.alwaysOnTop);
pack();
setLocation(loc.x, loc.y);
setVisible(true);
Dimension size = getSize();
if (size!=null) {
......@@ -202,7 +202,7 @@ public class ImageJ extends Frame implements ActionListener,
if (!Prefs.jFileChooserSettingChanged)
Prefs.useJFileChooser = true;
} else if (IJ.isMacOSX()) {
Rectangle maxBounds = GUI.getMaxWindowBounds();
Rectangle maxBounds = GUI.getMaxWindowBounds(this);
if (loc.x+size.width>maxBounds.x+maxBounds.width)
setLocation(loc.x, loc.y);
}
......@@ -277,9 +277,9 @@ public class ImageJ extends Frame implements ActionListener,
}
public Point getPreferredLocation() {
Rectangle maxBounds = GUI.getMaxWindowBounds();
int ijX = Prefs.getInt(IJ_X,-99);
int ijY = Prefs.getInt(IJ_Y,-99);
Rectangle maxBounds = GUI.getMaxWindowBounds();
//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);
......@@ -464,7 +464,7 @@ public class ImageJ extends Frame implements ActionListener,
|| (keyCode>=KeyEvent.VK_NUMPAD0 && keyCode<=KeyEvent.VK_NUMPAD9);
if ((!Prefs.requireControlKey||control||meta||functionKey||numPad) && keyChar!='+') {
Hashtable shortcuts = Menus.getShortcuts();
if (shift)
if (shift && !functionKey)
cmd = (String)shortcuts.get(new Integer(keyCode+200));
else
cmd = (String)shortcuts.get(new Integer(keyCode));
......@@ -609,17 +609,25 @@ public class ImageJ extends Frame implements ActionListener,
IJ.setKeyUp(e.getKeyCode());
}
/** called when escape pressed */
void abortPluginOrMacro(ImagePlus imp) {
if (imp!=null) {
ImageWindow win = imp.getWindow();
if (win!=null) {
Roi roi = imp.getRoi();
if (roi!=null && roi.getState()!=Roi.NORMAL) {
roi.abortModification(imp);
return;
} else {
win.running = false;
win.running2 = false;
}
}
}
Macro.abort();
Interpreter.abort();
if (Interpreter.getInstance()!=null) IJ.beep();
if (Interpreter.getInstance()!=null)
IJ.beep();
}
public void windowClosing(WindowEvent e) {
......@@ -678,10 +686,6 @@ 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));
}
......@@ -865,4 +869,12 @@ public class ImageJ extends Frame implements ActionListener,
commandName = name;
}
public void resize() {
double scale = Prefs.getGuiScale();
toolbar.init();
statusLine.setFont(new Font("SansSerif", Font.PLAIN, (int)(13*scale)));
progressBar.init((int)(ProgressBar.WIDTH*scale), (int)(ProgressBar.HEIGHT*scale));
pack();
}
}
......@@ -97,6 +97,7 @@ public class ImagePlus implements ImageObserver, Measurements, Cloneable {
private boolean ignoreGlobalCalibration;
private boolean oneSliceStack;
public boolean setIJMenuBar = Prefs.setIJMenuBar;
private Plot plot;
/** Constructs an uninitialized ImagePlus. */
......@@ -269,6 +270,17 @@ public class ImagePlus implements ImageObserver, Measurements, Cloneable {
draw();
}
/** Use to update the image when the underlying virtual stack changes. */
public void updateVirtualSlice() {
ImageStack vstack = getStack();
if (vstack.isVirtual()) {
double min=getDisplayRangeMin(), max=getDisplayRangeMax();
setProcessor(vstack.getProcessor(getCurrentSlice()));
setDisplayRange(min,max);
} else
throw new IllegalArgumentException("Virtual stack required");
}
/** Sets the display mode of composite color images, where 'mode'
should be IJ.COMPOSITE, IJ.COLOR or IJ.GRAYSCALE. */
public void setDisplayMode(int mode) {
......@@ -429,7 +441,6 @@ public class ImagePlus implements ImageObserver, Measurements, Cloneable {
if (roi!=null) roi.setImage(this);
if (overlay!=null && getCanvas()!=null)
getCanvas().setOverlay(overlay);
draw();
IJ.showStatus(statusMessage);
if (IJ.isMacro()) { // wait for window to be activated
long start = System.currentTimeMillis();
......@@ -872,9 +883,10 @@ public class ImagePlus implements ImageObserver, Measurements, Cloneable {
return mask;
}
/** Returns an 8-bit binary (0 and 255) ROI or overlay mask
* that has the same dimensions as this image. Creates an
* ROI mask If the image has both an ROI and an overlay.
/** Returns an 8-bit binary (foreground=255, background=0)
* ROI or overlay mask that has the same dimensions
* as this image. Creates an ROI mask If the image has both
* both an ROI and an overlay. Set the threshold of the mask to 255.
* @see #createThresholdMask
* @see ij.gui.Roi#getMask
*/
......@@ -902,16 +914,21 @@ public class ImagePlus implements ImageObserver, Measurements, Cloneable {
mask.fill(overlay2.get(i));
}
}
mask.setThreshold(255, 255, ImageProcessor.NO_LUT_UPDATE);
return mask;
}
/** Returns an 8-bit binary (0 and 255) threshold mask
/** Returns an 8-bit binary threshold mask
* (foreground=255, background=0)
* that has the same dimensions as this image.
* The threshold of the mask is set to 255.
* @see ij.plugin.Thresholder#createMask
* @see ij.process.ImageProcessor#createMask
*/
public ByteProcessor createThresholdMask() {
return Thresholder.createMask(this);
ByteProcessor mask = Thresholder.createMask(this);
mask.setThreshold(255, 255, ImageProcessor.NO_LUT_UPDATE);
return mask;
}
/** Get calibrated statistics for this image or ROI, including
......@@ -926,18 +943,22 @@ public class ImagePlus implements ImageObserver, Measurements, Cloneable {
IJ.log("Mean: "+stats.mean);
IJ.log("Max: "+stats.max);
</pre>
@return an {@link ij.process.ImageStatistics} object
@see #getAllStatistics
@see #getRawStatistics
@see ij.process.ImageProcessor#getStats
@see ij.process.ImageStatistics
@see ij.process.ImageStatistics#getStatistics
*/
public ImageStatistics getStatistics() {
return getStatistics(AREA+MEAN+STD_DEV+MODE+MIN_MAX+RECT);
}
/** This method returns complete calibrated statistics for this image or ROI
(with "Limit to threshold"), but it is up to 70 times slower than getStatistics().*/
/** This method returns complete calibrated statistics for this
* image or ROI (with "Limit to threshold"), but it is up to 70 times
* slower than getStatistics().
* @return an {@link ij.process.ImageStatistics} object
* @see #getStatistics
* @see ij.process.ImageProcessor#getStatistics
*/
public ImageStatistics getAllStatistics() {
return getStatistics(ALL_STATS+LIMIT);
}
......@@ -954,7 +975,6 @@ public class ImagePlus implements ImageObserver, Measurements, Cloneable {
/** Returns an ImageStatistics object generated using the
specified measurement options.
@see ij.process.ImageStatistics
@see ij.measure.Measurements
*/
public ImageStatistics getStatistics(int mOptions) {
......@@ -975,10 +995,16 @@ public class ImagePlus implements ImageObserver, Measurements, Cloneable {
int bitDepth = getBitDepth();
if (nBins!=256 && (bitDepth==8||bitDepth==24))
ip2 =ip.convertToShort(false);
if (roi!=null && roi.isArea())
ip2.setRoi(roi);
else
Roi roi2 = roi;
if (roi2==null)
ip2.resetRoi();
else if (roi2.isArea())
ip2.setRoi(roi2);
else if ((roi2 instanceof PointRoi) && roi2.size()==1) {
// needed to be consistent with ImageProcessor.getStatistics()
FloatPolygon p = roi2.getFloatPolygon();
ip2.setRoi((int)p.xpoints[0], (int)p.ypoints[0], 1, 1);
}
ip2.setHistogramSize(nBins);
Calibration cal = getCalibration();
if (getType()==GRAY16&& !(histMin==0.0&&histMax==0.0)) {
......@@ -1474,9 +1500,10 @@ public class ImagePlus implements ImageObserver, Measurements, Cloneable {
}
s.addSlice(label, ip2);
s.update(ip2);
setStack(s);
this.stack = s;
ip = ip2;
oneSliceStack = true;
setCurrentSlice(1);
} else {
s = stack;
if (ip!=null) {
......@@ -1662,8 +1689,10 @@ public class ImagePlus implements ImageObserver, Measurements, Cloneable {
Roi roi = getRoi();
if (roi!=null)
roi.endPaste();
if (isProcessor())
if (isProcessor()) {
if (currentSlice==0) currentSlice=1;
stack.setPixels(ip.getPixels(),currentSlice);
}
setCurrentSlice(n);
Object pixels = null;
Overlay overlay2 = null;
......@@ -1752,8 +1781,10 @@ public class ImagePlus implements ImageObserver, Measurements, Cloneable {
if (newRoi==null)
{deleteRoi(); return;}
}
if (bounds.width==0 && bounds.height==0 && !(newRoi.getType()==Roi.POINT||newRoi.getType()==Roi.LINE))
{deleteRoi(); return;}
if (bounds.width==0 && bounds.height==0 && !(newRoi.getType()==Roi.POINT||newRoi.getType()==Roi.LINE)) {
deleteRoi();
return;
}
roi = newRoi;
if (ip!=null) {
ip.setMask(null);
......@@ -1789,7 +1820,10 @@ public class ImagePlus implements ImageObserver, Measurements, Cloneable {
the tool bar is active. The user interactively sets the selection size and shape. */
public void createNewRoi(int sx, int sy) {
Roi previousRoi = roi;
deleteRoi();
deleteRoi(); //also saves the roi as <code>Roi.previousRoi</code> if non-null
if (Roi.previousRoi != null)
Roi.previousRoi.setImage(previousRoi== null ? null : this); //with 'this' it will be recalled in case of ESC
switch (Toolbar.getToolId()) {
case Toolbar.RECTANGLE:
if (Toolbar.getRectToolType()==Toolbar.ROTATED_RECT_ROI)
......@@ -1880,6 +1914,23 @@ public class ImagePlus implements ImageObserver, Measurements, Cloneable {
}
}
public boolean okToDeleteRoi() {
if (roi!=null && (roi instanceof PointRoi) && getWindow()!=null && ((PointRoi)roi).promptBeforeDeleting()) {
int npoints = ((PolygonRoi)roi).getNCoordinates();
int counters = ((PointRoi)roi).getNCounters();
String msg = "Delete this multi-point selection ("+npoints+" points, "+counters+" counter"+(counters>1?"s":"")+")?";
GenericDialog gd=new GenericDialog("Delete Points?");
gd.addMessage(msg+"\nRestore using Edit>Selection>Restore Selection.");
gd.addHelp(PointToolOptions.help);
gd.setOKLabel("Keep");
gd.setCancelLabel("Delete");
gd.showDialog();
if (gd.wasOKed())
return false;
}
return true;
}
/** Deletes the current region of interest. */
public void killRoi() {
deleteRoi();
......@@ -1894,10 +1945,20 @@ public class ImagePlus implements ImageObserver, Measurements, Cloneable {
Roi.previousRoi = (Roi)roi2.clone();
if (IJ.debugMode) IJ.log("saveRoi: "+roi2);
}
if ((roi2 instanceof PointRoi) && ((PointRoi)roi2).promptBeforeDeleting()) {
PointRoi.savedPoints = (PointRoi)roi2.clone();
if (IJ.debugMode) IJ.log("saveRoi: saving multi-point selection");
}
}
}
public void restoreRoi() {
if (Toolbar.getToolId()==Toolbar.POINT && PointRoi.savedPoints!=null) {
roi = (Roi)PointRoi.savedPoints.clone();
draw();
roi.notifyListeners(RoiListener.MODIFIED);
return;
}
if (Roi.previousRoi!=null) {
Roi pRoi = Roi.previousRoi;
Rectangle r = pRoi.getBounds();
......@@ -1909,7 +1970,7 @@ public class ImagePlus implements ImageObserver, Measurements, Cloneable {
else if (r.width==width && r.height==height) // is it the same size as the image
roi.setLocation(0, 0);
draw();
roi.notifyListeners(RoiListener.CREATED);
roi.notifyListeners(RoiListener.MODIFIED);
}
}
}
......@@ -1924,8 +1985,12 @@ public class ImagePlus implements ImageObserver, Measurements, Cloneable {
/** Implements the File/Revert command. */
public void revert() {
if (getStackSize()>1 && getStack().isVirtual())
if (getStackSize()>1 && getStack().isVirtual()) {
int thisSlice = currentSlice;
currentSlice = 0;
setSlice(thisSlice);
return;
}
FileInfo fi = getOriginalFileInfo();
boolean isFileInfo = fi!=null && fi.fileFormat!=FileInfo.UNKNOWN;
if (!isFileInfo && url==null)
......@@ -2037,7 +2102,8 @@ public class ImagePlus implements ImageObserver, Measurements, Cloneable {
switch (imageType) {
case GRAY8: case COLOR_256:
LookUpTable lut = createLut();
if (imageType==COLOR_256 || !lut.isGrayscale())
boolean customLut = !lut.isGrayscale() || (ip!=null&&!ip.isDefaultLut());
if (imageType==COLOR_256 || customLut)
fi.fileType = FileInfo.COLOR8;
else
fi.fileType = FileInfo.GRAY8;
......@@ -2053,7 +2119,7 @@ public class ImagePlus implements ImageObserver, Measurements, Cloneable {
fi.fileType = fi.GRAY16_UNSIGNED;
if (!compositeImage) {
lut = createLut();
if (!lut.isGrayscale())
if (!lut.isGrayscale() || (ip!=null&&!ip.isDefaultLut()))
addLut(lut, fi);
}
break;
......@@ -2061,7 +2127,7 @@ public class ImagePlus implements ImageObserver, Measurements, Cloneable {
fi.fileType = fi.GRAY32_FLOAT;
if (!compositeImage) {
lut = createLut();
if (!lut.isGrayscale())
if (!lut.isGrayscale() || (ip!=null&&!ip.isDefaultLut()))
addLut(lut, fi);
}
break;
......@@ -2161,6 +2227,34 @@ public class ImagePlus implements ImageObserver, Measurements, Cloneable {
return (new Duplicator()).crop(this);
}
/** Returns a cropped copy this image or stack, where 'options'
* can be "stack", "slice" or a range (e.g., "20-30").
* @see #duplicate
* @see #crop
* @see ij.plugin.Duplicator#crop
*/
public ImagePlus crop(String options) {
String msg = "crop: \"stack\", \"slice\" or a range (e.g., \"20-30\") expected";
int stackSize = getStackSize();
if (options==null || options.equals("stack"))
return (new Duplicator()).run(this);
else if (options.equals("slice") || stackSize==1)
return crop();
else {
String[] range = Tools.split(options, " -");
if (range.length!=2)
throw new IllegalArgumentException(msg);
double s1 = Tools.parseDouble(range[0]);
double s2 = Tools.parseDouble(range[1]);
if (Double.isNaN(s1) || Double.isNaN(s2))
throw new IllegalArgumentException(msg);
if (s1<1) s1 = 1;
if (s2>stackSize) s2 = stackSize;
if (s1>s2) {s1=1; s2=stackSize;}
return new Duplicator().run(this, (int)s1, (int)s2);
}
}
/** Returns a new ImagePlus with this image's attributes
(e.g. spatial scale), but no image. */
public ImagePlus createImagePlus() {
......@@ -2899,4 +2993,12 @@ public class ImagePlus implements ImageObserver, Measurements, Cloneable {
return stack!=null;
}
public void setPlot(Plot plot) {
this.plot = plot;
}
public Plot getPlot() {
return plot;
}
}
......@@ -102,8 +102,15 @@ public class ImageStack {
/** Adds the image in 'ip' to the end of the stack, setting
the string 'sliceLabel' as the slice metadata. */
public void addSlice(String sliceLabel, ImageProcessor ip) {
if (ip.getWidth()!=width || ip.getHeight()!=height)
if (ip.getWidth()!=width || ip.getHeight()!=height) {
if (width==0 && height==0) {
width = ip.getWidth();
height = ip.getHeight();
stack = new Object[INITIAL_SIZE];
label = new String[INITIAL_SIZE];
} else
throw new IllegalArgumentException("ImageStack.addSlice(): dimensions do not match");
}
if (nSlices==0) {
cm = ip.getColorModel();
min = ip.getMin();
......@@ -346,10 +353,11 @@ public class ImageStack {
return ("stack["+getWidth()+"x"+getHeight()+"x"+getSize()+v+"]");
}
/** Returns, as a double, the specified voxel. Returns
* NaN if x, y or z are beyond the stack limits. Use the
* ImagePlus.getStackIndex() method to convert a C,Z,T
* hyperstack position (one-based) into a z index (zero-based).
/** Returns, as a double, the value of the specified voxel.
* Throws an IndexOutOfBoundsException if x, y or z are
* beyond the stack limits. Use the ImagePlus.getStackIndex()
* method to convert a C,Z,T hyperstack position (one-based)
* into a z index (zero-based).
* @see ij.ImagePlus#getStackIndex
*/
public final double getVoxel(int x, int y, int z) {
......
......@@ -167,5 +167,12 @@ public class Macro {
return key;
}
/** Evaluates 'code' and returns the output, or any error,
* as a String (e.g., Macro.eval("2+2") returns "4").
*/
public static String eval(String code) {
return new Interpreter().eval(code);
}
}
......@@ -80,6 +80,7 @@ public class Menus {
private static int defaultFontSize = IJ.isWindows()?15:0;
private static int fontSize = Prefs.getInt(Prefs.MENU_SIZE, defaultFontSize);
private static Font menuFont;
private static double scale = 1.0;
static boolean jnlp; // true when using Java WebStart
public static int setMenuBarCount;
......@@ -92,6 +93,9 @@ public class Menus {
}
String addMenuBar() {
scale = Prefs.getGuiScale();
if ((scale>=1.5&&scale<2.0) || (scale>=2.5&&scale<3.0))
scale = (int)Math.round(scale);
nPlugins = nMacros = userPluginsIndex = 0;
addSorted = installingJars = duplicateCommand = false;
error = null;
......@@ -111,6 +115,15 @@ public class Menus {
addPlugInItem(openSamples, "Cache Sample Images ", "ij.plugin.URLOpener(\"cache\")", 0, false);
addOpenRecentSubMenu(file);
Menu importMenu = getMenu("File>Import", true);
Menu showFolderMenu = new Menu("Show Folder");
file.add(showFolderMenu);
addPlugInItem(showFolderMenu, "Image", "ij.plugin.SimpleCommands(\"showdirImage\")", 0, false);
addPlugInItem(showFolderMenu, "Plugins", "ij.plugin.SimpleCommands(\"showdirPlugins\")", 0, false);
addPlugInItem(showFolderMenu, "Macros", "ij.plugin.SimpleCommands(\"showdirMacros\")", 0, false);
addPlugInItem(showFolderMenu, "LUTs", "ij.plugin.SimpleCommands(\"showdirLuts\")", 0, false);
addPlugInItem(showFolderMenu, "ImageJ", "ij.plugin.SimpleCommands(\"showdirImageJ\")", 0, false);
addPlugInItem(showFolderMenu, "temp", "ij.plugin.SimpleCommands(\"showdirTemp\")", 0, false);
addPlugInItem(showFolderMenu, "Home", "ij.plugin.SimpleCommands(\"showdirHome\")", 0, false);
file.addSeparator();
addPlugInItem(file, "Close", "ij.plugin.Commands(\"close\")", KeyEvent.VK_W, false);
addPlugInItem(file, "Close All", "ij.plugin.Commands(\"close-all\")", KeyEvent.VK_W, true);
......@@ -249,13 +262,18 @@ public class Menus {
file.addSeparator();
addPlugInItem(file, "Quit", "ij.plugin.Commands(\"quit\")", 0, false);
if (fontSize!=0)
//System.out.println("MenuBar.setFont: "+fontSize+" "+scale+" "+getFont());
if (fontSize!=0 || scale>1.0)
mbar.setFont(getFont());
if (ij!=null) {
ij.setMenuBar(mbar);
Menus.setMenuBarCount++;
}
// Add deleted sample images to commands table
pluginsTable.put("Lena (68K)", "ij.plugin.URLOpener(\"lena-std.tif\")");
pluginsTable.put("Bridge (174K)", "ij.plugin.URLOpener(\"bridge.gif\")");
if (pluginError!=null)
error = error!=null?error+="\n"+pluginError:pluginError;
if (jarError!=null)
......@@ -296,6 +314,7 @@ public class Menus {
addExample(submenu, "Custom Measurement", "Custom_Measurement.ijm");
addExample(submenu, "Synthetic Images", "Synthetic_Images.ijm");
addExample(submenu, "Spiral Rotation", "Spiral_Rotation.ijm");
addExample(submenu, "Curve Fitting", "Curve_Fitting.ijm");
submenu.addSeparator();
addExample(submenu, "Circle Tool", "Circle_Tool.ijm");
addExample(submenu, "Star Tool", "Star_Tool.ijm");
......@@ -327,6 +346,7 @@ public class Menus {
addExample(submenu, "Terabyte VirtualStack", "Terabyte_VirtualStack.js");
addExample(submenu, "Event Listener", "Event_Listener.js");
addExample(submenu, "FFT Filter", "FFT_Filter.js");
addExample(submenu, "Curve Fitting", "Curve_Fitting.js");
submenu.addActionListener(listener);
menu.add(submenu);
submenu = new Menu("BeanShell");
......@@ -1148,9 +1168,8 @@ public class Menus {
int count = 0;
MenuItem mi;
popup = new PopupMenu("");
if (fontSize!=0)
if (fontSize!=0 || scale>1.0)
popup.setFont(getFont());
while (true) {
count++;
s = Prefs.getString("popup" + (count/10)%10 + count%10);
......@@ -1609,12 +1628,17 @@ public class Menus {
/** Returns the size (in points) used for the fonts in ImageJ menus. Returns
0 if the default font size is being used or if this is a Macintosh. */
public static int getFontSize() {
return IJ.isMacintosh()?0:fontSize;
return fontSize;
//return IJ.isMacintosh()?0:fontSize;
}
public static Font getFont() {
if (menuFont==null)
menuFont = new Font("SanSerif", Font.PLAIN, fontSize==0?12:fontSize);
if (menuFont==null) {
int size = fontSize==0?12:fontSize;
size = (int)Math.round(size*scale);
menuFont = new Font("SanSerif", Font.PLAIN, size);
}
//System.out.println("Menus.getFont: "+scale+" "+fontSize+" "+menuFont);
return menuFont;
}
......@@ -1648,4 +1672,26 @@ public class Menus {
IJ.showStatus("Menus updated: "+m.nPlugins + " commands, " + m.nMacros + " macros");
}
public static void updateFont() {
scale = (int)Math.round(Prefs.getGuiScale());
Font font = getFont();
mbar.setFont(font);
if (ij!=null)
ij.setMenuBar(mbar);
popup.setFont(font);
}
/** Adds a command to the ImageJ menu bar. */
public static void add(String menuPath, String plugin) {
if (pluginsTable==null)
return;
int index = menuPath.lastIndexOf(">");
if (index==-1 || index==menuPath.length()-1)
return;
String label = menuPath.substring(index+1, menuPath.length());
menuPath = menuPath.substring(0, index);
pluginsTable.put(label, plugin);
addItem(getMenu(menuPath), label, 0, false);
}
}
......@@ -36,6 +36,7 @@ public class Prefs {
public static final String DIV_BY_ZERO_VALUE = "div-by-zero";
public static final String NOISE_SD = "noise.sd";
public static final String MENU_SIZE = "menu.size";
public static final String GUI_SCALE = "gui.scale";
public static final String THREADS = "threads";
public static final String KEY_PREFIX = ".";
......@@ -169,7 +170,7 @@ public class Prefs {
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;
public static boolean doNotSaveWindowLocations;
/** Use JFileChooser setting changed/ */
public static boolean jFileChooserSettingChanged;
/** Convert tiff units to microns if pixel width is less than 0.0001 cm. */
......@@ -188,43 +189,58 @@ public class Prefs {
static Properties props = new Properties(ijPrefs);
static String prefsDir;
static String imagesURL;
static String homeDir; // ImageJ folder
static String ImageJDir;
static int threads;
static int transparentIndex = -1;
private static boolean resetPreferences;
/** Finds and loads the ImageJ configuration file, "IJ_Props.txt".
@return an error message if "IJ_Props.txt" not found.
private static double guiScale = 1.0;
private static Properties locKeys = new Properties();
private static String propertiesPath; // location of custom IJ_Props.txt
private static String preferencesPath; // location of custom IJ_Prefs.txt
/** Finds and loads the configuration file ("IJ_Props.txt")
* and the preferences file ("IJ_Prefs.txt").
* @return an error message if "IJ_Props.txt" not found.
*/
public static String load(Object ij, Applet applet) {
InputStream f = ij.getClass().getResourceAsStream("/"+PROPS_NAME);
if (applet!=null)
return loadAppletProps(f, applet);
if (homeDir==null)
homeDir = System.getProperty("user.dir");
if (ImageJDir==null)
ImageJDir = System.getProperty("user.dir");
InputStream f = null;
try { // Look for IJ_Props.txt in ImageJ folder
f = new FileInputStream(ImageJDir+"/"+PROPS_NAME);
propertiesPath = ImageJDir+"/"+PROPS_NAME;
} catch (FileNotFoundException e) {
f = null;
}
if (f==null) {
try {f = new FileInputStream(homeDir+"/"+PROPS_NAME);}
catch (FileNotFoundException e) {f=null;}
// Look in ij.jar if not found in ImageJ folder
f = ij.getClass().getResourceAsStream("/"+PROPS_NAME);
}
if (applet!=null)
return loadAppletProps(f, applet);
if (f==null)
return PROPS_NAME+" not found in ij.jar or in "+homeDir;
return PROPS_NAME+" not found in ij.jar or in "+ImageJDir;
f = new BufferedInputStream(f);
try {props.load(f); f.close();}
catch (IOException e) {return("Error loading "+PROPS_NAME);}
try {
props.load(f);
f.close();
} catch (IOException e) {
return("Error loading "+PROPS_NAME);
}
imagesURL = props.getProperty("images.location");
loadPreferences();
loadOptions();
guiScale = get(GUI_SCALE, 1.0);
return null;
}
/*
static void dumpPrefs(String title) {
IJ.log("");
IJ.log(title);
static void dumpPrefs() {
System.out.println("");
Enumeration e = ijPrefs.keys();
while (e.hasMoreElements()) {
String key = (String) e.nextElement();
IJ.log(key+": "+ijPrefs.getProperty(key));
System.out.println(key+": "+ijPrefs.getProperty(key));
}
}
*/
......@@ -258,14 +274,14 @@ public class Prefs {
/** Obsolete, replaced by getImageJDir(), which, unlike this method,
returns a path that ends with File.separator. */
public static String getHomeDir() {
return homeDir;
return ImageJDir;
}
/** Returns the path, ending in File.separator, to the ImageJ directory. */
public static String getImageJDir() {
String path = Menus.getImageJPath();
if (path==null)
return homeDir + File.separator;
return ImageJDir + File.separator;
else
return path;
}
......@@ -273,6 +289,15 @@ public class Prefs {
/** Returns the path to the directory where the
preferences file (IJPrefs.txt) is saved. */
public static String getPrefsDir() {
if (prefsDir==null) {
if (ImageJDir==null)
ImageJDir = System.getProperty("user.dir");
File f = new File(ImageJDir+File.separator+PREFS_NAME);
if (f.exists()) {
prefsDir = ImageJDir;
preferencesPath = ImageJDir+"/"+PREFS_NAME;
}
//System.out.println("getPrefsDir: "+f+" "+prefsDir);
if (prefsDir==null) {
String dir = System.getProperty("user.home");
if (IJ.isMacOSX())
......@@ -281,6 +306,7 @@ public class Prefs {
dir += File.separator+".imagej";
prefsDir = dir;
}
}
return prefsDir;
}
......@@ -288,7 +314,7 @@ public class Prefs {
static void setHomeDir(String path) {
if (path.endsWith(File.separator))
path = path.substring(0, path.length()-1);
homeDir = path;
ImageJDir = path;
}
/** Returns the default directory, if any, or null. */
......@@ -299,7 +325,7 @@ public class Prefs {
return getString(DIR_IMAGE);
}
/** Finds an string in IJ_Props or IJ_Prefs.txt. */
/** Finds a string in IJ_Props or IJ_Prefs.txt. */
public static String getString(String key) {
return props.getProperty(key);
}
......@@ -366,13 +392,13 @@ public class Prefs {
return separator;
}
/** Opens the IJ_Prefs.txt file. */
/** Opens the ImageJ preferences file ("IJ_Prefs.txt") file. */
static void loadPreferences() {
String path = getPrefsDir()+separator+PREFS_NAME;
boolean ok = loadPrefs(path);
if (!ok) { // not found
if (IJ.isWindows())
path = homeDir +separator+PREFS_NAME; // ImageJ folder
path = ImageJDir +separator+PREFS_NAME;
else
path = System.getProperty("user.home")+separator+PREFS_NAME; //User's home dir
ok = loadPrefs(path);
......@@ -499,6 +525,7 @@ public class Prefs {
jFileChooserSettingChanged = (options2&JFILE_CHOOSER_CHANGED)!=0;
dialogCancelButtonOnRight = (options2&CANCEL_BUTTON_ON_RIGHT)!=0;
ignoreRescaleSlope = (options2&IGNORE_RESCALE_SLOPE)!=0;
;
}
static void saveOptions(Properties prefs) {
......@@ -622,15 +649,20 @@ public class Prefs {
double yloc = Tools.parseDouble(value.substring(index+1));
if (Double.isNaN(yloc)) return null;
Point p = new Point((int)xloc, (int)yloc);
Dimension screen = null;
if (IJ.debugMode)
screen = Toolkit.getDefaultToolkit().getScreenSize();
else
screen = IJ.getScreenSize();
if (p.x>screen.width-100 || p.y>screen.height-40)
return null;
else
Rectangle bounds = GUI.getScreenBounds(p); // get bounds of screen that contains p
if (bounds!=null && p.x+100<=bounds.x+bounds.width && p.y+ 40<=bounds.y+bounds.height) {
if (locKeys.get(key)==null) { // first time for this key?
locKeys.setProperty(key, "");
Rectangle primaryScreen = GUI.getMaxWindowBounds();
ImageJ ij = IJ.getInstance();
Point ijLoc = ij!=null?ij.getLocation():null;
//System.out.println("getLoc: "+key+" "+(ijLoc!=null&&primaryScreen.contains(ijLoc)) + " "+!primaryScreen.contains(p));
if ((ijLoc!=null&&primaryScreen.contains(ijLoc)) && !primaryScreen.contains(p))
return null; // return null if "ImageJ" window on primary screen and this location is not
}
return p;
} else
return null;
}
/** Save plugin preferences. */
......@@ -686,5 +718,28 @@ public class Prefs {
return get("options.ext", ".csv");
}
/** Sets the GenericDialog and Command Finder text scale (0.5 to 3.0). */
public static void setGuiScale(double scale) {
if (scale>=0.5 && scale<=3.0) {
guiScale = scale;
set(GUI_SCALE, guiScale);
}
}
/** Returns the GenericDialog and Command Finder text scale. */
public static double getGuiScale() {
return guiScale;
}
/** Returns the custom properties (IJ_Props.txt) file path. */
public static String getCustomPropsPath() {
return propertiesPath;
}
/** Returns the custom preferences (IJ_Prefs.txt) file path. */
public static String getCustomPrefsPath() {
return preferencesPath;
}
}
......@@ -59,8 +59,9 @@ public class Undo {
else
reset();
} else if (what==MACRO) {
impCopy = new ImagePlus(imp.getTitle(), imp.getProcessor().duplicate());
whatToUndo = TRANSFORM;
ipCopy = imp.getProcessor().duplicate();
calCopy = (Calibration)imp.getCalibration().clone();
impCopy = null;
} else if (what==COMPOUND_FILTER) {
ImageProcessor ip = imp.getProcessor();
if (ip!=null)
......@@ -99,7 +100,6 @@ public class Undo {
lutCopy = null;
}
public static void undo() {
ImagePlus imp = WindowManager.getCurrentImage();
if (IJ.debugMode) IJ.log("Undo.undo: "+ whatToUndo+" "+imp+" "+impCopy);
......@@ -153,6 +153,12 @@ public class Undo {
setup(ROI, imp); // setup redo
imp.setRoi(roiCopy2);
return; //don't reset
case MACRO:
if (ipCopy!=null) {
imp.setProcessor(ipCopy);
if (calCopy!=null) imp.setCalibration(calCopy);
}
break;
case OVERLAY_ADDITION:
Overlay overlay = imp.getOverlay();
if (overlay==null)
......
......@@ -3,6 +3,7 @@ import ij.process.*;
import ij.io.*;
import ij.gui.ImageCanvas;
import ij.util.Tools;
import ij.plugin.FolderOpener;
import java.io.*;
import java.awt.*;
import java.awt.image.ColorModel;
......@@ -132,8 +133,14 @@ public class VirtualStack extends ImageStack {
int type = imp.getType();
ColorModel cm = imp.getProcessor().getColorModel();
String info = (String)imp.getProperty("Info");
if (info!=null && !(info.startsWith("Software")||info.startsWith("ImageDescription")))
if (info!=null) {
if (FolderOpener.useInfo(info))
labels[n-1] = info;
} else {
String sliceLabel = imp.getStack().getSliceLabel(1);
if (FolderOpener.useInfo(sliceLabel))
labels[n-1] = "Label: "+sliceLabel;
}
depthThisImage = imp.getBitDepth();
ip = imp.getProcessor();
ip.setOverlay(imp.getOverlay());
......@@ -189,10 +196,12 @@ public class VirtualStack extends ImageStack {
String label = labels[n-1];
if (label==null)
return names[n-1];
else if (label.length()>100 && label.indexOf('\n')>0)
return names[n-1]+"\n"+label;
else {
if (label.startsWith("Label: ")) // slice label
return label.substring(7,label.length());
else
return label;
return names[n-1]+"\n"+label;
}
}
/** Returns null. */
......@@ -215,7 +224,10 @@ public class VirtualStack extends ImageStack {
/** Returns the path to the directory containing the images. */
public String getDirectory() {
return path;
String path2 = path;
if (!(path2.endsWith("/") || path2.endsWith(File.separator)))
path2 = path2 + "/";
return path2;
}
/** Returns the file name of the specified slice, were 1<=n<=nslices. */
......
......@@ -375,7 +375,8 @@ public class WindowManager {
int index = imageList.indexOf(win);
if (index==-1)
return; // not on the window list
imageList.removeElementAt(index);
try {
imageList.remove(win);
activations.remove(win);
if (imageList.size()>1 && !Prefs.closingAll) {
ImageWindow win2 = activations.size()>0?(ImageWindow)activations.get(activations.size()-1):null;
......@@ -389,11 +390,12 @@ public class WindowManager {
Menus.removeWindowMenuItem(nonImageCount+index);
Menus.updateMenus();
Undo.reset();
} catch (Exception e) { }
}
/** The specified Window becomes the front window. */
public static void setWindow(Window win) {
//System.out.println("setWindow: "+win);
//System.out.println("setWindow(W): "+win);
frontWindow = win;
if (win instanceof Frame)
frontFrame = (Frame)win;
......@@ -403,7 +405,7 @@ public class WindowManager {
public static void setWindow(Frame win) {
frontWindow = win;
frontFrame = win;
//System.out.println("Set window: "+(win!=null?win.getTitle():"null"));
//System.out.println("Set window(F): "+(win!=null?win.getTitle():"null"));
}
/** Closes all windows. Stops and returns false if an image or Editor "save changes" dialog is canceled. */
......
......@@ -61,8 +61,7 @@ public class Arrow extends Line {
if (fillColor!=null) color = fillColor;
g.setColor(color);
Graphics2D g2 = (Graphics2D)g;
if (!overlay)
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
setRenderingHint(g2);
AffineTransform at = g2.getDeviceConfiguration().getDefaultTransform();
double mag = getMagnification();
int xbase=0, ybase=0;
......
......@@ -17,6 +17,7 @@ public class ColorChooser implements TextListener, AdjustmentListener {
boolean useHSB;
String title;
Frame frame;
double scale = Prefs.getGuiScale();
/** Constructs a ColorChooser using the specified title and initial color. */
public ColorChooser(String title, Color initialColor, boolean useHSB) {
......@@ -40,7 +41,7 @@ public class ColorChooser implements TextListener, AdjustmentListener {
gd.addSlider("Red:", 0, 255, red);
gd.addSlider("Green:", 0, 255, green);
gd.addSlider("Blue:", 0, 255, blue);
panel = new ColorPanel(initialColor);
panel = new ColorPanel(initialColor, scale);
gd.addPanel(panel, GridBagConstraints.CENTER, new Insets(10, 0, 0, 0));
colors = gd.getNumericFields();
for (int i=0; i<colors.size(); i++)
......@@ -80,16 +81,19 @@ public class ColorChooser implements TextListener, AdjustmentListener {
}
class ColorPanel extends Panel {
static final int WIDTH=150, HEIGHT=50;
static Font font = new Font("Monospaced", Font.PLAIN, 18);
Color c;
private int width=150, height=50;
private Font font;
private Color c;
ColorPanel(Color c) {
ColorPanel(Color c, double scale) {
this.c = c;
width = (int)(width*scale);
height = (int)(height*scale);
font = new Font("Monospaced", Font.PLAIN, (int)(18*scale));
}
public Dimension getPreferredSize() {
return new Dimension(WIDTH, HEIGHT);
return new Dimension(width, height);
}
void setColor(Color c) {
......@@ -97,21 +101,21 @@ class ColorPanel extends Panel {
}
public Dimension getMinimumSize() {
return new Dimension(WIDTH, HEIGHT);
return new Dimension(width, height);
}
public void paint(Graphics g) {
g.setColor(c);
g.fillRect(0, 0, WIDTH, HEIGHT);
g.fillRect(0, 0, width, height);
int intensity = (c.getRed()+c.getGreen()+c.getBlue())/3;
Color c2 = intensity<128?Color.white:Color.black;
g.setColor(c2);
g.setFont(font);
Java2.setAntialiasedText(g, true);
String s = Colors.colorToString(c);
g.drawString(s, 5, HEIGHT-5);
g.drawString(s, 5, height-5);
g.setColor(Color.black);
g.drawRect(0, 0, WIDTH-1, HEIGHT-1);
g.drawRect(0, 0, width-1, height-1);
}
}
......@@ -243,13 +243,22 @@ public class EllipseRoi extends PolygonRoi {
pw = cal.pixelWidth;
ph = cal.pixelHeight;
}
if (pw != ph) //the following calculation holds only for pixel aspect ratio == 1 (otherwise different axes in distorted ellipse)
return a;
double[] p = getParams();
double dx = (p[2] - p[0])*pw;
double dy = (p[3] - p[1])*ph;
double dx = p[2] - p[0]; //this is always major axis; aspect ratio p[4] is limited to <= 1
double dy = p[3] - p[1];
double major = Math.sqrt(dx*dx + dy*dy);
double minor = major*p[4];
a[0] = major;
a[2] = (pw==ph)?minor:a[2];
a[0] = major*pw; //Feret from convex hull should be accurate anyhow
a[2] = minor*pw; //here our own calculation is better
System.arraycopy(p, 0, a, 8, 4); //MaxFeret endpoints
double xCenter = 0.5*(p[2] + p[0]);
double yCenter = 0.5*(p[3] + p[1]);
double semiMinorX = dy * 0.5 * p[4];
double semiMinorY = dx * (-0.5) * p[4];
a[12] = xCenter + semiMinorX; a[14] = xCenter - semiMinorX;
a[13] = yCenter + semiMinorY; a[15] = yCenter - semiMinorY;
return a;
}
......