Using SVG Salamander

blackears edited this page Jul 4, 2016 · 2 revisions
Clone this wiki locally

Using SVG Salamander

SVG Salamander uses Java2D for all rendering, so it should integrate nicely with Swing projects.

The included com.kitfox.svg.app.SVGPlayer and com.kitfox.svg.app.SVGViewer classes implement a simple movie player and viewer for SVG content and examining the code is a great starting point for understanding the technical underpinnings of SVG Salamander.

The basic process is:

  • Create an SVGUniverse
  • Call universe.loadSVG() to load the SVG file into memory. (You can call this several times to load multiple files into the same universe. If an SVG file references another SVG file, the referenced files will be automatically loaded)
  • Call universe.getDiagram() to get an SVGDiagram object that can be used to render the SVG file.
  • Create a Graphics2D that the SVG should be rendered to. Make sure that either the Graphics2D has it's clip area set or that you call diagram.setIgnoringClipHeuristic(true). If the clip heuristic os not being ignored, shapes that do not appear within the clip area will not be rendered in the first place.
  • To change rendering with time, call universe.setCurTime() and then universe.updateTime() to update the universe to the time required. Call diagram.render() again to draw the new frame at this updated time.

The SVGDiagram is the object you are going to be most concerned with. It provides a way to access the root of the SVG document you loaded and a means to render it to a Graphics2D.

Accessing the document

All elements in an SVG document can be given an id that can be used to access the document in parts. For example, you can create a circle with the code <circle id="myCircle" cx="100" cy="100" r="50"/>. This circle can be referenced later with the key word 'myCircle'.

SVG Salamander provides the ability to access document parts with SVGDiagram.getElement(String elementName). You can then read and write the attributes of the element directly.

Using SVG in forms

The Salamander JAR contains some controls to let you use SVG easily in Swing forms. They are:

  • com.kitfox.svg.app.beans.SVGPanel
  • com.kitfox.svg.app.beans.SVGIcon

