/*
* 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 java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.net.URI;
import com.kitfox.svg.SVGCache;
import com.kitfox.svg.SVGDiagram;
import com.kitfox.svg.SVGException;
import com.kitfox.svg.SVGUniverse;
/**
*
* @author kitfox
*/
public class SVGIcon {
public static final long serialVersionUID = 1;
public static final String PROP_AUTOSIZE = "PROP_AUTOSIZE";
private final 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;
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;
/** 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;
}
}
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.
*/
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);
}
}