added sources for Slick

Former-commit-id: 1647fa32ef6894bd7db44f741f07c2f4dcdf9054
Former-commit-id: 0e5810dcfbe1fd59b13e7cabe9f1e93c5542da2d
This commit is contained in:
Song Minjae
2016-12-30 23:29:12 +09:00
parent d1f01a203d
commit d3080ffb78
329 changed files with 58400 additions and 7 deletions

View File

@@ -0,0 +1,171 @@
package org.newdawn.slick.svg.inkscape;
import java.util.ArrayList;
import org.newdawn.slick.Color;
import org.newdawn.slick.geom.Transform;
import org.newdawn.slick.svg.Diagram;
import org.newdawn.slick.svg.Gradient;
import org.newdawn.slick.svg.Loader;
import org.newdawn.slick.svg.ParsingException;
import org.newdawn.slick.util.Log;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
/**
* A processor for the defs node
*
* @author kevin
*/
public class DefsProcessor implements ElementProcessor {
/**
* @see org.newdawn.slick.svg.inkscape.ElementProcessor#handles(org.w3c.dom.Element)
*/
public boolean handles(Element element) {
if (element.getNodeName().equals("defs")) {
return true;
}
return false;
}
/**
* @see org.newdawn.slick.svg.inkscape.ElementProcessor#process(org.newdawn.slick.svg.Loader, org.w3c.dom.Element, org.newdawn.slick.svg.Diagram, org.newdawn.slick.geom.Transform)
*/
public void process(Loader loader, Element element, Diagram diagram, Transform transform) throws ParsingException {
NodeList patterns = element.getElementsByTagName("pattern");
for (int i=0;i<patterns.getLength();i++) {
Element pattern = (Element) patterns.item(i);
NodeList list = pattern.getElementsByTagName("image");
if (list.getLength() == 0) {
Log.warn("Pattern 1981 does not specify an image. Only image patterns are supported.");
continue;
}
Element image = (Element) list.item(0);
String patternName = pattern.getAttribute("id");
String ref = image.getAttributeNS(Util.XLINK, "href");
diagram.addPatternDef(patternName, ref);
}
NodeList linear = element.getElementsByTagName("linearGradient");
ArrayList toResolve = new ArrayList();
for (int i=0;i<linear.getLength();i++) {
Element lin = (Element) linear.item(i);
String name = lin.getAttribute("id");
Gradient gradient = new Gradient(name, false);
gradient.setTransform(Util.getTransform(lin, "gradientTransform"));
if (stringLength(lin.getAttribute("x1")) > 0) {
gradient.setX1(Float.parseFloat(lin.getAttribute("x1")));
}
if (stringLength(lin.getAttribute("x2")) > 0) {
gradient.setX2(Float.parseFloat(lin.getAttribute("x2")));
}
if (stringLength(lin.getAttribute("y1")) > 0) {
gradient.setY1(Float.parseFloat(lin.getAttribute("y1")));
}
if (stringLength(lin.getAttribute("y2")) > 0) {
gradient.setY2(Float.parseFloat(lin.getAttribute("y2")));
}
String ref = lin.getAttributeNS("http://www.w3.org/1999/xlink", "href");
if (stringLength(ref) > 0) {
gradient.reference(ref.substring(1));
toResolve.add(gradient);
} else {
NodeList steps = lin.getElementsByTagName("stop");
for (int j=0;j<steps.getLength();j++) {
Element s = (Element) steps.item(j);
float offset = Float.parseFloat(s.getAttribute("offset"));
String colInt = Util.extractStyle(s.getAttribute("style"),"stop-color");
String opaInt = Util.extractStyle(s.getAttribute("style"),"stop-opacity");
int col = Integer.parseInt(colInt.substring(1), 16);
Color stopColor = new Color(col);
stopColor.a = Float.parseFloat(opaInt);
gradient.addStep(offset, stopColor);
}
gradient.getImage();
}
diagram.addGradient(name, gradient);
}
NodeList radial = element.getElementsByTagName("radialGradient");
for (int i=0;i<radial.getLength();i++) {
Element rad = (Element) radial.item(i);
String name = rad.getAttribute("id");
Gradient gradient = new Gradient(name, true);
gradient.setTransform(Util.getTransform(rad, "gradientTransform"));
if (stringLength(rad.getAttribute("cx")) > 0) {
gradient.setX1(Float.parseFloat(rad.getAttribute("cx")));
}
if (stringLength(rad.getAttribute("cy")) > 0) {
gradient.setY1(Float.parseFloat(rad.getAttribute("cy")));
}
if (stringLength(rad.getAttribute("fx")) > 0) {
gradient.setX2(Float.parseFloat(rad.getAttribute("fx")));
}
if (stringLength(rad.getAttribute("fy")) > 0) {
gradient.setY2(Float.parseFloat(rad.getAttribute("fy")));
}
if (stringLength(rad.getAttribute("r")) > 0) {
gradient.setR(Float.parseFloat(rad.getAttribute("r")));
}
String ref = rad.getAttributeNS("http://www.w3.org/1999/xlink", "href");
if (stringLength(ref) > 0) {
gradient.reference(ref.substring(1));
toResolve.add(gradient);
} else {
NodeList steps = rad.getElementsByTagName("stop");
for (int j=0;j<steps.getLength();j++) {
Element s = (Element) steps.item(j);
float offset = Float.parseFloat(s.getAttribute("offset"));
String colInt = Util.extractStyle(s.getAttribute("style"),"stop-color");
String opaInt = Util.extractStyle(s.getAttribute("style"),"stop-opacity");
int col = Integer.parseInt(colInt.substring(1), 16);
Color stopColor = new Color(col);
stopColor.a = Float.parseFloat(opaInt);
gradient.addStep(offset, stopColor);
}
gradient.getImage();
}
diagram.addGradient(name, gradient);
}
for (int i=0;i<toResolve.size();i++) {
((Gradient) toResolve.get(i)).resolve(diagram);
((Gradient) toResolve.get(i)).getImage();
}
}
/**
* Utility to cope with null values
*
* @param value The value to get the length of
* @return The length of the string
*/
private int stringLength(String value) {
if (value == null) {
return 0;
}
return value.length();
}
}

