macro "Tilt-Correct Round-Wire Cross-Section" { /* Originally a version of "Fit_and_Draw_Overlay_Ellipse_Axes_on_Selection_v230906.ijm" stripped with the drawing component removed but with many post-processing features. v230907: Added scale bar option. Fixed interpolation options. v230911: Also logs Circle-to-ellipse required tilt. v230912: Image height limit added to default scale bar width. b: Added selection options. Uses safeSaveAndClose function. v230913: Cosmetic dialog tweaks. Saves Versatile Wand preferences and many most processing and output preferences. v230914: Simplified dialogs. b. "Tilt" replaces "AR" for menu options. F1: updated to safeSaveAndClose_v230815. v230926: Default wand setting changed for 16-bit images. Warns if there is no scale and removes scale bar option if there is not scale. a: Additional settings saved to work with rotate and scale macro. v230927: Added option to simply reapply the last tilt correction (no selections, no background removal etc.). Moved scale bar creation to function to efficiently add to 'reapply' option. v231003: Fixed missing selectionOption; F1: Replaced function: pad. F2: Updated safeSaveAndClose F3: Corrected RGB array functions */ macroL = "Tilt-Correct_Round-Wire_Cross-Section_v231003-f3.ijm"; requires("1.42i"); setBatchMode(true); /* Turn batch mode on */ getPixelSize(unit, pixelWidth, pixelHeight); imageDepth = bitDepth(); roiUsed = false; selType = selectionType; imageDir = getDir("image"); tOr = getTitle(); nameOr = stripKnownExtensionFromString(tOr); outputText = ""; storedSettings = ""; lRTimeStamp = call("ij.Prefs.get", "asc.fits.lastFit", ""); if (lRTimeStamp!="") storedSettings += "Using settings from: " + lRTimeStamp + "\n"; lRT = call("ij.Prefs.get", "asc.fits.lastImage", ""); if (lRT!="") storedSettings += "Based on image file: " + lRT + "\n"; lRPath = call("ij.Prefs.get", "asc.fits.lastPath", ""); if (lRPath!="") storedSettings += "in directory: " + lRPath + "\n"; aspectRatio = call("ij.Prefs.get", "asc.fits.aspectRatio", -1); rot = call("ij.Prefs.get", "asc.fits.majorAxisRotation", NaN); interp = call("ij.Prefs.get", "asc.tiltCorr.interp", "Bicubic"); scaleBar = call("ij.Prefs.get", "asc.tiltCorr.scaleBar", false); /* ASC message theme */ infoColor = "#006db0"; /* Honolulu blue */ instructionColor = "#798541"; /* green_dark_modern (121,133,65) AKA Wasabi */ infoWarningColor = "#ff69b4"; /* pink_modern AKA hot pink */ infoFontSize = 13; vWandOK = checkForPluginNameContains("Versatile_Wand"); if (selType<0 || selType>4){ if (roiManager("size")==1){ roiManager("Select", 0); roiUsed = true; outputText += "Selection by ROI#1\n"; } else if (roiManager("size")<1){ Dialog.create("Object selection options: " + macroL); selectionOptions = newArray("Make new selection", "Load ROI"); if (vWandOK) selectionOptions = Array.concat(selectionOptions, "Versatile Wand Selection"); if (!isNaN(rot) && aspectRatio>0 && lRTimeStamp!="") selectionOptions = Array.concat(selectionOptions, "Just reapply last tilt correction from: " + lRTimeStamp); rRows = Math.ceil(selectionOptions.length); Dialog.addRadioButtonGroup("Currently there is no selection to work with:", selectionOptions, rRows, 1, selectionOptions[0]); if (unit==" " || startsWith(unit,"pix")) Dialog.addMessage("Note: This image has no scale", infoFontSize, infoWarningColor); Dialog.show(); selectionOption = Dialog.getRadioButton(); roiText = ""; if (startsWith(selectionOption, "Make")) waitForUser("Create a selection for the ellipse fit"); else if (startsWith(selectionOption, "Versatile")){ Dialog.create("Versatile Wand Selection Options:" + macroL); if (imageDepth==16) Dialog.addSlider("Value Tolerance", 0, 65535, call("ij.Prefs.get", "asc.vWand.vTolerance16", 8000)); else Dialog.addSlider("Value Tolerance", 0, 100, call("ij.Prefs.get", "asc.vWand.vTolerance", 20)); Dialog.addSlider("Color: Gray only - Std - Ignore Brightness",0, 100, call("ij.Prefs.get", "asc.vWand.cTolerance", 0)); Dialog.addNumber("Gradient Tolerance \(0 = Off\)", call("ij.Prefs.get", "asc.vWand.gTolerance", 0), 2, 5, "Gray value/" + unit); Dialog.addRadioButtonGroup("Connectedness \(Versatile Wand\):",newArray("8-connected", "4-connected", "non-contiguous"),1,3, call("ij.Prefs.get", "asc.vWand.connectedness", "4-connected")); Dialog.addCheckbox("Include holes inside selection",true); Dialog.addMessage("Versatile Wand Instructions:\n1:\tClick on the 'OK' button below\n2:\tClick on the the round object to be tilt corrected", infoFontSize+4, instructionColor); Dialog.show(); vTolerance = Dialog.getNumber(); cTolerance = Dialog.getNumber(); gTolerance = Dialog.getNumber(); wConnect = Dialog.getRadioButton(); if (Dialog.getCheckbox) wHoles = " include"; else wHoles = ""; /* save vWand prefs */ if (imageDepth==16) call("ij.Prefs.set", "asc.vWand.vTolerance16", vTolerance); else call("ij.Prefs.set", "asc.vWand.vTolerance", vTolerance); call("ij.Prefs.set", "asc.vWand.cTolerance", cTolerance); call("ij.Prefs.set", "asc.vWand.gTolerance", gTolerance); call("ij.Prefs.set", "asc.vWand.connectedness", wConnect); selectWindow(tOr); leftButton=16; wait(50); gotClick = false; while (gotClick==false){ getCursorLoc(x, y, z, flags); if (flags&leftButton!=0) gotClick = true; } call("Versatile_Wand_Tool.doWand", x, y, vTolerance, cTolerance, gTolerance, wConnect + wHoles); waitForUser("Versatile wand check", "Are you satisfied with this spell \(an ellipse will be fitted to this selection\)?\nIf not, you could try experimenting with the wand outside of this macro"); } else if (!startsWith(selectionOption, "Just")) { roiPath = File.openDialog("Select ROI set to open"); if (File.exists(roiPath)) roiManager("Open", roiPath); if (roiManager("size")==1){ roiManager("Select", 0); } else if (roiManager("size")>1){ roiNumber = round(getNumber("Enter ROI number you want to use \(starting from 0",1)); if (roiNumber60) roiPath = substring(roiPath,0,28) + "....." + substring(roiPath,roiPath.length-28); roiText = " #1 from " + roiPath; } if (!startsWith(selectionOption, "Just")) outputText += "Selection by " + selectionOption + roiText + "\n"; } } else { selectionOption = "Existing selection"; outputText += "Using existing selection \(type " + selType + "\)\n"; } if (startsWith(selectionOption, "Just")){ setBatchMode(true); selectWindow(tOr); run("Duplicate...", "ignore"); tARC = "" + nameOr + "_TiltCorr"; rename(tARC); orBGC = Color.background; Color.setBackground("white"); run("Rotate... ", "angle=&rot grid=1 interpolation=&interp fill enlarge"); getDimensions(imageWidth, imageHeight,null,null,null); run("Scale...", "x="+1/aspectRatio+" y=1 width="+round(imageWidth/aspectRatio)+" height="+imageHeight+" interpolation=&interp fill average"); run("Auto Crop (guess background color)"); Color.setBackground(orBGC); if (scaleBar) addSimpleScaleBar(pixelWidth, "white"); setBatchMode("exit & display"); showStatus("Created aspect ratio corrected copy based on previous settings"); call("java.lang.System.gc") exit; } selType = selectionType; if (selType<0 || selType>4) exit("This macro requires an existing selection that an ellipse can fit to"); getDimensions(imageWidth, imageHeight,null,null,null); lcf = (pixelWidth + pixelHeight)/2; run("Create Mask"); /* No selection and therefore no ellipse fit */ tM = getTitle(); selectWindow(tOr); run("Fit Ellipse"); x = getValue("X raw"); y = getValue("Y raw"); D = getValue("Major raw"); d = getValue("Minor raw"); majorAxisAngle = getValue("Angle"); a = majorAxisAngle*PI/180; if ((majorAxisAngle>=270) && (majorAxisAngle<= 90)) aText = majorAxisAngle; else if ((majorAxisAngle>90) && (majorAxisAngle<=180)) aText = majorAxisAngle+180; else aText = majorAxisAngle-180; if (aText<0) aText += 180; DS = D * lcf; dS = d * lcf; fullMajorText = "Major = " + d2s(DS,-2) + " " + unit + ", " + d2s(majorAxisAngle,1) + fromCharCode(0x00B0); fullMinorText = "Minor = " + d2s(dS,-2) + " " + unit; call("ij.Prefs.set", "asc.fits.majorAxisRotation", majorAxisAngle); aspectRatio = D/d; call("ij.Prefs.set", "asc.fits.aspectRatio", aspectRatio); cirToElTilt = (180 / PI ) * acos(1 / aspectRatio); outputText += fullMajorText + ", " + fullMinorText + ", Aspect ratio = " + aspectRatio + "\nCircle-to-ellipse required tilt: " + d2s(cirToElTilt,1) + fromCharCode(0x00B0) + "\n______________\n"; Dialog.create(macroL + ": Processing and Output Options"); Dialog.addMessage(outputText, infoFontSize, infoColor); if (roiUsed) Dialog.addMessage("ROI#1 used for selection", infoFontSize, infoColor); extrasGroup = newArray("Restore selection at end", "Retain aspect corrected mask"); extrasChecks = newArray(call("ij.Prefs.get", "asc.tiltCorr.keepSelection",0), call("ij.Prefs.get", "asc.tiltCorr.createARMask",0)); if (Overlay.size>0){ extrasGroup = Array.concat(extrasGroup, "Remove the " + Overlay.size + " existing overlays?"); extrasChecks = Array.concat(extrasChecks, "true"); } Dialog.setInsets(20, 20, -10); /* (top, left, bottom) */ Dialog.addCheckboxGroup(Math.ceil(extrasGroup.length/2), 2, extrasGroup,extrasChecks); extraExtrasGroup = newArray("Tilt corrected copy: Crop to selection \(with 0.5% margin\)", "Tilt corrected copy: Fill outside", "Tilt corrected copy: Revert to original orientation","Tilt corrected copy: Rotate to line after correction \(overrides revert\)","Tilt corrected copy: NOT recommended - Enlarge minor instead of shrink major *"); extraExtrasChecks = newArray(call("ij.Prefs.get", "asc.tiltCorr.cropToMargin",1),call("ij.Prefs.get", "asc.tiltCorr.fillOutside",1),call("ij.Prefs.get", "asc.tiltCorr.revRot",0),call("ij.Prefs.get", "asc.tiltCorr.lineRot",0), 0); Dialog.setInsets(20, 20, 0); /* (top, left, bottom) */ Dialog.addCheckboxGroup(extraExtrasGroup.length,1,extraExtrasGroup,extraExtrasChecks); Dialog.setInsets(-5, 280, 0); /* (top, left, bottom) */ Dialog.addMessage("* : Requires scale correction", infoFontSize, infoWarningColor); Dialog.setInsets(5, 20, 0); /* (top, left, bottom) */ Dialog.addNumber("Tilt corrected copy: Margin", Math.ceil(0.005 * d), 0, 3, "pixels \(default 0.5% of minor axis\)"); grayChoices = newArray("white", "black", "off-white", "off-black", "light_gray", "gray", "dark_gray"); colorChoicesStd = newArray("red", "green", "blue", "cyan", "magenta", "yellow", "pink", "orange", "violet"); colorChoicesMod = newArray("garnet", "gold", "aqua_modern", "blue_accent_modern", "blue_dark_modern", "blue_modern", "blue_honolulu", "gray_modern", "green_dark_modern", "green_modern", "green_modern_accent", "green_spring_accent", "orange_modern", "pink_modern", "purple_modern", "red_n_modern", "red_modern", "tan_modern", "violet_modern", "yellow_modern"); colorChoicesNeon = newArray("jazzberry_jam", "radical_red", "wild_watermelon", "outrageous_orange", "supernova_orange", "atomic_tangerine", "neon_carrot", "sunglow", "laser_lemon", "electric_lime", "screamin'_green", "magic_mint", "blizzard_blue", "dodger_blue", "shocking_pink", "razzle_dazzle_rose", "hot_magenta"); colorChoices = Array.concat(grayChoices, colorChoicesStd, colorChoicesMod, colorChoicesNeon); Dialog.setInsets(5, 20, 0); /* (top, left, bottom) */ Dialog.addChoice("Outside fill color:", colorChoices, call("ij.Prefs.get", "asc.tiltCorr.fillColor", "white")); scalingOptions = newArray("None","Bilinear","Bicubic"); Dialog.addRadioButtonGroup("Interpolation:", scalingOptions, 1, 3, interp); Dialog.setInsets(20, 20, 0); /* (top, left, bottom) */ if (unit==" " || startsWith(unit,"pix")) Dialog.addMessage("Note: This image has no scale so there is no scale bar option", infoFontSize, infoWarningColor); else Dialog.addCheckbox("Add IJ-ScaleBar as overlay to bottom right corner \(complimentary color to fill if available\)", call("ij.Prefs.get", "asc.tiltCorr.scaleBar", false)); Dialog.addMessage("Save options:_______________"); outputOptions = newArray("Summary", "saveTIFF", "saveJPEG"); if (imageDir!="") outputChecks = newArray(1,1,1); else outputChecks = newArray(call("ij.Prefs.get", "asc.tiltCorr.textOut",1),call("ij.Prefs.get", "asc.tiltCorr.saveTIFF",0),call("ij.Prefs.get", "asc.tiltCorr.saveJPEG",0)); Dialog.setInsets(10, 20, 10); /* (top, left, bottom) */ Dialog.addCheckboxGroup(1,3,outputOptions,outputChecks); Dialog.addDirectory("Output directory:", imageDir); infoText = "The rotation and aspect correction are saved in the preferences and can be reapplied by\nthe Image>Transform> Rotate_and_Scale_Image_Using_Saved_Prefs macro"; Dialog.addMessage(infoText, infoFontSize, infoColor); Dialog.show; keepSelection = Dialog.getCheckbox(); createARMask = Dialog.getCheckbox(); if (Overlay.size>0){ if (Dialog.getCheckbox) run("Remove Overlay"); } cropToMargin = Dialog.getCheckbox(); fillOutside = Dialog.getCheckbox(); revRot = Dialog.getCheckbox(); lineRot = Dialog.getCheckbox(); if (lineRot) revRot = false; expIt = Dialog.getCheckbox(); cropMargin = Dialog.getNumber(); fillColor = Dialog.getChoice(); interp = Dialog.getRadioButton(); if (unit==" " || startsWith(unit,"pix")) scaleBar = false; else scaleBar = Dialog.getCheckbox(); textOut = Dialog.getCheckbox(); saveTIFF = Dialog.getCheckbox(); saveJPEG = Dialog.getCheckbox(); imageDir = Dialog.getString(); if (!endsWith(imageDir, File.separator) && imageDir!="") imageDir += File.separator; setBatchMode(true); /* save prefs */ call("ij.Prefs.set", "asc.tiltCorr.keepSelection", keepSelection); call("ij.Prefs.set", "asc.tiltCorr.createARMask", createARMask); call("ij.Prefs.set", "asc.tiltCorr.cropToMargin", cropToMargin); call("ij.Prefs.set", "asc.tiltCorr.fillOutside", fillOutside); call("ij.Prefs.set", "asc.tiltCorr.revRot", revRot); call("ij.Prefs.set", "asc.tiltCorr.lineRot", lineRot); call("ij.Prefs.set", "asc.tiltCorr.revRot", revRot); call("ij.Prefs.set", "asc.tiltCorr.cropMargin", cropMargin); call("ij.Prefs.set", "asc.tiltCorr.fillColor", fillColor); call("ij.Prefs.set", "asc.tiltCorr.interp", interp); call("ij.Prefs.set", "asc.tiltCorr.scaleBar", scaleBar); call("ij.Prefs.set", "asc.tiltCorr.textOut", textOut); call("ij.Prefs.set", "asc.tiltCorr.saveTIFF", saveTIFF); call("ij.Prefs.set", "asc.tiltCorr.saveJPEG", saveJPEG); /* Settings for Rotate and Scale Macro: */ call("ij.Prefs.set", "asc.fits.lastFit", getDateTimeCode()); call("ij.Prefs.set", "asc.fits.lastImage", tOr); call("ij.Prefs.set", "asc.fits.lastPath", imageDir); call("ij.Prefs.set", "asc.fits.aspectRatio", aspectRatio); call("ij.Prefs.set", "asc.fits.majorAxisRotation", majorAxisAngle); fillColHex = getHexColorFromColorName(fillColor); orBGC = Color.background; Color.setBackground("white"); if (!keepSelection) run("Select None"); /* First apply changes to Mask */ selectWindow(tM); run("Rotate... ", "angle=&majorAxisAngle grid=1 interpolation=&interp fill enlarge"); if (expIt) { run("Scale...", "x=1 y="+aspectRatio+" width="+Image.width+" height="+round(Image.height*aspectRatio)+" interpolation=&interp fill average"); run("Set Scale...", "distance=" + aspectRatio / pixelWidth + " known=1 unit=" + unit); } else run("Scale...", "x="+1/aspectRatio+" y=1 width="+round(Image.width/aspectRatio)+" height="+Image.height+" interpolation=&interp fill average"); if (revRot) run("Rotate... ", "angle="+360-majorAxisAngle+" grid=1 interpolation=&interp fill enlarge"); run("Convert to Mask"); tM = "Mask of " + nameOr + "_TiltCorr"; rename(tM); outputText = "Original filename: " + tOr + "\nDirectory: " + imageDir + "\n" + outputText; getPixelSize(unitCheck, pixelWidthCheck, pixelHeightCheck); if (pixelWidth==pixelWidthCheck && pixelHeight==pixelHeightCheck && unit==unitCheck) outputText += "No change applied to scale \(pixel width = " + pixelWidth + " " + unit + "\n"; else { warningText = "New scale: pixelWidth="+pixelWidthCheck+" pixelHeight="+pixelHeightCheck+" " + unitCheck + " \(original pixel width = " + pixelWidth + " " + unit; IJ.log(warningText); outputText += warningText + "\n"; } /* Processing of Mask finished */ selectWindow(tOr); run("Duplicate...", "ignore"); tARC = "" + nameOr + "_TiltCorr"; rename(tARC); run("Remove Overlay"); /* Now apply processing to output copy of image */ run("Rotate... ", "angle=&majorAxisAngle grid=1 interpolation=&interp fill enlarge"); if (expIt) { run("Scale...", "x=1 y="+aspectRatio+" width="+Image.width+" height="+round(Image.height*aspectRatio)+" interpolation=&interp fill average"); run("Set Scale...", "distance=" + aspectRatio / pixelWidth + " known=1 unit=" + unit); } else run("Scale...", "x="+1/aspectRatio+" y=1 width="+round(Image.width/aspectRatio)+" height="+Image.height+" interpolation=&interp fill average"); if (revRot) run("Rotate... ", "angle="+360-majorAxisAngle+" grid=1 interpolation=&interp fill enlarge"); else if (lineRot){ setTool("line"); setBatchMode("exit & display"); /* exit batch mode */ waitForUser("Draw reference line for rotation \(to horizontal\) and click on 'OK' when finished"); getLine(x1, y1, x2, y2, lineWidth); setBatchMode(true); /* Turn batch mode on */ refRotAngle = Math.toDegrees(atan2(y1-y2, x2-x1)); run("Rotate... ", "angle=&refRotAngle grid=1 interpolation=&interp fill enlarge"); rotLab = "_rot" + d2s(majorAxisAngle+refRotAngle,1); tARC += rotLab; rename(tARC); /* Now rotate Mask */ selectWindow(tM); run("Rotate... ", "angle=&refRotAngle grid=1 interpolation=&interp fill enlarge"); run("Convert to Mask"); tM += rotLab; rename(tM); selectWindow(tARC); } getSelectionFromMask(tM); if (fillOutside){ run("Make Inverse"); safeColorNameOrHexFill(fillColor); run("Make Inverse"); } if (cropToMargin){ run("Enlarge...", "enlarge=" + cropMargin + " pixel"); run("Crop"); if (!keepSelection) run("Select None"); } if (!createARMask) closeImageByTitle(tM); updateDisplay(); if (scaleBar) addSimpleScaleBar(pixelWidth, fillColor); Color.setBackground(orBGC); outputText += "Output image name: " + tARC + "\n--------------------\n"; if (textOut) File.saveString(outputText, imageDir + tARC + "_summary.txt"); if (saveJPEG) safeSaveAndClose("jpeg", imageDir, tARC, false); if (saveTIFF) safeSaveAndClose("tiff", imageDir, tARC, false); setBatchMode("exit & display"); /* exit batch mode */ //beep(); wait(200); beep(); wait(200); beep(); wait(300); beep(); showStatus("Created aspect ratio corrected copy"); call("java.lang.System.gc"); } /* ( 8(|) ( 8(|) All ASC Functions @@@@@:-) @@@@@:-)7 */ function addSimpleScaleBar(pixelWidth, backgroundColor){ sbWidth = pixelWidth * minOf(Image.width / 5, Image.height / 3); sbDP = autoCalculateDecPlacesFromValueOnly(sbWidth)+2; /* Add more dp for line labeling */ sbWidthString = d2s(sbWidth, sbDP); indexSBWidth = parseInt(substring(d2s(sbWidth, -1),indexOf(d2s(sbWidth, -1), "E")+1)); dpSB = maxOf(0,1 - indexSBWidth); sbWidth2SF = round(sbWidth/pow(10,indexSBWidth-1)); preferredSBW = newArray(10,20,25,50,75); /* Edit this list to your preferred 2 digit numbers */ sbWidth2SFC = closestValueFromArray(preferredSBW,sbWidth2SF,100); sbWidth = pow(10,indexSBWidth-1)*sbWidth2SFC; sbFontSize = maxOf(12, round((minOf(imageHeight,imageWidth))/30)); /* set minimum default font size as 12 */ sbHeight = sbWidth/2; sbThickness = 0.3 * sbFontSize; sbColor = getComplimentaryColorFromColorName(backgroundColor); /* The color does not seem to work for the scale bar */ ijScaleBarColorChoices = newArray("White", "Black", "Light Gray", "Gray", "Dark Gray", "Red", "Green", "Blue", "Yellow"); ijScaleBarHexChoices = newArray(); for (i=0; i=0) sbColor = toUpperCase(substring(ijScaleBarColorChoices[iCol],0,1)) + substring(ijScaleBarColorChoices[iCol],1); else if (backgroundColor=="white") sbColor = "Black"; /* IJ scale bar color is case sensitive */ else sbColor = "White"; run("Scale Bar...", "width=&sbWidth height=&sbHeight thickness=&sbThickness font=&sbFontSize color=&sbColor bold overlay"); } function autoCalculateDecPlacesFromValueOnly(value){ /* Note this version is different from the one used for ramp legends */ valueSci = d2s(value, -1); iExp = indexOf(valueSci, "E"); valueExp = parseInt(substring(valueSci, iExp+1)); if (valueExp>=2) dP = 0; if (valueExp<2) dP = 2-valueExp; if (valueExp<-5) dP = -1; /* Scientific Notation */ if (valueExp>=4) dP = -1; /* Scientific Notation */ return dP; } function checkForPluginNameContains(pluginNamePart) { /* v180831 1st version to check for partial names so avoid versioning problems ... v220722 Uses File.separator and adds .class v230912 This version is case insensitive and does NOT require restoreExit. NOTE: underlines are NOT converted to spaces in names */ pluginCheck = false; pluginNamePart = toLowerCase(pluginNamePart); fS = File.separator; pluginDir = getDirectory("plugins"); if (pluginDir == "") IJ.log("Failure to find any plugins!"); else { pluginFolderList = getFileList(pluginDir); subFolderList = newArray(); pluginList = newArray(); for (l=0; l=0) pluginCheck = true; } /* If not in the root try the subfolders */ if (!pluginCheck) { for (i=0; i=0) pluginCheck = true; } } } } return pluginCheck; } function closeImageByTitle(windowTitle) { /* Cannot be used with tables */ /* v181002: reselects original image at end if open v200925: uses "while" instead of if so it can also remove duplicates v230411: checks to see if any images open first. */ if(nImages>0){ oIID = getImageID(); while (isOpen(windowTitle)) { selectWindow(windowTitle); close(); } if (isOpen(oIID)) selectImage(oIID); } } function closestValueFromArray(array,value,default) { /* v190912 1st version pjl */ closest = default; proximity = abs(default-value); for (i=0; ifileSaveName.length-5) fileSaveName = substring(fileSaveName, 0, lastIndexOf(fileSaveName, ".")+1) + extension; else fileSaveName += "." + extension; } if (path!=""){ if(endsWith(path, fS)) path = substring(path, 0, path.length-1); fullPath = path + fS + fileSaveName; } else fullPath = ""; newSave = false; if (!File.exists(fullPath) && fullPath!=""){ saveAs(filetype, fullPath); if (File.exists(fullPath)) newSave = true; } if (!newSave){ Dialog.create("Options: " + functionL); if (path!=""){ Dialog.addMessage("File: " + fileSaveName + " already exists in\n" + path); Dialog.addMessage("If no changes are made below, the existing file will be overwritten"); } Dialog.addString("Change the filename?", fileSaveName, fileSaveName.length+5); if (path=="") path = File.directory; Dialog.addDirectory("Change the directory?", path); // Dialog.addChoice("Change the filetype?", filetypes, filetypes[0]); Dialog.addRadioButtonGroup("Change the filetype?", filetypes, 1, filetypes.length, filetypes[0]); Dialog.addCheckbox("Don't save file", false); Dialog.addCheckbox("Close image \(imageID: " + imageID + ") after successful save", closeImageIfSaved); Dialog.show; newFileSaveName = Dialog.getString(); newPath = Dialog.getString(); // newFiletype = Dialog.getChoice(); newFiletype = Dialog.getRadioButton(); dontSaveFile = Dialog.getCheckbox(); closeImageIfSaved = Dialog.getCheckbox(); if (!dontSaveFile){ if (!File.isDirectory(newPath)) File.makeDirectory(newPath); if (!endsWith(newPath, fS)) newPath += fS; for (i=0; i<3; i++){ if (newFiletype==filetypes[i]){ newExtension = extensions[i]; if (extension!=newExtension) newfileSaveName = replace(newFileSaveName, extension, newExtension); } } newFullPath = newPath + newFileSaveName; if (!File.exists(newFullPath) || newFullPath==fullPath) saveAs(newFiletype, newFullPath); else safeSaveAndClose(newFiletype, newPath, newFileSaveName, closeImageIfSaved); if (File.exists(newFullPath)) newSave = true; } } if (newSave && closeImageIfSaved && nImages>0){ if (getImageID()==imageID) close(); else IJ.log(functionL + ": Image ID change so fused image not closed"); } } function stripKnownExtensionFromString(string) { /* Note: Do not use on path as it may change the directory names v210924: Tries to make sure string stays as string. v211014: Adds some additional cleanup. v211025: fixes multiple 'known's issue. v211101: Added ".Ext_" removal. v211104: Restricts cleanup to end of string to reduce risk of corrupting path. v211112: Tries to fix trapped extension before channel listing. Adds xlsx extension. v220615: Tries to fix the fix for the trapped extensions ... v230504: Protects directory path if included in string. Only removes doubled spaces and lines. v230505: Unwanted dupes replaced by unusefulCombos. v230607: Quick fix for infinite loop on one of while statements. v230614: Added AVI. v230905: Better fix for infinite loop. v230914: Added BMP and "_transp" and rearranged */ fS = File.separator; string = "" + string; protectedPathEnd = lastIndexOf(string,fS)+1; if (protectedPathEnd>0){ protectedPath = substring(string,0,protectedPathEnd); string = substring(string,protectedPathEnd); } unusefulCombos = newArray("-", "_"," "); for (i=0; i=0) string = replace(string,combo,unusefulCombos[i]); } } if (lastIndexOf(string, ".")>0 || lastIndexOf(string, "_lzw")>0) { knownExts = newArray(".avi", ".csv", ".bmp", ".dsx", ".gif", ".jpg", ".jpeg", ".jp2", ".png", ".tif", ".txt", ".xlsx"); knownExts = Array.concat(knownExts,knownExts,"_transp","_lzw"); kEL = knownExts.length; for (i=0; i0){ preChan = substring(string,0,iChanLabels); postChan = substring(string,iChanLabels); while (indexOf(preChan,knownExts[i])>0){ preChan = replace(preChan,knownExts[i],""); string = preChan + postChan; } } } while (endsWith(string,knownExts[i])) string = "" + substring(string, 0, lastIndexOf(string, knownExts[i])); } } unwantedSuffixes = newArray(" ", "_","-"); for (i=0; i0){ if(!endsWith(protectedPath,fS)) protectedPath += fS; string = protectedPath + string; } return string; } =======================getRGBArrayFromColorName functions============================ function getRGBArrayFromColorName(colorName){ /* v230907: 1st version Peter J. Lee Applied Superconductivity Center v250423: Added FSU branding colors */ colors = newArray("white", 255, 255, 255); colors = Array.concat(colors, "black", 0, 0, 0); colors = Array.concat(colors, "off-white", 245, 245, 245); colors = Array.concat(colors, "off-black", 10, 10, 10); colors = Array.concat(colors, "light_gray", 200, 200, 200); colors = Array.concat(colors, "gray", 127, 127, 127); colors = Array.concat(colors, "dark_gray", 51, 51, 51); colors = Array.concat(colors, "off-black", 10, 10, 10); colors = Array.concat(colors, "light_gray", 200, 200, 200); colors = Array.concat(colors, "gray", 127, 127, 127); colors = Array.concat(colors, "dark_gray", 51, 51, 51); colors = Array.concat(colors, "red", 255, 0, 0); colors = Array.concat(colors, "green", 0, 255, 0); /* #00FF00 AKA Lime green */ colors = Array.concat(colors, "blue", 0, 0, 255); colors = Array.concat(colors, "cyan", 0, 255, 255); colors = Array.concat(colors, "yellow", 255, 255, 0); colors = Array.concat(colors, "magenta", 255, 0, 255); /* #FF00FF */ colors = Array.concat(colors, "pink", 255, 192, 203); colors = Array.concat(colors, "violet", 127, 0, 255); colors = Array.concat(colors, "orange", 255, 165, 0); colors = Array.concat(colors, "garnet", 120, 47, 64); /* #782F40 */ colors = Array.concat(colors, "gold", 206, 184, 136); /* #CEB888 */ colors = Array.concat(colors, "aqua_modern", 75, 172, 198); /* #4bacc6 AKA "Viking" aqua */ colors = Array.concat(colors, "blue_accent_modern", 79, 129, 189); /* #4f81bd */ colors = Array.concat(colors, "blue_dark_modern", 31, 73, 125); /* #1F497D */ colors = Array.concat(colors, "blue_honolulu", 0, 118, 182); /* Honolulu Blue #006db0 */ colors = Array.concat(colors, "blue_modern", 58, 93, 174); /* #3a5dae */ colors = Array.concat(colors, "gray_modern", 83, 86, 90); /* bright gray #53565A */ colors = Array.concat(colors, "green_dark_modern", 121, 133, 65); /* Wasabi #798541 */ colors = Array.concat(colors, "green_modern", 155, 187, 89); /* #9bbb59 AKA "Chelsea Cucumber" */ colors = Array.concat(colors, "green_modern_accent", 214, 228, 187); /* #D6E4BB AKA "Gin" */ colors = Array.concat(colors, "green_spring_accent", 0, 255, 102); /* #00FF66 AKA "Spring Green" */ colors = Array.concat(colors, "orange_modern", 247, 150, 70); /* #f79646 tan hide, light orange */ colors = Array.concat(colors, "pink_modern", 255, 105, 180); /* hot pink #ff69b4 */ colors = Array.concat(colors, "purple_modern", 128, 100, 162); /* blue-magenta, purple paradise #8064A2 */ colors = Array.concat(colors, "jazzberry_jam", 165, 11, 94); colors = Array.concat(colors, "red_n_modern", 227, 24, 55); colors = Array.concat(colors, "red_modern", 192, 80, 77); colors = Array.concat(colors, "tan_modern", 238, 236, 225); colors = Array.concat(colors, "violet_modern", 76, 65, 132); colors = Array.concat(colors, "yellow_modern", 247, 238, 69); /* FSU */ colors = Array.concat(colors, "garnet", 120, 47, 64); /* #782F40 */ colors = Array.concat(colors, "gold", 206, 184, 136); /* #CEB888 */ colors = Array.concat(colors, "gulf_sands", 223, 209, 167); /* #DFD1A7 */ colors = Array.concat(colors, "stadium_night", 16, 24, 32); /* #101820 */ colors = Array.concat(colors, "westcott_water", 92, 184, 178); /* #5CB8B2 */ colors = Array.concat(colors, "vault_garnet", 166, 25, 46); /* #A6192E */ colors = Array.concat(colors, "legacy_blue", 66, 85, 99); /* #425563 */ colors = Array.concat(colors, "plaza_brick", 66, 85, 99); /* #572932 */ colors = Array.concat(colors, "vault_gold", 255, 199, 44); /* #FFC72C */ /* Fluorescent Colors https://www.w3schools.com/colors/colors_crayola.asp */ colors = Array.concat(colors, "radical_red", 255, 53, 94); /* #FF355E */ colors = Array.concat(colors, "wild_watermelon", 253, 91, 120); /* #FD5B78 */ colors = Array.concat(colors, "shocking_pink", 255, 110, 255); /* #FF6EFF Ultra Pink */ colors = Array.concat(colors, "razzle_dazzle_rose", 238, 52, 210); /* #EE34D2 */ colors = Array.concat(colors, "hot_magenta", 255, 0, 204); /* #FF00CC AKA Purple Pizzazz */ colors = Array.concat(colors, "outrageous_orange", 255, 96, 55); /* #FF6037 */ colors = Array.concat(colors, "supernova_orange", 255, 191, 63); /* FFBF3F Supernova Neon Orange*/ colors = Array.concat(colors, "sunglow", 255, 204, 51); /* #FFCC33 */ colors = Array.concat(colors, "neon_carrot", 255, 153, 51); /* #FF9933 */ colors = Array.concat(colors, "atomic_tangerine", 255, 153, 102); /* #FF9966 */ colors = Array.concat(colors, "laser_lemon", 255, 255, 102); /* #FFFF66 "Unmellow Yellow" */ colors = Array.concat(colors, "electric_lime", 204, 255, 0); /* #CCFF00 */ colors = Array.concat(colors, "screamin'_green", 102, 255, 102); /* #66FF66 */ colors = Array.concat(colors, "magic_mint", 170, 240, 209); /* #AAF0D1 */ colors = Array.concat(colors, "blizzard_blue", 80, 191, 230); /* #50BFE6 Malibu */ colors = Array.concat(colors, "dodger_blue", 9, 159, 255); /* #099FFF Dodger Neon Blue */ rgbs = newArray(0, 0, 0); for (i=0; i