package lcm.util; import java.awt.*; import java.awt.image.*; import java.awt.geom.*; import java.awt.event.*; import javax.swing.*; import javax.swing.event.*; import java.io.*; import java.util.*; public class JImage extends JComponent { public static final long serialVersionUID=1001; BufferedImage im; boolean fit = false; JPopupMenu popupMenu = new JPopupMenu("JImage Menu"); AffineTransform t = new AffineTransform(); public JImage() { this(null, true); } public JImage(int width, int height) { this(new BufferedImage(width, height, BufferedImage.TYPE_BYTE_GRAY), true); } public JImage(BufferedImage im) { this(im, true); } public JImage(BufferedImage im, boolean enableControls) { this.im = im; if (enableControls) initControls(); } void initControls() { JMenuItem jmi; jmi=new JMenuItem("JImage Menu"); jmi.setEnabled(false); popupMenu.add(jmi); jmi=new JMenuItem("Fit"); jmi.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { fit = true; repaint(); } }); popupMenu.add(jmi); JMenu scaleMenu = new JMenu("Set Scale"); popupMenu.add(scaleMenu); int scales[] = new int[] { 25, 50, 100, 200, 400, 800 }; for (int i = 0; i < scales.length; i++) { jmi=new JMenuItem(scales[i]+" %"); jmi.addActionListener(new ScaleAction(scales[i])); scaleMenu.add(jmi); } MyListener l = new MyListener(); addMouseMotionListener(l); addMouseListener(l); addMouseWheelListener(l); addKeyListener(l); } class ScaleAction implements ActionListener { int scale; public ScaleAction(int scale) { this.scale = scale; } public void actionPerformed(ActionEvent e) { adjustZoom(scale/100.0, null); } } /** Zoom, preserving the center point on the screen. (When we draw, the center point may be moved in order to maximize the amount of image seen on screen.) **/ void adjustZoom(double z, Point2D cp) { if (cp == null) cp = new Point2D.Double(getWidth()/2, getHeight()/2); Point2D cxt = componentToImage(cp); double tx = cp.getX() - cxt.getX()*z; double ty = cp.getY() - cxt.getY()*z; t = new AffineTransform(); t.translate(tx, ty); t.scale(z, z); fit = false; repaint(); } // zoom in a notch void zoomIn(Point2D p) { double nz = t.getScaleX()*2.0; nz = Math.min(nz, 64); adjustZoom(nz, p); } // zoom out a notch void zoomOut(Point2D p) { double nz = t.getScaleX()*.5; nz = Math.max(nz, 1.0/32.0); adjustZoom(nz, p); } // if im == null, the image is cleared public void setImage(BufferedImage im) { this.im=im; invalidate(); repaint(); } public Dimension getMinimumSize() { // if (im==null) return new Dimension(2,2); // return new Dimension(im.getWidth(), im.getHeight()); } public Dimension getPreferredSize() { return getMaximumSize(); } public Dimension getMaximumSize() { if (im==null) return new Dimension(2,2); return new Dimension(im.getWidth(), im.getHeight()); } public Point2D componentToImage(Point2D p) { Point2D tp = null; try { tp = t.inverseTransform(p, null); } catch (NoninvertibleTransformException ex) { // can't happen. } return tp; } public synchronized void paint(Graphics gin) { Graphics2D g=(Graphics2D) gin; if (im==null) return; int height=getHeight(); int width=getWidth(); if (fit) { t = new AffineTransform(); double scale = Math.min(((double) width)/im.getWidth(), ((double) height)/im.getHeight()); // we'll re-center the transform in a moment. t.scale(scale, scale); } // if the image (in either X or Y) is smaller than the view port, then center // the image with respect to that axis. double mwidth = im.getWidth()*t.getScaleX(); double mheight = im.getHeight()*t.getScaleY(); if (mwidth < width) t.preConcatenate(AffineTransform.getTranslateInstance( (width-mwidth) / 2.0 - t.getTranslateX(), 0) ); if (mheight < height) t.preConcatenate(AffineTransform.getTranslateInstance( 0, (height-mheight)/2.0 - t.getTranslateY())); // if we're allowing panning (because only a portion of the image is visible), // don't allow translations that show less information that is possible. Point2D topleft = t.transform(new Point2D.Double(0,0), null); Point2D bottomright = t.transform(new Point2D.Double(im.getWidth(),im.getHeight()), null); if (mwidth > width) { if (topleft.getX() > 0) t.preConcatenate(AffineTransform.getTranslateInstance(-topleft.getX(),0)); if (bottomright.getX() < width) t.preConcatenate(AffineTransform.getTranslateInstance(width-bottomright.getX(), 0)); // t.translate(width-bottomright.getX(), 0); } if (mheight > height) { if (topleft.getY() > 0) t.preConcatenate(AffineTransform.getTranslateInstance(0, -topleft.getY())); if (bottomright.getY() < height) t.preConcatenate(AffineTransform.getTranslateInstance(0, height-bottomright.getY())); } g.drawImage(im, t, null); } /* public void setScale(boolean b) { scale=b; } */ class MyListener implements KeyListener, MouseMotionListener, MouseListener, MouseWheelListener { boolean nodrag = true; Point dragBegin = null; public void keyPressed(KeyEvent e) { } public void keyReleased(KeyEvent e) { } public void keyTyped(KeyEvent e) { } // returns true if the keypress was handled public boolean handleKeyPress(KeyEvent e) { return false; } public void mouseWheelMoved(MouseWheelEvent e) { int amount=e.getWheelRotation(); Point2D p = new Point2D.Double(e.getPoint().getX(), e.getPoint().getY()); if (amount > 0) zoomOut(p); if (amount < 0) zoomIn(p); } public void mouseDragged(MouseEvent e) { int mods=e.getModifiersEx(); Point dragEnd = e.getPoint(); boolean shift = (mods&MouseEvent.SHIFT_DOWN_MASK)>0; boolean ctrl = (mods&MouseEvent.CTRL_DOWN_MASK)>0; boolean alt = shift & ctrl; ctrl = ctrl & (!alt); shift = shift & (!alt); boolean nomods = !(shift | ctrl | alt); if (dragBegin == null) dragBegin = dragEnd; nodrag=false; if ((mods&InputEvent.BUTTON3_DOWN_MASK)>0 || true) { double dx = dragEnd.getX() - dragBegin.getX(); double dy = dragEnd.getY() - dragBegin.getY(); synchronized (JImage.this) { t.preConcatenate(AffineTransform.getTranslateInstance(dx, dy)); } dragBegin = dragEnd; repaint(); } } public void mouseMoved(MouseEvent e) { } public void mousePressed(MouseEvent e) { dragBegin = e.getPoint(); } public void mouseReleased(MouseEvent e) { int mods=e.getModifiersEx(); if (nodrag && e.getButton()==MouseEvent.BUTTON3) { popupMenu.show(JImage.this, (int) e.getPoint().getX(), (int) e.getPoint().getY()); } nodrag = true; dragBegin = null; } public void mouseClicked(MouseEvent e) { if (e.getButton()==1 && e.getClickCount()==2) { adjustZoom(1, null); } } public void mouseEntered(MouseEvent e) { } public void mouseExited(MouseEvent e) { } } }