source: josm/trunk/src/com/kitfox/svg/app/beans/SVGIcon.java@ 16632

Last change on this file since 16632 was 11525, checked in by Don-vip, 9 years ago

see #14319 - update to latest version of svgSalamander (2017-01-07, patched)

  • Property svn:eol-style set to native
File size: 15.3 KB
Line 
1/*
2 * SVG Salamander
3 * Copyright (c) 2004, Mark McKay
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or
7 * without modification, are permitted provided that the following
8 * conditions are met:
9 *
10 * - Redistributions of source code must retain the above
11 * copyright notice, this list of conditions and the following
12 * disclaimer.
13 * - Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following
15 * disclaimer in the documentation and/or other materials
16 * provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
22 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
23 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
27 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
29 * OF THE POSSIBILITY OF SUCH DAMAGE.
30 *
31 * Mark McKay can be contacted at mark@kitfox.com. Salamander and other
32 * projects can be found at http://www.kitfox.com
33 *
34 * Created on April 21, 2005, 10:45 AM
35 */
36
37package com.kitfox.svg.app.beans;
38
39import java.awt.Component;
40import java.awt.Dimension;
41import java.awt.Graphics;
42import java.awt.Graphics2D;
43import java.awt.Image;
44import java.awt.Rectangle;
45import java.awt.RenderingHints;
46import java.awt.geom.AffineTransform;
47import java.awt.geom.Rectangle2D;
48import java.awt.image.BufferedImage;
49import java.beans.PropertyChangeListener;
50import java.beans.PropertyChangeSupport;
51import java.net.URI;
52
53import javax.swing.ImageIcon;
54
55import com.kitfox.svg.SVGCache;
56import com.kitfox.svg.SVGDiagram;
57import com.kitfox.svg.SVGException;
58import com.kitfox.svg.SVGUniverse;
59
60/**
61 *
62 * @author kitfox
63 */
64public class SVGIcon extends ImageIcon
65{
66 public static final long serialVersionUID = 1;
67
68 public static final String PROP_AUTOSIZE = "PROP_AUTOSIZE";
69
70 private final PropertyChangeSupport changes = new PropertyChangeSupport(this);
71
72 SVGUniverse svgUniverse = SVGCache.getSVGUniverse();
73 public static final int INTERP_NEAREST_NEIGHBOR = 0;
74 public static final int INTERP_BILINEAR = 1;
75 public static final int INTERP_BICUBIC = 2;
76
77 private boolean antiAlias;
78 private int interpolation = INTERP_NEAREST_NEIGHBOR;
79 private boolean clipToViewbox;
80
81 URI svgURI;
82
83// private boolean scaleToFit;
84 AffineTransform scaleXform = new AffineTransform();
85
86 public static final int AUTOSIZE_NONE = 0;
87 public static final int AUTOSIZE_HORIZ = 1;
88 public static final int AUTOSIZE_VERT = 2;
89 public static final int AUTOSIZE_BESTFIT = 3;
90 public static final int AUTOSIZE_STRETCH = 4;
91 private int autosize = AUTOSIZE_NONE;
92
93 Dimension preferredSize;
94
95 /** Creates a new instance of SVGIcon */
96 public SVGIcon()
97 {
98 }
99
100 public void addPropertyChangeListener(PropertyChangeListener p)
101 {
102 changes.addPropertyChangeListener(p);
103 }
104
105 public void removePropertyChangeListener(PropertyChangeListener p)
106 {
107 changes.removePropertyChangeListener(p);
108 }
109
110 @Override
111 public Image getImage()
112 {
113 BufferedImage bi = new BufferedImage(getIconWidth(), getIconHeight(), BufferedImage.TYPE_INT_ARGB);
114 paintIcon(null, bi.getGraphics(), 0, 0);
115 return bi;
116 }
117
118 /**
119 * @return height of this icon
120 */
121 public int getIconHeightIgnoreAutosize()
122 {
123 if (preferredSize != null &&
124 (autosize == AUTOSIZE_VERT || autosize == AUTOSIZE_STRETCH
125 || autosize == AUTOSIZE_BESTFIT))
126 {
127 return preferredSize.height;
128 }
129
130 SVGDiagram diagram = svgUniverse.getDiagram(svgURI);
131 if (diagram == null)
132 {
133 return 0;
134 }
135 return (int)diagram.getHeight();
136 }
137
138 /**
139 * @return width of this icon
140 */
141 public int getIconWidthIgnoreAutosize()
142 {
143 if (preferredSize != null &&
144 (autosize == AUTOSIZE_HORIZ || autosize == AUTOSIZE_STRETCH
145 || autosize == AUTOSIZE_BESTFIT))
146 {
147 return preferredSize.width;
148 }
149
150 SVGDiagram diagram = svgUniverse.getDiagram(svgURI);
151 if (diagram == null)
152 {
153 return 0;
154 }
155 return (int)diagram.getWidth();
156 }
157
158 private boolean isAutoSizeBestFitUseFixedHeight(final int iconWidthIgnoreAutosize, final int iconHeightIgnoreAutosize,
159 final SVGDiagram diagram)
160 {
161 return iconHeightIgnoreAutosize/diagram.getHeight() < iconWidthIgnoreAutosize/diagram.getWidth();
162 }
163
164 @Override
165 public int getIconWidth()
166 {
167 final int iconWidthIgnoreAutosize = getIconWidthIgnoreAutosize();
168 final int iconHeightIgnoreAutosize = getIconHeightIgnoreAutosize();
169 final SVGDiagram diagram = svgUniverse.getDiagram(svgURI);
170 if (preferredSize != null && (autosize == AUTOSIZE_VERT ||
171 (autosize == AUTOSIZE_BESTFIT && isAutoSizeBestFitUseFixedHeight(iconWidthIgnoreAutosize, iconHeightIgnoreAutosize, diagram))))
172 {
173 final double aspectRatio = diagram.getHeight()/diagram.getWidth();
174 return (int)(iconHeightIgnoreAutosize / aspectRatio);
175 }
176 else
177 {
178 return iconWidthIgnoreAutosize;
179 }
180 }
181
182 @Override
183 public int getIconHeight()
184 {
185 final int iconWidthIgnoreAutosize = getIconWidthIgnoreAutosize();
186 final int iconHeightIgnoreAutosize = getIconHeightIgnoreAutosize();
187 final SVGDiagram diagram = svgUniverse.getDiagram(svgURI);
188 if (preferredSize != null && (autosize == AUTOSIZE_HORIZ ||
189 (autosize == AUTOSIZE_BESTFIT && !isAutoSizeBestFitUseFixedHeight(iconWidthIgnoreAutosize, iconHeightIgnoreAutosize, diagram))))
190 {
191 final double aspectRatio = diagram.getHeight()/diagram.getWidth();
192 return (int)(iconWidthIgnoreAutosize * aspectRatio);
193 }
194 else
195 {
196 return iconHeightIgnoreAutosize;
197 }
198 }
199
200 /**
201 * Draws the icon to the specified component.
202 * @param comp - Component to draw icon to. This is ignored by SVGIcon, and can be set to null; only gg is used for drawing the icon
203 * @param gg - Graphics context to render SVG content to
204 * @param x - X coordinate to draw icon
205 * @param y - Y coordinate to draw icon
206 */
207 @Override
208 public void paintIcon(Component comp, Graphics gg, int x, int y)
209 {
210 //Copy graphics object so that
211 Graphics2D g = (Graphics2D)gg.create();
212 paintIcon(comp, g, x, y);
213 g.dispose();
214 }
215
216 private void paintIcon(Component comp, Graphics2D g, int x, int y)
217 {
218 Object oldAliasHint = g.getRenderingHint(RenderingHints.KEY_ANTIALIASING);
219 g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, antiAlias ? RenderingHints.VALUE_ANTIALIAS_ON : RenderingHints.VALUE_ANTIALIAS_OFF);
220
221 Object oldInterpolationHint = g.getRenderingHint(RenderingHints.KEY_INTERPOLATION);
222 switch (interpolation)
223 {
224 case INTERP_NEAREST_NEIGHBOR:
225 g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR);
226 break;
227 case INTERP_BILINEAR:
228 g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
229 break;
230 case INTERP_BICUBIC:
231 g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
232 break;
233 }
234
235
236 SVGDiagram diagram = svgUniverse.getDiagram(svgURI);
237 if (diagram == null)
238 {
239 return;
240 }
241
242 g.translate(x, y);
243 diagram.setIgnoringClipHeuristic(!clipToViewbox);
244 if (clipToViewbox)
245 {
246 g.setClip(new Rectangle2D.Float(0, 0, diagram.getWidth(), diagram.getHeight()));
247 }
248
249
250 if (autosize == AUTOSIZE_NONE)
251 {
252 try
253 {
254 diagram.render(g);
255 g.translate(-x, -y);
256 g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, oldAliasHint);
257 }
258 catch (Exception e)
259 {
260 throw new RuntimeException(e);
261 }
262 return;
263 }
264
265 final int width = getIconWidthIgnoreAutosize();
266 final int height = getIconHeightIgnoreAutosize();
267// int width = getWidth();
268// int height = getHeight();
269
270 if (width == 0 || height == 0)
271 {
272 return;
273 }
274
275// if (width == 0 || height == 0)
276// {
277// //Chances are we're rendering offscreen
278// Dimension dim = getSize();
279// width = dim.width;
280// height = dim.height;
281// return;
282// }
283
284// g.setClip(0, 0, width, height);
285
286
287// final Rectangle2D.Double rect = new Rectangle2D.Double();
288// diagram.getViewRect(rect);
289//
290// scaleXform.setToScale(width / rect.width, height / rect.height);
291 double diaWidth = diagram.getWidth();
292 double diaHeight = diagram.getHeight();
293
294 double scaleW = 1;
295 double scaleH = 1;
296 if (autosize == AUTOSIZE_BESTFIT)
297 {
298 scaleW = scaleH = (height / diaHeight < width / diaWidth)
299 ? height / diaHeight : width / diaWidth;
300 }
301 else if (autosize == AUTOSIZE_HORIZ)
302 {
303 scaleW = scaleH = width / diaWidth;
304 }
305 else if (autosize == AUTOSIZE_VERT)
306 {
307 scaleW = scaleH = height / diaHeight;
308 }
309 else if (autosize == AUTOSIZE_STRETCH)
310 {
311 scaleW = width / diaWidth;
312 scaleH = height / diaHeight;
313 }
314 scaleXform.setToScale(scaleW, scaleH);
315
316 AffineTransform oldXform = g.getTransform();
317 g.transform(scaleXform);
318
319 try
320 {
321 diagram.render(g);
322 }
323 catch (SVGException e)
324 {
325 throw new RuntimeException(e);
326 }
327
328 g.setTransform(oldXform);
329
330
331 g.translate(-x, -y);
332
333 g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, oldAliasHint);
334 if (oldInterpolationHint != null)
335 {
336 g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, oldInterpolationHint);
337 }
338 }
339
340 /**
341 * @return the universe this icon draws it's SVGDiagrams from
342 */
343 public SVGUniverse getSvgUniverse()
344 {
345 return svgUniverse;
346 }
347
348 public void setSvgUniverse(SVGUniverse svgUniverse)
349 {
350 SVGUniverse old = this.svgUniverse;
351 this.svgUniverse = svgUniverse;
352 changes.firePropertyChange("svgUniverse", old, svgUniverse);
353 }
354
355 /**
356 * @return the uni of the document being displayed by this icon
357 */
358 public URI getSvgURI()
359 {
360 return svgURI;
361 }
362
363 /**
364 * Loads an SVG document from a URI.
365 * @param svgURI - URI to load document from
366 */
367 public void setSvgURI(URI svgURI)
368 {
369 URI old = this.svgURI;
370 this.svgURI = svgURI;
371
372 SVGDiagram diagram = svgUniverse.getDiagram(svgURI);
373 if (diagram != null)
374 {
375 Dimension size = getPreferredSize();
376 if (size == null)
377 {
378 size = new Dimension((int)diagram.getRoot().getDeviceWidth(), (int)diagram.getRoot().getDeviceHeight());
379 }
380 diagram.setDeviceViewport(new Rectangle(0, 0, size.width, size.height));
381 }
382
383 changes.firePropertyChange("svgURI", old, svgURI);
384 }
385
386 /**
387 * Loads an SVG document from the classpath. This function is equivilant to
388 * setSvgURI(new URI(getClass().getResource(resourcePath).toString());
389 * @param resourcePath - resource to load
390 */
391 public void setSvgResourcePath(String resourcePath)
392 {
393 URI old = this.svgURI;
394
395 try
396 {
397 svgURI = new URI(getClass().getResource(resourcePath).toString());
398 changes.firePropertyChange("svgURI", old, svgURI);
399
400 SVGDiagram diagram = svgUniverse.getDiagram(svgURI);
401 if (diagram != null)
402 {
403 diagram.setDeviceViewport(new Rectangle(0, 0, preferredSize.width, preferredSize.height));
404 }
405
406 }
407 catch (Exception e)
408 {
409 svgURI = old;
410 }
411 }
412
413 public Dimension getPreferredSize()
414 {
415 if (preferredSize == null)
416 {
417 SVGDiagram diagram = svgUniverse.getDiagram(svgURI);
418 if (diagram != null)
419 {
420 //preferredSize = new Dimension((int)diagram.getWidth(), (int)diagram.getHeight());
421 setPreferredSize(new Dimension((int)diagram.getWidth(), (int)diagram.getHeight()));
422 }
423 }
424
425 return new Dimension(preferredSize);
426 }
427
428 public void setPreferredSize(Dimension preferredSize)
429 {
430 Dimension old = this.preferredSize;
431 this.preferredSize = preferredSize;
432
433 SVGDiagram diagram = svgUniverse.getDiagram(svgURI);
434 if (diagram != null)
435 {
436 diagram.setDeviceViewport(new Rectangle(0, 0, preferredSize.width, preferredSize.height));
437 }
438
439 changes.firePropertyChange("preferredSize", old, preferredSize);
440 }
441
442 /**
443 * @return true if antiAliasing is turned on.
444 */
445 public boolean getAntiAlias()
446 {
447 return antiAlias;
448 }
449
450 /**
451 * @param antiAlias true to use antiAliasing.
452 */
453 public void setAntiAlias(boolean antiAlias)
454 {
455 boolean old = this.antiAlias;
456 this.antiAlias = antiAlias;
457 changes.firePropertyChange("antiAlias", old, antiAlias);
458 }
459
460 /**
461 * @return interpolation used in rescaling images
462 */
463 public int getInterpolation()
464 {
465 return interpolation;
466 }
467
468 /**
469 * @param interpolation Interpolation value used in rescaling images.
470 * Should be one of
471 * INTERP_NEAREST_NEIGHBOR - Fastest, one pixel resampling, poor quality
472 * INTERP_BILINEAR - four pixel resampling
473 * INTERP_BICUBIC - Slowest, nine pixel resampling, best quality
474 */
475 public void setInterpolation(int interpolation)
476 {
477 int old = this.interpolation;
478 this.interpolation = interpolation;
479 changes.firePropertyChange("interpolation", old, interpolation);
480 }
481
482 /**
483 * clipToViewbox will set a clip box equivilant to the SVG's viewbox before
484 * rendering.
485 */
486 public boolean isClipToViewbox()
487 {
488 return clipToViewbox;
489 }
490
491 public void setClipToViewbox(boolean clipToViewbox)
492 {
493 this.clipToViewbox = clipToViewbox;
494 }
495
496 /**
497 * @return the autosize
498 */
499 public int getAutosize()
500 {
501 return autosize;
502 }
503
504 /**
505 * @param autosize the autosize to set
506 */
507 public void setAutosize(int autosize)
508 {
509 int oldAutosize = this.autosize;
510 this.autosize = autosize;
511 changes.firePropertyChange(PROP_AUTOSIZE, oldAutosize, autosize);
512 }
513
514}
Note: See TracBrowser for help on using the repository browser.