4 import java.util.Properties;
5 import java.awt.image.*;
6 import java.awt.event.*;
7 import ij.process.ImageProcessor;
9 import ij.plugin.frame.Recorder;
15 public class ImageCanvas extends JPanel implements MouseListener, MouseMotionListener, Cloneable {
17 protected static Cursor defaultCursor =
new Cursor(Cursor.DEFAULT_CURSOR);
18 protected static Cursor handCursor =
new Cursor(Cursor.HAND_CURSOR);
19 protected static Cursor moveCursor =
new Cursor(Cursor.MOVE_CURSOR);
20 protected static Cursor crosshairCursor =
new Cursor(Cursor.CROSSHAIR_CURSOR);
27 static final int NO_MODS=0, ADD_TO_ROI=1, SUBTRACT_FROM_ROI=2;
30 protected boolean imageUpdated;
31 protected Rectangle srcRect;
32 protected int imageWidth, imageHeight;
37 private double magnification;
39 private int xMouseStart;
40 private int yMouseStart;
41 private int xSrcStart;
42 private int ySrcStart;
45 int roiModState = NO_MODS;
50 int width = imp.getWidth();
51 int height = imp.getHeight();
54 srcRect =
new Rectangle(0, 0, imageWidth, imageHeight);
55 addMouseListener(
this);
56 addMouseMotionListener(
this);
58 Dimension viewportSize = ij.getViewportSize();
60 magnification = Math.min(1.0, Math.min((
float)viewportSize.width / (
float)imageWidth, (
float)(viewportSize.height - 20) / (
float)imageHeight));
63 setForeground(Color.white);
64 setBackground(Color.black);
66 setForeground(Color.black);
67 setBackground(Color.white);
85 public void update(Graphics g) {
89 public void paintComponent(Graphics g) {
90 Roi roi = imp.getRoi();
91 if (roi != null) roi.updatePaste();
98 if (magnification<1.0)
99 Java2.setBilinearInterpolation(g,
true);
100 else if (IJ.isMacOSX())
101 Java2.setBilinearInterpolation(g,
false);
105 g.drawImage(img, 0, 0, (
int)(srcRect.width*magnification), (
int)(srcRect.height*magnification),
106 srcRect.x, srcRect.y, srcRect.x+srcRect.width, srcRect.y+srcRect.height, null);
110 catch(OutOfMemoryError e) {IJ.outOfMemory(
"Paint");}
116 return new Point(xMouse, yMouse);
128 Roi roi = imp.getRoi();
144 if (roi!=null && roi.getState()!=roi.CONSTRUCTING && roi.
isHandle(sx, sy)>=0)
146 else if (usePointer || (roi!=null && roi.getState()!=roi.CONSTRUCTING && roi.contains(ox, oy)))
155 return srcRect.x + (int)(x/magnification);
160 return srcRect.y + (int)(y/magnification);
165 return (
int)((x-srcRect.x)*magnification);
170 return (
int)((y-srcRect.y)*magnification);
173 public double getMagnification() {
174 return magnification;
177 public void setMagnification(
double magnification) {
178 this.magnification = magnification;
180 setSize((
int)(imp.getWidth() * magnification), (
int)(imp.getHeight() * magnification));
181 setPreferredSize(getSize());
186 public Rectangle getSrcRect() {
190 private static final double[] zoomLevels = {
191 1/72.0, 1/48.0, 1/32.0, 1/24.0, 1/16.0, 1/12.0,
192 1/8.0, 1/6.0, 1/4.0, 1/3.0, 1/2.0, 0.75, 1.0,
193 2.0, 3.0, 4.0, 6.0, 8.0, 12.0, 16.0, 24.0, 32.0 };
195 static double getLowerZoomLevel(
double currentMag) {
196 double newMag = zoomLevels[0];
197 for (
int i=0; i<zoomLevels.length; i++) {
198 if (zoomLevels[i] < currentMag)
199 newMag = zoomLevels[i];
206 static double getHigherZoomLevel(
double currentMag) {
207 double newMag = 32.0;
208 for (
int i=zoomLevels.length-1; i>=0; i--) {
209 if (zoomLevels[i]>currentMag)
210 newMag = zoomLevels[i];
220 if (magnification>=32)
222 double newMag = getHigherZoomLevel(magnification);
223 setMagnification(newMag);
227 boolean canEnlarge(
int newWidth,
int newHeight) {
234 if (magnification<=0.03125)
236 double newMag = getLowerZoomLevel(magnification);
237 setMagnification(newMag);
238 ij.getContentPane().repaint();
242 Dimension viewportSize = ij.getViewportSize();
243 double imag = Math.min(1.0, Math.min((
float)viewportSize.width / (
float)imageWidth, (
float)(viewportSize.height - 20) / (
float)imageHeight));
244 if (magnification==imag)
246 setMagnification(imag);
247 ij.getContentPane().repaint();
251 Color getColor(
int index){
252 IndexColorModel cm = (IndexColorModel)imp.
getProcessor().getColorModel();
254 return new Color(cm.getRGB(index));
257 protected void setDrawingColor(
int ox,
int oy,
boolean setBackground) {
262 case ImagePlus.GRAY8: {
264 setBackgroundColor(getColor(v[0]));
266 setForegroundColor(getColor(v[0]));
269 case ImagePlus.GRAY16:
case ImagePlus.GRAY32: {
272 double value = (type==ImagePlus.GRAY32)?Float.intBitsToFloat(v[0]):v[0];
273 int index = (int)(255.0*((value-min)/(max-min)));
274 if (index<0) index = 0;
275 if (index>255) index = 255;
277 setBackgroundColor(getColor(index));
279 setForegroundColor(getColor(index));
282 case ImagePlus.COLOR_RGB:
case ImagePlus.COLOR_256: {
283 Color c =
new Color(v[0], v[1], v[2]);
285 setBackgroundColor(c);
287 setForegroundColor(c);
293 c = Toolbar.getBackgroundColor();
295 c = Toolbar.getForegroundColor();
298 IJ.showStatus(
"("+c.getRed()+
", "+c.getGreen()+
", "+c.getBlue()+
")");
301 private void setForegroundColor(Color c) {
302 Toolbar.setForegroundColor(c);
304 Recorder.record(
"setForegroundColor", c.getRed(), c.getGreen(), c.getBlue());
307 private void setBackgroundColor(Color c) {
308 Toolbar.setBackgroundColor(c);
310 Recorder.record(
"setBackgroundColor", c.getRed(), c.getGreen(), c.getBlue());
313 public void mousePressed(MouseEvent e) {
314 if (ij==null)
return;
315 int toolID = Toolbar.getToolId();
320 flags = e.getModifiers();
321 if (IJ.debugMode) IJ.log(
"Mouse pressed: (" + x +
"," + y +
")" + ij.
modifiers(flags));
323 if (toolID!=Toolbar.MAGNIFIER && (e.isPopupTrigger() || (flags & Event.META_MASK)!=0)) {
330 xMouse = ox; yMouse = oy;
332 case Toolbar.MAGNIFIER:
333 if ((flags & (Event.ALT_MASK|Event.META_MASK|Event.CTRL_MASK))!=0)
338 case Toolbar.DROPPER:
339 setDrawingColor(ox, oy, IJ.altKeyDown());
341 case Toolbar.CROSSHAIR:
342 IJ.doCommand(
"Measure");
345 Roi roi = imp.getRoi();
346 if (roi!=null && roi.contains(ox, oy)) {
347 Rectangle r = roi.getBounds();
348 if (r.width==imageWidth && r.height==imageHeight)
351 handleRoiMouseDown(e);
356 int handle = roi.isHandle(x, y);
358 roi.mouseDownInHandle(handle, x, y);
362 setRoiModState(e, roi, -1);
363 int npoints = IJ.doWand(ox, oy);
364 if (Recorder.record && npoints>0)
365 Recorder.record(
"doWand", ox, oy);
368 handleRoiMouseDown(e);
372 protected void handlePopupMenu(MouseEvent e) {
373 if (IJ.debugMode) IJ.log(
"show popup: " + (e.isPopupTrigger()?
"true":
"false"));
376 Roi roi = imp.getRoi();
377 if (roi!=null && (roi.getType()==Roi.POLYGON || roi.getType()==Roi.POLYLINE || roi.getType()==Roi.ANGLE)
378 && roi.getState()==roi.CONSTRUCTING) {
379 roi.handleMouseUp(x, y);
380 roi.handleMouseUp(x, y);
383 JPopupMenu popup = Menus.getPopupMenu();
386 popup.show(
this, x, y);
390 public void mouseExited(MouseEvent e) {
396 public void mouseDragged(MouseEvent e) {
401 flags = e.getModifiers();
403 flags = InputEvent.BUTTON1_MASK;
404 if (Toolbar.getToolId()==Toolbar.HAND || IJ.spaceBarDown())
408 Roi roi = imp.getRoi();
410 roi.handleMouseDrag(x, y, flags);
414 void handleRoiMouseDown(MouseEvent e) {
419 Roi roi = imp.getRoi();
420 int handle = roi!=null?roi.isHandle(sx, sy):-1;
421 setRoiModState(e, roi, handle);
423 Rectangle r = roi.getBounds();
424 int type = roi.getType();
425 if (type==Roi.RECTANGLE && r.width==imp.getWidth() && r.height==imp.getHeight()
426 && roi.getPasteMode()==Roi.NOT_PASTING) {
431 roi.mouseDownInHandle(handle, sx, sy);
434 if (roi.contains(ox, oy)) {
435 if (roiModState==NO_MODS)
436 roi.handleMouseDown(sx, sy);
443 if ((type==Roi.POLYGON || type==Roi.POLYLINE || type==Roi.ANGLE)
444 && roi.getState()==roi.CONSTRUCTING)
450 void setRoiModState(MouseEvent e, Roi roi,
int handle) {
451 if (roi==null || !IJ.isJava2())
452 {roiModState = NO_MODS;
return;}
453 if (handle>=0 && roiModState==NO_MODS)
455 if (roi.state==Roi.CONSTRUCTING)
457 int tool = Toolbar.getToolId();
458 if (tool>Toolbar.FREEROI && tool!=Toolbar.WAND)
459 {roiModState = NO_MODS;
return;}
461 roiModState = ADD_TO_ROI;
462 else if (e.isAltDown())
463 roiModState = SUBTRACT_FROM_ROI;
465 roiModState = NO_MODS;
469 public void mouseReleased(MouseEvent e) {
470 flags = e.getModifiers();
471 flags &= ~InputEvent.BUTTON1_MASK;
473 Roi roi = imp.getRoi();
475 Rectangle r = roi.getBounds();
476 if ((r.width==0 || r.height==0)
477 && !(roi.getType()==Roi.POLYGON || roi.getType()==Roi.POLYLINE || roi.getType()==Roi.ANGLE)
478 && !(roi instanceof TextRoi)
479 && roi.getState()==roi.CONSTRUCTING)
482 roi.handleMouseUp(e.getX(), e.getY());
486 public void mouseMoved(MouseEvent e) {
487 if (ij==null)
return;
492 flags = e.getModifiers();
496 Roi roi = imp.getRoi();
497 if (roi!=null && (roi.getType()==Roi.POLYGON || roi.getType()==Roi.POLYLINE || roi.getType()==Roi.ANGLE)
498 && roi.getState()==roi.CONSTRUCTING) {
499 PolygonRoi pRoi = (PolygonRoi)roi;
500 pRoi.handleMouseMove(ox, oy);
507 public void mouseClicked(MouseEvent e) {}
508 public void mouseEntered(MouseEvent e) {}
511 static ImagePlus getClipboard() {
518 public void copy(
boolean cut) {
519 Roi roi = imp.getRoi();
520 String msg = (cut)?
"Cut":
"Copy";
524 clipboard =
new ImagePlus(
"Clipboard", ip2);
525 if (roi!=null && roi.getType()!=
Roi.RECTANGLE)
531 if (roi!=null && roi.getType()!=
Roi.RECTANGLE)
537 int bytesPerPixel = 1;
542 IJ.
showStatus(msg +
": " + (clipboard.getWidth()*clipboard.getHeight()*bytesPerPixel)/1024 +
"k");
548 if (clipboard==null) {
551 int cType = clipboard.
getType();
554 boolean sameType =
false;
560 IJ.
error(
"Images must be the same type to paste.");
563 int w = clipboard.getWidth();
564 int h = clipboard.getHeight();
565 if (w>imp.getWidth() || h>imp.getHeight()) {
566 IJ.error(
"Image is too large to paste.");
569 Roi roi = imp.getRoi();
573 if (r==null || (r!=null && (w!=r.width || h!=r.height))) {
575 Rectangle srcRect = getSrcRect();
576 int xCenter = srcRect.x + srcRect.width/2;
577 int yCenter = srcRect.y + srcRect.height/2;
578 Roi cRoi = clipboard.getRoi();
579 if (cRoi!=null && cRoi.getType()!=Roi.RECTANGLE) {
581 cRoi.setLocation(xCenter-w/2, yCenter-h/2);
584 imp.
setRoi(xCenter-w/2, yCenter-h/2, w, h);
587 if (IJ.macroRunning()) {
589 int pasteMode = Roi.getCurrentPasteMode();
590 boolean nonRect = roi.getType()!=Roi.RECTANGLE;
592 if (nonRect) ip.snapshot();
594 ip.copyBits(clipboard.
getProcessor(), r.x, r.y, pasteMode);
600 roi.startPaste(clipboard);
601 Undo.setup(Undo.PASTE, imp);