View File

@@ -0,0 +1,36 @@
package org.newdawn.slick.svg.inkscape;
import org.newdawn.slick.geom.Transform;
import org.newdawn.slick.svg.Diagram;
import org.newdawn.slick.svg.Loader;
import org.newdawn.slick.svg.ParsingException;
import org.w3c.dom.Element;
/**
* The description of a module which processes a single XML element from a SVG (inkscape)
* document.
*
* @author kevin
*/
public interface ElementProcessor {
/**
* Process a document extracting all the elements that the processor is
* interested in and producing appropriate diagram components for the
* element.
*
* @param loader The loader/context of the parsing
* @param element The element to be processed
* @param diagram The diagram to be built
* @param transform The transform to apply to all elements at this level
* @throws ParsingException Indicates an invalid content to an element
*/
public void process(Loader loader, Element element, Diagram diagram, Transform transform) throws ParsingException;
/**
* Check if this processor handles the element specified
*
* @param element The element to check
* @return True if this processor can handle the given element
*/
public boolean handles(Element element);
}

View File

@@ -0,0 +1,60 @@
package org.newdawn.slick.svg.inkscape;
import org.newdawn.slick.geom.Ellipse;
import org.newdawn.slick.geom.Shape;
import org.newdawn.slick.geom.Transform;
import org.newdawn.slick.svg.Diagram;
import org.newdawn.slick.svg.Figure;
import org.newdawn.slick.svg.Loader;
import org.newdawn.slick.svg.NonGeometricData;
import org.newdawn.slick.svg.ParsingException;
import org.w3c.dom.Element;
/**
* Processor for <ellipse> and <path> nodes marked as arcs
*
* @author kevin
*/
public class EllipseProcessor implements ElementProcessor {
/**
* @see org.newdawn.slick.svg.inkscape.ElementProcessor#process(org.newdawn.slick.svg.Loader, org.w3c.dom.Element, org.newdawn.slick.svg.Diagram, org.newdawn.slick.geom.Transform)
*/
public void process(Loader loader, Element element, Diagram diagram, Transform t) throws ParsingException {
Transform transform = Util.getTransform(element);
transform = new Transform(t, transform);
float x = Util.getFloatAttribute(element,"cx");
float y = Util.getFloatAttribute(element,"cy");
float rx = Util.getFloatAttribute(element,"rx");
float ry = Util.getFloatAttribute(element,"ry");
Ellipse ellipse = new Ellipse(x,y,rx,ry);
Shape shape = ellipse.transform(transform);
NonGeometricData data = Util.getNonGeometricData(element);
data.addAttribute("cx", ""+x);
data.addAttribute("cy", ""+y);
data.addAttribute("rx", ""+rx);
data.addAttribute("ry", ""+ry);
diagram.addFigure(new Figure(Figure.ELLIPSE, shape, data, transform));
}
/**
* @see org.newdawn.slick.svg.inkscape.ElementProcessor#handles(org.w3c.dom.Element)
*/
public boolean handles(Element element) {
if (element.getNodeName().equals("ellipse")) {
return true;
}
if (element.getNodeName().equals("path")) {
if ("arc".equals(element.getAttributeNS(Util.SODIPODI, "type"))) {
return true;
}
}
return false;
}
}

