ij.plugin.tool.BrushTool Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of ij Show documentation
Show all versions of ij Show documentation
ImageJ is an open source Java image processing program inspired by NIH Image for the Macintosh.
package ij.plugin.tool;
import ij.*;
import ij.process.*;
import ij.gui.*;
import ij.plugin.Colors;
import java.awt.*;
import java.awt.event.*;
import java.util.Vector;
// Versions
// 2012-07-22 shift to confine horizontally or vertically, ctrl-shift to resize, ctrl to pick
/** This class implements the Paintbrush Tool, which allows the user to draw on
an image, or on an Overlay if "Paint on overlay" is enabled. */
public class BrushTool extends PlugInTool implements Runnable {
private final static int UNCONSTRAINED=0, HORIZONTAL=1, VERTICAL=2, RESIZING=3, RESIZED=4, IDLE=5; //mode flags
private static String BRUSH_WIDTH_KEY = "brush.width";
private static String PENCIL_WIDTH_KEY = "pencil.width";
private static String CIRCLE_NAME = "brush-tool-overlay";
private static final String LOC_KEY = "brush.loc";
private static final String OVERLAY_KEY = "brush.overlay";
private String widthKey;
private int width;
private ImageProcessor ip;
private int mode; //resizing brush or motion constrained horizontally or vertically
private int xStart, yStart;
private int oldWidth;
private boolean isPencil;
private Overlay overlay;
private Options options;
private GenericDialog gd;
private ImageRoi overlayImage;
private boolean paintOnOverlay;
private static BrushTool brushInstance;
public void run(String arg) {
isPencil = "pencil".equals(arg);
widthKey = isPencil ? PENCIL_WIDTH_KEY : BRUSH_WIDTH_KEY;
width = (int)Prefs.get(widthKey, isPencil ? 1 : 5);
paintOnOverlay = Prefs.get(OVERLAY_KEY, false);
Toolbar.addPlugInTool(this);
if (!isPencil)
brushInstance = this;
}
public void mousePressed(ImagePlus imp, MouseEvent e) {
ImageCanvas ic = imp.getCanvas();
int x = ic.offScreenX(e.getX());
int y = ic.offScreenY(e.getY());
xStart = x;
yStart = y;
checkForOverlay(imp);
if (overlayImage!=null)
ip = overlayImage.getProcessor();
else
ip = imp.getProcessor();
int ctrlMask = IJ.isMacintosh() ? InputEvent.META_MASK : InputEvent.CTRL_MASK;
int resizeMask = InputEvent.SHIFT_MASK | ctrlMask;
if ((e.getModifiers() & resizeMask) == resizeMask) {
mode = RESIZING;
oldWidth = width;
return;
} else if ((e.getModifiers() & ctrlMask) != 0) {
boolean altKeyDown = (e.getModifiers() & InputEvent.ALT_MASK) != 0;
ic.setDrawingColor(x, y, altKeyDown); //pick color from image (ignore overlay)
if (!altKeyDown)
setColor(Toolbar.getForegroundColor());
mode = IDLE;
return;
}
mode = UNCONSTRAINED;
ip.snapshot();
Undo.setup(Undo.FILTER, imp);
ip.setLineWidth(width);
if (e.isAltDown()) {
if (overlayImage!=null)
ip.setColor(0); //erase
else
ip.setColor(Toolbar.getBackgroundColor());
} else
ip.setColor(Toolbar.getForegroundColor());
ip.moveTo(x, y);
if (!e.isShiftDown()) {
ip.lineTo(x, y);
if (overlayImage!=null) {
overlayImage.setProcessor(ip);
imp.draw();
} else
imp.updateAndDraw();
}
}
private void checkForOverlay(ImagePlus imp) {
overlayImage = getOverlayImage(imp);
if (overlayImage==null && paintOnOverlay) {
ImageProcessor overlayIP = new ColorProcessor(imp.getWidth(), imp.getHeight());
ImageRoi imageRoi = new ImageRoi(0, 0, overlayIP);
imageRoi.setZeroTransparent(true);
imageRoi.setName("[Brush]");
Overlay overlay = imp.getOverlay();
if (overlay==null)
overlay = new Overlay();
overlay.add(imageRoi);
overlay.selectable(false);
imp.setOverlay(overlay);
overlayImage = imageRoi;
}
}
private ImageRoi getOverlayImage(ImagePlus imp) {
if (!paintOnOverlay)
return null;
Overlay overlay = imp.getOverlay();
if (overlay==null)
return null;
Roi roi = overlay.get("[Brush]");
if (roi==null||!(roi instanceof ImageRoi))
return null;
Rectangle bounds = roi.getBounds();
if (bounds.x!=0||bounds.y!=0||bounds.width!=imp.getWidth()||bounds.height!=imp.getHeight())
return null;
return (ImageRoi)roi;
}
public void mouseDragged(ImagePlus imp, MouseEvent e) {
if (mode == IDLE) return;
ImageCanvas ic = imp.getCanvas();
int x = ic.offScreenX(e.getX());
int y = ic.offScreenY(e.getY());
if (mode == RESIZING) {
showToolSize(x-xStart, imp);
return;
}
if ((e.getModifiers() & InputEvent.SHIFT_MASK) != 0) { //shift constrains
if (mode == UNCONSTRAINED) { //first movement with shift down determines direction
if (Math.abs(x-xStart) > Math.abs(y-yStart))
mode = HORIZONTAL;
else if (Math.abs(x-xStart) < Math.abs(y-yStart))
mode = VERTICAL;
else return; //constraint direction still unclear
}
if (mode == HORIZONTAL)
y = yStart;
else if (mode == VERTICAL)
x = xStart;
} else {
xStart = x;
yStart = y;
mode = UNCONSTRAINED;
}
ip.setLineWidth(width);
ip.lineTo(x, y);
if (overlayImage!=null) {
overlayImage.setProcessor(ip);
imp.draw();
} else
imp.updateAndDraw();
}
public void mouseReleased(ImagePlus imp, MouseEvent e) {
if (mode==RESIZING) {
if (overlay!=null && overlay.size()>0 && CIRCLE_NAME.equals(overlay.get(overlay.size()-1).getName())) {
overlay.remove(overlay.size()-1);
imp.setOverlay(overlay);
}
overlay = null;
if (e.isShiftDown()) {
setWidth(width);
Prefs.set(widthKey, width);
}
}
}
private void setWidth(int width) {
if (gd==null)
return;
Vector numericFields = gd.getNumericFields();
TextField widthField = (TextField)numericFields.elementAt(0);
widthField.setText(""+width);
Vector sliders = gd.getSliders();
Scrollbar sb = (Scrollbar)sliders.elementAt(0);
sb.setValue(width);
}
private void setColor(Color c) {
if (gd==null)
return;
String name = Colors.colorToString2(c);
if (name.length()>0) {
Vector choices = gd.getChoices();
Choice ch = (Choice)choices.elementAt(0);
ch.select(name);
}
}
private void showToolSize(int deltaWidth, ImagePlus imp) {
if (deltaWidth !=0) {
width = oldWidth + deltaWidth;
if (width<1) width=1;
Roi circle = new OvalRoi(xStart-width/2, yStart-width/2, width, width);
circle.setName(CIRCLE_NAME);
circle.setStrokeColor(Color.red);
overlay = imp.getOverlay();
if (overlay==null)
overlay = new Overlay();
else if (overlay.size()>0 && CIRCLE_NAME.equals(overlay.get(overlay.size()-1).getName()))
overlay.remove(overlay.size()-1);
overlay.add(circle);
imp.setOverlay(overlay);
}
IJ.showStatus((isPencil?"Pencil":"Brush")+" width: "+ width);
}
public void showOptionsDialog() {
Thread thread = new Thread(this, "Brush Options");
thread.setPriority(Thread.NORM_PRIORITY);
thread.start();
}
public String getToolName() {
if (isPencil)
return "Pencil Tool";
else
return "Paintbrush Tool";
}
public String getToolIcon() {
// C123 is the foreground color
if (isPencil)
return "C037L4990L90b0Lc1c3L82a4Lb58bL7c4fDb4L494fC123L5a5dL6b6cD7b";
else
return "N02 C123H2i2g3e5c6b9b9e8g6h4i2i0 C037Lc07aLf09b P2i3e5c6b9b9e8g6h4i2i0";
}
public void run() {
new Options();
}
class Options implements DialogListener {
Options() {
if (gd != null) {
gd.toFront();
return;
}
options = this;
showDialog();
}
public void showDialog() {
Color color = Toolbar.getForegroundColor();
String colorName = Colors.colorToString2(color);
String name = isPencil?"Pencil":"Brush";
gd = GUI.newNonBlockingDialog(name+" Options");
gd.addSlider(name+" width:", 1, 50, width);
//gd.addSlider("Transparency (%):", 0, 100, transparency);
gd.addChoice("Color:", Colors.getColors(colorName), colorName);
gd.addCheckbox("Paint on overlay", paintOnOverlay);
gd.addDialogListener(this);
gd.addHelp(getHelp());
Point loc = Prefs.getLocation(LOC_KEY);
if (loc!=null) {
gd.centerDialog(false);
gd.setLocation (loc);
}
gd.showDialog();
Prefs.saveLocation(LOC_KEY, gd.getLocation());
gd = null;
}
public boolean dialogItemChanged(GenericDialog gd, AWTEvent e) {
if (e!=null && e.toString().contains("Undo")) {
ImagePlus imp = WindowManager.getCurrentImage();
if (imp!=null) IJ.run("Undo");
return true;
}
width = (int)gd.getNextNumber();
if (gd.invalidNumber() || width<0)
width = (int)Prefs.get(widthKey, 1);
//transparency = (int)gd.getNextNumber();
//if (gd.invalidNumber() || transparency<0 || transparency>100)
// transparency = 100;
String colorName = gd.getNextChoice();
paintOnOverlay = gd.getNextBoolean();
Color color = Colors.decode(colorName, null);
Toolbar.setForegroundColor(color);
Prefs.set(widthKey, width);
Prefs.set(OVERLAY_KEY, paintOnOverlay);
return true;
}
}
public static void setBrushWidth(int width) {
if (brushInstance!=null) {
Color c = Toolbar.getForegroundColor();
brushInstance.setWidth(width);
Toolbar.setForegroundColor(c);
}
}
private String getHelp() {
String ctrlString = IJ.isMacintosh()? "cmd":"ctrl";
return
""
+""
+"Key modifiers"
+""
+"- shift to draw horizontal or vertical lines
"
+" - alt to draw in background color (or
to erase if painting on overlay
"
+" - "+ ctrlString+"-shift-drag to change "+(isPencil ? "pencil" : "brush")+" width
"
+" - "+ ctrlString+"-click to change (\"pick up\") the
"
+"drawing color, or use the Color
Picker (shift-k)
"
+"
"
+"Use Edit>Selection>Create Mask to create
a mask from the painted overlay. "
+"Use
Image>Overlay>Remove Overlay to remove
the painted overlay.
"
+"
"
+"";
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy