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

Last change on this file since 1748 was 1748, checked in by stoecker, 15 years ago

applied relation sort - fix #27789 - patch by cjw

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