package edu.mbl.jif.gui.imaging; import edu.mbl.jif.gui.panel.PanelEnclosed; import java.io.*; import java.util.*; import javax.imageio.*; import java.awt.*; import java.awt.event.*; import java.awt.image.*; import javax.swing.*; import javax.swing.event.*; /** * PanelZoomImage - Maintains aspect ratio while scaling to available space */ public class ResizableZoomImagePanel extends PanelEnclosed { boolean debug = true; BorderLayout borderLayout1 = new BorderLayout(); private float zoomMagnification; int imageWidth; int imageHeight; float imageAspectRatio; Dimension minimumImageSize; Dimension minimumWindowSize; int winXdiff; int winYdiff; int scaledImageWidth; int scaledImageHeight; Dimension preferedImageSize; Dimension initialWinSize; Dimension canvasSize; Dimension largestImage; int xpadding; int ypadding; float ratio; Image zoomimage; Image overlay; Canvas canvas; Point pStart = null; Rectangle roiRect = null; Color colorRoi = Color.red; MyObservable _observable; public ResizableZoomImagePanel (Image _zoomimage, float _zoomMagnification, boolean pixelRoiSelection) { this(); setImage(_zoomimage, _zoomMagnification, pixelRoiSelection); } public ResizableZoomImagePanel () { try { jbInit(); } catch (Exception ex) { ex.printStackTrace(); } } void jbInit () throws Exception { this.setLayout(borderLayout1); _observable = new MyObservable(); } public void showImage (Image _image) { zoomimage = _image; //canvas.repaint(); repaint(); } public Dimension getImageSize () { return new Dimension(imageWidth, imageHeight); } public void setImage (Image _zoomimage, float _zoomMagnification, boolean pixelRoiSelection) { zoomimage = _zoomimage; zoomMagnification = _zoomMagnification; imageWidth = zoomimage.getWidth(null); imageHeight = zoomimage.getHeight(null); imageAspectRatio = imageWidth / (float) imageHeight; minimumImageSize = new Dimension(imageWidth, imageHeight); minimumWindowSize = new Dimension(getSize()); winXdiff = minimumWindowSize.width - minimumImageSize.width; winYdiff = minimumWindowSize.height - minimumImageSize.height; scaledImageWidth = Math.round(imageWidth * zoomMagnification); scaledImageHeight = Math.round(imageHeight * zoomMagnification); preferedImageSize = new Dimension(scaledImageWidth, scaledImageHeight); // create Overlay for ROI, annotations, etc. overlay = new BufferedImage((int) imageWidth, (int) imageHeight, BufferedImage.TYPE_INT_ARGB); // Add the Image Canvas canvas = new Canvas(); if (pixelRoiSelection) { canvas.addPixelRoiListener(); } this.add(canvas); Dimension initialWinSize = new Dimension(preferedImageSize.width + winXdiff, preferedImageSize.height + winYdiff); setPreferredSize(initialWinSize); addNotify(); } public void setRoiColor (Color c) { colorRoi = c; } public void addObserver (Observer obs) { _observable.addObserver(obs); } Vector overlays = new Vector(); public void addOverlay (Overlay olay) { overlays.add(olay); } class Canvas extends JPanel { public Canvas () { super(); this.setBackground(Color.black); } public void addPixelRoiListener () { // add listener for pixels and roi's PixelRoiListener myListener = new PixelRoiListener(); addMouseListener(myListener); addMouseMotionListener(myListener); } public Dimension getMinimumSize () { return minimumImageSize; } public Dimension getPreferedSize () { return preferedImageSize; } public void paintComponent (Graphics g) { super.paintComponent(g); Graphics2D g2 = (Graphics2D) g; if (false) { g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); } // get the requested new size canvasSize = getSize(); largestImage = new Dimension(canvasSize); if ((largestImage.width / (float) largestImage.height) > imageAspectRatio) { largestImage.width = (int) Math.ceil(largestImage.height * imageAspectRatio); } else { largestImage.height = (int) Math.ceil(largestImage.width / imageAspectRatio); } xpadding = canvasSize.width - largestImage.width; ypadding = canvasSize.height - largestImage.height; g2.drawImage(zoomimage, xpadding / 2, ypadding / 2, largestImage.width, largestImage.height, null); //System.out.println("Ration: " + ratio); drawOverlays(g2); } public void drawOverlays (Graphics2D g2) { if (roiRect != null) { drawScaledROI(g2, roiRect); } for (Iterator itero = overlays.iterator(); itero.hasNext(); ) { Overlay olay = (Overlay) itero.next(); olay.updateGraphics(g2); } } // ROI Selection ------------------------------------------------------ public void drawScaledROI (Graphics2D g2, Rectangle r) { Point z = getDescaledXY((int) r.getX(), (int) r.getY()); int w = (int) (ratio * r.getWidth()); int h = (int) (ratio * r.getHeight()); if (w > 0 && h > 0) { g2.setColor(colorRoi); g2.drawRect(z.x, z.y, w, h); } } Point getScaledXY (MouseEvent e) { int x = e.getX(); int y = e.getY(); return getScaledXY(x, y); } Point getScaledXY (int x, int y) { if (xpadding > 0) { ratio = (float) canvasSize.getHeight() / (float) imageHeight; } else { ratio = (float) canvasSize.getWidth() / (float) imageWidth; } int iX = Math.round((x - (float) xpadding / 2f) / ratio); int iY = Math.round((y - (float) ypadding / 2f) / ratio); if (iX < 0) { iX = 0; } if (iX > imageWidth) { iX = imageWidth; } if (iY < 0) { iY = 0; } if (iY > imageHeight) { iY = imageHeight; } return new Point(iX, iY); } Point getDescaledXY (int x, int y) { if (xpadding > 0) { ratio = (float) canvasSize.getHeight() / (float) imageHeight; } else { ratio = (float) canvasSize.getWidth() / (float) imageWidth; } int iX = Math.round((x * ratio + (float) xpadding / 2f)); int iY = Math.round((y * ratio + (float) ypadding / 2f)); if (iX < 0) { iX = 0; } // if (iX > imageWidth) { // iX = imageWidth; // } // if (iY < 0) { // iY = 0; // } // if (iY > imageHeight) { // iY = imageHeight; // } return new Point(iX, iY); } // Listener -------------------------------------------------------------- class PixelRoiListener extends MouseInputAdapter { public void mousePressed (MouseEvent e) { if (e.getButton() == MouseEvent.BUTTON1) { pStart = getScaledXY(e); if (debug) { System.out.println("Start: " + pStart.x + ", " + pStart.y); } roiRect = new Rectangle(pStart.x, pStart.y, 0, 0); repaint(); } if (e.getClickCount() == 2) { if (debug) { System.out.println(" double click"); } } if (e.getButton() == MouseEvent.BUTTON3) { if (debug) { System.out.println(" RightClick"); } } } public void mouseDragged (MouseEvent e) { Point p = getScaledXY(e); int x = p.x; int y = p.y; int width = pStart.x - p.x; int height = pStart.y - p.y; //Make the width and height positive, if necessary. if (width < 0) { width = 0 - width; x = x - width + 1; if (x < 0) { width += x; x = 0; } } if (height < 0) { height = 0 - height; y = y - height + 1; if (y < 0) { height += y; y = 0; } } if (debug) { System.out.println(x + "," + y + "," + width + "," + height); } roiRect.setBounds(x, y, width, height); repaint(); } public void mouseReleased (MouseEvent e) { if (debug) { System.out.println("ROI: " + roiRect); } _observable.notifyObservers(roiRect); } public void mouseMoved (MouseEvent e) { Point p = getScaledXY(e); //if (debug) { System.out.println("Pixel: " + p.x + ", " + p.y); } if(p!=null) { _observable.notifyObservers(p); } // Point pD = getDescaledXY(p.x, p.y); // System.out.println("e(" + e.getX() + ", " + e.getY() + ") " + // "p(" + p.x + ", " + p.y + ") " + // "pD(" + pD.x + ", " + pD.y + ") "); /** @todo */ } } }; class MyObservable extends Observable { public void clearChanged () { super.clearChanged(); } public void setChanged () { super.setChanged(); } public void notifyObservers (Object b) { // Otherwise it won't propagate changes: setChanged(); super.notifyObservers(b); } } // TEST ==================================================================== public void test () { String image_file_name = // edu.mbl.jif.Constants.testDataPath + "images\\PSCollagenDark.gif"; "jifSplashNoTitle.png"; //Image testImage = new ImageIcon(ClassLoader.getSystemResource(image_file_name)).getImage(); Image image = null; try { image = ImageIO.read(new File(image_file_name)); } catch (Exception e) { System.out.println("Exception loading: " + image_file_name); } //String image_file_name2 = "PSCollagenDarkInv.gif"; // 589 x 421 //Image testImage = new ImageIcon(ClassLoader.getSystemResource(image_file_name)).getImage(); // Image image2 = null; // try { // image2 = ImageIO.read(new File(image_file_name2)); // } // catch (Exception e) { // System.out.println("Exception loading: " + image_file_name); // } JFrame zoomwin = new JFrame(); ResizableZoomImagePanel p = new ResizableZoomImagePanel(); p.setImage(image, 0.1f, true); p.addObserver(new CursorWatcher(p)); zoomwin.getContentPane().setLayout(new BorderLayout()); zoomwin.getContentPane().add(p, BorderLayout.CENTER); zoomwin.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //zoomwin.getContentPane().add(SeriesPlayerController, BorderLayout.SOUTH); zoomwin.pack(); zoomwin.setSize(400, 400); zoomwin.setVisible(true); try { Thread.sleep(500); } catch (InterruptedException ex) { } //p.showImage(image2); } public static void main (String[] args) { new ResizableZoomImagePanel().test(); } } // end class ZoomWindow