Crossfire JXClient, Trunk
DitherTest.java
Go to the documentation of this file.
1 /*
2  * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * - Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *
11  * - Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in the
13  * documentation and/or other materials provided with the distribution.
14  *
15  * - Neither the name of Oracle nor the names of its
16  * contributors may be used to endorse or promote products derived
17  * from this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
20  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
23  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
26  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
27  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
28  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 /*
33  * This source code is provided to illustrate the usage of a given feature
34  * or technique and has been deliberately simplified. Additional steps
35  * required for a production-quality application, such as security checks,
36  * input validation and proper error handling, might not be present in
37  * this sample code.
38  */
39 
40 
41 
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;
66 
67 
68 enum DitherMethod {
69 
70  NOOP, RED, GREEN, BLUE, ALPHA, SATURATION
71 };
72 
73 
74 @SuppressWarnings("serial")
75 public class DitherTest extends Applet implements Runnable {
76 
77  private Thread runner;
78  private DitherControls XControls;
79  private DitherControls YControls;
80  private DitherCanvas canvas;
81 
82  public static void main(String args[]) {
83  Frame f = new Frame("DitherTest");
84  DitherTest ditherTest = new DitherTest();
85  ditherTest.init();
86  f.add("Center", ditherTest);
87  f.pack();
88  f.setVisible(true);
89  ditherTest.start();
90  }
91 
92  @Override
93  public void init() {
94  String xspec = null, yspec = null;
95  int xvals[] = new int[2];
96  int yvals[] = new int[2];
97 
98  try {
99  xspec = getParameter("xaxis");
100  yspec = getParameter("yaxis");
101  } catch (NullPointerException ignored) {
102  //only occurs if run as application
103  }
104 
105  if (xspec == null) {
106  xspec = "red";
107  }
108  if (yspec == null) {
109  yspec = "blue";
110  }
111  DitherMethod xmethod = colorMethod(xspec, xvals);
112  DitherMethod ymethod = colorMethod(yspec, yvals);
113 
114  setLayout(new BorderLayout());
115  XControls = new DitherControls(this, xvals[0], xvals[1],
116  xmethod, false);
117  YControls = new DitherControls(this, yvals[0], yvals[1],
118  ymethod, true);
119  YControls.addRenderButton();
120  add("North", XControls);
121  add("South", YControls);
122  add("Center", canvas = new DitherCanvas());
123  }
124 
125  private DitherMethod colorMethod(String s, int vals[]) {
126  DitherMethod method = DitherMethod.NOOP;
127  if (s == null) {
128  s = "";
129  }
130  String lower = s.toLowerCase();
131 
132  for (DitherMethod m : DitherMethod.values()) {
133  if (lower.startsWith(m.toString().toLowerCase())) {
134  method = m;
135  lower = lower.substring(m.toString().length());
136  }
137  }
138  if (method == DitherMethod.NOOP) {
139  vals[0] = 0;
140  vals[1] = 0;
141  return method;
142  }
143  int begval = 0;
144  int endval = 255;
145  try {
146  int dash = lower.indexOf('-');
147  if (dash < 0) {
148  endval = Integer.parseInt(lower);
149  } else {
150  begval = Integer.parseInt(lower.substring(0, dash));
151  endval = Integer.parseInt(lower.substring(dash + 1));
152  }
153  } catch (NumberFormatException ignored) {
154  }
155 
156  if (begval < 0) {
157  begval = 0;
158  } else if (begval > 255) {
159  begval = 255;
160  }
161 
162  if (endval < 0) {
163  endval = 0;
164  } else if (endval > 255) {
165  endval = 255;
166  }
167 
168  vals[0] = begval;
169  vals[1] = endval;
170  return method;
171  }
172 
177  private Image calculateImage() {
178  Thread me = Thread.currentThread();
179 
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]; //temporarily holds R,G,B,A information
188  int index = 0;
189  for (int j = 0; j < height; j++) {
190  for (int i = 0; i < width; i++) {
191  c[0] = c[1] = c[2] = 0;
192  c[3] = 255;
193  if (xmethod < ymethod) {
194  applyMethod(c, xmethod, i, width, xvals);
195  applyMethod(c, ymethod, j, height, yvals);
196  } else {
197  applyMethod(c, ymethod, j, height, yvals);
198  applyMethod(c, xmethod, i, width, xvals);
199  }
200  pixels[index++] = ((c[3] << 24) | (c[0] << 16) | (c[1] << 8)
201  | c[2]);
202  }
203 
204  // Poll once per row to see if we've been told to stop.
205  if (runner != me) {
206  return null;
207  }
208  }
209  return createImage(new MemoryImageSource(width, height,
210  ColorModel.getRGBdefault(), pixels, 0, width));
211  }
212 
213  private void applyMethod(int c[], int methodIndex, int step,
214  int total, int vals[]) {
215  DitherMethod method = DitherMethod.values()[methodIndex];
216  if (method == DitherMethod.NOOP) {
217  return;
218  }
219  int val = ((total < 2)
220  ? vals[0]
221  : vals[0] + ((vals[1] - vals[0]) * step / (total - 1)));
222  switch (method) {
223  case RED:
224  c[0] = val;
225  break;
226  case GREEN:
227  c[1] = val;
228  break;
229  case BLUE:
230  c[2] = val;
231  break;
232  case ALPHA:
233  c[3] = val;
234  break;
235  case SATURATION:
236  int max = Math.max(Math.max(c[0], c[1]), c[2]);
237  int min = max * (255 - val) / 255;
238  if (c[0] == 0) {
239  c[0] = min;
240  }
241  if (c[1] == 0) {
242  c[1] = min;
243  }
244  if (c[2] == 0) {
245  c[2] = min;
246  }
247  break;
248  }
249  }
250 
251  @Override
252  public void start() {
253  runner = new Thread(this);
254  runner.start();
255  }
256 
257  @Override
258  public void run() {
259  canvas.setImage(null); // Wipe previous image
260  Image img = calculateImage();
261  if (img != null && runner == Thread.currentThread()) {
262  canvas.setImage(img);
263  }
264  }
265 
266  @Override
267  public void stop() {
268  runner = null;
269  }
270 
271  @Override
272  public void destroy() {
273  remove(XControls);
274  remove(YControls);
275  remove(canvas);
276  }
277 
278  @Override
279  public String getAppletInfo() {
280  return "An interactive demonstration of dithering.";
281  }
282 
283  @Override
284  public String[][] getParameterInfo() {
285  String[][] info = {
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." }
290  };
291  return info;
292  }
293 }
294 
295 
296 @SuppressWarnings("serial")
297 class DitherCanvas extends Canvas {
298 
299  private Image img;
300  private static String calcString = "Calculating...";
301 
302  @Override
303  public void paint(Graphics g) {
304  int w = getSize().width;
305  int h = getSize().height;
306  if (img == null) {
307  super.paint(g);
308  g.setColor(Color.black);
309  FontMetrics fm = g.getFontMetrics();
310  int x = (w - fm.stringWidth(calcString)) / 2;
311  int y = h / 2;
312  g.drawString(calcString, x, y);
313  } else {
314  g.drawImage(img, 0, 0, w, h, this);
315  }
316  }
317 
318  @Override
319  public void update(Graphics g) {
320  paint(g);
321  }
322 
323  @Override
324  public Dimension getMinimumSize() {
325  return new Dimension(20, 20);
326  }
327 
328  @Override
329  public Dimension getPreferredSize() {
330  return new Dimension(200, 200);
331  }
332 
333  public Image getImage() {
334  return img;
335  }
336 
337  public void setImage(Image img) {
338  this.img = img;
339  repaint();
340  }
341 }
342 
343 
344 @SuppressWarnings("serial")
345 class DitherControls extends Panel implements ActionListener {
346 
347  private CardinalTextField start;
348  private CardinalTextField end;
349  private Button button;
350  private Choice choice;
351  private DitherTest applet;
352  private static LayoutManager dcLayout = new FlowLayout(FlowLayout.CENTER,
353  10, 5);
354 
355  public DitherControls(DitherTest app, int s, int e, DitherMethod type,
356  boolean vertical) {
357  applet = app;
358  setLayout(dcLayout);
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());
364  }
365  choice.select(type.ordinal());
366  add(start = new CardinalTextField(Integer.toString(s), 4));
367  add(end = new CardinalTextField(Integer.toString(e), 4));
368  }
369 
370  /* puts on the button */
371  public void addRenderButton() {
372  add(button = new Button("New Image"));
373  button.addActionListener(this);
374  }
375 
376  /* retrieves data from the user input fields */
377  public int getParams(int vals[]) {
378  try {
379  vals[0] = scale(Integer.parseInt(start.getText()));
380  } catch (NumberFormatException nfe) {
381  vals[0] = 0;
382  }
383  try {
384  vals[1] = scale(Integer.parseInt(end.getText()));
385  } catch (NumberFormatException nfe) {
386  vals[1] = 255;
387  }
388  return choice.getSelectedIndex();
389  }
390 
391  /* fits the number between 0 and 255 inclusive */
392  private int scale(int number) {
393  if (number < 0) {
394  number = 0;
395  } else if (number > 255) {
396  number = 255;
397  }
398  return number;
399  }
400 
401  /* called when user clicks the button */
402  @Override
403  public void actionPerformed(ActionEvent e) {
404  if (e.getSource() == button) {
405  applet.start();
406  }
407  }
408 }
409 
410 
411 @SuppressWarnings("serial")
412 class CardinalTextField extends TextField {
413 
414  String oldText = null;
415 
416  public CardinalTextField(String text, int columns) {
417  super(text, columns);
418  enableEvents(AWTEvent.KEY_EVENT_MASK | AWTEvent.TEXT_EVENT_MASK);
419  oldText = getText();
420  }
421 
422  // Consume non-digit KeyTyped events
423  // Note that processTextEvent kind of eliminates the need for this
424  // function, but this is neater, since ideally, it would prevent
425  // the text from appearing at all. Sigh. See bugid 4100317/4114565.
426  //
427  @Override
428  protected void processEvent(AWTEvent evt) {
429  int id = evt.getID();
430  if (id != KeyEvent.KEY_TYPED) {
431  super.processEvent(evt);
432  return;
433  }
434 
435  KeyEvent kevt = (KeyEvent) evt;
436  char c = kevt.getKeyChar();
437 
438  // Digits, backspace, and delete are okay
439  // Note that the minus sign is not allowed (neither is decimal)
440  if (Character.isDigit(c) || (c == '\b') || (c == '\u007f')) {
441  super.processEvent(evt);
442  return;
443  }
444 
445  Toolkit.getDefaultToolkit().beep();
446  kevt.consume();
447  }
448 
449  // Should consume TextEvents for non-integer Strings
450  // Store away the text in the tf for every TextEvent
451  // so we can revert to it on a TextEvent (paste, or
452  // legal key in the wrong location) with bad text
453  //
454  // Note: it would be easy to extend this to an eight-bit
455  // TextField (range 0-255), but I'll leave it as-is.
456  //
457  @Override
458  protected void processTextEvent(TextEvent te) {
459  // The empty string is okay, too
460  String newText = getText();
461  if (newText.equals("") || textIsCardinal(newText)) {
462  oldText = newText;
463  super.processTextEvent(te);
464  return;
465  }
466 
467  Toolkit.getDefaultToolkit().beep();
468  setText(oldText);
469  }
470 
471  // Returns true for Cardinal (non-negative) numbers
472  // Note that the empty string is not allowed
473  private boolean textIsCardinal(String textToCheck) {
474  try {
475  return Integer.parseInt(textToCheck, 10) >= 0;
476  } catch (NumberFormatException nfe) {
477  return false;
478  }
479  }
480 }
DitherTest.calculateImage
Image calculateImage()
Definition: DitherTest.java:177
DitherTest.applyMethod
void applyMethod(int c[], int methodIndex, int step, int total, int vals[])
Definition: DitherTest.java:213
DitherTest.YControls
DitherControls YControls
Definition: DitherTest.java:79
DitherTest.runner
Thread runner
Definition: DitherTest.java:77
DitherTest.start
void start()
Definition: DitherTest.java:252
DitherTest.init
void init()
Definition: DitherTest.java:93
DitherTest
Definition: DitherTest.java:75
DitherTest.colorMethod
DitherMethod colorMethod(String s, int vals[])
Definition: DitherTest.java:125
DitherTest.stop
void stop()
Definition: DitherTest.java:267
DitherTest.main
static void main(String args[])
Definition: DitherTest.java:82
DitherTest.XControls
DitherControls XControls
Definition: DitherTest.java:78
DitherTest.getParameterInfo
String[][] getParameterInfo()
Definition: DitherTest.java:284
DitherTest.canvas
DitherCanvas canvas
Definition: DitherTest.java:80
DitherTest.run
void run()
Definition: DitherTest.java:258
DitherTest.getAppletInfo
String getAppletInfo()
Definition: DitherTest.java:279
DitherTest.destroy
void destroy()
Definition: DitherTest.java:272