View File

@@ -0,0 +1,36 @@
package org.newdawn.slick.svg.inkscape;
import org.newdawn.slick.geom.Transform;
import org.newdawn.slick.svg.Diagram;
import org.newdawn.slick.svg.Loader;
import org.newdawn.slick.svg.ParsingException;
import org.w3c.dom.Element;
/**
* TODO: Document this class
*
* @author kevin
*/
public class GroupProcessor implements ElementProcessor {
/**
* @see org.newdawn.slick.svg.inkscape.ElementProcessor#handles(org.w3c.dom.Element)
*/
public boolean handles(Element element) {
if (element.getNodeName().equals("g")) {
return true;
}
return false;
}
/**O
* @see org.newdawn.slick.svg.inkscape.ElementProcessor#process(org.newdawn.slick.svg.Loader, org.w3c.dom.Element, org.newdawn.slick.svg.Diagram, org.newdawn.slick.geom.Transform)
*/
public void process(Loader loader, Element element, Diagram diagram, Transform t) throws ParsingException {
Transform transform = Util.getTransform(element);
transform = new Transform(t, transform);
loader.loadChildren(element, transform);
}
}

View File

@@ -0,0 +1,49 @@
package org.newdawn.slick.svg.inkscape;
import org.newdawn.slick.svg.NonGeometricData;
import org.w3c.dom.Element;
/**
* A custom non-geometric data type that can pass back any attribute
* on the field.
*
* @author kevin
*/
public class InkscapeNonGeometricData extends NonGeometricData {
/** The element read from the SVG */
private Element element;
/**
* Create a new non-geometric data holder
*
* @param metaData The metadata provided
* @param element The XML element from the SVG document
*/
public InkscapeNonGeometricData(String metaData, Element element) {
super(metaData);
this.element = element;
}
/**
* @see org.newdawn.slick.svg.NonGeometricData#getAttribute(java.lang.String)
*/
public String getAttribute(String attribute) {
String result = super.getAttribute(attribute);
if (result == null) {
result = element.getAttribute(attribute);
}
return result;
}
/**
* Returns the XML element that is wrapped by this instance.
*
* @return The XML element for this instance
*/
public Element getElement() {
return element;
}
}

View File

