/**
*
*/
package photoSpreadUtilities;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseWheelEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.ImageIcon;
import javax.swing.InputMap;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.KeyStroke;
import photoSpreadUtilities.Misc.ShowHelpAction;
import photoSpreadUtilities.Misc.WindowCloseAction;
/**
* @author paepcke
*
*/
public class Zoomer extends JFrame {
private static final long serialVersionUID = 1L;
private int _magnificationIncrement = 10; // percent
protected int _currentZoom = 100;
private static final String _titleBarStartTxt = "PhotoSpread Zoom";
private ZoomMouseClickAndWheelListener _mouseHandler = null;
JPanel _panel = null;
JScrollPane _scrollPane = null;
JLabel _label = null;
ImageIcon _fullSizeImgIcon = null;
/****************************************************
* Constructor(s)
*****************************************************/
public Zoomer (ImageIcon icon) {
initZoomer(icon);
}
public Zoomer (String path) throws IOException {
File file = new File(path);
Image img = ImageIO.read(file);
initZoomer(new ImageIcon(img));
}
private void initZoomer (ImageIcon imgIcon) {
_fullSizeImgIcon = imgIcon;
this.setTitle(_titleBarStartTxt +
": Initial Size (" +
imgIcon.getIconWidth() +
"x" +
imgIcon.getIconHeight() +
"). Full size: " +
imgIcon.getImage().getWidth(null) +
"x" +
imgIcon.getImage().getHeight(null) +
".");
_panel = new JPanel();
_panel.setBackground(Color.BLACK);
_panel.setLayout(new BorderLayout());
_label = new JLabel(_fullSizeImgIcon);
_panel.add(_label, BorderLayout.CENTER);
_mouseHandler = new ZoomMouseClickAndWheelListener();
_panel.addMouseWheelListener(_mouseHandler);
_panel.addMouseListener(_mouseHandler);
_panel.addMouseMotionListener(_mouseHandler);
// _panel.setSize(...
// Make sure resources are deallocated
// when window is closed:
this.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
_scrollPane = new JScrollPane(_panel);
_scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
_scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
this.add(_scrollPane);
ZoomAction zoomUpAction = new ZoomUpAction();
ZoomAction zoomDownAction = new ZoomDownAction();
WindowCloseAction winCloseAction = new Misc().new WindowCloseAction(this);
Misc.bindKey(_panel, "control PLUS", zoomUpAction);
Misc.bindKey(_panel, "control EQUALS", zoomUpAction);
Misc.bindKey(_panel, "control shift EQUALS", zoomUpAction);
Misc.bindKey(_panel, "control MINUS", zoomDownAction);
Misc.bindKey(_panel, "control shift MINUS", zoomDownAction);
Misc.bindKey(this, "control W", winCloseAction);
Misc.bindKey(this, "F1", new ShowHelpAction(
"To do in Zoomer Window",
"HelpFiles/zoomerHelp.html",
this));
// Center the window on the screen.
this.setLocationRelativeTo(null);
this.setVisible(true);
pack();
addWindowListener(new ZoomWindowListener());
requestFocus();
}
/****************************************************
* Actions
*****************************************************/
abstract class ZoomAction extends AbstractAction implements ActionListener {
private static final long serialVersionUID = 1L;
protected boolean isShiftDown(ActionEvent e) {
return ((e.getModifiers() & ActionEvent.SHIFT_MASK) == ActionEvent.SHIFT_MASK);
}
public abstract void actionPerformed(ActionEvent e);
}
class ZoomUpAction extends ZoomAction {
private static final long serialVersionUID = 1L;
@Override
public void actionPerformed(ActionEvent e) {
_currentZoom += _magnificationIncrement;
if (isShiftDown(e))
percentScaleImage(_currentZoom, Const.EXPAND_WINDOW);
else
percentScaleImage(_currentZoom, Const.DONT_EXPAND_WINDOW);
}
}
class ZoomDownAction extends ZoomAction {
private static final long serialVersionUID = 1L;
@Override
public void actionPerformed(ActionEvent e) {
_currentZoom -= _magnificationIncrement;
if (isShiftDown(e))
percentScaleImage(_currentZoom, Const.EXPAND_WINDOW);
else
percentScaleImage(_currentZoom, Const.DONT_EXPAND_WINDOW);
}
}
/****************************************************
* ZoomMouseClickAndWheelListener (Inner) Class
*****************************************************/
private class ZoomMouseClickAndWheelListener extends MouseAdapter {
Point _cursorDownPoint = null;
private boolean isShiftDown (MouseWheelEvent e) {
return ((e.getModifiers() & ActionEvent.SHIFT_MASK) == ActionEvent.SHIFT_MASK);
}
public void mouseWheelMoved (MouseWheelEvent e) {
int notches = e.getWheelRotation();
if (notches > 0)
_currentZoom += _magnificationIncrement;
else
_currentZoom -= _magnificationIncrement;
if (isShiftDown(e))
percentScaleImage(_currentZoom, Const.EXPAND_WINDOW);
else
percentScaleImage(_currentZoom, Const.DONT_EXPAND_WINDOW);
}
public void mousePressed(MouseEvent e) {
if (e.getClickCount() == 2) {
resetImage();
return;
}
_cursorDownPoint = e.getPoint();
}
public void mouseReleased(MouseEvent e) {
_cursorDownPoint = null;
}
/* (non-Javadoc)
* @see java.awt.event.MouseAdapter#mouseDragged(java.awt.event.MouseEvent)
*/
public void mouseDragged (MouseEvent e) {
if (_cursorDownPoint == null)
return;
Point currCursorLoc = e.getPoint();
int deltaX = currCursorLoc.x - _cursorDownPoint.x;
int deltaY = currCursorLoc.y - _cursorDownPoint.y;
int currImgX = _label.getLocation().x;
int currImgY = _label.getLocation().y;
_label.setLocation(currImgX + deltaX, currImgY + deltaY);
_cursorDownPoint = currCursorLoc;
}
}
public class ZoomWindowListener extends WindowAdapter implements WindowListener {
/* (non-Javadoc)
* @see java.awt.event.WindowListener#windowActivated(java.awt.event.WindowEvent)
*/
@Override
public void windowActivated(WindowEvent arg0) {
// _panel.requestFocus();
}
/* (non-Javadoc)
* @see java.awt.event.WindowListener#windowDeiconified(java.awt.event.WindowEvent)
@Override
public void windowDeiconified(WindowEvent e) {
// TODO Auto-generated method stub
}
(non-Javadoc)
* @see java.awt.event.WindowListener#windowIconified(java.awt.event.WindowEvent)
@Override
public void windowIconified(WindowEvent e) {
// TODO Auto-generated method stub
}
(non-Javadoc)
* @see java.awt.event.WindowListener#windowOpened(java.awt.event.WindowEvent)
@Override
public void windowOpened(WindowEvent e) {
// TODO Auto-generated method stub
}
*/
}
/****************************************************
* Methods
*****************************************************/
/**
* Bind a key to an action. The binding will be
* active while the Workspace window is selected.
*
* @param keyDescription A string describing the key as
* per KeyStroke.getKeyStroke(String). Ex: "alt A" or "ctrl UP" (for up-arrow).
* Key names are the <keyName> part in VK_<keyName>
* @param action Action object to invoke when key is pressed.
*/
public void bindKey (String keyDescription, Action action) {
InputMap keyMap = _panel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
ActionMap actionMap = _panel.getActionMap();
keyMap.put(KeyStroke.getKeyStroke(keyDescription), keyDescription);
actionMap.put(keyDescription, action);
}
private static Double getAspectRatio (ImageIcon imgIcon) {
return new Double(imgIcon.getIconHeight()) / new Double(imgIcon.getIconWidth());
}
/**
* Given an image icon and a target width,
* return a new image icon with an image of
* the specified width, and proportionately
* scaled height.
* @param srcImgIcon
* @param newWidth Target width in pixels.
* @return
*/
private static Image getScaledImage(ImageIcon srcImgIcon, int newWidth){
Image srcImg = srcImgIcon.getImage();
Double aspectRatio = getAspectRatio(srcImgIcon);
int newHeight = new Double(newWidth * aspectRatio).intValue();
BufferedImage resizedImg = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_RGB);
Graphics2D g2 = resizedImg.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2.drawImage(srcImg, 0, 0, newWidth, newHeight, null);
g2.dispose();
return resizedImg;
}
/**
* Scale image to the given percentage while keeping the window size constant.
* @param targetPercentage Desired final percentage of image's original size.
*/
public void percentScaleImage (int targetPercentage) {
percentScaleImage(targetPercentage, Const.DONT_EXPAND_WINDOW);
}
/**
* Scale image to the given percentage. Caller chooses whether
* enclosing window is to grow with the resize, or not.
* @param targetPercentage Desired final percentage of image's original size.
* @param expandWindow If true then the surrounding window grows/shrinks with the
* enlargement/reduction
*/
public void percentScaleImage (int targetPercentage, boolean expandWindow) {
Image img = _fullSizeImgIcon.getImage();
ImageIcon imgIcon = new ImageIcon(img);
int width = imgIcon.getIconWidth();
int newWidth = new Double (width * targetPercentage / 100f).intValue();
imgIcon.setImage(getScaledImage(imgIcon, newWidth));
_panel.remove(_label);
_label = new JLabel(imgIcon);
_panel.add(_label);
if (expandWindow)
pack();
else
validate();
setTitle(_titleBarStartTxt +
": " +
targetPercentage +
"% of " +
_fullSizeImgIcon.getImage().getWidth(null) +
"x" +
_fullSizeImgIcon.getImage().getHeight(null) +
" (" +
imgIcon.getImage().getWidth(null) +
"x" +
imgIcon.getImage().getHeight(null) +
").");
}
private void resetImage () {
percentScaleImage(100);
_label.setLocation(0,0);
pack();
}
/****************************************************
* Testing Methods
*****************************************************/
/* public static void main (String args[]) {
ImageIcon icon = new ImageIcon(
"E:\\Users\\Paepcke\\dldev\\src\\PhotoSpreadTesting\\TestCases\\Photos\\airplaneInteriorWithEvacueesFacing.jpg");
Zoomer zoomer = new Zoomer(icon);
}*/
}