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

Last change on this file since 4960 was 4960, checked in by stoecker, 12 years ago

mv jump to action from G to key J

  • Property svn:eol-style set to native
File size: 26.9 KB
Line 
1// License: GPL. Copyright 2007 by Immanuel Scholz and others
2package org.openstreetmap.josm.tools;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.awt.Component;
7import java.awt.Cursor;
8import java.awt.Dimension;
9import java.awt.Graphics;
10import java.awt.Graphics2D;
11import java.awt.GraphicsConfiguration;
12import java.awt.GraphicsEnvironment;
13import java.awt.Image;
14import java.awt.Point;
15import java.awt.RenderingHints;
16import java.awt.Toolkit;
17import java.awt.Transparency;
18import java.awt.image.BufferedImage;
19import java.io.ByteArrayInputStream;
20import java.io.File;
21import java.io.IOException;
22import java.io.InputStream;
23import java.io.StringReader;
24import java.io.UnsupportedEncodingException;
25import java.net.MalformedURLException;
26import java.net.URI;
27import java.net.URL;
28import java.net.URLDecoder;
29import java.util.Arrays;
30import java.util.Collection;
31import java.util.HashMap;
32import java.util.Map;
33import java.util.regex.Matcher;
34import java.util.regex.Pattern;
35import java.util.zip.ZipEntry;
36import java.util.zip.ZipFile;
37
38import javax.imageio.ImageIO;
39import javax.swing.Icon;
40import javax.swing.ImageIcon;
41
42import org.apache.commons.codec.binary.Base64;
43import org.openstreetmap.josm.Main;
44import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
45import org.openstreetmap.josm.io.MirroredInputStream;
46import org.openstreetmap.josm.plugins.PluginHandler;
47import org.xml.sax.Attributes;
48import org.xml.sax.EntityResolver;
49import org.xml.sax.InputSource;
50import org.xml.sax.SAXException;
51import org.xml.sax.XMLReader;
52import org.xml.sax.helpers.DefaultHandler;
53import org.xml.sax.helpers.XMLReaderFactory;
54
55import com.kitfox.svg.SVGDiagram;
56import com.kitfox.svg.SVGException;
57import com.kitfox.svg.SVGUniverse;
58
59/**
60 * Helper class to support the application with images.
61 *
62 * How to use:
63 *
64 * <code>ImageIcon icon = new ImageProvider(name).setMaxWidth(24).setMaxHeight(24).get();</code>
65 * (there are more options, see below)
66 *
67 * short form:
68 * <code>ImageIcon icon = ImageProvider.get(name);</code>
69 *
70 * @author imi
71 */
72public class ImageProvider {
73
74 /**
75 * Position of an overlay icon
76 * @author imi
77 */
78 public static enum OverlayPosition {
79 NORTHWEST, NORTHEAST, SOUTHWEST, SOUTHEAST
80 }
81
82 public static enum ImageType {
83 SVG, // scalable vector graphics
84 OTHER // everything else, e.g. png, gif (must be supported by Java)
85 }
86
87 protected Collection<String> dirs;
88 protected String id;
89 protected String subdir;
90 protected String name;
91 protected File archive;
92 protected int width = -1;
93 protected int height = -1;
94 protected int maxWidth = -1;
95 protected int maxHeight = -1;
96 protected boolean optional;
97
98 private static SVGUniverse svgUniverse;
99
100 /**
101 * The icon cache
102 */
103 private static Map<String, ImageResource> cache = new HashMap<String, ImageResource>();
104
105 /**
106 * @param subdir Subdirectory the image lies in.
107 * @param name The name of the image. If it does not end with '.png' or '.svg',
108 * both extensions are tried.
109 */
110 public ImageProvider(String subdir, String name) {
111 this.subdir = subdir;
112 this.name = name;
113 }
114
115 public ImageProvider(String name) {
116 this.name = name;
117 }
118
119 /**
120 * Directories to look for the image.
121 */
122 public ImageProvider setDirs(Collection<String> dirs) {
123 this.dirs = dirs;
124 return this;
125 }
126
127 /**
128 * An id used for caching. Id is not used for cache if name starts with http://. (URL is unique anyway.)
129 */
130 public ImageProvider setId(String id) {
131 this.id = id;
132 return this;
133 }
134
135 /**
136 * A zip file where the image is located.
137 */
138 public ImageProvider setArchive(File archive) {
139 this.archive = archive;
140 return this;
141 }
142
143 /**
144 * The dimensions of the image.
145 *
146 * If not specified, the original size of the image is used.
147 * The width part of the dimension can be -1. Then it will only set the height but
148 * keep the aspect ratio. (And the other way around.)
149 */
150 public ImageProvider setSize(Dimension size) {
151 this.width = size.width;
152 this.height = size.height;
153 return this;
154 }
155
156 /**
157 * see setSize
158 */
159 public ImageProvider setWidth(int width) {
160 this.width = width;
161 return this;
162 }
163
164 /**
165 * see setSize
166 */
167 public ImageProvider setHeight(int height) {
168 this.height = height;
169 return this;
170 }
171
172 /**
173 * The maximum size of the image.
174 *
175 * It will shrink the image if necessary, but keep the aspect ratio.
176 * The given width or height can be -1 which means this direction is not bounded.
177 *
178 * 'size' and 'maxSize' are not compatible, you should set only one of them.
179 */
180 public ImageProvider setMaxSize(Dimension maxSize) {
181 this.maxWidth = maxSize.width;
182 this.maxHeight = maxSize.height;
183 return this;
184 }
185
186 /**
187 * see setMaxSize
188 */
189 public ImageProvider setMaxWidth(int maxWidth) {
190 this.maxWidth = maxWidth;
191 return this;
192 }
193
194 /**
195 * see setMaxSize
196 */
197 public ImageProvider setMaxHeight(int maxHeight) {
198 this.maxHeight = maxHeight;
199 return this;
200 }
201
202 /**
203 * The image URL comes from user data and the image may be missing.
204 *
205 * Set true, if JOSM should *not* throw a RuntimeException in case the image cannot be located.
206 */
207 public ImageProvider setOptional(boolean optional) {
208 this.optional = optional;
209 return this;
210 }
211
212 /**
213 * Execute the image request.
214 */
215 public ImageIcon get() {
216 ImageResource ir = getIfAvailableImpl();
217 if (ir == null) {
218 if (!optional) {
219 String ext = name.indexOf('.') != -1 ? "" : ".???";
220 throw new RuntimeException(tr("Fatal: failed to locate image ''{0}''. This is a serious configuration problem. JOSM will stop working.", name + ext));
221 } else {
222 System.out.println(tr("Failed to locate image ''{0}''", name));
223 return null;
224 }
225 }
226 if (maxWidth != -1 || maxHeight != -1)
227 return ir.getImageIconBounded(new Dimension(maxWidth, maxHeight));
228 else
229 return ir.getImageIcon(new Dimension(width, height));
230 }
231
232 /**
233 * Return an image from the specified location. Throws a RuntimeException if
234 * the image cannot be located.
235 *
236 * @param subdir The position of the directory, e.g. 'layer'
237 * @param name The icons name (with or without '.png' or '.svg' extension)
238 * @return The requested Image.
239 */
240 public static ImageIcon get(String subdir, String name) {
241 return new ImageProvider(subdir, name).get();
242 }
243
244 public static ImageIcon get(String name) {
245 return new ImageProvider(name).get();
246 }
247
248 public static ImageIcon getIfAvailable(String name) {
249 return new ImageProvider(name).setOptional(true).get();
250 }
251
252 public static ImageIcon getIfAvailable(String subdir, String name) {
253 return new ImageProvider(subdir, name).setOptional(true).get();
254 }
255
256 /**
257 * {@code data:[<mediatype>][;base64],<data>}
258 * @see RFC2397
259 */
260 private static final Pattern dataUrlPattern = Pattern.compile(
261 "^data:([a-zA-Z]+/[a-zA-Z+]+)?(;base64)?,(.+)$");
262
263 private ImageResource getIfAvailableImpl() {
264 if (name == null)
265 return null;
266
267 try {
268 if (name.startsWith("data:")) {
269 Matcher m = dataUrlPattern.matcher(name);
270 if (m.matches()) {
271 String mediatype = m.group(1);
272 String base64 = m.group(2);
273 String data = m.group(3);
274 byte[] bytes = ";base64".equals(base64)
275 ? Base64.decodeBase64(data)
276 : URLDecoder.decode(data, "utf-8").getBytes();
277 if (mediatype != null && mediatype.contains("image/svg+xml")) {
278 URI uri = getSvgUniverse().loadSVG(new StringReader(new String(bytes)), name);
279 return new ImageResource(getSvgUniverse().getDiagram(uri));
280 } else {
281 return new ImageResource(new ImageIcon(bytes).getImage());
282 }
283 }
284 }
285 } catch (UnsupportedEncodingException ex) {
286 throw new RuntimeException(ex.getMessage(), ex);
287 } catch (IOException ex) {
288 throw new RuntimeException(ex.getMessage(), ex);
289 }
290
291 ImageType type = name.toLowerCase().endsWith(".svg") ? ImageType.SVG : ImageType.OTHER;
292
293 if (name.startsWith("http://")) {
294 String url = name;
295 ImageResource ir = cache.get(url);
296 if (ir != null) return ir;
297 ir = getIfAvailableHttp(url, type);
298 if (ir != null) {
299 cache.put(url, ir);
300 }
301 return ir;
302 } else if (name.startsWith("wiki://")) {
303 ImageResource ir = cache.get(name);
304 if (ir != null) return ir;
305 ir = getIfAvailableWiki(name, type);
306 if (ir != null) {
307 cache.put(name, ir);
308 }
309 return ir;
310 }
311
312 if (subdir == null) {
313 subdir = "";
314 } else if (!subdir.equals("")) {
315 subdir += "/";
316 }
317 String[] extensions;
318 if (name.indexOf('.') != -1) {
319 extensions = new String[] { "" };
320 } else {
321 extensions = new String[] { ".png", ".svg"};
322 }
323 final int ARCHIVE = 0, LOCAL = 1;
324 for (int place : new Integer[] { ARCHIVE, LOCAL }) {
325 for (String ext : extensions) {
326
327 if (".svg".equals(ext)) {
328 type = ImageType.SVG;
329 } else if (".png".equals(ext)) {
330 type = ImageType.OTHER;
331 }
332
333 String full_name = subdir + name + ext;
334 String cache_name = full_name;
335 /* cache separately */
336 if (dirs != null && dirs.size() > 0) {
337 cache_name = "id:" + id + ":" + full_name;
338 if(archive != null) {
339 cache_name += ":" + archive.getName();
340 }
341 }
342
343 ImageResource ir = cache.get(cache_name);
344 if (ir != null) return ir;
345
346 switch (place) {
347 case ARCHIVE:
348 if (archive != null) {
349 ir = getIfAvailableZip(full_name, archive, type);
350 if (ir != null) {
351 cache.put(cache_name, ir);
352 return ir;
353 }
354 }
355 break;
356 case LOCAL:
357 // getImageUrl() does a ton of "stat()" calls and gets expensive
358 // and redundant when you have a whole ton of objects. So,
359 // index the cache by the name of the icon we're looking for
360 // and don't bother to create a URL unless we're actually
361 // creating the image.
362 URL path = getImageUrl(full_name, dirs);
363 if (path == null) {
364 continue;
365 }
366 ir = getIfAvailableLocalURL(path, type);
367 if (ir != null) {
368 cache.put(cache_name, ir);
369 return ir;
370 }
371 break;
372 }
373 }
374 }
375 return null;
376 }
377
378 private static ImageResource getIfAvailableHttp(String url, ImageType type) {
379 try {
380 MirroredInputStream is = new MirroredInputStream(url,
381 new File(Main.pref.getCacheDirectory(), "images").getPath());
382 switch (type) {
383 case SVG:
384 URI uri = getSvgUniverse().loadSVG(is, is.getFile().toURI().toURL().toString());
385 SVGDiagram svg = getSvgUniverse().getDiagram(uri);
386 return svg == null ? null : new ImageResource(svg);
387 case OTHER:
388 BufferedImage img = null;
389 try {
390 img = ImageIO.read(is.getFile().toURI().toURL());
391 } catch (IOException e) {}
392 return img == null ? null : new ImageResource(img);
393 default:
394 throw new AssertionError();
395 }
396 } catch (IOException e) {
397 return null;
398 }
399 }
400
401 private static ImageResource getIfAvailableWiki(String name, ImageType type) {
402 final Collection<String> defaultBaseUrls = Arrays.asList(
403 "http://wiki.openstreetmap.org/w/images/",
404 "http://upload.wikimedia.org/wikipedia/commons/",
405 "http://wiki.openstreetmap.org/wiki/File:"
406 );
407 final Collection<String> baseUrls = Main.pref.getCollection("image-provider.wiki.urls", defaultBaseUrls);
408
409 final String fn = name.substring(name.lastIndexOf('/') + 1);
410
411 ImageResource result = null;
412 for (String b : baseUrls) {
413 String url;
414 if (b.endsWith(":")) {
415 url = getImgUrlFromWikiInfoPage(b, fn);
416 if (url == null) {
417 continue;
418 }
419 } else {
420 final String fn_md5 = Utils.md5Hex(fn);
421 url = b + fn_md5.substring(0,1) + "/" + fn_md5.substring(0,2) + "/" + fn;
422 }
423 result = getIfAvailableHttp(url, type);
424 if (result != null) {
425 break;
426 }
427 }
428 return result;
429 }
430
431 private static ImageResource getIfAvailableZip(String full_name, File archive, ImageType type) {
432 ZipFile zipFile = null;
433 try
434 {
435 zipFile = new ZipFile(archive);
436 ZipEntry entry = zipFile.getEntry(full_name);
437 if(entry != null)
438 {
439 int size = (int)entry.getSize();
440 int offs = 0;
441 byte[] buf = new byte[size];
442 InputStream is = null;
443 try {
444 is = zipFile.getInputStream(entry);
445 switch (type) {
446 case SVG:
447 URI uri = getSvgUniverse().loadSVG(is, full_name);
448 SVGDiagram svg = getSvgUniverse().getDiagram(uri);
449 return svg == null ? null : new ImageResource(svg);
450 case OTHER:
451 while(size > 0)
452 {
453 int l = is.read(buf, offs, size);
454 offs += l;
455 size -= l;
456 }
457 BufferedImage img = null;
458 try {
459 img = ImageIO.read(new ByteArrayInputStream(buf));
460 } catch (IOException e) {}
461 return img == null ? null : new ImageResource(img);
462 default:
463 throw new AssertionError();
464 }
465 } finally {
466 if (is != null) {
467 is.close();
468 }
469 }
470 }
471 } catch (Exception e) {
472 System.err.println(tr("Warning: failed to handle zip file ''{0}''. Exception was: {1}", archive.getName(), e.toString()));
473 } finally {
474 if (zipFile != null) {
475 try {
476 zipFile.close();
477 } catch (IOException ex) {
478 }
479 }
480 }
481 return null;
482 }
483
484 private static ImageResource getIfAvailableLocalURL(URL path, ImageType type) {
485 switch (type) {
486 case SVG:
487 URI uri = getSvgUniverse().loadSVG(path);
488 SVGDiagram svg = getSvgUniverse().getDiagram(uri);
489 return svg == null ? null : new ImageResource(svg);
490 case OTHER:
491 BufferedImage img = null;
492 try {
493 img = ImageIO.read(path);
494 } catch (IOException e) {}
495 return img == null ? null : new ImageResource(img);
496 default:
497 throw new AssertionError();
498 }
499 }
500
501 private static URL getImageUrl(String path, String name) {
502 if (path != null && path.startsWith("resource://")) {
503 String p = path.substring("resource://".length());
504 for (ClassLoader source : PluginHandler.getResourceClassLoaders()) {
505 URL res;
506 if ((res = source.getResource(p + name)) != null)
507 return res;
508 }
509 } else {
510 try {
511 File f = new File(path, name);
512 if (f.exists())
513 return f.toURI().toURL();
514 } catch (MalformedURLException e) {
515 }
516 }
517 return null;
518 }
519
520 private static URL getImageUrl(String imageName, Collection<String> dirs) {
521 URL u = null;
522
523 // Try passed directories first
524 if (dirs != null) {
525 for (String name : dirs) {
526 try {
527 u = getImageUrl(name, imageName);
528 if (u != null)
529 return u;
530 } catch (SecurityException e) {
531 System.out.println(tr(
532 "Warning: failed to access directory ''{0}'' for security reasons. Exception was: {1}",
533 name, e.toString()));
534 }
535
536 }
537 }
538 // Try user-preference directory
539 String dir = Main.pref.getPreferencesDir() + "images";
540 try {
541 u = getImageUrl(dir, imageName);
542 if (u != null)
543 return u;
544 } catch (SecurityException e) {
545 System.out.println(tr(
546 "Warning: failed to access directory ''{0}'' for security reasons. Exception was: {1}", dir, e
547 .toString()));
548 }
549
550 // Absolute path?
551 u = getImageUrl(null, imageName);
552 if (u != null)
553 return u;
554
555 // Try plugins and josm classloader
556 u = getImageUrl("resource://images/", imageName);
557 if (u != null)
558 return u;
559
560 // Try all other resource directories
561 for (String location : Main.pref.getAllPossiblePreferenceDirs()) {
562 u = getImageUrl(location + "images", imageName);
563 if (u != null)
564 return u;
565 u = getImageUrl(location, imageName);
566 if (u != null)
567 return u;
568 }
569
570 return null;
571 }
572
573 /**
574 * Reads the wiki page on a certain file in html format in order to find the real image URL.
575 */
576 private static String getImgUrlFromWikiInfoPage(final String base, final String fn) {
577
578 /** Quit parsing, when a certain condition is met */
579 class SAXReturnException extends SAXException {
580 private String result;
581
582 public SAXReturnException(String result) {
583 this.result = result;
584 }
585
586 public String getResult() {
587 return result;
588 }
589 }
590
591 try {
592 final XMLReader parser = XMLReaderFactory.createXMLReader();
593 parser.setContentHandler(new DefaultHandler() {
594 @Override
595 public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException {
596 System.out.println();
597 if (localName.equalsIgnoreCase("img")) {
598 String val = atts.getValue("src");
599 if (val.endsWith(fn))
600 throw new SAXReturnException(val); // parsing done, quit early
601 }
602 }
603 });
604
605 parser.setEntityResolver(new EntityResolver() {
606 public InputSource resolveEntity (String publicId, String systemId) {
607 return new InputSource(new ByteArrayInputStream(new byte[0]));
608 }
609 });
610
611 parser.parse(new InputSource(new MirroredInputStream(
612 base + fn,
613 new File(Main.pref.getPreferencesDir(), "images").toString()
614 )));
615 } catch (SAXReturnException r) {
616 return r.getResult();
617 } catch (Exception e) {
618 System.out.println("INFO: parsing " + base + fn + " failed:\n" + e);
619 return null;
620 }
621 System.out.println("INFO: parsing " + base + fn + " failed: Unexpected content.");
622 return null;
623 }
624
625 public static Cursor getCursor(String name, String overlay) {
626 ImageIcon img = get("cursor", name);
627 if (overlay != null) {
628 img = overlay(img, "cursor/modifier/" + overlay, OverlayPosition.SOUTHEAST);
629 }
630 Cursor c = Toolkit.getDefaultToolkit().createCustomCursor(img.getImage(),
631 name.equals("crosshair") ? new Point(10, 10) : new Point(3, 2), "Cursor");
632 return c;
633 }
634
635 /**
636 * @return an icon that represent the overlay of the two given icons. The second icon is layed
637 * on the first relative to the given position.
638 */
639 public static ImageIcon overlay(Icon ground, String overlayImage, OverlayPosition pos) {
640 return overlay(ground, ImageProvider.get(overlayImage), pos);
641 }
642
643 public static ImageIcon overlay(Icon ground, Icon overlay, OverlayPosition pos) {
644 GraphicsConfiguration conf = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice()
645 .getDefaultConfiguration();
646 int w = ground.getIconWidth();
647 int h = ground.getIconHeight();
648 int wo = overlay.getIconWidth();
649 int ho = overlay.getIconHeight();
650 BufferedImage img = conf.createCompatibleImage(w, h, Transparency.TRANSLUCENT);
651 Graphics g = img.createGraphics();
652 ground.paintIcon(null, g, 0, 0);
653 int x = 0, y = 0;
654 switch (pos) {
655 case NORTHWEST:
656 x = 0;
657 y = 0;
658 break;
659 case NORTHEAST:
660 x = w - wo;
661 y = 0;
662 break;
663 case SOUTHWEST:
664 x = 0;
665 y = h - ho;
666 break;
667 case SOUTHEAST:
668 x = w - wo;
669 y = h - ho;
670 break;
671 }
672 overlay.paintIcon(null, g, x, y);
673 return new ImageIcon(img);
674 }
675
676 /*
677 * from: http://www.jidesoft.com/blog/2008/02/29/rotate-an-icon-in-java/ License:
678 * "feel free to use"
679 */
680 final static double DEGREE_90 = 90.0 * Math.PI / 180.0;
681
682 /**
683 * Creates a rotated version of the input image.
684 *
685 * @param c The component to get properties useful for painting, e.g. the foreground or
686 * background color.
687 * @param icon the image to be rotated.
688 * @param rotatedAngle the rotated angle, in degree, clockwise. It could be any double but we
689 * will mod it with 360 before using it.
690 *
691 * @return the image after rotating.
692 */
693 public static Image createRotatedImage(Component c, Image img, double rotatedAngle) {
694 // convert rotatedAngle to a value from 0 to 360
695 double originalAngle = rotatedAngle % 360;
696 if (rotatedAngle != 0 && originalAngle == 0) {
697 originalAngle = 360.0;
698 }
699
700 // convert originalAngle to a value from 0 to 90
701 double angle = originalAngle % 90;
702 if (originalAngle != 0.0 && angle == 0.0) {
703 angle = 90.0;
704 }
705
706 double radian = Math.toRadians(angle);
707
708 new ImageIcon(img); // load completely
709 int iw = img.getWidth(null);
710 int ih = img.getHeight(null);
711 int w;
712 int h;
713
714 if ((originalAngle >= 0 && originalAngle <= 90) || (originalAngle > 180 && originalAngle <= 270)) {
715 w = (int) (iw * Math.sin(DEGREE_90 - radian) + ih * Math.sin(radian));
716 h = (int) (iw * Math.sin(radian) + ih * Math.sin(DEGREE_90 - radian));
717 } else {
718 w = (int) (ih * Math.sin(DEGREE_90 - radian) + iw * Math.sin(radian));
719 h = (int) (ih * Math.sin(radian) + iw * Math.sin(DEGREE_90 - radian));
720 }
721 BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
722 Graphics g = image.getGraphics();
723 Graphics2D g2d = (Graphics2D) g.create();
724
725 // calculate the center of the icon.
726 int cx = iw / 2;
727 int cy = ih / 2;
728
729 // move the graphics center point to the center of the icon.
730 g2d.translate(w / 2, h / 2);
731
732 // rotate the graphics about the center point of the icon
733 g2d.rotate(Math.toRadians(originalAngle));
734
735 g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
736 g2d.drawImage(img, -cx, -cy, c);
737
738 g2d.dispose();
739 new ImageIcon(image); // load completely
740 return image;
741 }
742
743 /**
744 * Replies the icon for an OSM primitive type
745 * @param type the type
746 * @return the icon
747 */
748 public static ImageIcon get(OsmPrimitiveType type) throws IllegalArgumentException {
749 CheckParameterUtil.ensureParameterNotNull(type, "type");
750 return get("data", type.getAPIName());
751 }
752
753 public static Image createImageFromSvg(SVGDiagram svg, Dimension dim) {
754 float realWidth = svg.getWidth();
755 float realHeight = svg.getHeight();
756 int width = Math.round(realWidth);
757 int height = Math.round(realHeight);
758 Double scaleX = null, scaleY = null;
759 if (dim.width != -1) {
760 width = dim.width;
761 scaleX = (double) width / realWidth;
762 if (dim.height == -1) {
763 scaleY = scaleX;
764 height = (int) Math.round(realHeight * scaleY);
765 } else {
766 height = dim.height;
767 scaleY = (double) height / realHeight;
768 }
769 } else if (dim.height != -1) {
770 height = dim.height;
771 scaleX = scaleY = (double) height / realHeight;
772 width = (int) Math.round(realWidth * scaleX);
773 }
774 Image img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
775 Graphics2D g = ((BufferedImage) img).createGraphics();
776 g.setClip(0, 0, width, height);
777 if (scaleX != null) {
778 g.scale(scaleX, scaleY);
779 }
780 g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
781 try {
782 svg.render(g);
783 } catch (SVGException ex) {
784 return null;
785 }
786 return img;
787 }
788
789 private static SVGUniverse getSvgUniverse() {
790 if (svgUniverse == null) {
791 svgUniverse = new SVGUniverse();
792 }
793 return svgUniverse;
794 }
795}
Note: See TracBrowser for help on using the repository browser.