@@ -0,0 +1,127 @@
package org.newdawn.slick.svg.inkscape;
import java.util.StringTokenizer;
import org.newdawn.slick.geom.Line;
import org.newdawn.slick.geom.Polygon;
import org.newdawn.slick.geom.Transform;
import org.newdawn.slick.svg.Diagram;
import org.newdawn.slick.svg.Figure;
import org.newdawn.slick.svg.Loader;
import org.newdawn.slick.svg.NonGeometricData;
import org.newdawn.slick.svg.ParsingException;
import org.w3c.dom.Element;
/**
* A processor for the <line> element
*
* @author kevin
*/
public class LineProcessor implements ElementProcessor {
/**
* Process the points in a polygon definition
*
* @param poly The polygon being built
* @param element The XML element being read
* @param tokens The tokens representing the path
* @return The number of points found
* @throws ParsingException Indicates an invalid token in the path
*/
private static int processPoly(Polygon poly, Element element, StringTokenizer tokens) throws ParsingException {
int count = 0;
while (tokens.hasMoreTokens()) {
String nextToken = tokens.nextToken();
if (nextToken.equals("L")) {
continue;
}
if (nextToken.equals("z")) {
break;
}
if (nextToken.equals("M")) {
continue;
}
if (nextToken.equals("C")) {
return 0;
}
String tokenX = nextToken;
String tokenY = tokens.nextToken();
try {
float x = Float.parseFloat(tokenX);
float y = Float.parseFloat(tokenY);
poly.addPoint(x,y);
count++;
} catch (NumberFormatException e) {
throw new ParsingException(element.getAttribute("id"), "Invalid token in points list", e);
}
}
return count;
}
/**
* @see org.newdawn.slick.svg.inkscape.ElementProcessor#process(org.newdawn.slick.svg.Loader, org.w3c.dom.Element, org.newdawn.slick.svg.Diagram, org.newdawn.slick.geom.Transform)
*/
public void process(Loader loader, Element element, Diagram diagram, Transform t) throws ParsingException {
Transform transform = Util.getTransform(element);
transform = new Transform(t, transform);
float x1;
float y1;
float x2;
float y2;
if (element.getNodeName().equals("line")) {
x1 = Float.parseFloat(element.getAttribute("x1"));
x2 = Float.parseFloat(element.getAttribute("x2"));
y1 = Float.parseFloat(element.getAttribute("y1"));
y2 = Float.parseFloat(element.getAttribute("y2"));
} else {
String points = element.getAttribute("d");
StringTokenizer tokens = new StringTokenizer(points, ", ");
Polygon poly = new Polygon();
if (processPoly(poly, element, tokens) == 2) {
x1 = poly.getPoint(0)[0];
y1 = poly.getPoint(0)[1];
x2 = poly.getPoint(1)[0];
y2 = poly.getPoint(1)[1];
} else {
return;
}
}
float[] in = new float[] {x1,y1,x2,y2};
float[] out = new float[4];
transform.transform(in,0,out,0,2);
Line line = new Line(out[0],out[1],out[2],out[3]);
NonGeometricData data = Util.getNonGeometricData(element);
data.addAttribute("x1",""+x1);
data.addAttribute("x2",""+x2);
data.addAttribute("y1",""+y1);
data.addAttribute("y2",""+y2);
diagram.addFigure(new Figure(Figure.LINE, line, data, transform));
}
/**
* @see org.newdawn.slick.svg.inkscape.ElementProcessor#handles(org.w3c.dom.Element)
*/
public boolean handles(Element element) {
if (element.getNodeName().equals("line")) {
return true;
}
if (element.getNodeName().equals("path")) {
if (!"arc".equals(element.getAttributeNS(Util.SODIPODI, "type"))) {
return true;
}
}
return false;
}
}

View File

