source: josm/trunk/src/org/openstreetmap/josm/tools/ImageProvider.java@ 1814

Last change on this file since 1814 was 1814, checked in by Gubaer, 15 years ago

removed dependencies to Main.ds, removed Main.ds
removed AddVisitor, NameVisitor, DeleteVisitor - unnecessary double dispatching for these simple cases

  • Property svn:eol-style set to native
File size: 11.0 KB
Line 
1// License: GPL. Copyright 2007 by Immanuel Scholz and others
2package org.openstreetmap.josm.tools;
3
4import java.awt.Component;
5import java.awt.Cursor;
6import java.awt.Graphics;
7import java.awt.Graphics2D;
8import java.awt.GraphicsConfiguration;
9import java.awt.GraphicsEnvironment;
10import java.awt.Image;
11import java.awt.Point;
12import java.awt.RenderingHints;
13import java.awt.Toolkit;
14import java.awt.Transparency;
15import java.awt.image.BufferedImage;
16import java.io.File;
17import java.io.IOException;
18import java.net.MalformedURLException;
19import java.net.URL;
20import java.util.Arrays;
21import java.util.Collection;
22import java.util.HashMap;
23import java.util.LinkedList;
24import java.util.List;
25import java.util.Map;
26
27import javax.swing.Icon;
28import javax.swing.ImageIcon;
29
30import org.openstreetmap.josm.Main;
31import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
32import org.openstreetmap.josm.io.MirroredInputStream;
33import static org.openstreetmap.josm.tools.I18n.tr;
34
35/**
36 * Helperclass to support the application with images.
37 * @author imi
38 */
39public class ImageProvider {
40
41 /**
42 * Position of an overlay icon
43 * @author imi
44 */
45 public static enum OverlayPosition {NORTHWEST, NORTHEAST, SOUTHWEST, SOUTHEAST}
46
47 /**
48 * The icon cache
49 */
50 private static Map<String, Image> cache = new HashMap<String, Image>();
51
52 /**
53 * Add here all ClassLoader whose ressource should be searched.
54 * Plugin's class loaders are added by main.
55 */
56 public static final List<ClassLoader> sources = new LinkedList<ClassLoader>();
57
58 /**
59 * Return an image from the specified location.
60 *
61 * @param subdir The position of the directory, e.g. "layer"
62 * @param name The icons name (without the ending of ".png")
63 * @return The requested Image.
64 */
65 public static ImageIcon get(String subdir, String name) {
66 ImageIcon icon = getIfAvailable(subdir, name);
67 if (icon == null) {
68 String ext = name.indexOf('.') != -1 ? "" : ".png";
69 throw new NullPointerException("/images/"+subdir+"/"+name+ext+" not found");
70 }
71 return icon;
72 }
73
74 public static ImageIcon getIfAvailable(String subdir, String name)
75 {
76 return getIfAvailable((Collection<String>)null, null, subdir, name);
77 }
78 public static final ImageIcon getIfAvailable(String[] dirs, String id, String subdir, String name)
79 {
80 return getIfAvailable(Arrays.asList(dirs), id, subdir, name);
81 }
82
83 /**
84 * Like {@link #get(String)}, but does not throw and return <code>null</code>
85 * in case of nothing is found. Use this, if the image to retrieve is optional.
86 */
87 public static ImageIcon getIfAvailable(Collection<String> dirs, String id, String subdir, String name)
88 {
89 if (name == null)
90 return null;
91 if (name.startsWith("http://"))
92 {
93 Image img = cache.get(name);
94 if(img == null)
95 {
96 try
97 {
98 MirroredInputStream is = new MirroredInputStream(name,
99 new File(Main.pref.getPreferencesDir(), "images").toString());
100 if(is != null)
101 {
102 img = Toolkit.getDefaultToolkit().createImage(is.getFile().toURI().toURL());
103 cache.put(name, img);
104 }
105 }
106 catch(IOException e) {
107 }
108 }
109 return img == null ? null : new ImageIcon(img);
110 }
111 if (subdir == null) {
112 subdir = "";
113 } else if (!subdir.equals("")) {
114 subdir += "/";
115 }
116 String ext = name.indexOf('.') != -1 ? "" : ".png";
117 String full_name = subdir+name+ext;
118 String cache_name = full_name;
119 /* cache separately */
120 if(dirs != null && dirs.size() > 0) {
121 cache_name = "id:"+id+":"+full_name;
122 }
123
124 Image img = cache.get(cache_name);
125 if (img == null) {
126 // getImageUrl() does a ton of "stat()" calls and gets expensive
127 // and redundant when you have a whole ton of objects. So,
128 // index the cache by the name of the icon we're looking for
129 // and don't bother to create a URL unless we're actually
130 // creating the image.
131 URL path = getImageUrl(full_name, dirs);
132 if (path == null)
133 return null;
134 img = Toolkit.getDefaultToolkit().createImage(path);
135 cache.put(cache_name, img);
136 }
137
138 return new ImageIcon(img);
139 }
140
141 private static URL getImageUrl(String path, String name)
142 {
143 if(path.startsWith("resource://"))
144 {
145 String p = path.substring("resource://".length());
146 for (ClassLoader source : sources)
147 {
148 URL res;
149 if ((res = source.getResource(p+name)) != null)
150 return res;
151 }
152 }
153 else
154 {
155 try {
156 File f = new File(path, name);
157 if(f.exists())
158 return f.toURI().toURL();
159 } catch (MalformedURLException e) {}
160 }
161 return null;
162 }
163
164 private static URL getImageUrl(String imageName, Collection<String> dirs)
165 {
166 URL u;
167 // Try passed directories first
168 if(dirs != null)
169 {
170 for (String name : dirs)
171 {
172 u = getImageUrl(name, imageName);
173 if(u != null) return u;
174 }
175 }
176 // Try user-preference directory
177 u = getImageUrl(Main.pref.getPreferencesDir()+"images", imageName);
178 if(u != null) return u;
179
180 // Try plugins and josm classloader
181 u = getImageUrl("resource://images/", imageName);
182 if(u != null) return u;
183
184 // Try all other ressource directories
185 for (String location : Main.pref.getAllPossiblePreferenceDirs())
186 {
187 u = getImageUrl(location+"images", imageName);
188 if(u != null) return u;
189 u = getImageUrl(location, imageName);
190 if(u != null) return u;
191 }
192 return null;
193 }
194
195 /**
196 * Shortcut for get("", name);
197 */
198 public static ImageIcon get(String name) {
199 return get("", name);
200 }
201
202 public static Cursor getCursor(String name, String overlay) {
203 ImageIcon img = get("cursor",name);
204 if (overlay != null) {
205 img = overlay(img, "cursor/modifier/"+overlay, OverlayPosition.SOUTHEAST);
206 }
207 Cursor c = Toolkit.getDefaultToolkit().createCustomCursor(img.getImage(),
208 name.equals("crosshair") ? new Point(10,10) : new Point(3,2), "Cursor");
209 return c;
210 }
211
212 /**
213 * @return an icon that represent the overlay of the two given icons. The
214 * second icon is layed on the first relative to the given position.
215 */
216 public static ImageIcon overlay(Icon ground, String overlayImage, OverlayPosition pos) {
217 GraphicsConfiguration conf = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
218 int w = ground.getIconWidth();
219 int h = ground.getIconHeight();
220 ImageIcon overlay = ImageProvider.get(overlayImage);
221 int wo = overlay.getIconWidth();
222 int ho = overlay.getIconHeight();
223 BufferedImage img = conf.createCompatibleImage(w,h, Transparency.TRANSLUCENT);
224 Graphics g = img.createGraphics();
225 ground.paintIcon(null, g, 0, 0);
226 int x = 0, y = 0;
227 switch (pos) {
228 case NORTHWEST:
229 x = 0;
230 y = 0;
231 break;
232 case NORTHEAST:
233 x = w-wo;
234 y = 0;
235 break;
236 case SOUTHWEST:
237 x = 0;
238 y = h-ho;
239 break;
240 case SOUTHEAST:
241 x = w-wo;
242 y = h-ho;
243 break;
244 }
245 overlay.paintIcon(null, g, x, y);
246 return new ImageIcon(img);
247 }
248
249 static {
250 try {
251 sources.add(ClassLoader.getSystemClassLoader());
252 sources.add(org.openstreetmap.josm.gui.MainApplication.class.getClassLoader());
253 } catch (SecurityException ex) {
254 sources.add(ImageProvider.class.getClassLoader());
255 }
256 }
257
258 /* from: http://www.jidesoft.com/blog/2008/02/29/rotate-an-icon-in-java/
259 * License: "feel free to use"
260 */
261 final static double DEGREE_90 = 90.0 * Math.PI / 180.0;
262
263 /**
264 * Creates a rotated version of the input image.
265 *
266 * @param c The component to get properties useful for painting, e.g. the foreground
267 * or background color.
268 * @param icon the image to be rotated.
269 * @param rotatedAngle the rotated angle, in degree, clockwise. It could be any double but we
270 * will mod it with 360 before using it.
271 *
272 * @return the image after rotating.
273 */
274 public static ImageIcon createRotatedImage(Component c, Icon icon, double rotatedAngle) {
275 // convert rotatedAngle to a value from 0 to 360
276 double originalAngle = rotatedAngle % 360;
277 if (rotatedAngle != 0 && originalAngle == 0) {
278 originalAngle = 360.0;
279 }
280
281 // convert originalAngle to a value from 0 to 90
282 double angle = originalAngle % 90;
283 if (originalAngle != 0.0 && angle == 0.0) {
284 angle = 90.0;
285 }
286
287 double radian = Math.toRadians(angle);
288
289 int iw = icon.getIconWidth();
290 int ih = icon.getIconHeight();
291 int w;
292 int h;
293
294 if ((originalAngle >= 0 && originalAngle <= 90) || (originalAngle > 180 && originalAngle <= 270)) {
295 w = (int) (iw * Math.sin(DEGREE_90 - radian) + ih * Math.sin(radian));
296 h = (int) (iw * Math.sin(radian) + ih * Math.sin(DEGREE_90 - radian));
297 }
298 else {
299 w = (int) (ih * Math.sin(DEGREE_90 - radian) + iw * Math.sin(radian));
300 h = (int) (ih * Math.sin(radian) + iw * Math.sin(DEGREE_90 - radian));
301 }
302 BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
303 Graphics g = image.getGraphics();
304 Graphics2D g2d = (Graphics2D) g.create();
305
306 // calculate the center of the icon.
307 int cx = iw / 2;
308 int cy = ih / 2;
309
310 // move the graphics center point to the center of the icon.
311 g2d.translate(w/2, h/2);
312
313 // rotate the graphics about the center point of the icon
314 g2d.rotate(Math.toRadians(originalAngle));
315
316 g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
317 icon.paintIcon(c, g2d, -cx, -cy);
318
319 g2d.dispose();
320 return new ImageIcon(image);
321 }
322
323 /**
324 * Replies the icon for an OSM primitive type
325 * @param type the type
326 * @return the icon
327 */
328 public static ImageIcon get(OsmPrimitiveType type) throws IllegalArgumentException {
329 if (type == null)
330 throw new IllegalArgumentException(tr("parameter ''{0}'' must not be null", "type"));
331 return get("data",type.getAPIName());
332 }
333}
Note: See TracBrowser for help on using the repository browser.