KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > prefuse > render > ImageFactory


1 package prefuse.render;
2
3 import java.awt.Component JavaDoc;
4 import java.awt.Image JavaDoc;
5 import java.awt.MediaTracker JavaDoc;
6 import java.awt.Toolkit JavaDoc;
7 import java.net.URL JavaDoc;
8 import java.util.HashMap JavaDoc;
9 import java.util.Iterator JavaDoc;
10 import java.util.LinkedHashMap JavaDoc;
11 import java.util.Map JavaDoc;
12
13 import prefuse.data.Tuple;
14 import prefuse.util.io.IOLib;
15
16
17 /**
18  * <p>Utility class that manages loading and storing images. Includes a
19  * configurable LRU cache for managing loaded images. Also supports optional
20  * image scaling of loaded images to cut down on memory and visualization
21  * operation costs.</p>
22  *
23  * <p>By default images are loaded upon first request. Use the
24  * {@link #preloadImages(Iterator, String)} method to load images before they
25  * are requested for rendering.</p>
26  *
27  * @author alan newberger
28  * @author <a HREF="http://jheer.org">jeffrey heer</a>
29  */

30 public class ImageFactory {
31     
32     protected int m_imageCacheSize = 3000;
33     protected int m_maxImageWidth = 100;
34     protected int m_maxImageHeight = 100;
35     protected boolean m_asynch = true;
36     
37     //a nice LRU cache courtesy of java 1.4
38
protected Map JavaDoc imageCache =
39         new LinkedHashMap JavaDoc((int) (m_imageCacheSize + 1 / .75F), .75F, true) {
40             public boolean removeEldestEntry(Map.Entry JavaDoc eldest) {
41                 return size() > m_imageCacheSize;
42             }
43         };
44     protected Map JavaDoc loadMap = new HashMap JavaDoc(50);
45
46     protected final Component JavaDoc component = new Component JavaDoc() {};
47     protected final MediaTracker JavaDoc tracker = new MediaTracker JavaDoc(component);
48     protected int nextTrackerID = 0;
49
50     /**
51      * Create a new ImageFactory. Assumes no scaling of loaded images.
52      */

53     public ImageFactory() {
54         this(-1,-1);
55     }
56     
57     /**
58      * Create a new ImageFactory. This instance will scale loaded images
59      * if they exceed the threshold arguments.
60      * @param maxImageWidth the maximum width of input images
61      * (-1 means no limit)
62      * @param maxImageHeight the maximum height of input images
63      * (-1 means no limit)
64      */

65     public ImageFactory(int maxImageWidth, int maxImageHeight) {
66         setMaxImageDimensions(maxImageWidth, maxImageHeight);
67     }
68
69     /**
70      * Sets the maximum image dimensions of loaded images, images larger than
71      * these limits will be scaled to fit within bounds.
72      * @param width the maximum width of input images (-1 means no limit)
73      * @param height the maximum height of input images (-1 means no limit)
74      */

75     public void setMaxImageDimensions(int width, int height) {
76         m_maxImageWidth = width;
77         m_maxImageHeight = height;
78     }
79
80     /**
81      * Sets the capacity of this factory's image cache
82      * @param size the new size of the image cache
83      */

84     public void setImageCacheSize(int size) {
85         m_imageCacheSize = size;
86     }
87
88     /**
89      * Indicates if the given string location corresponds to an image
90      * currently stored in this ImageFactory's cache.
91      * @param imageLocation the image location string
92      * @return true if the location is a key for a currently cached image,
93      * false otherwise.
94      */

95     public boolean isInCache(String JavaDoc imageLocation) {
96         return imageCache.containsKey(imageLocation);
97     }
98     
99     /**
100      * <p>Get the image associated with the given location string. If the image
101      * has already been loaded, it simply will return the image, otherwise it
102      * will load it from the specified location.</p>
103      *
104      * <p>The imageLocation argument must be a valid resource string pointing
105      * to either (a) a valid URL, (b) a file on the classpath, or (c) a file
106      * on the local filesystem. The location will be resolved in that order.
107      * </p>
108      *
109      * @param imageLocation the image location as a resource string.
110      * @return the corresponding image, if available
111      */

112     public Image JavaDoc getImage(String JavaDoc imageLocation) {
113         Image JavaDoc image = (Image JavaDoc) imageCache.get(imageLocation);
114         if (image == null && !loadMap.containsKey(imageLocation)) {
115             URL JavaDoc imageURL = IOLib.urlFromString(imageLocation);
116             if ( imageURL == null ) {
117                 System.err.println("Null image: " + imageLocation);
118                 return null;
119             }
120             image = Toolkit.getDefaultToolkit().createImage(imageURL);
121             
122             // if set for synchronous mode, block for image to load.
123
if ( !m_asynch ) {
124                 waitForImage(image);
125                 addImage(imageLocation, image);
126             } else {
127                 int id = ++nextTrackerID;
128                 tracker.addImage(image, id);
129                 loadMap.put(imageLocation, new LoadMapEntry(id,image));
130             }
131         } else if ( image == null && loadMap.containsKey(imageLocation) ) {
132             LoadMapEntry entry = (LoadMapEntry)loadMap.get(imageLocation);
133             if ( tracker.checkID(entry.id, true) ) {
134                 addImage(imageLocation, entry.image);
135                 loadMap.remove(imageLocation);
136                 tracker.removeImage(entry.image, entry.id);
137             }
138         } else {
139             return image;
140         }
141         return (Image JavaDoc) imageCache.get(imageLocation);
142     }
143     
144     /**
145      * Adds an image associated with a location string to this factory's cache.
146      * The image will be scaled as dictated by this current factory settings.
147      *
148      * @param location the location string uniquely identifying the image
149      * @param image the actual image
150      * @return the final image added to the cache. This may be a scaled version
151      * of the original input image.
152      */

153     public Image JavaDoc addImage(String JavaDoc location, Image JavaDoc image) {
154         if ( m_maxImageWidth > -1 || m_maxImageHeight > -1 ) {
155             image = getScaledImage(image);
156             image.getWidth(null); // trigger image load
157
}
158         imageCache.put(location, image);
159         return image;
160     }
161     
162     /**
163      * Wait for an image to load.
164      * @param image the image to wait for
165      */

166     protected void waitForImage(Image JavaDoc image) {
167         int id = ++nextTrackerID;
168         tracker.addImage(image, id);
169         try {
170             tracker.waitForID(id, 0);
171         } catch (InterruptedException JavaDoc e) {
172             e.printStackTrace();
173         }
174         tracker.removeImage(image, id);
175     }
176     
177     /**
178      * Scales an image to fit within the current size thresholds.
179      * @param img the image to scale
180      * @return the scaled image
181      */

182     protected Image JavaDoc getScaledImage(Image JavaDoc img) {
183         // resize image, if necessary, to conserve memory
184
// and reduce future scaling time
185
int w = img.getWidth(null) - m_maxImageWidth;
186         int h = img.getHeight(null) - m_maxImageHeight;
187
188         if ( w > h && w > 0 && m_maxImageWidth > -1 ) {
189             Image JavaDoc scaled = img.getScaledInstance(m_maxImageWidth, -1, Image.SCALE_SMOOTH);
190             img.flush(); //waitForImage(scaled);
191
return scaled;
192         } else if ( h > 0 && m_maxImageHeight > -1 ) {
193             Image JavaDoc scaled = img.getScaledInstance(-1, m_maxImageHeight, Image.SCALE_SMOOTH);
194             img.flush(); //waitForImage(scaled);
195
return scaled;
196         } else {
197             return img;
198         }
199     }
200     
201     /**
202      * <p>Preloads images for use in a visualization. Images to load are
203      * determined by taking objects from the given iterator and retrieving
204      * the value of the specified field. The items in the iterator must
205      * be instances of the {@link prefuse.data.Tuple} class.</p>
206      *
207      * <p>Images are loaded in the order specified by the iterator until the
208      * the iterator is empty or the maximum image cache size is met. Thus
209      * higher priority images should appear sooner in the iteration.</p>
210      *
211      * @param iter an Iterator of {@link prefuse.data.Tuple} instances
212      * @param field the data field that contains the image location
213      */

214     public void preloadImages(Iterator JavaDoc iter, String JavaDoc field) {
215         boolean synch = m_asynch;
216         m_asynch = false;
217         
218         String JavaDoc loc = null;
219         while ( iter.hasNext() && imageCache.size() <= m_imageCacheSize ) {
220             // get the string describing the image location
221
Tuple t = (Tuple)iter.next();
222             loc = t.getString(field);
223             if ( loc != null ) {
224                 getImage(loc);
225             }
226         }
227         m_asynch = synch;
228     }
229     
230     /**
231      * Helper class for storing an id/image pair.
232      */

233     private class LoadMapEntry {
234         public int id;
235         public Image JavaDoc image;
236         public LoadMapEntry(int id, Image JavaDoc image) {
237             this.id = id;
238             this.image = image;
239         }
240     }
241     
242 } // end of class ImageFactory
243
Popular Tags