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
RevLine 
[8084]1/*
2 * SVG Salamander
3 * Copyright (c) 2004, Mark McKay
4 * All rights reserved.
5 *
[11525]6 * Redistribution and use in source and binary forms, with or
[8084]7 * without modification, are permitted provided that the following
8 * conditions are met:
9 *
[11525]10 * - Redistributions of source code must retain the above
[8084]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
[11525]15 * disclaimer in the documentation and/or other materials
[8084]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
[11525]29 * OF THE POSSIBILITY OF SUCH DAMAGE.
30 *
[8084]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
[10787]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;
[11525]52
[10787]53import javax.swing.ImageIcon;
[8084]54
[11525]55import com.kitfox.svg.SVGCache;
56import com.kitfox.svg.SVGDiagram;
57import com.kitfox.svg.SVGException;
58import com.kitfox.svg.SVGUniverse;
[10787]59
[8084]60/**
61 *
62 * @author kitfox
63 */
[10787]64public class SVGIcon extends ImageIcon
[8084]65{
66 public static final long serialVersionUID = 1;
67
68 public static final String PROP_AUTOSIZE = "PROP_AUTOSIZE";
[11525]69
[8084]70 private final PropertyChangeSupport changes = new PropertyChangeSupport(this);
[11525]71
[8084]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;
[11525]76
[8084]77 private boolean antiAlias;
78 private int interpolation = INTERP_NEAREST_NEIGHBOR;
79 private boolean clipToViewbox;
[11525]80
[8084]81 URI svgURI;
[11525]82
[8084]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;
[11525]92
[8084]93 Dimension preferredSize;
[11525]94
[8084]95 /** Creates a new instance of SVGIcon */
96 public SVGIcon()
97 {
98 }
[11525]99
[8084]100 public void addPropertyChangeListener(PropertyChangeListener p)
101 {
102 changes.addPropertyChangeListener(p);
103 }
[11525]104
[8084]105 public void removePropertyChangeListener(PropertyChangeListener p)
106 {
107 changes.removePropertyChangeListener(p);
108 }
[11525]109
110 @Override
[10787]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
[8084]118 /**
119 * @return height of this icon
120 */
[11525]121 public int getIconHeightIgnoreAutosize()
[8084]122 {
123 if (preferredSize != null &&
[11525]124 (autosize == AUTOSIZE_VERT || autosize == AUTOSIZE_STRETCH
[8084]125 || autosize == AUTOSIZE_BESTFIT))
126 {
127 return preferredSize.height;
128 }
[11525]129
[8084]130 SVGDiagram diagram = svgUniverse.getDiagram(svgURI);
131 if (diagram == null)
132 {
133 return 0;
134 }
135 return (int)diagram.getHeight();
136 }
[11525]137
[8084]138 /**
139 * @return width of this icon
140 */
[11525]141 public int getIconWidthIgnoreAutosize()
[8084]142 {
143 if (preferredSize != null &&
[11525]144 (autosize == AUTOSIZE_HORIZ || autosize == AUTOSIZE_STRETCH
[8084]145 || autosize == AUTOSIZE_BESTFIT))
146 {
147 return preferredSize.width;
148 }
[11525]149
[8084]150 SVGDiagram diagram = svgUniverse.getDiagram(svgURI);
151 if (diagram == null)
152 {
153 return 0;
154 }
155 return (int)diagram.getWidth();
156 }
[11525]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
[8084]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 */
[11525]207 @Override
[8084]208 public void paintIcon(Component comp, Graphics gg, int x, int y)
209 {
[11525]210 //Copy graphics object so that
[8084]211 Graphics2D g = (Graphics2D)gg.create();
212 paintIcon(comp, g, x, y);
213 g.dispose();
214 }
[11525]215
[8084]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);
[11525]220
[8084]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 }
[11525]234
235
[8084]236 SVGDiagram diagram = svgUniverse.getDiagram(svgURI);
237 if (diagram == null)
238 {
239 return;
240 }
[11525]241
[8084]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 }
[11525]248
249
[8084]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 }
[11525]264
265 final int width = getIconWidthIgnoreAutosize();
266 final int height = getIconHeightIgnoreAutosize();
[8084]267// int width = getWidth();
268// int height = getHeight();
[11525]269
[8084]270 if (width == 0 || height == 0)
271 {
272 return;
273 }
[11525]274
[8084]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// }
[11525]283
[8084]284// g.setClip(0, 0, width, height);
[11525]285
286
[8084]287// final Rectangle2D.Double rect = new Rectangle2D.Double();
288// diagram.getViewRect(rect);
[11525]289//
[8084]290// scaleXform.setToScale(width / rect.width, height / rect.height);
291 double diaWidth = diagram.getWidth();
292 double diaHeight = diagram.getHeight();
[11525]293
[8084]294 double scaleW = 1;
295 double scaleH = 1;
296 if (autosize == AUTOSIZE_BESTFIT)
297 {
[11525]298 scaleW = scaleH = (height / diaHeight < width / diaWidth)
[8084]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);
[11525]315
[8084]316 AffineTransform oldXform = g.getTransform();
317 g.transform(scaleXform);
[11525]318
[8084]319 try
320 {
321 diagram.render(g);
322 }
323 catch (SVGException e)
324 {
325 throw new RuntimeException(e);
326 }
[11525]327
[8084]328 g.setTransform(oldXform);
[11525]329
330
[8084]331 g.translate(-x, -y);
[11525]332
[8084]333 g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, oldAliasHint);
334 if (oldInterpolationHint != null)
335 {
336 g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, oldInterpolationHint);
337 }
338 }
[11525]339
[8084]340 /**
341 * @return the universe this icon draws it's SVGDiagrams from
342 */
343 public SVGUniverse getSvgUniverse()
344 {
345 return svgUniverse;
346 }
[11525]347
[8084]348 public void setSvgUniverse(SVGUniverse svgUniverse)
349 {
350 SVGUniverse old = this.svgUniverse;
351 this.svgUniverse = svgUniverse;
352 changes.firePropertyChange("svgUniverse", old, svgUniverse);
353 }
[11525]354
[8084]355 /**
356 * @return the uni of the document being displayed by this icon
357 */
358 public URI getSvgURI()
359 {
360 return svgURI;
361 }
[11525]362
[8084]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;
[11525]371
[8084]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 }
[11525]382
[8084]383 changes.firePropertyChange("svgURI", old, svgURI);
384 }
[11525]385
[8084]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;
[11525]394
[8084]395 try
396 {
397 svgURI = new URI(getClass().getResource(resourcePath).toString());
398 changes.firePropertyChange("svgURI", old, svgURI);
[11525]399
[8084]400 SVGDiagram diagram = svgUniverse.getDiagram(svgURI);
401 if (diagram != null)
402 {
403 diagram.setDeviceViewport(new Rectangle(0, 0, preferredSize.width, preferredSize.height));
404 }
[11525]405
[8084]406 }
407 catch (Exception e)
408 {
409 svgURI = old;
410 }
411 }
[11525]412
[8084]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 }
[11525]424
[8084]425 return new Dimension(preferredSize);
426 }
[11525]427
[8084]428 public void setPreferredSize(Dimension preferredSize)
429 {
430 Dimension old = this.preferredSize;
431 this.preferredSize = preferredSize;
[11525]432
[8084]433 SVGDiagram diagram = svgUniverse.getDiagram(svgURI);
434 if (diagram != null)
435 {
436 diagram.setDeviceViewport(new Rectangle(0, 0, preferredSize.width, preferredSize.height));
437 }
[11525]438
[8084]439 changes.firePropertyChange("preferredSize", old, preferredSize);
440 }
[11525]441
[8084]442 /**
443 * @return true if antiAliasing is turned on.
444 */
445 public boolean getAntiAlias()
446 {
447 return antiAlias;
448 }
[11525]449
[8084]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 }
[11525]459
[8084]460 /**
461 * @return interpolation used in rescaling images
462 */
463 public int getInterpolation()
464 {
465 return interpolation;
466 }
[11525]467
[8084]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 }
[11525]481
[8084]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 }
[11525]490
[8084]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 }
[11525]513
[8084]514}
Note: See TracBrowser for help on using the repository browser.