@@ -0,0 +1,127 @@
package org.newdawn.slick.svg.inkscape;
import java.util.ArrayList;
import java.util.StringTokenizer;
import org.newdawn.slick.geom.Path;
import org.newdawn.slick.geom.Shape;
import org.newdawn.slick.geom.Transform;
import org.newdawn.slick.svg.Diagram;
import org.newdawn.slick.svg.Figure;
import org.newdawn.slick.svg.Loader;
import org.newdawn.slick.svg.NonGeometricData;
import org.newdawn.slick.svg.ParsingException;
import org.w3c.dom.Element;
/**
* A processor for the <polygon> and <path> elements marked as not an arc.
*
* @author kevin
*/
public class PathProcessor implements ElementProcessor {
/**
* Process the points in a polygon definition
*
* @param element The XML element being read
* @param tokens The tokens representing the path
* @return The number of points found
* @throws ParsingException Indicates an invalid token in the path
*/
private static Path processPoly(Element element, StringTokenizer tokens) throws ParsingException {
int count = 0;
ArrayList pts = new ArrayList();
boolean moved = false;
boolean reasonToBePath = false;
Path path = null;
while (tokens.hasMoreTokens()) {
try {
String nextToken = tokens.nextToken();
if (nextToken.equals("L")) {
float x = Float.parseFloat(tokens.nextToken());
float y = Float.parseFloat(tokens.nextToken());
path.lineTo(x,y);
continue;
}
if (nextToken.equals("z")) {
path.close();
continue;
}
if (nextToken.equals("M")) {
if (!moved) {
moved = true;
float x = Float.parseFloat(tokens.nextToken());
float y = Float.parseFloat(tokens.nextToken());
path = new Path(x,y);
continue;
}
reasonToBePath = true;
float x = Float.parseFloat(tokens.nextToken());
float y = Float.parseFloat(tokens.nextToken());
path.startHole(x,y);
continue;
}
if (nextToken.equals("C")) {
reasonToBePath = true;
float cx1 = Float.parseFloat(tokens.nextToken());
float cy1 = Float.parseFloat(tokens.nextToken());
float cx2 = Float.parseFloat(tokens.nextToken());
float cy2 = Float.parseFloat(tokens.nextToken());
float x = Float.parseFloat(tokens.nextToken());
float y = Float.parseFloat(tokens.nextToken());
path.curveTo(x,y,cx1,cy1,cx2,cy2);
continue;
}
} catch (NumberFormatException e) {
throw new ParsingException(element.getAttribute("id"), "Invalid token in points list", e);
}
}
if (!reasonToBePath) {
return null;
}
return path;
}
/**
* @see org.newdawn.slick.svg.inkscape.ElementProcessor#process(org.newdawn.slick.svg.Loader, org.w3c.dom.Element, org.newdawn.slick.svg.Diagram, org.newdawn.slick.geom.Transform)
*/
public void process(Loader loader, Element element, Diagram diagram, Transform t) throws ParsingException {
Transform transform = Util.getTransform(element);
transform = new Transform(t, transform);
String points = element.getAttribute("points");
if (element.getNodeName().equals("path")) {
points = element.getAttribute("d");
}
StringTokenizer tokens = new StringTokenizer(points, ", ");
Path path = processPoly(element, tokens);
NonGeometricData data = Util.getNonGeometricData(element);
if (path != null) {
Shape shape = path.transform(transform);
diagram.addFigure(new Figure(Figure.PATH, shape, data, transform));
}
}
/**
* @see org.newdawn.slick.svg.inkscape.ElementProcessor#handles(org.w3c.dom.Element)
*/
public boolean handles(Element element) {
if (element.getNodeName().equals("path")) {
if (!"arc".equals(element.getAttributeNS(Util.SODIPODI, "type"))) {
return true;
}
}
return false;
}
}

View File

