package ij.plugin;
import ij.*;
import ij.process.*;
import ij.gui.*;
import ij.measure.*;
import ij.util.Tools;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
public class ScaleBar implements PlugIn {
static final String[] locations = {"Upper Right", "Lower Right", "Lower Left", "Upper Left", "At Selection"};
static final int UPPER_RIGHT=0, LOWER_RIGHT=1, LOWER_LEFT=2, UPPER_LEFT=3, AT_SELECTION=4;
static final String[] colors = {"White","Black","Light Gray","Gray","Dark Gray","Red","Green","Blue","Yellow"};
static final String[] bcolors = {"None","Black","White","Dark Gray","Gray","Light Gray","Yellow","Blue","Green","Red"};
static final String[] checkboxLabels = {"Horizontal", "Vertical", "Bold Text", "Hide Text", "Serif Font", "Overlay"};
final static String SCALE_BAR = "|SB|";
private static final ScaleBarConfiguration sConfig = new ScaleBarConfiguration();
private ScaleBarConfiguration config = new ScaleBarConfiguration(sConfig);
ImagePlus imp;
ArrayList<Roi> previousScaleBar;
int hBarWidthInPixels;
int vBarHeightInPixels;
int roiX, roiY, roiWidth, roiHeight;
boolean userRoiExists;
boolean[] checkboxStates = new boolean[6];
Rectangle hBackground = new Rectangle();
Rectangle hBar = new Rectangle();
Rectangle hText = new Rectangle();
Rectangle vBackground = new Rectangle();
Rectangle vBar = new Rectangle();
Rectangle vText = new Rectangle();
public void run(String arg) {
imp = WindowManager.getCurrentImage();
if (imp == null) {
IJ.noImage();
return;
}
imp.getProcessor().snapshot();
saveAndDeleteOverlayScaleBar();
userRoiExists = parseCurrentROI();
GenericDialog dialog = askUserConfiguration(userRoiExists);
if (dialog.wasCanceled()) {
removeScalebar();
restoreOverlayScaleBar();
return;
} else if (dialog.wasOKed()) {
if (!IJ.isMacro())
persistConfiguration();
updateScalebar(!config.labelAll);
} else removeScalebar();
}
void removeScalebar() {
imp.getProcessor().reset();
imp.updateAndDraw();
Overlay overlay = imp.getOverlay();
if (overlay!=null) {
overlay.remove(SCALE_BAR);
imp.draw();
}
}
void saveAndDeleteOverlayScaleBar() {
Overlay overlay = imp.getOverlay();
if (overlay == null) return;
while (true) {
int index = overlay.getIndex(SCALE_BAR);
if (index < 0) break;
if (previousScaleBar == null)
previousScaleBar = new ArrayList<Roi>();
previousScaleBar.add(overlay.get(index));
overlay.remove(index);
}
}
void restoreOverlayScaleBar() {
if (previousScaleBar == null) return;
Overlay overlay = imp.getOverlay();
if (overlay == null) {
overlay = new Overlay();
imp.setOverlay(overlay);
}
for (Roi roi : previousScaleBar)
overlay.add(roi, SCALE_BAR);
imp.draw();
}
boolean parseCurrentROI() {
Roi roi = imp.getRoi();
if (roi == null) return false;
Rectangle r = roi.getBounds();
roiX = r.x;
roiY = r.y;
roiWidth = r.width;
roiHeight = r.height;
return true;
}
void computeDefaultBarWidth(boolean currentROIExists) {
Calibration cal = imp.getCalibration();
ImageWindow win = imp.getWindow();
double mag = (win!=null)?win.getCanvas().getMagnification():1.0;
if (mag>1.0) mag=1.0;
double pixelWidth = cal.pixelWidth;
if (pixelWidth==0.0)
pixelWidth = 1.0;
double pixelHeight = cal.pixelHeight;
if (pixelHeight==0.0)
pixelHeight = 1.0;
double imageWidth = imp.getWidth()*pixelWidth;
double imageHeight = imp.getHeight()*pixelHeight;
boolean hBarWidthChanged = false;
String options = Macro.getOptions();
if (options!=null && options.contains("width=")) {
String hBarWidthStr = Macro.getValue(options,"width","-1");
config.hBarWidth = Tools.parseDouble(hBarWidthStr,-1);
if (config.hBarWidth>0)
config.hDigits = Utils.getDigits(hBarWidthStr);
} else if (currentROIExists && roiX>=0 && roiWidth>10) {
config.hBarWidth = roiWidth*pixelWidth;
hBarWidthChanged = true;
} else if (config.hBarWidth<=0.0 || config.hBarWidth<0.01*imageWidth || config.hBarWidth>0.67*imageWidth) {
config.hBarWidth = (80.0*pixelWidth)/mag;
config.hBarWidth = Utils.round(config.hBarWidth);
if (config.hBarWidth>0.67*imageWidth)
config.hBarWidth = Utils.round(0.67*imageWidth);
else if (config.hBarWidth<0.04*imageWidth)
config.hBarWidth = Utils.round(0.04*imageWidth);
hBarWidthChanged = true;
}
boolean vBarHeightChanged = false;
if (options!=null && options.contains("height=")) {
String vBarHeightStr = Macro.getValue(options,"height","-1");
config.vBarHeight = Tools.parseDouble(vBarHeightStr,-1);
if (config.vBarHeight>0)
config.vDigits = Utils.getDigits(vBarHeightStr);
} else if (currentROIExists && roiY>=0 && roiHeight>10) {
config.vBarHeight = roiHeight*pixelHeight;
vBarHeightChanged = true;
} else if (config.vBarHeight<=0.0 || config.vBarHeight<0.01*imageHeight || config.vBarHeight>0.67*imageHeight) {
config.vBarHeight = (80.0*pixelHeight)/mag;
config.vBarHeight = Utils.round(config.vBarHeight);
if (config.vBarHeight>0.67*imageHeight)
config.vBarHeight = Utils.round(0.67*imageHeight);
else if (config.vBarHeight<0.04*imageHeight)
config.vBarHeight = Utils.round(0.04*imageHeight);
vBarHeightChanged = true;
}
if (hBarWidthChanged)
config.hDigits = Utils.getDigits(config.hBarWidth);
if (vBarHeightChanged)
config.vDigits = Utils.getDigits(config.vBarHeight);
}
GenericDialog askUserConfiguration(boolean currentROIExists) {
if (currentROIExists)
config.location = locations[AT_SELECTION];
if (IJ.isMacro()) {
config = new ScaleBarConfiguration();
config.boldText = false;
config.useOverlay = false;
}
Calibration cal = imp.getCalibration();
if (config.showHorizontal && (config.hBarWidth <= 5*cal.pixelWidth || config.hBarWidth > cal.pixelWidth*imp.getWidth()) ||
config.showVertical && (config.vBarHeight <= 5*cal.pixelHeight || config.vBarHeight > cal.pixelHeight*imp.getHeight()) ||
currentROIExists) {
computeDefaultBarWidth(currentROIExists);
}
updateScalebar(true);
boolean multipleSlices = imp.getStackSize() > 1;
GenericDialog dialog = new BarDialog(getHUnit(), getVUnit(), multipleSlices);
DialogListener dialogListener = new BarDialogListener(multipleSlices);
dialog.addDialogListener(dialogListener);
dialog.showDialog();
return dialog;
}
void persistConfiguration() {
sConfig.updateFrom(config);
}
String getHUnit() {
String hUnits = imp.getCalibration().getXUnits();
if (hUnits.equals("microns"))
hUnits = IJ.micronSymbol+"m";
return hUnits;
}
String getVUnit() {
String vUnits = imp.getCalibration().getYUnits();
if (vUnits.equals("microns"))
vUnits = IJ.micronSymbol+"m";
return vUnits;
}
Overlay createScaleBarOverlay() throws MissingRoiException {
Overlay overlay = new Overlay();
Color color = getColor();
Color bcolor = getBColor();
int fontType = config.boldText?Font.BOLD:Font.PLAIN;
String face = config.serifFont?"Serif":"SanSerif";
Font font = new Font(face, fontType, config.fontSize);
ImageProcessor ip = imp.getProcessor();
ip.setFont(font);
setElementsPositions(ip);
if (bcolor != null) {
if (config.showHorizontal) {
Roi hBackgroundRoi = new Roi(hBackground.x, hBackground.y, hBackground.width, hBackground.height);
hBackgroundRoi.setFillColor(bcolor);
overlay.add(hBackgroundRoi, SCALE_BAR);
}
if (config.showVertical) {
Roi vBackgroundRoi = new Roi(vBackground.x, vBackground.y, vBackground.width, vBackground.height);
vBackgroundRoi.setFillColor(bcolor);
overlay.add(vBackgroundRoi, SCALE_BAR);
}
}
if (config.showHorizontal) {
Roi hBarRoi = new Roi(hBar.x, hBar.y, hBar.width, hBar.height);
hBarRoi.setFillColor(color);
overlay.add(hBarRoi, SCALE_BAR);
}
if (config.showVertical) {
Roi vBarRoi = new Roi(vBar.x, vBar.y, vBar.width, vBar.height);
vBarRoi.setFillColor(color);
overlay.add(vBarRoi, SCALE_BAR);
}
if (!config.hideText) {
if (config.showHorizontal) {
TextRoi hTextRoi = new TextRoi(hText.x, hText.y, getHLabel(), font);
hTextRoi.setStrokeColor(color);
overlay.add(hTextRoi, SCALE_BAR);
}
if (config.showVertical) {
TextRoi vTextRoi = new TextRoi(vText.x, vText.y + vText.height, getVLabel(), font);
vTextRoi.setStrokeColor(color);
vTextRoi.setAngle(90.0);
overlay.add(vTextRoi, SCALE_BAR);
}
}
return overlay;
}
String getHLabel() {
return IJ.d2s(config.hBarWidth, config.hDigits) + " " + getHUnit();
}
String getVLabel() {
return IJ.d2s(config.vBarHeight, config.vDigits) + " " + getVUnit();
}
int getHBoxWidthInPixels() {
updateFont();
ImageProcessor ip = imp.getProcessor();
int hLabelWidth = config.hideText ? 0 : ip.getStringWidth(getHLabel());
int hBoxWidth = Math.max(hBarWidthInPixels, hLabelWidth);
return (config.showHorizontal ? hBoxWidth : 0);
}
int getHBoxHeightInPixels() {
int hLabelHeight = config.hideText ? 0 : config.fontSize;
int hBoxHeight = config.barThicknessInPixels + (int) (hLabelHeight * 1.25);
return (config.showHorizontal ? hBoxHeight : 0);
}
int getVBoxHeightInPixels() {
updateFont();
ImageProcessor ip = imp.getProcessor();
int vLabelHeight = config.hideText ? 0 : ip.getStringWidth(getVLabel());
int vBoxHeight = Math.max(vBarHeightInPixels, vLabelHeight);
return (config.showVertical ? vBoxHeight : 0);
}
int getVBoxWidthInPixels() {
int vLabelWidth = config.hideText ? 0 : config.fontSize;
int vBoxWidth = config.barThicknessInPixels + (int) (vLabelWidth * 1.25);
return (config.showVertical ? vBoxWidth : 0);
}
int getOuterMarginSizeInPixels() {
int imageWidth = imp.getWidth();
int imageHeight = imp.getHeight();
return (imageWidth + imageHeight) / 100;
}
int getInnerMarginSizeInPixels() {
int maxWidth = Math.max(getHBoxWidthInPixels(), getVBoxHeightInPixels());
int margin = Math.max(maxWidth/20, 2);
return config.bcolor.equals("None") ? 0 : margin;
}
void updateFont() {
int fontType = config.boldText?Font.BOLD:Font.PLAIN;
String font = config.serifFont?"Serif":"SanSerif";
ImageProcessor ip = imp.getProcessor();
ip.setFont(new Font(font, fontType, config.fontSize));
ip.setAntialiasedText(true);
}
void setBackgroundBoxesPositions(ImageProcessor ip) throws MissingRoiException {
Calibration cal = imp.getCalibration();
hBarWidthInPixels = (int)Math.round(config.hBarWidth/cal.pixelWidth);
vBarHeightInPixels = (int)Math.round(config.vBarHeight/cal.pixelHeight);
boolean hTextTop = config.showVertical && (config.location.equals(locations[UPPER_LEFT]) || config.location.equals(locations[UPPER_RIGHT]));
int imageWidth = imp.getWidth();
int imageHeight = imp.getHeight();
int hBoxWidth = getHBoxWidthInPixels();
int hBoxHeight = getHBoxHeightInPixels();
int vBoxWidth = getVBoxWidthInPixels();
int vBoxHeight = getVBoxHeightInPixels();
int outerMargin = getOuterMarginSizeInPixels();
int innerMargin = getInnerMarginSizeInPixels();
hBackground.width = innerMargin + hBoxWidth + innerMargin;
hBackground.height = innerMargin + hBoxHeight + innerMargin;
vBackground.width = innerMargin + vBoxWidth + innerMargin;
vBackground.height = innerMargin + vBoxHeight + innerMargin;
if (config.location.equals(locations[UPPER_RIGHT])) {
hBackground.x = imageWidth - outerMargin - innerMargin - vBoxWidth + (config.showVertical ? config.barThicknessInPixels : 0) - hBoxWidth - innerMargin;
hBackground.y = outerMargin;
vBackground.x = imageWidth - outerMargin - innerMargin - vBoxWidth - innerMargin;
vBackground.y = outerMargin + (hTextTop ? hBoxHeight - config.barThicknessInPixels : 0);
hBackground.width += (config.showVertical ? vBoxWidth - config.barThicknessInPixels : 0);
} else if (config.location.equals(locations[LOWER_RIGHT])) {
hBackground.x = imageWidth - outerMargin - innerMargin - vBoxWidth - hBoxWidth + (config.showVertical ? config.barThicknessInPixels : 0) - innerMargin;
hBackground.y = imageHeight - outerMargin - innerMargin - hBoxHeight - innerMargin;
vBackground.x = imageWidth - outerMargin - innerMargin - vBoxWidth - innerMargin;
vBackground.y = imageHeight - outerMargin - innerMargin - hBoxHeight + (config.showHorizontal ? config.barThicknessInPixels : 0) - vBoxHeight - innerMargin;
vBackground.height += (config.showHorizontal ? hBoxHeight - config.barThicknessInPixels : 0);
} else if (config.location.equals(locations[UPPER_LEFT])) {
hBackground.x = outerMargin + (config.showVertical ? vBackground.width - 2*innerMargin - config.barThicknessInPixels : 0);
hBackground.y = outerMargin;
vBackground.x = outerMargin;
vBackground.y = outerMargin + (hTextTop ? hBoxHeight - config.barThicknessInPixels : 0);
hBackground.width += (config.showVertical ? vBoxWidth - config.barThicknessInPixels : 0);
hBackground.x -= (config.showVertical ? vBoxWidth - config.barThicknessInPixels : 0);
} else if (config.location.equals(locations[LOWER_LEFT])) {
hBackground.x = outerMargin + (config.showVertical ? vBackground.width - 2*innerMargin - config.barThicknessInPixels : 0);
hBackground.y = imageHeight - outerMargin - innerMargin - hBoxHeight - innerMargin;
vBackground.x = outerMargin;
vBackground.y = imageHeight - outerMargin - innerMargin - hBoxHeight + (config.showHorizontal ? config.barThicknessInPixels : 0) - vBoxHeight - innerMargin;
vBackground.height += (config.showHorizontal ? hBoxHeight - config.barThicknessInPixels : 0);
} else {
if (!userRoiExists)
throw new MissingRoiException();
hBackground.x = roiX;
hBackground.y = roiY;
vBackground.x = roiX;
vBackground.y = roiY;
}
}
void setElementsPositions(ImageProcessor ip) throws MissingRoiException {
setBackgroundBoxesPositions(ip);
int hBoxWidth = getHBoxWidthInPixels();
int hBoxHeight = getHBoxHeightInPixels();
int vBoxWidth = getVBoxWidthInPixels();
int vBoxHeight = getVBoxHeightInPixels();
int innerMargin = getInnerMarginSizeInPixels();
boolean right = config.location.equals(locations[LOWER_RIGHT]) || config.location.equals(locations[UPPER_RIGHT]);
boolean upper = config.location.equals(locations[UPPER_RIGHT]) || config.location.equals(locations[UPPER_LEFT]);
boolean hTextTop = config.showVertical && upper;
hBar.x = hBackground.x + innerMargin + (hBoxWidth - hBarWidthInPixels)/2 + (config.showVertical && !right && upper ? vBoxWidth - config.barThicknessInPixels : 0);
hBar.y = hBackground.y + innerMargin + (hTextTop ? hBoxHeight - config.barThicknessInPixels : 0);
hBar.width = hBarWidthInPixels;
hBar.height = config.barThicknessInPixels;
hText.height = config.hideText ? 0 : config.fontSize;
hText.width = config.hideText ? 0 : ip.getStringWidth(getHLabel());
hText.x = hBackground.x + innerMargin + (hBoxWidth - hText.width)/2 + (config.showVertical && !right && upper ? vBoxWidth - config.barThicknessInPixels : 0);
hText.y = hTextTop ? (hBackground.y + innerMargin - (int)Math.round(config.fontSize*0.25)) : (hBar.y + hBar.height);
vBar.width = config.barThicknessInPixels;
vBar.height = vBarHeightInPixels;
vBar.x = vBackground.x + (right ? innerMargin : vBackground.width - config.barThicknessInPixels - innerMargin);
vBar.y = vBackground.y + innerMargin + (vBoxHeight - vBar.height)/2;
vText.height = config.hideText ? 0 : ip.getStringWidth(getVLabel());
vText.width = config.hideText ? 0 : config.fontSize;
vText.x = right ? (vBar.x + vBar.width) : (vBar.x - vBoxWidth + config.barThicknessInPixels - (int)Math.round(config.fontSize*0.25));
vText.y = vBackground.y + innerMargin + (vBoxHeight - vText.height)/2;
}
Color getColor() {
Color c = Color.black;
if (config.color.equals(colors[0])) c = Color.white;
else if (config.color.equals(colors[2])) c = Color.lightGray;
else if (config.color.equals(colors[3])) c = Color.gray;
else if (config.color.equals(colors[4])) c = Color.darkGray;
else if (config.color.equals(colors[5])) c = Color.red;
else if (config.color.equals(colors[6])) c = Color.green;
else if (config.color.equals(colors[7])) c = Color.blue;
else if (config.color.equals(colors[8])) c = Color.yellow;
return c;
}
Color getBColor() {
if (config.bcolor==null || config.bcolor.equals(bcolors[0])) return null;
Color bc = Color.white;
if (config.bcolor.equals(bcolors[1])) bc = Color.black;
else if (config.bcolor.equals(bcolors[3])) bc = Color.darkGray;
else if (config.bcolor.equals(bcolors[4])) bc = Color.gray;
else if (config.bcolor.equals(bcolors[5])) bc = Color.lightGray;
else if (config.bcolor.equals(bcolors[6])) bc = Color.yellow;
else if (config.bcolor.equals(bcolors[7])) bc = Color.blue;
else if (config.bcolor.equals(bcolors[8])) bc = Color.green;
else if (config.bcolor.equals(bcolors[9])) bc = Color.red;
return bc;
}
void updateScalebar(boolean previewOnly) {
removeScalebar();
Overlay scaleBarOverlay;
try {
scaleBarOverlay = createScaleBarOverlay();
} catch (MissingRoiException e) {
return; }
Overlay impOverlay = imp.getOverlay();
if (impOverlay==null) {
impOverlay = new Overlay();
}
if (config.useOverlay) {
for (Roi roi : scaleBarOverlay)
impOverlay.add(roi);
imp.setOverlay(impOverlay);
} else {
if (previewOnly) {
ImageProcessor ip = imp.getProcessor();
drawOverlayOnProcessor(scaleBarOverlay, ip);
imp.updateAndDraw();
} else {
ImageStack stack = imp.getStack();
for (int i=1; i<=stack.size(); i++) {
ImageProcessor ip = stack.getProcessor(i);
drawOverlayOnProcessor(scaleBarOverlay, ip);
imp.updateAndDraw();
}
imp.setStack(stack);
}
}
}
void drawOverlayOnProcessor(Overlay overlay, ImageProcessor processor) {
if (processor.getBitDepth() == 8 || processor.getBitDepth() == 24) {
processor.drawOverlay(overlay);
return;
}
ImageProcessor ip = new ByteProcessor(imp.getWidth(), imp.getHeight());
ip.setCalibrationTable(processor.getCalibrationTable());
LUT lut = ip.getLut();
for (Roi roi : overlay) {
Color fillColor = roi.getFillColor();
if (fillColor != null) {
int i = processor.getBestIndex(fillColor);
roi.setFillColor(new Color(lut.getRed(i), lut.getGreen(i), lut.getBlue(i)));
if (roi.getFillColor().equals(Color.BLACK)) roi.setFillColor(new Color(1, 1, 1));
}
Color strokeColor = roi.getStrokeColor();
if (strokeColor != null) {
int i = processor.getBestIndex(strokeColor);
roi.setStrokeColor(new Color(lut.getRed(i), lut.getGreen(i), lut.getBlue(i)));
if (roi.getStrokeColor().equals(Color.BLACK)) roi.setStrokeColor(new Color(1, 1, 1));
}
}
ip.drawOverlay(overlay);
for (int y = 0; y < ip.getHeight(); y++)
for (int x = 0; x < ip.getWidth(); x++) {
int p = ip.get(x, y);
if (p > 0) {
p = (int)Math.round(p * ((processor.getMax() - processor.getMin()) / 255d) + (float)processor.getMin());
if (processor.getBitDepth() == 32)
p = Float.floatToIntBits(p);
processor.putPixel(x, y, p);
}
}
}
class BarDialog extends GenericDialog {
BarDialog(String hUnits, String vUnits, boolean multipleSlices) {
super("Scale Bar");
if (config.hDigits>7) config.hDigits=4;
if (config.vDigits>7) config.vDigits=4;
addNumericField("Width in "+hUnits+": ", config.hBarWidth, config.hDigits);
addNumericField("Height in "+vUnits+": ", config.vBarHeight, config.vDigits);
addNumericField("Thickness in pixels: ", config.barThicknessInPixels, 0);
addNumericField("Font size: ", config.fontSize, 0);
addChoice("Color: ", colors, config.color);
addChoice("Background: ", bcolors, config.bcolor);
addChoice("Location: ", locations, config.location);
checkboxStates[0] = config.showHorizontal; checkboxStates[1] = config.showVertical;
checkboxStates[2] = config.boldText; checkboxStates[3] = config.hideText;
checkboxStates[4] = config.serifFont; checkboxStates[5] = config.useOverlay;
setInsets(10, 25, 0);
addCheckboxGroup(3, 2, checkboxLabels, checkboxStates);
if (multipleSlices) {
setInsets(0, 25, 0);
addCheckbox("Label all slices", config.labelAll);
}
if (previousScaleBar != null)
enableYesNoCancel("OK", "Remove Scale Bar");
}
}
class BarDialogListener implements DialogListener {
boolean multipleSlices;
public BarDialogListener(boolean multipleSlices) {
super();
this.multipleSlices = multipleSlices;
}
@Override
public boolean dialogItemChanged(GenericDialog gd, AWTEvent e) {
config.hBarWidth = gd.getNextNumber();
config.vBarHeight = gd.getNextNumber();
config.barThicknessInPixels = (int)gd.getNextNumber();
config.fontSize = (int)gd.getNextNumber();
config.color = gd.getNextChoice();
config.bcolor = bcolors[gd.getNextChoiceIndex()];
if (imp!=null && imp.getRoi()!=null)
config.location = gd.getNextChoice(); else
config.location = locations[gd.getNextChoiceIndex()];
config.showHorizontal = gd.getNextBoolean();
config.showVertical = gd.getNextBoolean();
config.boldText = gd.getNextBoolean();
config.hideText = gd.getNextBoolean();
config.serifFont = gd.getNextBoolean();
config.useOverlay = gd.getNextBoolean();
if (imp.isComposite())
config.useOverlay = true;
if (multipleSlices)
config.labelAll = gd.getNextBoolean();
if (!config.showHorizontal && !config.showVertical && IJ.isMacro()) {
config.showHorizontal = true;
String options = Macro.getOptions();
if ((int)config.vBarHeight!=50 && options!=null&&options.contains("height=")&&!options.contains("thickness="))
config.barThicknessInPixels = (int)config.vBarHeight;
config.vBarHeight = 0.0;
}
Vector numericFields = gd.getNumericFields();
if (numericFields!=null) {
String widthString = ((TextField) numericFields.elementAt(0)).getText();
config.hDigits = Utils.getDigits(widthString);
String heightString = ((TextField) numericFields.elementAt(1)).getText();
config.vDigits = Utils.getDigits(heightString);
}
updateScalebar(true);
return true;
}
}
class MissingRoiException extends Exception {
MissingRoiException() {
super("Scalebar location is set to AT_SELECTION but there is no selection on the image.");
}
}
static class ScaleBarConfiguration {
private static int defaultBarHeight = 4;
boolean showHorizontal;
boolean showVertical;
double hBarWidth;
double vBarHeight;
int hDigits; int vDigits;
int barThicknessInPixels;
String location;
String color;
String bcolor;
boolean boldText;
boolean hideText;
boolean serifFont;
boolean useOverlay;
int fontSize;
boolean labelAll;
ScaleBarConfiguration() {
this.showHorizontal = true;
this.showVertical = false;
this.hBarWidth = -1;
this.vBarHeight = -1;
this.barThicknessInPixels = defaultBarHeight;
this.location = locations[LOWER_RIGHT];
this.color = colors[0];
this.bcolor = bcolors[0];
this.boldText = true;
this.hideText = false;
this.serifFont = false;
this.useOverlay = true;
this.fontSize = 14;
this.labelAll = false;
}
ScaleBarConfiguration(ScaleBarConfiguration model) {
this.updateFrom(model);
}
void updateFrom(ScaleBarConfiguration model) {
this.showHorizontal = model.showHorizontal;
this.showVertical = model.showVertical;
this.hBarWidth = model.hBarWidth;
this.vBarHeight = model.vBarHeight;
this.hDigits = model.hDigits;
this.vDigits = model.vDigits;
this.barThicknessInPixels = model.barThicknessInPixels;
this.location = locations[LOWER_RIGHT];
this.color = model.color;
this.bcolor = model.bcolor;
this.boldText = model.boldText;
this.serifFont = model.serifFont;
this.hideText = model.hideText;
this.useOverlay = model.useOverlay;
this.fontSize = model.fontSize;
this.labelAll = model.labelAll;
}
}
static class Utils {
static int getDigits(double x) {
if (Math.abs(x) > 1000000 || Math.abs(x) < 1e-4)
return getDigits(IJ.d2s(x, -9).replaceAll("0+E", "E")); else
return getDigits(IJ.d2s(x, 9).replaceAll("0+\\z", "")); }
static int getDigits(String str) {
boolean hasDecimalPoint = false;
boolean scientificFormat = false;
int totalDigits = 0;
int decimalDigits = 0;
for (int i = 0; i < str.length(); i++) {
char c = str.charAt(i);
if (c == '.') {
hasDecimalPoint = true;
} else if (c == 'e' || c == 'E') {
scientificFormat = true;
break;
} else if (c >= '0' && c <= '9') {
totalDigits++;
if (hasDecimalPoint)
decimalDigits++;
}
}
if (scientificFormat) {
int digits = -(totalDigits-1);
if (digits == 0) digits = -1;
return digits;
} else {
return decimalDigits;
}
}
static double round(double x) {
double base = Math.pow(10, Math.floor(Math.log10(x)+1e-8));
if (x > 4.999999*base) return 5*base;
else if (x > 1.999999*base) return 2*base;
else return base;
}
} }