package cz.matejsimek.scup;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.awt.image.BufferedImage;
import java.util.concurrent.CountDownLatch;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.KeyStroke;
/**
* Display given image and crop it to user selected area (by mouse drag)
*
* @author Matej Simek | www.matejsimek.cz
*/
public class FullscreenFrame extends JFrame {
private CountDownLatch run;
private BufferedImage image;
private int imageWidth, imageHeight;
private Point startPoint = new Point();
private Point endPoint = new Point();
private Point oldPoint = new Point();
private Rectangle selectedRectangle = new Rectangle();
private Rectangle areaRectangle;
private boolean isCropped = false;
/**
* Initialize frame
*
* @param run for block calling Thread until frame is finished
* @param image image to display and crop
*/
public FullscreenFrame(CountDownLatch run, BufferedImage image) {
this.run = run;
this.image = image;
imageWidth = image.getWidth();
imageHeight = image.getHeight();
areaRectangle = new Rectangle(0, 0, imageWidth - 1, imageHeight - 1);
// Set frame parameteres
setAlwaysOnTop(true);
setUndecorated(true);
setExtendedState(MAXIMIZED_BOTH);
setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));
// Detect mouse events (for crop area)
addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e) {
startPoint = endPoint = oldPoint = e.getPoint();
repaint();
}
public void mouseReleased(MouseEvent e) {
crop();
setVisible(false);
}
});
addMouseMotionListener(new MouseMotionAdapter() {
public void mouseDragged(MouseEvent e) {
// Move with whole rectangle with CTRL key
if (e.isControlDown()) {
int xmove = oldPoint.x - e.getPoint().x;
int ymove = oldPoint.y - e.getPoint().y;
startPoint.x -= xmove;
startPoint.y -= ymove;
endPoint.x -= xmove;
endPoint.y -= ymove;
oldPoint = e.getPoint();
} // Move with endpoint
else {
endPoint = e.getPoint();
oldPoint = endPoint;
}
repaint();
}
});
// Close the frame when the user presses escape
KeyStroke escapeKeyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0, false);
Action escapeAction = new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
setVisible(false);
}
};
getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(escapeKeyStroke, "ESCAPE");
getRootPane().getActionMap().put("ESCAPE", escapeAction);
setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
}
/**
*
* @return cropped or original image
*/
public BufferedImage getCroppedImage() {
return image;
}
/**
* Paint image, yellow window border and user selected area
*
* @param g Graphics
*/
@Override
public void paint(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
g2d.drawImage(image, null, 0, 0);
if (startPoint.x != endPoint.x || startPoint.y != endPoint.y) {
int x1 = (startPoint.x < endPoint.x) ? startPoint.x : endPoint.x;
int y1 = (startPoint.y < endPoint.y) ? startPoint.y : endPoint.y;
int x2 = (startPoint.x > endPoint.x) ? startPoint.x : endPoint.x;
int y2 = (startPoint.y > endPoint.y) ? startPoint.y : endPoint.y;
selectedRectangle.x = x1;
selectedRectangle.y = y1;
selectedRectangle.width = (x2 - x1) + 1;
selectedRectangle.height = (y2 - y1) + 1;
g2d.draw(selectedRectangle);
}
g2d.setColor(Color.YELLOW);
g2d.draw(areaRectangle);
}
/**
* Behavior like
* <code>{@link JFrame}.setVisible(boolean b)</code>, but with onhide
* CountDownLatch release
*
* @param b if false unblock CountDownLatch and hide itself
*/
@Override
public void setVisible(boolean b) {
super.setVisible(b);
if (!b) {
run.countDown();
}
}
/**
*
* @return true if user already cropped image
*/
public boolean isImageCropped() {
return isCropped;
}
/**
* Crop image from startPoint to endPoint and set flag isCropped
*/
public void crop() {
if (startPoint.equals(endPoint)) {
setVisible(false);
}
int x1 = (startPoint.x < endPoint.x) ? startPoint.x : endPoint.x;
int y1 = (startPoint.y < endPoint.y) ? startPoint.y : endPoint.y;
int x2 = (startPoint.x > endPoint.x) ? startPoint.x : endPoint.x;
int y2 = (startPoint.y > endPoint.y) ? startPoint.y : endPoint.y;
int width = (x2 - x1) + 1;
int height = (y2 - y1) + 1;
BufferedImage croppedImage = image.getSubimage(x1, y1, width, height);
image.flush();
image = croppedImage;
croppedImage = null;
isCropped = true;
}
}