@@ -0,0 +1,119 @@
package org.newdawn.slick.svg.inkscape;
import java.util.ArrayList;
import java.util.StringTokenizer;
import org.newdawn.slick.geom.Polygon;
import org.newdawn.slick.geom.Shape;
import org.newdawn.slick.geom.Transform;
import org.newdawn.slick.svg.Diagram;
import org.newdawn.slick.svg.Figure;
import org.newdawn.slick.svg.Loader;
import org.newdawn.slick.svg.NonGeometricData;
import org.newdawn.slick.svg.ParsingException;
import org.w3c.dom.Element;
/**
* A processor for the <polygon> and <path> elements marked as not an arc.
*
* @author kevin
*/
public class PolygonProcessor implements ElementProcessor {
/**
* Process the points in a polygon definition
*
* @param poly The polygon being built
* @param element The XML element being read
* @param tokens The tokens representing the path
* @return The number of points found
* @throws ParsingException Indicates an invalid token in the path
*/
private static int processPoly(Polygon poly, Element element, StringTokenizer tokens) throws ParsingException {
int count = 0;
ArrayList pts = new ArrayList();
boolean moved = false;
boolean closed = false;
while (tokens.hasMoreTokens()) {
String nextToken = tokens.nextToken();
if (nextToken.equals("L")) {
continue;
}
if (nextToken.equals("z")) {
closed = true;
break;
}
if (nextToken.equals("M")) {
if (!moved) {
moved = true;
continue;
}
return 0;
}
if (nextToken.equals("C")) {
return 0;
}
String tokenX = nextToken;
String tokenY = tokens.nextToken();
try {
float x = Float.parseFloat(tokenX);
float y = Float.parseFloat(tokenY);
poly.addPoint(x,y);
count++;
} catch (NumberFormatException e) {
throw new ParsingException(element.getAttribute("id"), "Invalid token in points list", e);
}
}
poly.setClosed(closed);
return count;
}
/**
* @see org.newdawn.slick.svg.inkscape.ElementProcessor#process(org.newdawn.slick.svg.Loader, org.w3c.dom.Element, org.newdawn.slick.svg.Diagram, org.newdawn.slick.geom.Transform)
*/
public void process(Loader loader, Element element, Diagram diagram, Transform t) throws ParsingException {
Transform transform = Util.getTransform(element);
transform = new Transform(t, transform);
String points = element.getAttribute("points");
if (element.getNodeName().equals("path")) {
points = element.getAttribute("d");
}
StringTokenizer tokens = new StringTokenizer(points, ", ");
Polygon poly = new Polygon();
int count = processPoly(poly, element, tokens);
NonGeometricData data = Util.getNonGeometricData(element);
if (count > 3) {
Shape shape = poly.transform(transform);
diagram.addFigure(new Figure(Figure.POLYGON, shape, data, transform));
}
}
/**
* @see org.newdawn.slick.svg.inkscape.ElementProcessor#handles(org.w3c.dom.Element)
*/
public boolean handles(Element element) {
if (element.getNodeName().equals("polygon")) {
return true;
}
if (element.getNodeName().equals("path")) {
if (!"arc".equals(element.getAttributeNS(Util.SODIPODI, "type"))) {
return true;
}
}
return false;
}
}

View File

@@ -0,0 +1,54 @@
package org.newdawn.slick.svg.inkscape;
import org.newdawn.slick.geom.Rectangle;
import org.newdawn.slick.geom.Shape;
import org.newdawn.slick.geom.Transform;
import org.newdawn.slick.svg.Diagram;
import org.newdawn.slick.svg.Figure;
import org.newdawn.slick.svg.Loader;
import org.newdawn.slick.svg.NonGeometricData;
import org.newdawn.slick.svg.ParsingException;
import org.w3c.dom.Element;
/**
* A processor for the <rect> element.
*
* @author kevin
*/
public class RectProcessor implements ElementProcessor {
/**
* @see org.newdawn.slick.svg.inkscape.ElementProcessor#process(org.newdawn.slick.svg.Loader, org.w3c.dom.Element, org.newdawn.slick.svg.Diagram, org.newdawn.slick.geom.Transform)
*/
public void process(Loader loader, Element element, Diagram diagram, Transform t) throws ParsingException {
Transform transform = Util.getTransform(element);
transform = new Transform(t, transform);
float width = Float.parseFloat(element.getAttribute("width"));
float height = Float.parseFloat(element.getAttribute("height"));
float x = Float.parseFloat(element.getAttribute("x"));
float y = Float.parseFloat(element.getAttribute("y"));
Rectangle rect = new Rectangle(x,y,width+1,height+1);
Shape shape = rect.transform(transform);
NonGeometricData data = Util.getNonGeometricData(element);
data.addAttribute("width", ""+width);
data.addAttribute("height", ""+height);
data.addAttribute("x", ""+x);
data.addAttribute("y", ""+y);
diagram.addFigure(new Figure(Figure.RECTANGLE, shape, data, transform));
}
/**
* @see org.newdawn.slick.svg.inkscape.ElementProcessor#handles(org.w3c.dom.Element)
*/
public boolean handles(Element element) {
if (element.getNodeName().equals("rect")) {
return true;
}
return false;
}
}

View File

