From 44685d06871189a808ec75661d9152d3e5a5b0a6 Mon Sep 17 00:00:00 2001 From: Wayne Rasband Date: Mon, 24 Aug 2009 23:49:35 +0200 Subject: [PATCH] =?UTF-8?q?=20=20=E2=80=A2=201.43f,=2024=20August=202009?= =?UTF-8?q?=20=20=20=20=20=20=20=E2=96=A1=20The=20Image>Scale=20and=20Imag?= =?UTF-8?q?e>Adjust>Size=20commands=20now=20scale=20stacks=20=20=20=20=20?= =?UTF-8?q?=20=20=20=20and=20hyperstacks=20in=20the=20Z=20dimension.=20=20?= =?UTF-8?q?=20=20=20=20=20=E2=96=A1=20The=20Image>Color>Merge=20Channels?= =?UTF-8?q?=20command=20now=20works=20with=20=20=20=20=20=20=20=20=20hyper?= =?UTF-8?q?stacks.=20=20=20=20=20=20=20=E2=96=A1=20Added=20the=20File>New>?= =?UTF-8?q?Hyperstack=20command,=20an=20alias=20for=20Image>=20=20=20=20?= =?UTF-8?q?=20=20=20=20=20Hyperstacks>New=20Hyperstack.=20=20=20=20=20=20?= =?UTF-8?q?=20=E2=96=A1=20Analyze>Tools>Fractal=20Box=20Counter=20writes?= =?UTF-8?q?=20results=20that=20can=20be=20=20=20=20=20=20=20=20=20read=20b?= =?UTF-8?q?y=20macros.=20=20=20=20=20=20=20=E2=96=A1=20Added=20the=20List.?= =?UTF-8?q?setCommands,=20setFont("user"),=20getInfo=20=20=20=20=20=20=20?= =?UTF-8?q?=20=20("font.name"),=20getValue("font.size")=20and=20getValue?= =?UTF-8?q?=20=20=20=20=20=20=20=20=20("font.height")=20macro=20functions.?= =?UTF-8?q?=20=20=20=20=20=20=20=E2=96=A1=20Thanks=20to=20Johannes=20Schin?= =?UTF-8?q?delin,=20added=20the=20=20=20=20=20=20=20=20=20NonBlockingGener?= =?UTF-8?q?icDialog=20class,=20now=20used=20by=20the=20Process>Batch>=20?= =?UTF-8?q?=20=20=20=20=20=20=20=20Process=20command.=20=20=20=20=20=20=20?= =?UTF-8?q?=E2=96=A1=20Fixed=20a=20bug=20that=20sometimes=20caused=20the?= =?UTF-8?q?=20Image>Adjust>Brightness/=20=20=20=20=20=20=20=20=20Contrast?= =?UTF-8?q?=20"Apply"=20function=20to=20fail=20with=20RGB=20stacks.=20=20?= =?UTF-8?q?=20=20=20=20=20=E2=96=A1=20Fixed=20a=20bug=20that=20sometimes?= =?UTF-8?q?=20caused=20Image>Color>Split=20Channels=20to=20=20=20=20=20=20?= =?UTF-8?q?=20=20=20display=20a=20"save=20changes=3F"=20dialog=20box.=20?= =?UTF-8?q?=20=20=20=20=20=20=E2=96=A1=20Fixed=20a=20bug=20that=20caused?= =?UTF-8?q?=20File>Save=20As>Image=20Sequence=20to=20throw=20an=20=20=20?= =?UTF-8?q?=20=20=20=20=20=20exception=20if=20the=20window=20was=20closed?= =?UTF-8?q?=20before=20all=20the=20images=20in=20the=20=20=20=20=20=20=20?= =?UTF-8?q?=20=20stack=20were=20saved.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- IJ_Props.txt | 10 +- ij/IJ.java | 3 +- ij/ImageJ.java | 3 +- ij/Menus.java | 2 +- ij/Prefs.java | 9 + ij/gui/GenericDialog.java | 49 ++- ij/gui/NonBlockingGenericDialog.java | 26 ++ ij/gui/TextRoi.java | 22 ++ ij/io/FileSaver.java | 6 +- ij/io/OpenDialog.java | 12 +- ij/io/Opener.java | 126 ++++--- ij/io/SaveDialog.java | 4 +- ij/io/TiffDecoder.java | 2 +- ij/macro/Functions.java | 57 ++- ij/macro/Interpreter.java | 10 + ij/plugin/AVI_Reader.java | 6 +- ij/plugin/BatchProcesser.java | 21 +- ij/plugin/PNG_Writer.java | 43 --- ij/plugin/RGBStackMerge.java | 469 ++++++++++++++---------- ij/plugin/Resizer.java | 409 +++++++++++++++++++++ ij/plugin/Scaler.java | 294 +++++++++------ ij/plugin/StackWriter.java | 19 +- ij/plugin/filter/Analyzer.java | 2 +- ij/plugin/filter/FractalBoxCounter.java | 52 ++- ij/plugin/filter/RGBStackSplitter.java | 2 +- ij/plugin/filter/Resizer.java | 176 --------- ij/plugin/filter/StackLabeler.java | 15 +- ij/plugin/frame/ContrastAdjuster.java | 30 +- ij/process/ImageProcessor.java | 6 + ij/process/ShortProcessor.java | 2 +- release-notes.html | 31 +- 31 files changed, 1215 insertions(+), 703 deletions(-) create mode 100644 ij/gui/NonBlockingGenericDialog.java create mode 100644 ij/plugin/Resizer.java delete mode 100644 ij/plugin/filter/Resizer.java diff --git a/IJ_Props.txt b/IJ_Props.txt index 58a4cf4f0..c7c1b62ea 100644 --- a/IJ_Props.txt +++ b/IJ_Props.txt @@ -24,9 +24,11 @@ popup12=Duplicate... # Plugins installed in the File/New submenu new01="Image...[n]",ij.plugin.Commands("new") -new02="Text Window[N]",ij.plugin.NewPlugin("text") -new03="Internal Clipboard",ij.plugin.Clipboard("show") -new04="System Clipboard[V]",ij.plugin.Clipboard("showsys") +new02="Hyperstack...",ij.plugin.HyperStackConverter("new") +new03="Text Window[N]",ij.plugin.NewPlugin("text") +new04="Internal Clipboard",ij.plugin.Clipboard("show") +new05="System Clipboard[V]",ij.plugin.Clipboard("showsys") + # Plugins installed in the File/Import submenu import01="Image Sequence...",ij.plugin.FolderOpener import02="Raw...",ij.plugin.Raw @@ -101,7 +103,7 @@ adjust01="Brightness/Contrast...[C]",ij.plugin.frame.ContrastAdjuster adjust02="Window/Level...",ij.plugin.frame.ContrastAdjuster("wl") adjust03="Color Balance...",ij.plugin.frame.ContrastAdjuster("balance") adjust04="Threshold...[T]",ij.plugin.frame.ThresholdAdjuster -adjust05="Size...",ij.plugin.filter.Resizer +adjust05="Size...",ij.plugin.Resizer adjust06="Canvas Size...",ij.plugin.CanvasResizer adjust07="Line Width... ",ij.plugin.frame.LineWidthAdjuster diff --git a/ij/IJ.java b/ij/IJ.java index 607a16caf..9bb52697a 100644 --- a/ij/IJ.java +++ b/ij/IJ.java @@ -323,8 +323,7 @@ public static void showStatus(String s) { ic.setShowCursorStatus(s.length()==0?true:false); } - /** Displays a line of text in the "Results" window. Writes to - System.out.println if the "ImageJ" frame is not present. */ + /** Obsolete; replaced by IJ.log().*/ public static void write(String s) { if (textPanel==null && ij!=null) showResults(); diff --git a/ij/ImageJ.java b/ij/ImageJ.java index 5ea7b6b70..62bce3406 100644 --- a/ij/ImageJ.java +++ b/ij/ImageJ.java @@ -69,7 +69,7 @@ public class ImageJ extends Frame implements ActionListener, MouseListener, KeyListener, WindowListener, ItemListener, Runnable { /** Plugins should call IJ.getVersion() to get the version string. */ - public static final String VERSION = "1.43e"; + public static final String VERSION = "1.43f"; public static Color backgroundColor = new Color(220,220,220); //224,226,235 /** SansSerif, 12-point, plain font. */ public static final Font SansSerif12 = new Font("SansSerif", Font.PLAIN, 12); @@ -561,6 +561,7 @@ else if (delta>0 && DEFAULT_PORT+delta<65536) if (arg.startsWith("-")) { if ((arg.startsWith("-macro") || arg.startsWith("-batch")) && i+1Stacks", true); Menu hyperstacksMenu = getMenu("Image>Hyperstacks", true); image.addSeparator(); - addPlugInItem(image, "Crop", "ij.plugin.filter.Resizer(\"crop\")", KeyEvent.VK_X, true); + addPlugInItem(image, "Crop", "ij.plugin.Resizer(\"crop\")", KeyEvent.VK_X, true); addPlugInItem(image, "Duplicate...", "ij.plugin.filter.Duplicater", KeyEvent.VK_D, true); addPlugInItem(image, "Rename...", "ij.plugin.SimpleCommands(\"rename\")", 0, false); addPlugInItem(image, "Scale...", "ij.plugin.Scaler", KeyEvent.VK_E, false); diff --git a/ij/Prefs.java b/ij/Prefs.java index 5dba55008..ae85c388b 100644 --- a/ij/Prefs.java +++ b/ij/Prefs.java @@ -109,6 +109,7 @@ public class Prefs { static String homeDir; // ImageJ folder static int threads; static int transparentIndex = -1; + static boolean commandLineMacro; /** Finds and loads the ImageJ configuration file, "IJ_Props.txt". @return an error message if "IJ_Props.txt" not found. @@ -202,6 +203,14 @@ static void setHomeDir(String path) { homeDir = path; } + /** Returns the default directory, if any, or null. */ + public static String getDefaultDirectory() { + if (commandLineMacro) + return null; + else + return getString(DIR_IMAGE); + } + /** Finds an string in IJ_Props or IJ_Prefs.txt. */ public static String getString(String key) { return props.getProperty(key); diff --git a/ij/gui/GenericDialog.java b/ij/gui/GenericDialog.java index c0a7e9fbf..6cbc53de4 100644 --- a/ij/gui/GenericDialog.java +++ b/ij/gui/GenericDialog.java @@ -8,7 +8,7 @@ import ij.plugin.filter.PlugInFilter; import ij.plugin.filter.PlugInFilterRunner; import ij.util.Tools; -import ij.macro.MacroRunner; +import ij.macro.*; /** @@ -670,14 +670,20 @@ public double getNextNumber() { if (d!=null) value = d.doubleValue(); else { - invalidNumber = true; - errorMessage = "\""+theText+"\" is an invalid number"; - value = 0.0; - if (macro) { - IJ.error("Macro Error", "Numeric value expected in run() function\n \n" - +" Dialog: \""+getTitle()+"\"\n" - +" Label: \""+label+"\"\n" - +" Value: \""+theText+"\""); + // Is the value a macro variable? + if (theText.startsWith("&")) theText = theText.substring(1); + Interpreter interp = Interpreter.getInstance(); + value = interp!=null?interp.getVariable(theText):Double.NaN; + if (Double.isNaN(value)) { + invalidNumber = true; + errorMessage = "\""+theText+"\" is an invalid number"; + value = 0.0; + if (macro) { + IJ.error("Macro Error", "Numeric value expected in run() function\n \n" + +" Dialog box title: \""+getTitle()+"\"\n" + +" Key: \""+label.toLowerCase(Locale.US)+"\"\n" + +" Value or variable name: \""+theText+"\""); + } } } } @@ -744,7 +750,13 @@ public String getNextString() { if (macro) { String label = (String)labels.get((Object)tf); theText = Macro.getValue(macroOptions, label, theText); - //IJ.write("getNextString: "+label+" "+theText); + if (theText!=null && (theText.startsWith("&")||label.toLowerCase(Locale.US).startsWith(theText))) { + // Is the value a macro variable? + if (theText.startsWith("&")) theText = theText.substring(1); + Interpreter interp = Interpreter.getInstance(); + String s = interp!=null?interp.getStringVariable(theText):null; + if (s!=null) theText = s; + } } if (recorderOn) recordOption(tf, theText); @@ -824,10 +836,23 @@ public int getNextChoiceIndex() { String oldItem = thisChoice.getSelectedItem(); int oldIndex = thisChoice.getSelectedIndex(); String item = Macro.getValue(macroOptions, label, oldItem); + if (item!=null && item.startsWith("&")) { // value is macro variable + item = item.substring(1); + Interpreter interp = Interpreter.getInstance(); + String s = interp!=null?interp.getStringVariable(item):null; + if (s!=null) item = s; + } thisChoice.select(item); index = thisChoice.getSelectedIndex(); - if (index==oldIndex && !item.equals(oldItem)) - IJ.error(getTitle(), "\""+item+"\" is not a valid choice for \""+label+"\""); + if (index==oldIndex && !item.equals(oldItem)) { + // is value a macro variable? + Interpreter interp = Interpreter.getInstance(); + String s = interp!=null?interp.getStringVariable(item):null; + if (s==null) + IJ.error(getTitle(), "\""+item+"\" is not a valid choice for \""+label+"\""); + else + item = s; + } } if (recorderOn) recordOption(thisChoice, thisChoice.getSelectedItem()); diff --git a/ij/gui/NonBlockingGenericDialog.java b/ij/gui/NonBlockingGenericDialog.java new file mode 100644 index 000000000..8e4dc3c86 --- /dev/null +++ b/ij/gui/NonBlockingGenericDialog.java @@ -0,0 +1,26 @@ +package ij.gui; +import ij.IJ; +import java.awt.event.ActionEvent; + +/** This is an xtension of GenericDialog that is non-model. + * @author Johannes Schindelin + */ +public class NonBlockingGenericDialog extends GenericDialog { + public NonBlockingGenericDialog(String title) { + super(title, null); + setModal(false); + } + + public synchronized void showDialog() { + super.showDialog(); + try { + wait(); + } catch (InterruptedException e) { } + } + + public synchronized void actionPerformed(ActionEvent e) { + super.actionPerformed(e); + if (wasOKed() || wasCanceled()) + notify(); + } +} diff --git a/ij/gui/TextRoi.java b/ij/gui/TextRoi.java index 09f59abca..9617f3383 100644 --- a/ij/gui/TextRoi.java +++ b/ij/gui/TextRoi.java @@ -15,6 +15,7 @@ public class TextRoi extends Roi { private static int style = Font.PLAIN; private static int size = 18; private static Font font; + private Font instanceFont; private static boolean antialiasedText = true; private static boolean recordSetFont = true; private double previousMag; @@ -22,6 +23,22 @@ public class TextRoi extends Roi { private boolean firstMouseUp = true; private int cline = 0; + /** Creates a new TextRoi.*/ + public TextRoi(int x, int y, String text) { + this(x, y, text, null, null); + font = null; + firstChar = false; + } + + /** Creates a new TextRoi.*/ + public TextRoi(int x, int y, String text, Font font, Color color) { + super(x, y, 1, 1); + theText[0] = text; + instanceFont = font; + instanceColor = color; + if (IJ.debugMode) IJ.log("TextRoi: "+theText[0]+" "+width+","+height); + } + public TextRoi(int x, int y, ImagePlus imp) { super(x, y, imp); ImageCanvas ic = imp.getCanvas(); @@ -76,6 +93,8 @@ else if (cline>0) { } Font getCurrentFont() { + if (instanceFont!=null) + return instanceFont; double mag = ic.getMagnification(); if (font==null || mag!=previousMag) { font = new Font(name, style, (int)(size*mag)); @@ -103,6 +122,7 @@ public void drawPixels(ImageProcessor ip) { /** Draws the text on the screen, clipped to the ROI. */ public void draw(Graphics g) { +if (IJ.debugMode) IJ.log("draw: "+theText[0]+" "+width+","+height); super.draw(g); // draw the rectangle g.setColor(instanceColor!=null?instanceColor:ROIColor); double mag = ic.getMagnification(); @@ -192,6 +212,7 @@ protected void handleMouseUp(int screenX, int screenY) { /** Increases the size of the rectangle so it's large enough to hold the text. */ void adjustSize() { +if (IJ.debugMode) IJ.log("adjustSize1: "+theText[0]+" "+width+","+height); if (ic==null) return; double mag = ic.getMagnification(); @@ -225,6 +246,7 @@ void adjustSize() { y = yMax-height; updateClipRect(); imp.draw(clipX, clipY, clipWidth, clipHeight); +if (IJ.debugMode) IJ.log("adjustSize2: "+theText[0]+" "+width+","+height); } int stringWidth(String s, FontMetrics metrics, Graphics g) { diff --git a/ij/io/FileSaver.java b/ij/io/FileSaver.java index e5c717fc1..e8e028829 100644 --- a/ij/io/FileSaver.java +++ b/ij/io/FileSaver.java @@ -298,8 +298,7 @@ public boolean saveAsPgm(String path) { } /** Save the image in PNG format using a save file dialog. - Returns false if the user selects cancel. Requires - java 1.4 or later. */ + Returns false if the user selects cancel. */ public boolean saveAsPng() { String path = getPath("PNG", ".png"); if (path==null) @@ -308,8 +307,7 @@ public boolean saveAsPng() { return saveAsPng(path); } - /** Save the image in PNG format using the specified path. - Requires Java 1,4 or later. */ + /** Save the image in PNG format using the specified path. */ public boolean saveAsPng(String path) { IJ.runPlugIn(imp, "ij.plugin.PNG_Writer", path); return true; diff --git a/ij/io/OpenDialog.java b/ij/io/OpenDialog.java index 566505415..b971e9b74 100644 --- a/ij/io/OpenDialog.java +++ b/ij/io/OpenDialog.java @@ -3,6 +3,7 @@ import ij.gui.*; import ij.plugin.frame.Recorder; import ij.util.Java2; +import ij.macro.Interpreter; import java.awt.*; import java.io.*; import javax.swing.*; @@ -18,7 +19,7 @@ public class OpenDialog { private static String defaultDirectory; private static Frame sharedFrame; private String title; - static String lastDir, lastName; + private static String lastDir, lastName; /** Displays a file open dialog with 'title' as @@ -33,6 +34,13 @@ public OpenDialog(String title, String path) { path = Macro.getValue(macroOptions, "path", path); if ((path==null || path.equals("")) && title!=null && title.equals("Open As String")) path = Macro.getValue(macroOptions, "OpenAsString", path); + if (path!=null && path.indexOf(".")==-1 && !((new File(path)).exists())) { + // Is 'path' a macro variable? + if (path.startsWith("&")) path=path.substring(1); + Interpreter interp = Interpreter.getInstance(); + String path2 = interp!=null?interp.getStringVariable(path):null; + if (path2!=null) path = path2; + } } if (path==null || path.equals("")) { if (Prefs.useJFileChooser) @@ -180,7 +188,7 @@ public String getFileName() { returned string always ends with the separator character ("/" or "\").*/ public static String getDefaultDirectory() { if (defaultDirectory==null) - defaultDirectory = Prefs.getString(Prefs.DIR_IMAGE); + defaultDirectory = Prefs.getDefaultDirectory(); return defaultDirectory; } diff --git a/ij/io/Opener.java b/ij/io/Opener.java index 460519266..f76b44a58 100644 --- a/ij/io/Opener.java +++ b/ij/io/Opener.java @@ -27,9 +27,9 @@ public class Opener { public static final int UNKNOWN=0,TIFF=1,DICOM=2,FITS=3,PGM=4,JPEG=5, GIF=6,LUT=7,BMP=8,ZIP=9,JAVA_OR_TEXT=10,ROI=11,TEXT=12,PNG=13, - TIFF_AND_DICOM=14,CUSTOM=15, AVI=16; // don't forget to also update 'types' + TIFF_AND_DICOM=14,CUSTOM=15, AVI=16, OJJ=17; // don't forget to also update 'types' private static final String[] types = {"unknown","tif","dcm","fits","pgm", - "jpg","gif","lut","bmp","zip","java/txt","roi","txt","png","t&d","custom","avi"}; + "jpg","gif","lut","bmp","zip","java/txt","roi","txt","png","t&d","custom","ojj"}; private static String defaultDirectory = null; private static int fileType; private boolean error; @@ -122,13 +122,14 @@ public void open(String path) { (new PluginInstaller()).install(path); return; } - - boolean fullPath = path.startsWith("/") || path.startsWith("\\") || path.indexOf(":\\")==1 || isURL; - if (!fullPath && IJ.getInstance()!=null) { - String workingDir = OpenDialog.getDefaultDirectory(); - if (workingDir!=null) - path = workingDir + path; - } + boolean fullPath = path.startsWith("/") || path.startsWith("\\") || path.indexOf(":\\")==1 || isURL; + if (!fullPath) { + String defaultDir = OpenDialog.getDefaultDirectory(); + if (defaultDir!=null) + path = defaultDir + path; + else + path = (new File(path)).getAbsolutePath(); + } if (!silentMode) IJ.showStatus("Opening: " + path); long start = System.currentTimeMillis(); ImagePlus imp = openImage(path); @@ -168,6 +169,9 @@ public void open(String path) { } else new TextWindow(path,400,450); break; + case OJJ: // ObjectJ project + IJ.runPlugIn("ObjectJ_", path); + break; case UNKNOWN: String msg = "File is not in a supported format, a reader\n"+ @@ -176,7 +180,7 @@ public void open(String path) { if (path.length()>64) path = (new File(path)).getName(); if (path.length()<=64) - msg += " \n \n"+path; + msg += " \n \n"+path; } if (openUsingPlugins) msg += "\n \nNOTE: The \"OpenUsingPlugins\" option is set."; @@ -204,7 +208,7 @@ private boolean isText(String path) { /** Opens the specified file and adds it to the File/Open Recent menu. Returns true if the file was opened successfully. */ - public boolean openAndAddToRecent(String path) { + public boolean openAndAddToRecent(String path) { open(path); if (!error) Menus.addOpenRecentItem(path); @@ -298,7 +302,7 @@ public ImagePlus openImage(String path) { must end in ".zip" and dicom file names must end in ".dcm". Returns an ImagePlus object if successful. */ public ImagePlus openURL(String url) { - try { + try { String name = ""; int index = url.lastIndexOf('/'); if (index==-1) @@ -313,11 +317,11 @@ public ImagePlus openURL(String url) { IJ.showStatus(""+url); String lurl = url.toLowerCase(Locale.US); ImagePlus imp = null; - if (lurl.endsWith(".tif")) + if (lurl.endsWith(".tif")) imp = openTiff(u.openStream(), name); - else if (lurl.endsWith(".zip")) + else if (lurl.endsWith(".zip")) imp = openZipUsingUrl(u); - else if (lurl.endsWith(".dcm")) { + else if (lurl.endsWith(".dcm")) { imp = (ImagePlus)IJ.runPlugIn("ij.plugin.DICOM", url); if (imp!=null && imp.getWidth()==0) imp = null; } else if (lurl.endsWith(".jpg") || lurl.endsWith(".gif")) @@ -336,13 +340,13 @@ else if (type!=null && type.equals("image/png")) } IJ.showStatus(""); return imp; - } catch (Exception e) { - String msg = e.getMessage(); - if (msg==null || msg.equals("")) - msg = "" + e; + } catch (Exception e) { + String msg = e.getMessage(); + if (msg==null || msg.equals("")) + msg = "" + e; IJ.error("Open URL",msg + "\n \n" + url); return null; - } + } } /** Used by open() and IJ.open() to open text URLs. */ @@ -398,7 +402,7 @@ ImagePlus openZipUsingUrl(URL url) throws IOException { URLConnection uc = url.openConnection(); int fileSize = uc.getContentLength(); // compressed size fileSize *=2; // estimate uncompressed size - InputStream in = uc.getInputStream(); + InputStream in = uc.getInputStream(); ZipInputStream zin = new ZipInputStream(in); ByteArrayOutputStream out = new ByteArrayOutputStream(); byte[] buf = new byte[4096]; @@ -443,23 +447,23 @@ ImagePlus openPngUsingURL(String title, URL url) { } ImagePlus openJpegOrGif(String dir, String name) { - ImagePlus imp = null; + ImagePlus imp = null; Image img = Toolkit.getDefaultToolkit().createImage(dir+name); - if (img!=null) { - try { - imp = new ImagePlus(name, img); - } catch (IllegalStateException e) { + if (img!=null) { + try { + imp = new ImagePlus(name, img); + } catch (IllegalStateException e) { return null; // error loading image } - if (imp.getType()==ImagePlus.COLOR_RGB) - convertGrayJpegTo8Bits(imp); - FileInfo fi = new FileInfo(); - fi.fileFormat = fi.GIF_OR_JPG; - fi.fileName = name; - fi.directory = dir; - imp.setFileInfo(fi); - } - return imp; + if (imp.getType()==ImagePlus.COLOR_RGB) + convertGrayJpegTo8Bits(imp); + FileInfo fi = new FileInfo(); + fi.fileFormat = fi.GIF_OR_JPG; + fi.fileName = name; + fi.directory = dir; + imp.setFileInfo(fi); + } + return imp; } ImagePlus openUsingImageIO(String path) { @@ -478,7 +482,7 @@ ImagePlus openUsingImageIO(String path) { fi.fileName = f.getName(); fi.directory = f.getParent()+File.separator; imp.setFileInfo(fi); - return imp; + return imp; } /** If this image is grayscale, convert it to 8-bits. */ @@ -800,8 +804,8 @@ public int getFileType(String path) { return TIFF_AND_DICOM; // Big-endian TIFF ("MM") - if (name.endsWith(".lsm")) - return UNKNOWN; // The LSM Reader plugin opens these files + if (name.endsWith(".lsm")) + return UNKNOWN; // The LSM Reader plugin opens these files if (b0==73 && b1==73 && b2==42 && b3==0 && !(bioformats&&name.endsWith(".flex"))) return TIFF; @@ -824,9 +828,9 @@ public int getFileType(String path) { return DICOM; } - // ACR/NEMA with first tag = 00002,00xx or 00008,00xx - if ((b0==8||b0==2) && b1==0 && b3==0 && !name.endsWith(".spe") && !name.equals("fid")) - return DICOM; + // ACR/NEMA with first tag = 00002,00xx or 00008,00xx + if ((b0==8||b0==2) && b1==0 && b3==0 && !name.endsWith(".spe") && !name.equals("fid")) + return DICOM; // PGM ("P1", "P4", "P2", "P5", "P3" or "P6") if (b0==80&&(b1==49||b1==52||b1==50||b1==53||b1==51||b1==54)&&(b2==10||b2==13||b2==32||b2==9)) @@ -856,17 +860,21 @@ public int getFileType(String path) { if (b0==73 && b1==111) // "Iout" return ROI; - // Text file - boolean isText = true; - for (int i=0; i<10; i++) { - int c = buf[i]&255; - if ((c<32&&c!=9&&c!=10&&c!=13) || c>126) { - isText = false; - break; - } - } - if (isText) - return TEXT; + // ObjectJ project + if (name.endsWith(".ojj")) + return OJJ; + + // Text file + boolean isText = true; + for (int i=0; i<10; i++) { + int c = buf[i]&255; + if ((c<32&&c!=9&&c!=10&&c!=13) || c>126) { + isText = false; + break; + } + } + if (isText) + return TEXT; // BMP ("BM") if ((b0==66 && b1==77)||name.endsWith(".dib")) @@ -894,13 +902,13 @@ InputStream createInputStream(FileInfo fi) throws IOException, MalformedURLExcep else if (fi.url!=null && !fi.url.equals("")) return new URL(fi.url+fi.fileName).openStream(); else { - File f = new File(fi.directory + fi.fileName); - if (f==null || f.isDirectory()) - return null; - else { - InputStream is = new FileInputStream(f); - if (fi.compression>=FileInfo.LZW) - is = new RandomAccessStream(is); + File f = new File(fi.directory + fi.fileName); + if (f==null || f.isDirectory()) + return null; + else { + InputStream is = new FileInputStream(f); + if (fi.compression>=FileInfo.LZW) + is = new RandomAccessStream(is); return is; } } diff --git a/ij/io/SaveDialog.java b/ij/io/SaveDialog.java index a8a0558b9..d772f00e5 100644 --- a/ij/io/SaveDialog.java +++ b/ij/io/SaveDialog.java @@ -188,7 +188,7 @@ void save(String title, String defaultDir, String defaultName) { /** Returns the selected directory. */ public String getDirectory() { - OpenDialog.lastDir = dir; + OpenDialog.setLastDirectory(dir); return dir; } @@ -196,7 +196,7 @@ public String getDirectory() { public String getFileName() { if (Recorder.record) Recorder.recordPath(title, dir+name); - OpenDialog.lastName = name; + OpenDialog.setLastName(name); return name; } diff --git a/ij/io/TiffDecoder.java b/ij/io/TiffDecoder.java index b729cc3b1..ad849f482 100644 --- a/ij/io/TiffDecoder.java +++ b/ij/io/TiffDecoder.java @@ -443,7 +443,7 @@ else if (value==2 && fi.fileType==FileInfo.RGB) else if (value==1 && fi.samplesPerPixel==4) fi.fileType = FileInfo.ARGB; else if (value!=2 && !((fi.samplesPerPixel==1)||(fi.samplesPerPixel==3))) { - String msg = "Unsupported interleaved SamplesPerPixel: " + fi.samplesPerPixel; + String msg = "Unsupported SamplesPerPixel: " + fi.samplesPerPixel; error(msg); } break; diff --git a/ij/macro/Functions.java b/ij/macro/Functions.java index f7b4c5516..2a63b3c88 100644 --- a/ij/macro/Functions.java +++ b/ij/macro/Functions.java @@ -1303,6 +1303,11 @@ else if (key.equals("image.subtitle")) { Roi roi = imp.getRoi(); String name = roi!=null?roi.getName():null; return name!=null?name:""; + } else if (key.equals("font.name")) { + resetImage(); + ImageProcessor ip = getProcessor(); + setFont(ip); + return ip.getFont().getName(); } else { String value = ""; try {value = System.getProperty(key);} @@ -2097,7 +2102,8 @@ void open() { IJ.open(path); if (path!=null&&!path.equals("")) { int index = path.lastIndexOf('/'); - if (index==-1) path.lastIndexOf('\\'); + if (index==-1) + index = path.lastIndexOf('\\'); String name = index>=0&&index2?titles[2]:none; - gd.addChoice("Blue:", titles, title3); - String title4 = titles.length>3?titles[3]:none; - gd.addChoice("Gray:", titles, title4); + GenericDialog gd = new GenericDialog("Color Merge"); + gd.addChoice("Red:", titles, titles[0]); + gd.addChoice("Green:", titles, titles[1]); + String title3 = titles.length>2&&!IJ.macroRunning()?titles[2]:none; + gd.addChoice("Blue:", titles, title3); + String title4 = titles.length>3&&!IJ.macroRunning()?titles[3]:none; + gd.addChoice("Gray:", titles, title4); gd.addCheckbox("Create Composite", createComposite); - gd.addCheckbox("Keep Source Images", false); + gd.addCheckbox("Keep Source Images", false); gd.showDialog(); - if (gd.wasCanceled()) - return; - int[] index = new int[4]; - index[0] = gd.getNextChoiceIndex(); - index[1] = gd.getNextChoiceIndex(); - index[2] = gd.getNextChoiceIndex(); - index[3] = gd.getNextChoiceIndex(); - createComposite = gd.getNextBoolean(); - boolean keep = gd.getNextBoolean(); + if (gd.wasCanceled()) + return; + int[] index = new int[4]; + index[0] = gd.getNextChoiceIndex(); + index[1] = gd.getNextChoiceIndex(); + index[2] = gd.getNextChoiceIndex(); + index[3] = gd.getNextChoiceIndex(); + createComposite = gd.getNextBoolean(); + boolean keep = gd.getNextBoolean(); - ImagePlus[] image = new ImagePlus[4]; - int stackSize = 0; - int width = 0; - int height = 0; - int bitDepth = 0; - for (int i=0; i<4; i++) { - if (index[i]1) { + error("Source hyperstacks cannot have more than 1 channel."); + return; + } + if (img.getNSlices()!=slices || img.getNFrames()!=frames) { + error("Source hyperstacks must have the same dimensions."); + return; + } + mergeHyperstacks = true; + } // isHyperStack + if (img.getWidth()!=width || images[i].getHeight()!=height) { + error("The source images or stacks must have the same width and height."); + return; + } + if (createComposite) { + for (int j=0; j<4; j++) { + if (j!=i && images[j]!=null && img==images[j]) + createComposite = false; + } + } + if (createComposite && img.getBitDepth()!=bitDepth) { + error("The source images must have the same bit depth."); + return; + } + } - ImageStack red = image[0]!=null?image[0].getStack():null; - ImageStack green = image[1]!=null?image[1].getStack():null; - ImageStack blue = image[2]!=null?image[2].getStack():null; - ImageStack gray = image[3]!=null?image[3].getStack():null; + ImageStack[] stacks = new ImageStack[4]; + stacks[0] = images[0]!=null?images[0].getStack():null; + stacks[1] = images[1]!=null?images[1].getStack():null; + stacks[2] = images[2]!=null?images[2].getStack():null; + stacks[3] = images[3]!=null?images[3].getStack():null; String options = Macro.getOptions(); - if (options!=null && options.indexOf("gray=")==-1) - gray = null; // ensure compatibility with old macros - ImagePlus imp2; - if (gray!=null) - createComposite = true; - for (int i=0; i<4; i++) { - if (image[i]!=null && image[i].getBitDepth()==24) - createComposite = false; - } - if (createComposite) { - ImageStack[] stacks = new ImageStack[4]; - stacks[0]=red; stacks[1]=green; stacks[2]=blue; stacks[3]=gray; + if (options!=null && options.indexOf("gray=")==-1) + stacks[3] = null; // ensure compatibility with old macros + ImagePlus imp2; + if (stacks[3]!=null) + createComposite = true; + for (int i=0; i<4; i++) { + if (images[i]!=null && images[i].getBitDepth()==24) + createComposite = false; + } + if (mergeHyperstacks) { + imp2 = mergeHyperstacks(images, keep); + if (imp2==null) return; + } else if (createComposite) { imp2 = createComposite(width, height, stackSize, stacks, keep); if (imp2==null) return; } else { - ImageStack rgb = mergeStacks(width, height, stackSize, red, green, blue, keep); + ImageStack rgb = mergeStacks(width, height, stackSize, stacks[0], stacks[1], stacks[2], keep); imp2 = new ImagePlus("RGB", rgb); } - if (image[0]!=null) - imp2.setCalibration(image[0].getCalibration()); + if (images[0]!=null) + imp2.setCalibration(images[0].getCalibration()); if (!keep) { for (int i=0; i<4; i++) { - if (image[i]!=null) { - image[i].changes = false; - image[i].close(); + if (images[i]!=null) { + images[i].changes = false; + images[i].close(); } } } imp2.show(); - } - + } + + public ImagePlus mergeHyperstacks(ImagePlus[] images, boolean keep) { + int n = images.length; + int channels = 0; + for (int i=0; iSize commands\ndo not work with line selections."); + return; + } + Rectangle r = ip.getRoi(); + origWidth = r.width;; + origHeight = r.height; + sizeToHeight=false; + boolean restoreRoi = crop && roi!=null && roi.getType()!=Roi.RECTANGLE; + if (roi!=null) { + Rectangle b = roi.getBounds(); + int w = ip.getWidth(); + int h = ip.getHeight(); + if (b.x<0 || b.y<0 || b.x+b.width>w || b.y+b.height>h) { + ShapeRoi shape1 = new ShapeRoi(roi); + ShapeRoi shape2 = new ShapeRoi(new Roi(0, 0, w, h)); + roi = shape2.and(shape1); + if (restoreRoi) imp.setRoi(roi); + } + } + int stackSize= imp.getStackSize(); + int z1 = imp.getStackSize(); + int t1 = 0; + int z2=0, t2=0; + if (crop) { + Rectangle bounds = roi.getBounds(); + newWidth = bounds.width; + newHeight = bounds.height; + interpolationMethod = ImageProcessor.NONE; + } else { + if (newWidth==0 || newHeight==0) { + newWidth = (int)origWidth/2; + newHeight = (int)origHeight/2; + } + if (constrain) newHeight = (int)(newWidth*(origHeight/origWidth)); + if (stackSize>1) { + newWidth = (int)origWidth; + newHeight = (int)origHeight; + } + GenericDialog gd = new GenericDialog("Resize", IJ.getInstance()); + gd.addNumericField("Width (pixels):", newWidth, 0); + gd.addNumericField("Height (pixels):", newHeight, 0); + if (imp.isHyperStack()) { + z1 = imp.getNSlices(); + t1 = imp.getNFrames(); + } + if (z1>1 && z1==stackSize) + gd.addNumericField("Depth (images):", z1, 0); + else if (z1>1 && z11) + gd.addNumericField("Time (frames):", t1, 0); + gd.addCheckbox("Constrain aspect ratio", constrain); + gd.addChoice("Interpolation:", methods, methods[interpolationMethod]); + gd.addMessage("NOTE: Undo is not available"); + fields = gd.getNumericFields(); + for (int i=0; i<2; i++) + ((TextField)fields.elementAt(i)).addTextListener(this); + checkboxes = gd.getCheckboxes(); + ((Checkbox)checkboxes.elementAt(0)).addItemListener(this); + gd.showDialog(); + if (gd.wasCanceled()) + return; + newWidth = (int)gd.getNextNumber(); + newHeight = (int)gd.getNextNumber(); + if (z1>1) + z2 = (int)gd.getNextNumber(); + if (t1>1) + t2 = (int)gd.getNextNumber(); + if (gd.invalidNumber()) { + IJ.error("Width or height are invalid."); + return; + } + constrain = gd.getNextBoolean(); + interpolationMethod = gd.getNextChoiceIndex(); + if (constrain && newWidth==0) + sizeToHeight = true; + if (newWidth<=0.0 && !constrain) newWidth = 50; + if (newHeight<=0.0) newHeight = 50; + } + + if (!crop && constrain) { + if (sizeToHeight) + newWidth = (int)Math.round(newHeight*(origWidth/origHeight)); + else + newHeight = (int)Math.round(newWidth*(origHeight/origWidth)); + } + if (ip.getWidth()==1 || ip.getHeight()==1) + ip.setInterpolationMethod(ImageProcessor.NONE); + else + ip.setInterpolationMethod(interpolationMethod); + + + if (roi!=null || newWidth!=origWidth || newHeight!=origHeight) { + try { + StackProcessor sp = new StackProcessor(imp.getStack(), ip); + ImageStack s2 = sp.resize(newWidth, newHeight); + int newSize = s2.getSize(); + if (s2.getWidth()>0 && newSize>0) { + if (restoreRoi) + imp.killRoi(); + //imp.hide(); + Calibration cal = imp.getCalibration(); + if (cal.scaled()) { + cal.pixelWidth *= origWidth/newWidth; + cal.pixelHeight *= origHeight/newHeight; + imp.setCalibration(cal); + } + imp.setStack(null, s2); + if (restoreRoi && roi!=null) { + roi.setLocation(0, 0); + imp.setRoi(roi); + imp.draw(); + } + } + if (stackSize>1 && newSize0 && z2!=z1) + imp2 = zScale(imp, z2, interpolationMethod+IN_PLACE); + if (t2>0 && t2!=t1) + imp2 = zScale(imp2!=null?imp2:imp, t2, interpolationMethod+IN_PLACE+SCALE_T); + if (imp2!=null && imp2!=imp) { + imp2.show(); + imp.changes = false; + imp.close(); + } + } + + public ImagePlus zScale(ImagePlus imp, int newDepth, int interpolationMethod) { + ImagePlus imp2 = null; + if (imp.isHyperStack()) + imp2 = zScaleHyperstack(imp, newDepth, interpolationMethod); + else { + boolean inPlace = (interpolationMethod&IN_PLACE)!=0; + interpolationMethod = interpolationMethod&15; + int stackSize = imp.getStackSize(); + int bitDepth = imp.getBitDepth(); + if (newDepth<=stackSize/2 && interpolationMethod==ImageProcessor.NONE) + imp2 = shrinkZ(imp, newDepth, inPlace); + else + 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); + } + if (imp2==null) return null; + if (imp2!=imp && imp.isComposite()) { + imp2 = new CompositeImage(imp2, ((CompositeImage)imp).getMode()); + ((CompositeImage)imp2).copyLuts(imp); + } + imp2.setCalibration(imp.getCalibration()); + Calibration cal = imp2.getCalibration(); + if (cal.scaled()) cal.pixelDepth *= (double)imp.getNSlices()/imp2.getNSlices(); + Object info = imp.getProperty("Info"); + if (info!=null) imp2.setProperty("Info", info); + if (imp.isHyperStack()) + imp2.setOpenAsHyperStack(imp.isHyperStack()); + return imp2; + } + + private ImagePlus zScaleHyperstack(ImagePlus imp, int depth2, int interpolationMethod) { + boolean inPlace = (interpolationMethod&IN_PLACE)!=0; + boolean scaleT = (interpolationMethod&SCALE_T)!=0; + interpolationMethod = interpolationMethod&15; + int channels = imp.getNChannels(); + int slices = imp.getNSlices(); + int frames = imp.getNFrames(); + int slices2 = slices; + int frames2 = frames; + int bitDepth = imp.getBitDepth(); + if (slices==1 && frames>1) + scaleT = true; + if (scaleT) + frames2 = depth2; + else + slices2 = depth2; + double scale = (double)(depth2-1)/slices; + if (scaleT) scale = (double)(depth2-1)/frames; + if (scale<=0.5 && interpolationMethod==ImageProcessor.NONE) + return shrinkHyperstack(imp, depth2, inPlace, scaleT); + ImageStack stack1 = imp.getStack(); + int width = stack1.getWidth(); + int height = stack1.getHeight(); + ImagePlus imp2 = IJ.createImage(imp.getTitle(), bitDepth+"-bit", width, height, channels*slices2*frames2); + if (imp2==null) return null; + imp2.setDimensions(channels, slices2, frames2); + ImageStack stack2 = imp2.getStack(); + ImageProcessor ip = imp.getProcessor(); + int count = 0; + if (scaleT) { + IJ.showStatus("T Scaling..."); + ImageProcessor xtPlane1 = ip.createProcessor(width, frames); + xtPlane1.setInterpolationMethod(interpolationMethod); + ImageProcessor xtPlane2; + Object xtpixels1 = xtPlane1.getPixels(); + int last = slices*channels*height-1; + for (int z=1; z<=slices; z++) { + for (int c=1; c<=channels; c++) { + for (int y=0; y0 && newDepth!=imp.getStackSize()) { + newWindow = true; + processStack = true; + } if (ip.getWidth()>1 && ip.getHeight()>1) ip.setInterpolationMethod(interpolationMethod); else @@ -56,47 +62,55 @@ public void run(String arg) { } void createNewStack(ImagePlus imp, ImageProcessor ip) { - Rectangle r = ip.getRoi(); - boolean crop = r.width!=imp.getWidth() || r.height!=imp.getHeight(); int nSlices = imp.getStackSize(); - ImageStack stack1 = imp.getStack(); - ImageStack stack2 = new ImageStack(newWidth, newHeight); - ImageProcessor ip1, ip2; - int method = interpolationMethod; - if (imp.getWidth()==1 || imp.getHeight()==1) - method = ImageProcessor.NONE; - for (int i=1; i<=nSlices; i++) { - IJ.showStatus("Scale: " + i + "/" + nSlices); - ip1 = stack1.getProcessor(i); - String label = stack1.getSliceLabel(i); - if (crop) { - ip1.setRoi(r); - ip1 = ip1.crop(); - } - ip1.setInterpolationMethod(method); - ip2 = ip1.resize(newWidth, newHeight); - if (ip2!=null) - stack2.addSlice(label, ip2); - IJ.showProgress(i, nSlices); - } + int w=imp.getWidth(), h=imp.getHeight(); ImagePlus imp2 = imp.createImagePlus(); - imp2.setStack(title, stack2); - Calibration cal = imp2.getCalibration(); - if (cal.scaled()) { - cal.pixelWidth *= 1.0/xscale; - cal.pixelHeight *= 1.0/yscale; - } + if (newWidth!=w || newHeight!=h) { + Rectangle r = ip.getRoi(); + boolean crop = r.width!=imp.getWidth() || r.height!=imp.getHeight(); + ImageStack stack1 = imp.getStack(); + ImageStack stack2 = new ImageStack(newWidth, newHeight); + ImageProcessor ip1, ip2; + int method = interpolationMethod; + if (w==1 || h==1) + method = ImageProcessor.NONE; + for (int i=1; i<=nSlices; i++) { + IJ.showStatus("Scale: " + i + "/" + nSlices); + ip1 = stack1.getProcessor(i); + String label = stack1.getSliceLabel(i); + if (crop) { + ip1.setRoi(r); + ip1 = ip1.crop(); + } + ip1.setInterpolationMethod(method); + ip2 = ip1.resize(newWidth, newHeight); + if (ip2!=null) + stack2.addSlice(label, ip2); + IJ.showProgress(i, nSlices); + } + imp2.setStack(title, stack2); + Calibration cal = imp2.getCalibration(); + if (cal.scaled()) { + cal.pixelWidth *= 1.0/xscale; + cal.pixelHeight *= 1.0/yscale; + } + IJ.showProgress(1.0); + } else + imp2.setStack(title, imp.getStack()); int[] dim = imp.getDimensions(); imp2.setDimensions(dim[2], dim[3], dim[4]); - IJ.showProgress(1.0); if (imp.isComposite()) { - imp2 = new CompositeImage(imp2, 0); + imp2 = new CompositeImage(imp2, ((CompositeImage)imp).getMode()); ((CompositeImage)imp2).copyLuts(imp); } if (imp.isHyperStack()) imp2.setOpenAsHyperStack(true); - imp2.show(); - imp2.changes = true; + if (newDepth>0 && newDepth!=oldDepth) + imp2 = (new Resizer()).zScale(imp2, newDepth, interpolationMethod); + if (imp2!=null) { + imp2.show(); + imp2.changes = true; + } } void scale(ImageProcessor ip) { @@ -141,42 +155,74 @@ else if (macroOptions.indexOf(" interpolation=")==-1) Macro.setOptions(macroOptions); } int bitDepth = imp.getBitDepth(); - boolean isStack = imp.getStackSize()>1; - r = ip.getRoi(); - int width = newWidth; + int stackSize = imp.getStackSize(); + boolean isStack = stackSize>1; + oldDepth = stackSize; + if (isStack) { + xstr = "1.0"; + ystr = "1.0"; + zstr = "1.0"; + } + r = ip.getRoi(); + int width = newWidth; if (width==0) width = r.width; - int height = (int)((double)width*r.height/r.width); - xscale = Tools.parseDouble(xstr, 0.0); - yscale = Tools.parseDouble(ystr, 0.0); - if (xscale!=0.0 && yscale!=0.0) { - width = (int)(r.width*xscale); - height = (int)(r.height*yscale); - } else { - xstr = "-"; - ystr = "-"; - } + int height = (int)((double)width*r.height/r.width); + xscale = Tools.parseDouble(xstr, 0.0); + yscale = Tools.parseDouble(ystr, 0.0); + zscale = 1.0; + if (xscale!=0.0 && yscale!=0.0) { + width = (int)(r.width*xscale); + height = (int)(r.height*yscale); + } else { + xstr = "-"; + ystr = "-"; + } GenericDialog gd = new GenericDialog("Scale"); - gd.addStringField("X Scale (0.05-25):", xstr); - gd.addStringField("Y Scale (0.05-25):", ystr); + gd.addStringField("X Scale:", xstr); + gd.addStringField("Y Scale:", ystr); + if (isStack) + gd.addStringField("Z Scale:", zstr); gd.setInsets(5, 0, 5); gd.addStringField("Width (pixels):", ""+width); gd.addStringField("Height (pixels):", ""+height); + if (isStack) { + String label = "Depth (images):"; + if (imp.isHyperStack()) { + int slices = imp.getNSlices(); + int frames = imp.getNFrames(); + if (slices==1&&frames>1) { + label = "Depth (frames):"; + oldDepth = frames; + } else { + label = "Depth (slices):"; + oldDepth = slices; + } + } + gd.addStringField(label, ""+oldDepth); + } fields = gd.getStringFields(); - for (int i=0; i<3; i++) { + for (int i=0; i8) ndigits = 8; @@ -103,9 +106,10 @@ else if (format.equals("text image")) Calibration cal = imp.getCalibration(); int nSlices = stack.getSize(); String path,label=null; + imp.lock(); for (int i=1; i<=nSlices; i++) { IJ.showStatus("writing: "+i+"/"+nSlices); - IJ.showProgress((double)i/nSlices); + IJ.showProgress(i, nSlices); ImageProcessor ip = stack.getProcessor(i); if (luts!=null && nChannels>1 && hyperstack) { ip.setColorModel(luts[lutIndex++]); @@ -124,6 +128,7 @@ else if (format.equals("text image")) if (useLabels) { label = stack.getShortSliceLabel(i); if (label!=null && label.equals("")) label = null; + if (label!=null) label = label.replaceAll("/","-"); } if (label==null) path = directory+name+digits+extension; @@ -131,8 +136,8 @@ else if (format.equals("text image")) path = directory+label+extension; IJ.saveAs(imp2, format, path); } + imp.unlock(); IJ.showStatus(""); - IJ.showProgress(1.0); } String getDigits(int n) { diff --git a/ij/plugin/filter/Analyzer.java b/ij/plugin/filter/Analyzer.java index 9b76a2deb..99057afaf 100644 --- a/ij/plugin/filter/Analyzer.java +++ b/ij/plugin/filter/Analyzer.java @@ -298,7 +298,7 @@ void measureAngle(Roi roi) { } ImageProcessor ip = imp.getProcessor(); ip.setRoi(roi.getPolygon()); - ImageStatistics stats = ImageStatistics.getStatistics(ip, measurements, imp.getCalibration()); + ImageStatistics stats = new ImageStatistics(); saveResults(stats, roi); //IJ.write(rt.getCounter()+"\t"+n(((PolygonRoi)roi).getAngle())); } diff --git a/ij/plugin/filter/FractalBoxCounter.java b/ij/plugin/filter/FractalBoxCounter.java index 5cbbf1437..82795caee 100644 --- a/ij/plugin/filter/FractalBoxCounter.java +++ b/ij/plugin/filter/FractalBoxCounter.java @@ -30,10 +30,8 @@ needed to cover a one pixel wide, binary (black on white) border. */ public class FractalBoxCounter implements PlugInFilter { - static String sizes = "2,3,4,6,8,12,16,32,64"; static boolean blackBackground; - int[] boxSizes; float[] boxCountSums; int maxBoxSize; @@ -41,7 +39,6 @@ public class FractalBoxCounter implements PlugInFilter { Rectangle roi; int foreground; ImagePlus imp; - int boxSum; public int setup(String arg, ImagePlus imp) { this.imp = imp; @@ -96,7 +93,7 @@ public int[] s2ints(String s) { int[] ints = new int[nInts]; for(int i=0; iSize commands\ndo not work with line selections."); - return; - } - Rectangle r = ip.getRoi(); - origWidth = r.width;; - origHeight = r.height; - sizeToHeight=false; - boolean restoreRoi = crop && roi!=null && roi.getType()!=Roi.RECTANGLE; - if (roi!=null) { - Rectangle b = roi.getBounds(); - int w = ip.getWidth(); - int h = ip.getHeight(); - if (b.x<0 || b.y<0 || b.x+b.width>w || b.y+b.height>h) { - ShapeRoi shape1 = new ShapeRoi(roi); - ShapeRoi shape2 = new ShapeRoi(new Roi(0, 0, w, h)); - roi = shape2.and(shape1); - if (restoreRoi) imp.setRoi(roi); - } - } - if (crop) { - Rectangle bounds = roi.getBounds(); - newWidth = bounds.width; - newHeight = bounds.height; - interpolationMethod = ImageProcessor.NONE; - } else { - if (newWidth==0 || newHeight==0) { - newWidth = (int)origWidth/2; - newHeight = (int)origHeight/2; - } - if (constrain) newHeight = (int)(newWidth*(origHeight/origWidth)); - GenericDialog gd = new GenericDialog("Resize", IJ.getInstance()); - gd.addNumericField("Width (pixels):", newWidth, 0); - gd.addNumericField("Height (pixels):", newHeight, 0); - gd.addCheckbox("Constrain Aspect Ratio", constrain); - gd.addChoice("Interpolation:", methods, methods[interpolationMethod]); - gd.addMessage("NOTE: Undo is not available"); - fields = gd.getNumericFields(); - for (int i=0; i0 && newSize>0) { - if (restoreRoi) - imp.killRoi(); - //imp.hide(); - Calibration cal = imp.getCalibration(); - if (cal.scaled()) { - cal.pixelWidth *= origWidth/newWidth; - cal.pixelHeight *= origHeight/newHeight; - imp.setCalibration(cal); - } - imp.setStack(null, s2); - if (restoreRoi && roi!=null) { - roi.setLocation(0, 0); - imp.setRoi(roi); - imp.draw(); - } - } - if (nSlices>1 && newSize80) fontSize = 80; } + if (IJ.macroRunning()) { + decimalPlaces = 0; + interval=1; + text = ""; + } GenericDialog gd = new GenericDialog("StackLabeler"); gd.setInsets(2, 5, 0); gd.addStringField("Starting value:", IJ.d2s(start,decimalPlaces)); @@ -52,7 +57,7 @@ public int showDialog(ImagePlus imp, String command, PlugInFilterRunner pfr) { gd.addNumericField("Font size:", fontSize, 0); gd.addStringField("Text:", text, 10); gd.setInsets(10,20,0); - gd.addCheckbox("Text first", textBeforeNumber); + gd.addCheckbox("Zero pad", zeroPad); gd.addPreviewCheckbox(pfr); gd.addHelp(IJ.URL+"/docs/menus/image.html#label"); gd.addDialogListener(this); @@ -71,7 +76,7 @@ public boolean dialogItemChanged(GenericDialog gd, AWTEvent e) { y = (int)gd.getNextNumber(); fontSize = (int)gd.getNextNumber(); text = gd.getNextString(); - textBeforeNumber = gd.getNextBoolean(); + zeroPad = gd.getNextBoolean(); int index = str.indexOf("."); if (index!=-1) decimalPlaces = str.length()-index-1; @@ -116,9 +121,9 @@ public void run(ImageProcessor ip) { String getString(double time) { if (interval==0.0) return text; - else if (textBeforeNumber && decimalPlaces==0) + else if (zeroPad && decimalPlaces==0) return text+zeroFill((int)time); - else if (textBeforeNumber) + else if (zeroPad) return text+IJ.d2s(time, decimalPlaces); else return IJ.d2s(time, decimalPlaces)+" "+text; diff --git a/ij/plugin/frame/ContrastAdjuster.java b/ij/plugin/frame/ContrastAdjuster.java index b3ad22d40..05be16a3d 100644 --- a/ij/plugin/frame/ContrastAdjuster.java +++ b/ij/plugin/frame/ContrastAdjuster.java @@ -1,5 +1,4 @@ package ij.plugin.frame; -//import ij.plugin.frame.*; import java.awt.*; import java.awt.event.*; import java.awt.image.*; @@ -55,8 +54,6 @@ public class ContrastAdjuster extends PlugInFrame implements Runnable, Font sanFont = new Font("SansSerif", Font.PLAIN, 12); int channels = 7; // RGB Choice choice; - boolean updatingRGBStack; - public ContrastAdjuster() { super("B&C"); @@ -584,7 +581,7 @@ void apply(ImagePlus imp, ImageProcessor ip) { imp.unlock(); if (!imp.lock()) return; - if (imp.getType()==ImagePlus.COLOR_RGB) { + if (RGBImage) { if (imp.getStackSize()>1) applyRGBStack(imp); else { @@ -668,19 +665,24 @@ void applyRGBStack(ImagePlus imp) { "NOTE: There is no Undo for this operation.")) return; ImageProcessor mask = imp.getMask(); - updatingRGBStack = true; + Rectangle roi = imp.getRoi()!=null?imp.getRoi().getBounds():null; + ImageStack stack = imp.getStack(); for (int i=1; i<=n; i++) { + IJ.showProgress(i, n); + IJ.showStatus(i+"/"+n); if (i!=current) { - imp.setSlice(i); - ImageProcessor ip = imp.getProcessor(); + ImageProcessor ip = stack.getProcessor(i); + ip.setRoi(roi); if (mask!=null) ip.snapshot(); - setMinAndMax(imp, min, max); - ip.reset(mask); - IJ.showProgress((double)i/n); + if (channels!=7) + ((ColorProcessor)ip).setMinAndMax(min, max, channels); + else + ip.setMinAndMax(min, max); + if (mask!=null) ip.reset(mask); } } + imp.setStack(null, stack); imp.setSlice(current); - updatingRGBStack = false; imp.changes = true; if (Recorder.record) Recorder.record("run", "Apply LUT", "stack"); @@ -968,10 +970,8 @@ public void updateAndDraw() { public static void update() { if (instance!=null) { ContrastAdjuster ca = ((ContrastAdjuster)instance); - if (!ca.updatingRGBStack) { - ca.previousImageID = 0; - ca.setup(); - } + ca.previousImageID = 0; + ca.setup(); } } diff --git a/ij/process/ImageProcessor.java b/ij/process/ImageProcessor.java index 8fa7880ab..6afafc47d 100644 --- a/ij/process/ImageProcessor.java +++ b/ij/process/ImageProcessor.java @@ -1213,6 +1213,12 @@ public int getStringWidth(String s) { return w; } + /** Returns the current font. */ + public Font getFont() { + setupFontMetrics(); + return font; + } + /** Returns the current FontMetrics. */ public FontMetrics getFontMetrics() { setupFontMetrics(); diff --git a/ij/process/ShortProcessor.java b/ij/process/ShortProcessor.java index d50892d31..a8f795515 100644 --- a/ij/process/ShortProcessor.java +++ b/ij/process/ShortProcessor.java @@ -1,4 +1,4 @@ -package ij.process; + package ij.process; import java.util.*; import java.awt.*; diff --git a/release-notes.html b/release-notes.html index 7aa207a8a..7a32c319a 100644 --- a/release-notes.html +++ b/release-notes.html @@ -5,19 +5,26 @@ -
  • 1.43e, 6 August 2009 +
  • 1.43f, 24 August 2009
      -
    • Added a Process>Batch> submenu containing Measure, -Convert and Process commands. -
    • Thanks to Norbert Vischer, it is now easier to outline circular objects -using the elliptical selection tool with the shift key down. -
    • Added an "Export" button to Plugins>Utilities>Command Finder. -
    • Added the selectWindow("ImageJ") macro function. -
    • Fixed a bug that caused image zooming to fail on secondary monitors. -
    • Fixed a bug that cuased the particle analyzer to sometimes not work as expected -when "Black Background" was enabled in the Process>Binary>Options dialog box. -
    • Fixed a bug that caused the Plugins>Utilities>Memory Monitor -tool to not work correctly when the line width was greater than one. +
    • The Image>Scale and Image>Adjust>Size commands +can now scale stacks and hyperstacks in the Z dimension. +
    • The Image>Color>Merge Channels command +now works with hyperstacks. +
    • Added the File>New>Hyperstack command, which +is an alias for Image>Hyperstacks>New Hyperstack. +
    • Analyze>Tools>Fractal Box Counter writes results that +can be read by macros. +
    • Added the List.setCommands, setFont("user"), getInfo("font.name"), +getValue("font.size") and getValue("font.height") macro functions. +
    • Added the NonBlockingGenericDialog class (used by Process>Batch>Process), +thanks to Johannes Schindelin. +
    • Fixed a bug that sometimes caused the Image>Adjust>Brightness/Contrast +"Apply" function to fail with RGB stacks. +
    • Fixed a bug that sometimes caused Image>Color>Split Channels +to display a "save changes?" dialog box. +
    • Fixed a bug that caused File>Save As>Image Sequence to throw an +exception if the window was closed before all the images in the stack were saved.
    Home