42 import java.applet.Applet;
43 import java.awt.AWTEvent;
44 import java.awt.BorderLayout;
45 import java.awt.Button;
46 import java.awt.Canvas;
47 import java.awt.Choice;
48 import java.awt.Color;
49 import java.awt.Dimension;
50 import java.awt.FlowLayout;
51 import java.awt.FontMetrics;
52 import java.awt.Frame;
53 import java.awt.Graphics;
54 import java.awt.Image;
55 import java.awt.Label;
56 import java.awt.LayoutManager;
57 import java.awt.Panel;
58 import java.awt.TextField;
59 import java.awt.Toolkit;
60 import java.awt.event.ActionEvent;
61 import java.awt.event.ActionListener;
62 import java.awt.event.KeyEvent;
63 import java.awt.event.TextEvent;
64 import java.awt.image.ColorModel;
65 import java.awt.image.MemoryImageSource;
70 NOOP, RED, GREEN, BLUE, ALPHA, SATURATION
74 @SuppressWarnings(
"serial")
75 public class
DitherTest extends Applet implements Runnable {
82 public static void main(String args[]) {
83 Frame f =
new Frame(
"DitherTest");
86 f.add(
"Center", ditherTest);
94 String xspec =
null, yspec =
null;
95 int xvals[] =
new int[2];
96 int yvals[] =
new int[2];
99 xspec = getParameter(
"xaxis");
100 yspec = getParameter(
"yaxis");
101 }
catch (NullPointerException ignored) {
111 DitherMethod xmethod = colorMethod(xspec, xvals);
112 DitherMethod ymethod = colorMethod(yspec, yvals);
114 setLayout(
new BorderLayout());
115 XControls =
new DitherControls(
this, xvals[0], xvals[1],
117 YControls =
new DitherControls(
this, yvals[0], yvals[1],
119 YControls.addRenderButton();
120 add(
"North", XControls);
121 add(
"South", YControls);
122 add(
"Center", canvas =
new DitherCanvas());
126 DitherMethod method = DitherMethod.NOOP;
130 String lower = s.toLowerCase();
132 for (DitherMethod m : DitherMethod.values()) {
133 if (lower.startsWith(m.toString().toLowerCase())) {
135 lower = lower.substring(m.toString().length());
138 if (method == DitherMethod.NOOP) {
146 int dash = lower.indexOf(
'-');
148 endval = Integer.parseInt(lower);
150 begval = Integer.parseInt(lower.substring(0, dash));
151 endval = Integer.parseInt(lower.substring(dash + 1));
153 }
catch (NumberFormatException ignored) {
158 }
else if (begval > 255) {
164 }
else if (endval > 255) {
178 Thread me = Thread.currentThread();
180 int width = canvas.getSize().width;
181 int height = canvas.getSize().height;
182 int xvals[] =
new int[2];
183 int yvals[] =
new int[2];
184 int xmethod = XControls.getParams(xvals);
185 int ymethod = YControls.getParams(yvals);
186 int pixels[] =
new int[width * height];
187 int c[] =
new int[4];
189 for (
int j = 0; j < height; j++) {
190 for (
int i = 0; i < width; i++) {
191 c[0] = c[1] = c[2] = 0;
193 if (xmethod < ymethod) {
194 applyMethod(c, xmethod, i, width, xvals);
195 applyMethod(c, ymethod, j, height, yvals);
197 applyMethod(c, ymethod, j, height, yvals);
198 applyMethod(c, xmethod, i, width, xvals);
200 pixels[index++] = ((c[3] << 24) | (c[0] << 16) | (c[1] << 8)
209 return createImage(
new MemoryImageSource(width, height,
210 ColorModel.getRGBdefault(), pixels, 0, width));
214 int total,
int vals[]) {
215 DitherMethod method = DitherMethod.values()[methodIndex];
216 if (method == DitherMethod.NOOP) {
219 int val = ((total < 2)
221 : vals[0] + ((vals[1] - vals[0]) * step / (total - 1)));
236 int max = Math.max(Math.max(c[0], c[1]), c[2]);
237 int min = max * (255 - val) / 255;
253 runner =
new Thread(
this);
259 canvas.setImage(
null);
260 Image img = calculateImage();
261 if (img !=
null && runner == Thread.currentThread()) {
262 canvas.setImage(img);
280 return "An interactive demonstration of dithering.";
286 {
"xaxis",
"{RED, GREEN, BLUE, ALPHA, SATURATION}",
287 "The color of the Y axis. Default is RED." },
288 {
"yaxis",
"{RED, GREEN, BLUE, ALPHA, SATURATION}",
289 "The color of the X axis. Default is BLUE." }
296 @SuppressWarnings(
"serial")
297 class DitherCanvas extends Canvas {
300 private static String calcString =
"Calculating...";
303 public void paint(Graphics g) {
304 int w = getSize().width;
305 int h = getSize().height;
308 g.setColor(Color.black);
309 FontMetrics fm = g.getFontMetrics();
310 int x = (w - fm.stringWidth(calcString)) / 2;
312 g.drawString(calcString, x, y);
314 g.drawImage(img, 0, 0, w, h,
this);
319 public void update(Graphics g) {
324 public Dimension getMinimumSize() {
325 return new Dimension(20, 20);
329 public Dimension getPreferredSize() {
330 return new Dimension(200, 200);
333 public Image getImage() {
337 public void setImage(Image img) {
344 @SuppressWarnings(
"serial")
345 class DitherControls extends Panel implements ActionListener {
347 private CardinalTextField start;
348 private CardinalTextField end;
349 private Button button;
350 private Choice choice;
352 private static LayoutManager dcLayout =
new FlowLayout(FlowLayout.CENTER,
355 public DitherControls(
DitherTest app,
int s,
int e, DitherMethod type,
359 add(
new Label(vertical ?
"Vertical" :
"Horizontal"));
360 add(choice =
new Choice());
361 for (DitherMethod m : DitherMethod.values()) {
362 choice.addItem(m.toString().substring(0, 1)
363 + m.toString().substring(1).toLowerCase());
365 choice.select(type.ordinal());
366 add(start =
new CardinalTextField(Integer.toString(s), 4));
367 add(end =
new CardinalTextField(Integer.toString(e), 4));
371 public void addRenderButton() {
372 add(button =
new Button(
"New Image"));
373 button.addActionListener(
this);
377 public int getParams(
int vals[]) {
379 vals[0] = scale(Integer.parseInt(start.getText()));
380 }
catch (NumberFormatException nfe) {
384 vals[1] = scale(Integer.parseInt(end.getText()));
385 }
catch (NumberFormatException nfe) {
388 return choice.getSelectedIndex();
392 private int scale(
int number) {
395 }
else if (number > 255) {
403 public void actionPerformed(ActionEvent e) {
404 if (e.getSource() == button) {
411 @SuppressWarnings(
"serial")
412 class CardinalTextField extends TextField {
414 String oldText =
null;
416 public CardinalTextField(String text,
int columns) {
417 super(text, columns);
418 enableEvents(AWTEvent.KEY_EVENT_MASK | AWTEvent.TEXT_EVENT_MASK);
428 protected void processEvent(AWTEvent evt) {
429 int id = evt.getID();
430 if (
id != KeyEvent.KEY_TYPED) {
431 super.processEvent(evt);
435 KeyEvent kevt = (KeyEvent) evt;
436 char c = kevt.getKeyChar();
440 if (Character.isDigit(c) || (c ==
'\b') || (c ==
'\u007f')) {
441 super.processEvent(evt);
445 Toolkit.getDefaultToolkit().beep();
458 protected void processTextEvent(TextEvent te) {
460 String newText = getText();
461 if (newText.equals(
"") || textIsCardinal(newText)) {
463 super.processTextEvent(te);
467 Toolkit.getDefaultToolkit().beep();
473 private boolean textIsCardinal(String textToCheck) {
475 return Integer.parseInt(textToCheck, 10) >= 0;
476 }
catch (NumberFormatException nfe) {