@@ -0,0 +1,55 @@
package org.newdawn.slick.svg.inkscape;
import org.newdawn.slick.geom.Shape;
import org.newdawn.slick.geom.Transform;
import org.newdawn.slick.svg.Diagram;
import org.newdawn.slick.svg.Figure;
import org.newdawn.slick.svg.Loader;
import org.newdawn.slick.svg.NonGeometricData;
import org.newdawn.slick.svg.ParsingException;
import org.w3c.dom.Element;
/**
* Processor for the "use", a tag that allows references to other elements
* and cloning.
*
* @author kevin
*/
public class UseProcessor implements ElementProcessor {
/**
* @see org.newdawn.slick.svg.inkscape.ElementProcessor#handles(org.w3c.dom.Element)
*/
public boolean handles(Element element) {
return element.getNodeName().equals("use");
}
/**
* @see org.newdawn.slick.svg.inkscape.ElementProcessor#process(org.newdawn.slick.svg.Loader, org.w3c.dom.Element, org.newdawn.slick.svg.Diagram, org.newdawn.slick.geom.Transform)
*/
public void process(Loader loader, Element element, Diagram diagram,
Transform transform) throws ParsingException {
String ref = element.getAttributeNS("http://www.w3.org/1999/xlink", "href");
String href = Util.getAsReference(ref);
Figure referenced = diagram.getFigureByID(href);
if (referenced == null) {
throw new ParsingException(element, "Unable to locate referenced element: "+href);
}
Transform local = Util.getTransform(element);
Transform trans = local.concatenate(referenced.getTransform());
NonGeometricData data = Util.getNonGeometricData(element);
Shape shape = referenced.getShape().transform(trans);
data.addAttribute(NonGeometricData.FILL, referenced.getData().getAttribute(NonGeometricData.FILL));
data.addAttribute(NonGeometricData.STROKE, referenced.getData().getAttribute(NonGeometricData.STROKE));
data.addAttribute(NonGeometricData.OPACITY, referenced.getData().getAttribute(NonGeometricData.OPACITY));
data.addAttribute(NonGeometricData.STROKE_WIDTH, referenced.getData().getAttribute(NonGeometricData.STROKE_WIDTH));
Figure figure = new Figure(referenced.getType(), shape, data, trans);
diagram.addFigure(figure);
}
}

View File

