package de.juwimm.cms.content.panel;
import static de.juwimm.cms.client.beans.Application.getBean;
import static de.juwimm.cms.common.Constants.rb;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Image;
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.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.image.renderable.ParameterBlock;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.ByteArrayOutputStream;
import java.text.NumberFormat;
import javax.media.jai.InterpolationBilinear;
import javax.media.jai.JAI;
import javax.media.jai.PlanarImage;
import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFormattedTextField;
import javax.swing.JLabel;
import javax.swing.JLayeredPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSpinner;
import javax.swing.SpinnerModel;
import javax.swing.SpinnerNumberModel;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.EventListenerList;
import org.apache.log4j.Logger;
import de.juwimm.cms.client.beans.Beans;
import de.juwimm.cms.content.frame.DlgSavePicture;
import de.juwimm.cms.util.Communication;
import de.juwimm.cms.util.UIConstants;
import de.juwimm.cms.vo.PictureSlimValue;
/**
* @author <a href="mailto:rene.hertzfeldt@juwimm.com">Rene Hertzfeldt</a>
* @version $Id: DlgPictureEditor.java 6 2009-07-30 14:05:05Z skulawik@gmail.com $
*/
public class PanPictureEditor extends JLayeredPane {
// to prevent a class not found exception
static {
System.setProperty("com.sun.media.jai.disableMediaLib", "true");
}
private static final long serialVersionUID = -4307149141989890380L;
private static Logger log = Logger.getLogger(PanPicture.class);
protected Communication comm = ((Communication) getBean(Beans.COMMUNICATION));
private PictureSlimValue picSlimVal;
private PlanarImage picture;
private PlanarImage scaledImage = null;
private PanDisplayJAIScrollable panImage = null;
private final JButton btnCrop = new JButton();
private final JButton btnOk = new JButton();
private final JButton btnCancel = new JButton();
private final JSpinner spnResizePercentalSize = new JSpinner();
private final JFormattedTextField txtResizeWidth = new JFormattedTextField(NumberFormat.getIntegerInstance());
private final JFormattedTextField txtResizeHeight = new JFormattedTextField(NumberFormat.getIntegerInstance());
private final JLabel lblResizeHeader = new JLabel();
private final JLabel lblResizePercentalSize = new JLabel();
private final JLabel lblResizeWidth = new JLabel();
private final JLabel lblResizeHeight = new JLabel();
private final JLabel lblCurrentSize = new JLabel();
private final JLabel lblSelectedSize = new JLabel();
private final JLabel lblMousePosition = new JLabel();
private final JPanel panPostions = new JPanel();
private final JPanel panButtons = new JPanel();
private final JPanel panResize = new JPanel();
private Point selectStart = null;
private Point selectEnd = null;
private Rectangle selection = null;
private enum ScaleKey {
WIDTH, HEIGHT, PERCENT
};
private boolean startedSizeCalculation = false;
private final EventListenerList cancelListenerList = new EventListenerList();
public PanPictureEditor(int pictureID) {
try {
loadPicture(pictureID);
init();
} catch (Exception ex) {
log.error("Error while starting PanPictureEditor.", ex);
}
}
private void loadPicture(int pic) {
try {
picSlimVal = comm.getPicture(pic);
byte[] picData = comm.getPictureData(pic);
Image img = new ImageIcon(picData).getImage();
ParameterBlock pb = new ParameterBlock();
pb.add(img);
picture = JAI.create("AWTImage", pb);
} catch (Exception ex) {
log.error("catched exception while loading ImagePreview of imageId: " + picture, ex);
}
}
private void init() throws Exception {
initPositionsPanel();
initResizePanel();
btnCrop.setMaximumSize(new Dimension(95, 27));
btnCrop.setMinimumSize(new Dimension(95, 27));
btnCrop.setPreferredSize(new Dimension(95, 27));
btnCrop.setToolTipText(rb.getString("panel.content.pictureEditor.btnCrop.tooltiptext"));
btnCrop.setText(rb.getString("panel.content.pictureEditor.btnCrop") + " ");
btnCrop.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
btnCropActionPerformed(e);
}
});
btnCrop.setEnabled(false);
btnOk.setMaximumSize(new Dimension(95, 27));
btnOk.setMinimumSize(new Dimension(95, 27));
btnOk.setPreferredSize(new Dimension(95, 27));
// btnOk.setToolTipText(rb.getString("panel.content.pictureEditor.btnOk.tooltiptext"));
btnOk.setText(rb.getString("dialog.saveItem.btnSave"));
btnOk.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
btnOkActionPerformed(e);
}
});
btnCancel.setMaximumSize(new Dimension(95, 27));
btnCancel.setMinimumSize(new Dimension(95, 27));
btnCancel.setPreferredSize(new Dimension(95, 27));
// btnCancel.setToolTipText(rb.getString("panel.content.pictureEditor.btnCancel.tooltiptext"));
btnCancel.setText(rb.getString("dialog.saveItem.btnCancel"));
btnCancel.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
btnCancelActionPerformed(e);
}
});
panButtons.setLayout(new GridBagLayout());
panButtons.setBorder(BorderFactory.createLoweredBevelBorder());
GridBagConstraints c = new GridBagConstraints();
c.fill = GridBagConstraints.HORIZONTAL;
c.gridx = 0;
c.gridy = 0;
c.anchor = GridBagConstraints.FIRST_LINE_END;
c.insets = new Insets(20, 10, 10, 10);
panButtons.add(btnCrop, c);
c.gridy = 1;
c.gridheight = 6;
c.insets = new Insets(10, 10, 100, 10);
panButtons.add(panResize, c);
c.gridy = 7;
c.gridheight = 1;
c.insets = new Insets(100, 10, 5, 10);
c.anchor = GridBagConstraints.LAST_LINE_END;
panButtons.add(btnOk, c);
c.gridy = 8;
c.insets = new Insets(5, 10, 20, 10);
panButtons.add(btnCancel, c);
panButtons.setMaximumSize(new Dimension(170, 600));
panButtons.setMinimumSize(new Dimension(170, 600));
panButtons.setPreferredSize(new Dimension(170, 600));
panImage = new PanDisplayJAIScrollable(picture, picture.getWidth() / 10);
panImage.addMouseListener(new MouseListener() {
public void mousePressed(MouseEvent e) {
if (picture.getBounds().contains(e.getX(), e.getY())) {
selectStart = new Point(e.getX(), e.getY());
selectEnd = new Point();
}
}
public void mouseReleased(MouseEvent e) {
calculateSelection();
if (selectStart != null) {
btnCrop.setEnabled(true);
}
}
public void mouseClicked(MouseEvent e) {
deleteSelection();
}
public void mouseEntered(MouseEvent e) {
}
public void mouseExited(MouseEvent e) {
calculateMousePosition(0, 0);
}
});
panImage.addMouseMotionListener(new MouseMotionListener() {
public void mouseDragged(MouseEvent e) {
if (picture.getBounds().contains(e.getX(), e.getY())) {
selectEnd.x = e.getX();
selectEnd.y = e.getY();
calculateSelection();
repaint();
}
}
public void mouseMoved(MouseEvent e) {
calculateMousePosition(e.getX(), e.getY());
}
});
JScrollPane spaRoot = new JScrollPane(panImage);
spaRoot.setMaximumSize(new Dimension(700, 400));
spaRoot.setMinimumSize(new Dimension(700, 400));
spaRoot.setPreferredSize(new Dimension(700, 400));
this.setLayout(new BorderLayout());
this.setBorder(BorderFactory.createLoweredBevelBorder());
this.add(panButtons, BorderLayout.EAST);
this.add(spaRoot, BorderLayout.CENTER);
this.add(panPostions, BorderLayout.SOUTH);
}
private void initPositionsPanel() {
lblCurrentSize.setText(rb.getString("panel.content.pictureEditor.imageSize") + " " + picture.getWidth() + " x " + picture.getHeight());
lblCurrentSize.setToolTipText(rb.getString("panel.content.pictureEditor.currentSize.toolTip"));
calculateMousePosition(0, 0);
lblMousePosition.setToolTipText(rb.getString("panel.content.pictureEditor.mousePosition.toolTip"));
lblMousePosition.setMaximumSize(new Dimension(150, 25));
lblMousePosition.setMinimumSize(new Dimension(150, 25));
lblMousePosition.setPreferredSize(new Dimension(150, 25));
calculateSelection();
lblSelectedSize.setToolTipText(rb.getString("panel.content.pictureEditor.selectedSize.toolTip"));
panPostions.setLayout(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
c.fill = GridBagConstraints.HORIZONTAL;
panPostions.setBorder(BorderFactory.createLoweredBevelBorder());
c.gridx = 0;
c.gridy = 0;
c.insets = new Insets(5, 20, 5, 75);
panPostions.add(lblMousePosition, c);
c.gridx = 1;
c.insets = new Insets(5, 75, 5, 75);
panPostions.add(lblSelectedSize, c);
c.gridx = 2;
c.insets = new Insets(5, 75, 5, 20);
panPostions.add(lblCurrentSize, c);
panPostions.setMaximumSize(new Dimension(800, 30));
panPostions.setMinimumSize(new Dimension(800, 30));
panPostions.setPreferredSize(new Dimension(800, 30));
}
private void initResizePanel() {
lblResizeHeader.setText(rb.getString("panel.content.pictureEditor.resize.header"));
SpinnerModel spnModel = new SpinnerNumberModel(100, 1, 100, 1);
spnResizePercentalSize.setModel(spnModel);
spnResizePercentalSize.setMaximumSize(new Dimension(100, 27));
spnResizePercentalSize.setMinimumSize(new Dimension(100, 27));
spnResizePercentalSize.setPreferredSize(new Dimension(100, 27));
spnResizePercentalSize.addChangeListener(new ChangeListener() {
public void stateChanged(ChangeEvent e) {
calculatePictureSize(ScaleKey.PERCENT, ((Integer) spnResizePercentalSize.getValue()).longValue());
}
});
lblResizePercentalSize.setText(rb.getString("panel.content.pictureEditor.resize.percent"));
lblResizePercentalSize.setToolTipText(rb.getString("panel.content.pictureEditor.resize.percent.toolTip"));
lblResizePercentalSize.setMaximumSize(new Dimension(50, 27));
lblResizePercentalSize.setMinimumSize(new Dimension(50, 27));
lblResizePercentalSize.setPreferredSize(new Dimension(50, 27));
lblResizeWidth.setText(rb.getString("panel.content.pictureEditor.resize.width"));
lblResizeWidth.setToolTipText(rb.getString("panel.content.pictureEditor.resize.widht.toolTip"));
lblResizeWidth.setMaximumSize(new Dimension(50, 27));
lblResizeWidth.setMinimumSize(new Dimension(50, 27));
lblResizeWidth.setPreferredSize(new Dimension(50, 27));
txtResizeWidth.setValue(picture.getWidth());
txtResizeWidth.addPropertyChangeListener("value", new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
calculatePictureSize(ScaleKey.WIDTH, (Long) evt.getNewValue());
}
});
txtResizeWidth.setMaximumSize(new Dimension(50, 27));
txtResizeWidth.setMinimumSize(new Dimension(50, 27));
txtResizeWidth.setPreferredSize(new Dimension(50, 27));
lblResizeHeight.setText(rb.getString("panel.content.pictureEditor.resize.height"));
lblResizeHeight.setToolTipText(rb.getString("panel.content.pictureEditor.resize.height.toolTip"));
lblResizeHeight.setMaximumSize(new Dimension(50, 27));
lblResizeHeight.setMinimumSize(new Dimension(50, 27));
lblResizeHeight.setPreferredSize(new Dimension(50, 27));
txtResizeHeight.setValue(picture.getHeight());
txtResizeHeight.addPropertyChangeListener("value", new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
calculatePictureSize(ScaleKey.HEIGHT, (Long) evt.getNewValue());
}
});
txtResizeHeight.setMaximumSize(new Dimension(50, 27));
txtResizeHeight.setMinimumSize(new Dimension(50, 27));
txtResizeHeight.setPreferredSize(new Dimension(50, 27));
panResize.setLayout(new GridLayout(2, 1));
//panResize.setBorder(BorderFactory.createLoweredBevelBorder());
panResize.add(lblResizeHeader);
JPanel innerPanel = new JPanel();
innerPanel.setLayout(new GridLayout(3, 2));
innerPanel.add(lblResizePercentalSize);
innerPanel.add(spnResizePercentalSize);
innerPanel.add(lblResizeWidth);
innerPanel.add(txtResizeWidth);
innerPanel.add(lblResizeHeight);
innerPanel.add(txtResizeHeight);
panResize.add(innerPanel);
panResize.setMaximumSize(new Dimension(150, 150));
panResize.setMinimumSize(new Dimension(150, 150));
panResize.setPreferredSize(new Dimension(150, 150));
}
private PlanarImage scalePreviewImage(float scale) {
ParameterBlock pb = new ParameterBlock();
pb.addSource(picture);
pb.add(scale);
pb.add(scale);
pb.add(0.0f);
pb.add(0.0f);
pb.add(new InterpolationBilinear());
return JAI.create("scale", pb);
}
private void calculatePictureSize(ScaleKey sk, long value) {
if (startedSizeCalculation) {
return;
}
startedSizeCalculation = true;
if (sk == ScaleKey.WIDTH) {
long newWidth = value;
if (newWidth > picture.getWidth()) {
newWidth = picture.getWidth();
txtResizeWidth.setValue(newWidth);
}
if (value == picture.getWidth()) {
scaledImage = null;
}
long newHeight = newWidth * picture.getHeight() / picture.getWidth();
txtResizeHeight.setValue(newHeight);
long newPercent = newHeight * 100 / picture.getHeight();
spnResizePercentalSize.setValue(new Long(newPercent).intValue());
}
if (sk == ScaleKey.HEIGHT) {
long newHeight = value;
if (newHeight > picture.getHeight()) {
newHeight = picture.getHeight();
txtResizeHeight.setValue(newHeight);
}
if (value == picture.getHeight()) {
scaledImage = null;
}
long newWidth = newHeight * picture.getWidth() / picture.getHeight();
txtResizeWidth.setValue(newWidth);
long newPercent = newWidth * 100 / picture.getWidth();
spnResizePercentalSize.setValue(new Long(newPercent).intValue());
}
if (sk == ScaleKey.PERCENT) {
if (value == 100) {
scaledImage = null;
}
txtResizeHeight.setValue((picture.getHeight() * value / 100));
txtResizeWidth.setValue((picture.getWidth() * value / 100));
}
Thread resizer = new Thread() {
@Override
public void run() {
PlanarImage img = scalePreviewImage(((Long) txtResizeWidth.getValue()).floatValue() / picture.getWidth());
panImage.set(img);
scaledImage = img;
deleteSelection();
}
};
resizer.start();
startedSizeCalculation = false;
}
private void resetSizes() {
lblCurrentSize.setText(rb.getString("panel.content.pictureEditor.imageSize") + " " + picture.getWidth() + " x " + picture.getHeight());
spnResizePercentalSize.setValue(100);
txtResizeHeight.setValue(new Integer(picture.getHeight()).longValue());
txtResizeWidth.setValue(new Integer(picture.getWidth()).longValue());
}
private PlanarImage cropPreviewImage() {
PlanarImage img;
ParameterBlock pb = new ParameterBlock();
pb.addSource(picture);
pb.add((float) selection.x);
pb.add((float) selection.y);
pb.add((float) selection.width);
pb.add((float) selection.height);
img = JAI.create("crop", pb, null);
// croped Image would stay at the same place like in the original
// image - upper left corner has to be reseted to zero
pb = new ParameterBlock();
pb.addSource(img);
pb.add(-((float) selection.x));
pb.add(-((float) selection.y));
return JAI.create("translate", pb, null);
}
private PlanarImage createThumbnail() {
if (picture.getHeight() <= 90) {
return picture;
}
//thumbnail height sould be 90
float scale = 90f / picture.getHeight();
return scalePreviewImage(scale);
}
private void calculateMousePosition(int x, int y) {
String text = new String(rb.getString("panel.content.pictureEditor.mousePosition") + " ");
if (!picture.getBounds().contains(x, y)) {
x = 0;
y = 0;
}
text = text + x + " : " + y;
lblMousePosition.setText(text);
}
private void calculateSelection() {
String text = new String(rb.getString("panel.content.pictureEditor.selected") + " ");
if (selectStart != null) {
int minX = (selectStart.x < selectEnd.x) ? selectStart.x : selectEnd.x;
int maxX = (selectStart.x == minX) ? selectEnd.x : selectStart.x;
int minY = (selectStart.y < selectEnd.y) ? selectStart.y : selectEnd.y;
int maxY = (selectStart.y != minY) ? selectStart.y : selectEnd.y;
text = text + (maxX - minX) + " x " + (maxY - minY);
selection = new Rectangle(minX, minY, maxX - minX, maxY - minY);
}
lblSelectedSize.setText(text);
}
private void deleteSelection() {
lblSelectedSize.setText(rb.getString("panel.content.pictureEditor.selected") + " ");
selectStart = null;
selectEnd = null;
selection = null;
btnCrop.setEnabled(false);
repaint();
}
private void btnCropActionPerformed(ActionEvent e) {
if (scaledImage != null) {
picture = scaledImage;
scaledImage = null;
}
PlanarImage croped = cropPreviewImage();
panImage.set(croped);
picture = croped;
deleteSelection();
resetSizes();
}
private byte[] planarImage2ByteArray(PlanarImage img) {
ByteArrayOutputStream out = new ByteArrayOutputStream();
JAI.create("encode", img, out, "PNG", null);
return out.toByteArray();
}
private void btnOkActionPerformed(ActionEvent e) {
if (scaledImage != null) {
picture = scaledImage;
}
DlgSavePicture saveDialog = new DlgSavePicture(picSlimVal, planarImage2ByteArray(picture), planarImage2ByteArray(createThumbnail()));
saveDialog.addSaveActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
fireSaveActionListener(ae);
}
});
int frameHeight = 180;
int frameWidth = 250;
saveDialog.setSize(frameWidth, frameHeight);
saveDialog.setLocationRelativeTo(UIConstants.getMainFrame());
saveDialog.setModal(true);
saveDialog.setVisible(true);
}
private void btnCancelActionPerformed(ActionEvent e) {
fireCancelActionListener(e);
}
public void addSaveActionListener(ActionListener al) {
this.listenerList.add(ActionListener.class, al);
}
public void fireSaveActionListener(ActionEvent e) {
Object[] listeners = listenerList.getListenerList();
for (int i = listeners.length - 2; i >= 0; i -= 2) {
((ActionListener) listeners[i + 1]).actionPerformed(e);
}
}
public void addCancelActionListener(ActionListener al) {
this.cancelListenerList.add(ActionListener.class, al);
}
public void fireCancelActionListener(ActionEvent e) {
Object[] listeners = cancelListenerList.getListenerList();
for (int i = listeners.length - 2; i >= 0; i -= 2) {
((ActionListener) listeners[i + 1]).actionPerformed(e);
}
}
@Override
public void paint(Graphics g) {
super.paint(g);
int offsetX = panImage.getVisibleRect().x;
int offsetY = panImage.getVisibleRect().y;
int thickness = 3;
if (selectStart != null) {
int x = selection.x - offsetX;
int y = selection.y - offsetY;
int width = (panImage.getVisibleRect().width - x < selection.width) ? panImage.getVisibleRect().width - x : selection.width;
int height = (panImage.getVisibleRect().height - y < selection.height) ? panImage.getVisibleRect().height - y : selection.height;
for (int i = 0; i < thickness; i++) {
g.drawRect(x + i, y + i, width, height);
}
}
}
}