KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > DitherTest


1 /*
2  * @(#)DitherTest.java 1.17 06/02/22
3  *
4  * Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are met:
8  *
9  * -Redistribution of source code must retain the above copyright notice, this
10  * list of conditions and the following disclaimer.
11  *
12  * -Redistribution in binary form must reproduce the above copyright notice,
13  * this list of conditions and the following disclaimer in the documentation
14  * and/or other materials provided with the distribution.
15  *
16  * Neither the name of Sun Microsystems, Inc. or the names of contributors may
17  * be used to endorse or promote products derived from this software without
18  * specific prior written permission.
19  *
20  * This software is provided "AS IS," without a warranty of any kind. ALL
21  * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING
22  * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
23  * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN")
24  * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE
25  * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
26  * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST
27  * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL,
28  * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY
29  * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
30  * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
31  *
32  * You acknowledge that this software is not designed, licensed or intended
33  * for use in the design, construction, operation or maintenance of any
34  * nuclear facility.
35  */

36
37 /*
38  * @(#)DitherTest.java 1.17 06/02/22
39  */

40
41 import java.applet.Applet JavaDoc;
42 import java.awt.event.*;
43 import java.awt.*;
44 import java.awt.image.ColorModel JavaDoc;
45 import java.awt.image.MemoryImageSource JavaDoc;
46
47 public class DitherTest extends Applet JavaDoc implements Runnable JavaDoc {
48     final private static int NOOP = 0;
49     final private static int RED = 1;
50     final private static int GREEN = 2;
51     final private static int BLUE = 3;
52     final private static int ALPHA = 4;
53     final private static int SATURATION = 5;
54
55     private Thread JavaDoc runner;
56
57     private DitherControls XControls;
58     private DitherControls YControls;
59     private DitherCanvas canvas;
60
61     public static void main(String JavaDoc args[]) {
62         Frame f = new Frame("DitherTest");
63         DitherTest ditherTest = new DitherTest();
64         ditherTest.init();
65         f.add("Center", ditherTest);
66         f.pack();
67         f.setVisible(true);
68         ditherTest.start();
69     }
70
71     public void init() {
72         String JavaDoc xspec = null, yspec = null;
73         int xvals[] = new int[2];
74         int yvals[] = new int[2];
75         
76         try {
77             xspec = getParameter("xaxis");
78             yspec = getParameter("yaxis");
79         } catch (NullPointerException JavaDoc npe) {
80             //only occurs if run as application
81
}
82         
83         if (xspec == null) {
84             xspec = "red";
85         }
86         if (yspec == null) {
87             yspec = "blue";
88         }
89         int xmethod = colormethod(xspec, xvals);
90         int ymethod = colormethod(yspec, yvals);
91
92         setLayout(new BorderLayout());
93         XControls = new DitherControls(this, xvals[0], xvals[1],
94                                        xmethod, false);
95         YControls = new DitherControls(this, yvals[0], yvals[1],
96                                        ymethod, true);
97         YControls.addRenderButton();
98         add("North", XControls);
99         add("South", YControls);
100         add("Center", canvas = new DitherCanvas());
101     }
102
103     private int colormethod(String JavaDoc s, int vals[]) {
104         int method = NOOP;
105         if (s == null) {
106             s = "";
107         }
108         String JavaDoc lower = s.toLowerCase();
109         int len = 0;
110         if (lower.startsWith("red")) {
111             method = RED;
112             lower = lower.substring(3);
113         } else if (lower.startsWith("green")) {
114             method = GREEN;
115             lower = lower.substring(5);
116         } else if (lower.startsWith("blue")) {
117             method = BLUE;
118             lower = lower.substring(4);
119         } else if (lower.startsWith("alpha")) {
120             method = ALPHA;
121             lower = lower.substring(5);
122         } else if (lower.startsWith("saturation")) {
123             method = SATURATION;
124             lower = lower.substring(10);
125         }
126         if (method == NOOP) {
127             vals[0] = 0;
128             vals[1] = 0;
129             return method;
130         }
131         int begval = 0;
132         int endval = 255;
133         try {
134             int dash = lower.indexOf('-');
135             if (dash < 0) {
136                 endval = Integer.parseInt(lower);
137             } else {
138                 begval = Integer.parseInt(lower.substring(0, dash));
139                 endval = Integer.parseInt(lower.substring(dash + 1));
140             }
141         } catch (NumberFormatException JavaDoc nfe) {
142         }
143
144         if (begval < 0) {
145             begval = 0;
146         } else if (begval > 255) {
147             begval = 255;
148         }
149         
150         if (endval < 0) {
151             endval = 0;
152         } else if (endval > 255) {
153             endval = 255;
154         }
155
156         vals[0] = begval;
157         vals[1] = endval;
158         return method;
159     }
160
161     /**
162      * Calculates and returns the image. Halts the calculation and returns
163      * null if the Applet is stopped during the calculation.
164      */

165     private Image calculateImage() {
166         Thread JavaDoc me = Thread.currentThread();
167         
168         int width = canvas.getSize().width;
169         int height = canvas.getSize().height;
170         int xvals[] = new int[2];
171         int yvals[] = new int[2];
172         int xmethod = XControls.getParams(xvals);
173         int ymethod = YControls.getParams(yvals);
174         int pixels[] = new int[width * height];
175         int c[] = new int[4]; //temporarily holds R,G,B,A information
176
int index = 0;
177         for (int j = 0; j < height; j++) {
178             for (int i = 0; i < width; i++) {
179                 c[0] = c[1] = c[2] = 0;
180                 c[3] = 255;
181                 if (xmethod < ymethod) {
182                     applymethod(c, xmethod, i, width, xvals);
183                     applymethod(c, ymethod, j, height, yvals);
184                 } else {
185                     applymethod(c, ymethod, j, height, yvals);
186                     applymethod(c, xmethod, i, width, xvals);
187                 }
188                 pixels[index++] = ((c[3] << 24) |
189                                    (c[0] << 16) |
190                                    (c[1] << 8) |
191                                    c[2]);
192             }
193
194             // Poll once per row to see if we've been told to stop.
195
if (runner != me) {
196                 return null;
197             }
198         }
199         return createImage(new MemoryImageSource JavaDoc(width, height,
200                             ColorModel.getRGBdefault(), pixels, 0, width));
201     }
202
203     private void applymethod(int c[], int method, int step,
204                              int total, int vals[]) {
205         if (method == NOOP) {
206             return;
207         }
208         int val = ((total < 2)
209                    ? vals[0]
210                    : vals[0] + ((vals[1] - vals[0]) * step / (total - 1)));
211         switch (method) {
212         case RED:
213             c[0] = val;
214             break;
215         case GREEN:
216             c[1] = val;
217             break;
218         case BLUE:
219             c[2] = val;
220             break;
221         case ALPHA:
222             c[3] = val;
223             break;
224         case SATURATION:
225             int max = Math.max(Math.max(c[0], c[1]), c[2]);
226             int min = max * (255 - val) / 255;
227             if (c[0] == 0) {
228                 c[0] = min;
229             }
230             if (c[1] == 0) {
231                 c[1] = min;
232             }
233             if (c[2] == 0) {
234                 c[2] = min;
235             }
236             break;
237         }
238     }
239
240     public void start() {
241         runner = new Thread JavaDoc(this);
242         runner.start();
243     }
244
245     public void run() {
246         canvas.setImage(null); // Wipe previous image
247
Image img = calculateImage();
248         if (img != null && runner == Thread.currentThread()) {
249             canvas.setImage(img);
250         }
251     }
252
253     public void stop() {
254         runner = null;
255     }
256
257     public void destroy() {
258         remove(XControls);
259         remove(YControls);
260         remove(canvas);
261     }
262
263     public String JavaDoc getAppletInfo() {
264         return "An interactive demonstration of dithering.";
265     }
266
267     public String JavaDoc[][] getParameterInfo() {
268         String JavaDoc[][] info = {
269             {"xaxis", "{RED, GREEN, BLUE, ALPHA, SATURATION}",
270              "The color of the Y axis. Default is RED."},
271             {"yaxis", "{RED, GREEN, BLUE, ALPHA, SATURATION}",
272              "The color of the X axis. Default is BLUE."}
273         };
274         return info;
275     }
276 }
277
278 class DitherCanvas extends Canvas {
279     private Image img;
280     private static String JavaDoc calcString = "Calculating...";
281
282     public void paint(Graphics g) {
283         int w = getSize().width;
284         int h = getSize().height;
285         if (img == null) {
286             super.paint(g);
287             g.setColor(Color.black);
288             FontMetrics fm = g.getFontMetrics();
289             int x = (w - fm.stringWidth(calcString)) / 2;
290             int y = h / 2;
291             g.drawString(calcString, x, y);
292         } else {
293             g.drawImage(img, 0, 0, w, h, this);
294         }
295     }
296
297     public void update(Graphics g) {
298         paint(g);
299     }
300
301     public Dimension getMinimumSize() {
302         return new Dimension(20, 20);
303     }
304
305     public Dimension getPreferredSize() {
306         return new Dimension(200, 200);
307     }
308
309     public Image getImage() {
310         return img;
311     }
312
313     public void setImage(Image img) {
314         this.img = img;
315         repaint();
316     }
317 }
318
319 class DitherControls extends Panel implements ActionListener {
320     private CardinalTextField start;
321     private CardinalTextField end;
322     private Button button;
323     private Choice choice;
324     private DitherTest applet;
325
326     private static LayoutManager dcLayout = new FlowLayout(FlowLayout.CENTER,
327                                                            10, 5);
328
329     public DitherControls(DitherTest app, int s, int e, int type,
330                           boolean vertical) {
331         applet = app;
332         setLayout(dcLayout);
333         add(new Label(vertical ? "Vertical" : "Horizontal"));
334         add(choice = new Choice());
335         choice.addItem("Noop");
336         choice.addItem("Red");
337         choice.addItem("Green");
338         choice.addItem("Blue");
339         choice.addItem("Alpha");
340         choice.addItem("Saturation");
341         choice.select(type);
342         add(start = new CardinalTextField(Integer.toString(s), 4));
343         add(end = new CardinalTextField(Integer.toString(e), 4));
344     }
345
346     /* puts on the button */
347     public void addRenderButton() {
348         add(button = new Button("New Image"));
349         button.addActionListener(this);
350     }
351
352     /* retrieves data from the user input fields */
353     public int getParams(int vals[]) {
354         try {
355             vals[0] = scale(Integer.parseInt(start.getText()));
356         } catch (NumberFormatException JavaDoc nfe) {
357             vals[0] = 0;
358         }
359         try {
360             vals[1] = scale(Integer.parseInt(end.getText()));
361         } catch (NumberFormatException JavaDoc nfe) {
362             vals[1] = 255;
363         }
364         return choice.getSelectedIndex();
365     }
366     
367     /* fits the number between 0 and 255 inclusive */
368     private int scale(int number) {
369         if (number < 0) {
370             number = 0;
371         } else if (number > 255) {
372             number = 255;
373         }
374         return number;
375     }
376
377     /* called when user clicks the button */
378     public void actionPerformed(ActionEvent e) {
379         if (e.getSource() == button) {
380             applet.start();
381         }
382     }
383 }
384
385 class CardinalTextField extends TextField {
386
387     String JavaDoc oldText = null;
388
389     public CardinalTextField(String JavaDoc text, int columns) {
390         super(text, columns);
391         enableEvents(AWTEvent.KEY_EVENT_MASK | AWTEvent.TEXT_EVENT_MASK);
392         oldText = getText();
393     }
394
395     // Consume non-digit KeyTyped events
396
// Note that processTextEvent kind of eliminates the need for this
397
// function, but this is neater, since ideally, it would prevent
398
// the text from appearing at all. Sigh. See bugid 4100317/4114565.
399
//
400
protected void processEvent(AWTEvent evt) {
401         int id = evt.getID();
402         if (id != KeyEvent.KEY_TYPED) {
403             super.processEvent(evt);
404             return;
405         }
406
407         KeyEvent kevt = (KeyEvent) evt;
408         char c = kevt.getKeyChar();
409
410         // Digits, backspace, and delete are okay
411
// Note that the minus sign is not allowed (neither is decimal)
412
if (Character.isDigit(c) || (c == '\b') || (c == '\u007f')) {
413             super.processEvent(evt);
414             return;
415         }
416
417         Toolkit.getDefaultToolkit().beep();
418         kevt.consume();
419     }
420
421     // Should consume TextEvents for non-integer Strings
422
// Store away the text in the tf for every TextEvent
423
// so we can revert to it on a TextEvent (paste, or
424
// legal key in the wrong location) with bad text
425
//
426
// Note: it would be easy to extend this to an eight-bit
427
// TextField (range 0-255), but I'll leave it as-is.
428
//
429
protected void processTextEvent(TextEvent te) {
430         // The empty string is okay, too
431
String JavaDoc newText = getText();
432         if (newText.equals("") || textIsCardinal(newText)) {
433             oldText = newText;
434             super.processTextEvent(te);
435             return;
436         }
437
438         Toolkit.getDefaultToolkit().beep();
439         setText(oldText);
440     }
441
442     // Returns true for Cardinal (non-negative) numbers
443
// Note that the empty string is not allowed
444
private boolean textIsCardinal(String JavaDoc textToCheck) {
445         int value = -1;
446
447         try {
448             value = Integer.parseInt(textToCheck, 10);
449             return (value >= 0);
450         } catch (NumberFormatException JavaDoc nfe) {
451             return false;
452         }
453     }
454 }
455
456
Popular Tags