KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > ImageMap


1 /*
2  * @(#)ImageMap.java 1.21 05/11/17
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 MIDROSYSTEMS, 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  * @(#)ImageMap.java 1.21 05/11/17
39  */

40
41 import java.applet.Applet JavaDoc;
42 import java.awt.Image JavaDoc;
43 import java.awt.Graphics JavaDoc;
44 import java.awt.Rectangle JavaDoc;
45 import java.awt.MediaTracker JavaDoc;
46 import java.awt.event.*;
47 import java.util.StringTokenizer JavaDoc;
48 import java.util.Vector JavaDoc;
49 import java.util.Hashtable JavaDoc;
50 import java.net.URL JavaDoc;
51 import java.awt.image.ImageProducer JavaDoc;
52 import java.awt.image.ImageFilter JavaDoc;
53 import java.awt.image.CropImageFilter JavaDoc;
54 import java.awt.image.FilteredImageSource JavaDoc;
55 import java.net.MalformedURLException JavaDoc;
56
57 /**
58  * An extensible ImageMap applet class.
59  * The active areas on the image are controlled by ImageArea classes
60  * that can be dynamically loaded over the net.
61  *
62  * @author Jim Graham
63  * @version 1.21, 11/17/05
64  */

65 public class ImageMap
66     extends Applet JavaDoc
67     implements Runnable JavaDoc, MouseListener, MouseMotionListener {
68     /**
69      * The unhighlighted image being mapped.
70      */

71     Image JavaDoc baseImage;
72
73     /**
74      * The list of image area handling objects;
75      */

76     ImageMapArea areas[];
77
78     /**
79      * The primary highlight mode to be used.
80      */

81     static final int BRIGHTER = 0;
82     static final int DARKER = 1;
83
84     int hlmode = BRIGHTER;
85
86     /**
87      * The percentage of highlight to apply for the primary highlight mode.
88      */

89     int hlpercent = 50;
90
91     /**
92      * The MediaTracker for loading and constructing the various images.
93      */

94     MediaTracker JavaDoc tracker;
95
96     /**
97      * Get a rectangular region of the baseImage highlighted according to
98      * the primary highlight specification.
99      */

100     Image JavaDoc getHighlight(int x, int y, int w, int h) {
101     return getHighlight(x, y, w, h, hlmode, hlpercent);
102     }
103
104     /**
105      * Get a rectangular region of the baseImage with a specific highlight.
106      */

107     Image JavaDoc getHighlight(int x, int y, int w, int h, int mode, int percent) {
108     return getHighlight(x, y, w, h, new HighlightFilter(mode == BRIGHTER,
109                                 percent));
110     }
111
112     /**
113      * Get a rectangular region of the baseImage modified by an image filter.
114      */

115     Image JavaDoc getHighlight(int x, int y, int w, int h, ImageFilter JavaDoc filter) {
116     ImageFilter JavaDoc cropfilter = new CropImageFilter JavaDoc(x, y, w, h);
117     ImageProducer JavaDoc prod = new FilteredImageSource JavaDoc(baseImage.getSource(),
118                              cropfilter);
119     return makeImage(prod, filter, 0);
120     }
121
122     /**
123      * Make a filtered image based on another image.
124      */

125     Image JavaDoc makeImage(Image JavaDoc orig, ImageFilter JavaDoc filter) {
126     return makeImage(orig.getSource(), filter);
127     }
128
129     /**
130      * Make a filtered image based on another ImageProducer.
131      */

132     Image JavaDoc makeImage(ImageProducer JavaDoc prod, ImageFilter JavaDoc filter) {
133     return makeImage(prod, filter,
134              (prod == baseImage.getSource()) ? 1 : 0);
135     }
136
137     /**
138      * Make a filtered image based on another ImageProducer.
139      * Add it to the media tracker using the indicated ID.
140      */

141     Image JavaDoc makeImage(ImageProducer JavaDoc prod, ImageFilter JavaDoc filter, int ID) {
142     Image JavaDoc filtered = createImage(new FilteredImageSource JavaDoc(prod, filter));
143     tracker.addImage(filtered, ID);
144     return filtered;
145     }
146
147     /**
148      * Add an image to the list of images to be tracked.
149      */

150     void addImage(Image JavaDoc img) {
151     tracker.addImage(img, 1);
152     }
153
154     /**
155      * Parse a string representing the desired highlight to be applied.
156      */

157     void parseHighlight(String JavaDoc s) {
158     if (s == null) {
159         return;
160     }
161     if (s.startsWith("brighter") || s.startsWith("BRIGHTER")) {
162         hlmode = BRIGHTER;
163         if (s.length() > "brighter".length()) {
164         hlpercent = Integer.parseInt(s.substring("brighter".length()));
165         }
166     } else if (s.startsWith("darker") || s.startsWith("DARKER")) {
167         hlmode = DARKER;
168         if (s.length() > "darker".length()) {
169         hlpercent = Integer.parseInt(s.substring("darker".length()));
170         }
171     }
172     }
173
174     /**
175      * Initialize the applet. Get attributes.
176      *
177      * Initialize the ImageAreas.
178      * Each ImageArea is a subclass of the class ImageArea, and is
179      * specified with an attribute of the form:
180      * areaN=ImageAreaClassName,arguments...
181      * The ImageAreaClassName is parsed off and a new instance of that
182      * class is created. The initializer for that class is passed a
183      * reference to the applet and the remainder of the attribute
184      * string, from which the class should retrieve any information it
185      * needs about the area it controls and the actions it needs to
186      * take within that area.
187      */

188     public void init() {
189     String JavaDoc s;
190
191     tracker = new MediaTracker JavaDoc(this);
192     parseHighlight(getParameter("highlight"));
193     introTune = getParameter("startsound");
194     baseImage = getImage(getDocumentBase(), getParameter("img"));
195     Vector JavaDoc areaVec = new Vector JavaDoc();
196     int num = 1;
197     while (true) {
198         ImageMapArea newArea;
199         s = getParameter("area"+num);
200         if (s == null) {
201         // Try rect for backwards compatibility.
202
s = getParameter("rect"+num);
203         if (s == null) {
204             break;
205         }
206         try {
207             newArea = new HighlightArea();
208             newArea.init(this, s);
209             areaVec.addElement(newArea);
210             String JavaDoc url = getParameter("href"+num);
211             if (url != null) {
212             s += "," + url;
213             newArea = new LinkArea();
214             newArea.init(this, s);
215             areaVec.addElement(newArea);
216             }
217         } catch (Exception JavaDoc e) {
218             System.out.println("error processing: "+s);
219             e.printStackTrace();
220             break;
221         }
222         } else {
223         try {
224             int classend = s.indexOf(",");
225             String JavaDoc name = s.substring(0, classend);
226             newArea = (ImageMapArea) Class.forName(name).newInstance();
227             s = s.substring(classend+1);
228             newArea.init(this, s);
229             areaVec.addElement(newArea);
230         } catch (Exception JavaDoc e) {
231             System.out.println("error processing: "+s);
232             e.printStackTrace();
233             break;
234         }
235         }
236         num++;
237     }
238     areas = new ImageMapArea[areaVec.size()];
239     areaVec.copyInto(areas);
240     checkSize();
241     addMouseListener(this);
242     addMouseMotionListener(this);
243     }
244
245     public void destroy() {
246         removeMouseListener(this);
247         removeMouseMotionListener(this);
248     }
249
250     Thread JavaDoc aniThread = null;
251     String JavaDoc introTune = null;
252
253     public void start() {
254     if (introTune != null)
255         try {
256         play(new URL JavaDoc(getDocumentBase(), introTune));
257         } catch (MalformedURLException JavaDoc e) {}
258     if (aniThread == null) {
259             aniThread = new Thread JavaDoc(this);
260             aniThread.setName("ImageMap Animator");
261             aniThread.start();
262     }
263     }
264
265     public void run() {
266     Thread JavaDoc me = Thread.currentThread();
267     tracker.checkAll(true);
268     for (int i = areas.length; --i >= 0; ) {
269         areas[i].getMedia();
270     }
271     me.setPriority(Thread.MIN_PRIORITY);
272     while (aniThread == me) {
273         boolean animating = false;
274         for (int i = areas.length; --i >= 0; ) {
275         animating = areas[i].animate() || animating;
276         }
277         try {
278         synchronized(this) {
279             wait(animating ? 100 : 0);
280         }
281         } catch (InterruptedException JavaDoc e) {
282         break;
283         }
284     }
285     }
286
287     public synchronized void startAnimation() {
288     notify();
289     }
290
291     public synchronized void stop() {
292     aniThread = null;
293     notify();
294     for (int i = 0; i < areas.length; i++) {
295         areas[i].exit();
296     }
297     }
298
299     /**
300      * Check the size of this applet while the image is being loaded.
301      */

302     void checkSize() {
303     int w = baseImage.getWidth(this);
304     int h = baseImage.getHeight(this);
305     if (w > 0 && h > 0) {
306         resize(w, h);
307         synchronized(this) {
308         fullrepaint = true;
309         }
310         repaint(0, 0, w, h);
311     }
312     }
313
314     private boolean fullrepaint = false;
315     private final static long UPDATERATE = 100;
316
317     /**
318      * Handle updates from images being loaded.
319      */

320     public boolean imageUpdate(Image JavaDoc img, int infoflags,
321                    int x, int y, int width, int height) {
322     if ((infoflags & (WIDTH | HEIGHT)) != 0) {
323         checkSize();
324     }
325     if ((infoflags & (SOMEBITS | FRAMEBITS | ALLBITS)) != 0) {
326         synchronized(this) {
327         fullrepaint = true;
328         }
329         repaint(((infoflags & (FRAMEBITS | ALLBITS)) != 0)
330             ? 0 : UPDATERATE,
331             x, y, width, height);
332     }
333     return (infoflags & (ALLBITS | ERROR)) == 0;
334     }
335
336     /**
337      * Paint the image and all active highlights.
338      */

339     public void paint(Graphics JavaDoc g) {
340     synchronized(this) {
341         fullrepaint = false;
342     }
343     if (baseImage == null) {
344         return;
345     }
346     g.drawImage(baseImage, 0, 0, this);
347     if (areas != null) {
348         for (int i = areas.length; --i >= 0; ) {
349         areas[i].highlight(g);
350         }
351     }
352     }
353
354     /**
355      * Update the active highlights on the image.
356      */

357     public void update(Graphics JavaDoc g) {
358     boolean full;
359     synchronized(this) {
360         full = fullrepaint;
361     }
362     if (full) {
363         paint(g);
364         return;
365     }
366     if (baseImage == null) {
367         return;
368     }
369     g.drawImage(baseImage, 0, 0, this);
370     if (areas == null) {
371         return;
372     }
373     // First unhighlight all of the deactivated areas
374
for (int i = areas.length; --i >= 0; ) {
375         areas[i].highlight(g);
376     }
377     }
378
379       int pressX;
380       int pressY;
381
382   public void mouseClicked(MouseEvent e)
383   {}
384
385       /**
386        * Inform all active ImageAreas of a mouse press.
387        */

388   public void mousePressed(MouseEvent e)
389   {
390     pressX = e.getX();
391     pressY = e.getY();
392
393     for (int i = 0; i < areas.length; i++) {
394       if (areas[i].inside(pressX, pressY)) {
395     if (areas[i].press(pressX, pressY)) {
396       break;
397     }
398       }
399     }
400     e.consume();
401   }
402
403       /**
404        * Inform all active ImageAreas of a mouse release.
405        * Only those areas that were inside the original mousePressed()
406        * are informed of the mouseReleased.
407        */

408   public void mouseReleased(MouseEvent e)
409   {
410     for (int i = 0; i < areas.length; i++) {
411       if (areas[i].inside(pressX, pressY)) {
412     if (areas[i].lift(e.getX(), e.getY())) {
413       break;
414     }
415       }
416     }
417     e.consume();
418   }
419
420   public void mouseEntered(MouseEvent e)
421   {}
422
423       /**
424        * Make sure that no ImageAreas are highlighted.
425        */

426   public void mouseExited(MouseEvent e) {
427     for (int i = 0; i < areas.length; i++) {
428       areas[i].checkExit();
429     }
430     e.consume();
431   }
432
433
434       /**
435        * Inform all active ImageAreas of a mouse drag.
436        * Only those areas that were inside the original mouseDown()
437        * are informed of the mouseUp.
438        */

439
440   public void mouseDragged(MouseEvent e)
441   {
442     mouseMoved(e);
443     for (int i = 0; i < areas.length; i++) {
444       if (areas[i].inside(pressX, pressY)) {
445     if (areas[i].drag(e.getX(), e.getY())) {
446       break;
447     }
448       }
449     }
450     e.consume();
451   }
452
453       /**
454        * Find the ImageAreas that the mouse is in.
455        */

456   public void mouseMoved(MouseEvent e) {
457     boolean eaten = false;
458
459     for (int i = 0; i < areas.length; i++) {
460       if (!eaten && areas[i].inside(e.getX(), e.getY())) {
461     eaten = areas[i].checkEnter(e.getX(), e.getY());
462       } else {
463     areas[i].checkExit();
464       }
465     }
466     e.consume();
467   }
468
469     /**
470      * Scan all areas looking for the topmost status string.
471      */

472     public void newStatus() {
473     String JavaDoc msg = null;
474     for (int i = 0; i < areas.length; i++) {
475         msg = areas[i].getStatus(msg);
476     }
477     showStatus(msg);
478     }
479
480   public String JavaDoc getAppletInfo() {
481     return "Title: ImageMap \nAuthor: Jim Graham \nAn extensible ImageMap applet class. \nThe active areas on the image are controlled by ImageArea \nclasses that can be dynamically loaded over the net.";
482   }
483
484   public String JavaDoc[][] getParameterInfo() {
485     String JavaDoc[][] info = {
486       {"area[n]", "delimited string",
487 "This parameter takes the form of <ImageAreaClassName>, <ul>, <ur>, <ll>, <lr>, <action> where ImageAreaClassName is the name of the class from which this feedback area is controlled, the next four arguments are the four corners of the "
488 + " feedback zone, and the final argument is that action that should be taken on click or mouseover. That action can be 1) display text in the status bar (if you provide a string argument), 2) play a sound (if you provide the path to a sound file), or 3) load a page (if you provide a URL)."},
489       {"rect[n]", "delimited string", "Deprecated: use area[n]"},
490       {"href[n]", "URL string", "Pass in a URL to create a LinkArea which will point to this URL. Not used in these examples."},
491       {"highlight", "string/int", "Pass the word 'brighter' followed by an integer 'n' to change the highlight mode to brighter and the hightlight percentage to n. Pass the word 'darker' followed by an integer 'm' to change the highlight mode to darker and the highlight percentage to m. Anything else will be ignored. The default highlight mode is BRIGHTER and the default highlight percentage is 50."},
492       {"startsound", "path string", "The path of a soundclip to play when the image is first displayed."},
493       {"img", "path string", "The path to the image to be displayed as a live feedback image map."}
494     };
495     return info;
496   }
497 }
498
499
500
501
Popular Tags