package com.swingsane.gui.dialog;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics2D;
import java.awt.GraphicsEnvironment;
import java.awt.Insets;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.WindowConstants;
import javax.swing.border.EmptyBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import com.swingsane.business.image.transform.CropTransform;
import com.swingsane.business.image.transform.IImageTransform;
import com.swingsane.gui.panel.ITransformSettingsPanel;
import com.swingsane.i18n.Localizer;
/**
* @author Roland Quast (roland@formreturn.com)
*
*/
@SuppressWarnings("serial")
public class CropImageDialog extends JDialog implements ITransformSettingsPanel {
private final JPanel contentPanel = new JPanel();
private int dialogResult = JOptionPane.CANCEL_OPTION;
private static final int BOUNDS_WIDTH = 500;
private static final int BOUNDS_HEIGHT = 500;
private final Dimension minBounds = new Dimension(BOUNDS_WIDTH, BOUNDS_HEIGHT);
private CropTransform transform;
private ITransformSettingsPanel transformSettingsPanel;
private boolean hit = false;
private double zoom = -1.0d;
private Rectangle maximumWindowSize;
private BufferedImage sourceImage;
private JPanel cropPanel;
private JLabel imageLabel = new JLabel("", SwingConstants.LEFT);
private BufferedImage bufferedImage;
private ChangeListener transformListener;
private BufferedImage bufferedImageCopy;
public CropImageDialog(Component parent) {
initComponents();
pack();
}
private void addSettingsPanel() {
transformSettingsPanel = transform.getTransformSettingsPanel();
contentPanel.add((JPanel) transformSettingsPanel, BorderLayout.SOUTH);
}
private void cropSelectionRectangle() {
double width = sourceImage.getWidth();
double height = sourceImage.getHeight();
bufferedImage = new BufferedImage((int) (width * zoom), (int) (height * zoom),
BufferedImage.TYPE_INT_ARGB);
AffineTransform at = new AffineTransform();
at.scale(zoom, zoom);
AffineTransformOp scaleOp = new AffineTransformOp(at, AffineTransformOp.TYPE_BILINEAR);
bufferedImage = scaleOp.filter(sourceImage, bufferedImage);
bufferedImageCopy = new BufferedImage(bufferedImage.getWidth(), bufferedImage.getHeight(),
bufferedImage.getType());
imageLabel.setIcon(new ImageIcon(bufferedImageCopy));
repaint(bufferedImage, bufferedImageCopy);
imageLabel.repaint();
imageLabel.addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent me) {
Point point = me.getPoint();
translate(point);
if ((transform.getBounds() != null) && transform.getBounds().contains(point)) {
setHit(true);
} else {
setHit(false);
}
}
});
imageLabel.addMouseMotionListener(new MouseMotionAdapter() {
private Point start = new Point();
@Override
public void mouseDragged(MouseEvent me) {
Point end = me.getPoint();
translate(end);
int dx = end.x - start.x;
int dy = end.y - start.y;
if (hit) {
transform.getBounds().x += dx;
transform.getBounds().y += dy;
start = end;
} else {
transform.setBounds(new Rectangle(start, new Dimension(dx, dy)));
}
repaint(bufferedImage, bufferedImageCopy);
imageLabel.repaint();
restoreSettings();
((JPanel) transformSettingsPanel).revalidate();
((JPanel) transformSettingsPanel).repaint();
}
@Override
public void mouseMoved(MouseEvent me) {
start = me.getPoint();
translate(start);
repaint(bufferedImage, bufferedImageCopy);
imageLabel.repaint();
}
});
}
public final int getDialogResult() {
return dialogResult;
}
@Override
public final IImageTransform getTransform() {
return transform;
}
private Rectangle getTranslatedBounds(Rectangle bounds) {
Rectangle rect = new Rectangle();
rect.x = (int) (bounds.getX() * zoom);
rect.y = (int) (bounds.getY() * zoom);
rect.width = (int) (bounds.getWidth() * zoom);
rect.height = (int) (bounds.getHeight() * zoom);
return rect;
}
private void initComponents() {
setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
setTitle(Localizer.localize("CropImageDialogTitle"));
setMinimumSize(minBounds);
setMaximumWindowBounds();
getContentPane().setLayout(new BorderLayout());
contentPanel.setBorder(new EmptyBorder(12, 12, 0, 12));
getContentPane().add(contentPanel, BorderLayout.CENTER);
contentPanel.setLayout(new BorderLayout(0, 0));
{
JPanel buttonPane = new JPanel();
buttonPane.setBorder(new EmptyBorder(12, 12, 12, 12));
buttonPane.setLayout(new FlowLayout(FlowLayout.RIGHT));
getContentPane().add(buttonPane, BorderLayout.SOUTH);
{
JButton cropButton = new JButton(Localizer.localize("CropButtonText"));
cropButton.setIcon(new ImageIcon(CropImageDialog.class
.getResource("/com/famfamfam/silk/shape_handles.png")));
cropButton.setFont(UIManager.getFont("Button.font"));
cropButton.setMargin(new Insets(1, 5, 1, 5));
cropButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
dialogResult = JOptionPane.OK_OPTION;
dispose();
}
});
buttonPane.add(cropButton);
getRootPane().setDefaultButton(cropButton);
}
{
JButton cancelButton = new JButton(Localizer.localize("Cancel"));
cancelButton.setIcon(new ImageIcon(CropImageDialog.class
.getResource("/com/famfamfam/silk/cross.png")));
cancelButton.setFont(UIManager.getFont("Button.font"));
cancelButton.setMargin(new Insets(1, 5, 1, 5));
cancelButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
dispose();
}
});
buttonPane.add(cancelButton);
}
}
cropPanel = new JPanel(new BorderLayout());
cropPanel.addComponentListener(new ComponentAdapter() {
@Override
public void componentResized(ComponentEvent e) {
updateImage();
}
@Override
public void componentShown(ComponentEvent e) {
updateImage();
}
});
contentPanel.add(cropPanel, BorderLayout.CENTER);
cropPanel.add(imageLabel, BorderLayout.CENTER);
}
public final void loadImage() throws IOException {
setImage(ImageIO.read(transform.getSourceImageFile()));
}
private void repaint(BufferedImage orig, BufferedImage copy) {
Graphics2D g = copy.createGraphics();
g.drawImage(orig, 0, 0, null);
if (transform.getBounds() != null) {
Rectangle translatedBounds = getTranslatedBounds(transform.getBounds());
g.setColor(Color.BLUE);
g.draw(translatedBounds);
g.setColor(new Color(200, 200, 255, 150));
g.fill(translatedBounds);
}
g.dispose();
}
@Override
public final void restoreSettings() {
if ((transform == null) || (transformSettingsPanel == null)) {
return;
}
transformSettingsPanel.restoreSettings();
}
private void setHit(boolean hit) {
this.hit = hit;
}
private void setImage(final BufferedImage image) {
sourceImage = image;
}
private void setMaximumWindowBounds() {
GraphicsEnvironment graphicsEnvironment = GraphicsEnvironment.getLocalGraphicsEnvironment();
maximumWindowSize = graphicsEnvironment.getMaximumWindowBounds();
maximumWindowSize.height -= 50;
this.setBounds(maximumWindowSize);
Dimension bounds = maximumWindowSize.getSize();
setPreferredSize(bounds);
setSize(bounds);
}
@Override
public final void setTransform(IImageTransform transform) {
this.transform = (CropTransform) transform;
transformListener = new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
repaint(bufferedImage, bufferedImageCopy);
imageLabel.revalidate();
imageLabel.repaint();
}
});
}
};
this.transform.addChangeListener(transformListener);
addSettingsPanel();
}
private void translate(Point p) {
p.x = (int) (p.getX() / zoom);
p.y = (int) (p.getY() / zoom);
}
private void updateImage() {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
updateZoom(sourceImage.getWidth(), sourceImage.getHeight());
cropSelectionRectangle();
cropPanel.revalidate();
cropPanel.repaint();
}
});
}
private void updateZoom(int imageWidth, int imageHeight) {
Dimension viewSize = imageLabel.getSize();
if ((viewSize == null) || (viewSize.width == 0) || (viewSize.height == 0)) {
return;
}
double aspectRatio = (double) imageWidth / (double) imageHeight;
if (aspectRatio < 1) {
zoom = (double) viewSize.width / (double) imageWidth;
} else {
zoom = (double) viewSize.height / (double) imageHeight;
}
}
}