/* * SVG Salamander * Copyright (c) 2004, Mark McKay * All rights reserved. * * Redistribution and use in source and binary forms, with or * without modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above * copyright notice, this list of conditions and the following * disclaimer. * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * * Mark McKay can be contacted at mark@kitfox.com. Salamander and other * projects can be found at http://www.kitfox.com * * Created on April 21, 2005, 10:45 AM */ package com.kitfox.svg.app.beans; import com.kitfox.svg.*; import java.awt.*; import java.awt.geom.*; import java.beans.*; import java.net.*; import javax.swing.*; /** * * @author kitfox */ public class SVGIcon implements Icon { public static final long serialVersionUID = 1; public static final String PROP_AUTOSIZE = "PROP_AUTOSIZE"; private PropertyChangeSupport changes = new PropertyChangeSupport(this); SVGUniverse svgUniverse = SVGCache.getSVGUniverse(); public static final int INTERP_NEAREST_NEIGHBOR = 0; public static final int INTERP_BILINEAR = 1; public static final int INTERP_BICUBIC = 2; private boolean antiAlias; private int interpolation = INTERP_NEAREST_NEIGHBOR; private boolean clipToViewbox; // private String svgPath; URI svgURI; // private boolean scaleToFit; AffineTransform scaleXform = new AffineTransform(); public static final int AUTOSIZE_NONE = 0; public static final int AUTOSIZE_HORIZ = 1; public static final int AUTOSIZE_VERT = 2; public static final int AUTOSIZE_BESTFIT = 3; public static final int AUTOSIZE_STRETCH = 4; private int autosize = AUTOSIZE_NONE; // Dimension preferredSize = new Dimension(100, 100); Dimension preferredSize; /** Creates a new instance of SVGIcon */ public SVGIcon() { } public void addPropertyChangeListener(PropertyChangeListener p) { changes.addPropertyChangeListener(p); } public void removePropertyChangeListener(PropertyChangeListener p) { changes.removePropertyChangeListener(p); } /** * @return height of this icon */ public int getIconHeight() { if (preferredSize != null && (autosize == AUTOSIZE_VERT || autosize == AUTOSIZE_STRETCH || autosize == AUTOSIZE_BESTFIT)) { return preferredSize.height; } SVGDiagram diagram = svgUniverse.getDiagram(svgURI); if (diagram == null) { return 0; } return (int)diagram.getHeight(); } /** * @return width of this icon */ public int getIconWidth() { if (preferredSize != null && (autosize == AUTOSIZE_HORIZ || autosize == AUTOSIZE_STRETCH || autosize == AUTOSIZE_BESTFIT)) { return preferredSize.width; } SVGDiagram diagram = svgUniverse.getDiagram(svgURI); if (diagram == null) { return 0; } return (int)diagram.getWidth(); } /** * Draws the icon to the specified component. * @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 * @param gg - Graphics context to render SVG content to * @param x - X coordinate to draw icon * @param y - Y coordinate to draw icon */ public void paintIcon(Component comp, Graphics gg, int x, int y) { //Copy graphics object so that Graphics2D g = (Graphics2D)gg.create(); paintIcon(comp, g, x, y); g.dispose(); } private void paintIcon(Component comp, Graphics2D g, int x, int y) { Object oldAliasHint = g.getRenderingHint(RenderingHints.KEY_ANTIALIASING); g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, antiAlias ? RenderingHints.VALUE_ANTIALIAS_ON : RenderingHints.VALUE_ANTIALIAS_OFF); Object oldInterpolationHint = g.getRenderingHint(RenderingHints.KEY_INTERPOLATION); switch (interpolation) { case INTERP_NEAREST_NEIGHBOR: g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR); break; case INTERP_BILINEAR: g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); break; case INTERP_BICUBIC: g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC); break; } SVGDiagram diagram = svgUniverse.getDiagram(svgURI); if (diagram == null) { return; } g.translate(x, y); diagram.setIgnoringClipHeuristic(!clipToViewbox); if (clipToViewbox) { g.setClip(new Rectangle2D.Float(0, 0, diagram.getWidth(), diagram.getHeight())); } if (autosize == AUTOSIZE_NONE) { try { diagram.render(g); g.translate(-x, -y); g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, oldAliasHint); } catch (Exception e) { throw new RuntimeException(e); } return; } final int width = getIconWidth(); final int height = getIconHeight(); // int width = getWidth(); // int height = getHeight(); if (width == 0 || height == 0) { return; } // if (width == 0 || height == 0) // { // //Chances are we're rendering offscreen // Dimension dim = getSize(); // width = dim.width; // height = dim.height; // return; // } // g.setClip(0, 0, width, height); // final Rectangle2D.Double rect = new Rectangle2D.Double(); // diagram.getViewRect(rect); // // scaleXform.setToScale(width / rect.width, height / rect.height); double diaWidth = diagram.getWidth(); double diaHeight = diagram.getHeight(); double scaleW = 1; double scaleH = 1; if (autosize == AUTOSIZE_BESTFIT) { scaleW = scaleH = (height / diaHeight < width / diaWidth) ? height / diaHeight : width / diaWidth; } else if (autosize == AUTOSIZE_HORIZ) { scaleW = scaleH = width / diaWidth; } else if (autosize == AUTOSIZE_VERT) { scaleW = scaleH = height / diaHeight; } else if (autosize == AUTOSIZE_STRETCH) { scaleW = width / diaWidth; scaleH = height / diaHeight; } scaleXform.setToScale(scaleW, scaleH); AffineTransform oldXform = g.getTransform(); g.transform(scaleXform); try { diagram.render(g); } catch (SVGException e) { throw new RuntimeException(e); } g.setTransform(oldXform); g.translate(-x, -y); g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, oldAliasHint); if (oldInterpolationHint != null) { g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, oldInterpolationHint); } } /** * @return the universe this icon draws it's SVGDiagrams from */ public SVGUniverse getSvgUniverse() { return svgUniverse; } public void setSvgUniverse(SVGUniverse svgUniverse) { SVGUniverse old = this.svgUniverse; this.svgUniverse = svgUniverse; changes.firePropertyChange("svgUniverse", old, svgUniverse); } /** * @return the uni of the document being displayed by this icon */ public URI getSvgURI() { return svgURI; } /** * Loads an SVG document from a URI. * @param svgURI - URI to load document from */ public void setSvgURI(URI svgURI) { URI old = this.svgURI; this.svgURI = svgURI; SVGDiagram diagram = svgUniverse.getDiagram(svgURI); if (diagram != null) { Dimension size = getPreferredSize(); if (size == null) { size = new Dimension((int)diagram.getRoot().getDeviceWidth(), (int)diagram.getRoot().getDeviceHeight()); } diagram.setDeviceViewport(new Rectangle(0, 0, size.width, size.height)); } changes.firePropertyChange("svgURI", old, svgURI); } /** * Loads an SVG document from the classpath. This function is equivilant to * setSvgURI(new URI(getClass().getResource(resourcePath).toString()); * @param resourcePath - resource to load */ public void setSvgResourcePath(String resourcePath) { URI old = this.svgURI; try { svgURI = new URI(getClass().getResource(resourcePath).toString()); changes.firePropertyChange("svgURI", old, svgURI); SVGDiagram diagram = svgUniverse.getDiagram(svgURI); if (diagram != null) { diagram.setDeviceViewport(new Rectangle(0, 0, preferredSize.width, preferredSize.height)); } } catch (Exception e) { svgURI = old; } } /** * If this SVG document has a viewbox, if scaleToFit is set, will scale the viewbox to match the * preferred size of this icon * @deprecated * @return */ public boolean isScaleToFit() { return autosize == AUTOSIZE_STRETCH; } /** * @deprecated * @return */ public void setScaleToFit(boolean scaleToFit) { setAutosize(AUTOSIZE_STRETCH); // boolean old = this.scaleToFit; // this.scaleToFit = scaleToFit; // firePropertyChange("scaleToFit", old, scaleToFit); } public Dimension getPreferredSize() { if (preferredSize == null) { SVGDiagram diagram = svgUniverse.getDiagram(svgURI); if (diagram != null) { //preferredSize = new Dimension((int)diagram.getWidth(), (int)diagram.getHeight()); setPreferredSize(new Dimension((int)diagram.getWidth(), (int)diagram.getHeight())); } } return new Dimension(preferredSize); } public void setPreferredSize(Dimension preferredSize) { Dimension old = this.preferredSize; this.preferredSize = preferredSize; SVGDiagram diagram = svgUniverse.getDiagram(svgURI); if (diagram != null) { diagram.setDeviceViewport(new Rectangle(0, 0, preferredSize.width, preferredSize.height)); } changes.firePropertyChange("preferredSize", old, preferredSize); } /** * @return true if antiAliasing is turned on. * @deprecated */ public boolean getUseAntiAlias() { return getAntiAlias(); } /** * @param antiAlias true to use antiAliasing. * @deprecated */ public void setUseAntiAlias(boolean antiAlias) { setAntiAlias(antiAlias); } /** * @return true if antiAliasing is turned on. */ public boolean getAntiAlias() { return antiAlias; } /** * @param antiAlias true to use antiAliasing. */ public void setAntiAlias(boolean antiAlias) { boolean old = this.antiAlias; this.antiAlias = antiAlias; changes.firePropertyChange("antiAlias", old, antiAlias); } /** * @return interpolation used in rescaling images */ public int getInterpolation() { return interpolation; } /** * @param interpolation Interpolation value used in rescaling images. * Should be one of * INTERP_NEAREST_NEIGHBOR - Fastest, one pixel resampling, poor quality * INTERP_BILINEAR - four pixel resampling * INTERP_BICUBIC - Slowest, nine pixel resampling, best quality */ public void setInterpolation(int interpolation) { int old = this.interpolation; this.interpolation = interpolation; changes.firePropertyChange("interpolation", old, interpolation); } /** * clipToViewbox will set a clip box equivilant to the SVG's viewbox before * rendering. */ public boolean isClipToViewbox() { return clipToViewbox; } public void setClipToViewbox(boolean clipToViewbox) { this.clipToViewbox = clipToViewbox; } /** * @return the autosize */ public int getAutosize() { return autosize; } /** * @param autosize the autosize to set */ public void setAutosize(int autosize) { int oldAutosize = this.autosize; this.autosize = autosize; changes.firePropertyChange(PROP_AUTOSIZE, oldAutosize, autosize); } }