/*
* MedianCutDialog
*
* Copyright (c) 2001, 2002, 2003 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.gui.awt.dialogs;
import java.awt.BorderLayout;
import java.awt.Button;
import java.awt.Choice;
import java.awt.Dialog;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.GridLayout;
import java.awt.Label;
import java.awt.Panel;
import java.awt.Rectangle;
import java.awt.TextField;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import net.sourceforge.jiu.apps.Strings;
import net.sourceforge.jiu.color.dithering.ErrorDiffusionDithering;
import net.sourceforge.jiu.color.quantization.MedianCutQuantizer;
/**
* A dialog to enter the parameters for a Median Cut color quantization operation.
* It also allows to enter the optional algorithms that can be applied in combination with Median Cut.
* @author Marco Schmidt
*/
public class MedianCutDialog extends Dialog implements
ActionListener, ItemListener, KeyListener
{
public final int[][] METHODS =
{
{
MedianCutQuantizer.METHOD_REPR_COLOR_WEIGHTED_AVERAGE,
MedianCutQuantizer.METHOD_REPR_COLOR_AVERAGE,
MedianCutQuantizer.METHOD_REPR_COLOR_MEDIAN
},
{
Strings.METHOD_REPR_COLOR_WEIGHTED_AVERAGE,
Strings.METHOD_REPR_COLOR_AVERAGE,
Strings.METHOD_REPR_COLOR_MEDIAN
}
};
public final int[] ERROR_DIFFUSION_STRINGS =
{
Strings.FLOYD_STEINBERG_ERROR_DIFFUSION,
Strings.STUCKI_ERROR_DIFFUSION,
Strings.BURKES_ERROR_DIFFUSION,
Strings.SIERRA_ERROR_DIFFUSION,
Strings.JARVIS_JUDICE_NINKE_ERROR_DIFFUSION,
Strings.STEVENSON_ARCE_ERROR_DIFFUSION
};
public final int[] ERROR_DIFFUSION_TYPES =
{
ErrorDiffusionDithering.TYPE_FLOYD_STEINBERG,
ErrorDiffusionDithering.TYPE_STUCKI,
ErrorDiffusionDithering.TYPE_BURKES,
ErrorDiffusionDithering.TYPE_SIERRA,
ErrorDiffusionDithering.TYPE_JARVIS_JUDICE_NINKE,
ErrorDiffusionDithering.TYPE_STEVENSON_ARCE
};
private Button ok;
private Button cancel;
private TextField numColorsField;
private Choice outputColorType;
private Choice reprColorMethod;
private Choice algorithms;
private Choice errorDiffusion;
private TextField numPassesField;
private TextField tauField;
private boolean pressedOk;
/**
* Creates a modal dialog to enter the parameter.
* @param owner the parent of this modal dialog
* @param strings an object to get String constants in the current language
* @param numColors the number of colors in the resulting image
* @param representativeColorMethod the method to determine the representative color from a set of colors
* @param paletted if true, the output image will be paletted, otherwise truecolor
* @param numPasses number of contour removal iterations
* @param initialTau maximum distance for two colors to be considered similar in contour removal
*/
public MedianCutDialog(Frame owner, Strings strings, int numColors, int representativeColorMethod, boolean paletted, int numPasses, double initialTau)
{
super(owner, strings.get(Strings.MEDIAN_CUT_COLOR_QUANTIZATION), true);
pressedOk = false;
Panel panel = new Panel();
panel.setLayout(new GridLayout(0, 2));
panel.add(new Label(strings.get(Strings.NUM_COLORS)));
numColorsField = new TextField(Integer.toString(numColors), 6);
numColorsField.addKeyListener(this);
panel.add(numColorsField);
panel.add(new Label(strings.get(Strings.OUTPUT_COLOR_TYPE)));
outputColorType = new Choice();
outputColorType.add(strings.get(Strings.OUTPUT_COLOR_TYPE_PALETTED));
outputColorType.add(strings.get(Strings.OUTPUT_COLOR_TYPE_RGB));
outputColorType.select(paletted ? 0 : 1);
panel.add(outputColorType);
panel.add(new Label(strings.get(Strings.METHOD_REPR_COLOR)));
reprColorMethod = new Choice();
for (int i = 0; i < METHODS[0].length; i++)
{
reprColorMethod.add(strings.get(METHODS[1][i]));
if (representativeColorMethod == METHODS[0][i])
{
reprColorMethod.select(i);
}
}
panel.add(reprColorMethod);
panel.add(new Label(strings.get(Strings.OUTPUT_QUALITY_IMPROVEMENT_ALGORITHM)));
algorithms = new Choice();
algorithms.add(strings.get(Strings.ALGORITHMS_NONE));
algorithms.add(strings.get(Strings.ERROR_DIFFUSION));
algorithms.add(strings.get(Strings.CONTOUR_REMOVAL));
algorithms.select(1);
algorithms.addItemListener(this);
panel.add(algorithms);
panel.add(new Label(strings.get(Strings.ERROR_DIFFUSION)));
errorDiffusion = new Choice();
for (int i = 0; i < ERROR_DIFFUSION_STRINGS.length; i++)
{
errorDiffusion.add(strings.get(ERROR_DIFFUSION_STRINGS[i]));
}
errorDiffusion.select(0);
panel.add(errorDiffusion);
panel.add(new Label(strings.get(Strings.CONTOUR_REMOVAL_NUM_PASSES)));
numPassesField = new TextField(Integer.toString(numPasses));
numPassesField.addKeyListener(this);
panel.add(numPassesField);
panel.add(new Label(strings.get(Strings.CONTOUR_REMOVAL_TAU)));
tauField = new TextField(Double.toString(initialTau));
tauField.addKeyListener(this);
panel.add(tauField);
add(panel, BorderLayout.CENTER);
ok = new Button(strings.get(Strings.OK));
ok.addActionListener(this);
cancel = new Button(strings.get(Strings.CANCEL));
cancel.addActionListener(this);
updateStates();
panel = new Panel();
panel.add(ok);
panel.add(cancel);
add(panel, BorderLayout.SOUTH);
pack();
center();
}
/**
* Hides (closes) this dialog if the OK button was source of the action event
* (e.g. if the button was pressed).
*/
public void actionPerformed(ActionEvent e)
{
if (e.getSource() == ok)
{
pressedOk = true;
setVisible(false);
}
else
if (e.getSource() == cancel)
{
setVisible(false);
}
}
/**
* Centers the dialog on screen.
*/
public void center()
{
Rectangle rect = getBounds();
int width = rect.width;
int height = rect.height;
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
setLocation((screenSize.width / 2) - (width / 2),
(screenSize.height / 2) - (height / 2));
}
public int getErrorDiffusion()
{
if (algorithms.getSelectedIndex() == 1)
{
return ERROR_DIFFUSION_TYPES[errorDiffusion.getSelectedIndex()];
}
else
{
return -1;
}
}
private double getDoubleValue(TextField textField)
{
try
{
Double d = new Double(textField.getText());
return d.doubleValue();
}
catch (NumberFormatException nfe)
{
return Double.NaN;
}
}
private int getIntValue(TextField textField)
{
try
{
return Integer.parseInt(textField.getText());
}
catch (NumberFormatException nfe)
{
return -1;
}
}
public int getNumColors()
{
return getIntValue(numColorsField);
}
public int getNumPasses()
{
return getIntValue(numPassesField);
}
public int getReprColorMethod()
{
return METHODS[0][reprColorMethod.getSelectedIndex()];
}
public double getTau()
{
return getDoubleValue(tauField);
}
public boolean hasPressedOk()
{
return pressedOk;
}
public boolean isOutputTypePaletted()
{
return outputColorType.getSelectedIndex() == 0;
}
public void itemStateChanged(ItemEvent event)
{
if (event.getSource() == algorithms)
{
updateStates();
}
}
public void keyPressed(KeyEvent e)
{
updateOkButton();
}
public void keyReleased(KeyEvent e)
{
updateOkButton();
}
public void keyTyped(KeyEvent e)
{
updateOkButton();
}
private void updateOkButton()
{
int nc = getNumColors();
boolean enabled = nc >= 1 && nc <= 256;
if (enabled && algorithms.getSelectedIndex() == 2)
{
enabled = getTau() >= 0.0 && getNumPasses() >= 1;
}
ok.setEnabled(enabled);
}
private void updateStates()
{
int algorithmSelection = algorithms.getSelectedIndex();
boolean ed = algorithmSelection == 1;
errorDiffusion.setEnabled(ed);
ed = algorithmSelection == 2;
tauField.setEnabled(ed);
numPassesField.setEnabled(ed);
}
public boolean useContourRemoval()
{
return algorithms.getSelectedIndex() == 2;
}
public boolean useErrorDiffusion()
{
return algorithms.getSelectedIndex() == 1;
}
}