001 /* 002 * MedianCutDialog 003 * 004 * Copyright (c) 2001, 2002, 2003 Marco Schmidt. 005 * All rights reserved. 006 */ 007 008 package net.sourceforge.jiu.gui.awt.dialogs; 009 010 import java.awt.BorderLayout; 011 import java.awt.Button; 012 import java.awt.Choice; 013 import java.awt.Dialog; 014 import java.awt.Dimension; 015 import java.awt.Frame; 016 import java.awt.GridLayout; 017 import java.awt.Label; 018 import java.awt.Panel; 019 import java.awt.Rectangle; 020 import java.awt.TextField; 021 import java.awt.Toolkit; 022 import java.awt.event.ActionEvent; 023 import java.awt.event.ActionListener; 024 import java.awt.event.ItemEvent; 025 import java.awt.event.ItemListener; 026 import java.awt.event.KeyEvent; 027 import java.awt.event.KeyListener; 028 import net.sourceforge.jiu.apps.Strings; 029 import net.sourceforge.jiu.color.dithering.ErrorDiffusionDithering; 030 import net.sourceforge.jiu.color.quantization.MedianCutQuantizer; 031 032 /** 033 * A dialog to enter the parameters for a Median Cut color quantization operation. 034 * It also allows to enter the optional algorithms that can be applied in combination with Median Cut. 035 * @author Marco Schmidt 036 */ 037 public class MedianCutDialog extends Dialog implements 038 ActionListener, ItemListener, KeyListener 039 { 040 public final int[][] METHODS = 041 { 042 { 043 MedianCutQuantizer.METHOD_REPR_COLOR_WEIGHTED_AVERAGE, 044 MedianCutQuantizer.METHOD_REPR_COLOR_AVERAGE, 045 MedianCutQuantizer.METHOD_REPR_COLOR_MEDIAN 046 }, 047 { 048 Strings.METHOD_REPR_COLOR_WEIGHTED_AVERAGE, 049 Strings.METHOD_REPR_COLOR_AVERAGE, 050 Strings.METHOD_REPR_COLOR_MEDIAN 051 } 052 }; 053 public final int[] ERROR_DIFFUSION_STRINGS = 054 { 055 Strings.FLOYD_STEINBERG_ERROR_DIFFUSION, 056 Strings.STUCKI_ERROR_DIFFUSION, 057 Strings.BURKES_ERROR_DIFFUSION, 058 Strings.SIERRA_ERROR_DIFFUSION, 059 Strings.JARVIS_JUDICE_NINKE_ERROR_DIFFUSION, 060 Strings.STEVENSON_ARCE_ERROR_DIFFUSION 061 }; 062 public final int[] ERROR_DIFFUSION_TYPES = 063 { 064 ErrorDiffusionDithering.TYPE_FLOYD_STEINBERG, 065 ErrorDiffusionDithering.TYPE_STUCKI, 066 ErrorDiffusionDithering.TYPE_BURKES, 067 ErrorDiffusionDithering.TYPE_SIERRA, 068 ErrorDiffusionDithering.TYPE_JARVIS_JUDICE_NINKE, 069 ErrorDiffusionDithering.TYPE_STEVENSON_ARCE 070 }; 071 private Button ok; 072 private Button cancel; 073 private TextField numColorsField; 074 private Choice outputColorType; 075 private Choice reprColorMethod; 076 private Choice algorithms; 077 private Choice errorDiffusion; 078 private TextField numPassesField; 079 private TextField tauField; 080 private boolean pressedOk; 081 082 /** 083 * Creates a modal dialog to enter the parameter. 084 * @param owner the parent of this modal dialog 085 * @param strings an object to get String constants in the current language 086 * @param numColors the number of colors in the resulting image 087 * @param representativeColorMethod the method to determine the representative color from a set of colors 088 * @param paletted if true, the output image will be paletted, otherwise truecolor 089 * @param numPasses number of contour removal iterations 090 * @param initialTau maximum distance for two colors to be considered similar in contour removal 091 */ 092 public MedianCutDialog(Frame owner, Strings strings, int numColors, int representativeColorMethod, boolean paletted, int numPasses, double initialTau) 093 { 094 super(owner, strings.get(Strings.MEDIAN_CUT_COLOR_QUANTIZATION), true); 095 pressedOk = false; 096 097 Panel panel = new Panel(); 098 panel.setLayout(new GridLayout(0, 2)); 099 100 panel.add(new Label(strings.get(Strings.NUM_COLORS))); 101 numColorsField = new TextField(Integer.toString(numColors), 6); 102 numColorsField.addKeyListener(this); 103 panel.add(numColorsField); 104 105 panel.add(new Label(strings.get(Strings.OUTPUT_COLOR_TYPE))); 106 outputColorType = new Choice(); 107 outputColorType.add(strings.get(Strings.OUTPUT_COLOR_TYPE_PALETTED)); 108 outputColorType.add(strings.get(Strings.OUTPUT_COLOR_TYPE_RGB)); 109 outputColorType.select(paletted ? 0 : 1); 110 panel.add(outputColorType); 111 112 panel.add(new Label(strings.get(Strings.METHOD_REPR_COLOR))); 113 reprColorMethod = new Choice(); 114 for (int i = 0; i < METHODS[0].length; i++) 115 { 116 reprColorMethod.add(strings.get(METHODS[1][i])); 117 if (representativeColorMethod == METHODS[0][i]) 118 { 119 reprColorMethod.select(i); 120 } 121 } 122 panel.add(reprColorMethod); 123 124 panel.add(new Label(strings.get(Strings.OUTPUT_QUALITY_IMPROVEMENT_ALGORITHM))); 125 algorithms = new Choice(); 126 algorithms.add(strings.get(Strings.ALGORITHMS_NONE)); 127 algorithms.add(strings.get(Strings.ERROR_DIFFUSION)); 128 algorithms.add(strings.get(Strings.CONTOUR_REMOVAL)); 129 algorithms.select(1); 130 algorithms.addItemListener(this); 131 panel.add(algorithms); 132 133 panel.add(new Label(strings.get(Strings.ERROR_DIFFUSION))); 134 errorDiffusion = new Choice(); 135 for (int i = 0; i < ERROR_DIFFUSION_STRINGS.length; i++) 136 { 137 errorDiffusion.add(strings.get(ERROR_DIFFUSION_STRINGS[i])); 138 } 139 errorDiffusion.select(0); 140 panel.add(errorDiffusion); 141 142 panel.add(new Label(strings.get(Strings.CONTOUR_REMOVAL_NUM_PASSES))); 143 numPassesField = new TextField(Integer.toString(numPasses)); 144 numPassesField.addKeyListener(this); 145 panel.add(numPassesField); 146 147 panel.add(new Label(strings.get(Strings.CONTOUR_REMOVAL_TAU))); 148 tauField = new TextField(Double.toString(initialTau)); 149 tauField.addKeyListener(this); 150 panel.add(tauField); 151 152 add(panel, BorderLayout.CENTER); 153 154 ok = new Button(strings.get(Strings.OK)); 155 ok.addActionListener(this); 156 cancel = new Button(strings.get(Strings.CANCEL)); 157 cancel.addActionListener(this); 158 159 updateStates(); 160 161 panel = new Panel(); 162 panel.add(ok); 163 panel.add(cancel); 164 add(panel, BorderLayout.SOUTH); 165 166 pack(); 167 center(); 168 } 169 170 /** 171 * Hides (closes) this dialog if the OK button was source of the action event 172 * (e.g. if the button was pressed). 173 */ 174 public void actionPerformed(ActionEvent e) 175 { 176 if (e.getSource() == ok) 177 { 178 pressedOk = true; 179 setVisible(false); 180 } 181 else 182 if (e.getSource() == cancel) 183 { 184 setVisible(false); 185 } 186 } 187 188 /** 189 * Centers the dialog on screen. 190 */ 191 public void center() 192 { 193 Rectangle rect = getBounds(); 194 int width = rect.width; 195 int height = rect.height; 196 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); 197 setLocation((screenSize.width / 2) - (width / 2), 198 (screenSize.height / 2) - (height / 2)); 199 } 200 201 public int getErrorDiffusion() 202 { 203 if (algorithms.getSelectedIndex() == 1) 204 { 205 return ERROR_DIFFUSION_TYPES[errorDiffusion.getSelectedIndex()]; 206 } 207 else 208 { 209 return -1; 210 } 211 } 212 213 private double getDoubleValue(TextField textField) 214 { 215 try 216 { 217 Double d = new Double(textField.getText()); 218 return d.doubleValue(); 219 } 220 catch (NumberFormatException nfe) 221 { 222 return Double.NaN; 223 } 224 } 225 226 227 private int getIntValue(TextField textField) 228 { 229 try 230 { 231 return Integer.parseInt(textField.getText()); 232 } 233 catch (NumberFormatException nfe) 234 { 235 return -1; 236 } 237 } 238 239 public int getNumColors() 240 { 241 return getIntValue(numColorsField); 242 } 243 244 public int getNumPasses() 245 { 246 return getIntValue(numPassesField); 247 } 248 249 public int getReprColorMethod() 250 { 251 return METHODS[0][reprColorMethod.getSelectedIndex()]; 252 } 253 254 public double getTau() 255 { 256 return getDoubleValue(tauField); 257 } 258 259 public boolean hasPressedOk() 260 { 261 return pressedOk; 262 } 263 264 public boolean isOutputTypePaletted() 265 { 266 return outputColorType.getSelectedIndex() == 0; 267 } 268 269 public void itemStateChanged(ItemEvent event) 270 { 271 if (event.getSource() == algorithms) 272 { 273 updateStates(); 274 } 275 } 276 277 public void keyPressed(KeyEvent e) 278 { 279 updateOkButton(); 280 } 281 282 public void keyReleased(KeyEvent e) 283 { 284 updateOkButton(); 285 } 286 287 public void keyTyped(KeyEvent e) 288 { 289 updateOkButton(); 290 } 291 292 private void updateOkButton() 293 { 294 int nc = getNumColors(); 295 boolean enabled = nc >= 1 && nc <= 256; 296 if (enabled && algorithms.getSelectedIndex() == 2) 297 { 298 enabled = getTau() >= 0.0 && getNumPasses() >= 1; 299 } 300 ok.setEnabled(enabled); 301 } 302 303 private void updateStates() 304 { 305 int algorithmSelection = algorithms.getSelectedIndex(); 306 boolean ed = algorithmSelection == 1; 307 errorDiffusion.setEnabled(ed); 308 ed = algorithmSelection == 2; 309 tauField.setEnabled(ed); 310 numPassesField.setEnabled(ed); 311 } 312 313 public boolean useContourRemoval() 314 { 315 return algorithms.getSelectedIndex() == 2; 316 } 317 318 public boolean useErrorDiffusion() 319 { 320 return algorithms.getSelectedIndex() == 1; 321 } 322 }