@@ -0,0 +1,198 @@
package org.newdawn.slick.svg.inkscape;
import java.util.StringTokenizer;
import org.newdawn.slick.geom.Transform;
import org.newdawn.slick.svg.NonGeometricData;
import org.newdawn.slick.svg.ParsingException;
import org.w3c.dom.Element;
/**
* A set of utility for processing the SVG documents produced by Inkscape
*
* @author kevin
*/
public class Util {
/** The namespace for inkscape */
public static final String INKSCAPE = "http://www.inkscape.org/namespaces/inkscape";
/** The namespace for sodipodi */
public static final String SODIPODI = "http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd";
/** The namespace for xlink */
public static final String XLINK = "http://www.w3.org/1999/xlink";
/**
* Get the non-geometric data information from an XML element
*
* @param element The element to be processed
* @return The non-geometric data (i.e. stroke, fill, etc)
*/
static NonGeometricData getNonGeometricData(Element element) {
String meta = getMetaData(element);
NonGeometricData data = new InkscapeNonGeometricData(meta, element);
data.addAttribute(NonGeometricData.ID, element.getAttribute("id"));
data.addAttribute(NonGeometricData.FILL, getStyle(element, NonGeometricData.FILL));
data.addAttribute(NonGeometricData.STROKE, getStyle(element, NonGeometricData.STROKE));
data.addAttribute(NonGeometricData.OPACITY, getStyle(element, NonGeometricData.OPACITY));
data.addAttribute(NonGeometricData.STROKE_DASHARRAY, getStyle(element, NonGeometricData.STROKE_DASHARRAY));
data.addAttribute(NonGeometricData.STROKE_DASHOFFSET, getStyle(element, NonGeometricData.STROKE_DASHOFFSET));
data.addAttribute(NonGeometricData.STROKE_MITERLIMIT, getStyle(element, NonGeometricData.STROKE_MITERLIMIT));
data.addAttribute(NonGeometricData.STROKE_OPACITY, getStyle(element, NonGeometricData.STROKE_OPACITY));
data.addAttribute(NonGeometricData.STROKE_WIDTH, getStyle(element, NonGeometricData.STROKE_WIDTH));
return data;
}
/**
* Get the meta data store within an element either in the label or
* id atributes
*
* @param element The element to be processed
* @return The meta data stored
*/
static String getMetaData(Element element) {
String label = element.getAttributeNS(INKSCAPE, "label");
if ((label != null) && (!label.equals(""))) {
return label;
}
return element.getAttribute("id");
}
/**
* Get the style attribute setting for a given style information element (i.e. fill, stroke)
*
* @param element The element to be processed
* @param styleName The name of the attribute to retrieve
* @return The style value
*/
static String getStyle(Element element, String styleName) {
String value = element.getAttribute(styleName);
if ((value != null) && (value.length() > 0)) {
return value;
}
String style = element.getAttribute("style");
return extractStyle(style, styleName);
}
/**
* Extract the style value from a Inkscape encoded string
*
* @param style The style string to be decoded
* @param attribute The style attribute to retrieve
* @return The value for the given attribute
*/
static String extractStyle(String style, String attribute) {
if (style == null) {
return "";
}
StringTokenizer tokens = new StringTokenizer(style,";");
while (tokens.hasMoreTokens()) {
String token = tokens.nextToken();
String key = token.substring(0,token.indexOf(':'));
if (key.equals(attribute)) {
return token.substring(token.indexOf(':')+1);
}
}
return "";
}
/**
* Get a transform defined in the XML
*
* @param element The element from which the transform should be read
* @return The transform to be applied
*/
static Transform getTransform(Element element) {
return getTransform(element, "transform");
}
/**
* Get a transform defined in the XML
*
* @param element The element from which the transform should be read
* @param attribute The name of the attribute holding the transform
* @return The transform to be applied
*/
static Transform getTransform(Element element, String attribute) {
String str = element.getAttribute(attribute);
if (str == null) {
return new Transform();
}
if (str.equals("")) {
return new Transform();
} else if (str.startsWith("translate")) {
str = str.substring(0, str.length()-1);
str = str.substring("translate(".length());
StringTokenizer tokens = new StringTokenizer(str, ", ");
float x = Float.parseFloat(tokens.nextToken());
float y = Float.parseFloat(tokens.nextToken());
return Transform.createTranslateTransform(x,y);
} else if (str.startsWith("matrix")) {
float[] pose = new float[6];
str = str.substring(0, str.length()-1);
str = str.substring("matrix(".length());
StringTokenizer tokens = new StringTokenizer(str, ", ");
float[] tr = new float[6];
for (int j=0;j<tr.length;j++) {
tr[j] = Float.parseFloat(tokens.nextToken());
}
pose[0] = tr[0];
pose[1] = tr[2];
pose[2] = tr[4];
pose[3] = tr[1];
pose[4] = tr[3];
pose[5] = tr[5];
return new Transform(pose);
}
return new Transform();
}
/**
* Get a floating point attribute that may appear in either the default or
* SODIPODI namespace
*
* @param element The element from which the attribute should be read
* @param attr The attribute to be read
* @return The value from the given attribute
* @throws ParsingException Indicates the value in the attribute was not a float
*/
static float getFloatAttribute(Element element, String attr) throws ParsingException {
String cx = element.getAttribute(attr);
if ((cx == null) || (cx.equals(""))) {
cx = element.getAttributeNS(SODIPODI, attr);
}
try {
return Float.parseFloat(cx);
} catch (NumberFormatException e) {
throw new ParsingException(element, "Invalid value for: "+attr, e);
}
}
/**
* Get the attribute value as a reference to another entity
*
* @param value The value to treat as reference
* @return The reference part of the attribute value
*/
public static String getAsReference(String value) {
if (value.length() < 2) {
return "";
}
value = value.substring(1, value.length());
return value;
}
}