ij.gui.ImageWindow Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of imagej Show documentation
Show all versions of imagej Show documentation
Image processing and analysis framework. Allows the user to
record/replay macros and can be extended using plug-ins.
The newest version!
package ij.gui;
import java.awt.*;
import java.awt.image.*;
import java.util.Properties;
import java.awt.event.*;
import ij.*;
import ij.process.*;
import ij.io.*;
import ij.measure.*;
import ij.plugin.frame.*;
import ij.macro.Interpreter;
import ij.util.Java2;
/** A frame for displaying images. */
public class ImageWindow extends Frame implements FocusListener, WindowListener, WindowStateListener, MouseWheelListener {
public static final int MIN_WIDTH = 128;
public static final int MIN_HEIGHT = 32;
protected ImagePlus imp;
protected ImageJ ij;
protected ImageCanvas ic;
private double initialMagnification = 1;
private int newWidth, newHeight;
protected boolean closed;
private boolean newCanvas;
private boolean unzoomWhenMinimizing = true;
Rectangle maxWindowBounds; // largest possible window on this screen
Rectangle maxBounds; // Size of this window after it is maximized
long setMaxBoundsTime;
private static final int XINC = 8;
private static final int YINC = 12;
private static final int TEXT_GAP = 10;
private static int xbase = -1;
private static int ybase;
private static int xloc;
private static int yloc;
private static int count;
private static boolean centerOnScreen;
private static Point nextLocation;
private int textGap = centerOnScreen?0:TEXT_GAP;
/** This variable is set false if the user presses the escape key or closes the window. */
public boolean running;
/** This variable is set false if the user clicks in this
window, presses the escape key, or closes the window. */
public boolean running2;
public ImageWindow(String title) {
super(title);
}
public ImageWindow(ImagePlus imp) {
this(imp, null);
}
public ImageWindow(ImagePlus imp, ImageCanvas ic) {
super(imp.getTitle());
if (Prefs.blackCanvas && getClass().getName().equals("ij.gui.ImageWindow")) {
setForeground(Color.white);
setBackground(Color.black);
} else {
setForeground(Color.black);
if (IJ.isLinux())
setBackground(ImageJ.backgroundColor);
else
setBackground(Color.white);
}
boolean openAsHyperStack = imp.getOpenAsHyperStack();
ij = IJ.getInstance();
this.imp = imp;
if (ic==null)
{ic=new ImageCanvas(imp); newCanvas=true;}
this.ic = ic;
ImageWindow previousWindow = imp.getWindow();
setLayout(new ImageLayout(ic));
add(ic);
addFocusListener(this);
addWindowListener(this);
addWindowStateListener(this);
addKeyListener(ij);
setFocusTraversalKeysEnabled(false);
if (!(this instanceof StackWindow))
addMouseWheelListener(this);
setResizable(true);
if (!(this instanceof HistogramWindow&&IJ.isMacro()&&Interpreter.isBatchMode())) {
WindowManager.addWindow(this);
imp.setWindow(this);
}
if (previousWindow!=null) {
if (newCanvas)
setLocationAndSize(false);
else
ic.update(previousWindow.getCanvas());
Point loc = previousWindow.getLocation();
setLocation(loc.x, loc.y);
if (!(this instanceof StackWindow)) {
pack();
show();
}
if (ic.getMagnification()!=0.0)
imp.setTitle(imp.getTitle());
boolean unlocked = imp.lockSilently();
boolean changes = imp.changes;
imp.changes = false;
previousWindow.close();
imp.changes = changes;
if (unlocked)
imp.unlock();
if (this.imp!=null)
this.imp.setOpenAsHyperStack(openAsHyperStack);
WindowManager.setCurrentWindow(this);
} else {
setLocationAndSize(false);
if (ij!=null && !IJ.isMacintosh()) {
Image img = ij.getIconImage();
if (img!=null)
try {setIconImage(img);} catch (Exception e) {}
}
if (centerOnScreen) {
GUI.center(this);
centerOnScreen = false;
} else if (nextLocation!=null) {
setLocation(nextLocation);
nextLocation = null;
}
if (Interpreter.isBatchMode() || (IJ.getInstance()==null&&this instanceof HistogramWindow)) {
WindowManager.setTempCurrentImage(imp);
Interpreter.addBatchModeImage(imp);
} else
show();
}
}
private void setLocationAndSize(boolean updating) {
int width = imp.getWidth();
int height = imp.getHeight();
Rectangle maxWindow = getMaxWindow(0,0);
//if (maxWindow.x==maxWindow.width) // work around for Linux bug
// maxWindow = new Rectangle(0, maxWindow.y, maxWindow.width, maxWindow.height);
if (WindowManager.getWindowCount()<=1)
xbase = -1;
if (width>maxWindow.width/2 && xbase>maxWindow.x+5+XINC*6)
xbase = -1;
if (xbase==-1) {
count = 0;
xbase = maxWindow.x + 5;
if (width*2<=maxWindow.width)
xbase = maxWindow.x+maxWindow.width/2-width/2;
ybase = maxWindow.y;
xloc = xbase;
yloc = ybase;
}
int x = xloc;
int y = yloc;
xloc += XINC;
yloc += YINC;
count++;
if (count%6==0) {
xloc = xbase;
yloc = ybase;
}
int sliderHeight = (this instanceof StackWindow)?20:0;
int screenHeight = maxWindow.y+maxWindow.height-sliderHeight;
double mag = 1;
while (xbase+XINC*4+width*mag>maxWindow.x+maxWindow.width || ybase+height*mag>=screenHeight) {
//IJ.log(mag+" "+xbase+" "+width*mag+" "+maxWindow.width);
double mag2 = ImageCanvas.getLowerZoomLevel(mag);
if (mag2==mag) break;
mag = mag2;
}
if (mag<1.0) {
initialMagnification = mag;
ic.setDrawingSize((int)(width*mag), (int)(height*mag));
}
ic.setMagnification(mag);
if (y+height*mag>screenHeight)
y = ybase;
if (!updating) setLocation(x, y);
if (Prefs.open100Percent && ic.getMagnification()<1.0) {
while(ic.getMagnification()<1.0)
ic.zoomIn(0, 0);
setSize(Math.min(width, maxWindow.width-x), Math.min(height, screenHeight-y));
validate();
} else
pack();
}
Rectangle getMaxWindow(int xloc, int yloc) {
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
Rectangle bounds = ge.getMaximumWindowBounds();
//bounds.x=960; bounds.y=0; bounds.width=960; bounds.height=1200;
if (IJ.debugMode) IJ.log("getMaxWindow: "+bounds+" "+xloc+","+yloc);
if (xloc>bounds.x+bounds.width || yloc>bounds.y+bounds.height) {
Rectangle bounds2 = getSecondaryMonitorBounds(ge, xloc, yloc);
if (bounds2!=null) return bounds2;
}
Dimension ijSize = ij!=null?ij.getSize():new Dimension(0,0);
if (bounds.height>600) {
bounds.y += ijSize.height;
bounds.height -= ijSize.height;
}
return bounds;
}
private Rectangle getSecondaryMonitorBounds(GraphicsEnvironment ge, int xloc, int yloc) {
//IJ.log("getSecondaryMonitorBounds "+wb);
GraphicsDevice[] gs = ge.getScreenDevices();
for (int j=0; j1) {
ImageStack stack = imp.getStack();
int currentSlice = imp.getCurrentSlice();
s += currentSlice+"/"+nSlices;
String label = stack.getShortSliceLabel(currentSlice);
if (label!=null && label.length()>0) {
if (imp.isHyperStack()) label = label.replace(';', ' ');
s += " (" + label + ")";
}
if ((this instanceof StackWindow) && running2) {
return s;
}
s += "; ";
} else {
String label = (String)imp.getProperty("Label");
if (label!=null) {
int newline = label.indexOf('\n');
if (newline>0)
label = label.substring(0, newline);
int len = label.length();
if (len>4 && label.charAt(len-4)=='.' && !Character.isDigit(label.charAt(len-1)))
label = label.substring(0,len-4);
if (label.length()>60)
label = label.substring(0, 60);
s = label + "; ";
}
}
int type = imp.getType();
Calibration cal = imp.getCalibration();
if (cal.scaled()) {
s += IJ.d2s(imp.getWidth()*cal.pixelWidth,2) + "x" + IJ.d2s(imp.getHeight()*cal.pixelHeight,2)
+ " " + cal.getUnits() + " (" + imp.getWidth() + "x" + imp.getHeight() + "); ";
} else
s += imp.getWidth() + "x" + imp.getHeight() + " pixels; ";
double size = ((double)imp.getWidth()*imp.getHeight()*imp.getStackSize())/1024.0;
switch (type) {
case ImagePlus.GRAY8:
case ImagePlus.COLOR_256:
s += "8-bit";
break;
case ImagePlus.GRAY16:
s += "16-bit";
size *= 2.0;
break;
case ImagePlus.GRAY32:
s += "32-bit";
size *= 4.0;
break;
case ImagePlus.COLOR_RGB:
s += "RGB";
size *= 4.0;
break;
}
if (imp.isInvertedLut())
s += " (inverting LUT)";
String s2=null, s3=null;
if (size<1024.0)
{s2=IJ.d2s(size,0); s3="K";}
else if (size<10000.0)
{s2=IJ.d2s(size/1024.0,1); s3="MB";}
else if (size<1048576.0)
{s2=IJ.d2s(Math.round(size/1024.0),0); s3="MB";}
else
{s2=IJ.d2s(size/1048576.0,1); s3="GB";}
if (s2.endsWith(".0")) s2 = s2.substring(0, s2.length()-2);
return s+"; "+s2+s3;
}
public void paint(Graphics g) {
//if (IJ.debugMode) IJ.log("wPaint: " + imp.getTitle());
drawInfo(g);
Rectangle r = ic.getBounds();
int extraWidth = MIN_WIDTH - r.width;
int extraHeight = MIN_HEIGHT - r.height;
if (extraWidth<=0 && extraHeight<=0 && !Prefs.noBorder && !IJ.isLinux())
g.drawRect(r.x-1, r.y-1, r.width+1, r.height+1);
}
/** Removes this window from the window list and disposes of it.
Returns false if the user cancels the "save changes" dialog. */
public boolean close() {
boolean isRunning = running || running2;
running = running2 = false;
boolean virtual = imp.getStackSize()>1 && imp.getStack().isVirtual();
if (isRunning) IJ.wait(500);
if (ij==null || IJ.getApplet()!=null || Interpreter.isBatchMode() || IJ.macroRunning() || virtual)
imp.changes = false;
if (imp.changes) {
String msg;
String name = imp.getTitle();
if (name.length()>22)
msg = "Save changes to\n" + "\"" + name + "\"?";
else
msg = "Save changes to \"" + name + "\"?";
YesNoCancelDialog d = new YesNoCancelDialog(this, "ImageJ", msg);
if (d.cancelPressed())
return false;
else if (d.yesPressed()) {
FileSaver fs = new FileSaver(imp);
if (!fs.save()) return false;
}
}
closed = true;
if (WindowManager.getWindowCount()==0)
{xloc = 0; yloc = 0;}
WindowManager.removeWindow(this);
//setVisible(false);
if (ij!=null && ij.quitting()) // this may help avoid thread deadlocks
return true;
dispose();
if (imp!=null)
imp.flush();
imp = null;
return true;
}
public ImagePlus getImagePlus() {
return imp;
}
public void setImage(ImagePlus imp2) {
ImageCanvas ic = getCanvas();
if (ic==null || imp2==null)
return;
imp = imp2;
imp.setWindow(this);
ic.updateImage(imp);
ic.setImageUpdated();
ic.repaint();
repaint();
}
public void updateImage(ImagePlus imp) {
if (imp!=this.imp)
throw new IllegalArgumentException("imp!=this.imp");
this.imp = imp;
ic.updateImage(imp);
setLocationAndSize(true);
if (this instanceof StackWindow) {
StackWindow sw = (StackWindow)this;
int stackSize = imp.getStackSize();
int nScrollbars = sw.getNScrollbars();
if (stackSize==1 && nScrollbars>0)
sw.removeScrollbars();
else if (stackSize>1 && nScrollbars==0)
sw.addScrollbars(imp);
}
pack();
repaint();
maxBounds = getMaximumBounds();
setMaximizedBounds(maxBounds);
setMaxBoundsTime = System.currentTimeMillis();
}
public ImageCanvas getCanvas() {
return ic;
}
static ImagePlus getClipboard() {
return ImagePlus.getClipboard();
}
public Rectangle getMaximumBounds() {
double width = imp.getWidth();
double height = imp.getHeight();
double iAspectRatio = width/height;
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
Rectangle maxWindow = ge.getMaximumWindowBounds();
maxWindowBounds = maxWindow;
if (iAspectRatio/((double)maxWindow.width/maxWindow.height)>0.75) {
maxWindow.y += 22; // uncover ImageJ menu bar
maxWindow.height -= 22;
}
Dimension extraSize = getExtraSize();
double maxWidth = maxWindow.width-extraSize.width;
double maxHeight = maxWindow.height-extraSize.height;
double mAspectRatio = maxWidth/maxHeight;
int wWidth, wHeight;
double mag;
if (iAspectRatio>=mAspectRatio) {
mag = maxWidth/width;
wWidth = maxWindow.width;
wHeight = (int)(height*mag+extraSize.height);
} else {
mag = maxHeight/height;
wHeight = maxWindow.height;
wWidth = (int)(width*mag+extraSize.width);
}
int xloc = (int)(maxWidth-wWidth)/2;
if (xloc<0) xloc = 0;
return new Rectangle(xloc, maxWindow.y, wWidth, wHeight);
}
Dimension getExtraSize() {
Insets insets = getInsets();
int extraWidth = insets.left+insets.right + 10;
int extraHeight = insets.top+insets.bottom + 10;
if (extraHeight==20) extraHeight = 42;
int members = getComponentCount();
//if (IJ.debugMode) IJ.log("getExtraSize: "+members+" "+insets);
for (int i=1; iic.getMagnification() || aspectRatio<0.5 || aspectRatio>2.0) {
ic.setMagnification2(mag);
ic.setSrcRect(new Rectangle(0, 0, width, height));
ic.setDrawingSize((int)(width*mag), (int)(height*mag));
validate();
unzoomWhenMinimizing = true;
} else
unzoomWhenMinimizing = false;
}
public void minimize() {
if (unzoomWhenMinimizing)
ic.unzoom();
unzoomWhenMinimizing = true;
}
/** Has this window been closed? */
public boolean isClosed() {
return closed;
}
public void focusGained(FocusEvent e) {
if (!Interpreter.isBatchMode() && ij!=null && !ij.quitting() && imp!=null) {
if (IJ.debugMode) IJ.log("focusGained: "+imp);
WindowManager.setCurrentWindow(this);
}
}
public void windowActivated(WindowEvent e) {
if (IJ.debugMode) IJ.log("windowActivated: "+imp.getTitle());
ImageJ ij = IJ.getInstance();
boolean quitting = ij!=null && ij.quitting();
if (IJ.isMacintosh() && ij!=null && !quitting) {
IJ.wait(10); // may be needed for Java 1.4 on OS X
setMenuBar(Menus.getMenuBar());
}
if (imp==null) return;
if (!closed && !quitting && !Interpreter.isBatchMode())
WindowManager.setCurrentWindow(this);
if (imp.isComposite())
Channels.updateChannels();
imp.setActivated(); // notify ImagePlus that image has been activated
}
public void windowClosing(WindowEvent e) {
//IJ.log("windowClosing: "+imp.getTitle()+" "+closed);
if (closed)
return;
if (ij!=null) {
WindowManager.setCurrentWindow(this);
IJ.doCommand("Close");
} else {
//setVisible(false);
dispose();
WindowManager.removeWindow(this);
}
}
public void windowStateChanged(WindowEvent e) {
int oldState = e.getOldState();
int newState = e.getNewState();
//IJ.log("WSC: "+getBounds()+" "+oldState+" "+newState);
if ((oldState & Frame.MAXIMIZED_BOTH) == 0 && (newState & Frame.MAXIMIZED_BOTH) != 0)
maximize();
else if ((oldState & Frame.MAXIMIZED_BOTH) != 0 && (newState & Frame.MAXIMIZED_BOTH) == 0)
minimize();
}
public void windowClosed(WindowEvent e) {}
public void windowDeactivated(WindowEvent e) {}
public void focusLost(FocusEvent e) {}
public void windowDeiconified(WindowEvent e) {}
public void windowIconified(WindowEvent e) {}
public void windowOpened(WindowEvent e) {}
public void mouseWheelMoved(MouseWheelEvent event) {
int rotation = event.getWheelRotation();
int width = imp.getWidth();
int height = imp.getHeight();
Rectangle srcRect = ic.getSrcRect();
int xstart = srcRect.x;
int ystart = srcRect.y;
if (IJ.spaceBarDown() || srcRect.height==height) {
srcRect.x += rotation*Math.max(width/200, 1);
if (srcRect.x<0) srcRect.x = 0;
if (srcRect.x+srcRect.width>width) srcRect.x = width-srcRect.width;
} else {
srcRect.y += rotation*Math.max(height/200, 1);
if (srcRect.y<0) srcRect.y = 0;
if (srcRect.y+srcRect.height>height) srcRect.y = height-srcRect.height;
}
if (srcRect.x!=xstart || srcRect.y!=ystart)
ic.repaint();
}
/** Copies the current ROI to the clipboard. The entire
image is copied if there is no ROI. */
public void copy(boolean cut) {
imp.copy(cut);
}
public void paste() {
imp.paste();
}
/** This method is called by ImageCanvas.mouseMoved(MouseEvent).
@see ij.gui.ImageCanvas#mouseMoved
*/
public void mouseMoved(int x, int y) {
imp.mouseMoved(x, y);
}
public String toString() {
return imp!=null?imp.getTitle():"";
}
/** Causes the next image to be opened to be centered on the screen
and displayed without informational text above the image. */
public static void centerNextImage() {
centerOnScreen = true;
}
/** Causes the next image to be displayed at the specified location. */
public static void setNextLocation(Point loc) {
nextLocation = loc;
}
/** Causes the next image to be displayed at the specified location. */
public static void setNextLocation(int x, int y) {
nextLocation = new Point(x, y);
}
/** Moves and resizes this window. Changes the
magnification so the image fills the window. */
public void setLocationAndSize(int x, int y, int width, int height) {
setBounds(x, y, width, height);
getCanvas().fitToWindow();
pack();
}
/** Overrides the setBounds() method in Component so
we can find out when the window is resized. */
//public void setBounds(int x, int y, int width, int height) {
// super.setBounds(x, y, width, height);
// ic.resizeSourceRect(width, height);
//}
} //class ImageWindow