package ij.macro; import ij.*; import ij.process.*; import ij.gui.*; import ij.measure.*; import ij.plugin.*; import ij.plugin.filter.*; import ij.plugin.frame.*; import ij.text.*; import ij.io.*; import ij.util.*; import java.awt.*; import java.awt.image.*; import java.util.*; import java.io.*; import java.awt.event.KeyEvent; import java.lang.reflect.*; import java.net.URL; import java.awt.datatransfer.*; import java.awt.geom.*;; /** This class implements the built-in macro functions. */ public class Functions implements MacroConstants, Measurements { Interpreter interp; Program pgm; boolean updateNeeded; boolean autoUpdate = true; ImageProcessor defaultIP; int imageType; boolean colorSet, fontSet; Color defaultColor; double defaultValue = Double.NaN; Plot plot; static int plotID; int justification = ImageProcessor.LEFT_JUSTIFY; Font font; GenericDialog gd; PrintWriter writer; boolean altKeyDown, shiftKeyDown; boolean antialiasedText; StringBuffer buffer; RoiManager roiManager; Properties props; CurveFitter fitter; boolean showFitDialog; boolean logFitResults; boolean resultsPending; Overlay offscreenOverlay; Overlay overlayClipboard; GeneralPath overlayPath; boolean saveSettingsCalled; boolean usePointerCursor, hideProcessStackDialog; float divideByZeroValue; int jpegQuality; int saveLineWidth; boolean doScaling; boolean weightedColor; double[] weights; boolean interpolateScaledImages, open100Percent, blackCanvas; boolean useJFileChooser,debugMode; Color foregroundColor, backgroundColor, roiColor; boolean pointAutoMeasure, requireControlKey, useInvertingLut; boolean disablePopup; int measurements; int decimalPlaces; boolean blackBackground; static WaitForUserDialog waitForUserDialog; int pasteMode; int lineWidth = 1; boolean expandableArrays; Functions(Interpreter interp, Program pgm) { this.interp = interp; this.pgm = pgm; } void doFunction(int type) { switch (type) { case RUN: doRun(); break; case SELECT: IJ.selectWindow(getStringArg()); resetImage(); break; case WAIT: IJ.wait((int)getArg()); break; case BEEP: interp.getParens(); IJ.beep(); break; case RESET_MIN_MAX: interp.getParens(); IJ.resetMinAndMax(); resetImage(); break; case RESET_THRESHOLD: interp.getParens(); IJ.resetThreshold(); resetImage(); break; case PRINT: case WRITE: print(); break; case DO_WAND: doWand(); break; case SET_MIN_MAX: setMinAndMax(); break; case SET_THRESHOLD: setThreshold(); break; case SET_TOOL: setTool(); break; case SET_FOREGROUND: setForegroundColor(); break; case SET_BACKGROUND: setBackgroundColor(); break; case SET_COLOR: setColor(); break; case MAKE_LINE: makeLine(); break; case MAKE_OVAL: makeOval(); break; case MAKE_RECTANGLE: makeRectangle(); break; case DUMP: interp.dump(); break; case LINE_TO: lineTo(); break; case MOVE_TO: moveTo(); break; case DRAW_LINE: drawLine(); break; case REQUIRES: requires(); break; case AUTO_UPDATE: autoUpdate = getBooleanArg(); break; case UPDATE_DISPLAY: interp.getParens(); updateDisplay(); break; case DRAW_STRING: drawString(); break; case SET_PASTE_MODE: IJ.setPasteMode(getStringArg()); break; case DO_COMMAND: doCommand(); break; case SHOW_STATUS: IJ.showStatus(getStringArg()); interp.statusUpdated=true; break; case SHOW_PROGRESS: showProgress(); break; case SHOW_MESSAGE: showMessage(false); break; case SHOW_MESSAGE_WITH_CANCEL: showMessage(true); break; case SET_PIXEL: case PUT_PIXEL: setPixel(); break; case SNAPSHOT: case RESET: case FILL: doIPMethod(type); break; case SET_LINE_WIDTH: setLineWidth((int)getArg()); break; case CHANGE_VALUES: changeValues(); break; case SELECT_IMAGE: selectImage(); break; case EXIT: exit(); break; case SET_LOCATION: setLocation(); break; case GET_CURSOR_LOC: getCursorLoc(); break; case GET_LINE: getLine(); break; case GET_VOXEL_SIZE: getVoxelSize(); break; case GET_HISTOGRAM: getHistogram(); break; case GET_BOUNDING_RECT: case GET_BOUNDS: getBounds(); break; case GET_LUT: getLut(); break; case SET_LUT: setLut(); break; case GET_COORDINATES: getCoordinates(); break; case MAKE_SELECTION: makeSelection(); break; case SET_RESULT: setResult(); break; case UPDATE_RESULTS: updateResults(); break; case SET_BATCH_MODE: setBatchMode(); break; case PLOT: doPlot(); break; case SET_JUSTIFICATION: setJustification(); break; case SET_Z_COORDINATE: setZCoordinate(); break; case GET_THRESHOLD: getThreshold(); break; case GET_PIXEL_SIZE: getPixelSize(); break; case SETUP_UNDO: interp.getParens(); Undo.setup(Undo.TRANSFORM, getImage()); break; case SAVE_SETTINGS: saveSettings(); break; case RESTORE_SETTINGS: restoreSettings(); break; case SET_KEY_DOWN: setKeyDown(); break; case OPEN: open(); break; case SET_FONT: setFont(); break; case GET_MIN_AND_MAX: getMinAndMax(); break; case CLOSE: close(); break; case SET_SLICE: setSlice(); break; case NEW_IMAGE: newImage(); break; case SAVE: IJ.save(getStringArg()); break; case SAVE_AS: saveAs(); break; case SET_AUTO_THRESHOLD: setAutoThreshold(); break; case RENAME: getImage().setTitle(getStringArg()); break; case GET_STATISTICS: getStatistics(true); break; case GET_RAW_STATISTICS: getStatistics(false); break; case FLOOD_FILL: floodFill(); break; case RESTORE_PREVIOUS_TOOL: restorePreviousTool(); break; case SET_VOXEL_SIZE: setVoxelSize(); break; case GET_LOCATION_AND_SIZE: getLocationAndSize(); break; case GET_DATE_AND_TIME: getDateAndTime(); break; case SET_METADATA: setMetadata(); break; case CALCULATOR: imageCalculator(); break; case SET_RGB_WEIGHTS: setRGBWeights(); break; case MAKE_POLYGON: makePolygon(); break; case SET_SELECTION_NAME: setSelectionName(); break; case DRAW_RECT: case FILL_RECT: case DRAW_OVAL: case FILL_OVAL: drawOrFill(type); break; case SET_OPTION: setOption(); break; case SHOW_TEXT: showText(); break; case SET_SELECTION_LOC: setSelectionLocation(); break; case GET_DIMENSIONS: getDimensions(); break; case WAIT_FOR_USER: waitForUser(); break; case MAKE_POINT: makePoint(); break; case MAKE_TEXT: makeText(); break; case MAKE_ELLIPSE: makeEllipse(); break; case GET_DISPLAYED_AREA: getDisplayedArea(); break; case TO_SCALED: toScaled(); break; case TO_UNSCALED: toUnscaled(); break; } } final double getFunctionValue(int type) { double value = 0.0; switch (type) { case GET_PIXEL: value = getPixel(); break; case ABS: case COS: case EXP: case FLOOR: case LOG: case ROUND: case SIN: case SQRT: case TAN: case ATAN: case ASIN: case ACOS: value = math(type); break; case MAX_OF: case MIN_OF: case POW: case ATAN2: value=math2(type); break; case GET_TIME: interp.getParens(); value=System.currentTimeMillis(); break; case GET_WIDTH: interp.getParens(); value=getImage().getWidth(); break; case GET_HEIGHT: interp.getParens(); value=getImage().getHeight(); break; case RANDOM: value=random(); break; case GET_COUNT: case NRESULTS: value=getResultsCount(); break; case GET_RESULT: value=getResult(); break; case GET_NUMBER: value=getNumber(); break; case NIMAGES: value=getImageCount(); break; case NSLICES: value=getStackSize(); break; case LENGTH_OF: value=lengthOf(); break; case GET_ID: interp.getParens(); value=getImage().getID(); break; case BIT_DEPTH: interp.getParens(); value = getImage().getBitDepth(); break; case SELECTION_TYPE: value=getSelectionType(); break; case IS_OPEN: value=isOpen(); break; case IS_ACTIVE: value=isActive(); break; case INDEX_OF: value=indexOf(); break; case LAST_INDEX_OF: value=getFirstString().lastIndexOf(getLastString()); break; case CHAR_CODE_AT: value=charCodeAt(); break; case GET_BOOLEAN: value=getBoolean(); break; case STARTS_WITH: case ENDS_WITH: value = startsWithEndsWith(type); break; case IS_NAN: value = Double.isNaN(getArg())?1:0; break; case GET_ZOOM: value = getZoom(); break; case PARSE_FLOAT: value = parseDouble(getStringArg()); break; case PARSE_INT: value = parseInt(); break; case IS_KEY_DOWN: value=isKeyDown(); break; case GET_SLICE_NUMBER: interp.getParens(); value=getImage().getCurrentSlice(); break; case SCREEN_WIDTH: case SCREEN_HEIGHT: value = getScreenDimension(type); break; case CALIBRATE: value = getImage().getCalibration().getCValue(getArg()); break; case ROI_MANAGER: value = roiManager(); break; case TOOL_ID: interp.getParens(); value = Toolbar.getToolId(); break; case IS: value = is(); break; case GET_VALUE: value = getValue(); break; case STACK: value = doStack(); break; case MATCHES: value = matches(); break; case GET_STRING_WIDTH: value = getStringWidth(); break; case FIT: value = fit(); break; case OVERLAY: value = overlay(); break; case SELECTION_CONTAINS: value = selectionContains(); break; default: interp.error("Numeric function expected"); } return value; } String getStringFunction(int type) { String str; switch (type) { case D2S: str = d2s(); break; case TO_HEX: str = toString(16); break; case TO_BINARY: str = toString(2); break; case GET_TITLE: interp.getParens(); str=getImage().getTitle(); break; case GET_STRING: str = getStringDialog(); break; case SUBSTRING: str = substring(); break; case FROM_CHAR_CODE: str = fromCharCode(); break; case GET_INFO: str = getInfo(); break; case GET_IMAGE_INFO: interp.getParens(); str = getImageInfo(); break; case GET_DIRECTORY: str = getDirectory(); break; case GET_ARGUMENT: interp.getParens(); str=interp.argument!=null?interp.argument:""; break; case TO_LOWER_CASE: str = getStringArg().toLowerCase(Locale.US); break; case TO_UPPER_CASE: str = getStringArg().toUpperCase(Locale.US); break; case RUN_MACRO: str = runMacro(false); break; case EVAL: str = runMacro(true); break; case TO_STRING: str = doToString(); break; case REPLACE: str = replace(); break; case DIALOG: str = doDialog(); break; case GET_METADATA: str = getMetadata(); break; case FILE: str = doFile(); break; case SELECTION_NAME: str = selectionName(); break; case GET_VERSION: interp.getParens(); str = IJ.getVersion(); break; case GET_RESULT_LABEL: str = getResultLabel(); break; case CALL: str = call(); break; case STRING: str = doString(); break; case EXT: str = doExt(); break; case EXEC: str = exec(); break; case LIST: str = doList(); break; case DEBUG: str = debug(); break; case IJ_CALL: str = ijCall(); break; default: str=""; interp.error("String function expected"); } return str; } private void setLineWidth(int width) { lineWidth = width; getProcessor().setLineWidth(width); } Variable[] getArrayFunction(int type) { Variable[] array; switch (type) { case GET_PROFILE: array=getProfile(); break; case NEW_ARRAY: array = newArray(); break; case SPLIT: array = split(); break; case GET_FILE_LIST: array = getFileList(); break; case GET_FONT_LIST: array = getFontList(); break; case NEW_MENU: array = newMenu(); break; case GET_LIST: array = getList(); break; case ARRAY_FUNC: array = doArray(); break; default: array = null; interp.error("Array function expected"); } return array; } final double math(int type) { double arg = getArg(); switch (type) { case ABS: return Math.abs(arg); case COS: return Math.cos(arg); case EXP: return Math.exp(arg); case FLOOR: return Math.floor(arg); case LOG: return Math.log(arg); case ROUND: return Math.floor(arg + 0.5); case SIN: return Math.sin(arg); case SQRT: return Math.sqrt(arg); case TAN: return Math.tan(arg); case ATAN: return Math.atan(arg); case ASIN: return Math.asin(arg); case ACOS: return Math.acos(arg); default: return 0.0; } } final double math2(int type) { double a1 = getFirstArg(); double a2 = getLastArg(); switch (type) { case MIN_OF: return Math.min(a1, a2); case MAX_OF: return Math.max(a1, a2); case POW: return Math.pow(a1, a2); case ATAN2: return Math.atan2(a1, a2); default: return 0.0; } } final String getString() { String str = interp.getStringTerm(); while (true) { interp.getToken(); if (interp.token=='+') str += interp.getStringTerm(); else { interp.putTokenBack(); break; } }; return str; } final boolean isStringFunction() { Symbol symbol = pgm.table[interp.tokenAddress]; return symbol.type==D2S; } final double getArg() { interp.getLeftParen(); double arg = interp.getExpression(); interp.getRightParen(); return arg; } final double getFirstArg() { interp.getLeftParen(); return interp.getExpression(); } final double getNextArg() { interp.getComma(); return interp.getExpression(); } final double getLastArg() { interp.getComma(); double arg = interp.getExpression(); interp.getRightParen(); return arg; } String getStringArg() { interp.getLeftParen(); String arg = getString(); interp.getRightParen(); return arg; } final String getFirstString() { interp.getLeftParen(); return getString(); } final String getNextString() { interp.getComma(); return getString(); } final String getLastString() { interp.getComma(); String arg = getString(); interp.getRightParen(); return arg; } boolean getBooleanArg() { interp.getLeftParen(); double arg = interp.getBooleanExpression(); interp.checkBoolean(arg); interp.getRightParen(); return arg==0?false:true; } final Variable getVariableArg() { interp.getLeftParen(); Variable v = getVariable(); interp.getRightParen(); return v; } final Variable getFirstVariable() { interp.getLeftParen(); return getVariable(); } final Variable getNextVariable() { interp.getComma(); return getVariable(); } final Variable getLastVariable() { interp.getComma(); Variable v = getVariable(); interp.getRightParen(); return v; } final Variable getVariable() { interp.getToken(); if (interp.token!=WORD) interp.error("Variable expected"); Variable v = interp.lookupLocalVariable(interp.tokenAddress); if (v==null) v = interp.push(interp.tokenAddress, 0.0, null, interp); Variable[] array = v.getArray(); if (array!=null) { int index = interp.getIndex(); checkIndex(index, 0, v.getArraySize()-1); v = array[index]; } return v; } final Variable getFirstArrayVariable() { interp.getLeftParen(); return getArrayVariable(); } final Variable getNextArrayVariable() { interp.getComma(); return getArrayVariable(); } final Variable getLastArrayVariable() { interp.getComma(); Variable v = getArrayVariable(); interp.getRightParen(); return v; } final Variable getArrayVariable() { interp.getToken(); if (interp.token!=WORD) interp.error("Variable expected"); Variable v = interp.lookupLocalVariable(interp.tokenAddress); if (v==null) v = interp.push(interp.tokenAddress, 0.0, null, interp); return v; } final double[] getFirstArray() { interp.getLeftParen(); return getNumericArray(); } final double[] getNextArray() { interp.getComma(); return getNumericArray(); } final double[] getLastArray() { interp.getComma(); double[] a = getNumericArray(); interp.getRightParen(); return a; } double[] getNumericArray() { Variable[] a1 = getArray(); double[] a2 = new double[a1.length]; for (int i=0; i<a1.length; i++) a2[i] = a1[i].getValue(); return a2; } String[] getStringArray() { Variable[] a1 = getArray(); String[] a2 = new String[a1.length]; for (int i=0; i<a1.length; i++) { String s = a1[i].getString(); if (s==null) s = "" + a1[i].getValue(); a2[i] = s; } return a2; } Variable[] getArray() { interp.getToken(); boolean newArray = interp.token==ARRAY_FUNCTION && pgm.table[interp.tokenAddress].type==NEW_ARRAY; if (!(interp.token==WORD||newArray)) interp.error("Array expected"); Variable[] a; if (newArray) a = getArrayFunction(NEW_ARRAY); else { Variable v = interp.lookupVariable(); a= v.getArray(); int size = v.getArraySize(); if (a!=null && a.length!=size) { Variable[] a2 = new Variable[size]; for (int i=0; i<size; i++) a2[i] = a[i]; v.setArray(a2); a = v.getArray(); } } if (a==null) interp.error("Array expected"); return a; } Color getColor() { String color = getString(); color = color.toLowerCase(Locale.US); if (color.equals("black")) return Color.black; else if (color.equals("white")) return Color.white; else if (color.equals("red")) return Color.red; else if (color.equals("green")) return Color.green; else if (color.equals("blue")) return Color.blue; else if (color.equals("cyan")) return Color.cyan; else if (color.equals("darkgray")) return Color.darkGray; else if (color.equals("gray")) return Color.gray; else if (color.equals("lightgray")) return Color.lightGray; else if (color.equals("magenta")) return Color.magenta; else if (color.equals("orange")) return Color.orange; else if (color.equals("yellow")) return Color.yellow; else if (color.equals("pink")) return Color.pink; else interp.error("'red', 'green', etc. expected"); return null; } void checkIndex(int index, int lower, int upper) { if (index<lower || index>upper) interp.error("Index ("+index+") is outside of the "+lower+"-"+upper+" range"); } void doRun() { interp.getLeftParen(); String arg1 = getString(); interp.getToken(); if (!(interp.token==')' || interp.token==',')) interp.error("',' or ')' expected"); String arg2 = null; if (interp.token==',') { arg2 = getString(); interp.getRightParen(); } if (arg2!=null) IJ.run(arg1, arg2); else IJ.run(arg1); resetImage(); IJ.setKeyUp(IJ.ALL_KEYS); shiftKeyDown = altKeyDown = false; } void setForegroundColor() { boolean isImage = WindowManager.getCurrentImage()!=null; int lineWidth = 0; if (isImage) lineWidth = getProcessor().getLineWidth(); IJ.setForegroundColor((int)getFirstArg(), (int)getNextArg(), (int)getLastArg()); resetImage(); if (isImage) setLineWidth(lineWidth); defaultColor = null; defaultValue = Double.NaN; } void setBackgroundColor() { IJ.setBackgroundColor((int)getFirstArg(), (int)getNextArg(), (int)getLastArg()); resetImage(); } void setColor() { colorSet = true; interp.getLeftParen(); if (isStringArg()) { defaultColor = getColor(); getProcessor().setColor(defaultColor); defaultValue = Double.NaN; interp.getRightParen(); return; } double arg1 = interp.getExpression(); if (interp.nextToken()==')') {interp.getRightParen(); setColor(arg1); return;} int red=(int)arg1, green=(int)getNextArg(), blue=(int)getLastArg(); if (red<0) red=0; if (green<0) green=0; if (blue<0) blue=0; if (red>255) red=255; if (green>255) green=255; if (blue>255) blue=255; defaultColor = new Color(red, green, blue); getProcessor().setColor(defaultColor); defaultValue = Double.NaN; } void setColor(double value) { ImageProcessor ip = getProcessor(); ImagePlus imp = getImage(); switch (imp.getBitDepth()) { case 8: if (value<0 || value>255) interp.error("Argument out of 8-bit range (0-255)"); ip.setValue(value); break; case 16: if (imp.getLocalCalibration().isSigned16Bit()) value += 32768; if (value<0 || value>65535) interp.error("Argument out of 16-bit range (0-65535)"); ip.setValue(value); break; default: ip.setValue(value); break; } defaultValue = value; defaultColor = null; } void makeLine() { double x1d = getFirstArg(); double y1d = getNextArg(); double x2d = getNextArg(); interp.getComma(); double y2d = interp.getExpression(); interp.getToken(); if (interp.token==')') IJ.makeLine(x1d, y1d, x2d, y2d); else { int x1 = (int)Math.round(x1d); int y1 = (int)Math.round(y1d); int x2 = (int)Math.round(x2d); int y2 = (int)Math.round(y2d); int max = 200; int[] x = new int[max]; int[] y = new int[max]; x[0]=x1; y[0]=y1; x[1]=x2; y[1]=y2; int n = 2; while (interp.token==',' && n<max) { x[n] = (int)Math.round(interp.getExpression()); if (n==2 && interp.nextToken()==')') { interp.getRightParen(); Roi line = new Line(x1, y1, x2, y2); line.updateWideLine((float)x[n]); getImage().setRoi(line); return; } interp.getComma(); y[n] = (int)Math.round(interp.getExpression()); interp.getToken(); n++; } if (n==max && interp.token!=')') interp.error("More than "+max+" points"); getImage().setRoi(new PolygonRoi(x, y, n, Roi.POLYLINE)); } resetImage(); } void makeOval() { Roi previousRoi = getImage().getRoi(); if (shiftKeyDown||altKeyDown) getImage().saveRoi(); IJ.makeOval((int)Math.round(getFirstArg()), (int)Math.round(getNextArg()), (int)Math.round(getNextArg()), (int)Math.round(getLastArg())); Roi roi = getImage().getRoi(); if (previousRoi!=null && roi!=null) updateRoi(roi); resetImage(); } void makeRectangle() { Roi previousRoi = getImage().getRoi(); if (shiftKeyDown||altKeyDown) getImage().saveRoi(); int x = (int)Math.round(getFirstArg()); int y = (int)Math.round(getNextArg()); int w = (int)Math.round(getNextArg()); int h = (int)Math.round(getNextArg()); int arcSize = 0; if (interp.nextToken()==',') { interp.getComma(); arcSize = (int)interp.getExpression(); } interp.getRightParen(); if (arcSize<1) IJ.makeRectangle(x, y, w, h); else { ImagePlus imp = getImage(); imp.setRoi(new Roi(x,y,w,h,arcSize)); } Roi roi = getImage().getRoi(); if (previousRoi!=null && roi!=null) updateRoi(roi); resetImage(); } ImagePlus getImage() { ImagePlus imp = IJ.getImage(); if (imp.getWindow()==null && IJ.getInstance()!=null && !interp.isBatchMode() && WindowManager.getTempCurrentImage()==null) throw new RuntimeException(Macro.MACRO_CANCELED); defaultIP = null; return imp; } void resetImage() { defaultIP = null; colorSet = fontSet = false; lineWidth = 1; } ImageProcessor getProcessor() { if (defaultIP==null) { defaultIP = getImage().getProcessor(); if (lineWidth!=1) defaultIP.setLineWidth(lineWidth); } return defaultIP; } int getType() { imageType = getImage().getType(); return imageType; } void setPixel() { interp.getLeftParen(); int a1 = (int)interp.getExpression(); interp.getComma(); double a2 = interp.getExpression(); interp.getToken(); if (interp.token==',') { double a3 = interp.getExpression(); interp.getRightParen(); if (getType()==ImagePlus.GRAY32) getProcessor().putPixelValue(a1, (int)a2, a3); else getProcessor().putPixel(a1, (int)a2, (int)a3); } else { if (interp.token!=')') interp.error("')' expected"); getProcessor().setf(a1, (float)a2); } updateNeeded = true; } double getPixel() { interp.getLeftParen(); double a1 = interp.getExpression(); ImageProcessor ip = getProcessor(); double value = 0.0; interp.getToken(); if (interp.token==',') { double a2 = interp.getExpression(); interp.getRightParen(); int ia1 = (int)a1; int ia2 = (int)a2; if (a1==ia1 && a2==ia2) { if (getType()==ImagePlus.GRAY32) value = ip.getPixelValue(ia1, ia2); else value = ip.getPixel(ia1, ia2); } else { if (getType()==ImagePlus.COLOR_RGB) value = ip.getPixelInterpolated(a1, a2); else value = ip.getInterpolatedValue(a1, a2); } } else { if (interp.token!=')') interp.error("')' expected"); value = ip.getf((int)a1); } return value; } void setZCoordinate() { int z = (int)getArg(); ImagePlus imp = getImage(); ImageStack stack = imp.getStack(); int size = stack.getSize(); if (z<0 || z>=size) interp.error("Z coordinate ("+z+") is out of 0-"+(size-1)+ " range"); this.defaultIP = stack.getProcessor(z+1); } void moveTo() { interp.getLeftParen(); int a1 = (int)Math.round(interp.getExpression()); interp.getComma(); int a2 = (int)Math.round(interp.getExpression()); interp.getRightParen(); getProcessor().moveTo(a1, a2); } void lineTo() { interp.getLeftParen(); int a1 = (int)Math.round(interp.getExpression()); interp.getComma(); int a2 = (int)Math.round(interp.getExpression()); interp.getRightParen(); ImageProcessor ip = getProcessor(); if (!colorSet) setForegroundColor(ip); ip.lineTo(a1, a2); updateAndDraw(); } void drawLine() { interp.getLeftParen(); int x1 = (int)Math.round(interp.getExpression()); interp.getComma(); int y1 = (int)Math.round(interp.getExpression()); interp.getComma(); int x2 = (int)Math.round(interp.getExpression()); interp.getComma(); int y2 = (int)Math.round(interp.getExpression()); interp.getRightParen(); ImageProcessor ip = getProcessor(); if (!colorSet) setForegroundColor(ip); ip.drawLine(x1, y1, x2, y2); updateAndDraw(); } void setForegroundColor(ImageProcessor ip) { if (defaultColor!=null) ip.setColor(defaultColor); else if (!Double.isNaN(defaultValue)) ip.setValue(defaultValue); else ip.setColor(Toolbar.getForegroundColor()); colorSet = true; } void doIPMethod(int type) { interp.getParens(); ImageProcessor ip = getProcessor(); switch (type) { case SNAPSHOT: ip.snapshot(); break; case RESET: ip.reset(); updateNeeded = true; break; case FILL: ImagePlus imp = getImage(); Roi roi = imp.getRoi(); if (!colorSet) setForegroundColor(ip); if (roi==null) { ip.resetRoi(); ip.fill(); } else { ip.setRoi(roi); ip.fill(ip.getMask()); } imp.updateAndDraw(); break; } } void updateAndDraw() { if (autoUpdate) { ImagePlus imp = getImage(); imp.updateChannelAndDraw(); imp.changes = true; } else updateNeeded = true; } void updateDisplay() { if (updateNeeded && WindowManager.getImageCount()>0) { ImagePlus imp = getImage(); imp.updateAndDraw(); updateNeeded = false; } } void drawString() { interp.getLeftParen(); String str = getString(); interp.getComma(); int x = (int)(interp.getExpression()+0.5); interp.getComma(); int y = (int)(interp.getExpression()+0.5); Color background = null; if (interp.nextToken()==',') { interp.getComma(); background = getColor(); } interp.getRightParen(); ImageProcessor ip = getProcessor(); if (!colorSet) setForegroundColor(ip); setFont(ip); ip.setJustification(justification); ip.setAntialiasedText(antialiasedText); if (background!=null) ip.drawString(str, x, y, background); else ip.drawString(str, x, y); updateAndDraw(); } void setFont(ImageProcessor ip) { if (font!=null && !fontSet) ip.setFont(font); fontSet = true; } void setJustification() { String str = getStringArg().toLowerCase(Locale.US); int just = ImageProcessor.LEFT_JUSTIFY; if (str.equals("center")) just = ImageProcessor.CENTER_JUSTIFY; else if (str.equals("right")) just = ImageProcessor.RIGHT_JUSTIFY; justification = just; } void changeValues() { double darg1 = getFirstArg(); double darg2 = getNextArg(); double darg3 = getLastArg(); ImagePlus imp = getImage(); ImageProcessor ip = getProcessor(); Roi roi = imp.getRoi(); ImageProcessor mask = null; if (roi==null || !roi.isArea()) { ip.resetRoi(); roi = null; } else { ip.setRoi(roi); mask = ip.getMask(); if (mask!=null) ip.snapshot(); } int xmin=0, ymin=0, xmax=imp.getWidth(), ymax=imp.getHeight(); if (roi!=null) { Rectangle r = roi.getBounds(); xmin=r.x; ymin=r.y; xmax=r.x+r.width; ymax=r.y+r.height; } boolean isFloat = getType()==ImagePlus.GRAY32; if (imp.getBitDepth()==24) { darg1 = (int)darg1&0xffffff; darg2 = (int)darg2&0xffffff; } double v; for (int y=ymin; y<ymax; y++) { for (int x=xmin; x<xmax; x++) { v = isFloat?ip.getPixelValue(x,y):ip.getPixel(x,y)&0xffffff; if (v>=darg1 && v<=darg2) { if (isFloat) ip.putPixelValue(x, y, darg3); else ip.putPixel(x, y, (int)darg3); } } } if (mask!=null) ip.reset(mask); if (imp.getType()==ImagePlus.GRAY16 || imp.getType()==ImagePlus.GRAY32) ip.resetMinAndMax(); imp.updateAndDraw(); updateNeeded = false; } void requires() { if (IJ.versionLessThan(getStringArg())) interp.done = true; } Random ran; double random() { double dseed = Double.NaN; if (interp.nextToken()=='(') { interp.getLeftParen(); if (isStringArg()) { String arg = getString().toLowerCase(Locale.US); if (arg.indexOf("seed")==-1) interp.error("'seed' expected"); interp.getComma(); dseed = interp.getExpression(); long seed = (long)dseed; if (seed!=dseed) interp.error("Seed not integer"); ran = new Random(seed); } interp.getRightParen(); if (!Double.isNaN(dseed)) return Double.NaN; } interp.getParens(); if (ran==null) ran = new Random(); return ran.nextDouble(); } //void setSeed() { // long seed = (long)getArg(); // if (ran==null) // ran = new Random(seed); // else // ran.setSeed(seed); //} double getResult() { interp.getLeftParen(); String column = getString(); int row = -1; if (interp.nextToken()==',') { interp.getComma(); row = (int)interp.getExpression(); } interp.getRightParen(); ResultsTable rt = Analyzer.getResultsTable(); int counter = rt.getCounter(); if (counter==0) interp.error("\"Results\" table empty"); if (row==-1) row = counter-1; if (row<0 || row>=counter) interp.error("Row ("+row+") out of range"); int col = rt.getColumnIndex(column); if (!rt.columnExists(col)) return Double.NaN; else return rt.getValueAsDouble(col, row); } String getResultLabel() { int row = (int)getArg(); ResultsTable rt = Analyzer.getResultsTable(); int counter = rt.getCounter(); if (counter==0) interp.error("\"Results\" table empty"); if (row<0 || row>=counter) interp.error("Row ("+row+") out of range"); String label = rt.getLabel(row); return label!=null?label:""; } void setResult() { interp.getLeftParen(); String column = getString(); interp.getComma(); int row = (int)interp.getExpression(); interp.getComma(); double value = 0.0; String label = null; if (column.equals("Label")) label = getString(); else value = interp.getExpression(); interp.getRightParen(); ResultsTable rt = Analyzer.getResultsTable(); if (row<0 || row>rt.getCounter()) interp.error("Row ("+row+") out of range"); if (row==rt.getCounter()) rt.incrementCounter(); try { if (label!=null) rt.setLabel(label, row); else rt.setValue(column, row, value); resultsPending = true; } catch (Exception e) { interp.error(""+e.getMessage()); } } void updateResults() { interp.getParens(); ResultsTable rt = Analyzer.getResultsTable(); rt.show("Results"); resultsPending = false; } double getNumber() { String prompt = getFirstString(); double defaultValue = getLastArg(); String title = interp.macroName!=null?interp.macroName:""; if (title.endsWith(" Options")) title = title.substring(0, title.length()-8); GenericDialog gd = new GenericDialog(title); int decimalPlaces = (int)defaultValue==defaultValue?0:2; gd.addNumericField(prompt, defaultValue, decimalPlaces); gd.showDialog(); if (gd.wasCanceled()) { interp.done = true; return defaultValue; } double v = gd.getNextNumber(); if (gd.invalidNumber()) return defaultValue; else return v; } double getBoolean() { String prompt = getStringArg(); String title = interp.macroName!=null?interp.macroName:""; if (title.endsWith(" Options")) title = title.substring(0, title.length()-8); YesNoCancelDialog d = new YesNoCancelDialog(IJ.getInstance(), title, prompt); if (d.cancelPressed()) { interp.done = true; return 0.0; } else if (d.yesPressed()) return 1.0; else return 0.0; } double getBoolean2() { String prompt = getFirstString(); interp.getComma(); double defaultValue = interp.getBooleanExpression(); interp.checkBoolean(defaultValue); interp.getRightParen(); String title = interp.macroName!=null?interp.macroName:""; if (title.endsWith(" Options")) title = title.substring(0, title.length()-8); GenericDialog gd = new GenericDialog(title); gd.addCheckbox(prompt, defaultValue==1.0?true:false); gd.showDialog(); if (gd.wasCanceled()) { interp.done = true; return 0.0; } return gd.getNextBoolean()?1.0:0.0; } String getStringDialog() { interp.getLeftParen(); String prompt = getString(); interp.getComma(); String defaultStr = getString(); interp.getRightParen(); String title = interp.macroName!=null?interp.macroName:""; if (title.endsWith(" Options")) title = title.substring(0, title.length()-8); GenericDialog gd = new GenericDialog(title); gd.addStringField(prompt, defaultStr, 20); gd.showDialog(); String str = ""; if (gd.wasCanceled()) interp.done = true; else str = gd.getNextString(); return str; } String d2s() { return IJ.d2s(getFirstArg(), (int)getLastArg()); } String toString(int base) { int arg = (int)getArg(); if (base==2) return Integer.toBinaryString(arg); else return Integer.toHexString(arg); } double getStackSize() { interp.getParens(); return getImage().getStackSize(); } double getImageCount() { interp.getParens(); return WindowManager.getImageCount(); } double getResultsCount() { interp.getParens(); return Analyzer.getResultsTable().getCounter(); } void getCoordinates() { Variable xCoordinates = getFirstArrayVariable(); Variable yCoordinates = getLastArrayVariable(); ImagePlus imp = getImage(); Roi roi = imp.getRoi(); if (roi==null) interp.error("Selection required"); Variable[] xa, ya; if (roi.getType()==Roi.LINE) { xa = new Variable[2]; ya = new Variable[2]; Line line = (Line)roi; xa[0] = new Variable(line.x1d); ya[0] = new Variable(line.y1d); xa[1] = new Variable(line.x2d); ya[1] = new Variable(line.y2d); } else { FloatPolygon fp = roi.getFloatPolygon(); if (fp!=null) { xa = new Variable[fp.npoints]; ya = new Variable[fp.npoints]; for (int i=0; i<fp.npoints; i++) xa[i] = new Variable(fp.xpoints[i]); for (int i=0; i<fp.npoints; i++) ya[i] = new Variable(fp.ypoints[i]); } else { Polygon p = roi.getPolygon(); xa = new Variable[p.npoints]; ya = new Variable[p.npoints]; for (int i=0; i<p.npoints; i++) xa[i] = new Variable(p.xpoints[i]); for (int i=0; i<p.npoints; i++) ya[i] = new Variable(p.ypoints[i]); } } xCoordinates.setArray(xa); yCoordinates.setArray(ya); } Variable[] getProfile() { interp.getParens(); ImagePlus imp = getImage(); if (imp.getRoi()==null) interp.error("Selection required"); ProfilePlot pp = new ProfilePlot(imp, IJ.altKeyDown()); double[] array = pp.getProfile(); if (array==null) {interp.done=true; return null;} else return new Variable(array).getArray(); } Variable[] newArray() { if (interp.nextToken()!='(' || interp.nextNextToken()==')') { interp.getParens(); return new Variable[0]; } interp.getLeftParen(); int next = interp.nextToken(); int nextNext = interp.nextNextToken(); if (next==STRING_CONSTANT || nextNext==',' || nextNext=='[' || next=='-' || next==PI) return initNewArray(); int size = (int)interp.getExpression(); if (size<0) interp.error("Negative array size"); interp.getRightParen(); Variable[] array = new Variable[size]; for (int i=0; i<size; i++) array[i] = new Variable(); return array; } Variable[] split() { String s1 = getFirstString(); String s2 = null; if (interp.nextToken()==')') interp.getRightParen(); else s2 = getLastString(); if (s1==null) return null; String[] strings = (s2==null||s2.equals(""))?Tools.split(s1):Tools.split(s1, s2); Variable[] array = new Variable[strings.length]; for (int i=0; i<strings.length; i++) array[i] = new Variable(0, 0.0, strings[i]); return array; } Variable[] getFileList() { String dir = getStringArg(); File f = new File(dir); if (!f.exists() || !f.isDirectory()) return new Variable[0]; String[] list = f.list(); if (list==null) return new Variable[0]; if (System.getProperty("os.name").indexOf("Linux")!=-1) ij.util.StringSorter.sort(list); File f2; int hidden = 0; for (int i=0; i<list.length; i++) { if (list[i].startsWith(".") || list[i].equals("Thumbs.db")) { list[i] = null; hidden++; } else { f2 = new File(dir, list[i]); if (f2.isDirectory()) list[i] = list[i] + "/"; } } int n = list.length-hidden; if (n<=0) return new Variable[0]; if (hidden>0) { String[] list2 = new String[n]; int j = 0; for (int i=0; i<list.length; i++) { if (list[i]!=null) list2[j++] = list[i]; } list = list2; } Variable[] array = new Variable[n]; for (int i=0; i<n; i++) array[i] = new Variable(0, 0.0, list[i]); return array; } Variable[] initNewArray() { Vector vector = new Vector(); int size = 0; do { Variable v = new Variable(); if (isStringArg()) v.setString(getString()); else v.setValue(interp.getExpression()); vector.addElement(v); size++; interp.getToken(); } while (interp.token==','); if (interp.token!=')') interp.error("';' expected"); Variable[] array = new Variable[size]; vector.copyInto((Variable[])array); if (array.length==1 && array[0].getString()==null) { size = (int)array[0].getValue(); if (size<0) interp.error("Negative array size"); Variable[] array2 = new Variable[size]; for (int i=0; i<size; i++) array2[i] = new Variable(); return array2; } else return array; } String fromCharCode() { char[] chars = new char[100]; int count = 0; interp.getLeftParen(); while(interp.nextToken()!=')') { int value = (int)interp.getExpression(); if (value<0 || value>65535) interp.error("Value (" + value + ") out of 0-65535 range"); chars[count++] = (char)value; if (interp.nextToken()==',') interp.getToken(); } interp.getRightParen(); return new String(chars, 0, count); } String getInfo() { if (interp.nextNextToken()==STRING_CONSTANT || (interp.nextToken()=='('&&interp.nextNextToken()!=')')) return getInfo(getStringArg()); else { interp.getParens(); return getWindowContents(); } } String getInfo(String key) { int len = key.length(); if (len==9 && key.charAt(4)==',') { String tag = DicomTools.getTag(getImage(), key); return tag!=null?tag:""; } else if (key.equals("overlay")) { Overlay overlay = getImage().getOverlay(); if (overlay==null) return ""; else return overlay.toString(); } else if (key.equals("log")||key.equals("Log")) { String log = IJ.getLog(); return log!=null?log:""; } else if (key.indexOf(".")==-1) { String value = getMetadataValue(key); if (value!=null) return value; } else if (key.equals("micrometer.abbreviation")) return "\u00B5m"; else if (key.equals("image.subtitle")) { ImagePlus imp = getImage(); ImageWindow win = imp.getWindow(); return win!=null?win.createSubtitle():""; } else if (key.equals("slice.label")) { ImagePlus imp = getImage(); if (imp.getStackSize()==1) return ""; String label = imp.getStack().getShortSliceLabel(imp.getCurrentSlice()); return label!=null?label:""; } else if (key.equals("window.contents")) { return getWindowContents(); } else if (key.equals("image.description")) { String description = ""; FileInfo fi = getImage().getOriginalFileInfo(); if (fi!=null) description = fi.description; if (description==null) description = ""; return description; } else if (key.equals("image.filename")) { String name= ""; FileInfo fi = getImage().getOriginalFileInfo(); if (fi!=null && fi.fileName!=null) name= fi.fileName; return name; } else if (key.equals("image.directory")) { String dir= ""; FileInfo fi = getImage().getOriginalFileInfo(); if (fi!=null && fi.directory!=null) dir= fi.directory; return dir; } else if (key.equals("selection.name")||key.equals("roi.name")) { ImagePlus imp = getImage(); 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 if (key.equals("threshold.method")) { return ThresholdAdjuster.getMethod(); } else if (key.equals("threshold.mode")) { return ThresholdAdjuster.getMode(); } else { String value = ""; try {value = System.getProperty(key);} catch (Exception e) {}; return value!=null?value:""; } return ""; } String getMetadataValue(String key) { String metadata = getMetadataAsString(); if (metadata==null) return null; int index1 = metadata.indexOf(key+" ="); if (index1!=-1) index1 += key.length() + 2; else { index1 = metadata.indexOf(key+":"); if (index1!=-1) index1 += key.length() + 1; else return null; } int index2 = metadata.indexOf("\n", index1); if (index2==-1) return null; String value = metadata.substring(index1+1, index2); if (value.startsWith(" ")) value = value.substring(1, value.length()); return value; } String getMetadataAsString() { ImagePlus imp = getImage(); String metadata = null; if (imp.getStackSize()>1) { ImageStack stack = imp.getStack(); String label = stack.getSliceLabel(imp.getCurrentSlice()); if (label!=null && label.indexOf('\n')>0) metadata = label; } if (metadata==null) metadata = (String)imp.getProperty("Info"); return metadata; } String getWindowContents() { Frame frame = WindowManager.getFrontWindow(); if (frame!=null && frame instanceof TextWindow) { TextPanel tp = ((TextWindow)frame).getTextPanel(); return tp.getText(); } else if (frame!=null && frame instanceof Editor) { return ((Editor)frame).getText(); } else if (frame!=null && frame instanceof Recorder) { return ((Recorder)frame).getText(); } else return getImageInfo(); } String getImageInfo() { ImagePlus imp = getImage(); Info infoPlugin = new Info(); return infoPlugin.getImageInfo(imp, getProcessor()); } public String getDirectory() { String dir = IJ.getDirectory(getStringArg()); if (dir==null) dir = ""; return dir; } double getSelectionType() { interp.getParens(); double type = -1; ImagePlus imp = getImage(); Roi roi = imp.getRoi(); if (roi!=null) type = roi.getType(); return type; } void showMessage(boolean withCancel) { String message; interp.getLeftParen(); String title = getString(); if (interp.nextToken()==',') { interp.getComma(); message = getString(); } else { message = title; title = ""; } interp.getRightParen(); if (withCancel) IJ.showMessageWithCancel(title, message); else IJ.showMessage(title, message); } double lengthOf() { int length = 0; interp.getLeftParen(); switch (interp.nextToken()) { case STRING_CONSTANT: case STRING_FUNCTION: case USER_FUNCTION: length = getString().length(); break; case WORD: if (pgm.code[interp.pc+2]=='[') { length = getString().length(); break; } interp.getToken(); Variable v = interp.lookupVariable(); if (v==null) return 0.0; String s = v.getString(); if (s!=null) length = s.length(); else { Variable[] array = v.getArray(); if (array!=null) length = v.getArraySize(); else interp.error("String or array expected"); } break; default: interp.error("String or array expected"); } interp.getRightParen(); return length; } void getCursorLoc() { Variable x = getFirstVariable(); Variable y = getNextVariable(); Variable z = getNextVariable(); Variable flags = getLastVariable(); ImagePlus imp = getImage(); ImageCanvas ic = imp.getCanvas(); if (ic==null) return; Point p = ic.getCursorLoc(); x.setValue(p.x); y.setValue(p.y); z.setValue(imp.getCurrentSlice()-1); Roi roi = imp.getRoi(); flags.setValue(ic.getModifiers()+((roi!=null)&&roi.contains(p.x,p.y)?32:0)); } void getLine() { Variable vx1 = getFirstVariable(); Variable vy1 = getNextVariable(); Variable vx2 = getNextVariable(); Variable vy2 = getNextVariable(); Variable lineWidth = getLastVariable(); ImagePlus imp = getImage(); double x1=-1, y1=-1, x2=-1, y2=-1; Roi roi = imp.getRoi(); if (roi!=null && roi.getType()==Roi.LINE) { Line line = (Line)roi; x1=line.x1d; y1=line.y1d; x2=line.x2d; y2=line.y2d; } vx1.setValue(x1); vy1.setValue(y1); vx2.setValue(x2); vy2.setValue(y2); lineWidth.setValue(roi!=null?roi.getStrokeWidth():1); } void getVoxelSize() { Variable width = getFirstVariable(); Variable height = getNextVariable(); Variable depth = getNextVariable(); Variable unit = getLastVariable(); ImagePlus imp = getImage(); Calibration cal = imp.getCalibration(); width.setValue(cal.pixelWidth); height.setValue(cal.pixelHeight); depth.setValue(cal.pixelDepth); unit.setString(cal.getUnits()); } void getHistogram() { interp.getLeftParen(); Variable values = null; if (interp.nextToken()==NUMBER) interp.getExpression(); else values = getArrayVariable(); Variable counts = getNextArrayVariable(); interp.getComma(); int nBins = (int)interp.getExpression(); ImagePlus imp = getImage(); double histMin=0.0, histMax=0.0; boolean setMinMax = false; int bitDepth = imp.getBitDepth(); if (interp.nextToken()==',') { histMin = getNextArg(); histMax = getLastArg(); if (bitDepth==8 || bitDepth==24) interp.error("16 or 32-bit image required to set histMin and histMax"); setMinMax = true; } else interp.getRightParen(); if ((bitDepth==8||bitDepth==24) && nBins!=256) interp.error("Bin count ("+nBins+") must be 256 for 8-bit and RGB images"); if (nBins==65536 && bitDepth==16) { Variable[] array = counts.getArray(); int[] hist = getProcessor().getHistogram(); if (array!=null && array.length==nBins) { for (int i=0; i<nBins; i++) array[i].setValue(hist[i]); } else counts.setArray(new Variable(hist).getArray()); return; } ImageStatistics stats; if (setMinMax) stats = imp.getStatistics(AREA+MEAN+MODE+MIN_MAX, nBins, histMin, histMax); else stats = imp.getStatistics(AREA+MEAN+MODE+MIN_MAX, nBins); if (values!=null) { Calibration cal = imp.getCalibration(); double[] array = new double[nBins]; double value = cal.getCValue(stats.histMin); double inc = 1.0; if (bitDepth==16 || bitDepth==32 || cal.calibrated()) inc = (cal.getCValue(stats.histMax) - cal.getCValue(stats.histMin))/stats.nBins; for (int i=0; i<nBins; i++) { array[i] = value; value += inc; } values.setArray(new Variable(array).getArray()); } Variable[] array = counts.getArray(); if (array!=null && array.length==nBins) { for (int i=0; i<nBins; i++) array[i].setValue(stats.histogram[i]); } else counts.setArray(new Variable(stats.histogram).getArray()); } void getLut() { Variable reds = getFirstArrayVariable(); Variable greens = getNextArrayVariable(); Variable blues = getLastArrayVariable(); ImagePlus imp = getImage(); IndexColorModel cm = null; if (imp.isComposite()) cm = ((CompositeImage)imp).getChannelLut(); else { ImageProcessor ip = imp.getProcessor(); if (ip instanceof ColorProcessor) interp.error("Non-RGB image expected"); cm = (IndexColorModel)ip.getColorModel(); } int mapSize = cm.getMapSize(); byte[] rLUT = new byte[mapSize]; byte[] gLUT = new byte[mapSize]; byte[] bLUT = new byte[mapSize]; cm.getReds(rLUT); cm.getGreens(gLUT); cm.getBlues(bLUT); reds.setArray(new Variable(rLUT).getArray()); greens.setArray(new Variable(gLUT).getArray()); blues.setArray(new Variable(bLUT).getArray()); } void setLut() { double[] reds = getFirstArray(); double[] greens = getNextArray(); double[] blues = getLastArray(); int length = reds.length; if (greens.length!=length || blues.length!=length) interp.error("Arrays are not the same length"); ImagePlus imp = getImage(); if (imp.getBitDepth()==24) interp.error("Non-RGB image expected"); ImageProcessor ip = getProcessor(); byte[] r = new byte[length]; byte[] g = new byte[length]; byte[] b = new byte[length]; for (int i=0; i<length; i++) { r[i] = (byte)reds[i]; g[i] = (byte)greens[i]; b[i] = (byte)blues[i]; } LUT lut = new LUT(8, length, r, g, b); if (imp.isComposite()) ((CompositeImage)imp).setChannelLut(lut); else ip.setColorModel(lut); imp.updateAndDraw(); updateNeeded = false; } void getThreshold() { Variable lower = getFirstVariable(); Variable upper = getLastVariable(); ImagePlus imp = getImage(); ImageProcessor ip = getProcessor(); double t1 = ip.getMinThreshold(); double t2 = ip.getMaxThreshold(); if (t1==ImageProcessor.NO_THRESHOLD) { t1 = -1; t2 = -1; } else { Calibration cal = imp.getCalibration(); t1 = cal.getCValue(t1); t2 = cal.getCValue(t2); } lower.setValue(t1); upper.setValue(t2); } void getPixelSize() { Variable unit = getFirstVariable(); Variable width = getNextVariable(); Variable height = getNextVariable(); Variable depth = null; if (interp.nextToken()==',') depth = getNextVariable(); interp.getRightParen(); Calibration cal = getImage().getCalibration(); unit.setString(cal.getUnits()); width.setValue(cal.pixelWidth); height.setValue(cal.pixelHeight); if (depth!=null) depth.setValue(cal.pixelDepth); } void makeSelection() { String type = null; int roiType = -1; interp.getLeftParen(); if (isStringArg()) { type = getString().toLowerCase(); roiType = Roi.POLYGON; if (type.indexOf("free")!=-1) roiType = Roi.FREEROI; if (type.indexOf("traced")!=-1) roiType = Roi.TRACED_ROI; if (type.indexOf("line")!=-1) { if (type.indexOf("free")!=-1) roiType = Roi.FREELINE; else roiType = Roi.POLYLINE; } if (type.indexOf("angle")!=-1) roiType = Roi.ANGLE; if (type.indexOf("point")!=-1) roiType = Roi.POINT; } else { roiType = (int)interp.getExpression(); if (roiType<0 || roiType==Roi.COMPOSITE) interp.error("Invalid selection type ("+roiType+")"); if (roiType==Roi.RECTANGLE) roiType = Roi.POLYGON; if (roiType==Roi.OVAL) roiType = Roi.FREEROI; } double[] x = getNextArray(); int n = x.length; interp.getComma(); double[] y = getNumericArray(); if (interp.nextToken()==',') { n = (int)getLastArg(); if (n>x.length || n>y.length) interp.error("Array too short"); } else { interp.getRightParen(); if (y.length!=n) interp.error("Arrays are not the same length"); } ImagePlus imp = getImage(); int[] xcoord = new int[n]; int[] ycoord = new int[n]; int height = imp.getHeight(); for (int i=0; i<n; i++) { xcoord[i] = (int)Math.round(x[i]); ycoord[i] = (int)Math.round(y[i]); } Roi roi = null; if (roiType==Roi.LINE) { if (xcoord.length!=2) interp.error("2 element arrays expected"); roi = new Line(xcoord[0], ycoord[0], xcoord[1], ycoord[1]); } else if (roiType==Roi.POINT) roi = new PointRoi(xcoord, ycoord, n); else roi = new PolygonRoi(xcoord, ycoord, n, roiType); Roi previousRoi = imp.getRoi(); if (shiftKeyDown||altKeyDown) imp.saveRoi(); imp.setRoi(roi); if (roiType==Roi.POLYGON || roiType==Roi.FREEROI) { roi = imp.getRoi(); if (previousRoi!=null && roi!=null) updateRoi(roi); } updateNeeded = false; } void doPlot() { interp.getToken(); if (interp.token!='.') interp.error("'.' expected"); interp.getToken(); if (!(interp.token==WORD || interp.token==PREDEFINED_FUNCTION)) interp.error("Function name expected: "); String name = interp.tokenString; if (name.equals("create")) { newPlot(); return; } else if (name.equals("getValues")) { getPlotValues(); return; } if (plot==null) interp.error("No plot defined"); if (name.equals("show")) { showPlot(); return; } else if (name.equals("update")) { updatePlot(); return; } else if (name.equals("setFrameSize")) { plot.setFrameSize((int)getFirstArg(), (int)getLastArg()); return; } else if (name.equals("setLimits")) { plot.setLimits(getFirstArg(), getNextArg(), getNextArg(), getLastArg()); return; } else if (name.equals("addText") || name.equals("drawLabel")) { addPlotText(); return; } else if (name.equals("drawLine")) { drawPlotLine(); return; } else if (name.equals("setColor")) { setPlotColor(); return; } else if (name.equals("add")) { String arg = getFirstString(); arg = arg.toLowerCase(Locale.US); int what = Plot.CIRCLE; if (arg.indexOf("curve")!=-1 || arg.indexOf("line")!=-1) what = Plot.LINE; else if (arg.indexOf("box")!=-1) what = Plot.BOX; else if (arg.indexOf("triangle")!=-1) what = Plot.TRIANGLE; else if (arg.indexOf("cross")!=-1) what = Plot.CROSS; else if (arg.indexOf("dot")!=-1) what = Plot.DOT; else if (arg.indexOf("x")!=-1) what = Plot.X; else if (arg.indexOf("error")!=-1) what = -1; addToPlot(what); return; } else if (name.startsWith("setLineWidth")) { plot.setLineWidth((int)getArg()); return; } else if (name.startsWith("setJustification")) { doFunction(SET_JUSTIFICATION); return; } else interp.error("Unrecognized plot function"); } void getPlotValues() { Variable xvar = getFirstArrayVariable(); Variable yvar = getLastArrayVariable(); float[] xvalues = new float[0]; float[] yvalues = new float[0]; ImagePlus imp = getImage(); ImageWindow win = imp.getWindow(); if (imp.getProperty("XValues")!=null) { xvalues = (float[])imp.getProperty("XValues"); yvalues = (float[])imp.getProperty("YValues"); } else if (win!=null && win instanceof PlotWindow) { PlotWindow pw = (PlotWindow)win; xvalues = pw.getXValues(); yvalues = pw.getYValues(); } else if (win!=null && win instanceof HistogramWindow) { HistogramWindow hw = (HistogramWindow)win; double[] x = hw.getXValues(); xvalues = new float[x.length]; for (int i=0; i<x.length; i++) xvalues[i] = (float)x[i]; int[] y = hw.getHistogram(); yvalues = new float[y.length]; for (int i=0; i<y.length; i++) yvalues[i] = y[i]; } else interp.error("No plot or histogram window"); Variable[] xa = new Variable[xvalues.length]; Variable[] ya = new Variable[yvalues.length]; for (int i=0; i<xvalues.length; i++) xa[i] = new Variable(xvalues[i]); for (int i=0; i<yvalues.length; i++) ya[i] = new Variable(yvalues[i]); xvar.setArray(xa); yvar.setArray(ya); } void newPlot() { String title = getFirstString(); String xLabel = getNextString(); String yLabel = getNextString(); double[] x, y; if (interp.nextToken()==')') x = y = null; else { x = getNextArray(); if (interp.nextToken()==')') { y = x; x = new double[y.length]; for (int i=0; i<y.length; i++) x[i] = i; } else y = getNextArray(); } interp.getRightParen(); plot = new Plot(title, xLabel, yLabel, x, y); } void showPlot() { if (plot!=null) { PlotWindow plotWindow = plot.show(); if (plotWindow!=null) plotID = plotWindow.getImagePlus().getID(); } plot = null; interp.getParens(); } void updatePlot() { if (plot!=null) { ImagePlus plotImage = WindowManager.getImage(plotID); ImageWindow win = plotImage!=null?plotImage.getWindow():null; if (win!=null) ((PlotWindow)win).drawPlot(plot); else { PlotWindow plotWindow = plot.show(); if (plotWindow!=null) plotID = plotWindow.getImagePlus().getID(); } } plot = null; interp.getParens(); } void addPlotText() { String str = getFirstString(); double x = getNextArg(); double y = getLastArg(); plot.setJustification(justification); plot.addLabel(x, y, str); } void drawPlotLine() { double x1 = getFirstArg(); double y1 = getNextArg(); double x2 = getNextArg(); double y2 = getLastArg(); plot.drawLine(x1, y1, x2, y2); } void setPlotColor() { interp.getLeftParen(); plot.setColor(getColor()); interp.getRightParen(); } void addToPlot(int what) { double[] x = getNextArray(); double[] y; if (interp.nextToken()==')') { y = x; x = new double[y.length]; for (int i=0; i<y.length; i++) x[i] = i; } else { interp.getComma(); y = getNumericArray(); } interp.getRightParen(); if (what==-1) plot.addErrorBars(y); else plot.addPoints(x, y, what); } void getBounds() { Variable x = getFirstVariable(); Variable y = getNextVariable(); Variable width = getNextVariable(); Variable height = getLastVariable(); ImagePlus imp = getImage(); Roi roi = imp.getRoi(); if (roi!=null) { Rectangle r = roi.getBounds(); x.setValue(r.x); y.setValue(r.y); width.setValue(r.width); height.setValue(r.height); } else { x.setValue(0); y.setValue(0); width.setValue(imp.getWidth()); height.setValue(imp.getHeight()); } } String substring() { String s = getFirstString(); int index1 = (int)getNextArg(); int index2 = s.length(); if (interp.nextToken()==',') index2 = (int)getLastArg(); else interp.getRightParen(); if (index1>index2) interp.error("beginIndex>endIndex"); checkIndex(index1, 0, s.length()); checkIndex(index2, 0, s.length()); return s.substring(index1, index2); } int indexOf() { String s1 = getFirstString(); String s2 = getNextString(); int fromIndex = 0; if (interp.nextToken()==',') { fromIndex = (int)getLastArg(); checkIndex(fromIndex, 0, s1.length()-1); } else interp.getRightParen(); if (fromIndex==0) return s1.indexOf(s2); else return s1.indexOf(s2, fromIndex); } int startsWithEndsWith(int type) { String s1 = getFirstString(); String s2 = getLastString(); if (type==STARTS_WITH) return s1.startsWith(s2)?1:0; else return s1.endsWith(s2)?1:0; } double isActive() { int id = (int)getArg(); ImagePlus imp = WindowManager.getCurrentImage(); if (imp==null || imp.getID()!=id) return 0.0; //false else return 1.0; //true } double isOpen() { interp.getLeftParen(); if (isStringArg()) { String title = getString(); interp.getRightParen(); return isOpen(title)?1.0:0.0; } else { int id = (int)interp.getExpression(); interp.getRightParen(); return WindowManager.getImage(id)==null?0.0:1.0; } } boolean isOpen(String title) { boolean open = WindowManager.getFrame(title)!=null; if (open) return true; else if (Interpreter.isBatchMode() && Interpreter.imageTable!=null) { for (Enumeration en=Interpreter.imageTable.elements(); en.hasMoreElements();) { ImagePlus imp = (ImagePlus)en.nextElement(); if (imp!=null && imp.getTitle().equals(title)) return true; } } return false; } boolean isStringArg() { int nextToken = pgm.code[interp.pc+1]; int tok = nextToken&0xff; if (tok==STRING_CONSTANT||tok==STRING_FUNCTION) return true; if (tok!=WORD) return false; Variable v = interp.lookupVariable(nextToken>>TOK_SHIFT); if (v==null) return false; int type = v.getType(); if (type!=Variable.ARRAY) return v.getType()==Variable.STRING; Variable[] array = v.getArray(); if (array.length==0) return false; return array[0].getType()==Variable.STRING; } void exit() { String msg = null; if (interp.nextToken()=='(') { interp.getLeftParen(); if (isStringArg()) msg = getString(); interp.getRightParen(); } interp.finishUp(); if (msg!=null) IJ.showMessage("Macro", msg); throw new RuntimeException(Macro.MACRO_CANCELED); } void showProgress() { ImageJ ij = IJ.getInstance(); ij.gui.ProgressBar progressBar = ij!=null?ij.getProgressBar():null; interp.getLeftParen(); double arg1 = interp.getExpression(); if (interp.nextToken()==',') { interp.getComma(); double arg2 = interp.getExpression(); if (progressBar!=null) progressBar.show((arg1+1.0)/arg2, true); } else if (progressBar!=null) progressBar.show(arg1, true); interp.getRightParen(); interp.showingProgress = true; } void saveSettings() { interp.getParens(); usePointerCursor = Prefs.usePointerCursor; hideProcessStackDialog = IJ.hideProcessStackDialog; divideByZeroValue = FloatBlitter.divideByZeroValue; jpegQuality = FileSaver.getJpegQuality(); saveLineWidth = Line.getWidth(); doScaling = ImageConverter.getDoScaling(); weightedColor = Prefs.weightedColor; weights = ColorProcessor.getWeightingFactors(); interpolateScaledImages = Prefs.interpolateScaledImages; open100Percent = Prefs.open100Percent; blackCanvas = Prefs.blackCanvas; useJFileChooser = Prefs.useJFileChooser; debugMode = IJ.debugMode; foregroundColor =Toolbar.getForegroundColor(); backgroundColor =Toolbar.getBackgroundColor(); roiColor = Roi.getColor(); pointAutoMeasure = Prefs.pointAutoMeasure; requireControlKey = Prefs.requireControlKey; useInvertingLut = Prefs.useInvertingLut; saveSettingsCalled = true; measurements = Analyzer.getMeasurements(); decimalPlaces = Analyzer.getPrecision(); blackBackground = Prefs.blackBackground; pasteMode = Roi.getCurrentPasteMode(); } void restoreSettings() { interp.getParens(); if (!saveSettingsCalled) interp.error("saveSettings() not called"); Prefs.usePointerCursor = usePointerCursor; IJ.hideProcessStackDialog = hideProcessStackDialog; FloatBlitter.divideByZeroValue = divideByZeroValue; FileSaver.setJpegQuality(jpegQuality); Line.setWidth(saveLineWidth); ImageConverter.setDoScaling(doScaling); if (weightedColor!=Prefs.weightedColor) { ColorProcessor.setWeightingFactors(weights[0], weights[1], weights[2]); Prefs.weightedColor = !(weights[0]==1d/3d && weights[1]==1d/3d && weights[2]==1d/3d); } Prefs.interpolateScaledImages = interpolateScaledImages; Prefs.open100Percent = open100Percent; Prefs.blackCanvas = blackCanvas; Prefs.useJFileChooser = useJFileChooser; Prefs.useInvertingLut = useInvertingLut; IJ.debugMode = debugMode; Toolbar.setForegroundColor(foregroundColor); Toolbar.setBackgroundColor(backgroundColor); Roi.setColor(roiColor); Analyzer.setMeasurements(measurements); Analyzer.setPrecision(decimalPlaces); ColorProcessor.setWeightingFactors(weights[0], weights[1], weights[2]); Prefs.blackBackground = blackBackground; Roi.setPasteMode(pasteMode); } void setKeyDown() { String keys = getStringArg(); keys = keys.toLowerCase(Locale.US); altKeyDown = keys.indexOf("alt")!=-1; if (altKeyDown) IJ.setKeyDown(KeyEvent.VK_ALT); else IJ.setKeyUp(KeyEvent.VK_ALT); shiftKeyDown = keys.indexOf("shift")!=-1; if (shiftKeyDown) IJ.setKeyDown(KeyEvent.VK_SHIFT); else IJ.setKeyUp(KeyEvent.VK_SHIFT); if (keys.equals("space")) IJ.setKeyDown(KeyEvent.VK_SPACE); else IJ.setKeyUp(KeyEvent.VK_SPACE); if (keys.indexOf("esc")!=-1) abortPluginOrMacro(); else interp.keysSet = true; } void abortPluginOrMacro() { Interpreter.abortPrevious(); IJ.setKeyDown(KeyEvent.VK_ESCAPE); ImagePlus imp = WindowManager.getCurrentImage(); if (imp!=null) { ImageWindow win = imp.getWindow(); if (win!=null) { win.running = false; win.running2 = false; } } //Macro.abort(); } void open() { interp.getLeftParen(); if (interp.nextToken()==')') { interp.getRightParen(); IJ.open(); } else { double n = Double.NaN; String path = getString(); if (interp.nextToken()==',') { interp.getComma(); n = interp.getExpression(); } interp.getRightParen(); if (!Double.isNaN(n)) { try { IJ.open(path, (int)n); } catch (Exception e) { String msg = e.getMessage(); if (msg!=null&&msg.indexOf("canceled")==-1) interp.error(""+msg); } } else IJ.open(path); if (path!=null&&!path.equals("")) { int index = path.lastIndexOf('/'); if (index==-1) index = path.lastIndexOf('\\'); String name = index>=0&&index<path.length()?path.substring(index+1):path; OpenDialog.setLastName(name); } } resetImage(); } double roiManager() { String cmd = getFirstString(); cmd = cmd.toLowerCase(); String path = null; String color = null; double lineWidth = 1.0; int index=0; double countOrIndex=Double.NaN; boolean twoArgCommand = cmd.equals("open")||cmd.equals("save")||cmd.equals("rename") ||cmd.equals("set color")||cmd.equals("set fill color")||cmd.equals("set line width") ||cmd.equals("associate")||cmd.equals("centered")||cmd.equals("usenames"); boolean select = cmd.equals("select"); boolean multiSelect = false; boolean add = cmd.equals("add"); if (twoArgCommand) path = getLastString(); else if (add) { if (interp.nextToken()==',') { interp.getComma(); color = interp.getString(); } if (interp.nextToken()==',') { interp.getComma(); lineWidth = interp.getExpression(); } interp.getRightParen(); } else if (select) { interp.getComma(); multiSelect = isArrayArg(); if (!multiSelect) { index = (int)interp.getExpression(); interp.getRightParen(); } } else interp.getRightParen(); if (RoiManager.getInstance()==null&&roiManager==null) { if (Interpreter.isBatchMode()) roiManager = new RoiManager(true); else IJ.run("ROI Manager..."); } RoiManager rm = roiManager!=null?roiManager:RoiManager.getInstance(); if (rm==null) interp.error("ROI Manager not found"); if (multiSelect) return setMultipleIndexes(rm); if (twoArgCommand) rm.runCommand(cmd, path); else if (add) rm.runCommand("Add", color, lineWidth); else if (select) { int n = rm.getList().getItemCount(); checkIndex(index, 0, n-1); if (shiftKeyDown || altKeyDown) { rm.select(index, shiftKeyDown, altKeyDown); shiftKeyDown = altKeyDown = false; } else rm.select(index); } else if (cmd.equals("count")) countOrIndex = rm.getList().getItemCount(); else if (cmd.equals("index")) countOrIndex = rm.getList().getSelectedIndex(); else { if (!rm.runCommand(cmd)) interp.error("Invalid ROI Manager command"); } return countOrIndex; } boolean isArrayArg() { int nextToken = pgm.code[interp.pc+1]; int tok = nextToken&0xff; if (tok==ARRAY_FUNCTION) return true; if (tok!=WORD) return false; Variable v = interp.lookupVariable(nextToken>>TOK_SHIFT); if (v==null) return false; return v.getType()==Variable.ARRAY; } double setMultipleIndexes(RoiManager rm) { if (interp.nextToken()==',') interp.getComma(); double[] indexes = getNumericArray(); interp.getRightParen(); int[] selectedIndexes = new int[indexes.length]; int count = rm.getList().getItemCount(); for (int i=0; i<indexes.length; i++) { selectedIndexes[i] = (int)indexes[i]; if (selectedIndexes[i]<0 || selectedIndexes[i]>=count) interp.error("Invalid index: "+selectedIndexes[i]); } rm.setSelectedIndexes(selectedIndexes); return Double.NaN; } void setFont() { String name = getFirstString(); int size = 0; int style = 0; if (name.equals("user")) { name = TextRoi.getFont(); size = TextRoi.getSize(); style = TextRoi.getStyle(); antialiasedText = TextRoi.isAntialiased(); interp.getRightParen(); } else { size = (int)getNextArg(); antialiasedText = false; if (interp.nextToken()==',') { String styles = getLastString().toLowerCase(); if (styles.indexOf("bold")!=-1) style += Font.BOLD; if (styles.indexOf("italic")!=-1) style += Font.ITALIC; if (styles.indexOf("anti")!=-1) antialiasedText = true; } else interp.getRightParen(); } font = new Font(name, style, size); fontSet = false; } void getMinAndMax() { Variable min = getFirstVariable(); Variable max = getLastVariable(); ImagePlus imp = getImage(); double v1 = imp.getDisplayRangeMin(); double v2 = imp.getDisplayRangeMax(); Calibration cal = imp.getCalibration(); v1 = cal.getCValue(v1); v2 = cal.getCValue(v2); min.setValue(v1); max.setValue(v2); } void selectImage() { interp.getLeftParen(); if (isStringArg()) { String title = getString(); if (!isOpen(title)) interp.error("\""+title+"\" not found"); selectImage(title); interp.getRightParen(); } else { int id = (int)interp.getExpression(); if (WindowManager.getImage(id)==null) interp.error("Image "+id+" not found"); IJ.selectWindow(id); interp.getRightParen(); } resetImage(); } void selectImage(String title) { if (Interpreter.isBatchMode()) { if (Interpreter.imageTable!=null) { for (Enumeration en=Interpreter.imageTable.elements(); en.hasMoreElements();) { ImagePlus imp = (ImagePlus)en.nextElement(); if (imp!=null) { if (imp.getTitle().equals(title)) { ImagePlus imp2 = WindowManager.getCurrentImage(); if (imp2!=null && imp2!=imp) imp2.saveRoi(); WindowManager.setTempCurrentImage(imp); return; } } } } selectWindowManagerImage(title); } else selectWindowManagerImage(title); } void notFound(String title) { interp.error(title+" not found"); } void selectWindowManagerImage(String title) { long start = System.currentTimeMillis(); while (System.currentTimeMillis()-start<4000) { // 4 sec timeout int[] wList = WindowManager.getIDList(); int len = wList!=null?wList.length:0; for (int i=0; i<len; i++) { ImagePlus imp = WindowManager.getImage(wList[i]); if (imp!=null) { if (imp.getTitle().equals(title)) { IJ.selectWindow(imp.getID()); return; } } } IJ.wait(10); } notFound(title); } void close() { interp.getParens(); ImagePlus imp = getImage(); ImageWindow win = imp.getWindow(); if (win!=null) { imp.changes = false; win.close(); } else { imp.saveRoi(); WindowManager.setTempCurrentImage(null); interp.removeBatchModeImage(imp); } resetImage(); } void setBatchMode() { boolean enterBatchMode = false; String sarg = null; interp.getLeftParen(); if (isStringArg()) sarg = getString(); else { double arg = interp.getBooleanExpression(); interp.checkBoolean(arg); enterBatchMode = arg==1.0; } interp.getRightParen(); if (!interp.isBatchMode()) interp.calledMacro = false; resetImage(); if (enterBatchMode) { // true if (interp.isBatchMode()) return; interp.setBatchMode(true); ImagePlus tmp = WindowManager.getTempCurrentImage(); if (tmp!=null) Interpreter.addBatchModeImage(tmp); return; } IJ.showProgress(0, 0); ImagePlus imp2 = WindowManager.getCurrentImage(); WindowManager.setTempCurrentImage(null); roiManager = null; if (sarg==null) { //false interp.setBatchMode(false); displayBatchModeImage(imp2); } else { Vector v = Interpreter.imageTable; if (v==null) return; interp.setBatchMode(false); for (int i=0; i<v.size(); i++) { imp2 = (ImagePlus)v.elementAt(i); if (imp2!=null) displayBatchModeImage(imp2); } } } void displayBatchModeImage(ImagePlus imp2) { if (imp2!=null) { ImageWindow win = imp2.getWindow(); if (win==null) imp2.show(); else { if (!win.isVisible()) win.show(); imp2.updateAndDraw(); } Roi roi = imp2.getRoi(); if (roi!=null) imp2.setRoi(roi); } } void setLocation() { int x = (int)getFirstArg(); int y = (int)getNextArg(); int width=0, height=0; if (interp.nextToken()==',') { width = (int)getNextArg(); height = (int)getNextArg(); } interp.getRightParen(); if (width==0&&height==0) { Frame frame = WindowManager.getFrontWindow(); if (frame!=null) frame.setLocation(x, y); } else { ImagePlus imp = getImage(); ImageWindow win = imp.getWindow(); if (win!=null) win.setLocationAndSize(x, y, width, height); } } void setSlice() { int n = (int)getArg(); ImagePlus imp = getImage(); int nSlices = imp.getStackSize(); if (n==1 && nSlices==1) return; else if (n<1 || n>nSlices) interp.error("Argument must be >=1 and <="+nSlices); else { if (imp.isHyperStack()) imp.setPosition(n); else imp.setSlice(n); } resetImage(); } void newImage() { String title = getFirstString(); String type = getNextString(); int width = (int)getNextArg(); int height = (int)getNextArg(); int depth = (int)getLastArg(); if (width<1 || height<1) interp.error("Width or height < 1"); IJ.newImage(title, type, width, height, depth); resetImage(); } void saveAs() { String format = getFirstString(); String path = null; if (interp.nextToken()==',') path = getLastString(); else interp.getRightParen(); IJ.saveAs(format, path); } double getZoom() { interp.getParens(); ImagePlus imp = getImage(); ImageCanvas ic = imp.getCanvas(); if (ic==null) {interp.error("Image not displayed"); return 0.0;} else return ic.getMagnification(); } void setAutoThreshold() { String mString = null; if (interp.nextToken()=='(') { interp.getLeftParen(); if (isStringArg()) mString = getString(); interp.getRightParen(); } ImagePlus img = getImage(); ImageProcessor ip = getProcessor(); if (ip instanceof ColorProcessor) interp.error("Non-RGB image expected"); ip.setRoi(img.getRoi()); if (mString!=null) { try { if (mString.indexOf("stack")!=-1) IJ.setAutoThreshold(img, mString); else ip.setAutoThreshold(mString); } catch (Exception e) { interp.error(""+e.getMessage()); } } else ip.setAutoThreshold(ImageProcessor.ISODATA2, ImageProcessor.RED_LUT); img.updateAndDraw(); resetImage(); } double parseDouble(String s) { if (s==null) return 0.0; s = s.trim(); if (s.indexOf(' ')!=-1) s = s.substring(0, s.indexOf(' ')); return Tools.parseDouble(s); } double parseInt() { String s = getFirstString(); int radix = 10; if (interp.nextToken()==',') { interp.getComma(); radix = (int)interp.getExpression(); if (radix<2||radix>36) radix = 10; } interp.getRightParen(); double n; try { if (radix==10) { n = parseDouble(s); if (!Double.isNaN(n)) n = Math.round(n); } else n = Integer.parseInt(s, radix); } catch (NumberFormatException e) { n = Double.NaN; } return n; } void print() { interp.inPrint = true; String s = getFirstString(); if (interp.nextToken()==',') { if (s.startsWith("[") && s.endsWith("]")) { printToWindow(s); return; } else if (s.equals("~0~")) { if (writer==null) interp.error("File not open"); String s2 = getLastString(); if (s2.endsWith("\n")) writer.print(s2); else writer.println(s2); interp.inPrint = false; return; } StringBuffer sb = new StringBuffer(s); do { sb.append(" "); sb.append(getNextString()); } while (interp.nextToken()==','); s = sb.toString(); } interp.getRightParen(); IJ.log(s); interp.inPrint = false; } void printToWindow(String s) { String title = s.substring(1, s.length()-1); String s2 = getLastString(); boolean isCommand = s2.startsWith("\\"); Frame frame = WindowManager.getFrame(title); if (frame==null) { if (isCommand) { interp.done = true; return; } else interp.error("Window not found"); } boolean isEditor = frame instanceof Editor; if (!(isEditor || frame instanceof TextWindow)) interp.error("Window is not text window"); if (isEditor) { Editor ed = (Editor)frame; ed.setIsMacroWindow(true); if (isCommand) handleEditorCommand(ed, s2); else ed.append(s2); } else { TextWindow tw = (TextWindow)frame; if (isCommand) handleTextWindowCommand(tw, s2); else tw.append(s2); } } void handleEditorCommand(Editor ed, String s) { if (s.startsWith("\\Update:")) { TextArea ta = ed.getTextArea(); ta.setText(s.substring(8, s.length())); ta.setEditable(false); } else if (s.equals("\\Close")) ed.close(); else ed.append(s); } void handleTextWindowCommand(TextWindow tw, String s) { TextPanel tp = tw.getTextPanel(); if (s.startsWith("\\Update:")) { int n = tp.getLineCount(); String s2 = s.substring(8, s.length()); if (n==0) tp.append(s2); else tp.setLine(n-1, s2); } else if (s.startsWith("\\Update")) { int cindex = s.indexOf(":"); if (cindex==-1) {tp.append(s); return;} String nstr = s.substring(7, cindex); int line = (int)Tools.parseDouble(nstr, -1); if (line<0) interp.error("Row index<0 or NaN"); int count = tp.getLineCount(); while (line>=count) { tp.append(""); count++; } String s2 = s.substring(cindex+1, s.length()); tp.setLine(line, s2); } else if (s.equals("\\Clear")) tp.clear(); else if (s.equals("\\Close")) tw.close(); else if (s.startsWith("\\Headings:")) tp.setColumnHeadings(s.substring(10)); else tp.append(s); } double isKeyDown() { double value = 0.0; String key = getStringArg().toLowerCase(Locale.US); if (key.indexOf("alt")!=-1) value = IJ.altKeyDown()==true?1.0:0.0; else if (key.indexOf("shift")!=-1) value = IJ.shiftKeyDown()==true?1.0:0.0; else if (key.indexOf("space")!=-1) value = IJ.spaceBarDown()==true?1.0:0.0; else interp.error("Invalid key"); return value; } String runMacro(boolean eval) { interp.getLeftParen(); String name = getString(); String arg = null; if (interp.nextToken()==',') { interp.getComma(); arg = getString(); } interp.getRightParen(); if (eval) { if (arg!=null && (name.equals("script")||name.equals("js"))) return (new Macro_Runner()).runJavaScript(arg, ""); else return IJ.runMacro(name, arg); } else return IJ.runMacroFile(name, arg); } void setThreshold() { double lower = getFirstArg(); double upper = getNextArg(); String mode = null; if (interp.nextToken()==',') { interp.getComma(); mode = getString(); } interp.getRightParen(); IJ.setThreshold(lower, upper, mode); resetImage(); } void drawOrFill(int type) { int x = (int)getFirstArg(); int y = (int)getNextArg(); int width = (int)getNextArg(); int height = (int)getLastArg(); ImageProcessor ip = getProcessor(); if (!colorSet) setForegroundColor(ip); switch (type) { case DRAW_RECT: ip.drawRect(x, y, width, height); break; case FILL_RECT: ip.setRoi(x, y, width, height); ip.fill(); break; case DRAW_OVAL: ip.drawOval(x, y, width, height); break; case FILL_OVAL: ip.fillOval(x, y, width, height); break; } updateAndDraw(); } double getScreenDimension(int type) { interp.getParens(); Dimension screen = IJ.getScreenSize(); if (type==SCREEN_WIDTH) return screen.width; else return screen.height; } void getStatistics(boolean calibrated) { Variable count = getFirstVariable(); Variable mean=null, min=null, max=null, std=null, hist=null; int params = AREA+MEAN+MIN_MAX; interp.getToken(); int arg = 1; while (interp.token==',') { arg++; switch (arg) { case 2: mean = getVariable(); break; case 3: min = getVariable(); break; case 4: max = getVariable(); break; case 5: std = getVariable(); params += STD_DEV; break; case 6: hist = getArrayVariable(); break; default: interp.error("')' expected"); } interp.getToken(); } if (interp.token!=')') interp.error("')' expected"); ImagePlus imp = getImage(); Calibration cal = calibrated?imp.getCalibration():null; ImageProcessor ip = getProcessor(); ImageStatistics stats = null; Roi roi = imp.getRoi(); int lineWidth = Line.getWidth(); if (roi!=null && roi.isLine() && lineWidth>1) { ImageProcessor ip2; if (roi.getType()==Roi.LINE) { ip2 = ip; Rectangle saveR = ip2.getRoi(); ip2.setRoi(roi.getPolygon()); stats = ImageStatistics.getStatistics(ip2, params, cal); ip2.setRoi(saveR); } else { ip2 = (new Straightener()).straightenLine(imp, lineWidth); stats = ImageStatistics.getStatistics(ip2, params, cal); } } else if (roi!=null && roi.isLine()) { ProfilePlot profile = new ProfilePlot(imp); double[] values = profile.getProfile(); ImageProcessor ip2 = new FloatProcessor(values.length, 1, values); if (roi instanceof Line) { Line l = (Line)roi; if ((l.y1==l.y2||l.x1==l.x2)&&l.x1==l.x1d&& l.y1==l.y1d&& l.x2==l.x2d&& l.y2==l.y2d) ip2.setRoi(0, 0, ip2.getWidth()-1, 1); } stats = ImageStatistics.getStatistics(ip2, params, cal); } else { ip.setRoi(roi); stats = ImageStatistics.getStatistics(ip, params, cal); } if (calibrated) count.setValue(stats.area); else count.setValue(stats.pixelCount); if (mean!=null) mean.setValue(stats.mean); if (min!=null) min.setValue(stats.min); if (max!=null) max.setValue(stats.max); if (std!=null) std.setValue(stats.stdDev); if (hist!=null) { boolean is16bit = !calibrated && ip instanceof ShortProcessor && stats.histogram16!=null; int[] histogram = is16bit?stats.histogram16:stats.histogram; int bins = is16bit?(int)(stats.max+1):histogram.length; Variable[] array = new Variable[bins]; int hmax = is16bit?(int)stats.max:255; for (int i=0; i<=hmax; i++) array[i] = new Variable(histogram[i]); hist.setArray(array); } } String replace() { String s1 = getFirstString(); String s2 = getNextString(); String s3 = getLastString(); if (s2.length()==1 && s3.length()==1) return s1.replace(s2.charAt(0), s3.charAt(0)); else { try { return s1.replaceAll(s2, s3); } catch (Exception e) { interp.error(""+e); return null; } } } void floodFill() { int x = (int)getFirstArg(); int y = (int)getNextArg(); boolean fourConnected = true; if (interp.nextToken()==',') { String s = getLastString(); if (s.indexOf("8")!=-1) fourConnected = false; } else interp.getRightParen(); ImageProcessor ip = getProcessor(); if (!colorSet) setForegroundColor(ip); FloodFiller ff = new FloodFiller(ip); if (fourConnected) ff.fill(x, y); else ff.fill8(x, y); updateAndDraw(); if (Recorder.record && pgm.hasVars) Recorder.record("floodFill", x, y); } void restorePreviousTool() { interp.getParens(); Toolbar tb = Toolbar.getInstance(); if (tb!=null) tb.restorePreviousTool(); } void setVoxelSize() { double width = getFirstArg(); double height = getNextArg(); double depth = getNextArg(); String unit = getLastString(); ImagePlus imp = getImage(); Calibration cal = imp.getCalibration(); cal.pixelWidth = width; cal.pixelHeight = height; cal.pixelDepth = depth; cal.setUnit(unit); imp.repaintWindow(); } void getLocationAndSize() { Variable v1 = getFirstVariable(); Variable v2 = getNextVariable(); Variable v3 = getNextVariable(); Variable v4 = getLastVariable(); ImagePlus imp = getImage(); int x=0, y=0, w=0, h=0; ImageWindow win = imp.getWindow(); if (win!=null) { Point loc = win.getLocation(); Dimension size = win.getSize(); x=loc.x; y=loc.y; w=size.width; h=size.height; } v1.setValue(x); v2.setValue(y); v3.setValue(w); v4.setValue(h); } String doDialog() { interp.getToken(); if (interp.token!='.') interp.error("'.' expected"); interp.getToken(); if (!(interp.token==WORD || interp.token==STRING_FUNCTION || interp.token==NUMERIC_FUNCTION)) interp.error("Function name expected: "); String name = interp.tokenString; try { if (name.equals("create")) { gd = new GenericDialog(getStringArg()); return null; } if (gd==null) { interp.error("No dialog created with Dialog.create()"); return null; } if (name.equals("addString")) { String label = getFirstString(); String defaultStr = getNextString(); int columns = 8; if (interp.nextToken()==',') columns = (int)getNextArg(); interp.getRightParen(); gd.addStringField(label, defaultStr, columns); } else if (name.equals("addNumber")) { int columns = 6; String units = null; String prompt = getFirstString(); double defaultNumber = getNextArg(); int decimalPlaces = (int)defaultNumber==defaultNumber?0:3; if (interp.nextToken()==',') { decimalPlaces = (int)getNextArg(); columns = (int)getNextArg(); units = getLastString(); } else interp.getRightParen(); gd.addNumericField(prompt, defaultNumber, decimalPlaces, columns, units); } else if (name.equals("addSlider")) { String label = getFirstString(); double minValue = getNextArg(); double maxValue = getNextArg(); double defaultValue = getLastArg(); gd.addSlider(label, minValue, maxValue, defaultValue); } else if (name.equals("addCheckbox")) { gd.addCheckbox(getFirstString(), getLastArg()==1?true:false); } else if (name.equals("addCheckboxGroup")) { addCheckboxGroup(gd); } else if (name.equals("addMessage")) { gd.addMessage(getStringArg()); } else if (name.equals("addHelp")) { gd.addHelp(getStringArg()); } else if (name.equals("addChoice")) { String prompt = getFirstString(); interp.getComma(); String[] choices = getStringArray(); String defaultChoice = null; if (interp.nextToken()==',') { interp.getComma(); defaultChoice = getString(); } else defaultChoice = choices[0]; interp.getRightParen(); gd.addChoice(prompt, choices, defaultChoice); } else if (name.equals("setInsets")) { gd.setInsets((int)getFirstArg(), (int)getNextArg(), (int)getLastArg()); } else if (name.equals("show")) { interp.getParens(); gd.showDialog(); if (gd.wasCanceled()) { interp.finishUp(); throw new RuntimeException(Macro.MACRO_CANCELED); } } else if (name.equals("getString")) { interp.getParens(); return gd.getNextString(); } else if (name.equals("getNumber")) { interp.getParens(); return ""+gd.getNextNumber(); } else if (name.equals("getCheckbox")) { interp.getParens(); return gd.getNextBoolean()==true?"1":"0"; } else if (name.equals("getChoice")) { interp.getParens(); return gd.getNextChoice(); } else interp.error("Unrecognized Dialog function "+name); } catch (IndexOutOfBoundsException e) { interp.error("Dialog error"); } return null; } void addCheckboxGroup(GenericDialog gd) { int rows = (int)getFirstArg(); int columns = (int)getNextArg(); interp.getComma(); String[] labels = getStringArray(); int n = labels.length; double[] dstates = getLastArray(); if (n!=dstates.length) interp.error("labels.length!=states.length"); boolean[] states = new boolean[n]; for (int i=0; i<n; i++) states[i] = dstates[i]==1.0?true:false; gd.addCheckboxGroup(rows, columns, labels, states); } void getDateAndTime() { Variable year = getFirstVariable(); Variable month = getNextVariable(); Variable dayOfWeek = getNextVariable(); Variable dayOfMonth = getNextVariable(); Variable hour = getNextVariable(); Variable minute = getNextVariable(); Variable second = getNextVariable(); Variable millisecond = getLastVariable(); Calendar date = Calendar.getInstance(); year.setValue(date.get(Calendar.YEAR)); month.setValue(date.get(Calendar.MONTH)); dayOfWeek.setValue(date.get(Calendar.DAY_OF_WEEK)-1); dayOfMonth.setValue(date.get(Calendar.DAY_OF_MONTH)); hour.setValue(date.get(Calendar.HOUR_OF_DAY)); minute.setValue(date.get(Calendar.MINUTE)); second.setValue(date.get(Calendar.SECOND)); millisecond.setValue(date.get(Calendar.MILLISECOND)); } void setMetadata() { String metadata = null; String arg1 = getFirstString(); boolean oneArg = false; if (interp.nextToken()==',') metadata = getLastString(); else interp.getRightParen(); boolean isInfo = false; if (metadata==null) { metadata = arg1; oneArg = true; if (metadata.startsWith("Info:")) { metadata = metadata.substring(5); isInfo = true; } } else isInfo = arg1.startsWith("info") || arg1.startsWith("Info"); ImagePlus imp = getImage(); if (isInfo) imp.setProperty("Info", metadata); else { if (imp.getStackSize()==1) { if (oneArg) imp.setProperty("Info", metadata); else { imp.setProperty("Label", metadata); if (!Interpreter.isBatchMode()) imp.repaintWindow(); } } else { imp.getStack().setSliceLabel(metadata, imp.getCurrentSlice()); if (!Interpreter.isBatchMode()) imp.repaintWindow(); } } } String getMetadata() { String type = "label"; boolean noArg = true; if (interp.nextToken()=='(' && interp.nextNextToken()!=')') { type = getStringArg().toLowerCase(Locale.US); noArg = false; } else interp.getParens(); ImagePlus imp = getImage(); String metadata = null; if (type.indexOf("label")!=-1) { if (imp.getStackSize()==1) { metadata = (String)imp.getProperty("Label"); if (metadata==null && noArg) metadata = (String)imp.getProperty("Info"); } else metadata = imp.getStack().getSliceLabel(imp.getCurrentSlice()); } else metadata = (String)imp.getProperty("Info"); if (metadata==null) metadata = ""; return metadata; } ImagePlus getImageArg() { ImagePlus img = null; if (isStringArg()) { String title = getString(); img = WindowManager.getImage(title); } else { int id = (int)interp.getExpression(); img = WindowManager.getImage(id); } if (img==null) interp.error("Image not found"); return img; } void imageCalculator() { String operator = getFirstString(); interp.getComma(); ImagePlus img1 = getImageArg(); interp.getComma(); ImagePlus img2 = getImageArg(); interp.getRightParen(); ImageCalculator ic = new ImageCalculator(); ic.calculate(operator, img1, img2); resetImage(); } void setRGBWeights() { double r = getFirstArg(); double g = getNextArg(); double b = getLastArg(); if (interp.rgbWeights==null) interp.rgbWeights = ColorProcessor.getWeightingFactors(); ColorProcessor.setWeightingFactors(r, g, b); } void makePolygon() { int max = 200; int[] x = new int[max]; int[] y = new int[max]; x[0] = (int)Math.round(getFirstArg()); y[0] = (int)Math.round(getNextArg()); interp.getToken(); int n = 1; while (interp.token==',' && n<max) { x[n] = (int)Math.round(interp.getExpression()); interp.getComma(); y[n] = (int)Math.round(interp.getExpression()); interp.getToken(); n++; } if (n<3) interp.error("Fewer than 3 points"); if (n==max && interp.token!=')') interp.error("More than "+max+" points"); ImagePlus imp = getImage(); Roi previousRoi = imp.getRoi(); if (shiftKeyDown||altKeyDown) imp.saveRoi(); imp.setRoi(new PolygonRoi(x, y, n, Roi.POLYGON)); Roi roi = imp.getRoi(); if (previousRoi!=null && roi!=null) updateRoi(roi); resetImage(); } void updateRoi(Roi roi) { if (shiftKeyDown || altKeyDown) roi.update(shiftKeyDown, altKeyDown); shiftKeyDown = altKeyDown = false; } String doFile() { interp.getToken(); if (interp.token!='.') interp.error("'.' expected"); interp.getToken(); if (!(interp.token==WORD || interp.token==STRING_FUNCTION || interp.token==NUMERIC_FUNCTION || interp.token==PREDEFINED_FUNCTION)) interp.error("Function name expected: "); String name = interp.tokenString; if (name.equals("open")) return openFile(); else if (name.equals("openAsString")) return openAsString(false); else if (name.equals("openAsRawString")) return openAsString(true); else if (name.equals("openUrlAsString")) return IJ.openUrlAsString(getStringArg()); else if (name.equals("openDialog")) return openDialog(); else if (name.equals("close")) return closeFile(); else if (name.equals("separator")) { interp.getParens(); return File.separator; } else if (name.equals("directory")) { interp.getParens(); String lastDir = OpenDialog.getLastDirectory(); return lastDir!=null?lastDir:""; } else if (name.equals("name")) { interp.getParens(); String lastName = OpenDialog.getLastName(); return lastName!=null?lastName:""; } else if (name.equals("nameWithoutExtension")) { interp.getParens(); return nameWithoutExtension(); } else if (name.equals("rename")) { File f1 = new File(getFirstString()); File f2 = new File(getLastString()); if (checkPath(f1) && checkPath(f2)) return f1.renameTo(f2)?"1":"0"; else return "0"; } else if (name.equals("append")) { String err = IJ.append(getFirstString(), getLastString()); if (err!=null) interp.error(err); return null; } else if (name.equals("saveString")) { String err = IJ.saveString(getFirstString(), getLastString()); if (err!=null) interp.error(err); return null; } File f = new File(getStringArg()); if (name.equals("getLength")||name.equals("length")) return ""+f.length(); else if (name.equals("getName")) return f.getName(); else if (name.equals("getAbsolutePath")) return f.getAbsolutePath(); else if (name.equals("getParent")) return f.getParent(); else if (name.equals("exists")) return f.exists()?"1":"0"; else if (name.equals("isDirectory")) return f.isDirectory()?"1":"0"; else if (name.equals("makeDirectory")||name.equals("mkdir")) { f.mkdir(); return null; } else if (name.equals("lastModified")) return ""+f.lastModified(); else if (name.equals("dateLastModified")) return (new Date(f.lastModified())).toString(); else if (name.equals("delete")) { return f.delete()?"1":"0"; } else interp.error("Unrecognized File function "+name); return null; } String nameWithoutExtension() { String name = OpenDialog.getLastName(); if (name==null) return ""; int dotIndex = name.lastIndexOf("."); if (dotIndex>=0 && (name.length()-dotIndex)<=5) name = name.substring(0, dotIndex); return name; } boolean checkPath(File f) { String path = f.getPath(); if (path.equals("0") || path.equals("NaN")) { interp.error("Invalid path"); return false; } else return true; } String openDialog() { String title = getStringArg(); OpenDialog od = new OpenDialog(title, null); String directory = od.getDirectory(); String name = od.getFileName(); if (name==null) return ""; else return directory+name; } void setSelectionName() { Roi roi = getImage().getRoi(); if (roi==null) interp.error("No selection"); else roi.setName(getStringArg()); } String selectionName() { Roi roi = getImage().getRoi(); String name = null; if (roi==null) interp.error("No selection"); else name = roi.getName(); return name!=null?name:""; } String openFile() { if (writer!=null) { interp.error("Currently, only one file can be open at a time"); return""; } String path = getFirstString(); String defaultName = null; if (interp.nextToken()==')') interp.getRightParen(); else defaultName = getLastString(); if (path.equals("") || defaultName!=null) { String title = defaultName!=null?path:"openFile"; defaultName = defaultName!=null?defaultName:"log.txt"; SaveDialog sd = new SaveDialog(title, defaultName, ".txt"); if(sd.getFileName()==null) return ""; path = sd.getDirectory()+sd.getFileName(); } else { File file = new File(path); if (file.exists() && !(path.endsWith(".txt")||path.endsWith(".java")||path.endsWith(".xls") ||path.endsWith(".ijm")||path.endsWith(".html")||path.endsWith(".htm"))) interp.error("File exists and suffix is not '.txt', '.java', etc."); } try { FileOutputStream fos = new FileOutputStream(path); BufferedOutputStream bos = new BufferedOutputStream(fos); writer = new PrintWriter(bos); } catch (IOException e) { interp.error("File open error \n\""+e.getMessage()+"\"\n"); return ""; } return "~0~"; } String openAsString(boolean raw) { int max = 5000; String path = getFirstString(); boolean specifiedMax = false; if (raw && interp.nextToken()==',') { max = (int)getNextArg(); specifiedMax = true; } interp.getRightParen(); if (path.equals("")) { OpenDialog od = new OpenDialog("Open As String", ""); String directory = od.getDirectory(); String name = od.getFileName(); if (name==null) return ""; path = directory + name; } String str = ""; File file = new File(path); if (!file.exists()) interp.error("File not found"); try { StringBuffer sb = new StringBuffer(5000); if (raw) { int len = (int)file.length(); if (max>len || (path.endsWith(".txt")&&!specifiedMax)) max = len; InputStream in = new BufferedInputStream(new FileInputStream(path)); DataInputStream dis = new DataInputStream(in); byte[] buffer = new byte[max]; dis.readFully(buffer); dis.close(); char[] buffer2 = new char[buffer.length]; for (int i=0; i<buffer.length; i++) buffer2[i] = (char)(buffer[i]&255); str = new String(buffer2); } else { BufferedReader r = new BufferedReader(new FileReader(file)); while (true) { String s=r.readLine(); if (s==null) break; else sb.append(s+"\n"); } r.close(); str = new String(sb); } } catch (Exception e) { interp.error("File open error \n\""+e.getMessage()+"\"\n"); } return str; } String closeFile() { String f = getStringArg(); if (!f.equals("~0~")) interp.error("Invalid file variable"); if (writer!=null) { writer.close(); writer = null; } return null; } // Calls a public static method with an arbitrary number // of String parameters, returning a String. // Contributed by Johannes Schindelin String call() { // get class and method name String fullName = getFirstString(); int dot = fullName.lastIndexOf('.'); if(dot<0) { interp.error("'classname.methodname' expected"); return null; } String className = fullName.substring(0,dot); String methodName = fullName.substring(dot+1); // get optional string arguments Object[] args = null; if (interp.nextToken()==',') { Vector vargs = new Vector(); do vargs.add(getNextString()); while (interp.nextToken()==','); args = vargs.toArray(); } interp.getRightParen(); if (args==null) args = new Object[0]; // get the class Class c; try { c = IJ.getClassLoader().loadClass(className); } catch(Exception ex) { interp.error("Could not load class "+className); return null; } // get method Method m; try { Class[] argClasses = null; if(args.length>0) { argClasses = new Class[args.length]; for(int i=0;i<args.length;i++) argClasses[i] = args[i].getClass(); } m = c.getMethod(methodName,argClasses); } catch(Exception ex) { m = null; } if (m==null && args.length>0) { try { Class[] argClasses = new Class[args.length]; for(int i=0;i<args.length;i++) { double value = Tools.parseDouble((String)args[i]); if (!Double.isNaN(value)) { args[i] = new Integer((int)value); argClasses[i] = int.class; } else argClasses[i] = args[i].getClass(); } m = c.getMethod(methodName,argClasses); } catch(Exception ex) { m = null; } } if (m==null) interp.error("Could not find the method "+methodName+" with "+ args.length+" parameter(s) in class "+className); try { Object obj = m.invoke(null, args); return obj!=null?obj.toString():null; } catch(InvocationTargetException e) { CharArrayWriter caw = new CharArrayWriter(); PrintWriter pw = new PrintWriter(caw); e.getCause().printStackTrace(pw); String s = caw.toString(); if (IJ.getInstance()!=null) new TextWindow("Exception", s, 400, 400); else IJ.log(s); return null; } catch(Exception e) { IJ.log("Call error ("+e+")"); return null; } } Variable[] getFontList() { interp.getParens(); String fonts[] = null; GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); fonts = ge.getAvailableFontFamilyNames(); if (fonts==null) return null; Variable[] array = new Variable[fonts.length]; for (int i=0; i<fonts.length; i++) array[i] = new Variable(0, 0.0, fonts[i]); return array; } void setOption() { String arg1 = getFirstString(); boolean state = true; if (interp.nextToken()==',') { interp.getComma(); double arg2 = interp.getBooleanExpression(); interp.checkBoolean(arg2); state = arg2==0?false:true; } interp.getRightParen(); arg1 = arg1.toLowerCase(Locale.US); if (arg1.equals("disablepopupmenu")) { ImageCanvas ic = getImage().getCanvas(); if (ic!=null) ic.disablePopupMenu(state); } else if (arg1.startsWith("show all")) { ImagePlus img = getImage(); ImageCanvas ic = img.getCanvas(); if (ic!=null) { boolean previousState = ic.getShowAllROIs(); ic.setShowAllROIs(state); if (state!=previousState) img.draw(); } } else if (arg1.equals("changes")) getImage().changes = state; else if (arg1.equals("debugmode")) IJ.debugMode = state; else if (arg1.equals("openusingplugins")) Opener.setOpenUsingPlugins(state); else if (arg1.equals("queuemacros")) pgm.queueCommands = state; else if (arg1.equals("disableundo")) Prefs.disableUndo = state; else if (arg1.startsWith("openashyper")) getImage().setOpenAsHyperStack(true); else if (arg1.startsWith("black")) Prefs.blackBackground = state; else if (arg1.startsWith("display lab")) Analyzer.setMeasurement(LABELS, state); else if (arg1.startsWith("limit to")) Analyzer.setMeasurement(LIMIT, state); else if (arg1.equals("area")) Analyzer.setMeasurement(AREA, state); else if (arg1.equals("mean")) Analyzer.setMeasurement(MEAN, state); else if (arg1.startsWith("std")) Analyzer.setMeasurement(STD_DEV, state); else if (arg1.equals("showrownumbers")) ResultsTable.getResultsTable().showRowNumbers(state); else if (arg1.startsWith("show")) Analyzer.setOption(arg1, state); else if (arg1.startsWith("bicubic")) ImageProcessor.setUseBicubic(state); else if (arg1.startsWith("wand")||arg1.indexOf("points")!=-1) Wand.setAllPoints(state); else if (arg1.startsWith("expandablearrays")) expandableArrays = state; else if (arg1.startsWith("loop")) Calibration.setLoopBackAndForth(state); else interp.error("Invalid option"); } void setMeasurementOption(String option) { } void showText() { String title = getFirstString(); String text = getLastString(); Editor ed = new Editor(); ed.setSize(350, 300); ed.create(title, text); } Variable[] newMenu() { String name = getFirstString(); interp.getComma(); String[] commands = getStringArray(); interp.getRightParen(); if (pgm.menus==null) pgm.menus = new Hashtable(); pgm.menus.put(name, commands); Variable[] commands2 = new Variable[commands.length]; for (int i=0; i<commands.length; i++) commands2[i] = new Variable(0, 0.0, commands[i]); return commands2; } void setSelectionLocation() { int x = (int)Math.round(getFirstArg()); int y = (int)Math.round(getLastArg()); ImagePlus imp = getImage(); Roi roi = imp.getRoi(); if (roi==null) interp.error("Selection required"); roi.setLocation(x, y); imp.draw(); } double is() { boolean state = false; String arg = getStringArg(); arg = arg.toLowerCase(Locale.US); if (arg.equals("locked")) state = getImage().isLocked(); else if (arg.indexOf("invert")!=-1) state = getImage().isInvertedLut(); else if (arg.indexOf("hyper")!=-1) state = getImage().isHyperStack(); else if (arg.indexOf("batch")!=-1) state = Interpreter.isBatchMode(); else if (arg.indexOf("applet")!=-1) state = IJ.getApplet()!=null; else if (arg.indexOf("virtual")!=-1) state = getImage().getStack().isVirtual(); else if (arg.indexOf("composite")!=-1) state = getImage().isComposite(); else if (arg.indexOf("caps")!=-1) state = getCapsLockState(); else if (arg.indexOf("changes")!=-1) state = getImage().changes; else if (arg.indexOf("binary")!=-1) state = getProcessor().isBinary(); else if (arg.indexOf("animated")!=-1) { ImageWindow win = getImage().getWindow(); state = win!=null && (win instanceof StackWindow) && ((StackWindow)win).getAnimate(); } else interp.error("Invalid argument"); return state?1.0:0.0; } final boolean getCapsLockState() { boolean capsDown = false; try { capsDown = Toolkit.getDefaultToolkit().getLockingKeyState(KeyEvent.VK_CAPS_LOCK); } catch(Exception e) {} return capsDown; } Variable[] getList() { String key = getStringArg(); if (key.equals("java.properties")) { Properties props = System.getProperties(); Vector v = new Vector(); for (Enumeration en=props.keys(); en.hasMoreElements();) v.addElement((String)en.nextElement()); Variable[] array = new Variable[v.size()]; for (int i=0; i<array.length; i++) array[i] = new Variable(0, 0.0, (String)v.elementAt(i)); return array; } else if (key.equals("window.titles")) { Frame[] list = WindowManager.getNonImageWindows(); Variable[] array = new Variable[list.length]; for (int i=0; i<list.length; i++) { Frame frame = list[i]; array[i] = new Variable(0, 0.0, frame.getTitle()); } return array; } else if (key.equals("threshold.methods")) { String[] list = AutoThresholder.getMethods(); Variable[] array = new Variable[list.length]; for (int i=0; i<list.length; i++) array[i] = new Variable(0, 0.0, list[i]); return array; } else { interp.error("Unvalid key"); return null; } } String doString() { interp.getToken(); if (interp.token!='.') interp.error("'.' expected"); interp.getToken(); if (interp.token!=WORD) interp.error("Function name expected: "); String name = interp.tokenString; if (name.equals("append")) return appendToBuffer(); else if (name.equals("copy")) return copyStringToClipboard(); else if (name.equals("copyResults")) return copyResults(); else if (name.equals("paste")) return getClipboardContents(); else if (name.equals("resetBuffer")) return resetBuffer(); else if (name.equals("buffer")) return getBuffer(); else interp.error("Unrecognized String function"); return null; } String appendToBuffer() { String text = getStringArg(); if (buffer==null) buffer = new StringBuffer(256); buffer.append(text); return null; } String copyStringToClipboard() { String text = getStringArg(); StringSelection ss = new StringSelection(text); java.awt.datatransfer.Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); clipboard.setContents(ss, null); return null; } String getClipboardContents() { interp.getParens(); java.awt.datatransfer.Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); Transferable data = clipboard.getContents(null); String s = null; try {s = (String)data.getTransferData(DataFlavor.stringFlavor);} catch (Exception e) {s = data.toString();} return s; } String copyResults() { interp.getParens(); if (!IJ.isResultsWindow()) interp.error("No results"); TextPanel tp = IJ.getTextPanel(); if (tp==null) return null; StringSelection ss = new StringSelection(tp.getText()); java.awt.datatransfer.Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); clipboard.setContents(ss, null); return null; } String resetBuffer() { interp.getParens(); buffer = new StringBuffer(256); return null; } String getBuffer() { interp.getParens(); if (buffer==null) buffer = new StringBuffer(256); return buffer.toString(); } void doCommand() { String arg = getStringArg(); if (arg.equals("Start Animation")) arg = "Start Animation [\\]"; IJ.doCommand(arg); } void getDimensions() { Variable width = getFirstVariable(); Variable height = getNextVariable(); Variable channels = getNextVariable(); Variable slices = getNextVariable(); Variable frames = getLastVariable(); ImagePlus imp = getImage(); int[] dim = imp.getDimensions(); width.setValue(dim[0]); height.setValue(dim[1]); channels.setValue(dim[2]); slices.setValue(dim[3]); frames.setValue(dim[4]); } public static void registerExtensions(MacroExtension extensions) { Interpreter interp = Interpreter.getInstance(); if (interp==null) { IJ.error("Macro must be running to install macro extensions"); return; } interp.pgm.extensionRegistry = new Hashtable(); ExtensionDescriptor[] descriptors = extensions.getExtensionFunctions(); for (int i=0; i<descriptors.length; ++i) interp.pgm.extensionRegistry.put(descriptors[i].name, descriptors[i]); } String doExt() { interp.getToken(); if (interp.token!='.') interp.error("'.' expected"); interp.getToken(); if (!(interp.token==WORD || interp.token==STRING_FUNCTION || interp.token==NUMERIC_FUNCTION || interp.token==PREDEFINED_FUNCTION)) interp.error("Function name expected: "); String name = interp.tokenString; if (name.equals("install")) { Object plugin = IJ.runPlugIn(getStringArg(), ""); if (plugin==null) interp.error("Plugin not found"); return null; } ExtensionDescriptor desc = null; if (pgm.extensionRegistry!=null) desc = (ExtensionDescriptor) pgm.extensionRegistry.get(name); if (desc == null) { interp.error("Unrecognized Ext function"); return null; } return desc.dispatch(this); } String exec() { String[] cmd; StringBuffer sb = new StringBuffer(256); String arg1 = getFirstString(); if (interp.nextToken()==',') { Vector v = new Vector(); v.add(arg1); do v.add(getNextString()); while (interp.nextToken()==','); cmd = new String[v.size()]; v.copyInto((String[])cmd); } else cmd = Tools.split(arg1); interp.getRightParen(); boolean openingDoc = cmd.length==2&&cmd[0].equals("open") || cmd.length==5&&cmd[3].equals("excel.exe"); if (openingDoc&&IJ.isWindows()) { String path = cmd[1]; if (path.startsWith("http://")||path.startsWith("HTTP://")) { cmd = new String[4]; cmd[2] = "start"; cmd[3] = path; } else { cmd = new String[3]; cmd[2] = path; } cmd[0] = "cmd"; cmd[1] = "/c"; } BufferedReader reader = null; try { Process p = Runtime.getRuntime().exec(cmd); if (openingDoc) return null; reader = new BufferedReader(new InputStreamReader(p.getInputStream())); String line; int count=1; while ((line=reader.readLine())!=null) { sb.append(line+"\n"); if (count++==1&&line.startsWith("Microsoft Windows")) break; // user probably ran 'cmd' without /c option } } catch (Exception e) { sb.append(e.getMessage()+"\n"); } finally { if (reader!=null) try {reader.close();} catch (IOException e) {} } return sb.toString(); } double getValue() { String key = getStringArg(); if (key.indexOf("foreground")!=-1) return Toolbar.getForegroundColor().getRGB()&0xffffff; else if (key.indexOf("background")!=-1) return Toolbar.getBackgroundColor().getRGB()&0xffffff; else if (key.equals("font.size")) { resetImage(); ImageProcessor ip = getProcessor(); setFont(ip); return ip.getFont().getSize(); } else if (key.equals("font.height")) { resetImage(); ImageProcessor ip = getProcessor(); setFont(ip); return ip.getFontMetrics().getHeight(); } else { interp.error("Invalid key"); return 0.0; } } double doStack() { interp.getToken(); if (interp.token!='.') interp.error("'.' expected"); interp.getToken(); if (interp.token!=WORD && interp.token!=PREDEFINED_FUNCTION) interp.error("Function name expected: "); String name = interp.tokenString; if (name.equals("isHyperstack")||name.equals("isHyperStack")) return getImage().isHyperStack()?1.0:0.0; else if (name.equals("getDimensions")) {getDimensions(); return Double.NaN;} ImagePlus imp = getImage(); if (name.equals("setPosition")) {setPosition(imp); return Double.NaN;} if (name.equals("getPosition")) {getPosition(imp); return Double.NaN;} Calibration cal = imp.getCalibration(); if (name.equals("getFrameRate")) {interp.getParens(); return cal.fps;} if (name.equals("setFrameRate")) {cal.fps=getArg(); return Double.NaN;} if (name.equals("getFrameInterval")) {interp.getParens(); return cal.frameInterval;} if (name.equals("setFrameInterval")) {cal.frameInterval=getArg(); return Double.NaN;} if (name.equals("setTUnit")) {cal.setTimeUnit(getStringArg()); return Double.NaN;} if (name.equals("setZUnit")) {cal.setZUnit(getStringArg()); return Double.NaN;} if (name.equals("getUnits")) {getStackUnits(cal); return Double.NaN;} if (imp.getStackSize()==1) interp.error("Stack required"); if (name.equals("setDimensions")) setDimensions(imp); else if (name.equals("setChannel")) imp.setPosition((int)getArg(), imp.getSlice(), imp.getFrame()); else if (name.equals("setSlice")) imp.setPosition(imp.getChannel(), (int)getArg(), imp.getFrame()); else if (name.equals("setFrame")) imp.setPosition(imp.getChannel(), imp.getSlice(), (int)getArg()); else if (name.equals("setDisplayMode")) setDisplayMode(imp, getStringArg()); else if (name.equals("getDisplayMode")) getDisplayMode(imp); else if (name.equals("setActiveChannels")) setActiveChannels(imp, getStringArg()); else if (name.equals("getActiveChannels")) getActiveChannels(imp); else if (name.equals("swap")) swapStackImages(imp); else if (name.equals("getStatistics")) getStackStatistics(imp, true); else interp.error("Unrecognized Stack function"); return Double.NaN; } void getStackUnits(Calibration cal) { Variable x = getFirstVariable(); Variable y = getNextVariable(); Variable z = getNextVariable(); Variable t = getNextVariable(); Variable v = getLastVariable(); x.setString(cal.getXUnit()); y.setString(cal.getYUnit()); z.setString(cal.getZUnit()); t.setString(cal.getTimeUnit()); v.setString(cal.getValueUnit()); } void getStackStatistics(ImagePlus imp, boolean calibrated) { Variable count = getFirstVariable(); Variable mean=null, min=null, max=null, std=null, hist=null; int params = AREA+MEAN+MIN_MAX; interp.getToken(); int arg = 1; while (interp.token==',') { arg++; switch (arg) { case 2: mean = getVariable(); break; case 3: min = getVariable(); break; case 4: max = getVariable(); break; case 5: std = getVariable(); params += STD_DEV; break; case 6: hist = getArrayVariable(); break; default: interp.error("')' expected"); } interp.getToken(); } if (interp.token!=')') interp.error("')' expected"); ImageStatistics stats = new StackStatistics(imp); count.setValue(stats.pixelCount); if (mean!=null) mean.setValue(stats.mean); if (min!=null) min.setValue(stats.min); if (max!=null) max.setValue(stats.max); if (std!=null) std.setValue(stats.stdDev); if (hist!=null) { int[] histogram = stats.histogram; int bins = histogram.length; Variable[] array = new Variable[bins]; int hmax = 255; for (int i=0; i<=hmax; i++) array[i] = new Variable(histogram[i]); hist.setArray(array); } } void setActiveChannels(ImagePlus imp, String channels) { if (!imp.isComposite()) interp.error("Composite image required"); boolean[] active = ((CompositeImage)imp).getActiveChannels(); for (int i=0; i<active.length; i++) { boolean b = false; if (channels.length()>i && channels.charAt(i)=='1') b = true; active[i] = b; } imp.updateAndDraw(); } void getActiveChannels(ImagePlus imp) { if (!imp.isComposite()) interp.error("Composite image required"); boolean[] active = ((CompositeImage)imp).getActiveChannels(); int n = active.length; char[] chars = new char[n]; int nChannels = imp.getNChannels(); for (int i=0; i<n; i++) { if (i<nChannels) chars[i] = active[i]?'1':'0'; else chars[i] = '0'; } Variable channels = getVariableArg(); channels.setString(new String(chars)); } void setDisplayMode(ImagePlus imp, String mode) { mode = mode.toLowerCase(Locale.US); if (!imp.isComposite()) interp.error("Composite image required"); int m = -1; if (mode.equals("composite")) m = CompositeImage.COMPOSITE; else if (mode.equals("color")) m = CompositeImage.COLOR; else if (mode.startsWith("gray")) m = CompositeImage.GRAYSCALE; if (m==-1) interp.error("Invalid mode"); ((CompositeImage)imp).setMode(m); imp.updateAndDraw(); } void swapStackImages(ImagePlus imp) { int n1 = (int)getFirstArg(); int n2 = (int)getLastArg(); ImageStack stack = imp.getStack(); int size = stack.getSize(); if (n1<1||n1>size||n2<1||n2>size) interp.error("Argument out of range"); Object pixels = stack.getPixels(n1); String label = stack.getSliceLabel(n1); stack.setPixels(stack.getPixels(n2), n1); stack.setSliceLabel(stack.getSliceLabel(n2), n1); stack.setPixels(pixels, n2); stack.setSliceLabel(label, n2); int current = imp.getCurrentSlice(); if (imp.isComposite()) { CompositeImage ci = (CompositeImage)imp; if (ci.getMode()==CompositeImage.COMPOSITE) { ci.reset(); imp.updateAndDraw(); imp.repaintWindow(); return; } } if (n1==current || n2==current) imp.setStack(null, stack); } void getDisplayMode(ImagePlus imp) { Variable v = getVariableArg(); String mode = ""; if (imp.isComposite()) mode = ((CompositeImage)imp).getModeAsString(); v.setString(mode); } void getPosition(ImagePlus imp) { Variable channel = getFirstVariable(); Variable slice = getNextVariable(); Variable frame = getLastVariable(); int c = imp.getChannel(); int z = imp.getSlice(); int t = imp.getFrame(); if (c*z*t>imp.getStackSize()) {c=1; z=imp.getCurrentSlice(); t=1;} channel.setValue(c); slice.setValue(z); frame.setValue(t); } void setPosition(ImagePlus img) { int channel = (int)getFirstArg(); int slice = (int)getNextArg(); int frame = (int)getLastArg(); if (interp.isBatchMode()) img.setPositionWithoutUpdate(channel, slice, frame); else img.setPosition(channel, slice, frame); } void setDimensions(ImagePlus img) { int c = (int)getFirstArg(); int z = (int)getNextArg(); int t = (int)getLastArg(); img.setDimensions(c, z, t); if (img.getWindow()==null) img.setOpenAsHyperStack(true); } void setTool() { interp.getLeftParen(); if (isStringArg()) { boolean ok = IJ.setTool(getString()); if (!ok) interp.error("Unrecognized tool name"); } else IJ.setTool((int)interp.getExpression()); interp.getRightParen(); } String doToString() { String s = getFirstString(); interp.getToken(); if (interp.token==',') { double value = Tools.parseDouble(s); s = IJ.d2s(value, (int)interp.getExpression()); interp.getToken(); } if (interp.token!=')') interp.error("')' expected"); return s; } double matches() { String str = getFirstString(); String regex = getLastString(); boolean matches = str.matches(regex); return matches?1.0:0.0; } void waitForUser() { if (waitForUserDialog!=null && waitForUserDialog.isVisible()) interp.error("Duplicate call"); String title = "Action Required"; String text = " Click \"OK\" to continue "; if (interp.nextToken()=='(') { title = getFirstString(); if (interp.nextToken()==',') text = getLastString(); else { text = title; title = "Action Required"; interp.getRightParen(); } } waitForUserDialog = new WaitForUserDialog(title, text); waitForUserDialog.show(); if (waitForUserDialog.escPressed()) throw new RuntimeException(Macro.MACRO_CANCELED); } void abortDialog() { if (waitForUserDialog!=null && waitForUserDialog.isVisible()) waitForUserDialog.close(); } double getStringWidth() { resetImage(); ImageProcessor ip = getProcessor(); setFont(ip); return ip.getStringWidth(getStringArg()); } String doList() { interp.getToken(); if (interp.token!='.') interp.error("'.' expected"); interp.getToken(); if (!(interp.token==WORD||interp.token==ARRAY_FUNCTION||interp.token==NUMERIC_FUNCTION)) interp.error("Function name expected: "); if (props==null) props = new Properties(); String value = null; String name = interp.tokenString; if (name.equals("get")) { value = props.getProperty(getStringArg()); value = value!=null?value:""; } else if (name.equals("getValue")) { value = props.getProperty(getStringArg()); if (value==null) interp.error("Value not found"); } else if (name.equals("set")||name.equals("add")||name.equals("put")) props.setProperty(getFirstString(), getLastString()); else if (name.equals("clear")||name.equals("reset")) { interp.getParens(); props.clear(); } else if (name.equals("setList")) setProperties(); else if (name.equals("getList")) value = getProperties(); else if (name.equals("size")||name.equals("getSize")) { interp.getParens(); value = ""+props.size(); } else if (name.equals("setMeasurements")) setMeasurements(); else if (name.equals("setCommands")) setCommands(); else interp.error("Unrecognized List function"); return value; } void setCommands() { interp.getParens(); Hashtable commands = Menus.getCommands(); props = new Properties(); for (Enumeration en=commands.keys(); en.hasMoreElements();) { String command = (String)en.nextElement(); props.setProperty(command, (String)commands.get(command)); } } void setMeasurements() { interp.getParens(); props.clear(); ImagePlus imp = getImage(); int measurements = AREA+MEAN+STD_DEV+MODE+MIN_MAX+ CENTROID+CENTER_OF_MASS+PERIMETER+RECT+ ELLIPSE+SHAPE_DESCRIPTORS+FERET+INTEGRATED_DENSITY+ MEDIAN+SKEWNESS+KURTOSIS+AREA_FRACTION; ImageStatistics stats = imp.getStatistics(measurements); ResultsTable rt = new ResultsTable(); Analyzer analyzer = new Analyzer(imp, measurements, rt); analyzer.saveResults(stats, imp.getRoi()); for (int i=0; i<=rt.getLastColumn(); i++) { if (rt.columnExists(i)) { String name = rt.getColumnHeading(i); String value = ""+rt.getValueAsDouble(i, 0); props.setProperty(name, value); } } } void setProperties() { String list = getStringArg(); props.clear(); try { InputStream is = new ByteArrayInputStream(list.getBytes("utf-8")); props.load(is); } catch(Exception e) { interp.error(""+e); } } String getProperties() { interp.getParens(); Vector v = new Vector(); for (Enumeration en=props.keys(); en.hasMoreElements();) v.addElement(en.nextElement()); String[] keys = new String[v.size()]; for (int i=0; i<keys.length; i++) keys[i] = (String)v.elementAt(i); Arrays.sort(keys); StringBuffer sb = new StringBuffer(); for (int i=0; i<keys.length; i++) { sb.append(keys[i]); sb.append("="); sb.append(props.get(keys[i])); sb.append("\n"); } return sb.toString(); } void makePoint() { int x = (int)getFirstArg(); int y = (int)getLastArg(); IJ.makePoint(x, y); resetImage(); } void makeText() { String text = getFirstString(); int x = (int)getNextArg(); int y = (int)getLastArg(); ImagePlus imp = getImage(); Font font = this.font; boolean nullFont = font==null; if (nullFont) font = imp.getProcessor().getFont(); TextRoi roi = new TextRoi(x, y, text, font); if (!nullFont) roi.setAntialiased(antialiasedText); imp.setRoi(roi); } void makeEllipse() { ImagePlus imp = getImage(); Roi previousRoi = imp.getRoi(); if (shiftKeyDown||altKeyDown) imp.saveRoi(); double x1 = getFirstArg(); double y1 = getNextArg(); double x2 = getNextArg(); double y2 = getNextArg(); double aspectRatio = getLastArg(); Roi roi = new EllipseRoi(x1,y1,x2,y2,aspectRatio); imp.setRoi(roi); if (previousRoi!=null && roi!=null) updateRoi(roi); resetImage(); } double fit() { interp.getToken(); if (interp.token!='.') interp.error("'.' expected"); interp.getToken(); if (!(interp.token==WORD||interp.token==ARRAY_FUNCTION)) interp.error("Function name expected: "); if (props==null) props = new Properties(); String name = interp.tokenString; if (name.equals("doFit")) return fitCurve(); else if (name.equals("getEquation")) return getEquation(); else if (name.equals("nEquations")) { interp.getParens(); return CurveFitter.fitList.length; } else if (name.equals("showDialog")) { showFitDialog = true; return Double.NaN; } else if (name.equals("logResults")) { logFitResults = true; return Double.NaN; } if (fitter==null) interp.error("No fit"); if (name.equals("f")) return fitter.f(fitter.getParams(), getArg()); else if (name.equals("plot")) { interp.getParens(); Fitter.plot(fitter); return Double.NaN; } else if (name.equals("nParams")) { interp.getParens(); return fitter.getNumParams(); } else if (name.equals("p")) { int index = (int)getArg(); checkIndex(index, 0, fitter.getNumParams()-1); double[] p = fitter.getParams(); return p[index]; } else if (name.equals("rSquared")) { interp.getParens(); return fitter.getRSquared(); } return Double.NaN; } double fitCurve() { interp.getLeftParen(); int fit = -1; String name = null; double[] initialValues = null; if (isStringArg()) { name = getString().toLowerCase(Locale.US); String[] list = CurveFitter.fitList; for (int i=0; i<list.length; i++) { if (name.equals(list[i].toLowerCase(Locale.US))) { fit = i; break; } } boolean isCustom = name.indexOf("y=")!=-1 || name.indexOf("y =")!=-1; if (fit==-1&&!isCustom) interp.error("Unrecognized fit"); } else fit = (int)interp.getExpression(); double[] x = getNextArray(); interp.getComma(); double[] y = getNumericArray(); if (interp.nextToken()==',') { interp.getComma(); initialValues = getNumericArray(); } interp.getRightParen(); if (x.length!=y.length) interp.error("Arrays not same length"); if (x.length==0) interp.error("Zero length array"); fitter = new CurveFitter(x, y); if (fit==-1 && name!=null) { Interpreter instance = Interpreter.getInstance(); int params = fitter.doCustomFit(name, initialValues, showFitDialog); Interpreter.instance = instance; if (params==0) interp.error("Invalid custom function"); } else fitter.doFit(fit, showFitDialog); if (logFitResults) { IJ.log(fitter.getResultString()); logFitResults = false; } showFitDialog = false; return Double.NaN; } double getEquation() { int index = (int)getFirstArg(); Variable name = getNextVariable(); Variable formula = getLastVariable(); checkIndex(index, 0, CurveFitter.fitList.length-1); name.setString(CurveFitter.fitList[index]); formula.setString(CurveFitter.fList[index]); return Double.NaN; } void setMinAndMax() { double min = getFirstArg(); double max = getNextArg(); int channels = 7; if (interp.nextToken()==',') { channels = (int)getLastArg(); if (getImage().getBitDepth()!=24) interp.error("RGB image required"); } else interp.getRightParen(); IJ.setMinAndMax(min, max, channels); resetImage(); } String debug() { String arg = "break"; if (interp.nextToken()=='(') arg = getStringArg().toLowerCase(Locale.US); else interp.getParens(); if (interp.editor==null && !(arg.equals("throw")||arg.equals("dump"))) { Editor ed = Editor.getInstance(); if (ed==null) interp.error("Macro editor not available"); else interp.setEditor(ed); } if (arg.equals("run")) interp.setDebugMode(Interpreter.RUN); else if (arg.equals("break")) interp.setDebugMode(Interpreter.STEP); else if (arg.equals("trace")) interp.setDebugMode(Interpreter.TRACE); else if (arg.indexOf("fast")!=-1) interp.setDebugMode(Interpreter.FAST_TRACE); else if (arg.equals("dump")) interp.dump(); else if (arg.indexOf("throw")!=-1) throw new IllegalArgumentException(); else interp.error("Argument must be 'run', 'break', 'trace', 'fast-trace' or 'dump'"); IJ.setKeyUp(IJ.ALL_KEYS); return null; } Variable[] doArray() { interp.getToken(); if (interp.token!='.') interp.error("'.' expected"); interp.getToken(); if (!(interp.token==WORD||interp.token==PREDEFINED_FUNCTION)) interp.error("Function name expected: "); String name = interp.tokenString; if (name.equals("copy")) return copyArray(); else if (name.equals("trim")) return trimArray(); else if (name.equals("sort")) return sortArray(); else if (name.equals("rankPositions")) return getRankPositions(); else if (name.equals("getStatistics")) return getArrayStatistics(); else if (name.equals("fill")) return fillArray(); else if (name.equals("invert")) return invertArray(); else interp.error("Unrecognized Array function"); return null; } Variable[] copyArray() { interp.getLeftParen(); Variable[] a = getArray(); interp.getRightParen(); return duplicate(a); } Variable[] duplicate(Variable[] a1) { Variable[] a2 = new Variable[a1.length]; for (int i=0; i<a1.length; i++) a2[i] = (Variable)a1[i].clone(); return a2; } Variable[] trimArray() { interp.getLeftParen(); Variable[] a1 = getArray(); int len = a1.length; int size = (int)getLastArg(); if (size<0) size = 0; if (size>len) size = len; Variable[] a2 = new Variable[size]; for (int i=0; i<size; i++) a2[i] = (Variable)a1[i].clone(); return a2; } Variable[] sortArray() { interp.getLeftParen(); Variable[] a = getArray(); interp.getRightParen(); int len = a.length; int nNumbers = 0; for (int i=0; i<len; i++) { if (a[i].getString()==null) nNumbers++; } if (nNumbers==len) { double[] d = new double[len]; for (int i=0; i<len; i++) d[i] = a[i].getValue(); Arrays.sort(d); for (int i=0; i<len; i++) a[i].setValue(d[i]); } else if (nNumbers==0) { String[] s = new String[len]; for (int i=0; i<len; i++) s[i] = a[i].getString(); //StringSorter.sort(s); Arrays.sort(s, String.CASE_INSENSITIVE_ORDER); for (int i=0; i<len; i++) a[i].setString(s[i]); } else interp.error("Mixed strings and numbers"); return a; } Variable[] getRankPositions() { interp.getLeftParen(); Variable[] a = getArray(); interp.getRightParen(); int len = a.length; int nNumbers = 0; int[] indexes = new int[len]; for (int i = 0; i < len; i++) { indexes[i] = i; if (a[i].getString()==null) nNumbers++; } if (nNumbers!=len && nNumbers!=0) { interp.error("Mixed strings and numbers"); return a; } Variable[] varArray = new Variable[len]; if (nNumbers==len) { double[] doubles = new double[len]; for (int i = 0; i < len; i++) doubles[i] = (double) (a[i].getValue()); Tools.quicksort(doubles, indexes); } else if (nNumbers==0) { String[] strings = new String[len]; for (int i = 0; i < len; i++) strings[i] = a[i].getString(); Tools.quicksort(strings, indexes); } for (int i=0; i<len; i++) varArray[i] = new Variable((double) indexes[i]); return varArray; } Variable[] getArrayStatistics() { interp.getLeftParen(); Variable[] a = getArray(); Variable minv = getNextVariable(); Variable maxv=null, mean=null, std=null; interp.getToken(); int arg = 1; while (interp.token==',') { arg++; switch (arg) { case 2: maxv = getVariable(); break; case 3: mean = getVariable(); break; case 4: std = getVariable(); break; default: interp.error("')' expected"); } interp.getToken(); } if (interp.token!=')') interp.error("')' expected"); int n = a.length; double sum=0.0, sum2=0.0, value; double min = Double.POSITIVE_INFINITY; double max = Double.NEGATIVE_INFINITY; for (int i=0; i<n; i++) { value = a[i].getValue(); sum += value; sum2 += value*value; if (value<min) min = value; if (value>max) max = value; } minv.setValue(min); if (maxv!=null) maxv.setValue(max); if (mean!=null) mean.setValue(sum/n); if (std!=null) { double stdDev = (n*sum2-sum*sum)/n; stdDev = Math.sqrt(stdDev/(n-1.0)); std.setValue(stdDev); } return a; } Variable[] fillArray() { interp.getLeftParen(); Variable[] a = getArray(); double v = getLastArg(); for (int i=0; i<a.length; i++) a[i].setValue(v); return a; } Variable[] invertArray() { interp.getLeftParen(); Variable[] a = getArray(); interp.getRightParen(); int n = a.length; for (int i=0; i<n/2; i++) { Variable temp = a[i]; a[i] = a[n-i-1]; a[n-i-1] = temp; } return a; } double charCodeAt() { String str = getFirstString(); int index = (int)getLastArg(); checkIndex(index, 0, str.length()-1); return str.charAt(index); } void doWand() { int x = (int)getFirstArg(); int y = (int)getNextArg(); double tolerance = 0.0; String mode = null; if (interp.nextToken()==',') { tolerance = getNextArg(); mode = getNextString(); } interp.getRightParen(); IJ.doWand(x, y, tolerance, mode); resetImage(); } String ijCall() { interp.getToken(); if (interp.token!='.') interp.error("'.' expected"); interp.getToken(); if (!(interp.token==WORD||interp.token==NUMERIC_FUNCTION)) interp.error("Function name expected: "); String name = interp.tokenString; if (name.equals("pad")) return IJ.pad((int)getFirstArg(), (int)getLastArg()); else if (name.equals("deleteRows")) IJ.deleteRows((int)getFirstArg(), (int)getLastArg()); else if (name.equals("log")) IJ.log(getStringArg()); else if (name.equals("freeMemory")) {interp.getParens(); return IJ.freeMemory();} else if (name.equals("currentMemory")) {interp.getParens(); return ""+IJ.currentMemory();} else if (name.equals("maxMemory")) {interp.getParens(); return ""+IJ.maxMemory();} else if (name.equals("getToolName")) {interp.getParens(); return ""+IJ.getToolName();} else if (name.equals("redirectErrorMessages")) {interp.getParens(); IJ.redirectErrorMessages(); return null;} else if (name.equals("renameResults")) IJ.renameResults(getStringArg()); else interp.error("Unrecognized IJ function name"); return null; } double overlay() { interp.getToken(); if (interp.token!='.') interp.error("'.' expected"); interp.getToken(); if (!(interp.token==WORD||interp.token==ARRAY_FUNCTION ||interp.token==PREDEFINED_FUNCTION||interp.token==USER_FUNCTION)) interp.error("Function name expected: "); String name = interp.tokenString; ImagePlus imp = getImage(); if (name.equals("lineTo")) return overlayLineTo(); else if (name.equals("moveTo")) return overlayMoveTo(); else if (name.equals("drawLine")) return overlayDrawLine(); else if (name.equals("drawRect")) return overlayDrawRectOrEllipse(imp, false); else if (name.equals("drawEllipse")) return overlayDrawRectOrEllipse(imp, true); else if (name.equals("drawString")) return overlayDrawString(imp); else if (name.equals("add")) return addDrawing(imp); else if (name.equals("show")) return showOverlay(imp); else if (name.equals("hide")) return hideOverlay(imp); else if (name.equals("remove")) return removeOverlay(imp); else if (name.equals("paste")) { interp.getParens(); if (overlayClipboard==null) interp.error("Overlay clipboard empty"); getImage().setOverlay(overlayClipboard); return Double.NaN; } Overlay overlay = imp.getOverlay(); if (overlay==null && name.equals("size")) return 0.0; if (overlay==null) interp.error("No overlay"); int size = overlay.size(); if (name.equals("size")||name.equals("getSize")) return size; else if (name.equals("copy")) { interp.getParens(); overlayClipboard = getImage().getOverlay(); return Double.NaN; } else if (name.equals("removeSelection")||name.equals("removeRoi")) { int index = (int)getArg(); checkIndex(index, 0, size-1); overlay.remove(index); imp.draw(); return Double.NaN; } else if (name.equals("setPosition")) { int n = (int)getArg(); if (size>0) overlay.get(size-1).setPosition(n); return Double.NaN; } else interp.error("Unrecognized function name"); return Double.NaN; } double overlayMoveTo() { if (overlayPath==null) overlayPath = new GeneralPath(); interp.getLeftParen(); float x = (float)interp.getExpression(); interp.getComma(); float y = (float)interp.getExpression(); interp.getRightParen(); overlayPath.moveTo(x, y); return Double.NaN; } double overlayLineTo() { if (overlayPath==null) overlayPath = new GeneralPath(); interp.getLeftParen(); float x = (float)interp.getExpression(); interp.getComma(); float y = (float)interp.getExpression(); interp.getRightParen(); overlayPath.lineTo(x, y); return Double.NaN; } double overlayDrawLine() { if (overlayPath==null) overlayPath = new GeneralPath(); interp.getLeftParen(); float x1 = (float)interp.getExpression(); interp.getComma(); float y1 = (float)interp.getExpression(); interp.getComma(); float x2 = (float)interp.getExpression(); interp.getComma(); float y2 = (float)interp.getExpression(); interp.getRightParen(); overlayPath.moveTo(x1, y1); overlayPath.lineTo(x2, y2); return Double.NaN; } double overlayDrawRectOrEllipse(ImagePlus imp, boolean ellipse) { addDrawingToOverlay(imp); float x = (float)Math.round(getFirstArg()); float y = (float)Math.round(getNextArg()); float w = (float)Math.round(getNextArg()); float h = (float)Math.round(getLastArg()); Shape shape = null; if (ellipse) shape = new Ellipse2D.Float(x, y, w, h); else shape = new Rectangle2D.Float(x, y, w, h); Roi roi = new ShapeRoi(shape); addRoi(imp, roi); return Double.NaN; } double overlayDrawString(ImagePlus imp) { addDrawingToOverlay(imp); String text = getFirstString(); int x = (int)getNextArg(); int y = (int)getLastArg(); Font font = this.font; boolean nullFont = font==null; if (nullFont) font = imp.getProcessor().getFont(); FontMetrics metrics = imp.getProcessor().getFontMetrics(); int fontHeight = metrics.getHeight(); TextRoi roi = new TextRoi(x, y-fontHeight, text, font); if (!nullFont) roi.setAntialiased(antialiasedText); addRoi(imp, roi); return Double.NaN; } double addDrawing(ImagePlus imp) { interp.getParens(); addDrawingToOverlay(imp); return Double.NaN; } void addDrawingToOverlay(ImagePlus imp) { if (overlayPath==null) return; Roi roi = new ShapeRoi(overlayPath); overlayPath = null; addRoi(imp, roi); } void addRoi(ImagePlus imp, Roi roi){ Overlay overlay = imp.getOverlay(); if (overlay==null) { if (offscreenOverlay==null) offscreenOverlay = new Overlay(); overlay = offscreenOverlay; } if (defaultColor!=null) roi.setStrokeColor(defaultColor); roi.setLineWidth(getProcessor().getLineWidth()); overlay.add(roi); } double showOverlay(ImagePlus imp) { interp.getParens(); addDrawingToOverlay(imp); if (offscreenOverlay!=null) { imp.setOverlay(offscreenOverlay); offscreenOverlay = null; } else IJ.run(imp, "Show Overlay", ""); return Double.NaN; } double hideOverlay(ImagePlus imp) { interp.getParens(); IJ.run(imp, "Hide Overlay", ""); return Double.NaN; } double removeOverlay(ImagePlus imp) { interp.getParens(); imp.setOverlay(null); offscreenOverlay = null; return Double.NaN; } final double selectionContains() { int x = (int)Math.round(getFirstArg()); int y = (int)Math.round(getLastArg()); ImagePlus imp = getImage(); Roi roi = imp.getRoi(); if (roi==null) interp.error("Selection required"); return roi.contains(x,y)?1.0:0.0; } void getDisplayedArea() { Variable x = getFirstVariable(); Variable y = getNextVariable(); Variable w = getNextVariable(); Variable h = getLastVariable(); ImagePlus imp = getImage(); ImageCanvas ic = imp.getCanvas(); if (ic==null) return; Rectangle r = ic.getSrcRect(); x.setValue(r.x); y.setValue(r.y); w.setValue(r.width); h.setValue(r.height); } void toScaled() { ImagePlus imp = getImage(); int height = imp.getHeight(); Calibration cal = imp.getCalibration(); interp.getLeftParen(); if (isArrayArg()) { Variable[] x = getArray(); interp.getComma(); Variable[] y = getArray(); interp.getRightParen(); for (int i=0; i<x.length; i++) x[i].setValue(cal.getX(x[i].getValue())); for (int i=0; i<y.length; i++) y[i].setValue(cal.getY(y[i].getValue(),height)); } else { Variable xv = getVariable(); Variable yv = null; boolean twoArgs = interp.nextToken()==','; if (twoArgs) { interp.getComma(); yv = getVariable(); } interp.getRightParen(); double x = xv.getValue(); if (twoArgs) { double y = yv.getValue(); xv.setValue(cal.getX(x)); yv.setValue(cal.getY(y,height)); } else { xv.setValue(x*cal.pixelWidth); } } } void toUnscaled() { ImagePlus imp = getImage(); int height = imp.getHeight(); Calibration cal = imp.getCalibration(); interp.getLeftParen(); if (isArrayArg()) { Variable[] x = getArray(); interp.getComma(); Variable[] y = getArray(); interp.getRightParen(); for (int i=0; i<x.length; i++) x[i].setValue(cal.getRawX(x[i].getValue())); for (int i=0; i<y.length; i++) y[i].setValue(cal.getRawY(y[i].getValue(),height)); } else { Variable xv = getVariable(); Variable yv = null; boolean twoArgs = interp.nextToken()==','; if (twoArgs) { interp.getComma(); yv = getVariable(); } interp.getRightParen(); double x = xv.getValue(); if (twoArgs) { double y = yv.getValue(); xv.setValue(cal.getRawX(x)); yv.setValue(cal.getRawY(y,height)); } else { xv.setValue(x/cal.pixelWidth); } } } } // class Functions