These components are both beans and can be used in NetBeans or other beans aware Java editors. Once you have installed the Jar in your editor (see your IDE's documentation for how to do this), you can place them on your form.

Both of these beans have anti-aliasing turned off by default. To turn it on, be sure to call setAntiAlias(true).

A fast way to place an SVG element on your form:

  • Place an SVG file in the resources directory of your project
  • Place a SVGPanel on your form
  • Set SvgResourcePath to the path of your resource
  • Check ScaleToFit to force the graphic to scale to the fill size of the panel

Updating the SVG document

SVG Salamander parallels the DOM model internally, and can be interactively updated at runtime. That is, you can change colors, positions and other aspects of a loaded SVGDiagram.

Tree Navigation

Use SVGDiagram.getRoot() to get an instance of SVGRoot. The SVGRoot coresponds to the <SVG> element of an SVG document. You can then get a list of it's children by calling SVGRoot.getChildren(null). The tree can be further navigated at deeper depths by calling the getChildren() method.

Adding and Editing Attributes

SVG Salamander stores attributes as strings and parses them into values at runtime to draw the SVG elements. This allows for the rich variety of types of values that the SVG specification defines. Attributes can also be either style attribtes or presentation attributes. Style attributes are defined in the 'style' attribute of an SVG element. Presentation attributes are the attributes defined as attributes outside of the 'style' attribute. If both style and presentation attributes are present, the style attribute overrides the presentation attribute. For example:

<ellipse id="myCircle" style="fill:red; stroke:black; stroke-width:5;" cx="30" cy="80" rx="10" ry="20"/>

In the above, the style attributes are fill, stroke and stroke-width while the presentation attributes are cx, cy, rx and ry.

SVG Salamander distinguishes between the two types of attributes by using the AnimationElement.AT_CSS and AnimationElement.AT_XML constants. AnimationElement.AT_CSS represents style attributes, and AnimationElement.AT_XML represents presentation attributes. If both style and presentation attributes exist for the same attribute name, the style attribute takes precedence.

To check if an attribute is defined

svgElement.hasAttribute("x", AnimationElement.AT_XML);

To add a new attribute attribute, call your element with the name of the attribute, a constant representing whether this attribute should be a style or presentation attribute, and a valid string representing the value of this attribute. If this attribute is already defined, this will throw a RuntimeException, so make sure to call hasAttribute() first if you're not sure if this attribute exists. The following adds a new style attribute to the given SVG element:

svgElement.addAttribute("fill-opacity", AnimationElement.AT_CSS, "0.5");

To setting an attribute, call the set function with the string representation of the value to set the attribute to. Make sure that the element already exists, or this will throw an exception:

svgElement.setAttribute("x", AnimationElement.AT_XML, "0.5");

Sometimes after setting an attribute, it will be necessary to take an animation step to update the element to reflect it's current state. For example, after setting the 'r' attribute of a circle, it will be necessary to call updateTime(timeInSeconds) on the circle or on one of the circle's ancestors to update the circle's shape. If your SVG diagram isn't using animation, you can pass any value in as the time. Not all attributes will require updateTime() to be called, but calling this will not hurt. Typically, atributes that alter shape will require an update while attributes that alter fills and colors do not. For convenience, you might want to update all the elements in a diagram, and then call svgDiagram.updateTime() to update the entire document at once.

circle.setAttribute("r", AnimationElement.AT_XML, "10");
circle.updateTime(0f);

At the moment, you can only set the text of tspan elements. You can do this by calling setText() on the tspan element. After doing this, you need to call rebuild() on the text element that contains the tspan element to update the caching data.

To get the value of an attribute, you can create an empty attribute and pass it to getStyle(). This will overwrite the value in the passed style attribute with the element's value of the attribute.

StyleAttribute attrib = new StyleAttribute();
svgElement.getStyle("fill", attrib);
double value = attrib.getDoubleValue();

Note that getting the value of a style attribute will first check to see if this attribute has a style set. If not, it checks to find the closest ancestor that may have this style set. If no ancestor has this attribute set, it then checks to see if a presentation attribute with the same name is set on this element. This is in keeping with the SVG convetion that style attributes override first ancestors and then presentation attributes. To get the value of only the style attribute of this element, call getStyleAbsolute() instead. getPresAbsolute() will check for the local presentation attribute.

Adding and removing children

To add a new element, create an instance of the element you wish to add, set it's attributes, and then add it to it's parent elemnt in the scene graph:

SVGDiagram diagram = SVGCache.getSVGUniverse().getDiagram(uri);
Group group = (Group)diagram.getElement("parentGroup");

Circle circle = new Circle();
try
{
circle.addAttribute("cx", AnimationElement.AT_XML, "80");
circle.addAttribute("cy", AnimationElement.AT_XML, "80");
circle.addAttribute("r", AnimationElement.AT_XML, "10");

group.loaderAddChild(null, circle);

//Update animation state for group and it's decendants so that it reflects new animation values.<br />
// We could also call diagram.update(0.0) or SVGCache.getSVGUniverse().update().  Note that calling<br />
// circle.update(0.0) won't display anything since even though it will update the circle's state,<br />
// it won't update the parent group's state.<br />
group.updateTime(0.0);<br />

}
catch (SVGException e)
{
e.printStackTrace();
}

To remove an element, call removeChild() on an element capable of having children:

SVGDiagram diagram = SVGCache.getSVGUniverse().getDiagram(uri);
Group group = (Group)diagram.getElement("circleGroup");
Circle circle = (Circle)diagram.getElement("circleToRemove");

try
{
group.removeChild(circle);
}
catch (SVGException e)
{
e.printStackTrace();
}

Picking

To pick shapes within an SVGDiagram, use the pick() method.

SVGDiagram diagram = SVGCache.getSVGUniverse().getDiagram(uri);
Point pickPoint = new Point(20, 80);
Vector pickedElements = diagram.pick(pickPoint, null);

The pick method will return a vector of vectors of SVGElements. Each vector contains the path from the root of the diagram to the picked RenderableElement.

Ant Task

The SVG Salamander Ant task allows you to easily convert SVG documents to images from an Ant script. To use it, include the SVGSalamander.jar in your class path and write an Ant target similar to:

    <target name="testAntTask">
        <typedef name="SVGToImage" classname="com.kitfox.svg.app.ant.SVGToImageAntTask" classpath="www/binaries/svgSalamander.jar"/>

        <SVGToImage format="png" antiAlias="false" verbose="true">
            <fileset dir="examples">
                <include name="hinorei.svg"/>
            </fileset>
        </SVGToImage>
    </target>

Parameters:

  • destDir - If present, specifies a directory to write SVG files to. Otherwise writes images to directory SVG file was found in verbose - If true, prints processing information to the console
  • format - File format for output images. The java core javax.imageio.ImageIO class is used for creating images, so format strings will depend on what files your system is configured to handle. By default, "gif", "jpg" and "png" files are guaranteed to be present. If omitted, "png" is used by default.
  • backgroundColor - Optional background color. Color can be specified as a standard HTML color. That is, as the name of a standard color such as "blue" or "limegreen", using the # notation as in #ff00ff for magenta, or in rgb format listing the components as in rgb(255, 192, 192) for pink. If omitted, background is transparent.
  • antiAlias - If set, shapes are drawn using anti-aliasing. Defaults to true.
  • interpolation - String describing image interpolation algorithm. Can be one of "nearest neighbor", "bilinear" or "bicubic". Defaults to "bicubic".
  • width - If greater than 0, determines the width of the written image. Otherwise, the width is obtained from the SVG document. Defaults to -1;
  • height - If greater than 0, determines the height of the written image. Otherwise, the height is obtained from the SVG document. Defaults to -1.
  • sizeToFit - If true and the width and height of the output image differ from that of the SVG image, the valid area of the SVG image will be resized to fit the specified size.
  • verbose - IF true, prints out diagnostic information about processing. Defaults to false.

Examples

Some example SVG files that can be loaded and played in this browser can be found in the /examples directory of the source.

Here's some example code that demonstrates the use of the SVGSalamander package:

  • Static SVGIcon - Create an SVGIcon from a string and draw it to a JPanel
  • Dynamic SVGIcon - Dynamically add and remove SVG elements and alter their attributes